Example #1
0
def test_to_matrix_LincombOperator():
    np.random.seed(0)
    A = np.random.randn(3, 3)
    B = np.random.randn(3, 2)
    a = np.random.randn()
    b = np.random.randn()
    C = a * A + b * B.dot(B.T)

    Aop = NumpyMatrixOperator(A)
    Bop = NumpyMatrixOperator(B)
    Cop = LincombOperator([Aop, Concatenation([Bop, Bop.T])], [a, b])
    assert_type_and_allclose(C, Cop, 'dense')

    Aop = NumpyMatrixOperator(sps.csc_matrix(A))
    Bop = NumpyMatrixOperator(B)
    Cop = LincombOperator([Aop, Concatenation([Bop, Bop.T])], [a, b])
    assert_type_and_allclose(C, Cop, 'dense')

    Aop = NumpyMatrixOperator(A)
    Bop = NumpyMatrixOperator(sps.csc_matrix(B))
    Cop = LincombOperator([Aop, Concatenation([Bop, Bop.T])], [a, b])
    assert_type_and_allclose(C, Cop, 'dense')

    Aop = NumpyMatrixOperator(sps.csc_matrix(A))
    Bop = NumpyMatrixOperator(sps.csc_matrix(B))
    Cop = LincombOperator([Aop, Concatenation([Bop, Bop.T])], [a, b])
    assert_type_and_allclose(C, Cop, 'sparse')
Example #2
0
 def __init__(self, op):
     operators    = [self._wrapper[op.component(i)]   for i in xrange(op.num_components())]
     coefficients = [self._wrapper[op.coefficient(i)] for i in xrange(op.num_components())]
     if op.has_affine_part():
         operators.append(self._wrapper[op.affine_part()])
         coefficients.append(1.)
     LincombOperator.__init__(self, operators, coefficients)
Example #3
0
def test_lincomb_adjoint():
    op = LincombOperator([NumpyMatrixOperator(np.eye(10)), NumpyMatrixOperator(np.eye(10))],
                         [1+3j, ExpressionParameterFunctional('c[0] + 3', {'c': 1})])
    mu = op.parameters.parse(1j)
    U = op.range.random()
    V = op.apply_adjoint(U, mu=mu)
    VV = op.H.apply(U, mu=mu)
    assert np.all(almost_equal(V, VV))
    VVV = op.apply(U, mu=mu).conj()
    assert np.all(almost_equal(V, VVV))
Example #4
0
 def lincomb(operators, coefficients, name=None):
     import warnings
     warnings.warn(
         'OperatorInterface.lincomb is deprecated!' +
         'Use pymor.operators.constructions.LincombOperator instead.')
     from pymor.operators.constructions import LincombOperator
     op = LincombOperator(operators, coefficients, name=None)
     if op.parametric:
         return op
     else:
         return op.assemble()
Example #5
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 #6
0
def test_to_matrix():
    np.random.seed(0)
    A = np.random.randn(2, 2)
    B = np.random.randn(3, 3)
    C = np.random.randn(3, 3)

    X = np.bmat([[np.eye(2) + A, np.zeros((2, 3))],
                 [np.zeros((3, 2)), B.dot(C.T)]])

    C = sps.csc_matrix(C)

    Aop = NumpyMatrixOperator(A)
    Bop = NumpyMatrixOperator(B)
    Cop = NumpyMatrixOperator(C)

    Xop = BlockDiagonalOperator([
        LincombOperator([IdentityOperator(NumpyVectorSpace(2)), Aop], [1, 1]),
        Concatenation(Bop, AdjointOperator(Cop))
    ])

    assert np.allclose(X, to_matrix(Xop))
    assert np.allclose(X, to_matrix(Xop, format='csr').toarray())

    np.random.seed(0)
    V = np.random.randn(10, 2)
    Vva = NumpyVectorArray(V.T)
    Vop = VectorArrayOperator(Vva)
    assert np.allclose(V, to_matrix(Vop))
    Vop = VectorArrayOperator(Vva, transposed=True)
    assert np.allclose(V, to_matrix(Vop).T)
Example #7
0
    def _add_sub(self, other, sign):
        if not isinstance(other, Operator):
            return NotImplemented
        from pymor.operators.constructions import LincombOperator
        if self.name != 'LincombOperator' or not isinstance(
                self, LincombOperator):
            if other.name == 'LincombOperator' and isinstance(
                    other, LincombOperator):
                operators = (self, ) + other.operators
                coefficients = (1., ) + (other.coefficients if sign == 1. else
                                         tuple(-c for c in other.coefficients))
            else:
                operators, coefficients = (self, other), (1., sign)
        elif other.name == 'LincombOperator' and isinstance(
                other, LincombOperator):
            operators = self.operators + other.operators
            coefficients = self.coefficients + (
                other.coefficients if sign == 1. else tuple(
                    -c for c in other.coefficients))
        else:
            operators, coefficients = self.operators + (
                other, ), self.coefficients + (sign, )

        return LincombOperator(operators,
                               coefficients,
                               solver_options=self.solver_options)
Example #8
0
def mpi_wrap_operator(obj_id, mpi_range, mpi_source, with_apply2=False, pickle_local_spaces=True,
                      space_type=MPIVectorSpace):
    """Wrap MPI distributed local |Operators| to a global |Operator| on rank 0.

    Given MPI distributed local |Operators| referred to by the
    :class:`~pymor.tools.mpi.ObjectId` `obj_id`, return a new |Operator|
    which manages these distributed operators from rank 0. This
    is done by instantiating :class:`MPIOperator`. Additionally, the
    structure of the wrapped operators is preserved. E.g. |LincombOperators|
    will be wrapped as a |LincombOperator| of :class:`MPIOperators <MPIOperator>`.

    Parameters
    ----------
    See :class:`MPIOperator`.

    Returns
    -------
    The wrapped |Operator|.
    """
    op = mpi.get_object(obj_id)
    if isinstance(op, LincombOperator):
        obj_ids = mpi.call(_mpi_wrap_operator_LincombOperator_manage_operators, obj_id)
        return LincombOperator([mpi_wrap_operator(o, mpi_range, mpi_source, with_apply2, pickle_local_spaces,
                                                  space_type)
                                for o in obj_ids], op.coefficients, name=op.name)
    elif isinstance(op, VectorArrayOperator):
        array_obj_id, local_spaces = mpi.call(_mpi_wrap_operator_VectorArrayOperator_manage_array,
                                              obj_id, pickle_local_spaces)
        if all(ls == local_spaces[0] for ls in local_spaces):
            local_spaces = (local_spaces[0],)
        return VectorArrayOperator(space_type(local_spaces).make_array(array_obj_id),
                                   adjoint=op.adjoint, name=op.name)
    else:
        return MPIOperator(obj_id, mpi_range, mpi_source, with_apply2, pickle_local_spaces, space_type)
Example #9
0
 def __add__(self, other):
     if not isinstance(other, OperatorInterface):
         return NotImplemented
     from pymor.operators.constructions import LincombOperator
     if isinstance(other, LincombOperator):
         return NotImplemented
     else:
         return LincombOperator([self, other], [1., 1.])
Example #10
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)
Example #11
0
 def __mul__(self, other):
     assert isinstance(other, (Number, ParameterFunctional))
     from pymor.operators.constructions import LincombOperator
     if self.name != 'LincombOperator' or not isinstance(
             self, LincombOperator):
         return LincombOperator((self, ), (other, ))
     else:
         return self.with_(coefficients=tuple(c * other
                                              for c in self.coefficients))
