示例#1
0
    def to_lti(self):
        """Convert model to |LTIModel|.

        This method interprets the given model as an |LTIModel|
        in the following way::

            - self.operator        -> A
            self.rhs               -> B
            self.outputs           -> C
            None                   -> D
            self.mass              -> E
        """
        if len(self.outputs) == 0:
            raise ValueError('No outputs defined.')
        if len(self.outputs) > 1:
            raise NotImplementedError('Only one output supported.')
        A = -self.operator
        B = self.rhs
        C = next(iter(self.outputs.values()))
        E = self.mass

        if not all(op.linear for op in [A, B, C, E]):
            raise ValueError('Operators not linear.')

        from pymor.models.iosys import LTIModel
        return LTIModel(A, B, C, E=E, visualizer=self.visualizer)
示例#2
0
def create_cl_fom(Re=110, level=2, palpha=1e-3, control='bc'):
    """Create model which is used to evaluate the H2-Gap norm."""
    setup_str = 'lvl_' + str(level) + ('_' + control if control is not None else '') \
                + '_re_' + str(Re) + ('_palpha_' + str(palpha) if control == 'bc' else '')

    fom = load_fom(Re, level, palpha, control)

    Bra = fom.B.as_range_array()
    Cva = fom.C.as_source_array()

    Z = solve_ricc_lrcf(fom.A, fom.E, Bra, Cva, trans=False)
    K = fom.E.apply(Z).lincomb(Z.dot(Cva).T)

    KC = LowRankOperator(K, np.eye(len(K)), Cva)
    mKB = cat_arrays([-K, Bra]).to_numpy().T
    mKBop = NumpyMatrixOperator(mKB)

    mKBop_proj = LerayProjectedOperator(mKBop,
                                        fom.A.source.G,
                                        fom.A.source.E,
                                        projection_space='range')

    cl_fom = LTIModel(fom.A - KC, mKBop_proj, fom.C, None, fom.E)

    with open(setup_str + '/cl_fom', 'wb') as cl_fom_file:
        pickle.dump({'cl_fom': cl_fom}, cl_fom_file)
示例#3
0
def get_gap_rom(rom):
    """Based on a rom, create model which is used to evaluate H2-Gap norm."""
    A = to_matrix(rom.A, format='dense')
    B = to_matrix(rom.B, format='dense')
    C = to_matrix(rom.C, format='dense')

    if isinstance(rom.E, IdentityOperator):
        P = spla.solve_continuous_are(A.T,
                                      C.T,
                                      B.dot(B.T),
                                      np.eye(len(C)),
                                      balanced=False)
        F = P @ C.T
    else:
        E = to_matrix(rom.E, format='dense')
        P = spla.solve_continuous_are(A.T,
                                      C.T,
                                      B.dot(B.T),
                                      np.eye(len(C)),
                                      e=E.T,
                                      balanced=False)
        F = E @ P @ C.T

    AF = A - F @ C
    mFB = np.concatenate((-F, B), axis=1)
    return LTIModel.from_matrices(
        AF, mFB, C, E=None if isinstance(rom.E, IdentityOperator) else E)
示例#4
0
文件: basic.py 项目: weslowrie/pymor
    def to_lti(self):
        """Convert model to |LTIModel|.

        This method interprets the given model as an |LTIModel|
        in the following way::

            - self.operator        -> A
            self.rhs               -> B
            self.output_functional -> C
            None                   -> D
            self.mass              -> E
        """
        if self.output_functional is None:
            raise ValueError('No output defined.')
        A = -self.operator
        B = self.rhs
        C = self.output_functional
        E = self.mass

        if not all(op.linear for op in [A, B, C, E]):
            raise ValueError('Operators not linear.')

        from pymor.models.iosys import LTIModel
        return LTIModel(A,
                        B,
                        C,
                        E=E,
                        parameter_space=self.parameter_space,
                        visualizer=self.visualizer)
