Пример #1
0
 def test_dAgammaW0_dzeta_unit(self):
     """Test matrix against numerical example."""
     M = 1
     N = 1
     K = M * N
     dAgamW0_dzeta = np.zeros((3 * (M + 1) * (N + 1)))
     zeta = np.array(
         (0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0))
     zetaW = np.array(
         (1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 2.0, 0.0, 0.0, 2.0, 1.0, 0.0))
     gammaW0 = np.array((1.0))
     Cpp_dAgamma0_dZeta(zetaW, M, N, gammaW0, zeta, M, N, dAgamW0_dzeta)
     for foo in range(100):
         dZeta = np.random.random(len(zeta)) / 100.0  #1% variations
         # change in downwash
         dwApprox = np.dot(dAgamW0_dzeta, dZeta)
         # calculate AICs for numrical solution
         AIC = np.zeros((K, K))
         AIC2 = np.zeros((K, K))
         Cpp_AIC(zetaW, M, N, zeta, M, N, AIC)
         Cpp_AIC(zetaW, M, N, zeta + dZeta, M, N, AIC2)
         # calculate exact solution
         dwExact = np.dot(AIC2, gammaW0) - np.dot(AIC, gammaW0)
         # check less than 1% maximum rel error
         if False:
             print("test no. ", foo)
             print(np.dot(AIC, gammaW0))
             print(dwExact)
             print(dwApprox)
             print((dwApprox - dwExact) / (np.dot(AIC, gammaW0)))
         # check less than 2%
         self.assertLess(
             np.absolute((dwApprox - dwExact) / (np.dot(AIC, gammaW0))),
             0.01)
Пример #2
0
 def test_dAgammaW0_dzeta_unit2DM10(self):
     """Test matrix against numerical example for 2D aerofoil, 10 panels, 90 wake panels."""
     #Init AIC
     m = 10
     mW = 190
     n = 2
     k = m * n
     kW = mW * n
     gammaW0 = np.ones((kW))
     AIC = np.zeros((k, kW))
     AIC2 = np.zeros((k, kW))
     dAgamW0_dzeta = np.zeros((k, 3 * (m + 1) * (n + 1)))
     # initialize grid for 3D solver (Unit VR)
     chords = np.linspace(0.0, 1.0, m + 1, True)
     chordsW = np.linspace(1.0, mW * (1.0 / m), mW + 1, True)
     spans = np.linspace(-1000, 1000, n + 1, True)
     zeta = np.zeros(3 * len(chords) * len(spans))
     zetaW = np.zeros(3 * len(chordsW) * len(spans))
     kk = 0
     for c in chords:
         for s in spans:
             zeta[3 * kk] = c
             zeta[3 * kk + 1] = s
             kk = kk + 1
     kk = 0
     for c in chordsW:
         for s in spans:
             zetaW[3 * kk] = c
             zetaW[3 * kk + 1] = s
             kk = kk + 1
     # gen matrix
     Cpp_dAgamma0_dZeta(zetaW, mW, n, gammaW0, zeta, m, n, dAgamW0_dzeta)
     for foo in range(10):
         # gen random zeta
         dZeta = np.random.random(len(zeta)) / 1000.0  #1% chord panel vars
         # calc dw Approx
         dwApprox = np.dot(dAgamW0_dzeta, dZeta)
         # calc AICs for numerical comparison
         Cpp_AIC(zetaW, mW, n, zeta, m, n, AIC)
         Cpp_AIC(zetaW, mW, n, zeta + dZeta, m, n, AIC2)
         dwExact = np.dot(AIC2, gammaW0) - np.dot(AIC, gammaW0)
         if False:
             print("test no. ", foo)
             print(np.dot(AIC, gammaW0))
             print(dwExact)
             print(dwApprox)
             print((dwExact - dwApprox) / np.dot(AIC, gammaW0))
         self.assertLess(
             np.max(
                 np.absolute(
                     (dwApprox - dwExact) / (np.dot(AIC, gammaW0)))), 0.01)