Example #12
0
    def _build_dual_models(self):
        assert self.primal_rom is not None
        assert self.RBPrimal is not None
        RBbasis = self.RBPrimal
        rhs_operators = list(
            self.fom.output_functional_dict['d_u_linear_part'].operators)
        rhs_coefficients = list(
            self.fom.output_functional_dict['d_u_linear_part'].coefficients)

        bilinear_part = self.fom.output_functional_dict['d_u_bilinear_part']

        for i in range(len(RBbasis)):
            u = RBbasis[i]
            if isinstance(bilinear_part, LincombOperator):
                for j, op in enumerate(bilinear_part.operators):
                    rhs_operators.append(VectorOperator(op.apply(u)))
                    rhs_coefficients.append(
                        ExpressionParameterFunctional(
                            'basis_coefficients[{}]'.format(i),
                            {'basis_coefficients': len(RBbasis)}) *
                        bilinear_part.coefficients[j])
            else:
                rhs_operators.append(
                    VectorOperator(bilinear_part.apply(u, None)))
                rhs_coefficients.append(1. * ExpressionParameterFunctional(
                    'basis_coefficients[{}]'.format(i),
                    {'basis_coefficients': len(RBbasis)}))

        dual_rhs_operator = LincombOperator(rhs_operators, rhs_coefficients)

        dual_intermediate_fom = self.fom.primal_model.with_(
            rhs=dual_rhs_operator)

        if self.reductor_type == 'simple_coercive':
            print('building simple coercive dual reductor...')
            dual_reductor = SimpleCoerciveRBReductor(
                dual_intermediate_fom,
                RB=self.RBDual,
                product=self.opt_product,
                coercivity_estimator=self.coercivity_estimator)
        elif self.reductor_type == 'non_assembled':
            print('building non assembled dual reductor...')
            dual_reductor = NonAssembledCoerciveRBReductor(
                dual_intermediate_fom,
                RB=self.RBDual,
                product=self.opt_product,
                coercivity_estimator=self.coercivity_estimator)
        else:
            print('building coercive dual reductor...')
            dual_reductor = CoerciveRBReductor(
                dual_intermediate_fom,
                RB=self.RBDual,
                product=self.opt_product,
                coercivity_estimator=self.coercivity_estimator)

        dual_rom = dual_reductor.reduce()
        return dual_intermediate_fom, dual_rom, dual_reductor
Example #13
0
 def __add__(self, other):
     """Sum of two operators."""
     if other == 0:
         return self
     if not isinstance(other, Operator):
         return NotImplemented
     from pymor.operators.constructions import LincombOperator
     if isinstance(other, LincombOperator):
         return NotImplemented
     else:
         return LincombOperator([self, other], [1., 1.])
Example #14
0
def test_d_mu_of_LincombOperator():
    dict_of_d_mus = {'mu': ['100', '2'], 'nu': 'cos(nu)'}

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

    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)

    assert operator.evaluate_coefficients(mu) == [1., 10, 1004.]
    assert eval_mu_1 == [0., 1., 100.]
    assert eval_mu_2 == [0., 0., 2.]
    assert eval_nu == [0., 0., 1.]
Example #15
0
 def create_product(products, product_type):
     if product_type is None:
         return None, 'None'
     if not isinstance(product_type, tuple):
         return products[product_type], product_type
     else:
         prods = [products[tt] for tt in product_type]
         product_name = product_type[0]
         for ii in np.arange(1, len(product_type)):
             product_name += '_plus_' + product_type[ii]
         return LincombOperator(operators=prods,
                                coefficients=[1 for pp in prods
                                              ]), product_name
Example #16
0
    def _reduce(self):
        d = self.d

        self.logger.info('Computing oswald interpolations ...')
        oi = d.estimator.oswald_interpolation_error

        oi_red = []
        for i, OI_i_space in enumerate(oi.range.subspaces):
            oi_i = oi._blocks[i, i]
            basis = self.bases[oi_i.source.id]
            self.bases[OI_i_space.id] = oi_i.apply(basis)
            oi_red.append(
                NumpyMatrixOperator(np.eye(len(basis)),
                                    source_id=oi_i.source.id,
                                    range_id=oi_i.range.id))
        oi_red = unblock(BlockDiagonalOperator(oi_red))

        self.logger.info('Computing flux reconstructions ...')
        fr = d.estimator.flux_reconstruction

        for i, RT_i_space in enumerate(fr.range.subspaces):
            self.bases[RT_i_space.id] = RT_i_space.empty()

        red_aff_components = []
        for i_aff, aff_component in enumerate(fr.operators):
            red_aff_component = []
            for i, RT_i_space in enumerate(aff_component.range.subspaces):
                fr_i = aff_component._blocks[i, i]
                basis = self.bases[fr_i.source.id]
                self.bases[RT_i_space.id].append(fr_i.apply(basis))
                M = np.zeros((len(basis) * len(fr.operators), len(basis)))
                M[i_aff * len(basis):(i_aff + 1) * len(basis), :] = np.eye(
                    len(basis))
                red_aff_component.append(
                    NumpyMatrixOperator(M,
                                        source_id=fr_i.source.id,
                                        range_id=fr_i.range.id))
            red_aff_components.append(BlockDiagonalOperator(red_aff_component))
        fr_red = LincombOperator(red_aff_components, fr.coefficients)
        fr_red = unblock(fr_red)

        red_estimator = d.estimator.with_(flux_reconstruction=fr_red,
                                          oswald_interpolation_error=oi_red)

        rd = super()._reduce()
        rd = rd.with_(estimator=red_estimator)

        return rd
Example #17
0
def mpi_wrap_operator(obj_id,
                      functional=False,
                      vector=False,
                      with_apply2=False,
                      pickle_subtypes=True,
                      array_type=MPIVectorArray):
    """Wrap MPI distributed local |Operators| to a global |Operator| on rank 0.

    Given MPI distributed local |Operators| referred to by the
    `~pymor.tools.mpi.ObjectId` `obj_id`, return a new |Operator|
    which manages these distributed operators from rank 0. This
    is done by instantiating :class:`MPIOperator`. Additionally, the
    structure of the wrapped operators is preserved. E.g. |LincombOperators|
    will be wrapped as a |LincombOperator| of :class:`MPIOperators`.

    Parameters
    ----------
    See :class:`MPIOperator`.

    Returns
    -------
    The wrapped |Operator|.
    """
    op = mpi.get_object(obj_id)
    if isinstance(op, LincombOperator):
        obj_ids = mpi.call(_mpi_wrap_operator_LincombOperator_manage_operators,
                           obj_id)
        return LincombOperator([
            mpi_wrap_operator(o, functional, vector, with_apply2,
                              pickle_subtypes, array_type) for o in obj_ids
        ],
                               op.coefficients,
                               name=op.name)
    elif isinstance(op, VectorArrayOperator):
        array_obj_id, subtypes = mpi.call(
            _mpi_wrap_operator_VectorArrayOperator_manage_array, obj_id,
            pickle_subtypes)
        if all(subtype == subtypes[0] for subtype in subtypes):
            subtypes = (subtypes[0], )
        return VectorArrayOperator(array_type(type(op._array), subtypes,
                                              array_obj_id),
                                   transposed=op.transposed,
                                   name=op.name)
    else:
        return MPIOperator(obj_id, functional, vector, with_apply2,
                           pickle_subtypes, array_type)