示例#5
0
def _poles_b_c_to_lti(poles, b, c):
    r"""Create an |LTIModel| from poles and residue rank-1 factors.

    Returns an |LTIModel| with real matrices such that its transfer
    function is

    .. math::
        \sum_{i = 1}^r \frac{c_i b_i^T}{s - \lambda_i}

    where :math:`\lambda_i, b_i, c_i` are the poles and residue rank-1
    factors.

    Parameters
    ----------
    poles
        Sequence of poles.
    b
        |VectorArray| of right residue rank-1 factors.
    c
        |VectorArray| of left residue rank-1 factors.

    Returns
    -------
    |LTIModel|.
    """
    A, B, C = [], [], []
    for i, pole in enumerate(poles):
        if pole.imag == 0:
            A.append(pole.real)
            B.append(b[i].to_numpy().real)
            C.append(c[i].to_numpy().real.T)
        elif pole.imag > 0:
            A.append([[pole.real, pole.imag],
                      [-pole.imag, pole.real]])
            bi = b[i].to_numpy()
            B.append(np.vstack([2 * bi.real, -2 * bi.imag]))
            ci = c[i].to_numpy()
            C.append(np.hstack([ci.real.T, ci.imag.T]))
    A = spla.block_diag(*A)
    B = np.vstack(B)
    C = np.hstack(C)
    return LTIModel.from_matrices(A, B, C)
示例#6
0
文件: h2.py 项目: meretp/pymor
def _poles_b_c_to_lti(poles, b, c):
    r"""Create an |LTIModel| from poles and residue rank-1 factors.

    Returns an |LTIModel| with real matrices such that its transfer
    function is

    .. math::
        \sum_{i = 1}^r \frac{c_i b_i^T}{s - \lambda_i}

    where :math:`\lambda_i, b_i, c_i` are the poles and residue rank-1
    factors.

    Parameters
    ----------
    poles
        Sequence of poles.
    b
        |NumPy array| of shape `(rom.order, rom.dim_input)`.
    c
        |NumPy array| of shape `(rom.order, rom.dim_output)`.

    Returns
    -------
    |LTIModel|.
    """
    A, B, C = [], [], []
    for i, pole in enumerate(poles):
        if pole.imag == 0:
            A.append(pole.real)
            B.append(b[i].real)
            C.append(c[i].real[:, np.newaxis])
        elif pole.imag > 0:
            A.append([[pole.real, pole.imag],
                      [-pole.imag, pole.real]])
            B.append(np.vstack([2 * b[i].real, -2 * b[i].imag]))
            C.append(np.hstack([c[i].real[:, np.newaxis], c[i].imag[:, np.newaxis]]))
    A = spla.block_diag(*A)
    B = np.vstack(B)
    C = np.hstack(C)
    return LTIModel.from_matrices(A, B, C)
