예제 #1
0
def eval_seg_comp_loop(DerP, DerA, DerB, ZetaP, ZetaA, ZetaB, gamma_seg,
                       vortex_radius):
    """
    Derivative of induced velocity Q w.r.t. collocation and segment coordinates
    in format:
        [ (x,y,z) of Q, (x,y,z) of Zeta ]
    Warning: function optimised for performance. Variables are scaled during the
    execution.
    """

    vortex_radius_sq = vortex_radius * vortex_radius
    Cfact = cfact_biot * gamma_seg

    RA = ZetaP - ZetaA
    RB = ZetaP - ZetaB
    RAB = ZetaB - ZetaA
    Vcr = algebra.cross3(RA, RB)
    vcr2 = np.dot(Vcr, Vcr)

    # numerical radious
    if vcr2 < (vortex_radius_sq * algebra.normsq3d(RAB)):
        return

    ### other constants
    ra1, rb1 = algebra.norm3d(RA), algebra.norm3d(RB)
    rainv = 1. / ra1
    rbinv = 1. / rb1
    Tv = RA * rainv - RB * rbinv
    dotprod = np.dot(RAB, Tv)

    ### --------------------------------------------- cross-product derivatives
    # lower triangular part only
    vcr2inv = 1. / vcr2
    vcr4inv = vcr2inv * vcr2inv
    diag_fact = Cfact * vcr2inv * dotprod
    off_fact = -2. * Cfact * vcr4inv * dotprod
    Dvcross = [[diag_fact + off_fact * Vcr[0]**2],
               [off_fact * Vcr[0] * Vcr[1], diag_fact + off_fact * Vcr[1]**2],
               [
                   off_fact * Vcr[0] * Vcr[2], off_fact * Vcr[1] * Vcr[2],
                   diag_fact + off_fact * Vcr[2]**2
               ]]

    ### ------------------------------------------ difference terms derivatives
    Vsc = Vcr * vcr2inv * Cfact
    Ddiff = np.array([RAB * Vsc[0], RAB * Vsc[1], RAB * Vsc[2]])
    dQ_dRAB = np.array([Tv * Vsc[0], Tv * Vsc[1], Tv * Vsc[2]])

    ### ---------------------------------------------- Final assembly (crucial)
    # ps: calling Dvcross_by_skew3d does not slow down execution.

    dQ_dRA = Dvcross_by_skew3d(Dvcross, -RB) \
             + np.dot(Ddiff, der_runit(RA, rainv, -rainv ** 3))
    dQ_dRB = Dvcross_by_skew3d(Dvcross, RA) \
             - np.dot(Ddiff, der_runit(RB, rbinv, -rbinv ** 3))

    DerP += dQ_dRA + dQ_dRB  # w.r.t. P
    DerA -= dQ_dRAB + dQ_dRA  # w.r.t. A
    DerB += dQ_dRAB - dQ_dRB  # w.r.t. B
예제 #2
0
def biot_panel_fast(zetaC, ZetaPanel, gamma=1.0):
    """
    Induced velocity over point ZetaC of a panel of vertices coordinates
    ZetaPanel and circulaiton gamma, where:
        ZetaPanel.shape=(4,3)=[vertex local number, (x,y,z) component]
    """

    Cfact = cfact_biot * gamma
    q = np.zeros((3, ))

    R_list = zetaC - ZetaPanel
    Runit_list = [R_list[ii] / algebra.norm3d(R_list[ii]) for ii in svec]

    for aa, bb in LoopPanel:

        RAB = ZetaPanel[bb, :] - ZetaPanel[aa, :]  # segment vector
        Vcr = algebra.cross3(R_list[aa], R_list[bb])
        vcr2 = np.dot(Vcr, Vcr)
        if vcr2 < (VORTEX_RADIUS_SQ * algebra.normsq3d(RAB)):
            continue

        q += ((Cfact / vcr2) *
              np.dot(RAB, Runit_list[aa] - Runit_list[bb])) * Vcr

    return q