Example #18
0
    def _localizedly_project_operator(self, op):
        if isinstance(op, LincombOperator):
            ops = [
                self._localizedly_project_operator(foo) for foo in op.operators
            ]
            return LincombOperator(ops, coefficients=op.coefficients)
        assert op.linear and not op.parametric

        mats = [[
            None if (op.uid, source_space,
                     range_space) not in self.reduced_localized_operators else
            self.reduced_localized_operators[(op.uid, source_space,
                                              range_space)].matrix
            for source_space in self.source_spaces
        ] for range_space in self.range_spaces]
        result = NumpyMatrixOperator(scipy.sparse.bmat(mats).tocsc())
        return result
Example #19
0
 def unblock_op(op, sparse=False):
     assert op._blocks[0][0] is not None
     if isinstance(op._blocks[0][0], LincombOperator):
         coefficients = op._blocks[0][0].coefficients
         operators = [
             None for kk in np.arange(len(op._blocks[0][0].operators))
         ]
         for kk in np.arange(len(op._blocks[0][0].operators)):
             ops = [[
                 op._blocks[ii][jj].operators[kk]
                 if op._blocks[ii][jj] is not None else None
                 for jj in np.arange(op.num_source_blocks)
             ] for ii in np.arange(op.num_range_blocks)]
             operators[kk] = unblock_op(BlockOperator(ops))
         return LincombOperator(operators=operators,
                                coefficients=coefficients)
     else:
         assert all(
             all([
                 isinstance(block, NumpyMatrixOperator
                            ) if block is not None else True
                 for block in row
             ]) for row in op._blocks)
         if op.source.dim == 0 and op.range.dim == 0:
             return NumpyMatrixOperator(np.zeros((0, 0)))
         elif op.source.dim == 1:
             mat = np.concatenate([
                 op._blocks[ii][0]._matrix
                 for ii in np.arange(op.num_range_blocks)
             ],
                                  axis=1)
         elif op.range.dim == 1:
             mat = np.concatenate([
                 op._blocks[0][jj]._matrix
                 for jj in np.arange(op.num_source_blocks)
             ],
                                  axis=1)
         else:
             mat = bmat([[
                 coo_matrix(op._blocks[ii][jj]._matrix)
                 if op._blocks[ii][jj] is not None else coo_matrix(
                     (op._range_dims[ii], op._source_dims[jj]))
                 for jj in np.arange(op.num_source_blocks)
             ] for ii in np.arange(op.num_range_blocks)])
             mat = mat.toarray()
         return NumpyMatrixOperator(mat)
Example #20
0
def test_output_d_mu():
    from pymordemos.linear_optimization import create_fom

    grid_intervals = 10
    training_samples = 3

    fom, mu_bar = create_fom(grid_intervals, vector_valued_output=True)
    easy_fom, _ = create_fom(grid_intervals, vector_valued_output=False)

    parameter_space = fom.parameters.space(0, np.pi)
    training_set = parameter_space.sample_uniformly(training_samples)

    #verifying that the adjoint and sensitivity gradients are the same and that solve_d_mu works
    for mu in training_set:
        gradient_with_adjoint_approach = fom.output_d_mu(mu, return_array=True, use_adjoint=True)
        gradient_with_sensitivities = fom.output_d_mu(mu, return_array=True, use_adjoint=False)
        assert np.allclose(gradient_with_adjoint_approach, gradient_with_sensitivities)
        u_d_mu = fom.solve_d_mu('diffusion', 1, mu=mu).to_numpy()
        u_d_mu_ = fom.compute(solution_d_mu=True, mu=mu)['solution_d_mu']['diffusion'][1].to_numpy()
        assert np.allclose(u_d_mu, u_d_mu_)

        # test the complex case
        complex_fom = easy_fom.with_(operator=easy_fom.operator.with_(
            operators=[op* (1+2j) for op in easy_fom.operator.operators]))
        complex_gradient_adjoint = complex_fom.output_d_mu(mu, return_array=True, use_adjoint=True)
        complex_gradient = complex_fom.output_d_mu(mu, return_array=True, use_adjoint=False)
        assert np.allclose(complex_gradient_adjoint, complex_gradient)

        complex_fom = easy_fom.with_(output_functional=easy_fom.output_functional.with_(
            operators=[op* (1+2j) for op in easy_fom.output_functional.operators]))
        complex_gradient_adjoint = complex_fom.output_d_mu(mu, return_array=True, use_adjoint=True)
        complex_gradient = complex_fom.output_d_mu(mu, return_array=True, use_adjoint=False)
        assert np.allclose(complex_gradient_adjoint, complex_gradient)

    # another fom to test the 3d case
    ops, coefs = fom.operator.operators, fom.operator.coefficients
    ops += (fom.operator.operators[1],)
    coefs += (ProjectionParameterFunctional('nu', 1, 0),)
    fom_ = fom.with_(operator=LincombOperator(ops, coefs))
    parameter_space = fom_.parameters.space(0, np.pi)
    training_set = parameter_space.sample_uniformly(training_samples)
    for mu in training_set:
        gradient_with_adjoint_approach = fom_.output_d_mu(mu, return_array=True, use_adjoint=True)
        gradient_with_sensitivities = fom_.output_d_mu(mu, return_array=True, use_adjoint=False)
        assert np.allclose(gradient_with_adjoint_approach, gradient_with_sensitivities)
Example #21
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].data
    rhs_data[:] = np.ones(len(rhs_data))
    rhs_data[0] = 0
    rhs_data[len(rhs_data) - 1] = 0
    rhs = VectorFunctional(rhs_vec)

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

    time_stepper = ExplicitEulerTimeStepper(nt)
    parameter_space = CubicParameterSpace(operator.parameter_type, 0.1, 1)

    d = InstationaryDiscretization(T=1e-0,
                                   operator=operator,
                                   rhs=rhs,
                                   initial_data=initial_data,
                                   time_stepper=time_stepper,
                                   num_values=20,
                                   parameter_space=parameter_space,
                                   visualizer=visualizer,
                                   name='C++-Discretization',
                                   cache_region=None)
    return d
Example #22
0
    def _localizedly_project_functional(self, op):
        if isinstance(op, LincombOperator):
            ops = [
                self._localizedly_project_functional(foo)
                for foo in op.operators
            ]
            return LincombOperator(ops, coefficients=op.coefficients)

        assert op.linear and not op.parametric
        v = op.as_vector()

        def project_block(ids, basis):
            o = self.l.localize_vector_array(v, ids)
            if basis is None:
                return o.data
            else:
                return basis.dot(o).T

        mats = [
            project_block(ids, basis)
            for ids, basis in zip(self.range_spaces, self.range_bases)
        ]
        return NumpyVectorSpace.make_array(np.concatenate(mats, axis=1))
