def __init__(self, fom, RB=None, product=None, coercivity_estimator=None, check_orthonormality=None, check_tol=None): if not isinstance(fom.time_stepper, ImplicitEulerTimeStepper): raise NotImplementedError if fom.mass is not None and fom.mass.parametric and 't' in fom.mass.parameters: raise NotImplementedError super().__init__(fom, RB, product=product, check_orthonormality=check_orthonormality, check_tol=check_tol) self.coercivity_estimator = coercivity_estimator self.residual_reductor = ImplicitEulerResidualReductor( self.bases['RB'], fom.operator, fom.mass, fom.T / fom.time_stepper.nt, rhs=fom.rhs, product=product) self.initial_residual_reductor = ResidualReductor( self.bases['RB'], IdentityOperator(fom.solution_space), fom.initial_data, product=fom.l2_product, riesz_representatives=False)
def __init__(self, fom, RB=None, product=None, coercivity_estimator=None, check_orthonormality=None, check_tol=None): assert isinstance(fom.time_stepper, ImplicitEulerTimeStepper) super().__init__(fom, RB, product=product, check_orthonormality=check_orthonormality, check_tol=check_tol) self.coercivity_estimator = coercivity_estimator self.residual_reductor = ImplicitEulerResidualReductor( self.bases['RB'], fom.operator, fom.mass, fom.T / fom.time_stepper.nt, rhs=fom.rhs, product=product) self.initial_residual_reductor = ResidualReductor( self.bases['RB'], IdentityOperator(fom.solution_space), fom.initial_data, product=fom.l2_product, riesz_representatives=False)
def __init__(self, fom, RB=None, product=None, coercivity_estimator=None, check_orthonormality=None, check_tol=None): super().__init__(fom, RB, product=product, check_orthonormality=check_orthonormality, check_tol=check_tol) self.coercivity_estimator = coercivity_estimator self.residual_reductor = ResidualReductor(self.bases['RB'], self.fom.operator, self.fom.rhs, product=product, riesz_representatives=True)
def __init__(self, d, RB=None, orthogonal_projection=('initial_data',), product=None, coercivity_estimator=None): super().__init__(d, RB, orthogonal_projection=orthogonal_projection, product=product) self.coercivity_estimator = coercivity_estimator self.residual_reductor = ResidualReductor(self.RB, self.d.operator, self.d.rhs, product=product)
def __init__(self, fom, RB=None, product=None, coercivity_estimator=None, check_orthonormality=None, check_tol=None): assert fom.operator.linear and fom.rhs.linear assert isinstance(fom.operator, LincombOperator) assert all(not op.parametric for op in fom.operator.operators) if fom.rhs.parametric: assert isinstance(fom.rhs, LincombOperator) assert all(not op.parametric for op in fom.rhs.operators) super().__init__(fom, RB, product=product, check_orthonormality=check_orthonormality, check_tol=check_tol) self.coercivity_estimator = coercivity_estimator self.residual_reductor = ResidualReductor(self.bases['RB'], self.fom.operator, self.fom.rhs, product=product) self.extends = None
def __init__(self, d, RB=None, product=None, coercivity_estimator=None): assert isinstance(d.time_stepper, ImplicitEulerTimeStepper) super().__init__(d, RB, product=product) self.coercivity_estimator = coercivity_estimator self.residual_reductor = ImplicitEulerResidualReductor( self.RB, d.operator, d.mass, d.T / d.time_stepper.nt, functional=d.rhs, product=product) self.initial_residual_reductor = ResidualReductor( self.RB, IdentityOperator(d.solution_space), d.initial_data, product=d.l2_product)
class CoerciveRBReductor(GenericRBReductor): """Reduced Basis reductor for |StationaryDiscretizations| with coercive linear operator. The only addition to :class:`~pymor.reductors.basic.GenericRBReductor` is an error estimator which evaluates the dual norm of the residual with respect to a given inner product. For the reduction of the residual we use :class:`~pymor.reductors.residual.ResidualReductor` for improved numerical stability [BEOR14]_. .. [BEOR14] A. Buhr, C. Engwer, M. Ohlberger, S. Rave, A Numerically Stable A Posteriori Error Estimator for Reduced Basis Approximations of Elliptic Equations, Proceedings of the 11th World Congress on Computational Mechanics, 2014. Parameters ---------- d The |Discretization| which is to be reduced. RB |VectorArray| containing the reduced basis on which to project. orthogonal_projection List of keys in `d.operators` for which the corresponding |Operator| should be orthogonally projected (i.e. operators which map to vectors in contrast to bilinear forms which map to functionals). product Inner product for the projection of the |Operators| given by `orthogonal_projection` and for the computation of Riesz representatives of the residual. If `None`, the Euclidean product is used. coercivity_estimator `None` or a |Parameterfunctional| returning a lower bound for the coercivity constant of the given problem. Note that the computed error estimate is only guaranteed to be an upper bound for the error when an appropriate coercivity estimate is specified. """ def __init__(self, d, RB=None, orthogonal_projection=('initial_data',), product=None, coercivity_estimator=None): super().__init__(d, RB, orthogonal_projection=orthogonal_projection, product=product) self.coercivity_estimator = coercivity_estimator self.residual_reductor = ResidualReductor(self.RB, self.d.operator, self.d.rhs, product=product) def _reduce(self): with self.logger.block('RB projection ...'): rd = super()._reduce() with self.logger.block('Assembling error estimator ...'): residual = self.residual_reductor.reduce() estimator = CoerciveRBEstimator(residual, tuple(self.residual_reductor.residual_range_dims), self.coercivity_estimator) rd = rd.with_(estimator=estimator) return rd
class CoerciveRBReductor(GenericRBReductor): """Reduced Basis reductor for |StationaryDiscretizations| with coercive linear operator. The only addition to :class:`~pymor.reductors.basic.GenericRBReductor` is an error estimator which evaluates the dual norm of the residual with respect to a given inner product. For the reduction of the residual we use :class:`~pymor.reductors.residual.ResidualReductor` for improved numerical stability [BEOR14]_. Parameters ---------- d The |Discretization| which is to be reduced. RB |VectorArray| containing the reduced basis on which to project. basis_is_orthonormal If `RB` is specified, indicate whether or not the basis is orthonormal w.r.t. `product`. vector_ranged_operators List of keys in `d.operators` for which the corresponding |Operator| should be orthogonally projected (i.e. operators which map to vectors in contrast to bilinear forms which map to functionals). product Inner product for the orthonormalization of `RB`, the projection of the |Operators| given by `vector_ranged_operators` and for the computation of Riesz representatives of the residual. If `None`, the Euclidean product is used. coercivity_estimator `None` or a |Parameterfunctional| returning a lower bound for the coercivity constant of the given problem. Note that the computed error estimate is only guaranteed to be an upper bound for the error when an appropriate coercivity estimate is specified. """ def __init__(self, d, RB=None, basis_is_orthonormal=None, vector_ranged_operators=('initial_data',), product=None, coercivity_estimator=None): super().__init__(d, RB, basis_is_orthonormal=basis_is_orthonormal, vector_ranged_operators=vector_ranged_operators, product=product) self.coercivity_estimator = coercivity_estimator self.residual_reductor = ResidualReductor(self.RB, self.d.operator, self.d.rhs, product=product, riesz_representatives=True) def _reduce(self): with self.logger.block('RB projection ...'): rd = super()._reduce() with self.logger.block('Assembling error estimator ...'): residual = self.residual_reductor.reduce() estimator = CoerciveRBEstimator(residual, tuple(self.residual_reductor.residual_range_dims), self.coercivity_estimator) rd = rd.with_(estimator=estimator) return rd
def __init__(self, d, RB=None, basis_is_orthonormal=None, vector_ranged_operators=('initial_data',), product=None, coercivity_estimator=None): super().__init__(d, RB, basis_is_orthonormal=basis_is_orthonormal, vector_ranged_operators=vector_ranged_operators, product=product) self.coercivity_estimator = coercivity_estimator self.residual_reductor = ResidualReductor(self.RB, self.d.operator, self.d.rhs, product=product, riesz_representatives=True)
class CoerciveRBReductor(StationaryRBReductor): """Reduced Basis reductor for |StationaryModels| with coercive linear operator. The only addition to :class:`~pymor.reductors.basic.StationaryRBReductor` is an error estimator which evaluates the dual norm of the residual with respect to a given inner product. For the reduction of the residual we use :class:`~pymor.reductors.residual.ResidualReductor` for improved numerical stability [BEOR14]_. Parameters ---------- fom The |Model| which is to be reduced. RB |VectorArray| containing the reduced basis on which to project. product Inner product for the orthonormalization of `RB`, the projection of the |Operators| given by `vector_ranged_operators` and for the computation of Riesz representatives of the residual. If `None`, the Euclidean product is used. coercivity_estimator `None` or a |Parameterfunctional| returning a lower bound for the coercivity constant of the given problem. Note that the computed error estimate is only guaranteed to be an upper bound for the error when an appropriate coercivity estimate is specified. """ def __init__(self, fom, RB=None, product=None, coercivity_estimator=None, check_orthonormality=None, check_tol=None): super().__init__(fom, RB, product=product, check_orthonormality=check_orthonormality, check_tol=check_tol) self.coercivity_estimator = coercivity_estimator self.residual_reductor = ResidualReductor(self.bases['RB'], self.fom.operator, self.fom.rhs, product=product, riesz_representatives=True) def assemble_estimator(self): residual = self.residual_reductor.reduce() estimator = CoerciveRBEstimator( residual, tuple(self.residual_reductor.residual_range_dims), self.coercivity_estimator) return estimator def assemble_estimator_for_subbasis(self, dims): return self._last_rom.estimator.restricted_to_subbasis( dims['RB'], m=self._last_rom)
def __init__(self, d, RB=None, orthogonal_projection=('initial_data',), product=None, coercivity_estimator=None): assert d.linear assert isinstance(d.operator, LincombOperator) assert all(not op.parametric for op in d.operator.operators) if d.rhs.parametric: assert isinstance(d.rhs, LincombOperator) assert all(not op.parametric for op in d.rhs.operators) super().__init__(d, RB, orthogonal_projection=orthogonal_projection, product=product) self.coercivity_estimator = coercivity_estimator self.residual_reductor = ResidualReductor(self.RB, self.d.operator, self.d.rhs, product=product) self.extends = None
class CoerciveRBReductor(StationaryRBReductor): """Reduced Basis reductor for |StationaryModels| with coercive linear operator. The only addition to :class:`~pymor.reductors.basic.StationaryRBReductor` is an error estimator which evaluates the dual norm of the residual with respect to a given inner product. For the reduction of the residual we use :class:`~pymor.reductors.residual.ResidualReductor` for improved numerical stability [BEOR14]_. Parameters ---------- fom The |Model| which is to be reduced. RB |VectorArray| containing the reduced basis on which to project. product Inner product for the orthonormalization of `RB`, the projection of the |Operators| given by `vector_ranged_operators` and for the computation of Riesz representatives of the residual. If `None`, the Euclidean product is used. coercivity_estimator `None` or a |Parameterfunctional| returning a lower bound for the coercivity constant of the given problem. Note that the computed error estimate is only guaranteed to be an upper bound for the error when an appropriate coercivity estimate is specified. """ def __init__(self, fom, RB=None, product=None, coercivity_estimator=None, check_orthonormality=None, check_tol=None): super().__init__(fom, RB, product=product, check_orthonormality=check_orthonormality, check_tol=check_tol) self.coercivity_estimator = coercivity_estimator self.residual_reductor = ResidualReductor(self.bases['RB'], self.fom.operator, self.fom.rhs, product=product, riesz_representatives=True) def assemble_estimator(self): residual = self.residual_reductor.reduce() estimator = CoerciveRBEstimator(residual, tuple(self.residual_reductor.residual_range_dims), self.coercivity_estimator) return estimator def assemble_estimator_for_subbasis(self, dims): return self._last_rom.estimator.restricted_to_subbasis(dims['RB'], m=self._last_rom)
def __init__(self, d, RB=None, product=None, coercivity_estimator=None): assert isinstance(d.time_stepper, ImplicitEulerTimeStepper) super().__init__(d, RB, product=product) self.coercivity_estimator = coercivity_estimator self.residual_reductor = ImplicitEulerResidualReductor( self.RB, d.operator, d.mass, d.T / d.time_stepper.nt, functional=d.rhs, product=product ) self.initial_residual_reductor = ResidualReductor( self.RB, IdentityOperator(d.solution_space), d.initial_data, product=d.l2_product )
def __init__(self, d, RB=None, basis_is_orthonormal=None, product=None, coercivity_estimator=None): assert isinstance(d.time_stepper, ImplicitEulerTimeStepper) super().__init__(d, RB, basis_is_orthonormal=basis_is_orthonormal, product=product) self.coercivity_estimator = coercivity_estimator self.residual_reductor = ImplicitEulerResidualReductor( self.RB, d.operator, d.mass, d.T / d.time_stepper.nt, rhs=d.rhs, product=product ) self.initial_residual_reductor = ResidualReductor( self.RB, IdentityOperator(d.solution_space), d.initial_data, product=d.l2_product, riesz_representatives=False )
def __init__(self, fom, RB=None, product=None, coercivity_estimator=None, check_orthonormality=None, check_tol=None): assert isinstance(fom.time_stepper, ImplicitEulerTimeStepper) super().__init__(fom, RB, product=product, check_orthonormality=check_orthonormality, check_tol=check_tol) self.coercivity_estimator = coercivity_estimator self.residual_reductor = ImplicitEulerResidualReductor( self.bases['RB'], fom.operator, fom.mass, fom.T / fom.time_stepper.nt, rhs=fom.rhs, product=product ) self.initial_residual_reductor = ResidualReductor( self.bases['RB'], IdentityOperator(fom.solution_space), fom.initial_data, product=fom.l2_product, riesz_representatives=False )
class ParabolicRBReductor(InstationaryRBReductor): r"""Reduced Basis Reductor for parabolic equations. This reductor uses :class:`~pymor.reductors.basic.InstationaryRBReductor` for the actual RB-projection. The only addition is the assembly of an error estimator which bounds the discrete l2-in time / energy-in space error similar to [GP05]_, [HO08]_ as follows: .. math:: \left[ C_a^{-1}(\mu)\|e_N(\mu)\|^2 + \sum_{n=1}^{N} \Delta t\|e_n(\mu)\|^2_e \right]^{1/2} \leq \left[ C_a^{-1}(\mu)\Delta t \sum_{n=1}^{N}\|\mathcal{R}^n(u_n(\mu), \mu)\|^2_{e,-1} + C_a^{-1}(\mu)\|e_0\|^2 \right]^{1/2} Here, :math:`\|\cdot\|` denotes the norm induced by the problem's mass matrix (e.g. the L^2-norm) and :math:`\|\cdot\|_e` is an arbitrary energy norm w.r.t. which the space operator :math:`A(\mu)` is coercive, and :math:`C_a(\mu)` is a lower bound for its coercivity constant. Finally, :math:`\mathcal{R}^n` denotes the implicit Euler timestepping residual for the (fixed) time step size :math:`\Delta t`, .. math:: \mathcal{R}^n(u_n(\mu), \mu) := f - M \frac{u_{n}(\mu) - u_{n-1}(\mu)}{\Delta t} - A(u_n(\mu), \mu), where :math:`M` denotes the mass operator and :math:`f` the source term. The dual norm of the residual is computed using the numerically stable projection from [BEOR14]_. Parameters ---------- fom The |InstationaryModel| which is to be reduced. RB |VectorArray| containing the reduced basis on which to project. product The energy inner product |Operator| w.r.t. which the reduction error is estimated and `RB` is orthonormalized. coercivity_estimator `None` or a |Parameterfunctional| returning a lower bound :math:`C_a(\mu)` for the coercivity constant of `fom.operator` w.r.t. `product`. """ def __init__(self, fom, RB=None, product=None, coercivity_estimator=None, check_orthonormality=None, check_tol=None): assert isinstance(fom.time_stepper, ImplicitEulerTimeStepper) super().__init__(fom, RB, product=product, check_orthonormality=check_orthonormality, check_tol=check_tol) self.coercivity_estimator = coercivity_estimator self.residual_reductor = ImplicitEulerResidualReductor( self.bases['RB'], fom.operator, fom.mass, fom.T / fom.time_stepper.nt, rhs=fom.rhs, product=product ) self.initial_residual_reductor = ResidualReductor( self.bases['RB'], IdentityOperator(fom.solution_space), fom.initial_data, product=fom.l2_product, riesz_representatives=False ) def assemble_estimator(self): residual = self.residual_reductor.reduce() initial_residual = self.initial_residual_reductor.reduce() estimator = ParabolicRBEstimator(residual, self.residual_reductor.residual_range_dims, initial_residual, self.initial_residual_reductor.residual_range_dims, self.coercivity_estimator) return estimator def assemble_estimator_for_subbasis(self, dims): return self._last_rom.estimator.restricted_to_subbasis(dims['RB'], m=self._last_rom)
class ParabolicRBReductor(InstationaryRBReductor): r"""Reduced Basis Reductor for parabolic equations. This reductor uses :class:`~pymor.reductors.basic.InstationaryRBReductor` for the actual RB-projection. The only addition is the assembly of an error estimator which bounds the discrete l2-in time / energy-in space error similar to [GP05]_, [HO08]_ as follows: .. math:: \left[ C_a^{-1}(\mu)\|e_N(\mu)\|^2 + \sum_{n=1}^{N} \Delta t\|e_n(\mu)\|^2_e \right]^{1/2} \leq \left[ C_a^{-2}(\mu)\Delta t \sum_{n=1}^{N}\|\mathcal{R}^n(u_n(\mu), \mu)\|^2_{e,-1} + C_a^{-1}(\mu)\|e_0\|^2 \right]^{1/2} Here, :math:`\|\cdot\|` denotes the norm induced by the problem's mass matrix (e.g. the L^2-norm) and :math:`\|\cdot\|_e` is an arbitrary energy norm w.r.t. which the space operator :math:`A(\mu)` is coercive, and :math:`C_a(\mu)` is a lower bound for its coercivity constant. Finally, :math:`\mathcal{R}^n` denotes the implicit Euler timestepping residual for the (fixed) time step size :math:`\Delta t`, .. math:: \mathcal{R}^n(u_n(\mu), \mu) := f - M \frac{u_{n}(\mu) - u_{n-1}(\mu)}{\Delta t} - A(u_n(\mu), \mu), where :math:`M` denotes the mass operator and :math:`f` the source term. The dual norm of the residual is computed using the numerically stable projection from [BEOR14]_. Parameters ---------- fom The |InstationaryModel| which is to be reduced. RB |VectorArray| containing the reduced basis on which to project. product The energy inner product |Operator| w.r.t. which the reduction error is estimated and `RB` is orthonormalized. coercivity_estimator `None` or a |Parameterfunctional| returning a lower bound :math:`C_a(\mu)` for the coercivity constant of `fom.operator` w.r.t. `product`. """ def __init__(self, fom, RB=None, product=None, coercivity_estimator=None, check_orthonormality=None, check_tol=None): if not isinstance(fom.time_stepper, ImplicitEulerTimeStepper): raise NotImplementedError if fom.mass is not None and fom.mass.parametric and 't' in fom.mass.parameters: raise NotImplementedError super().__init__(fom, RB, product=product, check_orthonormality=check_orthonormality, check_tol=check_tol) self.coercivity_estimator = coercivity_estimator self.residual_reductor = ImplicitEulerResidualReductor( self.bases['RB'], fom.operator, fom.mass, fom.T / fom.time_stepper.nt, rhs=fom.rhs, product=product) self.initial_residual_reductor = ResidualReductor( self.bases['RB'], IdentityOperator(fom.solution_space), fom.initial_data, product=fom.l2_product, riesz_representatives=False) def assemble_estimator(self): residual = self.residual_reductor.reduce() initial_residual = self.initial_residual_reductor.reduce() estimator = ParabolicRBEstimator( residual, self.residual_reductor.residual_range_dims, initial_residual, self.initial_residual_reductor.residual_range_dims, self.coercivity_estimator) return estimator def assemble_estimator_for_subbasis(self, dims): return self._last_rom.estimator.restricted_to_subbasis( dims['RB'], m=self._last_rom)
class ParabolicRBReductor(GenericRBReductor): r"""Reduced Basis Reductor for parabolic equations. This reductor uses :class:`~pymor.reductors.basic.GenericRBReductor` for the actual RB-projection. The only addition is the assembly of an error estimator which bounds the discrete l2-in time / energy-in space error similar to [GP05]_, [HO08]_ as follows: .. math:: \left[ C_a^{-1}(\mu)\|e_N(\mu)\|^2 + \sum_{n=1}^{N} \Delta t\|e_n(\mu)\|^2_e \right]^{1/2} \leq \left[ C_a^{-1}(\mu)\Delta t \sum_{n=1}^{N}\|\mathcal{R}^n(u_n(\mu), \mu)\|^2_{e,-1} + C_a^{-1}(\mu)\|e_0\|^2 \right]^{1/2} Here, :math:`\|\cdot\|` denotes the norm induced by the problem's mass matrix (e.g. the L^2-norm) and :math:`\|\cdot\|_e` is an arbitrary energy norm w.r.t. which the space operator :math:`A(\mu)` is coercive, and :math:`C_a(\mu)` is a lower bound for its coercivity constant. Finally, :math:`\mathcal{R}^n` denotes the implicit Euler timestepping residual for the (fixed) time step size :math:`\Delta t`, .. math:: \mathcal{R}^n(u_n(\mu), \mu) := f - M \frac{u_{n}(\mu) - u_{n-1}(\mu)}{\Delta t} - A(u_n(\mu), \mu), where :math:`M` denotes the mass operator and :math:`f` the source term. The dual norm of the residual is computed using the numerically stable projection from [BEOR14]_. .. warning:: The reduced basis `RB` is required to be orthonormal w.r.t. the given energy product. If not, the projection of the initial values will be computed incorrectly. .. [GP05] M. A. Grepl, A. T. Patera, A Posteriori Error Bounds For Reduced-Basis Approximations Of Parametrized Parabolic Partial Differential Equations, M2AN 39(1), 157-181, 2005. .. [HO08] B. Haasdonk, M. Ohlberger, Reduced basis method for finite volume approximations of parametrized evolution equations, M2AN 42(2), 277-302, 2008. Parameters ---------- d The |InstationaryDiscretization| which is to be reduced. RB |VectorArray| containing the reduced basis on which to project. product The energy inner product |Operator| w.r.t. the reduction error is estimated. RB must be to be orthonomrmal w.r.t. this product! coercivity_estimator `None` or a |Parameterfunctional| returning a lower bound :math:`C_a(\mu)` for the coercivity constant of `d.operator` w.r.t. `product`. """ def __init__(self, d, RB=None, product=None, coercivity_estimator=None): assert isinstance(d.time_stepper, ImplicitEulerTimeStepper) super().__init__(d, RB, product=product) self.coercivity_estimator = coercivity_estimator self.residual_reductor = ImplicitEulerResidualReductor( self.RB, d.operator, d.mass, d.T / d.time_stepper.nt, functional=d.rhs, product=product ) self.initial_residual_reductor = ResidualReductor( self.RB, IdentityOperator(d.solution_space), d.initial_data, product=d.l2_product ) def _reduce(self): with self.logger.block('RB projection ...'): rd = super()._reduce() with self.logger.block('Assembling error estimator ...'): residual = self.residual_reductor.reduce() initial_residual = self.initial_residual_reductor.reduce() estimator = ParabolicRBEstimator(residual, self.residual_reductor.residual_range_dims, initial_residual, self.initial_residual_reductor.residual_range_dims, self.coercivity_estimator) rd = rd.with_(estimator=estimator) return rd
class ParabolicRBReductor(GenericRBReductor): r"""Reduced Basis Reductor for parabolic equations. This reductor uses :class:`~pymor.reductors.basic.GenericRBReductor` for the actual RB-projection. The only addition is the assembly of an error estimator which bounds the discrete l2-in time / energy-in space error similar to [GP05]_, [HO08]_ as follows: .. math:: \left[ C_a^{-1}(\mu)\|e_N(\mu)\|^2 + \sum_{n=1}^{N} \Delta t\|e_n(\mu)\|^2_e \right]^{1/2} \leq \left[ C_a^{-1}(\mu)\Delta t \sum_{n=1}^{N}\|\mathcal{R}^n(u_n(\mu), \mu)\|^2_{e,-1} + C_a^{-1}(\mu)\|e_0\|^2 \right]^{1/2} Here, :math:`\|\cdot\|` denotes the norm induced by the problem's mass matrix (e.g. the L^2-norm) and :math:`\|\cdot\|_e` is an arbitrary energy norm w.r.t. which the space operator :math:`A(\mu)` is coercive, and :math:`C_a(\mu)` is a lower bound for its coercivity constant. Finally, :math:`\mathcal{R}^n` denotes the implicit Euler timestepping residual for the (fixed) time step size :math:`\Delta t`, .. math:: \mathcal{R}^n(u_n(\mu), \mu) := f - M \frac{u_{n}(\mu) - u_{n-1}(\mu)}{\Delta t} - A(u_n(\mu), \mu), where :math:`M` denotes the mass operator and :math:`f` the source term. The dual norm of the residual is computed using the numerically stable projection from [BEOR14]_. .. warning:: The reduced basis `RB` is required to be orthonormal w.r.t. the given energy product. If not, the projection of the initial values will be computed incorrectly. .. [GP05] M. A. Grepl, A. T. Patera, A Posteriori Error Bounds For Reduced-Basis Approximations Of Parametrized Parabolic Partial Differential Equations, M2AN 39(1), 157-181, 2005. .. [HO08] B. Haasdonk, M. Ohlberger, Reduced basis method for finite volume approximations of parametrized evolution equations, M2AN 42(2), 277-302, 2008. Parameters ---------- discretization The |InstationaryDiscretization| which is to be reduced. RB |VectorArray| containing the reduced basis on which to project. product The energy inner product |Operator| w.r.t. the reduction error is estimated. RB must be to be orthonomrmal w.r.t. this product! coercivity_estimator `None` or a |Parameterfunctional| returning a lower bound :math:`C_a(\mu)` for the coercivity constant of `discretization.operator` w.r.t. `product`. """ def __init__(self, d, RB=None, product=None, coercivity_estimator=None): assert isinstance(d.time_stepper, ImplicitEulerTimeStepper) super().__init__(d, RB, product=product) self.coercivity_estimator = coercivity_estimator self.residual_reductor = ImplicitEulerResidualReductor( self.RB, d.operator, d.mass, d.T / d.time_stepper.nt, functional=d.rhs, product=product) self.initial_residual_reductor = ResidualReductor( self.RB, IdentityOperator(d.solution_space), d.initial_data, product=d.l2_product) def _reduce(self): with self.logger.block('RB projection ...'): rd = super()._reduce() with self.logger.block('Assembling error estimator ...'): residual = self.residual_reductor.reduce() initial_residual = self.initial_residual_reductor.reduce() estimator = ParabolicRBEstimator( residual, self.residual_reductor.residual_range_dims, initial_residual, self.initial_residual_reductor.residual_range_dims, self.coercivity_estimator) rd = rd.with_(estimator=estimator) return rd
class ParabolicRBReductor(GenericRBReductor): r"""Reduced Basis Reductor for parabolic equations. This reductor uses :class:`~pymor.reductors.basic.GenericRBReductor` for the actual RB-projection. The only addition is the assembly of an error estimator which bounds the discrete l2-in time / energy-in space error similar to [GP05]_, [HO08]_ as follows: .. math:: \left[ C_a^{-1}(\mu)\|e_N(\mu)\|^2 + \sum_{n=1}^{N} \Delta t\|e_n(\mu)\|^2_e \right]^{1/2} \leq \left[ C_a^{-1}(\mu)\Delta t \sum_{n=1}^{N}\|\mathcal{R}^n(u_n(\mu), \mu)\|^2_{e,-1} + C_a^{-1}(\mu)\|e_0\|^2 \right]^{1/2} Here, :math:`\|\cdot\|` denotes the norm induced by the problem's mass matrix (e.g. the L^2-norm) and :math:`\|\cdot\|_e` is an arbitrary energy norm w.r.t. which the space operator :math:`A(\mu)` is coercive, and :math:`C_a(\mu)` is a lower bound for its coercivity constant. Finally, :math:`\mathcal{R}^n` denotes the implicit Euler timestepping residual for the (fixed) time step size :math:`\Delta t`, .. math:: \mathcal{R}^n(u_n(\mu), \mu) := f - M \frac{u_{n}(\mu) - u_{n-1}(\mu)}{\Delta t} - A(u_n(\mu), \mu), where :math:`M` denotes the mass operator and :math:`f` the source term. The dual norm of the residual is computed using the numerically stable projection from [BEOR14]_. Parameters ---------- d The |InstationaryDiscretization| which is to be reduced. RB |VectorArray| containing the reduced basis on which to project. basis_is_orthonormal Indicate whether or not the basis is orthonormal w.r.t. `product`. product The energy inner product |Operator| w.r.t. which the reduction error is estimated and `RB` is orthonormalized. coercivity_estimator `None` or a |Parameterfunctional| returning a lower bound :math:`C_a(\mu)` for the coercivity constant of `d.operator` w.r.t. `product`. """ def __init__(self, d, RB=None, basis_is_orthonormal=None, product=None, coercivity_estimator=None): assert isinstance(d.time_stepper, ImplicitEulerTimeStepper) super().__init__(d, RB, basis_is_orthonormal=basis_is_orthonormal, product=product) self.coercivity_estimator = coercivity_estimator self.residual_reductor = ImplicitEulerResidualReductor( self.RB, d.operator, d.mass, d.T / d.time_stepper.nt, rhs=d.rhs, product=product ) self.initial_residual_reductor = ResidualReductor( self.RB, IdentityOperator(d.solution_space), d.initial_data, product=d.l2_product, riesz_representatives=False ) def _reduce(self): with self.logger.block('RB projection ...'): rd = super()._reduce() with self.logger.block('Assembling error estimator ...'): residual = self.residual_reductor.reduce() initial_residual = self.initial_residual_reductor.reduce() estimator = ParabolicRBEstimator(residual, self.residual_reductor.residual_range_dims, initial_residual, self.initial_residual_reductor.residual_range_dims, self.coercivity_estimator) rd = rd.with_(estimator=estimator) return rd