Source code for pymor.algorithms.pod

# This file is part of the pyMOR project (
# Copyright 2013-2020 pyMOR developers and contributors. All rights reserved.
# License: BSD 2-Clause License (

from numbers import Number

import numpy as np

from pymor.algorithms.gram_schmidt import gram_schmidt
from pymor.algorithms.svd_va import method_of_snapshots, qr_svd
from pymor.core.defaults import defaults
from pymor.core.logger import getLogger
from pymor.operators.interface import Operator
from pymor.vectorarrays.interface import VectorArray

[docs]@defaults('rtol', 'atol', 'l2_err', 'method', 'orth_tol') def pod(A, product=None, modes=None, rtol=1e-7, atol=0., l2_err=0., method='method_of_snapshots', orth_tol=1e-10): """Proper orthogonal decomposition of `A`. Viewing the |VectorArray| `A` as a `A.dim` x `len(A)` matrix, the return values of this method are the |VectorArray| of left singular vectors and a |NumPy array| of singular values of the singular value decomposition of `A`, where the inner product on R^(`dim(A)`) is given by `product` and the inner product on R^(`len(A)`) is the Euclidean inner product. Parameters ---------- A The |VectorArray| for which the POD is to be computed. product Inner product |Operator| w.r.t. which the POD is computed. modes If not `None`, at most the first `modes` POD modes (singular vectors) are returned. rtol Singular values smaller than this value multiplied by the largest singular value are ignored. atol Singular values smaller than this value are ignored. l2_err Do not return more modes than needed to bound the l2-approximation error by this value. I.e. the number of returned modes is at most :: argmin_N { sum_{n=N+1}^{infty} s_n^2 <= l2_err^2 } where `s_n` denotes the n-th singular value. method Which SVD method from :mod:`~pymor.algorithms.svd_va` to use (`'method_of_snapshots'` or `'qr_svd'`). orth_tol POD modes are reorthogonalized if the orthogonality error is above this value. Returns ------- POD |VectorArray| of POD modes. SVALS One-dimensional |NumPy array| of singular values. """ if isinstance(product, Number): # old pod signature assert modes is None modes, product = product, None import warnings warnings.warn("pod signature has changed. Provide 'modes' as keyword argument.", DeprecationWarning, stacklevel=3) assert isinstance(A, VectorArray) assert product is None or isinstance(product, Operator) assert modes is None or modes <= len(A) assert method in ('method_of_snapshots', 'qr_svd') logger = getLogger('pymor.algorithms.pod.pod') svd_va = method_of_snapshots if method == 'method_of_snapshots' else qr_svd with logger.block('Computing SVD ...'): POD, SVALS, _ = svd_va(A, product=product, modes=modes, rtol=rtol, atol=atol, l2_err=l2_err) if POD.dim > 0 and len(POD) > 0 and np.isfinite(orth_tol):'Checking orthonormality ...') err = np.max(np.abs(POD.inner(POD, product) - np.eye(len(POD)))) if err >= orth_tol:'Reorthogonalizing POD modes ...') gram_schmidt(POD, product=product, atol=0., rtol=0., copy=False) return POD, SVALS