def discretize(grid_and_problem_data, solver_options, mpi_comm):
    ################ Setup

    logger = getLogger('discretize_elliptic_block_swipdg.discretize')
    logger.info('discretizing ... ')

    grid, boundary_info = grid_and_problem_data['grid'], grid_and_problem_data[
        'boundary_info']
    local_all_dirichlet_boundary_info = make_subdomain_boundary_info(
        grid, {'type': 'xt.grid.boundaryinfo.alldirichlet'})
    local_subdomains, num_local_subdomains, num_global_subdomains = _get_subdomains(
        grid)
    local_all_neumann_boundary_info = make_subdomain_boundary_info(
        grid, {'type': 'xt.grid.boundaryinfo.allneumann'})

    block_space = make_block_dg_space(grid)
    global_rt_space = make_rt_space(grid)
    subdomain_rt_spaces = [
        global_rt_space.restrict_to_dd_subdomain_view(grid, ii)
        for ii in range(num_global_subdomains)
    ]

    local_patterns = [
        block_space.local_space(ii).compute_pattern('face_and_volume')
        for ii in range(block_space.num_blocks)
    ]
    coupling_patterns = {
        'in_in': {},
        'out_out': {},
        'in_out': {},
        'out_in': {}
    }
    coupling_matrices = {
        'in_in': {},
        'out_out': {},
        'in_out': {},
        'out_in': {}
    }

    for ii in range(num_global_subdomains):
        ii_size = block_space.local_space(ii).size()
        for jj in grid.neighboring_subdomains(ii):
            jj_size = block_space.local_space(jj).size()
            if ii < jj:  # Assemble primally (visit each coupling only once).
                coupling_patterns['in_in'][(ii, jj)] = block_space.local_space(
                    ii).compute_pattern('face_and_volume')
                coupling_patterns['out_out'][(
                    ii, jj)] = block_space.local_space(jj).compute_pattern(
                        'face_and_volume')
                coupling_patterns['in_out'][(
                    ii, jj)] = block_space.compute_coupling_pattern(
                        ii, jj, 'face')
                coupling_patterns['out_in'][(
                    ii, jj)] = block_space.compute_coupling_pattern(
                        jj, ii, 'face')
                coupling_matrices['in_in'][(ii, jj)] = Matrix(
                    ii_size, ii_size, coupling_patterns['in_in'][(ii, jj)])
                coupling_matrices['out_out'][(ii, jj)] = Matrix(
                    jj_size, jj_size, coupling_patterns['out_out'][(ii, jj)])
                coupling_matrices['in_out'][(ii, jj)] = Matrix(
                    ii_size, jj_size, coupling_patterns['in_out'][(ii, jj)])
                coupling_matrices['out_in'][(ii, jj)] = Matrix(
                    jj_size, ii_size, coupling_patterns['out_in'][(ii, jj)])
    boundary_patterns = {}
    for ii in grid.boundary_subdomains():
        boundary_patterns[ii] = block_space.local_space(ii).compute_pattern(
            'face_and_volume')

    ################ Assemble LHS and RHS

    lambda_, kappa = grid_and_problem_data['lambda'], grid_and_problem_data[
        'kappa']
    if isinstance(lambda_, dict):
        lambda_funcs = lambda_['functions']
        lambda_coeffs = lambda_['coefficients']
    else:
        lambda_funcs = [
            lambda_,
        ]
        lambda_coeffs = [
            1,
        ]

    logger.debug('block op ... ')
    ops, block_ops = zip(*(discretize_lhs(
        lf, grid, block_space, local_patterns, boundary_patterns,
        coupling_matrices, kappa, local_all_neumann_boundary_info,
        boundary_info, coupling_patterns, solver_options)
                           for lf in lambda_funcs))
    global_operator = LincombOperator(ops,
                                      lambda_coeffs,
                                      solver_options=solver_options,
                                      name='GlobalOperator')
    logger.debug('block op global done ')
    block_op = LincombOperator(block_ops,
                               lambda_coeffs,
                               name='lhs',
                               solver_options=solver_options)
    logger.debug('block op done ')

    f = grid_and_problem_data['f']
    if isinstance(f, dict):
        f_funcs = f['functions']
        f_coeffs = f['coefficients']
    else:
        f_funcs = [
            f,
        ]
        f_coeffs = [
            1,
        ]
    rhss, block_rhss = zip(*(discretize_rhs(
        ff, grid, block_space, global_operator, block_ops, block_op)
                             for ff in f_funcs))
    global_rhs = LincombOperator(rhss, f_coeffs)
    block_rhs = LincombOperator(block_rhss, f_coeffs)

    solution_space = block_op.source

    ################ Assemble interpolation and reconstruction operators
    logger.info('discretizing interpolation ')

    # Oswald interpolation error operator
    oi_op = BlockDiagonalOperator([
        OswaldInterpolationErrorOperator(ii, block_op.source, grid,
                                         block_space)
        for ii in range(num_global_subdomains)
    ],
                                  name='oswald_interpolation_error')

    # Flux reconstruction operator
    fr_op = LincombOperator([
        BlockDiagonalOperator([
            FluxReconstructionOperator(ii, block_op.source, grid, block_space,
                                       global_rt_space, subdomain_rt_spaces,
                                       lambda_xi, kappa)
            for ii in range(num_global_subdomains)
        ]) for lambda_xi in lambda_funcs
    ],
                            lambda_coeffs,
                            name='flux_reconstruction')

    ################ Assemble inner products and error estimator operators
    logger.info('discretizing inner products ')

    lambda_bar, lambda_hat = grid_and_problem_data[
        'lambda_bar'], grid_and_problem_data['lambda_hat']
    mu_bar, mu_hat = grid_and_problem_data['mu_bar'], grid_and_problem_data[
        'mu_hat']
    operators = {}
    local_projections = []
    local_rt_projections = []
    local_oi_projections = []
    local_div_ops = []
    local_l2_products = []
    data = dict(grid=grid,
                block_space=block_space,
                local_projections=local_projections,
                local_rt_projections=local_rt_projections,
                local_oi_projections=local_oi_projections,
                local_div_ops=local_div_ops,
                local_l2_products=local_l2_products)

    for ii in range(num_global_subdomains):

        neighborhood = grid.neighborhood_of(ii)

        ################ Assemble local inner products

        local_dg_space = block_space.local_space(ii)
        # we want a larger pattern to allow for axpy with other matrices
        tmp_local_matrix = Matrix(
            local_dg_space.size(), local_dg_space.size(),
            local_dg_space.compute_pattern('face_and_volume'))
        local_energy_product_ops = []
        local_energy_product_coeffs = []
        for func, coeff in zip(lambda_funcs, lambda_coeffs):
            local_energy_product_ops.append(
                make_elliptic_matrix_operator(func,
                                              kappa,
                                              tmp_local_matrix.copy(),
                                              local_dg_space,
                                              over_integrate=0))
            local_energy_product_coeffs.append(coeff)
            local_energy_product_ops.append(
                make_penalty_product_matrix_operator(
                    grid,
                    ii,
                    local_all_dirichlet_boundary_info,
                    local_dg_space,
                    func,
                    kappa,
                    over_integrate=0))
            local_energy_product_coeffs.append(coeff)
        local_l2_product = make_l2_matrix_operator(tmp_local_matrix.copy(),
                                                   local_dg_space)
        del tmp_local_matrix
        local_assembler = make_system_assembler(local_dg_space)
        for local_product_op in local_energy_product_ops:
            local_assembler.append(local_product_op)
        local_assembler.append(local_l2_product)
        local_assembler.assemble()
        local_energy_product_name = 'local_energy_dg_product_{}'.format(ii)
        local_energy_product = LincombOperator([
            DuneXTMatrixOperator(op.matrix(),
                                 source_id='domain_{}'.format(ii),
                                 range_id='domain_{}'.format(ii))
            for op in local_energy_product_ops
        ],
                                               local_energy_product_coeffs,
                                               name=local_energy_product_name)
        operators[local_energy_product_name] = \
            local_energy_product.assemble(mu_bar).with_(name=local_energy_product_name)

        local_l2_product = DuneXTMatrixOperator(
            local_l2_product.matrix(),
            source_id='domain_{}'.format(ii),
            range_id='domain_{}'.format(ii))
        local_l2_products.append(local_l2_product)

        # assemble local elliptic product
        matrix = make_local_elliptic_matrix_operator(grid, ii, local_dg_space,
                                                     lambda_bar, kappa)
        matrix.assemble()
        local_elliptic_product = DuneXTMatrixOperator(
            matrix.matrix(),
            range_id='domain_{}'.format(ii),
            source_id='domain_{}'.format(ii))

        ################ Assemble local to global projections

        # assemble projection (solution space) ->  (ii space)
        local_projection = BlockProjectionOperator(block_op.source, ii)
        local_projections.append(local_projection)

        # assemble projection (RT spaces on neighborhoods of subdomains) ->  (local RT space on ii)
        ops = np.full(num_global_subdomains, None)
        for kk in neighborhood:
            component = grid.neighborhood_of(kk).index(ii)
            assert fr_op.range.subspaces[kk].subspaces[
                component].id == 'LOCALRT_{}'.format(ii)
            ops[kk] = BlockProjectionOperator(fr_op.range.subspaces[kk],
                                              component)
        local_rt_projection = BlockRowOperator(
            ops,
            source_spaces=fr_op.range.subspaces,
            name='local_rt_projection_{}'.format(ii))
        local_rt_projections.append(local_rt_projection)

        # assemble projection (OI spaces on neighborhoods of subdomains) ->  (ii space)
        ops = np.full(num_global_subdomains, None)
        for kk in neighborhood:
            component = grid.neighborhood_of(kk).index(ii)
            assert oi_op.range.subspaces[kk].subspaces[
                component].id == 'domain_{}'.format(ii)
            ops[kk] = BlockProjectionOperator(oi_op.range.subspaces[kk],
                                              component)
        local_oi_projection = BlockRowOperator(
            ops,
            source_spaces=oi_op.range.subspaces,
            name='local_oi_projection_{}'.format(ii))
        local_oi_projections.append(local_oi_projection)

        ################ Assemble additional operators for error estimation

        # assemble local divergence operator
        local_rt_space = global_rt_space.restrict_to_dd_subdomain_view(
            grid, ii)
        local_div_op = make_divergence_matrix_operator_on_subdomain(
            grid, ii, local_dg_space, local_rt_space)
        local_div_op.assemble()
        local_div_op = DuneXTMatrixOperator(
            local_div_op.matrix(),
            source_id='LOCALRT_{}'.format(ii),
            range_id='domain_{}'.format(ii),
            name='local_divergence_{}'.format(ii))
        local_div_ops.append(local_div_op)

        ################ Assemble error estimator operators -- Nonconformity

        operators['nc_{}'.format(ii)] = \
            Concatenation([local_oi_projection.T, local_elliptic_product, local_oi_projection],
                          name='nonconformity_{}'.format(ii))

        ################ Assemble error estimator operators -- Residual

        if len(f_funcs) == 1:
            assert f_coeffs[0] == 1
            local_div = Concatenation([local_div_op, local_rt_projection])
            local_rhs = VectorFunctional(
                block_rhs.operators[0]._array._blocks[ii])

            operators['r_fd_{}'.format(ii)] = \
                Concatenation([local_rhs, local_div], name='r1_{}'.format(ii))

            operators['r_dd_{}'.format(ii)] = \
                Concatenation([local_div.T, local_l2_product, local_div], name='r2_{}'.format(ii))

        ################ Assemble error estimator operators -- Diffusive flux

        operators['df_aa_{}'.format(ii)] = LincombOperator(
            [
                assemble_estimator_diffusive_flux_aa(
                    lambda_xi, lambda_xi_prime, grid, ii, block_space,
                    lambda_hat, kappa, solution_space)
                for lambda_xi in lambda_funcs
                for lambda_xi_prime in lambda_funcs
            ], [
                ProductParameterFunctional([c1, c2]) for c1 in lambda_coeffs
                for c2 in lambda_coeffs
            ],
            name='diffusive_flux_aa_{}'.format(ii))

        operators['df_bb_{}'.format(
            ii)] = assemble_estimator_diffusive_flux_bb(
                grid, ii, subdomain_rt_spaces, lambda_hat, kappa,
                local_rt_projection)

        operators['df_ab_{}'.format(ii)] = LincombOperator(
            [
                assemble_estimator_diffusive_flux_ab(
                    lambda_xi, grid, ii, block_space, subdomain_rt_spaces,
                    lambda_hat, kappa, local_rt_projection, local_projection)
                for lambda_xi in lambda_funcs
            ],
            lambda_coeffs,
            name='diffusive_flux_ab_{}'.format(ii))

    ################ Final assembly
    logger.info('final assembly ')

    # instantiate error estimator
    min_diffusion_evs = np.array([
        min_diffusion_eigenvalue(grid, ii, lambda_hat, kappa)
        for ii in range(num_global_subdomains)
    ])
    subdomain_diameters = np.array(
        [subdomain_diameter(grid, ii) for ii in range(num_global_subdomains)])
    if len(f_funcs) == 1:
        assert f_coeffs[0] == 1
        local_eta_rf_squared = np.array([
            apply_l2_product(grid,
                             ii,
                             f_funcs[0],
                             f_funcs[0],
                             over_integrate=2)
            for ii in range(num_global_subdomains)
        ])
    else:
        local_eta_rf_squared = None
    estimator = EllipticEstimator(grid,
                                  min_diffusion_evs,
                                  subdomain_diameters,
                                  local_eta_rf_squared,
                                  lambda_coeffs,
                                  mu_bar,
                                  mu_hat,
                                  fr_op,
                                  oswald_interpolation_error=oi_op,
                                  mpi_comm=mpi_comm)
    l2_product = BlockDiagonalOperator(local_l2_products)

    # instantiate discretization
    neighborhoods = [
        grid.neighborhood_of(ii) for ii in range(num_global_subdomains)
    ]
    local_boundary_info = make_subdomain_boundary_info(
        grid_and_problem_data['grid'],
        {'type': 'xt.grid.boundaryinfo.alldirichlet'})
    d = DuneDiscretization(global_operator=global_operator,
                           global_rhs=global_rhs,
                           neighborhoods=neighborhoods,
                           enrichment_data=(grid, local_boundary_info, lambda_,
                                            kappa, f, block_space),
                           operator=block_op,
                           rhs=block_rhs,
                           visualizer=DuneGDTVisualizer(block_space),
                           operators=operators,
                           products={'l2': l2_product},
                           estimator=estimator,
                           data=data)
    parameter_range = grid_and_problem_data['parameter_range']
    logger.info('final assembly B')
    d = d.with_(parameter_space=CubicParameterSpace(
        d.parameter_type, parameter_range[0], parameter_range[1]))
    logger.info('final assembly C')
    return d, data
Example #24
0
def discretize_elliptic_cg(analytical_problem,
                           diameter=None,
                           domain_discretizer=None,
                           grid=None,
                           boundary_info=None):
    """Discretizes an |EllipticProblem| using finite elements.

    Parameters
    ----------
    analytical_problem
        The |EllipticProblem| to discretize.
    diameter
        If not `None`, `diameter` is passed to the `domain_discretizer`.
    domain_discretizer
        Discretizer to be used for discretizing the analytical domain. This has
        to be a function `domain_discretizer(domain_description, diameter, ...)`.
        If further arguments should be passed to the discretizer, use
        :func:`functools.partial`. If `None`, |discretize_domain_default| is used.
    grid
        Instead of using a domain discretizer, the |Grid| can also be passed directly
        using this parameter.
    boundary_info
        A |BoundaryInfo| specifying the boundary types of the grid boundary entities.
        Must be provided if `grid` is specified.

    Returns
    -------
    discretization
        The |Discretization| that has been generated.
    data
        Dictionary with the following entries:

            :grid:           The generated |Grid|.
            :boundary_info:  The generated |BoundaryInfo|.
    """

    assert isinstance(analytical_problem, EllipticProblem)
    assert grid is None or boundary_info is not None
    assert boundary_info is None or grid is not None
    assert grid is None or domain_discretizer is None

    if grid is None:
        domain_discretizer = domain_discretizer or discretize_domain_default
        if diameter is None:
            grid, boundary_info = domain_discretizer(analytical_problem.domain)
        else:
            grid, boundary_info = domain_discretizer(analytical_problem.domain,
                                                     diameter=diameter)

    assert isinstance(grid, (OnedGrid, TriaGrid, RectGrid))

    if isinstance(grid, RectGrid):
        Operator = cg.DiffusionOperatorQ1
        Functional = cg.L2ProductFunctionalQ1
    else:
        Operator = cg.DiffusionOperatorP1
        Functional = cg.L2ProductFunctionalP1

    p = analytical_problem

    if p.diffusion_functionals is not None:
        L0 = Operator(grid,
                      boundary_info,
                      diffusion_constant=0,
                      name='diffusion_boundary_part')

        Li = [
            Operator(grid,
                     boundary_info,
                     diffusion_function=df,
                     dirichlet_clear_diag=True,
                     name='diffusion_{}'.format(i))
            for i, df in enumerate(p.diffusion_functions)
        ]

        L = LincombOperator(operators=[L0] + Li,
                            coefficients=[1.] + list(p.diffusion_functionals),
                            name='diffusion')
    else:
        assert len(p.diffusion_functions) == 1
        L = Operator(grid,
                     boundary_info,
                     diffusion_function=p.diffusion_functions[0],
                     name='diffusion')

    F = Functional(grid,
                   p.rhs,
                   boundary_info,
                   dirichlet_data=p.dirichlet_data,
                   neumann_data=p.neumann_data)

    if isinstance(grid, (TriaGrid, RectGrid)):
        visualizer = PatchVisualizer(grid=grid,
                                     bounding_box=grid.domain,
                                     codim=2)
    else:
        visualizer = Matplotlib1DVisualizer(grid=grid, codim=1)

    empty_bi = EmptyBoundaryInfo(grid)
    l2_product = cg.L2ProductQ1(grid, empty_bi) if isinstance(
        grid, RectGrid) else cg.L2ProductP1(grid, empty_bi)
    h1_semi_product = Operator(grid, empty_bi)
    products = {
        'h1': l2_product + h1_semi_product,
        'h1_semi': h1_semi_product,
        'l2': l2_product
    }

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

    discretization = StationaryDiscretization(L,
                                              F,
                                              products=products,
                                              visualizer=visualizer,
                                              parameter_space=parameter_space,
                                              name='{}_CG'.format(p.name))

    return discretization, {'grid': grid, 'boundary_info': boundary_info}
