Skip to content

Commit

Permalink
Merge pull request #1046 from pymor/operator-names
Browse files Browse the repository at this point in the history
Append Operator to LinearAdvectionLaxFriedrichs, Concatenation and ComponentProjection
  • Loading branch information
pmli committed Aug 27, 2020
2 parents 425d033 + e96bbdd commit 85fc34b
Show file tree
Hide file tree
Showing 15 changed files with 129 additions and 77 deletions.
26 changes: 26 additions & 0 deletions docs/source/release_notes.rst
Expand Up @@ -4,6 +4,32 @@
Release Notes
*************

pyMOR 2020.2 (?, 2020)
----------------------


Release highlights
^^^^^^^^^^^^^^^^^^


Additional new features
^^^^^^^^^^^^^^^^^^^^^^^


Backward incompatible changes
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Renaming of some Operators
~~~~~~~~~~~~~~~~~~~~~~~~~~
`ComponentProjection`, `Concatenation` and `LinearAdvectionLaxFriedrichs` were
renamed to `ComponentProjectionOperator`, `ConcatenationOperator` and
`LinearAdvectionLaxFriedrichsOperator`, respectively.


Further notable improvements
^^^^^^^^^^^^^^^^^^^^^^^^^^^^


pyMOR 2020.1 (July 23, 2020)
----------------------------
We are proud to announce the release of pyMOR 2020.1! Highlights of this release
Expand Down
2 changes: 1 addition & 1 deletion docs/source/substitutions.py
Expand Up @@ -91,7 +91,7 @@
.. |NumpyGenericOperator| replace:: :class:`~pymor.operators.numpy.NumpyGenericOperator`
.. |EmpiricalInterpolatedOperator| replace:: :class:`~pymor.operators.ei.EmpiricalInterpolatedOperator`
.. |EmpiricalInterpolatedOperators| replace:: :class:`EmpiricalInterpolatedOperators <pymor.operators.ei.EmpiricalInterpolatedOperator>`
.. |Concatenation| replace:: :class:`~pymor.operators.constructions.Concatenation`
.. |ConcatenationOperator| replace:: :class:`~pymor.operators.constructions.ConcatenationOperator`
.. |NumpyVectorSpace| replace:: :func:`~pymor.vectorarrays.numpy.NumpyVectorSpace`
.. |NumpyVectorSpaces| replace:: :func:`NumpyVectorSpaces <pymor.vectorarrays.numpy.NumpyVectorSpace>`
Expand Down
10 changes: 5 additions & 5 deletions src/pymor/algorithms/image.py
Expand Up @@ -6,7 +6,7 @@
from pymor.algorithms.rules import RuleTable, match_class, match_generic
from pymor.core.exceptions import ImageCollectionError, NoMatchingRuleError
from pymor.core.logger import getLogger
from pymor.operators.constructions import Concatenation, LincombOperator, SelectionOperator
from pymor.operators.constructions import ConcatenationOperator, LincombOperator, SelectionOperator
from pymor.operators.ei import EmpiricalInterpolatedOperator
from pymor.operators.interface import Operator
from pymor.vectorarrays.interface import VectorArray
Expand Down Expand Up @@ -238,8 +238,8 @@ def action_EmpiricalInterpolatedOperator(self, op):
if hasattr(op, 'collateral_basis') and not self.extends:
self.image.append(op.collateral_basis)

@match_class(Concatenation)
def action_Concatenation(self, op):
@match_class(ConcatenationOperator)
def action_ConcatenationOperator(self, op):
if len(op.operators) == 1:
self.apply(op.operators[0])
else:
Expand Down Expand Up @@ -267,8 +267,8 @@ def action_as_range_array(self, op):
def action_recurse(self, op):
self.apply_children(op)

@match_class(Concatenation)
def action_Concatenation(self, op):
@match_class(ConcatenationOperator)
def action_ConcatenationOperator(self, op):
if len(op.operators) == 1:
self.apply(op.operators[0])
else:
Expand Down
4 changes: 2 additions & 2 deletions src/pymor/algorithms/preassemble.py
Expand Up @@ -4,7 +4,7 @@