예제 #3
0
def biot_segment(zetaP, zetaA, zetaB, gamma=1.0):
    """
    Induced velocity of segment A_>B of circulation gamma over point P.
    """

    # differences
    ra = zetaP - zetaA
    rb = zetaP - zetaB
    rab = zetaB - zetaA
    ra_norm, rb_norm = algebra.norm3d(ra), algebra.norm3d(rb)
    vcross = algebra.cross3(ra, rb)
    vcross_sq = np.dot(vcross, vcross)

    # numerical radius
    if vcross_sq < (VORTEX_RADIUS_SQ * algebra.normsq3d(rab)):
        return np.zeros((3, ))

    q = ((cfact_biot * gamma / vcross_sq) * \
         (np.dot(rab, ra) / ra_norm - np.dot(rab, rb) / rb_norm)) * vcross

    return q
예제 #4
0
def panel_area(ZetaPanel):
    """
    return area of panel with vertices coordinates ZetaPanel, where:
        ZetaPanel.shape=(4,3)
    using Bretschneider formula - for cyclic or non-cyclic quadrilaters.
    """

    # build cross-vectors
    r02 = ZetaPanel[2, :] - ZetaPanel[0, :]
    r13 = ZetaPanel[3, :] - ZetaPanel[1, :]
    # build side vectors
    r01 = ZetaPanel[1, :] - ZetaPanel[0, :]
    r12 = ZetaPanel[2, :] - ZetaPanel[1, :]
    r23 = ZetaPanel[3, :] - ZetaPanel[2, :]
    r30 = ZetaPanel[0, :] - ZetaPanel[3, :]

    # compute distances
    d02 = algebra.norm3d(r02)
    d13 = algebra.norm3d(r13)
    d01 = algebra.norm3d(r01)
    d12 = algebra.norm3d(r12)
    d23 = algebra.norm3d(r23)
    d30 = algebra.norm3d(r30)

    A = 0.25 * np.sqrt((4. * d02**2 * d13**2) - ((d12**2 + d30**2) -
                                                 (d01**2 + d23**2))**2)

    return A
예제 #5
0
def panel_normal(ZetaPanel):
    """
    return normal of panel with vertex coordinates ZetaPanel, where:
        ZetaPanel.shape=(4,3)
    """

    # build cross-vectors
    r02 = ZetaPanel[2, :] - ZetaPanel[0, :]
    r13 = ZetaPanel[3, :] - ZetaPanel[1, :]

    nvec = algebra.cross3(r02, r13)
    nvec = nvec / algebra.norm3d(nvec)

    return nvec