Пример #3
0
 def test_AIC_unit2DM10(self):
     """Compare AIC matrix to VLM.cpp AIC matrix"""
     #Init AIC
     m = 10
     n = 1
     k = m * n
     AIC = np.zeros((k, k))
     # initialize grid for 3D solver (Unit VR)
     chords = np.linspace(0.0, 1.0, m + 1, True)
     spans = (-1000, 1000)
     zeta = np.zeros(3 * len(chords) * len(spans))
     kk = 0
     for c in chords:
         for s in spans:
             zeta[3 * kk] = c
             zeta[3 * kk + 1] = s
             kk = kk + 1
     # call AIC matrix function
     Cpp_AIC(zeta, m, n, zeta, m, n, AIC)
     # load data for comparison
     data = np.loadtxt(TestDir + "unit2DM10.dat")
     # check all entries
     for i in range(k - 1):
         for j in range(k - 1):
             self.assertAlmostEqual(AIC[i, j], data[i, j], 4)
Пример #4
0
    def test_AIC_image(self):
        """Compare image solution to full solution."""
        m = 1
        n = 10
        k = m * n
        AIC = np.zeros((k, k))
        gam = np.ones((k))
        AIChalf = np.zeros((int(k / 2), int(k / 2)))
        gamHalf = np.ones((int(k / 2)))
        chords = np.linspace(0.0, 1.0, m + 1, True)
        spans = np.linspace(-5, 5, n + 1, True)
        spansHalf = np.linspace(0, 5, int(n / 2) + 1, True)
        zeta = np.zeros(3 * len(chords) * len(spans))
        zetaHalf = np.zeros(3 * len(chords) * (int(len(spans) / 2) + 1))
        kk = 0
        for c in chords:
            for s in spans:
                zeta[3 * kk] = c
                zeta[3 * kk + 1] = s
                kk = kk + 1
        kk = 0
        for c in chords:
            for s in spansHalf:
                zetaHalf[3 * kk] = c
                zetaHalf[3 * kk + 1] = s
                kk = kk + 1
        # call AIC matrix function
        Cpp_AIC(zeta, m, n, zeta, m, n, AIC)
        Cpp_AIC(zetaHalf, m, int(n / 2), zetaHalf, m, int(n / 2), AIChalf,
                True)

        # downwash
        w = np.dot(AIC, gam)
        wHalf = np.dot(AIChalf, gamHalf)
        self.assertTrue(
            np.all(np.abs(w[int(n / 2):] - wHalf) < np.finfo(float).eps))
Пример #5
0
 def test_dAgamma0_dzeta_unit(self):
     """Test matrix against numerical example."""
     M = 1
     N = 1
     K = M * N
     dAgam0_dzeta = np.zeros((3 * (M + 1) * (N + 1)))
     zeta = np.array(
         (0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0))
     gamma0 = np.array((1.0))
     dZeta = np.random.random(len(zeta)) / 10.0  #10% variations
     # create matrix
     Cpp_dAgamma0_dZeta(zeta, M, N, gamma0, zeta, M, N, dAgam0_dzeta)
     # change in downwash
     dwApprox = np.dot(dAgam0_dzeta, dZeta)
     # calculate AICs for numrical solution
     AIC = np.zeros((K, K))
     AIC2 = np.zeros((K, K))
     Cpp_AIC(zeta, M, N, zeta, M, N, AIC)
     Cpp_AIC(zeta + dZeta, M, N, zeta + dZeta, M, N, AIC2)
     # calculate exact solution
     dwExact = np.dot(AIC2, gamma0) - np.dot(AIC, gamma0)
     # check less than 1% maximum rel error
     self.assertLess(
         np.absolute((dwApprox - dwExact) / (np.dot(AIC, gamma0))), 0.01)
Пример #6
0
 def test_AIC_unit(self):
     """Compare AIC matrix to trusted results."""
     #Init AIC
     m = 1
     n = 1
     k = m * n
     AIC = np.zeros((k, k))
     # initialize grid for 3D solver (Unit VR)
     chords = (0, 1)
     spans = (0, 1)
     zeta = np.zeros(3 * len(chords) * len(spans))
     k = 0
     for c in chords:
         for s in spans:
             zeta[3 * k] = c
             zeta[3 * k + 1] = s
             k = k + 1
     # call AIC matrix function
     Cpp_AIC(zeta, 1, 1, zeta, 1, 1, AIC)
     self.assertAlmostEqual(AIC[0, 0], -0.900316, 6)
