class SOBTfvReductor(BasicObject): """Free-velocity Second-Order Balanced Truncation reductor. See [MS96]_. Parameters ---------- fom The full-order |SecondOrderModel| to reduce. mu |Parameter values|. """ def __init__(self, fom, mu=None): assert isinstance(fom, SecondOrderModel) if not isinstance(mu, Mu): mu = fom.parameters.parse(mu) assert fom.parameters.assert_compatible(mu) self.fom = fom self.mu = mu self.V = None self.W = None self._pg_reductor = None def reduce(self, r, projection='bfsr'): """Reduce using SOBTfv. Parameters ---------- r Order of the reduced model. projection Projection method used: - `'sr'`: square root method - `'bfsr'`: balancing-free square root method (default, since it avoids scaling by singular values and orthogonalizes the projection matrices, which might make it more accurate than the square root method) - `'biorth'`: like the balancing-free square root method, except it biorthogonalizes the projection matrices Returns ------- rom Reduced-order |SecondOrderModel|. """ assert 0 < r < self.fom.order assert projection in ('sr', 'bfsr', 'biorth') # compute all necessary Gramian factors pcf = self.fom.gramian('pc_lrcf', mu=self.mu) pof = self.fom.gramian('po_lrcf', mu=self.mu) if r > min(len(pcf), len(pof)): raise ValueError( 'r needs to be smaller than the sizes of Gramian factors.') # find necessary SVDs _, sp, Vp = spla.svd(pof.inner(pcf), lapack_driver='gesvd') # compute projection matrices self.V = pcf.lincomb(Vp[:r]) if projection == 'sr': alpha = 1 / np.sqrt(sp[:r]) self.V.scal(alpha) elif projection == 'bfsr': gram_schmidt(self.V, atol=0, rtol=0, copy=False) elif projection == 'biorth': gram_schmidt(self.V, product=self.fom.M, atol=0, rtol=0, copy=False) self.W = self.V # find the reduced model if self.fom.parametric: fom_mu = self.fom.with_( **{ op: getattr(self.fom, op).assemble(mu=self.mu) for op in ['M', 'E', 'K', 'B', 'Cp', 'Cv'] }) else: fom_mu = self.fom self._pg_reductor = SOLTIPGReductor(fom_mu, self.W, self.V, projection == 'biorth') rom = self._pg_reductor.reduce() return rom def reconstruct(self, u): """Reconstruct high-dimensional vector from reduced vector `u`.""" return self._pg_reductor.reconstruct(u)
class GenericSOBTpvReductor(BasicObject): """Generic Second-Order Balanced Truncation position/velocity reductor. See [RS08]_. Parameters ---------- fom The full-order |SecondOrderModel| to reduce. mu |Parameter values|. """ def __init__(self, fom, mu=None): assert isinstance(fom, SecondOrderModel) if not isinstance(mu, Mu): mu = fom.parameters.parse(mu) assert fom.parameters.assert_compatible(mu) self.fom = fom self.mu = mu self.V = None self.W = None self._pg_reductor = None def _gramians(self): """Return Gramians.""" raise NotImplementedError def _projection_matrices_and_singular_values(self, r, gramians): """Return projection matrices and singular values.""" raise NotImplementedError def reduce(self, r, projection='bfsr'): """Reduce using GenericSOBTpv. Parameters ---------- r Order of the reduced model. projection Projection method used: - `'sr'`: square root method - `'bfsr'`: balancing-free square root method (default, since it avoids scaling by singular values and orthogonalizes the projection matrices, which might make it more accurate than the square root method) - `'biorth'`: like the balancing-free square root method, except it biorthogonalizes the projection matrices Returns ------- rom Reduced-order |SecondOrderModel|. """ assert 0 < r < self.fom.order assert projection in ('sr', 'bfsr', 'biorth') # compute all necessary Gramian factors gramians = self._gramians() if r > min(len(g) for g in gramians): raise ValueError( 'r needs to be smaller than the sizes of Gramian factors.') # compute projection matrices self.V, self.W, singular_values = self._projection_matrices_and_singular_values( r, gramians) if projection == 'sr': alpha = 1 / np.sqrt(singular_values[:r]) self.V.scal(alpha) self.W.scal(alpha) elif projection == 'bfsr': gram_schmidt(self.V, atol=0, rtol=0, copy=False) gram_schmidt(self.W, atol=0, rtol=0, copy=False) elif projection == 'biorth': gram_schmidt_biorth(self.V, self.W, product=self.fom.M, copy=False) # find the reduced model if self.fom.parametric: fom_mu = self.fom.with_( **{ op: getattr(self.fom, op).assemble(mu=self.mu) for op in ['M', 'E', 'K', 'B', 'Cp', 'Cv'] }) else: fom_mu = self.fom self._pg_reductor = SOLTIPGReductor(fom_mu, self.W, self.V, projection == 'biorth') rom = self._pg_reductor.reduce() return rom def reconstruct(self, u): """Reconstruct high-dimensional vector from reduced vector `u`.""" return self._pg_reductor.reconstruct(u)
class SOBTfvReductor(BasicInterface): """Free-velocity Second-Order Balanced Truncation reductor. See [MS96]_. Parameters ---------- fom The full-order |SecondOrderModel| to reduce. """ def __init__(self, fom): assert isinstance(fom, SecondOrderModel) self.fom = fom self._pg_reductor = None self.V = None self.W = None def reduce(self, r, projection='bfsr'): """Reduce using SOBTfv. Parameters ---------- r Order of the reduced model. projection Projection method used: - `'sr'`: square root method - `'bfsr'`: balancing-free square root method (default, since it avoids scaling by singular values and orthogonalizes the projection matrices, which might make it more accurate than the square root method) - `'biorth'`: like the balancing-free square root method, except it biorthogonalizes the projection matrices Returns ------- rom Reduced-order |SecondOrderModel|. """ assert 0 < r < self.fom.order assert projection in ('sr', 'bfsr', 'biorth') # compute all necessary Gramian factors pcf = self.fom.gramian('pc_lrcf') pof = self.fom.gramian('po_lrcf') if r > min(len(pcf), len(pof)): raise ValueError( 'r needs to be smaller than the sizes of Gramian factors.') # find necessary SVDs _, sp, Vp = spla.svd(pof.inner(pcf)) # compute projection matrices self.V = pcf.lincomb(Vp[:r]) if projection == 'sr': alpha = 1 / np.sqrt(sp[:r]) self.V.scal(alpha) elif projection == 'bfsr': self.V = gram_schmidt(self.V, atol=0, rtol=0) elif projection == 'biorth': self.V = gram_schmidt(self.V, product=self.fom.M, atol=0, rtol=0) self.W = self.V # find the reduced model self._pg_reductor = SOLTIPGReductor(self.fom, self.W, self.V, projection == 'biorth') rom = self._pg_reductor.reduce() return rom def reconstruct(self, u): """Reconstruct high-dimensional vector from reduced vector `u`.""" return self._pg_reductor.reconstruct(u)
class GenericSOBTpvReductor(BasicInterface): """Generic Second-Order Balanced Truncation position/velocity reductor. See [RS08]_. Parameters ---------- fom The system which is to be reduced. """ def __init__(self, fom): assert isinstance(fom, SecondOrderModel) self.fom = fom self.V = None self.W = None def _gramians(self): """Returns gramians.""" raise NotImplementedError def _projection_matrices_and_singular_values(self, r, gramians): """Returns projection matrices and singular values.""" raise NotImplementedError def reduce(self, r, projection='bfsr'): """Reduce using GenericSOBTpv. Parameters ---------- r Order of the reduced model. projection Projection method used: - `'sr'`: square root method - `'bfsr'`: balancing-free square root method (default, since it avoids scaling by singular values and orthogonalizes the projection matrices, which might make it more accurate than the square root method) - `'biorth'`: like the balancing-free square root method, except it biorthogonalizes the projection matrices Returns ------- rom Reduced system. """ assert 0 < r < self.fom.order assert projection in ('sr', 'bfsr', 'biorth') # compute all necessary Gramian factors gramians = self._gramians() if r > min(len(g) for g in gramians): raise ValueError( 'r needs to be smaller than the sizes of Gramian factors.') # compute projection matrices and find the reduced model self.V, self.W, singular_values = self._projection_matrices_and_singular_values( r, gramians) if projection == 'sr': alpha = 1 / np.sqrt(singular_values[:r]) self.V.scal(alpha) self.W.scal(alpha) elif projection == 'bfsr': self.V = gram_schmidt(self.V, atol=0, rtol=0) self.W = gram_schmidt(self.W, atol=0, rtol=0) elif projection == 'biorth': self.V, self.W = gram_schmidt_biorth(self.V, self.W, product=self.fom.M) self.pg_reductor = SOLTIPGReductor(self.fom, self.W, self.V, projection == 'biorth') rom = self.pg_reductor.reduce() return rom def reconstruct(self, u): """Reconstruct high-dimensional vector from reduced vector `u`.""" self.pg_reductor.reconstruct(u)
class SOBTfvReductor(BasicInterface): """Free-velocity Second-Order Balanced Truncation reductor. See [MS96]_. Parameters ---------- fom The full-order |SecondOrderModel| to reduce. """ def __init__(self, fom): assert isinstance(fom, SecondOrderModel) self.fom = fom self._pg_reductor = None self.V = None self.W = None def reduce(self, r, projection='bfsr'): """Reduce using SOBTfv. Parameters ---------- r Order of the reduced model. projection Projection method used: - `'sr'`: square root method - `'bfsr'`: balancing-free square root method (default, since it avoids scaling by singular values and orthogonalizes the projection matrices, which might make it more accurate than the square root method) - `'biorth'`: like the balancing-free square root method, except it biorthogonalizes the projection matrices Returns ------- rom Reduced-order |SecondOrderModel|. """ assert 0 < r < self.fom.order assert projection in ('sr', 'bfsr', 'biorth') # compute all necessary Gramian factors pcf = self.fom.gramian('pc_lrcf') pof = self.fom.gramian('po_lrcf') if r > min(len(pcf), len(pof)): raise ValueError('r needs to be smaller than the sizes of Gramian factors.') # find necessary SVDs _, sp, Vp = spla.svd(pof.inner(pcf)) # compute projection matrices self.V = pcf.lincomb(Vp[:r]) if projection == 'sr': alpha = 1 / np.sqrt(sp[:r]) self.V.scal(alpha) elif projection == 'bfsr': self.V = gram_schmidt(self.V, atol=0, rtol=0) elif projection == 'biorth': self.V = gram_schmidt(self.V, product=self.fom.M, atol=0, rtol=0) self.W = self.V # find the reduced model self._pg_reductor = SOLTIPGReductor(self.fom, self.W, self.V, projection == 'biorth') rom = self._pg_reductor.reduce() return rom def reconstruct(self, u): """Reconstruct high-dimensional vector from reduced vector `u`.""" return self._pg_reductor.reconstruct(u)
class GenericSOBTpvReductor(BasicInterface): """Generic Second-Order Balanced Truncation position/velocity reductor. See [RS08]_. Parameters ---------- fom The full-order |SecondOrderModel| to reduce. """ def __init__(self, fom): assert isinstance(fom, SecondOrderModel) self.fom = fom self.V = None self.W = None self._pg_reductor = None def _gramians(self): """Return Gramians.""" raise NotImplementedError def _projection_matrices_and_singular_values(self, r, gramians): """Return projection matrices and singular values.""" raise NotImplementedError def reduce(self, r, projection='bfsr'): """Reduce using GenericSOBTpv. Parameters ---------- r Order of the reduced model. projection Projection method used: - `'sr'`: square root method - `'bfsr'`: balancing-free square root method (default, since it avoids scaling by singular values and orthogonalizes the projection matrices, which might make it more accurate than the square root method) - `'biorth'`: like the balancing-free square root method, except it biorthogonalizes the projection matrices Returns ------- rom Reduced-order |SecondOrderModel|. """ assert 0 < r < self.fom.order assert projection in ('sr', 'bfsr', 'biorth') # compute all necessary Gramian factors gramians = self._gramians() if r > min(len(g) for g in gramians): raise ValueError('r needs to be smaller than the sizes of Gramian factors.') # compute projection matrices self.V, self.W, singular_values = self._projection_matrices_and_singular_values(r, gramians) if projection == 'sr': alpha = 1 / np.sqrt(singular_values[:r]) self.V.scal(alpha) self.W.scal(alpha) elif projection == 'bfsr': self.V = gram_schmidt(self.V, atol=0, rtol=0) self.W = gram_schmidt(self.W, atol=0, rtol=0) elif projection == 'biorth': self.V, self.W = gram_schmidt_biorth(self.V, self.W, product=self.fom.M) # find the reduced model self._pg_reductor = SOLTIPGReductor(self.fom, self.W, self.V, projection == 'biorth') rom = self._pg_reductor.reduce() return rom def reconstruct(self, u): """Reconstruct high-dimensional vector from reduced vector `u`.""" return self._pg_reductor.reconstruct(u)