示例#7
0
    def reduce(self, sigma, b, c):
        """Realization-independent tangential Hermite interpolation.

        Parameters
        ----------
        sigma
            Interpolation points (closed under conjugation), list of length `r`.
        b
            Right tangential directions, |NumPy array| of shape `(fom.input_dim, r)`.
        c
            Left tangential directions, |NumPy array| of shape `(fom.output_dim, r)`.

        Returns
        -------
        lti
            The reduced-order |LTIModel| interpolating the transfer function of `fom`.
        """
        r = len(sigma)
        assert isinstance(b, np.ndarray) and b.shape == (self.fom.input_dim, r)
        assert isinstance(c,
                          np.ndarray) and c.shape == (self.fom.output_dim, r)

        # rescale tangential directions (to avoid overflow or underflow)
        if b.shape[0] > 1:
            for i in range(r):
                b[:, i] /= spla.norm(b[:, i])
        else:
            b = np.ones((1, r))
        if c.shape[0] > 1:
            for i in range(r):
                c[:, i] /= spla.norm(c[:, i])
        else:
            c = np.ones((1, r))

        # matrices of the interpolatory LTI system
        Er = np.empty((r, r), dtype=complex)
        Ar = np.empty((r, r), dtype=complex)
        Br = np.empty((r, self.fom.input_dim), dtype=complex)
        Cr = np.empty((self.fom.output_dim, r), dtype=complex)

        Hs = [self.fom.eval_tf(s, mu=self.mu) for s in sigma]
        dHs = [self.fom.eval_dtf(s, mu=self.mu) for s in sigma]

        for i in range(r):
            for j in range(r):
                if i != j:
                    Er[i, j] = -c[:, i].dot(
                        (Hs[i] - Hs[j]).dot(b[:, j])) / (sigma[i] - sigma[j])
                    Ar[i, j] = -c[:, i].dot(
                        (sigma[i] * Hs[i] - sigma[j] * Hs[j])).dot(b[:, j]) / (
                            sigma[i] - sigma[j])
                else:
                    Er[i, i] = -c[:, i].dot(dHs[i].dot(b[:, i]))
                    Ar[i, i] = -c[:, i].dot(
                        (Hs[i] + sigma[i] * dHs[i]).dot(b[:, i]))
            Br[i, :] = Hs[i].T.dot(c[:, i])
            Cr[:, i] = Hs[i].dot(b[:, i])

        # transform the system to have real matrices
        T = np.zeros((r, r), dtype=complex)
        for i in range(r):
            if sigma[i].imag == 0:
                T[i, i] = 1
            else:
                indices = np.nonzero(
                    np.isclose(sigma[i + 1:], sigma[i].conjugate()))[0]
                if len(indices) > 0:
                    j = i + 1 + indices[0]
                    T[i, i] = 1
                    T[i, j] = 1
                    T[j, i] = -1j
                    T[j, j] = 1j
        Er = (T.dot(Er).dot(T.conj().T)).real
        Ar = (T.dot(Ar).dot(T.conj().T)).real
        Br = (T.dot(Br)).real
        Cr = (Cr.dot(T.conj().T)).real

        return LTIModel.from_matrices(Ar,
                                      Br,
                                      Cr,
                                      D=None,
                                      E=Er,
                                      cont_time=self.fom.cont_time)
示例#8
0
 def build_rom(self, projected_operators, error_estimator):
     return LTIModel(error_estimator=error_estimator, **projected_operators)
示例#9
0
    def reduce(self, sigma, b, c):
        """Realization-independent tangential Hermite interpolation.

        Parameters
        ----------
        sigma
            Interpolation points (closed under conjugation), sequence of
            length `r`.
        b
            Right tangential directions, |NumPy array| of shape
            `(r, fom.dim_input)`.
        c
            Left tangential directions, |NumPy array| of shape
            `(r, fom.dim_output)`.

        Returns
        -------
        lti
            The reduced-order |LTIModel| interpolating the transfer
            function of `fom`.
        """
        r = len(sigma)
        assert b.shape == (r, self.fom.dim_input)
        assert c.shape == (r, self.fom.dim_output)

        # rescale tangential directions (to avoid overflow or underflow)
        b = b * (1 / np.linalg.norm(b)) if b.shape[1] > 1 else np.ones((r, 1))
        c = c * (1 / np.linalg.norm(c)) if c.shape[1] > 1 else np.ones((r, 1))

        # matrices of the interpolatory LTI system
        Er = np.empty((r, r), dtype=np.complex_)
        Ar = np.empty((r, r), dtype=np.complex_)
        Br = np.empty((r, self.fom.dim_input), dtype=np.complex_)
        Cr = np.empty((self.fom.dim_output, r), dtype=np.complex_)

        Hs = [self.fom.eval_tf(s, mu=self.mu) for s in sigma]
        dHs = [self.fom.eval_dtf(s, mu=self.mu) for s in sigma]

        for i in range(r):
            for j in range(r):
                if i != j:
                    Er[i, j] = -c[i] @ (Hs[i] - Hs[j]) @ b[j] / (sigma[i] -
                                                                 sigma[j])
                    Ar[i, j] = (
                        -c[i] @ (sigma[i] * Hs[i] - sigma[j] * Hs[j]) @ b[j] /
                        (sigma[i] - sigma[j]))
                else:
                    Er[i, i] = -c[i] @ dHs[i] @ b[i]
                    Ar[i, i] = -c[i] @ (Hs[i] + sigma[i] * dHs[i]) @ b[i]
            Br[i, :] = Hs[i].T @ c[i]
            Cr[:, i] = Hs[i] @ b[i]

        # transform the system to have real matrices
        T = np.zeros((r, r), dtype=np.complex_)
        for i in range(r):
            if sigma[i].imag == 0:
                T[i, i] = 1
            else:
                j = np.argmin(np.abs(sigma - sigma[i].conjugate()))
                if i < j:
                    T[i, i] = 1
                    T[i, j] = 1
                    T[j, i] = -1j
                    T[j, j] = 1j
        Er = (T @ Er @ T.conj().T).real
        Ar = (T @ Ar @ T.conj().T).real
        Br = (T @ Br).real
        Cr = (Cr @ T.conj().T).real

        return LTIModel.from_matrices(Ar,
                                      Br,
                                      Cr,
                                      None,
                                      Er,
                                      cont_time=self.fom.cont_time)