Пример #7
0
 def test_AIC3vAIC(self):
     """Test against trusted result of typical AIC."""
     #Init AIC
     m = 5
     n = 1
     k = m * n
     AIC = np.zeros((k, k))
     AIC3 = np.zeros((3 * k, k))
     # initialize grid for 3D solver (Unit VR)
     chords = np.linspace(0.0, 1.0, m + 1, True)
     spans = (-1000, 1000)
     zeta = np.zeros(3 * len(chords) * len(spans))
     kk = 0
     for c in chords:
         for s in spans:
             zeta[3 * kk] = c
             zeta[3 * kk + 1] = s
             kk = kk + 1
     # call AIC matrix function
     Cpp_AIC(zeta, m, n, zeta, m, n, AIC)
     Cpp_AIC3(zeta, m, n, zeta, m, n, AIC3)
     for i in range(k - 1):
         for j in range(k - 1):
             self.assertAlmostEqual(AIC3[3 * i + 2, j], AIC[i, j], 4)
Пример #8
0
def genSSuvlm(gam,
              gamW,
              gamPri,
              zeta,
              zetaW,
              zetaPri,
              nu,
              m,
              n,
              mW,
              delS,
              imageMeth=False):
    """@details generate state-space matrices for linear UVLM.
    @param gam Reference circulation distribution on body.
    @param gamW Reference circulation distribution in the wake.
    @param gamPri Reference Rate of change of circulation on body.
    @param zeta Lattice vertices.
    @param zetaW Wake lattice vertices.
    @param zetaPri Vertex velocities.
    @param nu Atmospheric velocities.
    @param m Chordwise panels.
    @param n Spanwise.
    @param mW Chordwise panels in wake.
    @param delS Nondimensional timestep.
    @param imageMeth Use image method across xz-plane.
    @return E LHS state transfer matrix.
    @return F RHS state transfer matrix.
    @return G RHS Input matrix.
    @return C Output matrix.
    @return D Feedthrough matrix.
    @note All of the above should be nondimensional."""

    midPoint = False  # use midpoint approximation for derivative of gamma

    # init matrices
    E = np.zeros((2 * m * n + mW * n, 2 * m * n + mW * n))
    F = np.zeros((2 * m * n + mW * n, 2 * m * n + mW * n))
    G = np.zeros((2 * m * n + mW * n, 9 * (m + 1) * (n + 1)))
    C = np.zeros((3 * (m + 1) * (n + 1), 2 * m * n + mW * n))
    D = np.zeros((3 * (m + 1) * (n + 1), 9 * (m + 1) * (n + 1)))

    # populate E
    AIC = np.zeros((m * n, m * n))
    Cpp_AIC(zeta, m, n, zeta, m, n, AIC, imageMeth)
    AICw = np.zeros((m * n, mW * n))
    Cpp_AIC(zetaW, mW, n, zeta, m, n, AICw, imageMeth)
    E[0:m * n, 0:m * n] = AIC
    E[0:m * n, m * n:m * n + mW * n] = AICw
    E[m * n:m * n + mW * n, m * n:m * n + mW * n] = np.eye(mW * n)
    if midPoint == True:
        E[m * n + mW * n:, 0:m * n] = np.eye(m * n)
        E[m * n + mW * n:, m * n + mW * n:] = -0.5 * delS * np.eye(m * n)
    else:
        E[m * n + mW * n:, 0:m * n] = -np.eye(m * n)
        E[m * n + mW * n:, m * n + mW * n:] = delS * np.eye(m * n)

    # populate F
    Cgam = np.zeros((mW * n, m * n))
    Cgam[0:n, m * n - n:m * n] = np.eye(n)
    CgamW = np.zeros((mW * n, mW * n))
    CgamW[n:, 0:mW * n - n] = np.eye(n * (mW - 1))
    #CgamW[-1:,-1]=0.99975
    F[m * n:m * n + mW * n, 0:m * n] = Cgam
    F[m * n:m * n + mW * n, m * n:m * n + mW * n] = CgamW
    if midPoint == True:
        F[m * n + mW * n:, 0:m * n] = np.eye(m * n)
        F[m * n + mW * n:, m * n + mW * n:] = 0.5 * delS * np.eye(m * n)
    else:
        F[m * n + mW * n:, 0:m * n] = -np.eye(m * n)

    # populate G
    W = np.zeros((m * n, 3 * (m + 1) * (n + 1)))
    Cpp_genW(zeta, m, n, W)
    dAgam_dZeta = np.zeros((m * n, 3 * (m + 1) * (n + 1)))
    Cpp_dAgamma0_dZeta(zeta, m, n, gam, zeta, m, n, dAgam_dZeta, imageMeth)
    dAwGamW_dZeta = np.zeros((m * n, 3 * (m + 1) * (n + 1)))
    #Cpp_dAgamma0_dZeta(zetaW, mW, n, gamW, zeta, m, n, dAwGamW_dZeta, imageMeth)
    dWzetaPri_dZeta = np.zeros((m * n, 3 * (m + 1) * (n + 1)))
    dWnuPri_dZeta = np.zeros((m * n, 3 * (m + 1) * (n + 1)))
    Cpp_dWzetaPri0_dZeta(zeta, m, n, zetaPri, dWzetaPri_dZeta)
    Cpp_dWzetaPri0_dZeta(zeta, m, n, nu, dWnuPri_dZeta)
    G[0:m * n, 0:3 * (m + 1) * (n + 1)] = 2 * W
    G[0:m * n, 3 * (m + 1) * (n + 1):6 * (m + 1) * (
        n + 1
    )] = -dAgam_dZeta - dAwGamW_dZeta + 2 * dWzetaPri_dZeta - 2 * dWnuPri_dZeta
    G[0:m * n, 6 * (m + 1) * (n + 1):] = -2 * W

    # populate output matrices C and D
    Xi = np.zeros((3 * m * n, 3 * (m + 1) * (n + 1)))
    H = np.zeros((3 * (m + 1) * (n + 1), 12 * m * n))
    Y1 = np.zeros((12 * m * n, m * n))
    Y2 = np.zeros((12 * m * n, 3 * (m + 1) * (n + 1)))
    Y3 = np.zeros((12 * m * n, 12 * m * n))
    Y4 = np.zeros((3 * m * n, m * n))
    Y5 = np.zeros((3 * m * n, 3 * (m + 1) * (n + 1)))
    AICs3 = np.zeros((12 * m * n, m * n))
    AICs3w = np.zeros((12 * m * n, mW * n))
    dAs3gam_dZeta = np.zeros((12 * m * n, 3 * (m + 1) * (n + 1)))
    dAs3wGamW_dZeta = np.zeros((12 * m * n, 3 * (m + 1) * (n + 1)))

    # gen interpolation and AIC matrices
    Cpp_genXi(m, n, 0.5, 0.5, Xi)
    Cpp_genH(m, n, H)
    Cpp_AIC3s(zeta, m, n, zeta, m, n, AICs3, imageMeth)
    Cpp_AIC3s(zetaW, mW, n, zeta, m, n, AICs3w, imageMeth)
    Cpp_dAs3gamma0_dZeta_num(zeta, m, n, gam, zeta, m, n, dAs3gam_dZeta,
                             imageMeth)
    Cpp_dAs3gamma0_dZeta_num(zetaW, mW, n, gamW, zeta, m, n, dAs3wGamW_dZeta,
                             imageMeth)

    # generate Y matrices
    vM0 = np.zeros((12 * m * n))  # collocation fluid-grid relative velocities
    vM0[:] = np.dot(AICs3, gam) + np.dot(AICs3w, gamW) + 2.0 * np.dot(
        H.transpose(), nu) - 2.0 * np.dot(H.transpose(), zetaPri)
    Cpp_Y1(vM0, zeta, m, n, Y1)
    Cpp_Y2(gam, vM0, m, n, Y2)
    Cpp_Y3(gam, zeta, m, n, Y3)
    Cpp_Y4(zeta, m, n, Y4)
    Cpp_Y5(gamPri, zeta, m, n, Y5)

    # Matrix C
    C[:, 0:m * n] = np.dot(H, Y1) - np.dot(H, np.dot(Y3, AICs3))
    C[:, m * n:m * n + mW * n] = -np.dot(H, np.dot(Y3, AICs3w))
    C[:, m * n + mW * n:] = 2.0 * np.dot(np.transpose(Xi), Y4)

    # Matrix D
    D[:, 0:3 * (m + 1) * (n + 1)] = 2.0 * np.dot(H, np.dot(Y3, H.transpose()))
    D[:, 3 * (m + 1) * (n + 1):6 * (m + 1) *
      (n + 1)] = (np.dot(H, Y2) -
                  np.dot(H, np.dot(Y3, dAs3gam_dZeta + dAs3wGamW_dZeta)) +
                  np.dot(np.transpose(Xi), Y5))
    D[:, 6 * (m + 1) * (n + 1):] = -2.0 * np.dot(H, np.dot(Y3, H.transpose()))

    return E, F, G, C, D