예제 #6
0
def eval_seg_exp_loop(DerP, DerA, DerB, ZetaP, ZetaA, ZetaB, gamma_seg,
                      vortex_radius):
    """
    Derivative of induced velocity Q w.r.t. collocation (DerC) and segment
    coordinates in format.

    To optimise performance, the function requires the derivative terms to be
    pre-allocated and passed as input.

    Each Der* term returns derivatives in the format

        [ (x,y,z) of Zeta,  (x,y,z) of Q]

    Warning: to optimise performance, variables are scaled during the execution.
    """

    RA = ZetaP - ZetaA
    RB = ZetaP - ZetaB
    RAB = ZetaB - ZetaA
    Vcr = algebra.cross3(RA, RB)
    vcr2 = np.dot(Vcr, Vcr)

    # numerical radious
    vortex_radious_here = vortex_radius * algebra.norm3d(RAB)
    if vcr2 < vortex_radious_here**2:
        return

    # scaling
    ra1, rb1 = algebra.norm3d(RA), algebra.norm3d(RB)
    ra2, rb2 = ra1**2, rb1**2
    rainv = 1. / ra1
    rbinv = 1. / rb1
    ra_dir, rb_dir = RA * rainv, RB * rbinv
    ra3inv, rb3inv = rainv**3, rbinv**3
    Vcr = Vcr / vcr2

    diff_vec = ra_dir - rb_dir
    vdot_prod = np.dot(diff_vec, RAB)
    T2 = vdot_prod / vcr2

    # Extract components
    ra_x, ra_y, ra_z = RA
    rb_x, rb_y, rb_z = RB
    rab_x, rab_y, rab_z = RAB
    vcr_x, vcr_y, vcr_z = Vcr
    ra2_x, ra2_y, ra2_z = RA**2
    rb2_x, rb2_y, rb2_z = RB**2
    ra_vcr_x, ra_vcr_y, ra_vcr_z = 2. * algebra.cross3(RA, Vcr)
    rb_vcr_x, rb_vcr_y, rb_vcr_z = 2. * algebra.cross3(RB, Vcr)
    vcr_sca_x, vcr_sca_y, vcr_sca_z = Vcr * ra3inv
    vcr_scb_x, vcr_scb_y, vcr_scb_z = Vcr * rb3inv

    # # ### derivatives indices:
    # # # the 1st is the component of the vaiable w.r.t derivative are taken.
    # # # the 2nd is the component of the output
    dQ_dRA = np.array([
        [
            -vdot_prod * rb_vcr_x * vcr_x + vcr_sca_x *
            (rab_x *
             (ra2 - ra2_x) - ra_x * ra_y * rab_y - ra_x * ra_z * rab_z),
            -T2 * rb_z - vdot_prod * rb_vcr_x * vcr_y + vcr_sca_y *
            (rab_x *
             (ra2 - ra2_x) - ra_x * ra_y * rab_y - ra_x * ra_z * rab_z),
            T2 * rb_y - vdot_prod * rb_vcr_x * vcr_z + vcr_sca_z *
            (rab_x * (ra2 - ra2_x) - ra_x * ra_y * rab_y - ra_x * ra_z * rab_z)
        ],
        [
            T2 * rb_z - vdot_prod * rb_vcr_y * vcr_x + vcr_sca_x *
            (rab_y *
             (ra2 - ra2_y) - ra_x * ra_y * rab_x - ra_y * ra_z * rab_z),
            -vdot_prod * rb_vcr_y * vcr_y + vcr_sca_y *
            (rab_y *
             (ra2 - ra2_y) - ra_x * ra_y * rab_x - ra_y * ra_z * rab_z),
            -T2 * rb_x - vdot_prod * rb_vcr_y * vcr_z + vcr_sca_z *
            (rab_y * (ra2 - ra2_y) - ra_x * ra_y * rab_x - ra_y * ra_z * rab_z)
        ],
        [
            -T2 * rb_y - vdot_prod * rb_vcr_z * vcr_x + vcr_sca_x *
            (rab_z *
             (ra2 - ra2_z) - ra_x * ra_z * rab_x - ra_y * ra_z * rab_y),
            T2 * rb_x - vdot_prod * rb_vcr_z * vcr_y + vcr_sca_y *
            (rab_z *
             (ra2 - ra2_z) - ra_x * ra_z * rab_x - ra_y * ra_z * rab_y),
            -vdot_prod * rb_vcr_z * vcr_z + vcr_sca_z *
            (rab_z * (ra2 - ra2_z) - ra_x * ra_z * rab_x - ra_y * ra_z * rab_y)
        ]
    ])

    dQ_dRB = np.array([[
        vdot_prod * ra_vcr_x * vcr_x + vcr_scb_x *
        (rab_x * (-rb2 + rb2_x) + rab_y * rb_x * rb_y + rab_z * rb_x * rb_z),
        T2 * ra_z + vdot_prod * ra_vcr_x * vcr_y + vcr_scb_y *
        (rab_x * (-rb2 + rb2_x) + rab_y * rb_x * rb_y + rab_z * rb_x * rb_z),
        -T2 * ra_y + vdot_prod * ra_vcr_x * vcr_z + vcr_scb_z *
        (rab_x * (-rb2 + rb2_x) + rab_y * rb_x * rb_y + rab_z * rb_x * rb_z)
    ],
                       [
                           -T2 * ra_z + vdot_prod * ra_vcr_y * vcr_x +
                           vcr_scb_x * (rab_x * rb_x * rb_y + rab_y *
                                        (-rb2 + rb2_y) + rab_z * rb_y * rb_z),
                           vdot_prod * ra_vcr_y * vcr_y + vcr_scb_y *
                           (rab_x * rb_x * rb_y + rab_y *
                            (-rb2 + rb2_y) + rab_z * rb_y * rb_z),
                           T2 * ra_x + vdot_prod * ra_vcr_y * vcr_z +
                           vcr_scb_z * (rab_x * rb_x * rb_y + rab_y *
                                        (-rb2 + rb2_y) + rab_z * rb_y * rb_z)
                       ],
                       [
                           T2 * ra_y + vdot_prod * ra_vcr_z * vcr_x +
                           vcr_scb_x *
                           (rab_x * rb_x * rb_z + rab_y * rb_y * rb_z + rab_z *
                            (-rb2 + rb2_z)), -T2 * ra_x +
                           vdot_prod * ra_vcr_z * vcr_y + vcr_scb_y *
                           (rab_x * rb_x * rb_z + rab_y * rb_y * rb_z + rab_z *
                            (-rb2 + rb2_z)),
                           vdot_prod * ra_vcr_z * vcr_z + vcr_scb_z *
                           (rab_x * rb_x * rb_z + rab_y * rb_y * rb_z + rab_z *
                            (-rb2 + rb2_z))
                       ]])

    dQ_dRAB = np.array(
        [[vcr_x * diff_vec[0], vcr_y * diff_vec[0], vcr_z * diff_vec[0]],
         [vcr_x * diff_vec[1], vcr_y * diff_vec[1], vcr_z * diff_vec[1]],
         [vcr_x * diff_vec[2], vcr_y * diff_vec[2], vcr_z * diff_vec[2]]])

    DerP += (cfact_biot * gamma_seg) * (dQ_dRA + dQ_dRB).T  # w.r.t. P
    DerA += (cfact_biot * gamma_seg) * (-dQ_dRAB - dQ_dRA).T  # w.r.t. A
    DerB += (cfact_biot * gamma_seg) * (dQ_dRAB - dQ_dRB).T  # w.r.t. B
예제 #7
0
def eval_panel_fast_coll(zetaP, ZetaPanel, vortex_radius, gamma_pan=1.0):
    """
    Computes derivatives of induced velocity w.r.t. coordinates of target point,
    zetaP, coordinates. Returns two elements:
        - DerP: derivative of induced velocity w.r.t. ZetaP, with:
            DerP.shape=(3,3) : DerC[ Uind_{x,y,z}, ZetaC_{x,y,z} ]

    The function is based on eval_panel_fast, but does not perform operations
    required to compute the derivatives w.r.t. the panel coordinates.
    """

    vortex_radius_sq = vortex_radius * vortex_radius
    DerP = np.zeros((3, 3))

    ### ---------------------------------------------- Compute common variables
    # these are constants or variables depending only on vertices and P coords
    Cfact = cfact_biot * gamma_pan

    # distance vertex ii-th from P
    R_list = zetaP - ZetaPanel
    r1_list = [algebra.norm3d(R_list[ii]) for ii in svec]
    r1inv_list = [1. / r1_list[ii] for ii in svec]
    Runit_list = [R_list[ii] * r1inv_list[ii] for ii in svec]
    Der_runit_list = [
        der_runit(R_list[ii], r1inv_list[ii], -r1inv_list[ii]**3)
        for ii in svec
    ]

    ### ------------------------------------------------- Loop through segments
    for aa, bb in LoopPanel:

        RAB = ZetaPanel[bb, :] - ZetaPanel[aa, :]  # segment vector
        Vcr = algebra.cross3(R_list[aa], R_list[bb])
        vcr2 = np.dot(Vcr, Vcr)

        if vcr2 < (vortex_radius_sq * algebra.normsq3d(RAB)):
            continue

        Tv = Runit_list[aa] - Runit_list[bb]
        dotprod = np.dot(RAB, Tv)

        ### ----------------------------------------- cross-product derivatives
        # lower triangular part only
        vcr2inv = 1. / vcr2
        vcr4inv = vcr2inv * vcr2inv
        diag_fact = Cfact * vcr2inv * dotprod
        off_fact = -2. * Cfact * vcr4inv * dotprod
        Dvcross = [[diag_fact + off_fact * Vcr[0]**2],
                   [
                       off_fact * Vcr[0] * Vcr[1],
                       diag_fact + off_fact * Vcr[1]**2
                   ],
                   [
                       off_fact * Vcr[0] * Vcr[2], off_fact * Vcr[1] * Vcr[2],
                       diag_fact + off_fact * Vcr[2]**2
                   ]]

        ### ---------------------------------------- difference term derivative
        Vsc = Vcr * vcr2inv * Cfact
        Ddiff = np.array([RAB * Vsc[0], RAB * Vsc[1], RAB * Vsc[2]])

        ### ------------------------------------------ Final assembly (crucial)

        # dQ_dRA=Dvcross_by_skew3d(Dvcross,-R_list[bb])\
        # 									 +np.dot(Ddiff, Der_runit_list[aa] )
        # dQ_dRB=Dvcross_by_skew3d(Dvcross, R_list[aa])\
        # 									 -np.dot(Ddiff, Der_runit_list[bb] )

        DerP += Dvcross_by_skew3d(Dvcross, RAB) + \
                +np.dot(Ddiff, Der_runit_list[aa] - Der_runit_list[bb])

    return DerP