from pymor.algorithms.rules import RuleTable, match_class, match_generic
from pymor.models.interface import Model
from pymor.operators.constructions import (LincombOperator, Concatenation, ProjectedOperator,
from pymor.operators.constructions import (LincombOperator, ConcatenationOperator, ProjectedOperator,
AffineOperator, AdjointOperator, SelectionOperator)
from pymor.operators.interface import Operator

Expand All @@ -24,7 +24,7 @@ class PreAssembleRules(RuleTable):
def __init__(self):
super().__init__(use_caching=True)

@match_class(Model, AffineOperator, Concatenation, SelectionOperator)
@match_class(Model, AffineOperator, ConcatenationOperator, SelectionOperator)
def action_recurse(self, op):
return self.replace_children(op)

Expand Down
8 changes: 4 additions & 4 deletions src/pymor/algorithms/projection.py
Expand Up @@ -7,7 +7,7 @@
from pymor.algorithms.rules import RuleTable, match_class, match_generic, match_always
from pymor.core.exceptions import RuleNotMatchingError, NoMatchingRuleError
from pymor.operators.block import BlockOperatorBase, BlockRowOperator, BlockColumnOperator
from pymor.operators.constructions import (LincombOperator, Concatenation, ConstantOperator, ProjectedOperator,
from pymor.operators.constructions import (LincombOperator, ConcatenationOperator, ConstantOperator, ProjectedOperator,
ZeroOperator, AffineOperator, AdjointOperator, SelectionOperator,
IdentityOperator)
from pymor.operators.ei import EmpiricalInterpolatedOperator, ProjectedEmpiciralInterpolatedOperator
Expand Down Expand Up @@ -136,8 +136,8 @@ def action_apply_basis(self, op):
from pymor.operators.numpy import NumpyMatrixOperator
return NumpyMatrixOperator(op.apply2(range_basis, source_basis), name=op.name)

@match_class(Concatenation)
def action_Concatenation(self, op):
@match_class(ConcatenationOperator)
def action_ConcatenationOperator(self, op):
if len(op.operators) == 1:
return self.apply(op.operators[0])

Expand All @@ -153,7 +153,7 @@ def action_Concatenation(self, op):
else:
projected_first = project(first, None, source_basis)
projected_last = project(last, range_basis, None)
return Concatenation((projected_last,) + op.operators[1:-1] + (projected_first,), name=op.name)
return ConcatenationOperator((projected_last,) + op.operators[1:-1] + (projected_first,), name=op.name)

@match_class(AdjointOperator)
def action_AdjointOperator(self, op):
Expand Down
12 changes: 6 additions & 6 deletions src/pymor/algorithms/to_matrix.py
Expand Up @@ -9,8 +9,8 @@

from pymor.algorithms.rules import RuleTable, match_class
from pymor.operators.block import BlockOperatorBase
from pymor.operators.constructions import (AdjointOperator, ComponentProjection, Concatenation, IdentityOperator,
LincombOperator, LowRankOperator, LowRankUpdatedOperator,
from pymor.operators.constructions import (AdjointOperator, ComponentProjectionOperator, ConcatenationOperator,
IdentityOperator, LincombOperator, LowRankOperator, LowRankUpdatedOperator,
VectorArrayOperator, ZeroOperator)
from pymor.operators.numpy import NumpyMatrixOperator

Expand Down Expand Up @@ -99,8 +99,8 @@ def action_AdjointOperator(self, op):
res = getattr(sps, format + '_matrix')(res)
return res

@match_class(ComponentProjection)
def action_ComponentProjection(self, op):
@match_class(ComponentProjectionOperator)
def action_ComponentProjectionOperator(self, op):
format = self.format
if format == 'dense':
res = np.zeros((op.range.dim, op.source.dim))
Expand All @@ -114,8 +114,8 @@ def action_ComponentProjection(self, op):
res = res.asformat(format if format else 'csc')
return res

@match_class(Concatenation)
def action_Concatenation(self, op):
@match_class(ConcatenationOperator)
def action_ConcatenationOperator(self, op):
mats = [self.apply(o) for o in op.operators]
while len(mats) > 1:
if self.format is None and not sps.issparse(mats[-2]) and sps.issparse(mats[-1]):
Expand Down
14 changes: 8 additions & 6 deletions src/pymor/basic.py
Expand Up @@ -22,7 +22,8 @@
from pymor.algorithms.projection import project, project_to_subbasis

from pymor.analyticalproblems.burgers import burgers_problem, burgers_problem_2d
from pymor.analyticalproblems.domaindescriptions import RectDomain, CylindricalDomain, TorusDomain, LineDomain, CircleDomain
from pymor.analyticalproblems.domaindescriptions import (RectDomain, CylindricalDomain, TorusDomain, LineDomain,
CircleDomain)
from pymor.analyticalproblems.domaindescriptions import DiscDomain, CircularSectorDomain, PolygonalDomain
from pymor.analyticalproblems.elliptic import StationaryProblem
from pymor.analyticalproblems.functions import (ConstantFunction, GenericFunction, ExpressionFunction, LincombFunction,
Expand All @@ -44,12 +45,13 @@
discretize_stationary_fv, discretize_instationary_fv,
OnedGrid, TriaGrid, RectGrid, load_gmsh)
from pymor.discretizers.builtin.domaindiscretizers.default import discretize_domain_default
from pymor.discretizers.builtin.grids.boundaryinfos import EmptyBoundaryInfo, GenericBoundaryInfo, AllDirichletBoundaryInfo
from pymor.discretizers.builtin.grids.boundaryinfos import (EmptyBoundaryInfo, GenericBoundaryInfo,
AllDirichletBoundaryInfo)

from pymor.operators.constructions import (LincombOperator, Concatenation, ComponentProjection, IdentityOperator,
ConstantOperator, ZeroOperator, VectorArrayOperator, VectorOperator,
VectorFunctional, FixedParameterOperator, AdjointOperator,
SelectionOperator, induced_norm)
from pymor.operators.constructions import (LincombOperator, Concatenation, ConcatenationOperator, ComponentProjection,
ComponentProjectionOperator, IdentityOperator, ConstantOperator,
ZeroOperator, VectorArrayOperator, VectorOperator, VectorFunctional,
FixedParameterOperator, AdjointOperator, SelectionOperator, induced_norm)
from pymor.operators.ei import EmpiricalInterpolatedOperator
from pymor.operators.numpy import NumpyGenericOperator, NumpyMatrixOperator

Expand Down
28 changes: 19 additions & 9 deletions src/pymor/discretizers/builtin/fv.py
Expand Up @@ -23,10 +23,11 @@
from pymor.discretizers.builtin.inplace import iadd_masked, isub_masked
from pymor.discretizers.builtin.quadratures import GaussQuadratures
from pymor.models.basic import StationaryModel, InstationaryModel
from pymor.operators.constructions import ComponentProjection, LincombOperator, ZeroOperator
from pymor.operators.constructions import ComponentProjectionOperator, LincombOperator, ZeroOperator
from pymor.operators.interface import Operator
from pymor.operators.numpy import NumpyGenericOperator, NumpyMatrixBasedOperator, NumpyMatrixOperator
from pymor.parameters.base import ParametricObject
from pymor.tools.deprecated import Deprecated
from pymor.vectorarrays.numpy import NumpyVectorSpace


Expand Down Expand Up @@ -240,11 +241,12 @@ def restricted(self, dofs):
op = self.with_(grid=sub_grid, boundary_info=sub_boundary_info, space_id=None,
name=f'{self.name}_restricted')
sub_grid_indices = sub_grid.indices_from_parent_indices(dofs, codim=0)
proj = ComponentProjection(sub_grid_indices, op.range)
proj = ComponentProjectionOperator(sub_grid_indices, op.range)
return proj @ op, sub_grid.parent_indices(0)

def _fetch_grid_data(self):
# pre-fetch all grid-associated data to avoid searching the cache for each operator application
# pre-fetch all grid-associated data to avoid searching the cache for each operator
# application
g = self.grid
bi = self.boundary_info
self._grid_data = dict(SUPE=g.superentities(1, 0),
Expand Down Expand Up @@ -433,7 +435,8 @@ def nonlinear_advection_lax_friedrichs_operator(grid, boundary_info, flux, lxf_l

def nonlinear_advection_simplified_engquist_osher_operator(grid, boundary_info, flux, flux_derivative,
dirichlet_data=None, solver_options=None, name=None):
"""Instantiate a :class:`NonlinearAdvectionOperator` using :class:`SimplifiedEngquistOsherFlux`."""
"""Instantiate a :class:`NonlinearAdvectionOperator` using
:class:`SimplifiedEngquistOsherFlux`."""
num_flux = SimplifiedEngquistOsherFlux(flux, flux_derivative)
return NonlinearAdvectionOperator(grid, boundary_info, num_flux, dirichlet_data, solver_options, name=name)

Expand All @@ -445,7 +448,7 @@ def nonlinear_advection_engquist_osher_operator(grid, boundary_info, flux, flux_
return NonlinearAdvectionOperator(grid, boundary_info, num_flux, dirichlet_data, solver_options, name=name)


class LinearAdvectionLaxFriedrichs(NumpyMatrixBasedOperator):
class LinearAdvectionLaxFriedrichsOperator(NumpyMatrixBasedOperator):
"""Linear advection finite Volume |Operator| using Lax-Friedrichs flux.
The operator is of the form ::
Expand Down Expand Up @@ -515,6 +518,11 @@ def _assemble(self, mu=None):
return A


@Deprecated(LinearAdvectionLaxFriedrichsOperator)
def LinearAdvectionLaxFriedrichs(*args, **kwargs):
return LinearAdvectionLaxFriedrichsOperator(*args, **kwargs)


class L2Product(NumpyMatrixBasedOperator):
"""|Operator| representing the L2-product between finite volume functions.
Expand Down Expand Up @@ -649,7 +657,8 @@ def _assemble(self, mu=None):
bi = self.boundary_info

if self.function is not None:
# evaluate function at all quadrature points -> shape = (g.size(0), number of quadrature points, 1)
# evaluate function at all quadrature points
# -> shape = (g.size(0), number of quadrature points, 1)
F = self.function(g.quadrature_points(0, order=self.order), mu=mu)

_, w = g.reference_element.quadrature(order=self.order)
Expand All @@ -676,7 +685,8 @@ def _assemble(self, mu=None):
BOUNDARY_DISTS = np.sum((centers[dirichlet_mask, :] - g.orthogonal_centers()[SE_I0_D, :])
* boundary_normals,
axis=-1)
DIRICHLET_FLUXES = VOLS[dirichlet_mask] * self.dirichlet_data(centers[dirichlet_mask], mu=mu) / BOUNDARY_DISTS
DIRICHLET_FLUXES = (VOLS[dirichlet_mask]
* self.dirichlet_data(centers[dirichlet_mask], mu=mu) / BOUNDARY_DISTS)
if self.diffusion_function is not None:
DIRICHLET_FLUXES *= self.diffusion_function(centers[dirichlet_mask], mu=mu)
if self.diffusion_constant is not None:
Expand Down Expand Up @@ -907,11 +917,11 @@ def discretize_stationary_fv(analytical_problem, diameter=None, domain_discretiz

# advection part
if isinstance(p.advection, LincombFunction):
L += [LinearAdvectionLaxFriedrichs(grid, boundary_info, af, name=f'advection_{i}')
L += [LinearAdvectionLaxFriedrichsOperator(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 += [LinearAdvectionLaxFriedrichsOperator(grid, boundary_info, p.advection, name='advection')]
L_coefficients.append(1.)

# nonlinear advection part
Expand Down
4 changes: 2 additions & 2 deletions src/pymor/discretizers/builtin/list.py
Expand Up @@ -5,7 +5,7 @@
from pymor.algorithms.preassemble import preassemble
from pymor.algorithms.rules import RuleTable, match_class
from pymor.models.interface import Model
from pymor.operators.constructions import (AdjointOperator, AffineOperator, Concatenation,
from pymor.operators.constructions import (AdjointOperator, AffineOperator, ConcatenationOperator,
FixedParameterOperator, LincombOperator,
SelectionOperator, VectorArrayOperator,
VectorFunctional, VectorOperator)
Expand Down Expand Up @@ -39,7 +39,7 @@ class ConvertToNumpyListVectorArrayRules(RuleTable):
def __init__(self):
super().__init__(use_caching=True)

@match_class(AdjointOperator, AffineOperator, Concatenation,
@match_class(AdjointOperator, AffineOperator, ConcatenationOperator,
FixedParameterOperator, LincombOperator, SelectionOperator,
Model)
def action_recurse(self, op):
Expand Down
35 changes: 23 additions & 12 deletions src/pymor/operators/constructions.py
Expand Up @@ -15,6 +15,7 @@
from pymor.operators.interface import Operator
from pymor.parameters.base import ParametricObject
from pymor.parameters.functionals import ParameterFunctional, ConjugateParameterFunctional
from pymor.tools.deprecated import Deprecated
from pymor.vectorarrays.interface import VectorArray, VectorSpace
from pymor.vectorarrays.numpy import NumpyVectorSpace

Expand Down Expand Up @@ -272,7 +273,7 @@ def __mul__(self, other):
return self.with_(coefficients=tuple(c * other for c in self.coefficients))


class Concatenation(Operator):
class ConcatenationOperator(Operator):
"""|Operator| representing the concatenation of two |Operators|.
Parameters
Expand Down Expand Up @@ -322,43 +323,48 @@ def jacobian(self, U, mu=None):
for op in self.operators[:0:-1]:
Us.append(op.apply(Us[-1], mu=mu))
options = self.solver_options.get('jacobian') if self.solver_options else None
return Concatenation(tuple(op.jacobian(U, mu=mu) for op, U in zip(self.operators, Us[::-1])),
solver_options=options, name=self.name + '_jacobian')
return ConcatenationOperator(tuple(op.jacobian(U, mu=mu) for op, U in zip(self.operators, Us[::-1])),
solver_options=options, name=self.name + '_jacobian')

def restricted(self, dofs):
restricted_ops = []
for op in self.operators:
rop, dofs = op.restricted(dofs)
restricted_ops.append(rop)
return Concatenation(restricted_ops), dofs
return ConcatenationOperator(restricted_ops), dofs

def __matmul__(self, other):
if not isinstance(other, Operator):
return NotImplemented

if self.name != 'Concatenation':
if isinstance(other, Concatenation) and other.name == 'Concatenation':
if self.name != 'ConcatenationOperator':
if isinstance(other, ConcatenationOperator) and other.name == 'ConcatenationOperator':
operators = (self,) + other.operators
else:
operators = (self, other)
elif isinstance(other, Concatenation) and other.name == 'Concatenation':
elif isinstance(other, ConcatenationOperator) and other.name == 'ConcatenationOperator':
operators = self.operators + other.operators
else:
operators = self.operators + (other,)

return Concatenation(operators, solver_options=self.solver_options)
return ConcatenationOperator(operators, solver_options=self.solver_options)

def __rmatmul__(self, other):
if not isinstance(other, Operator):
return NotImplemented

# note that 'other' can never be a Concatenation
if self.name != 'Concatenation':
# note that 'other' can never be a ConcatenationOperator
if self.name != 'ConcatenationOperator':
operators = (other, self)
else:
operators = (other,) + self.operators

return Concatenation(operators, solver_options=other.solver_options)
return ConcatenationOperator(operators, solver_options=other.solver_options)


@Deprecated(ConcatenationOperator)
def Concatenation(*args, **kwargs):
return ConcatenationOperator(*args, **kwargs)


class ProjectedOperator(Operator):
Expand Down Expand Up @@ -626,7 +632,7 @@ def apply_inverse_adjoint(self, U, mu=None, initial_guess=None, least_squares=Fa
return V


class ComponentProjection(Operator):
class ComponentProjectionOperator(Operator):
"""|Operator| representing the projection of a |VectorArray| onto some of its components.
Parameters
Expand Down Expand Up @@ -755,6 +761,11 @@ def apply_inverse(self, V, mu=None, initial_guess=None, least_squares=False):
return self.source.zeros(len(V))


@Deprecated(ComponentProjectionOperator)
def ComponentProjection(*args, **kwargs):
return ComponentProjectionOperator(*args, **kwargs)


class ZeroOperator(Operator):
"""The |Operator| which maps every vector to zero.
Expand Down

0 comments on commit 85fc34b

Please sign in to comment.