Beispiel #1
0
def test_ntfl():
    freq = np.arange(0.0, 25.1, 0.1)
    M1 = 10.0
    M2 = 30.0
    M3 = 3.0
    M4 = 2.0
    c1 = 15.0
    c2 = 15.0
    c3 = 15.0
    k1 = 45000.0
    k2 = 25000.0
    k3 = 10000.0

    # 2. Solve coupled system:

    MASS = np.array([[M1, 0, 0, 0], [0, M2, 0, 0], [0, 0, M3, 0],
                     [0, 0, 0, M4]])
    DAMP = np.array([
        [c1, -c1, 0, 0],
        [-c1, c1 + c2, -c2, 0],
        [0, -c2, c2 + c3, -c3],
        [0, 0, -c3, c3],
    ])
    STIF = np.array([
        [k1, -k1, 0, 0],
        [-k1, k1 + k2, -k2, 0],
        [0, -k2, k2 + k3, -k3],
        [0, 0, -k3, k3],
    ])
    F = np.vstack((np.ones((1, len(freq))), np.zeros((3, len(freq)))))
    fs = ode.SolveUnc(MASS, DAMP, STIF, pre_eig=True)
    fullsol = fs.fsolve(F, freq)
    A_coupled = fullsol.a[1]
    F_coupled = (M2 / 2 * A_coupled - k2 * (fullsol.d[2] - fullsol.d[1]) - c2 *
                 (fullsol.v[2] - fullsol.v[1]))

    # 3. Solve for free acceleration; SOURCE setup: [m, b, k, bdof]:

    ms = np.array([[M1, 0], [0, M2 / 2]])
    cs = np.array([[c1, -c1], [-c1, c1]])
    ks = np.array([[k1, -k1], [-k1, k1]])
    source = [ms, cs, ks, [[0, 1]]]
    fs_source = ode.SolveUnc(ms, cs, ks, pre_eig=True)
    sourcesol = fs_source.fsolve(F[:2], freq)
    As = sourcesol.a[1:2]  # free acceleration

    # LOAD setup: [m, b, k, bdof]:

    ml = np.array([[M2 / 2, 0, 0], [0, M3, 0], [0, 0, M4]])
    cl = np.array([[c2, -c2, 0], [-c2, c2 + c3, -c3], [0, -c3, c3]])
    kl = np.array([[k2, -k2, 0], [-k2, k2 + k3, -k3], [0, -k3, k3]])
    load = [ml, cl, kl, [[1, 0, 0]]]

    # 4. Use NT to couple equations. First value (rigid-body motion)
    # should equal ``Source Mass / Total Mass = 25/45 = 0.55555...``
    # Results should match the coupled method.

    r = frclim.ntfl(source, load, As, freq)
    assert np.allclose(25 / 45, abs(r.R[0, 0]))
    assert np.allclose(A_coupled, r.A)
    assert np.allclose(F_coupled, r.F)
    assert_raises(ValueError, frclim.ntfl, source, load, As, freq[:-1])

    r2 = frclim.ntfl(r.SAM, r.LAM, As, freq)
    assert r.SAM is r2.SAM
    assert r.LAM is r2.LAM
    assert np.all(r.TAM == r2.TAM)
    assert np.allclose(r.R, r2.R)
    assert np.allclose(r.A, r2.A)
    assert np.allclose(r.F, r2.F)
Beispiel #2
0
def calcAM(S, freq):
    """
    Calculate apparent mass

    Parameters
    ----------
    S : list/tuple
        Contains: ``[mass, damp, stiff, bdof]`` for structure. These
        are the source mass, damping, and stiffness matrices (see
        :class:`pyyeti.ode.SolveUnc`) and `bdof`, which is described
        below.
    freq : 1d array_like
        Frequency vector (Hz)

    Returns
    -------
    AM : 3d ndarray
        Apparent mass matrix in a 3d array:

        .. code-block:: none

            boundary DOF x Frequencies x boundary DOF
             (response)                   (input)

    Notes
    -----
    The `bdof` input defines boundary DOF in one of two ways as
    follows. Let `N` be total number of DOF in mass, damping, &
    stiffness.

       1.  If `bdof` is a 2d array_like, it is interpreted to be a
           data recovery matrix to the b-set (number b-set =
           ``bdof.shape[0]``). Structure is treated generically (uses
           :class:`pyyeti.ode.SolveUnc` with ``pre_eig=True`` to
           compute apparent mass).
       2.  Otherwise, `bdof` is assumed to be a 1d partition vector
           from full `N` size to b-set and structure is assumed to be
           in Craig-Bampton form (uses :func:`pyyeti.cb.cbtf` to
           compute apparent mass).

    The routine :func:`ntfl` example demonstrates this function.

    See also
    --------
    :func:`ntfl`.
    """
    lf = len(freq)
    m = S[0]
    b = S[1]
    k = S[2]
    bdof = np.atleast_1d(S[3])

    if bdof.ndim == 2:  # bdof is treated as a drm
        r = bdof.shape[0]
        T = bdof
        Frc = np.zeros((r, lf))
        Acc = np.empty((r, lf, r), dtype=complex)
        fs = ode.SolveUnc(m, b, k, pre_eig=True)
        for direc in range(r):
            Frc[direc, :] = 1.0
            sol = fs.fsolve(T.T @ Frc, freq)
            Acc[:, :, direc] = T @ sol.a
            Frc[direc, :] = 0.0
        AM = np.empty((r, lf, r), dtype=complex)
        for j in range(lf):
            AM[:, j, :] = la.inv(Acc[:, j, :])
    else:  # bdof treated as a partition vector for CB model
        r = len(bdof)
        acce = np.eye(r)
        # Perform Baseshake
        # cbtf = craig bampton transfer function; this will genenerate
        # the corresponding interface force required to meet imposed
        # acceleration
        AM = np.empty((r, lf, r), dtype=complex)
        save = {}
        for direc in range(r):
            tf = cb.cbtf(m, b, k, acce[direc, :], freq, bdof, save)
            AM[:, :, direc] = tf.frc
    return AM
Beispiel #3
0
    b = 2 * 0.02 * np.sqrt(k)
    mbk = (m, b, k)

    # load in forcing functions:
    toes = matlab.loadmat("toes_ffns.mat",
                          squeeze_me=True,
                          struct_as_record=False)
    toes["ffns"] = toes["ffns"][:3, ::2]
    toes["sr"] = toes["sr"] / 2
    toes["t"] = toes["t"][::2]

    # form force transform:
    T = n2p.formdrm(nas, 0, [[8, 12], [24, 13]])[0].T

    # do pre-calcs and loop over all cases:
    ts = ode.SolveUnc(*mbk, 1 / toes["sr"], rf=rfmodes)
    LC = toes["ffns"].shape[0]
    t = toes["t"]
    for j, force in enumerate(toes["ffns"]):
        print("Running {} case {}".format(event, j + 1))
        genforce = T @ ([[1], [0.1], [1], [0.1]] * force[None, :])
        # solve equations of motion
        sol = ts.tsolve(genforce, static_ic=1)
        sol.t = t
        sol = DR.apply_uf(sol, *mbk, nas["nrb"], rfmodes)
        caseid = "{} {:2d}".format(event, j + 1)
        results.time_data_recovery(sol, nas["nrb"], caseid, DR, LC, j)

    results.calc_stat_ext(stats.ksingle(0.99, 0.90, LC))

    # save results: