예제 #1
0
def eval(Zeta00, Zeta01, Zeta02, Zeta03, Uc):
    '''
	Returns a 4 x 3 array, containing the derivative of Wnc*Uc w.r.t the panel
	vertices coordinates.
	'''

    R02 = Zeta02 - Zeta00
    R13 = Zeta03 - Zeta01

    crR02R13 = libalg.cross3d(R02, R13)
    norm_crR02R13 = np.linalg.norm(crR02R13)
    cub_crR02R13 = norm_crR02R13**3

    Acr = libalg.cross3d(crR02R13, R13)
    Bcr = libalg.cross3d(crR02R13, R02)
    Cdot = np.dot(crR02R13, Uc)

    uc_x, uc_y, uc_z = Uc
    r02_x, r02_y, r02_z = R02
    r13_x, r13_y, r13_z = R13
    crR13Uc_x, crR13Uc_y, crR13Uc_z = libalg.cross3d(R13, Uc)
    crR02Uc_x, crR02Uc_y, crR02Uc_z = libalg.cross3d(R02, Uc)
    crR02R13_x, crR02R13_y, crR02R13_z = crR02R13
    Acr_x, Acr_y, Acr_z = Acr
    Bcr_x, Bcr_y, Bcr_z = Bcr

    # dUnorm_dR.shape=(2,3)
    dUnorm_dR = np.array(
        [[
            Acr_x * Cdot / cub_crR02R13 + crR13Uc_x / norm_crR02R13,
            Acr_y * Cdot / cub_crR02R13 + crR13Uc_y / norm_crR02R13,
            Acr_z * Cdot / cub_crR02R13 + crR13Uc_z / norm_crR02R13
        ],
         [
             -Bcr_x * Cdot / cub_crR02R13 - crR02Uc_x / norm_crR02R13,
             -Bcr_y * Cdot / cub_crR02R13 - crR02Uc_y / norm_crR02R13,
             -Bcr_z * Cdot / cub_crR02R13 - crR02Uc_z / norm_crR02R13
         ]])

    # Allocate
    dUnorm_dZeta = np.zeros((4, 3))
    for vv in range(4):  # loop through panel vertices
        for cc_zeta in range(3):  # loop panel vertices component
            for rr in range(2):  # loop segments R02, R13
                for cc_rvec in range(3):  # loop segment component
                    dUnorm_dZeta[vv,cc_zeta]+=\
                        dUnorm_dR[rr,cc_rvec]*dR_dZeta[vv,cc_zeta,rr,cc_rvec]

    return dUnorm_dZeta
예제 #2
0
def eval_seg_comp_loop(DerP, DerA, DerB, ZetaP, ZetaA, ZetaB, gamma_seg):
    '''
	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.
	'''

    Cfact = cfact_biot * gamma_seg

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

    # numerical radious
    if vcr2 < (VORTEX_RADIUS_SQ * libalg.normsq3d(RAB)):
        return

    ### other constants
    ra1, rb1 = libalg.norm3d(RA), libalg.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
예제 #3
0
def joukovski_qs_segment(zetaA,zetaB,v_mid,gamma=1.0,fact=0.5):
	'''
	Joukovski force over vetices A and B produced by the segment A->B.
	The factor fact allows to compute directly the contribution over the
	vertices A and B (e.g. 0.5) or include DENSITY.
	'''

	rab=zetaB-zetaA
	fs=libalg.cross3d(v_mid,rab)
	gfact=fact*gamma

	return gfact*fs
예제 #4
0
def panel_normal(ZetaPanel):
	'''
	return normal of panel with vertiex coordinates ZetaPanel, where:
		ZetaPanel.shape=(4,3)		
	'''
	
	# build cross-vectors
	r02=ZetaPanel[2,:]-ZetaPanel[0,:]
	r13=ZetaPanel[3,:]-ZetaPanel[1,:]

	nvec=libalg.cross3d(r02,r13)
	nvec=nvec/libalg.norm3d(nvec)

	return nvec
예제 #5
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=libalg.norm3d(ra),libalg.norm3d(rb)
	vcross=libalg.cross3d(ra,rb)
	vcross_sq=np.dot(vcross,vcross)

	# numerical radious
	if vcross_sq<(VORTEX_RADIUS_SQ*libalg.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
예제 #6
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]/libalg.norm3d(R_list[ii]) for ii in svec]

	for aa,bb in LoopPanel:

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

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

	return q
예제 #7
0
def eval_seg_exp_loop(DerP, DerA, DerB, ZetaP, ZetaA, ZetaB, gamma_seg):
    '''
	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 = libalg.cross3d(RA, RB)
    vcr2 = np.dot(Vcr, Vcr)

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

    # scaling
    ra1, rb1 = libalg.norm3d(RA), libalg.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. * libalg.cross3d(RA, Vcr)
    rb_vcr_x, rb_vcr_y, rb_vcr_z = 2. * libalg.cross3d(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
예제 #8
0
def eval_panel_fast_coll(zetaP, ZetaPanel, 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.
	'''

    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 = [libalg.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 = libalg.cross3d(R_list[aa], R_list[bb])
        vcr2 = np.dot(Vcr, Vcr)

        if vcr2 < (VORTEX_RADIUS_SQ * libalg.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
예제 #9
0
def eval_panel_fast(zetaP, ZetaPanel, 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.
	'''

    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 = [libalg.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 = libalg.cross3d(R_list[aa], R_list[bb])
        vcr2 = np.dot(Vcr, Vcr)

        if vcr2 < (VORTEX_RADIUS_SQ * libalg.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