def discretize(grid_and_problem_data, polorder=1, solver_options=None):

    logger = getLogger('discretize_elliptic_swipdg.discretize')
    logger.info('discretizing ... ')
    over_integrate = 2

    grid, boundary_info = grid_and_problem_data['grid'], grid_and_problem_data[
        'boundary_info']

    _lambda, kappa, f = (grid_and_problem_data['lambda'],
                         grid_and_problem_data['kappa'],
                         grid_and_problem_data['f'])
    lambda_bar, lambda_bar = grid_and_problem_data[
        'lambda_bar'], grid_and_problem_data['lambda_bar']
    mu_bar, mu_hat, parameter_range = (
        grid_and_problem_data['mu_bar'], grid_and_problem_data['mu_hat'],
        grid_and_problem_data['parameter_range'])
    space = make_dg_space(grid)
    # prepare operators and functionals
    if isinstance(_lambda, dict):
        system_ops = [
            make_elliptic_swipdg_matrix_operator(lambda_func, kappa,
                                                 boundary_info, space,
                                                 over_integrate)
            for lambda_func in _lambda['functions']
        ]
        elliptic_ops = [
            make_elliptic_matrix_operator(lambda_func, kappa, space,
                                          over_integrate)
            for lambda_func in _lambda['functions']
        ]
    else:
        system_ops = [
            make_elliptic_swipdg_matrix_operator(_lambda, kappa, boundary_info,
                                                 space, over_integrate),
        ]
        elliptic_ops = [
            make_elliptic_matrix_operator(_lambda, kappa, space,
                                          over_integrate),
        ]
    if isinstance(f, dict):
        rhs_functionals = [
            make_l2_volume_vector_functional(f_func, space, over_integrate)
            for f_func in f['functions']
        ]
    else:
        rhs_functionals = [
            make_l2_volume_vector_functional(f, space, over_integrate),
        ]
    l2_matrix_with_system_pattern = system_ops[0].matrix().copy()
    l2_operator = make_l2_matrix_operator(l2_matrix_with_system_pattern, space)
    # assemble everything in one grid walk
    system_assembler = make_system_assembler(space)
    for op in system_ops:
        system_assembler.append(op)
    for op in elliptic_ops:
        system_assembler.append(op)
    for func in rhs_functionals:
        system_assembler.append(func)
    system_assembler.append(l2_operator)
    system_assembler.walk()
    # wrap everything
    if isinstance(_lambda, dict):
        op = LincombOperator([
            DuneXTMatrixOperator(o.matrix(),
                                 dof_communicator=space.dof_communicator)
            for o in system_ops
        ], _lambda['coefficients'])
        elliptic_op = LincombOperator(
            [DuneXTMatrixOperator(o.matrix()) for o in elliptic_ops],
            _lambda['coefficients'])
    else:
        op = DuneXTMatrixOperator(system_ops[0].matrix())
        elliptic_op = DuneXTMatrixOperator(elliptic_ops[0].matrix())
    if isinstance(f, dict):
        rhs = LincombOperator([
            VectorFunctional(op.range.make_array([func.vector()]))
            for func in rhs_functionals
        ], f['coefficients'])
    else:
        rhs = VectorFunctional(
            op.range.make_array([rhs_functionals[0].vector()]))
    operators = {
        'l2':
        DuneXTMatrixOperator(l2_matrix_with_system_pattern),
        'elliptic':
        elliptic_op,
        'elliptic_mu_bar':
        DuneXTMatrixOperator(elliptic_op.assemble(mu=mu_bar).matrix)
    }
    d = StationaryDiscretization(op,
                                 rhs,
                                 operators=operators,
                                 visualizer=DuneGDTVisualizer(space))
    d = d.with_(parameter_space=CubicParameterSpace(
        d.parameter_type, parameter_range[0], parameter_range[1]))

    return d, {'space': space}