示例#10
0
def main(
        n: int = Argument(100, help='Order of the FOM.'),
        r: int = Argument(10, help='Order of the ROMs.'),
):
    """Synthetic parametric demo.

    See the `MOR Wiki page <http://modelreduction.org/index.php/Synthetic_parametric_model>`_.
    """
    # Model
    # set coefficients
    a = -np.linspace(1e1, 1e3, n // 2)
    b = np.linspace(1e1, 1e3, n // 2)
    c = np.ones(n // 2)
    d = np.zeros(n // 2)

    # build 2x2 submatrices
    aa = np.empty(n)
    aa[::2] = a
    aa[1::2] = a
    bb = np.zeros(n)
    bb[::2] = b

    # set up system matrices
    Amu = sps.diags(aa, format='csc')
    A0 = sps.diags([bb, -bb], [1, -1], shape=(n, n), format='csc')
    B = np.zeros((n, 1))
    B[::2, 0] = 2
    C = np.empty((1, n))
    C[0, ::2] = c
    C[0, 1::2] = d

    # form operators
    A0 = NumpyMatrixOperator(A0)
    Amu = NumpyMatrixOperator(Amu)
    B = NumpyMatrixOperator(B)
    C = NumpyMatrixOperator(C)
    A = A0 + Amu * ProjectionParameterFunctional('mu')

    # form a model
    lti = LTIModel(A, B, C)

    mu_list = [1 / 50, 1 / 20, 1 / 10, 1 / 5, 1 / 2, 1]
    w = np.logspace(0.5, 3.5, 200)

    # System poles
    fig, ax = plt.subplots()
    for mu in mu_list:
        poles = lti.poles(mu=mu)
        ax.plot(poles.real, poles.imag, '.', label=fr'$\mu = {mu}$')
    ax.set_title('System poles')
    ax.legend()
    plt.show()

    # Magnitude plot
    fig, ax = plt.subplots()
    for mu in mu_list:
        lti.mag_plot(w, ax=ax, mu=mu, label=fr'$\mu = {mu}$')
    ax.legend()
    plt.show()

    # Hankel singular values
    fig, ax = plt.subplots()
    for mu in mu_list:
        hsv = lti.hsv(mu=mu)
        ax.semilogy(range(1, len(hsv) + 1), hsv, '.-', label=fr'$\mu = {mu}$')
    ax.set_title('Hankel singular values')
    ax.legend()
    plt.show()

    # System norms
    for mu in mu_list:
        print(f'mu = {mu}:')
        print(f'    H_2-norm of the full model:    {lti.h2_norm(mu=mu):e}')
        if config.HAVE_SLYCOT:
            print(
                f'    H_inf-norm of the full model:  {lti.hinf_norm(mu=mu):e}')
        print(f'    Hankel-norm of the full model: {lti.hankel_norm(mu=mu):e}')

    # Model order reduction
    run_mor_method_param(lti, r, w, mu_list, BTReductor, 'BT')
    run_mor_method_param(lti, r, w, mu_list, IRKAReductor, 'IRKA')
C[0, 1::2] = d

# In[ ]:

A0 = NumpyMatrixOperator(A0)
Amu = NumpyMatrixOperator(Amu)
B = NumpyMatrixOperator(B)
C = NumpyMatrixOperator(C)

# In[ ]:

A = A0 + Amu * ProjectionParameterFunctional('mu', ())

# In[ ]:

lti = LTIModel(A, B, C)

# # Magnitude plot

# In[ ]:

mu_list_short = [1 / 50, 1 / 20, 1 / 10, 1 / 5, 1 / 2, 1]

# In[ ]:

w = np.logspace(0.5, 3.5, 200)

fig, ax = plt.subplots()
for mu in mu_list_short:
    lti.mag_plot(w, ax=ax, mu=mu, label=fr'$\mu = {mu}$')
ax.legend()
示例#12
0
    def reduce(self, sigma, b, c):
        """Realization-independent tangential Hermite interpolation.

        Parameters
        ----------
        sigma
            Interpolation points (closed under conjugation), list of length `r`.
        b
            Right tangential directions, |NumPy array| of shape `(fom.input_dim, r)`.
        c
            Left tangential directions, |NumPy array| of shape `(fom.output_dim, r)`.

        Returns
        -------
        lti
            The reduced-order |LTIModel| interpolating the transfer function of `fom`.
        """
        r = len(sigma)
        assert isinstance(b, np.ndarray) and b.shape == (self.fom.input_dim, r)
        assert isinstance(c, np.ndarray) and c.shape == (self.fom.output_dim, r)

        # rescale tangential directions (to avoid overflow or underflow)
        if b.shape[0] > 1:
            for i in range(r):
                b[:, i] /= spla.norm(b[:, i])
        else:
            b = np.ones((1, r))
        if c.shape[0] > 1:
            for i in range(r):
                c[:, i] /= spla.norm(c[:, i])
        else:
            c = np.ones((1, r))

        # matrices of the interpolatory LTI system
        Er = np.empty((r, r), dtype=complex)
        Ar = np.empty((r, r), dtype=complex)
        Br = np.empty((r, self.fom.input_dim), dtype=complex)
        Cr = np.empty((self.fom.output_dim, r), dtype=complex)

        Hs = [self.fom.eval_tf(s) for s in sigma]
        dHs = [self.fom.eval_dtf(s) for s in sigma]

        for i in range(r):
            for j in range(r):
                if i != j:
                    Er[i, j] = -c[:, i].dot((Hs[i] - Hs[j]).dot(b[:, j])) / (sigma[i] - sigma[j])
                    Ar[i, j] = -c[:, i].dot((sigma[i] * Hs[i] - sigma[j] * Hs[j])).dot(b[:, j]) / (sigma[i] - sigma[j])
                else:
                    Er[i, i] = -c[:, i].dot(dHs[i].dot(b[:, i]))
                    Ar[i, i] = -c[:, i].dot((Hs[i] + sigma[i] * dHs[i]).dot(b[:, i]))
            Br[i, :] = Hs[i].T.dot(c[:, i])
            Cr[:, i] = Hs[i].dot(b[:, i])

        # transform the system to have real matrices
        T = np.zeros((r, r), dtype=complex)
        for i in range(r):
            if sigma[i].imag == 0:
                T[i, i] = 1
            else:
                indices = np.nonzero(np.isclose(sigma[i + 1:], sigma[i].conjugate()))[0]
                if len(indices) > 0:
                    j = i + 1 + indices[0]
                    T[i, i] = 1
                    T[i, j] = 1
                    T[j, i] = -1j
                    T[j, j] = 1j
        Er = (T.dot(Er).dot(T.conj().T)).real
        Ar = (T.dot(Ar).dot(T.conj().T)).real
        Br = (T.dot(Br)).real
        Cr = (Cr.dot(T.conj().T)).real

        return LTIModel.from_matrices(Ar, Br, Cr, D=None, E=Er, cont_time=self.fom.cont_time)