Source code for pymor.algorithms.basisextension
# This file is part of the pyMOR project (http://www.pymor.org).
# Copyright 2013-2017 pyMOR developers and contributors. All rights reserved.
# License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
"""This module contains algorithms for extending a given reduced basis by a new vector.
The methods are mainly designed to be used in conjunction with
the :func:`~pymor.algorithms.greedy.greedy` algorithm. Each method is of the form ::
extension_algorithm(basis, U, ...)
where `basis` and `U` are |VectorArrays| containing the old basis and new vectors
to be added. The methods return a tuple `new_basis, data` where new_basis holds the
extended basis and data is a dict containing additional information about the extension
process. The `data` dict at least has the key `hierarchic` whose value signifies
if the new basis contains the old basis as its first vectors.
If the basis extension fails, e.g. because the new vector is not linearly
independent from the basis, an :class:`~pymor.core.exceptions.ExtensionError`
exception is raised.
"""
import numpy as np
from pymor.algorithms.basic import almost_equal
from pymor.algorithms.gram_schmidt import gram_schmidt
from pymor.algorithms.pod import pod
from pymor.core.exceptions import ExtensionError
[docs]def trivial_basis_extension(basis, U, copy_basis=True, copy_U=True):
"""Extend basis by simply appending the new vectors.
We check if the new vectors are already contained in the basis, but we do
not check for linear independence.
Parameters
----------
basis
|VectorArray| containing the basis to extend.
U
|VectorArray| containing the new basis vectors.
copy_basis
If `copy_basis` is `False`, the old basis is extended in-place.
copy_U
If `copy_U` is `False`, the new basis vectors are removed from `U`.
Returns
-------
new_basis
The extended basis.
extension_data
Dict containing the following fields:
:hierarchic: `True` if `new_basis` contains `basis` as its first vectors.
Raises
------
ExtensionError
Raised when all vectors in `U` are already contained in the basis.
"""
if basis is None:
basis = U.empty(reserve=len(U))
old_basis_length = len(basis)
remove = set()
for i in range(len(U)):
if np.any(almost_equal(U[i], basis)):
remove.add(i)
new_basis = basis.copy() if copy_basis else basis
new_basis.append(U[[i for i in range(len(U)) if i not in remove]],
remove_from_other=(not copy_U))
if len(new_basis) == old_basis_length:
raise ExtensionError
return new_basis, {'hierarchic': True}
[docs]def gram_schmidt_basis_extension(basis, U, product=None, copy_basis=True, copy_U=True):
"""Extend basis using Gram-Schmidt orthonormalization.
Parameters
----------
basis
|VectorArray| containing the basis to extend.
U
|VectorArray| containing the new basis vectors.
product
The inner product w.r.t. which to orthonormalize; if `None`, the Euclidean
product is used.
copy_basis
If `copy_basis` is `False`, the old basis is extended in-place.
copy_U
If `copy_U` is `False`, the new basis vectors are removed from `U`.
Returns
-------
new_basis
The extended basis.
extension_data
Dict containing the following fields:
:hierarchic: `True` if `new_basis` contains `basis` as its first vectors.
Raises
------
ExtensionError
Gram-Schmidt orthonormalization has failed. This is the case when no
vector in `U` is linearly independent of the basis.
"""
if basis is None:
basis = U.empty(reserve=len(U))
basis_length = len(basis)
new_basis = basis.copy() if copy_basis else basis
new_basis.append(U, remove_from_other=(not copy_U))
gram_schmidt(new_basis, offset=basis_length, product=product, copy=False)
if len(new_basis) <= basis_length:
raise ExtensionError
return new_basis, {'hierarchic': True}
[docs]def pod_basis_extension(basis, U, count=1, copy_basis=True, product=None, orthonormalize=True):
"""Extend basis with the first `count` POD modes of the defect of the projection of
`U` onto the current basis.
.. warning::
The provided basis is assumed to be orthonormal w.r.t. the given
inner product!
Parameters
----------
basis
|VectorArray| containing the basis to extend. The basis is expected to be
orthonormal w.r.t. `product`.
U
|VectorArray| containing the vectors to which the POD is applied.
count
Number of POD modes that shall be appended to the basis.
product
The inner product w.r.t. which to orthonormalize; if `None`, the Euclidean
product is used.
copy_basis
If `copy_basis` is `False`, the old basis is extended in-place.
orthonormalize
If `True`, re-orthonormalize the new basis vectors obtained by the POD
in order to improve numerical accuracy.
Returns
-------
new_basis
The extended basis.
extension_data
Dict containing the following fields:
:hierarchic: `True` if `new_basis` contains `basis` as its first vectors.
Raises
------
ExtensionError
POD has produced no new vectors. This is the case when no vector in `U`
is linearly independent of the basis.
"""
if basis is None:
return pod(U, modes=count, product=product)[0], {'hierarchic': True}
basis_length = len(basis)
new_basis = basis.copy() if copy_basis else basis
if product is None:
U_proj_err = U - basis.lincomb(U.dot(basis))
else:
U_proj_err = U - basis.lincomb(product.apply2(U, basis))
new_basis.append(pod(U_proj_err, modes=count, product=product, orthonormalize=False)[0])
if orthonormalize:
gram_schmidt(new_basis, offset=len(basis), product=product, copy=False)
if len(new_basis) <= basis_length:
raise ExtensionError
return new_basis, {'hierarchic': True}