Example #26
0
 def _K_apply_inverse_adjoint(self, s, V):
     Ks = LincombOperator(
         (self.fom.E, self.fom.A) + self.fom.Ad,
         (s, -1) + tuple(-np.exp(-taui * s) for taui in self.fom.tau))
     return Ks.apply_inverse_adjoint(V, mu=self.mu)
Example #27
0
 def __mul__(self, other):
     if not isinstance(other, (Number, ParameterFunctionalInterface)):
         return NotImplemented
     from pymor.operators.constructions import LincombOperator
     return LincombOperator([self], [other])
Example #28
0
 def _K_apply_inverse_adjoint(self, s, V):
     Ks = LincombOperator((self.d.E, self.d.A) + self.d.Ad,
                          (s, -1) + tuple(-np.exp(-taui * s) for taui in self.d.tau))
     return Ks.apply_inverse_adjoint(V)
Example #29
0
def discretize_stationary_cg(analytical_problem,
                             diameter=None,
                             domain_discretizer=None,
                             grid_type=None,
                             grid=None,
                             boundary_info=None,
                             preassemble=True):
    """Discretizes a |StationaryProblem| using finite elements.

    Parameters
    ----------
    analytical_problem
        The |StationaryProblem| to discretize.
    diameter
        If not `None`, `diameter` is passed as an argument to the `domain_discretizer`.
    domain_discretizer
        Discretizer to be used for discretizing the analytical domain. This has
        to be a function `domain_discretizer(domain_description, diameter, ...)`.
        If `None`, |discretize_domain_default| is used.
    grid_type
        If not `None`, this parameter is forwarded to `domain_discretizer` to specify
        the type of the generated |Grid|.
    grid
        Instead of using a domain discretizer, the |Grid| can also be passed directly
        using this parameter.
    boundary_info
        A |BoundaryInfo| specifying the boundary types of the grid boundary entities.
        Must be provided if `grid` is specified.
    preassemble
        If `True`, preassemble all operators in the resulting |Model|.

    Returns
    -------
    m
        The |Model| that has been generated.
    data
        Dictionary with the following entries:

            :grid:           The generated |Grid|.
            :boundary_info:  The generated |BoundaryInfo|.
            :unassembled_m:  In case `preassemble` is `True`, the generated |Model|
                             before preassembling operators.
    """

    assert isinstance(analytical_problem, StationaryProblem)
    assert grid is None or boundary_info is not None
    assert boundary_info is None or grid is not None
    assert grid is None or domain_discretizer is None
    assert grid_type is None or grid is None

    p = analytical_problem

    if not (p.nonlinear_advection == p.nonlinear_advection_derivative ==
            p.nonlinear_reaction == p.nonlinear_reaction_derivative is None):
        raise NotImplementedError

    if grid is None:
        domain_discretizer = domain_discretizer or discretize_domain_default
        if grid_type:
            domain_discretizer = partial(domain_discretizer,
                                         grid_type=grid_type)
        if diameter is None:
            grid, boundary_info = domain_discretizer(p.domain)
        else:
            grid, boundary_info = domain_discretizer(p.domain,
                                                     diameter=diameter)

    assert grid.reference_element in (line, triangle, square)

    if grid.reference_element is square:
        DiffusionOperator = DiffusionOperatorQ1
        AdvectionOperator = AdvectionOperatorQ1
        ReactionOperator = L2ProductQ1
        L2Functional = L2ProductFunctionalQ1
        BoundaryL2Functional = BoundaryL2ProductFunctional
    else:
        DiffusionOperator = DiffusionOperatorP1
        AdvectionOperator = AdvectionOperatorP1
        ReactionOperator = L2ProductP1
        L2Functional = L2ProductFunctionalP1
        BoundaryL2Functional = BoundaryL2ProductFunctional

    Li = [
        DiffusionOperator(grid,
                          boundary_info,
                          diffusion_constant=0,
                          name='boundary_part')
    ]
    coefficients = [1.]

    # diffusion part
    if isinstance(p.diffusion, LincombFunction):
        Li += [
            DiffusionOperator(grid,
                              boundary_info,
                              diffusion_function=df,
                              dirichlet_clear_diag=True,
                              name=f'diffusion_{i}')
            for i, df in enumerate(p.diffusion.functions)
        ]
        coefficients += list(p.diffusion.coefficients)
    elif p.diffusion is not None:
        Li += [
            DiffusionOperator(grid,
                              boundary_info,
                              diffusion_function=p.diffusion,
                              dirichlet_clear_diag=True,
                              name='diffusion')
        ]
        coefficients.append(1.)

    # advection part
    if isinstance(p.advection, LincombFunction):
        Li += [
            AdvectionOperator(grid,
                              boundary_info,
                              advection_function=af,
                              dirichlet_clear_diag=True,
                              name=f'advection_{i}')
            for i, af in enumerate(p.advection.functions)
        ]
        coefficients += list(p.advection.coefficients)
    elif p.advection is not None:
        Li += [
            AdvectionOperator(grid,
                              boundary_info,
                              advection_function=p.advection,
                              dirichlet_clear_diag=True,
                              name='advection')
        ]
        coefficients.append(1.)

    # reaction part
    if isinstance(p.reaction, LincombFunction):
        Li += [
            ReactionOperator(grid,
                             boundary_info,
                             coefficient_function=rf,
                             dirichlet_clear_diag=True,
                             name=f'reaction_{i}')
            for i, rf in enumerate(p.reaction.functions)
        ]
        coefficients += list(p.reaction.coefficients)
    elif p.reaction is not None:
        Li += [
            ReactionOperator(grid,
                             boundary_info,
                             coefficient_function=p.reaction,
                             dirichlet_clear_diag=True,
                             name='reaction')
        ]
        coefficients.append(1.)

    # robin boundaries
    if p.robin_data is not None:
        assert isinstance(p.robin_data, tuple) and len(p.robin_data) == 2
        if isinstance(p.robin_data[0], LincombFunction):
            for i, rd in enumerate(p.robin_data[0].functions):
                robin_tuple = (rd, p.robin_data[1])
                Li += [
                    RobinBoundaryOperator(grid,
                                          boundary_info,
                                          robin_data=robin_tuple,
                                          name=f'robin_{i}')
                ]
            coefficients += list(p.robin_data[0].coefficients)
        else:
            Li += [
                RobinBoundaryOperator(grid,
                                      boundary_info,
                                      robin_data=p.robin_data,
                                      name=f'robin')
            ]
            coefficients.append(1.)

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

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

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

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

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

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

    if grid.reference_element in (triangle, square):
        visualizer = PatchVisualizer(grid=grid,
                                     bounding_box=grid.bounding_box(),
                                     codim=2)
    elif grid.reference_element is line:
        visualizer = OnedVisualizer(grid=grid, codim=1)
    else:
        visualizer = None

    Prod = L2ProductQ1 if grid.reference_element is square else L2ProductP1
    empty_bi = EmptyBoundaryInfo(grid)
    l2_product = Prod(grid, empty_bi, name='l2')
    l2_0_product = Prod(grid,
                        boundary_info,
                        dirichlet_clear_columns=True,
                        name='l2_0')
    h1_semi_product = DiffusionOperator(grid, empty_bi, name='h1_semi')
    h1_0_semi_product = DiffusionOperator(grid,
                                          boundary_info,
                                          dirichlet_clear_columns=True,
                                          name='h1_0_semi')
    products = {
        'h1': l2_product + h1_semi_product,
        'h1_semi': h1_semi_product,
        'l2': l2_product,
        'h1_0': l2_0_product + h1_0_semi_product,
        'h1_0_semi': h1_0_semi_product,
        'l2_0': l2_0_product
    }

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

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

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

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

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

    return m, data