예제 #8
0
def eval_panel_fast(zetaP, ZetaPanel, vortex_radius, gamma_pan=1.0):
    """
    Computes derivatives of induced velocity w.r.t. coordinates of target point,
    zetaP, and panel coordinates. Returns two elements:
        - DerP: derivative of induced velocity w.r.t. ZetaP, with:
            DerP.shape=(3,3) : DerC[ Uind_{x,y,z}, ZetaC_{x,y,z} ]
        - DerVertices: derivative of induced velocity wrt panel vertices, with:
            DerVertices.shape=(4,3,3) :
            DerVertices[ vertex number {0,1,2,3},  Uind_{x,y,z}, ZetaC_{x,y,z} ]

    The function is based on eval_panel_comp, but minimises operationsby
    recycling variables.
    """

    vortex_radius_sq = vortex_radius * vortex_radius
    DerP = np.zeros((3, 3))
    DerVertices = np.zeros((4, 3, 3))

    ### ---------------------------------------------- Compute common variables
    # these are constants or variables depending only on vertices and P coords
    Cfact = cfact_biot * gamma_pan

    # distance vertex ii-th from P
    R_list = zetaP - ZetaPanel
    r1_list = [algebra.norm3d(R_list[ii]) for ii in svec]
    r1inv_list = [1. / r1_list[ii] for ii in svec]
    Runit_list = [R_list[ii] * r1inv_list[ii] for ii in svec]
    Der_runit_list = [
        der_runit(R_list[ii], r1inv_list[ii], -r1inv_list[ii]**3)
        for ii in svec
    ]

    ### ------------------------------------------------- Loop through segments
    for aa, bb in LoopPanel:

        RAB = ZetaPanel[bb, :] - ZetaPanel[aa, :]  # segment vector
        Vcr = algebra.cross3(R_list[aa], R_list[bb])
        vcr2 = np.dot(Vcr, Vcr)

        if vcr2 < (vortex_radius_sq * algebra.normsq3d(RAB)):
            continue

        Tv = Runit_list[aa] - Runit_list[bb]
        dotprod = np.dot(RAB, Tv)

        ### ----------------------------------------- cross-product derivatives
        # lower triangular part only
        vcr2inv = 1. / vcr2
        vcr4inv = vcr2inv * vcr2inv
        diag_fact = Cfact * vcr2inv * dotprod
        off_fact = -2. * Cfact * vcr4inv * dotprod
        Dvcross = [[diag_fact + off_fact * Vcr[0]**2],
                   [
                       off_fact * Vcr[0] * Vcr[1],
                       diag_fact + off_fact * Vcr[1]**2
                   ],
                   [
                       off_fact * Vcr[0] * Vcr[2], off_fact * Vcr[1] * Vcr[2],
                       diag_fact + off_fact * Vcr[2]**2
                   ]]

        ### ---------------------------------------- difference term derivative
        Vsc = Vcr * vcr2inv * Cfact
        Ddiff = np.array([RAB * Vsc[0], RAB * Vsc[1], RAB * Vsc[2]])

        ### ---------------------------------------------------- RAB derivative
        dQ_dRAB = np.array([Tv * Vsc[0], Tv * Vsc[1], Tv * Vsc[2]])

        ### ------------------------------------------ Final assembly (crucial)

        dQ_dRA = Dvcross_by_skew3d(Dvcross, -R_list[bb]) \
                 + np.dot(Ddiff, Der_runit_list[aa])
        dQ_dRB = Dvcross_by_skew3d(Dvcross, R_list[aa]) \
                 - np.dot(Ddiff, Der_runit_list[bb])

        DerP += dQ_dRA + dQ_dRB  # w.r.t. P
        DerVertices[aa, :, :] -= dQ_dRAB + dQ_dRA  # w.r.t. A
        DerVertices[bb, :, :] += dQ_dRAB - dQ_dRB  # w.r.t. B

    # ### collocation point only
    # DerP +=Dvcross_by_skew3d(Dvcross,RA-RB)+np.dot(Ddiff,
    # 		  der_runit(RA,rainv,minus_rainv3)-der_runit(RB,rbinv,minus_rbinv3))

    return DerP, DerVertices