Example #30
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
Example #31
0
def _discretize_fenics(xblocks, yblocks, grid_num_intervals, element_order):

    # assemble system matrices - FEniCS code
    ########################################

    import dolfin as df
    mesh = df.UnitSquareMesh(grid_num_intervals, grid_num_intervals, 'crossed')
    V = df.FunctionSpace(mesh, 'Lagrange', element_order)
    u = df.TrialFunction(V)
    v = df.TestFunction(V)

    diffusion = df.Expression('(lower0 <= x[0]) * (open0 ? (x[0] < upper0) : (x[0] <= upper0)) *'
                              '(lower1 <= x[1]) * (open1 ? (x[1] < upper1) : (x[1] <= upper1))',
                              lower0=0., upper0=0., open0=0,
                              lower1=0., upper1=0., open1=0,
                              element=df.FunctionSpace(mesh, 'DG', 0).ufl_element())

    def assemble_matrix(x, y, nx, ny):
        diffusion.user_parameters['lower0'] = x/nx
        diffusion.user_parameters['lower1'] = y/ny
        diffusion.user_parameters['upper0'] = (x + 1)/nx
        diffusion.user_parameters['upper1'] = (y + 1)/ny
        diffusion.user_parameters['open0'] = (x + 1 == nx)
        diffusion.user_parameters['open1'] = (y + 1 == ny)
        return df.assemble(df.inner(diffusion * df.nabla_grad(u), df.nabla_grad(v)) * df.dx)

    mats = [assemble_matrix(x, y, xblocks, yblocks)
            for x in range(xblocks) for y in range(yblocks)]
    mat0 = mats[0].copy()
    mat0.zero()
    h1_mat = df.assemble(df.inner(df.nabla_grad(u), df.nabla_grad(v)) * df.dx)
    l2_mat = df.assemble(u * v * df.dx)

    f = df.Constant(1.) * v * df.dx
    F = df.assemble(f)

    bc = df.DirichletBC(V, 0., df.DomainBoundary())
    for m in mats:
        bc.zero(m)
    bc.apply(mat0)
    bc.apply(h1_mat)
    bc.apply(F)

    # wrap everything as a pyMOR model
    ##################################

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

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

    # define parameter functionals (same as in pymor.analyticalproblems.thermalblock)
    def parameter_functional_factory(x, y):
        return ProjectionParameterFunctional(component_name='diffusion',
                                             component_shape=(yblocks, xblocks),
                                             index=(yblocks - y - 1, x),
                                             name=f'diffusion_{x}_{y}')
    parameter_functionals = tuple(parameter_functional_factory(x, y)
                                  for x in range(xblocks) for y in range(yblocks))

    # wrap operators
    ops = [FenicsMatrixOperator(mat0, V, V)] + [FenicsMatrixOperator(m, V, V) for m in mats]
    op = LincombOperator(ops, (1.,) + parameter_functionals)
    rhs = VectorOperator(FenicsVectorSpace(V).make_array([F]))
    h1_product = FenicsMatrixOperator(h1_mat, V, V, name='h1_0_semi')
    l2_product = FenicsMatrixOperator(l2_mat, V, V, name='l2')

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

    return fom
    def solve_for_local_correction(self,
                                   subdomain,
                                   Us,
                                   mu=None,
                                   inverse_options=None):
        grid, local_boundary_info, affine_lambda, kappa, f, block_space = self.enrichment_data
        neighborhood = self.neighborhoods[subdomain]
        neighborhood_space = block_space.restricted_to_neighborhood(
            neighborhood)
        # Compute current solution restricted to the neighborhood to be usable as Dirichlet values for the correction
        # problem.
        current_solution = [U._list for U in Us]
        assert np.all(len(v) == 1 for v in current_solution)
        current_solution = [v[0].impl for v in current_solution]
        current_solution = neighborhood_space.project_onto_neighborhood(
            current_solution, neighborhood)
        current_solution = make_discrete_function(neighborhood_space,
                                                  current_solution)
        # Solve the local corrector problem.
        #   LHS
        ops = []
        for lambda_ in affine_lambda['functions']:
            ops.append(
                make_elliptic_swipdg_matrix_operator_on_neighborhood(
                    grid,
                    subdomain,
                    local_boundary_info,
                    neighborhood_space,
                    lambda_,
                    kappa,
                    over_integrate=0))
        ops_coeffs = affine_lambda['coefficients'].copy()
        #   RHS
        funcs = []

        # We don't have any boundary treatment right now. Things will probably
        # break in multiple ways in case of non-trivial boundary conditions,
        # so we can comment this out for now ..

        # for lambda_ in affine_lambda['functions']:
        #     funcs.append(make_elliptic_swipdg_vector_functional_on_neighborhood(
        #         grid, subdomain, local_boundary_info,
        #         neighborhood_space,
        #         current_solution, lambda_, kappa,
        #         over_integrate=0))
        # funcs_coeffs = affine_lambda['coefficients'].copy()
        funcs.append(
            make_l2_vector_functional_on_neighborhood(grid,
                                                      subdomain,
                                                      neighborhood_space,
                                                      f,
                                                      over_integrate=2))
        # funcs_coeffs.append(1.)
        funcs_coeffs = [1]
        #   assemble in one grid walk
        neighborhood_assembler = make_neighborhood_system_assembler(
            grid, subdomain, neighborhood_space)
        for op in ops:
            neighborhood_assembler.append(op)
        for func in funcs:
            neighborhood_assembler.append(func)
        neighborhood_assembler.assemble()
        # solve
        local_space_id = self.solution_space.subspaces[subdomain].id
        lhs = LincombOperator([
            DuneXTMatrixOperator(
                o.matrix(), source_id=local_space_id, range_id=local_space_id)
            for o in ops
        ], ops_coeffs)
        rhs = LincombOperator([
            VectorFunctional(lhs.range.make_array([v.vector()])) for v in funcs
        ], funcs_coeffs)
        correction = lhs.apply_inverse(rhs.as_source_array(mu),
                                       mu=mu,
                                       inverse_options=inverse_options)
        assert len(correction) == 1
        # restrict to subdomain
        local_sizes = [
            block_space.local_space(nn).size() for nn in neighborhood
        ]
        local_starts = [
            int(np.sum(local_sizes[:nn])) for nn in range(len(local_sizes))
        ]
        local_starts.append(neighborhood_space.mapper.size)
        localized_corrections_as_np = np.array(correction._list[0].impl,
                                               copy=False)
        localized_corrections_as_np = [
            localized_corrections_as_np[local_starts[nn]:local_starts[nn + 1]]
            for nn in range(len(local_sizes))
        ]
        subdomain_index_in_neighborhood = np.where(
            np.array(list(neighborhood)) == subdomain)[0]
        assert len(subdomain_index_in_neighborhood) == 1
        subdomain_index_in_neighborhood = subdomain_index_in_neighborhood[0]
        subdomain_correction = Vector(
            local_sizes[subdomain_index_in_neighborhood], 0.)
        subdomain_correction_as_np = np.array(subdomain_correction, copy=False)
        subdomain_correction_as_np[:] = localized_corrections_as_np[
            subdomain_index_in_neighborhood][:]
        return self.solution_space.subspaces[subdomain].make_array(
            [subdomain_correction])