def panel_positions(self, DSTEP1, DSTEP2, DSTEP3, T, THETA, HEAVE):
        """Updates all the absolute-frame coordinates of the body.

        Args:
            DSTEP: Small incremental distance to pass into neutral_plane().
            T: Time of current step.
            THETA: Current pitching angle.

        """
        bfx = self.BF.x
        bfy = self.BF.y                 #No y information coming from the geometry class yet
        bfz = self.BF.z
        bfz_col = self.BF.z_col
        V0 = self.V0 # Used only for x_le

        (x_neut, y_neut, z_neut) = self.neutral_plane(bfx, bfy, T, THETA, HEAVE)

        # Infinitesimal differences on the neutral axis to calculate the tangential and normal vectors
        v1 = (xdp_y, ydp_y, zdp_y) = self.neutral_plane(bfx, bfy, T, THETA, HEAVE, 0, DSTEP2, DSTEP3)
        v2 = (xdm_y, ydm_y, zdm_y) = self.neutral_plane(bfx, bfy, T, THETA, HEAVE, 0, -DSTEP2, -DSTEP3)

        v3 = (xdp_x, ydp_x, zdp_x) = self.neutral_plane(bfx, bfy, T, THETA, HEAVE, DSTEP1, 0, 0)
        v4 = (xdm_x, ydm_x, zdm_x) = self.neutral_plane(bfx, bfy, T, THETA, HEAVE, -DSTEP1, 0, 0)
        
        # Absolute-frame panel endpoint positions for time t
        afx = x_neut + point_vectors(v1,v2,v3,v4)[1]*bfz
        afy = y_neut + point_vectors(v1,v2,v3,v4)[2]*bfz
        afz = z_neut + point_vectors(v1,v2,v3,v4)[3]*bfz

        # Absolute-frame panel midpoint positions
        x_mid = (afx[1:,:-1]+afx[:-1,:-1])/2
        y_mid = (afy[1:,:-1]+afy[:-1,:-1])/2
        z_mid = (afz[1:,:-1]+afz[:-1,:-1])/2

        # Collocation points are the points where impermeable boundary condition is forced
        # They should be shifted inside or outside of the boundary depending on the dirichlet or neumann condition
        # Shifting surface collocation points some percent of the height from the neutral axis
        # Normal vectors point outward but positive S is inward, so the shift must be subtracted from the panel midpoints
        afx_col = x_mid - self.S*panel_vectors(afx, afz)[2]*np.absolute(bfz_col)
        afy_col = y_mid - self.S*panel_vectors(afx, afz)[2]*np.absolute(bfz_col)
        afz_col = z_mid - self.S*panel_vectors(afx, afz)[3]*np.absolute(bfz_col)

        self.AF.x = afx
        self.AF.y = afy
        self.AF.z = afz
        self.AF.x_col = afx_col
        self.AF.y_col = afy_col
        self.AF.z_col = afz_col
        self.AF.x_mid = x_mid
        self.AF.y_mid = y_mid
        self.AF.z_mid = z_mid
        self.AF.x_neut = x_neut
        self.AF.y_neut = y_neut
        self.AF.z_neut = z_neut
        # Location of leading edge (currently pitching motion only)
        self.AF.x_le = V0*T
        self.AF.y_le = 0
        self.AF.z_le = HEAVE
    def pressure(self, RHO, DEL_T, i):
        """Calculates the pressure distribution along the body's surface.

        Args:
            RHO: Fluid density.
            DEL_T: Time step length.
            i: Time step number.
        """

        (tx,tz,nx,nz,lpanel) = panel_vectors(self.AF.x,self.AF.z)

        # Tangential panel velocity dmu/dl, first-order differencing
        dmu_dl = np.empty(self.N)
        dmu_dl[0] = (self.mu[0]-self.mu[1]) / (lpanel[0]/2 + lpanel[1]/2)
        dmu_dl[1:-1] = (self.mu[:-2]-self.mu[2:]) / (lpanel[:-2]/2 + lpanel[1:-1] + lpanel[2:]/2)
        dmu_dl[-1] = (self.mu[-2]-self.mu[-1]) / (lpanel[-2]/2 + lpanel[-1]/2)

        # Potential change dmu/dt, second-order differencing after first time step
        if i == 0:
            dmu_dt = self.mu / DEL_T
        if i == 1:
            dmu_dt = (self.mu - self.mu_past[0,:])/DEL_T
        else:
            dmu_dt = (3*self.mu - 4*self.mu_past[0,:] + self.mu_past[1,:])/(2*DEL_T)

        # Unsteady pressure calculation (from Matlab code)
        qpx_tot = dmu_dl*tx + self.sigma*nx
        qpz_tot = dmu_dl*tz + self.sigma*nz

        self.p = -RHO*(qpx_tot**2 + qpz_tot**2)/2. + RHO*dmu_dt + RHO*(qpx_tot*(self.V0+self.vx) + qpz_tot*self.vz)
        self.cp = self.p / (0.5*RHO*self.V0**2)
    def fsi_panel_positions(self, FSI, T, THETA, HEAVE):
        self.AF.x = self.AF.x + (FSI.fluidNodeDispl[:,0] - FSI.fluidNodeDisplOld[:,0])
        self.AF.z = self.AF.z + (FSI.fluidNodeDispl[:,1] - FSI.fluidNodeDisplOld[:,1])                 

        self.AF.x_mid[0,:] = (self.AF.x[:-1] + self.AF.x[1:])/2
        self.AF.z_mid[0,:] = (self.AF.z[:-1] + self.AF.z[1:])/2

        self.BF.x = (self.AF.x - self.AF.x_le) * np.cos(-1*THETA) - (self.AF.z - self.AF.z_le) * np.sin(-1*THETA)
        self.BF.z = (self.AF.z - self.AF.z_le) * np.cos(-1*THETA) + (self.AF.x - self.AF.x_le) * np.sin(-1*THETA)
        self.BF.x_col = ((self.BF.x[1:] + self.BF.x[:-1])/2)
        self.BF.z_col = ((self.BF.z[1:] + self.BF.z[:-1])/2)

        (self.AF.x_neut, self.AF.z_neut) = self.neutral_axis(self.BF.x, T, THETA, HEAVE)

        self.AF.x_col = self.AF.x_mid[0,:] - self.S*panel_vectors(self.AF.x, self.AF.z)[2]*np.absolute(self.zcval) #self.BF.z_col
        self.AF.z_col = self.AF.z_mid[0,:] - self.S*panel_vectors(self.AF.x, self.AF.z)[3]*np.absolute(self.zcval)
    def force(self, THETA, RHO, V0, C, B, i):
        """Calculates drag and lift forces acting on the body.

        Args:
            i: Time step number.
        """
        
        (tx,tz,nx,nz,lpanel) = panel_vectors(self.AF.x, self.AF.z)

        delFx = -self.p * lpanel * B * nx
        delFz = -self.p * lpanel * B * nz
        delF = np.array([delFx, delFz])
#        delF = -np.multiply(np.kron(self.p, np.array([1, 1])), np.array([nx, nz]).T)
        delP = np.sum(-delF * np.array([self.vx.T, self.vz.T]), 1)

        force = np.sum(delF,1)
        lift = force[1] * np.cos(THETA) - force[0] * np.sin(THETA)
        thrust = -(force[1] * np.sin(THETA) + force[0] * np.cos(THETA))
        power = np.sum(delP, 0)
        
        self.Cf = np.sqrt(force[0]**2 + force[1]**2) / (0.5 * RHO * V0**2 * C *B)
        self.Cl = lift /(0.5 * RHO * V0**2 * C *B)
        self.Ct = thrust / (0.5 * RHO * V0**2 * C *B)
        self.Cpow = power /  (0.5 * RHO * V0**3 * C *B)
        
#        Body.drag[i-1] = np.dot(self.p[i-1,:]*lpanel, np.reshape(tx,(self.N,1)))\
#                      + np.dot(self.p[i-1,:]*lpanel, np.reshape(-tz,(self.N,1)))
#
#        self.lift[i-1] = np.dot(self.p[i-1,:]*lpanel, np.reshape(-nz,(self.N,1)))\
#                      + np.dot(self.p[i-1,:]*lpanel, np.reshape(nx,(self.N,1)))
    def panel_positions(self, DSTEP, T):
        """Updates all the absolute-frame coordinates of the body.

        Args:
            DSTEP: Small incremental distance to pass into neutral_axis().
            T: Time of current step.
            bfx, bfz: Body-frame x- and z-coordinates.
            bfz_col: Body-frame collocation z-coordinates (unshifted)
            V0: Free-stream velocity.
        """
        bfx = self.BF.x
        bfz = self.BF.z
        bfz_col = self.BF.z_col
        V0 = self.V0 # Used only for x_le

        (x_neut, z_neut) = self.neutral_axis(bfx, T)

        # Infinitesimal differences on the neutral axis to calculate the tangential and normal vectors
        (xdp_s, zdp_s) = self.neutral_axis(bfx, T, DSTEP)
        (xdm_s, zdm_s) = self.neutral_axis(bfx, T, -DSTEP)

        # Absolute-frame panel endpoint positions for time t
        afx = x_neut + point_vectors(xdp_s, xdm_s, zdp_s, zdm_s)[2]*bfz
        afz = z_neut + point_vectors(xdp_s, xdm_s, zdp_s, zdm_s)[3]*bfz

        # Absolute-frame panel midpoint positions
        x_mid = (afx[:-1]+afx[1:])/2
        z_mid = (afz[:-1]+afz[1:])/2

        # Collocation points are the points where impermeable boundary condition is forced
        # They should be shifted inside or outside of the boundary depending on the dirichlet or neumann condition
        # Shifting surface collocation points some percent of the height from the neutral axis
        # Normal vectors point outward but positive S is inward, so the shift must be subtracted from the panel midpoints
        afx_col = x_mid - self.S*panel_vectors(afx, afz)[2]*np.absolute(bfz_col)
        afz_col = z_mid - self.S*panel_vectors(afx, afz)[3]*np.absolute(bfz_col)

        self.AF.x = afx
        self.AF.z = afz
        self.AF.x_col = afx_col
        self.AF.z_col = afz_col
        self.AF.x_mid[0,:] = x_mid
        self.AF.z_mid[0,:] = z_mid
        self.AF.x_neut = x_neut
        self.AF.z_neut = z_neut
        # Location of leading edge (assuming pitching motion only)
        self.AF.x_le = V0*T
        self.AF.z_le = 0.
Beispiel #6
0
    def edge_shed(self, DEL_T, i):
        """Updates the position of the Edge panel.

        This should only be done once each time step for a swimmer.
        The edge panel's length is based on Edge.CE.
        The strength of this panel is solved for in kutta().

        Args:
            DEL_T: Time step length.
            i: Time step number.
            Body: Body of the swimmer.
            Edge: Edge panel of separation.
        """
        Body = self.Body
        Edge = self.Edge

        Edge.x[0] = Body.AF.x[0]
        Edge.z[0] = Body.AF.z[0]
        Edge.x[1] = Body.AF.x[0] + Edge.CE*panel_vectors(Body.AF.x_neut,Body.AF.z_neut)[0][0]*Body.V0*DEL_T
        Edge.z[1] = Body.AF.z[0] + Edge.CE*panel_vectors(Body.AF.x_neut,Body.AF.z_neut)[1][0]*Body.V0*DEL_T
Beispiel #7
0
def s2f(Solid, tempNodes, SW_INTERP_MTD):
    # Build arrays containing the new fluid panel node positions.
    newxp = np.zeros_like(Solid.meanline_p0)
    newzp = np.zeros_like(Solid.meanline_p0)
    (tx,tz,nx,nz,lelem) = panel_vectors(tempNodes[:,0], tempNodes[:,1])
    for i in xrange(Solid.xp_0.shape[0]):
        assoElem =  Solid.elemAsso[i]
        percent = (Solid.meanline_p0[i] - Solid.nodes[assoElem,2]) / (Solid.nodes[assoElem+1,2] - Solid.nodes[assoElem,2])
        newxp[i] = tempNodes[assoElem,0] + percent * lelem[assoElem] * tx[assoElem] + Solid.zp_0[i] * nx[assoElem]
        newzp[i] = tempNodes[assoElem,1] + percent * lelem[assoElem] * tz[assoElem] + Solid.zp_0[i] * nz[assoElem]
      
    return (newxp, newzp)
    def surface_kinematics(self, DSTEP, TSTEP, THETA_MINUS, THETA_PLUS, HEAVE_MINUS, HEAVE_PLUS, DEL_T, T, i):
        """Calculates the body-frame surface velocities of body panels.

        Also finds the body panel source strengths based on these surface
        velocities.

        Args:
            DSTEP, TSTEP: Incremental distance/time passed into neutral_axis().
            DEL_T: Time step length.
            T: Time of current step.
            i: Time step number.
            THETA_MINUS: Pitching angle minus a small time difference (TSTEP)
            THETA_PLUS: Pitching angle plus a small time difference (TSTEP)
        """
        if i == 0:

            x_col = self.BF.x_col
            z_col = self.BF.z_col

            # Panel midpoint velocity calculations
            # Calculating the surface positions at tplus(tp) and tminus(tm)
            (xtpneut, ztpneut) = self.neutral_axis(x_col, T, THETA_PLUS, HEAVE_PLUS, 0)
            (xtpdp, ztpdp) = self.neutral_axis(x_col, T, THETA_PLUS, HEAVE_PLUS, DSTEP)
            (xtpdm, ztpdm) = self.neutral_axis(x_col, T, THETA_PLUS, HEAVE_PLUS, -DSTEP)
            (xtmneut, ztmneut) = self.neutral_axis(x_col, T, THETA_MINUS, HEAVE_MINUS, 0)
            (xtmdp, ztmdp) = self.neutral_axis(x_col, T, THETA_MINUS, HEAVE_MINUS, DSTEP)
            (xtmdm, ztmdm) = self.neutral_axis(x_col, T, THETA_MINUS, HEAVE_MINUS, -DSTEP)

            # Displaced airfoil's panel midpoints for times tplus(tp) and tminus(tm)
            xctp = xtpneut + point_vectors(xtpdp, xtpdm, ztpdp, ztpdm)[2]*z_col
            xctm = xtmneut + point_vectors(xtmdp, xtmdm, ztmdp, ztmdm)[2]*z_col

            zctp = ztpneut + point_vectors(xtpdp, xtpdm, ztpdp, ztpdm)[3]*z_col
            zctm = ztmneut + point_vectors(xtmdp, xtmdm, ztmdp, ztmdm)[3]*z_col

            # Velocity calculations on the surface panel midpoints
            self.vx = (xctp - xctm)/(2*TSTEP)
            self.vz = (zctp - zctm)/(2*TSTEP)

        elif i == 1:
            # First-order backwards differencing of body collocation point positions
            self.vx = (self.AF.x_mid[0,:]-self.AF.x_mid[1,:])/DEL_T - self.V0
            self.vz = (self.AF.z_mid[0,:]-self.AF.z_mid[1,:])/DEL_T

        else:
            # Second-order backwards differencing of body collocation point positions
            self.vx = (3*self.AF.x_mid[0,:]-4*self.AF.x_mid[1,:]+self.AF.x_mid[2,:])/(2*DEL_T) - self.V0
            self.vz = (3*self.AF.z_mid[0,:]-4*self.AF.z_mid[1,:]+self.AF.z_mid[2,:])/(2*DEL_T)

        # Body source strengths with normal vector pointing outward (overall sigma pointing outward)
        (nx,nz) = panel_vectors(self.AF.x,self.AF.z)[2:4]
        self.sigma = nx*(self.V0 + self.vx) + nz*self.vz
    def force(self, i):
        """Calculates drag and lift forces acting on the body.

        Args:
            i: Time step number.
        """
        (tx,tz,nx,nz,lpanel) = panel_vectors(self.AF.x, self.AF.z)

        Body.drag[i-1] = np.dot(self.p[i-1,:]*lpanel, np.reshape(tx,(self.N,1)))\
                      + np.dot(self.p[i-1,:]*lpanel, np.reshape(-tz,(self.N,1)))

        self.lift[i-1] = np.dot(self.p[i-1,:]*lpanel, np.reshape(-nz,(self.N,1)))\
                      + np.dot(self.p[i-1,:]*lpanel, np.reshape(nx,(self.N,1)))
Beispiel #10
0
def s2f(Solid, tempNodes, SW_INTERP_MTD):
    # Build arrays containing the new fluid panel node positions.
    newxp = np.zeros_like(Solid.meanline_p0)
    newzp = np.zeros_like(Solid.meanline_p0)
    (tx, tz, nx, nz, lelem) = panel_vectors(tempNodes[:, 0], tempNodes[:, 1])
    for i in xrange(Solid.xp_0.shape[0]):
        assoElem = Solid.elemAsso[i]
        percent = (Solid.meanline_p0[i] - Solid.nodes[assoElem, 2]) / (
            Solid.nodes[assoElem + 1, 2] - Solid.nodes[assoElem, 2])
        newxp[i] = tempNodes[assoElem, 0] + percent * lelem[assoElem] * tx[
            assoElem] + Solid.zp_0[i] * nx[assoElem]
        newzp[i] = tempNodes[assoElem, 1] + percent * lelem[assoElem] * tz[
            assoElem] + Solid.zp_0[i] * nz[assoElem]

    return (newxp, newzp)
    def surface_kinematics(self, DSTEP, TSTEP, DEL_T, T, i):
        """Calculates the body-frame surface velocities of body panels.

        Args:
            DSTEP, TSTEP: Incremental distance/time passed into neutral_axis().
            DEL_T: Time step length.
            T: Time of current step.
            i: Time step number.
            x_col, z_col: Unshifted body-frame collocation point coordinates.
        """
        if i == 0:

            x_col = self.BF.x_col
            z_col = self.BF.z_col

            # Panel midpoint velocity calculations
            # Calculating the surface positions at tplus(tp) and tminus(tm)
            (xtpneut, ztpneut) = self.neutral_axis(x_col, T, 0, TSTEP)
            (xtpdp, ztpdp) = self.neutral_axis(x_col, T, DSTEP, TSTEP)
            (xtpdm, ztpdm) = self.neutral_axis(x_col, T, -DSTEP, TSTEP)
            (xtmneut, ztmneut) = self.neutral_axis(x_col, T, 0, -TSTEP)
            (xtmdp, ztmdp) = self.neutral_axis(x_col, T, DSTEP, -TSTEP)
            (xtmdm, ztmdm) = self.neutral_axis(x_col, T, -DSTEP, -TSTEP)

            # Displaced airfoil's panel midpoints for times tplus(tp) and tminus(tm)
            xctp = xtpneut + point_vectors(xtpdp, xtpdm, ztpdp, ztpdm)[2]*z_col
            xctm = xtmneut + point_vectors(xtmdp, xtmdm, ztmdp, ztmdm)[2]*z_col

            zctp = ztpneut + point_vectors(xtpdp, xtpdm, ztpdp, ztpdm)[3]*z_col
            zctm = ztmneut + point_vectors(xtmdp, xtmdm, ztmdp, ztmdm)[3]*z_col

            # Velocity calculations on the surface panel midpoints
            self.vx = (xctp - xctm)/(2*TSTEP)
            self.vz = (zctp - zctm)/(2*TSTEP)

        elif i == 1:
            # First-order backwards differencing of body collocation point positions
            self.vx = (self.AF.x_mid[0,:]-self.AF.x_mid[1,:])/DEL_T - self.V0
            self.vz = (self.AF.z_mid[0,:]-self.AF.z_mid[1,:])/DEL_T

        else:
            # Second-order backwards differencing of body collocation point positions
            self.vx = (3*self.AF.x_mid[0,:]-4*self.AF.x_mid[1,:]+self.AF.x_mid[2,:])/(2*DEL_T) - self.V0
            self.vz = (3*self.AF.z_mid[0,:]-4*self.AF.z_mid[1,:]+self.AF.z_mid[2,:])/(2*DEL_T)

        (nx,nz) = panel_vectors(self.AF.x,self.AF.z)[2:4]
        self.sigma = nx*(self.V0 + self.vx) + nz*self.vz
def body_plot(Swimmers, SW_PLOT_FIG):
    global n_fig
        
    if SW_PLOT_FIG:
        figure = plt.figure(1)
        ax = figure.gca(projection='3d')
#        ax.set_aspect('equal') This feature has not been implemented in 3D plotting yet
        figure.set_size_inches(16, 9)
        plt.tick_params(labelsize=28)
            
        for Swim in Swimmers:
            (nx, ny, nz, txs, tys, tzs, txc, tyc, tzc, lps, lpc) = panel_vectors(Swim.Body.AF.x, Swim.Body.AF.y, Swim.Body.AF.z)
            x = Swim.Body.AF.x_mid[::5,::5,0] + 0.1 * nx[::5,::5]
            y = Swim.Body.AF.y_mid[::5,::5,0] + 0.1 * ny[::5,::5]
            z = Swim.Body.AF.z_mid[::5,::5,0] + 0.1 * nz[::5,::5]
            nx = nx[::5,::5]
            ny = ny[::5,::5]
            nz = nz[::5,::5]
            ax.quiver(x, y, z, nx, ny, nz, length=0.1, color='r')
            ax.quiver(Swim.Body.AF.x_mid[::5,::5,0], Swim.Body.AF.y_mid[::5,::5,0], Swim.Body.AF.z_mid[::5,::5,0], txs[::5,::5], tys[::5,::5], tzs[::5,::5], length=0.1, color='g')
            ax.quiver(Swim.Body.AF.x_mid[::5,::5,0], Swim.Body.AF.y_mid[::5,::5,0], Swim.Body.AF.z_mid[::5,::5,0], txc[::5,::5], tyc[::5,::5], tzc[::5,::5], length=0.1, color='b')
            ax.plot_surface(Swim.Body.AF.x, Swim.Body.AF.y, Swim.Body.AF.z, rstride=1, cstride=1, linewidth=0, color='k', antialiased=True)
    
        # Determine if the output directory exists. If not, create the directory.
        if not os.path.exists('./movies'):
            os.makedirs('./movies')
        
        ax.set_xlim(np.min(Swim.Body.AF.x)-1.25, np.min(Swim.Body.AF.x)+1.25)
        ax.set_ylim(-1.25, 1.25)
        ax.set_zlim(-1.25, 1.25)
        ax.view_init(elev=18, azim=-124)

        ax.set_xlabel('$X$ $[m]$', fontsize=28)
        ax.set_ylabel('$Y$ $[m]$', fontsize=28)
        ax.set_zlabel('$Z$ $[m]$', fontsize=28)
        ax.xaxis._axinfo['label']['space_factor'] = 2.0
        ax.yaxis._axinfo['label']['space_factor'] = 2.0
        ax.zaxis._axinfo['label']['space_factor'] = 2.0
            
        figure.savefig('./movies/%05i.png' % (n_fig), format='png')
        
        plt.clf()
    
    n_fig += 1
    def force(self, THETA, RHO, V0, C, B, i, SW_SV_FORCES):
        """Calculates drag and lift forces acting on the body.

        Args:
            i: Time step number.
        """
        (tx,tz,nx,nz,lpanel) = panel_vectors(self.AF.x, self.AF.z)

        delFx = -self.p * lpanel * B * nx
        delFz = -self.p * lpanel * B * nz
        delF = np.array([delFx, delFz])
        delP = np.sum(-delF * np.array([self.vx.T, self.vz.T]), 1)

        force = np.sum(delF,1)
        lift = force[1]
        thrust = -force[0]
#        lift = force[1] * np.cos(THETpythonforce[0] * np.cos(THETA))
        power = np.sum(delP, 0)
        
        self.Cf = np.sqrt(force[0]**2 + force[1]**2) / (0.5 * RHO * np.abs(V0)**2 * C * B)
        self.Cl = lift /(0.5 * RHO * np.abs(V0)**2 * C * B)
        self.Ct = thrust / (0.5 * RHO * np.abs(V0)**2 * C * B)
        self.Cpow = power /  (0.5 * RHO * np.abs(V0)**3 * C * B)
    def force(self, THETA, RHO, V0, C, B, i):
        """Calculates drag, lift, and thrust forces acting on the body. 
        Calculates input power.

        Args:
            i: Time step number.
        """
        
        (tx,tz,nx,nz,lpanel) = panel_vectors(self.AF.x, self.AF.z)

        delFx = -self.p * lpanel * B * nx
        delFz = -self.p * lpanel * B * nz
        delF = np.array([delFx, delFz])
        delP = np.sum(-delF * np.array([self.vx.T, self.vz.T]), 1)

        force = np.sum(delF,1)
        lift = force[1] * np.cos(THETA) - force[0] * np.sin(THETA)
        thrust = -(force[1] * np.sin(THETA) + force[0] * np.cos(THETA))
        power = np.sum(delP, 0)
        
        self.Cf = np.sqrt(force[0]**2 + force[1]**2) / (0.5 * RHO * V0**2 * C *B)
        self.Cl = lift /(0.5 * RHO * V0**2 * C *B)
        self.Ct = thrust / (0.5 * RHO * V0**2 * C *B)
        self.Cpow = power /  (0.5 * RHO * V0**3 * C *B)
def wake_rollup(Swimmers, DEL_T, i, P):
    """Performs wake rollup on the swimmers' wake panels.

    Args:
        Swimmers: List of Swimmer objects being simulated.
        DEL_T: Time step length.
        i: Time step number.
    """
    if (P['SW_ROLLUP']):
        # Wake panels initialize when i==1
        if i == 0:
            pass

        else:
            NT = i  # Number of targets (wake panel points that are rolling up)
            for SwimT in Swimmers:
                SwimT.Wake.vx = np.zeros(NT)
                SwimT.Wake.vz = np.zeros(NT)
                DELTA_CORE = SwimT.DELTA_CORE
                for SwimI in Swimmers:
                    # Coordinate transformation for body panels influencing wake
                    (xp1, xp2, zp) = transformation(SwimT.Wake.x[1:i + 1],
                                                    SwimT.Wake.z[1:i + 1],
                                                    SwimI.Body.AF.x,
                                                    SwimI.Body.AF.z)

                    # Angle of normal vector with respect to global z-axis
                    (nx, nz) = panel_vectors(SwimI.Body.AF.x,
                                             SwimI.Body.AF.z)[2:4]
                    beta = np.arctan2(-nx, nz)

                    # Katz-Plotkin eqns 10.20 and 10.21 for body source influence
                    dummy1 = np.log(
                        (xp1**2 + zp**2) / (xp2**2 + zp**2)) / (4 * np.pi)
                    dummy2 = (np.arctan2(zp, xp2) -
                              np.arctan2(zp, xp1)) / (2 * np.pi)

                    # Rotate back to global coordinates
                    dummy3 = dummy1 * np.cos(beta) - dummy2 * np.sin(beta)
                    dummy4 = dummy1 * np.sin(beta) + dummy2 * np.cos(beta)

                    # Finish eqns 10.20 and 10.21 for induced velocity by multiplying with sigma
                    SwimT.Wake.vx += np.dot(dummy3, SwimI.Body.sigma)
                    SwimT.Wake.vz += np.dot(dummy4, SwimI.Body.sigma)

                    # Formation of (x-x0) and (z-z0) matrices, similar to xp1/xp2/zp but coordinate transformation is not necessary
                    NI = SwimI.Body.N + 1
                    xp = np.repeat(SwimT.Wake.x[1:i + 1, np.newaxis], NI,
                                   1) - np.repeat(
                                       SwimI.Body.AF.x[:, np.newaxis].T, NT, 0)
                    zp = np.repeat(SwimT.Wake.z[1:i + 1, np.newaxis], NI,
                                   1) - np.repeat(
                                       SwimI.Body.AF.z[:, np.newaxis].T, NT, 0)

                    # Find distance r_b between each influence/target
                    r_b = np.sqrt(xp**2 + zp**2)

                    # Katz-Plotkin eqns 10.9 and 10.10 for body doublet (represented as point vortices) influence
                    dummy1 = zp / (2 * np.pi * (r_b**2 + DELTA_CORE**2))
                    dummy2 = -xp / (2 * np.pi * (r_b**2 + DELTA_CORE**2))

                    # Finish eqns 10.9 and 10.10 by multiplying with Body.gamma, add to induced velocity
                    SwimT.Wake.vx += np.dot(dummy1, SwimI.Body.gamma)
                    SwimT.Wake.vz += np.dot(dummy2, SwimI.Body.gamma)

                    # Formation of (x-x0) and (z-z0) matrices, similar to xp1/xp2/zp but coordinate transformation is not necessary
                    NI = SwimI.Edge.N + 1
                    xp = np.repeat(SwimT.Wake.x[1:i + 1, np.newaxis], NI,
                                   1) - np.repeat(
                                       SwimI.Edge.x[:, np.newaxis].T, NT, 0)
                    zp = np.repeat(SwimT.Wake.z[1:i + 1, np.newaxis], NI,
                                   1) - np.repeat(
                                       SwimI.Edge.z[:, np.newaxis].T, NT, 0)

                    # Find distance r_e between each influence/target
                    r_e = np.sqrt(xp**2 + zp**2)

                    # Katz-Plotkin eqns 10.9 and 10.10 for edge (as point vortices) influence
                    dummy1 = zp / (2 * np.pi * (r_e**2 + DELTA_CORE**2))
                    dummy2 = -xp / (2 * np.pi * (r_e**2 + DELTA_CORE**2))

                    # Finish eqns 10.9 and 10.10 by multiplying with Edge.gamma, add to induced velocity
                    SwimT.Wake.vx += np.dot(dummy1, SwimI.Edge.gamma)
                    SwimT.Wake.vz += np.dot(dummy2, SwimI.Edge.gamma)

                    # Formation of (x-x0) and (z-z0) matrices, similar to xp1/xp2/zp but coordinate transformation is not necessary
                    NI = i + 1
                    xp = np.repeat(
                        SwimT.Wake.x[1:i + 1, np.newaxis], NI, 1) - np.repeat(
                            SwimI.Wake.x[:i + 1, np.newaxis].T, NT, 0)
                    zp = np.repeat(
                        SwimT.Wake.z[1:i + 1, np.newaxis], NI, 1) - np.repeat(
                            SwimI.Wake.z[:i + 1, np.newaxis].T, NT, 0)

                    # Find distance r_w between each influence/target
                    r_w = np.sqrt(xp**2 + zp**2)

                    # Katz-Plotkin eqns 10.9 and 10.10 for wake (as point vortices) influence
                    dummy1 = zp / (2 * np.pi * (r_w**2 + DELTA_CORE**2))
                    dummy2 = -xp / (2 * np.pi * (r_w**2 + DELTA_CORE**2))

                    # Finish eqns 10.9 and 10.10 by multiplying with Wake.gamma, add to induced velocity
                    SwimT.Wake.vx += np.dot(dummy1, SwimI.Wake.gamma[:i + 1])
                    SwimT.Wake.vz += np.dot(dummy2, SwimI.Wake.gamma[:i + 1])

            for Swim in Swimmers:
                # Modify wake with the total induced velocity
                Swim.Wake.x[1:i + 1] += Swim.Wake.vx * DEL_T
                Swim.Wake.z[1:i + 1] += Swim.Wake.vz * DEL_T
    def surface_kinematics(self, P, i):
        """Calculates the body-frame surface velocities of body panels.

        Also finds the body panel source strengths based on these surface
        velocities.

        Args:
            DSTEP, TSTEP: Incremental distance/time passed into neutral_axis().
            DEL_T: Time step length.
            T: Time of current step.
            i: Time step number.
            THETA_MINUS: Pitching angle minus a small time difference (TSTEP)
            THETA_PLUS: Pitching angle plus a small time difference (TSTEP)
        """
        TSTEP = P['TSTEP']
        THETA_MINUS = P['THETA_MINUS'][i]
        THETA_PLUS = P['THETA_PLUS'][i]
        HEAVE_MINUS = P['HEAVE_MINUS'][i]
        HEAVE_PLUS = P['HEAVE_PLUS'][i]
        DEL_T = P['DEL_T']
        T = P['T'][i]

        if i == 0:
            # Use the prescribed kinematics to do a central difference over a
            # small period of time
            x_col = self.BF.x_col
            z_col = self.BF.z_col

            xp = x_col * np.cos(THETA_PLUS) - z_col * np.sin(
                THETA_PLUS) + self.V * (T + TSTEP)
            zp = x_col * np.sin(THETA_PLUS) + z_col * np.cos(
                THETA_PLUS) + HEAVE_PLUS

            xm = x_col * np.cos(THETA_MINUS) - z_col * np.sin(
                THETA_MINUS) + self.V * (T - TSTEP)
            zm = x_col * np.sin(THETA_MINUS) + z_col * np.cos(
                THETA_MINUS) + HEAVE_MINUS

            self.vx = (xp - xm) / (2. * TSTEP) - self.V
            self.vz = (zp - zm) / (2. * TSTEP)

        elif i == 1:
            # First-order backwards differencing of body collocation point positions
            self.vx = (self.AF.x_mid[0, :] -
                       self.AF.x_mid[1, :]) / DEL_T - self.V
            self.vz = (self.AF.z_mid[0, :] - self.AF.z_mid[1, :]) / DEL_T

        elif i == 2 or i == 3:
            # Second-order backwards differencing of body collocation point positions
            self.vx = (3 * self.AF.x_mid[0, :] - 4 * self.AF.x_mid[1, :] +
                       self.AF.x_mid[2, :]) / (2 * DEL_T) - self.V
            self.vz = (3 * self.AF.z_mid[0, :] - 4 * self.AF.z_mid[1, :] +
                       self.AF.z_mid[2, :]) / (2 * DEL_T)

        else:
            # Fourth-order backwards differencing of body collocation point positions
            self.vx = (25 / 12 * self.AF.x_mid[0, :] - 4 * self.AF.x_mid[1, :]
                       + 3 * self.AF.x_mid[2, :] - 4 / 3 * self.AF.x_mid[3, :]
                       + 1 / 4 * self.AF.x_mid[4, :]) / DEL_T - self.V
            self.vz = (25 / 12 * self.AF.z_mid[0, :] -
                       4 * self.AF.z_mid[1, :] + 3 * self.AF.z_mid[2, :] -
                       4 / 3 * self.AF.z_mid[3, :] +
                       1 / 4 * self.AF.z_mid[4, :]) / DEL_T

        # Body source strengths with normal vector pointing outward (overall sigma pointing outward)
        (nx, nz) = panel_vectors(self.AF.x, self.AF.z)[2:4]
        self.sigma = nx * (self.V + self.vx) + nz * self.vz
Beispiel #17
0
    def setInterfaceForce(self, Solid, Body, PyFEA, THETA, HEAVE, outerCorr, 
                          SW_VISC_DRAG, delFs, SW_INTERP_MTD, C, i_t):
        """
        Updates the structural mesh position, calculates the traction forces on
        the free nodes, and determines the initial condisitons for the timestep.
        
        Args:
            Solid (object): A solid object created from the solid class.
            Body (object): A body object created from the swimmer class.
            PyFEA (object): A FEA solver object created from the PyFEA class.
            t (float): Current simulation time.
            TSTEP (flaot): Small, incremental distance/time offsets.
            outerCorr (int): Current FSI subiteration number.
            SW_VISC_DRAG (bool): Used to determine 
                if viscous forces should be included.
            delFs (float): NumPy array of viscous force components.
            SW_INTERP_MTD (bool): Used to determine if linear or cubic spline 
                interpolation between fluid and solid domains should be used.
            C (float): Body chord length.
            i_t (int): Current time-step number.       
        """        
        # Superposing the structural displacements
        if (outerCorr > 1):
            Solid.nodes[:,0] += (self.nodeDispl[:,0] - self.nodeDisplOld[:,0])
            Solid.nodes[:,1] += (self.nodeDispl[:,1] - self.nodeDisplOld[:,1])         
            
        if (outerCorr <= 1):
            # Updating the new kinematics
            Solid.nodes[:,0] = (Solid.nodesNew[:,0] - Solid.nodesNew[0,0])*np.cos(THETA)
            Solid.nodes[:,1] = HEAVE + (Solid.nodesNew[:,0] - Solid.nodesNew[0,0])*np.sin(THETA)
            
            # Calculating the shift in node positions with the swimming velocity
            nodeDelxp = Body.AF.x_le * np.ones((Solid.Nelements + 1,1))
#            nodeDelzp = Body.AF.z_le * np.ones((Solid.Nelements + 1,1))
            
            #Superposiing the kinematics and swimming translations
            Solid.nodes[:,0] = Solid.nodes[:,0] + nodeDelxp.T
#            Solid.nodes[:,1] = Solid.nodes[:,1] + nodeDelzp.T          
            
        # Determine the load conditons from the fluid solver
        # Calculate the panel lengths and normal vectors
        (nx,nz,lp) = panel_vectors(Body.AF.x,Body.AF.z)[2:5]
        
        # Calculate the force magnitude acting on the panel due to pressure,
        # then calculate the x-z components of this force
        magPF = Body.p * lp * 1.
        pF = np.zeros((Body.N,2))
        if (SW_VISC_DRAG == 1):
            pF[:,0] = (magPF.T * nx.T * -1.) + delFs[:,0]
            pF[:,1] = (magPF.T * nz.T * -1.) + delFs[:,1]
        else:
            pF[:,0] = magPF.T * nx.T * -1.
            pF[:,1] = magPF.T * nz.T * -1.
        
        # Determine the moment arm between top and bottom panel points, and
        # collapse force and moments to the camber line
        colM = np.zeros((0.5*Body.N,1))
        colPF = np.zeros((0.5*Body.N,2))
        meanPt = np.zeros((0.5*Body.N,2))
        for i in xrange(int(0.5*Body.N)):
            meanPt[i,0] = 0.5*(Body.AF.x_mid[0,i] + Body.AF.x_mid[0,-(i+1)])
            meanPt[i,1] = 0.5*(Body.AF.z_mid[0,i] + Body.AF.z_mid[0,-(i+1)])
            colPF[i,:] = pF[i,:] + pF[-(i+1),:]
            colM[i,:] = -1. * pF[i,0] * (Body.AF.z_mid[0,i] - meanPt[i,1]) + \
                   pF[i,1] * (Body.AF.x_mid[0,i] - meanPt[i,0]) + \
                   -1. * pF[-(i+1),0] * (Body.AF.z_mid[0,-(i+1)] - meanPt[i,1]) + \
                   pF[-(i+1),1] * (Body.AF.x_mid[0,-(i+1)] - meanPt[i,0])
                   
        colPF = np.flipud(colPF)
        colM = np.flipud(colM)
        
        # Interpolate the collapsed forces and moments onto the structural mesh
        nodalInput = np.zeros((Solid.Nnodes,6))
        if (SW_INTERP_MTD == True):
            f1 = extrap1d(interp1d(Solid.meanline_c0[0.5*Body.N:], colPF[:,0]))
            f2 = extrap1d(interp1d( Solid.meanline_c0[0.5*Body.N:], colPF[:,1]))
            f3 = extrap1d(interp1d(Solid.meanline_c0[0.5*Body.N:], colM[:,0]))
            nodalInput[:,0] = f1(Solid.nodes[:,2])
            nodalInput[:,1] = f2(Solid.nodes[:,2])
            nodalInput[:,5] = f3(Solid.nodes[:,2])
#            nodalInput[:,0] = np.interp(Solid.nodes[:,2], Solid.meanline_c0[0.5*Body.N:], colPF[:,0], left=0, right=0)
#            nodalInput[:,1] = np.interp(Solid.nodes[:,2], Solid.meanline_c0[0.5*Body.N:], colPF[:,1], left=0, right=0)
#            nodalInput[:,5] = np.interp(Solid.nodes[:,2], Solid.meanline_c0[0.5*Body.N:], colM[:,0], left=0, right=0)
        else:
            nodalInput[:,0] = spline(Solid.meanline_c0[0.5*Body.N:], colPF[:,0], Solid.nodes[:,2])
            nodalInput[:,1] = spline(Solid.meanline_c0[0.5*Body.N:], colPF[:,1], Solid.nodes[:,2])
            nodalInput[:,5] = spline(Solid.meanline_c0[0.5*Body.N:], colM[:,0], Solid.nodes[:,2])
            
        # Rotate force components into the relative cooridnate system
        (nodalInput[:,0], nodalInput[:,1]) = self.rotatePts(nodalInput[:,0], nodalInput[:,1], -THETA)
        
        # Create the load matrix
        Fload = np.zeros((3*(Solid.Nnodes),1))
        Fload[0::3,0] = np.copy(nodalInput[:,0])
        Fload[1::3,0] = np.copy(nodalInput[:,1])
        Fload[2::3,0] = np.copy(nodalInput[:,5])
        
        # Create element area matrix
        A = np.copy(Solid.tBeamStruct[:,0])
        
        # Create area moment of inertia matrix
        I = 1. * Solid.tBeamStruct[:,0]**3 / 12
        
        # Initial element length
        l_0 = C / Solid.Nelements
        
        # Initial displacements and velocities
#        if (i_t <= 1 and outerCorr <= 1):
        temp = 3 * Solid.fixedCounter
        if (i_t <= 1 and outerCorr <= 1):
            PyFEA.U_n = np.zeros((3*Solid.Nnodes,1))
            PyFEA.Udot_n = np.zeros((3*Solid.Nnodes,1))
            PyFEA.UdotDot_n = np.zeros((3*Solid.Nnodes - temp,1))
            PyFEA.U_nPlus = np.zeros((3*Solid.Nnodes - temp,1))
            PyFEA.Udot_nPlus = np.zeros((3*Solid.Nnodes - temp,1))
            PyFEA.UdotDot_nPlus = np.zeros((3*Solid.Nnodes - temp,1))
        elif (i_t > 0 and outerCorr <= 1):
            PyFEA.U_n = np.zeros((3*Solid.Nnodes,1))
            PyFEA.Udot_n = np.zeros((3*Solid.Nnodes,1))
            PyFEA.UdotDot_n = np.zeros((3*Solid.Nnodes - temp,1))
            PyFEA.U_n[temp:,0] = PyFEA.U_nPlus.T
            PyFEA.Udot_n[temp:,0] = PyFEA.Udot_nPlus.T
            PyFEA.UdotDot_n = PyFEA.Udot_nPlus
        
        PyFEA.Fload = np.copy(Fload)
        PyFEA.A = np.copy(A)
        PyFEA.I = np.copy(I)
        PyFEA.l = l_0 * np.ones(Solid.Nelements)
Beispiel #18
0
    def setInterfaceForce(self, Solid, Body, PyFEA, t, TSTEP, outerCorr, 
                          SWITCH_VISC_DRAG, delFs, SWITCH_INTERP_MTD, C, i_t):
        """
        Updates the structural mesh position, calculates the traction forces on
        the free nodes, and determines the initial condisitons for the timestep.
        Returns the node positions, traction forces, and initial conditions for
        the structural solver.        
        
        Keyword arguments:
        """
        # Determine current pitching angle and heave position
        # TODO: Add heaving functionality to kinematics
        theta = Body.MP.THETA_MAX * np.sin(2 * np.pi * Body.MP.F * (t + TSTEP) + Body.MP.PHI)  
        heave = 0
        
        # Superposing the structural displacements
        if (outerCorr > 1):
            Solid.nodes[:,0] += (self.nodeDispl[:,0] - self.nodeDisplOld[:,0])
            Solid.nodes[:,1] += (self.nodeDispl[:,1] - self.nodeDisplOld[:,1])         
            
        if (outerCorr <= 1):
            # Updating the new kinematics
            Solid.nodes[:,0] = (Solid.nodesNew[:,0] - Solid.nodesNew[0,0])*np.cos(theta)
            Solid.nodes[:,1] = heave + (Solid.nodesNew[:,0] - Solid.nodesNew[0,0])*np.sin(theta)
            
            # Calculating the shift in node positions with the swimming velocity
            nodeDelxp = Body.AF.x_le * np.ones((Solid.Nelements + 1,1))
            nodeDelzp = Body.AF.z_le * np.ones((Solid.Nelements + 1,1))
            
            #Superposiing the kinematics and swimming translations
            Solid.nodes[:,0] = Solid.nodes[:,0] + nodeDelxp.T
            Solid.nodes[:,1] = Solid.nodes[:,1] + nodeDelzp.T          
            
        # Determine the load conditons from the fluid solver
        # Calculate the panel lengths and normal vectors
        (nx,nz,lp) = panel_vectors(Body.AF.x,Body.AF.z)[2:5]
        
        # Calculate the force magnitude acting on the panel due to pressure,
        # then calculate the x-z components of this force
        magPF = Body.p * lp * 1.
        pF = np.zeros((Body.N,2))
        if (SWITCH_VISC_DRAG == 1):
            pF[:,0] = (magPF.T * nx.T * -1.) + delFs[:,0]
            pF[:,1] = (magPF.T * nz.T * -1.) + delFs[:,1]
        else:
            pF[:,0] = magPF.T * nx.T * -1.
            pF[:,1] = magPF.T * nz.T * -1.
        
        # Determine the moment arm between top and bottom panel points, and
        # collapse force and moments to the camber line
        colM = np.zeros((0.5*Body.N,1))
        colPF = np.zeros((0.5*Body.N,2))
        meanPt = np.zeros((0.5*Body.N,2))
        for i in xrange(int(0.5*Body.N)):
            meanPt[i,0] = 0.5*(Body.AF.x_mid[0,i] + Body.AF.x_mid[0,-(i+1)])
            meanPt[i,1] = 0.5*(Body.AF.z_mid[0,i] + Body.AF.z_mid[0,-(i+1)])
            colPF[i,:] = pF[i,:] + pF[-(i+1),:]
            colM[i,:] = -1. * pF[i,0] * (Body.AF.z_mid[0,i] - meanPt[i,1]) + \
                   pF[i,1] * (Body.AF.x_mid[0,i] - meanPt[i,0]) + \
                   -1. * pF[-(i+1),0] * (Body.AF.z_mid[0,-(i+1)] - meanPt[i,1]) + \
                   pF[-(i+1),1] * (Body.AF.x_mid[0,-(i+1)] - meanPt[i,0])
                   
        colPF = np.flipud(colPF)
        colM = np.flipud(colM)
        relXp = Body.AF.x - np.min(Body.AF.x)
        relXc = Body.AF.x_mid - np.min(Body.AF.x)
        
        # Interpolate the collapsed forces and moments onto the structural mesh
        nodalInput = np.zeros((Solid.Nnodes,6))
        if (SWITCH_INTERP_MTD == 1):
            nodalInput[:,0] = np.interp(Solid.nodes[:,2], Solid.meanline_c0[0.5*Body.N:], colPF[:,0], left=0, right=0)
            nodalInput[:,1] = np.interp(Solid.nodes[:,2], Solid.meanline_c0[0.5*Body.N:], colPF[:,1], left=0, right=0)
            nodalInput[:,5] = np.interp(Solid.nodes[:,2], Solid.meanline_c0[0.5*Body.N:], colM[:,0], left=0, right=0)
        else:
            nodalInput[:,0] = spline(Solid.meanline_c0[0.5*Body.N:], colPF[:,0], Solid.nodes[:,2])
            nodalInput[:,1] = spline(Solid.meanline_c0[0.5*Body.N:], colPF[:,1], Solid.nodes[:,2])
            nodalInput[:,5] = spline(Solid.meanline_c0[0.5*Body.N:], colM[:,0], Solid.nodes[:,2])

        # Rotate force components into the relative cooridnate system
        (nodalInput[:,0], nodalInput[:,1]) = self.rotatePts(nodalInput[:,0], nodalInput[:,1], -theta)
        
        # Create the load matrix
        Fload = np.zeros((3*(Solid.Nnodes),1))
        Fload[0::3,0] = np.copy(nodalInput[:,0])
        Fload[1::3,0] = np.copy(nodalInput[:,1])
        Fload[2::3,0] = np.copy(nodalInput[:,5])
        
        # Create element area matrix
        A = np.copy(Solid.tBeamStruct[:,0])
        
        # Create area moment of inertia matrix
        I = 1. * Solid.tBeamStruct[:,0]**3 / 12
        
        # Set fixed nodes
        fixedNodes = np.copy(Solid.fixedCounter)
        
        # Initial element length
        l_0 = C / Solid.Nelements
        
        # Initial displacements and velocities
#        if (i_t <= 1 and outerCorr <= 1):
        if (i_t <= 1):
            PyFEA.U_n = np.zeros((3*(Solid.Nnodes),1))
            PyFEA.Udot_n = np.zeros((3*(Solid.Nnodes),1))
            PyFEA.UdotDot_n = np.zeros((3*(Solid.Nelements+1),1))
            PyFEA.U_nPlus = np.zeros((3*(Solid.Nelements+1),1))
            PyFEA.Udot_nPlus = np.zeros((3*(Solid.Nelements+1),1))
            PyFEA.UdotDot_nPlus = np.zeros((3*(Solid.Nelements+1),1))
        if (i_t > 1 and outerCorr == 1):
            PyFEA.initU = np.copy(PyFEA.U_nPlus)
            PyFEA.initUdot = np.copy(PyFEA.Udot_nPlus)
        if (i_t > 1):
            PyFEA.U_n.resize((3*(Solid.Nnodes),1))
            PyFEA.Udot_n.resize((3*(Solid.Nnodes),1))
#            PyFEA.U_n = np.zeros()
#            PyFEA.Udot_n = np.zeros((3*(Solid.Nnodes),1))
            PyFEA.U_n[3*fixedNodes:,0] = PyFEA.initU.T
            PyFEA.Udot_n[3*fixedNodes:,0] = PyFEA.initUdot.T
        
        # Resize matricies to acount for all nodes after first subiteration
        PyFEA.Fload.resize((3*Solid.Nnodes,1))
        
        PyFEA.Fload = np.copy(Fload)
        PyFEA.A = np.copy(A)
        PyFEA.I = np.copy(I)
        PyFEA.l = l_0 * np.ones(Solid.Nelements)
            
        return relXp, relXc
def body_plot(Swimmers, SW_PLOT_FIG):
    global n_fig

    if SW_PLOT_FIG:
        figure = plt.figure(1)
        ax = figure.gca(projection='3d')
        #        ax.set_aspect('equal') This feature has not been implemented in 3D plotting yet
        figure.set_size_inches(16, 9)
        plt.tick_params(labelsize=28)

        for Swim in Swimmers:
            (nx, ny, nz, txs, tys, tzs, txc, tyc, tzc, lps,
             lpc) = panel_vectors(Swim.Body.AF.x, Swim.Body.AF.y,
                                  Swim.Body.AF.z)
            x = Swim.Body.AF.x_mid[::5, ::5, 0] + 0.1 * nx[::5, ::5]
            y = Swim.Body.AF.y_mid[::5, ::5, 0] + 0.1 * ny[::5, ::5]
            z = Swim.Body.AF.z_mid[::5, ::5, 0] + 0.1 * nz[::5, ::5]
            nx = nx[::5, ::5]
            ny = ny[::5, ::5]
            nz = nz[::5, ::5]
            ax.quiver(x, y, z, nx, ny, nz, length=0.1, color='r')
            ax.quiver(Swim.Body.AF.x_mid[::5, ::5, 0],
                      Swim.Body.AF.y_mid[::5, ::5, 0],
                      Swim.Body.AF.z_mid[::5, ::5, 0],
                      txs[::5, ::5],
                      tys[::5, ::5],
                      tzs[::5, ::5],
                      length=0.1,
                      color='g')
            ax.quiver(Swim.Body.AF.x_mid[::5, ::5, 0],
                      Swim.Body.AF.y_mid[::5, ::5, 0],
                      Swim.Body.AF.z_mid[::5, ::5, 0],
                      txc[::5, ::5],
                      tyc[::5, ::5],
                      tzc[::5, ::5],
                      length=0.1,
                      color='b')
            ax.plot_surface(Swim.Body.AF.x,
                            Swim.Body.AF.y,
                            Swim.Body.AF.z,
                            rstride=1,
                            cstride=1,
                            linewidth=0,
                            color='k',
                            antialiased=True)

        # Determine if the output directory exists. If not, create the directory.
        if not os.path.exists('./movies'):
            os.makedirs('./movies')

        ax.set_xlim(
            np.min(Swim.Body.AF.x) - 1.25,
            np.min(Swim.Body.AF.x) + 1.25)
        ax.set_ylim(-1.25, 1.25)
        ax.set_zlim(-1.25, 1.25)
        ax.view_init(elev=18, azim=-124)

        ax.set_xlabel('$X$ $[m]$', fontsize=28)
        ax.set_ylabel('$Y$ $[m]$', fontsize=28)
        ax.set_zlabel('$Z$ $[m]$', fontsize=28)
        ax.xaxis._axinfo['label']['space_factor'] = 2.0
        ax.yaxis._axinfo['label']['space_factor'] = 2.0
        ax.zaxis._axinfo['label']['space_factor'] = 2.0

        figure.savefig('./movies/%05i.png' % (n_fig), format='png')

        plt.clf()

    n_fig += 1
Beispiel #20
0
    def surface_kinematics(self, DSTEP1, DSTEP2, DSTEP3, TSTEP, THETA_MINUS,
                           THETA_PLUS, HEAVE_MINUS, HEAVE_PLUS, DEL_T, T, i):
        """Calculates the body-frame surface velocities of body panels.

        Also finds the body panel source strengths based on these surface
        velocities.

        Args:
            DSTEP, TSTEP: Incremental distance/time passed into neutral_axis().
            DEL_T: Time step length.
            T: Time of current step.
            i: Time step number.
            THETA_MINUS: Pitching angle minus a small time difference (TSTEP)
            THETA_PLUS: Pitching angle plus a small time difference (TSTEP)
        """
        Nc = self.BF.x_mid.shape[0]
        Ns = self.BF.x_mid.shape[1]

        if i == 0:
            x_col = self.BF.x_mid
            y_col = self.BF.y_mid
            z_col = self.BF.z_mid

            # Panel midpoint velocity calculations
            # Calculating the surface positions at tplus(tp) and tminus(tm)
            (xtpneut, ytpneut,
             ztpneut) = self.neutral_plane(x_col, y_col, T, THETA_PLUS,
                                           HEAVE_PLUS, 0, 0, 0)

            (xtpdp_y, ytpdp_y,
             ztpdp_y) = self.neutral_plane(x_col, y_col, T, THETA_PLUS,
                                           HEAVE_PLUS, 0, DSTEP2, DSTEP3)
            (xtpdp_x, ytpdp_x,
             ztpdp_x) = self.neutral_plane(x_col, y_col, T, THETA_PLUS,
                                           HEAVE_PLUS, DSTEP1, 0, 0)

            (xtpdm_y, ytpdm_y,
             ztpdm_y) = self.neutral_plane(x_col, y_col, T, THETA_PLUS,
                                           HEAVE_PLUS, 0, -DSTEP2, -DSTEP3)
            (xtpdm_x, ytpdm_x,
             ztpdm_x) = self.neutral_plane(x_col, y_col, T, THETA_PLUS,
                                           HEAVE_PLUS, -DSTEP1, 0, 0)

            (xtmneut, ytmneut,
             ztmneut) = self.neutral_plane(x_col, y_col, T, THETA_MINUS,
                                           HEAVE_MINUS, 0, 0, 0)

            (xtmdp_y, ytmdp_y,
             ztmdp_y) = self.neutral_plane(x_col, y_col, T, THETA_MINUS,
                                           HEAVE_MINUS, 0, DSTEP2, DSTEP3)
            (xtmdp_x, ytmdp_x,
             ztmdp_x) = self.neutral_plane(x_col, y_col, T, THETA_MINUS,
                                           HEAVE_MINUS, DSTEP1, 0, 0)

            (xtmdm_y, ytmdm_y,
             ztmdm_y) = self.neutral_plane(x_col, y_col, T, THETA_MINUS,
                                           HEAVE_MINUS, 0, -DSTEP2, -DSTEP3)
            (xtmdm_x, ytmdm_x,
             ztmdm_x) = self.neutral_plane(x_col, y_col, T, THETA_MINUS,
                                           HEAVE_MINUS, -DSTEP1, 0, 0)

            # Displaced airfoil's panel midpoints for times tplus(tp) and tminus(tm)
            xctp = xtpneut + point_vectors(
                Nc, Ns, (xtpdp_y, ytpdp_y, ztpdp_y),
                (xtpdm_y, ytpdm_y, ztpdm_y), (xtpdp_x, ytpdp_x, ztpdp_x),
                (xtpdm_x, ytpdm_x, ztpdm_x))[0] * z_col
            xctm = xtmneut + point_vectors(
                Nc, Ns, (xtmdp_y, ytmdp_y, ztmdp_y),
                (xtmdm_y, ytmdm_y, ztmdm_y), (xtmdp_x, ytmdp_x, ztmdp_x),
                (xtmdm_x, ytmdm_x, ztmdm_x))[0] * z_col

            yctp = ytpneut + point_vectors(
                Nc, Ns, (xtpdp_y, ytpdp_y, ztpdp_y),
                (xtpdm_y, ytpdm_y, ztpdm_y), (xtpdp_x, ytpdp_x, ztpdp_x),
                (xtpdm_x, ytpdm_x, ztpdm_x))[1] * z_col
            yctm = ytmneut + point_vectors(
                Nc, Ns, (xtmdp_y, ytmdp_y, ztmdp_y),
                (xtmdm_y, ytmdm_y, ztmdm_y), (xtmdp_x, ytmdp_x, ztmdp_x),
                (xtmdm_x, ytmdm_x, ztmdm_x))[1] * z_col

            zctp = ztpneut + point_vectors(
                Nc, Ns, (xtpdp_y, ytpdp_y, ztpdp_y),
                (xtpdm_y, ytpdm_y, ztpdm_y), (xtpdp_x, ytpdp_x, ztpdp_x),
                (xtpdm_x, ytpdm_x, ztpdm_x))[2] * z_col
            zctm = ztmneut + point_vectors(
                Nc, Ns, (xtmdp_y, ytmdp_y, ztmdp_y),
                (xtmdm_y, ytmdm_y, ztmdm_y), (xtmdp_x, ytmdp_x, ztmdp_x),
                (xtmdm_x, ytmdm_x, ztmdm_x))[2] * z_col

            # Velocity calculations on the surface panel midpoints
            self.vx = (xctp - xctm) / (2 * TSTEP)
            self.vy = (yctp - yctm) / (2 * TSTEP)
            self.vz = (zctp - zctm) / (2 * TSTEP)

        elif i == 1:
            # First-order backwards differencing of body collocation point positions
            self.vx = (self.AF.x_mid[:, :, 0] -
                       self.AF.x_mid[:, :, 1]) / DEL_T - self.V0
            self.vy = (self.AF.y_mid[:, :, 0] - self.AF.y_mid[:, :, 1]) / DEL_T
            self.vz = (self.AF.z_mid[:, :, 0] - self.AF.z_mid[:, :, 1]) / DEL_T

        else:
            # Second-order backwards differencing of body collocation point positions
            self.vx = (3 * self.AF.x_mid[:, :, 0] - 4 * self.AF.x_mid[:, :, 1]
                       + self.AF.x_mid[:, :, 2]) / (2 * DEL_T) - self.V0
            self.vy = (3 * self.AF.y_mid[:, :, 0] - 4 * self.AF.y_mid[:, :, 1]
                       + self.AF.y_mid[:, :, 2]) / (2 * DEL_T)
            self.vz = (3 * self.AF.z_mid[:, :, 0] - 4 * self.AF.z_mid[:, :, 1]
                       + self.AF.z_mid[:, :, 2]) / (2 * DEL_T)

#        # Body source strengths with normal vector pointing outward (overall sigma pointing outward)
        (nx, ny, nz) = panel_vectors(self.AF.x, self.AF.y, self.AF.z)[0:3]
        self.sigma = nx * (self.V0 + self.vx) + ny * self.vy + nz * self.vz
Beispiel #21
0
    def panel_positions(self, DSTEP1, DSTEP2, DSTEP3, T, THETA, HEAVE):
        """Updates all the absolute-frame coordinates of the body.

        Args:
            DSTEP: Small incremental distance to pass into neutral_plane().
            T: Time of current step.
            THETA: Current pitching angle.

        """
        #        Nc = int(0.5*(self.BF.x.shape[0]-1))
        Nc = self.BF.x.shape[0]
        Ns = self.BF.x.shape[1]
        bfx = self.BF.x
        bfy = self.BF.y  #No y information coming from the geometry class yet
        bfz = self.BF.z
        bfz_col = self.BF.z_mid
        V0 = self.V0  # Used only for x_le

        (x_neut, y_neut, z_neut) = self.neutral_plane(bfx, bfy, T, THETA,
                                                      HEAVE)

        # Infinitesimal differences on the neutral axis to calculate the tangential and normal vectors
        v1 = (xdp_y, ydp_y,
              zdp_y) = self.neutral_plane(bfx, bfy, T, THETA, HEAVE, 0, DSTEP2,
                                          DSTEP3)
        v2 = (xdm_y, ydm_y,
              zdm_y) = self.neutral_plane(bfx, bfy, T, THETA, HEAVE, 0,
                                          -DSTEP2, -DSTEP3)

        v3 = (xdp_x, ydp_x,
              zdp_x) = self.neutral_plane(bfx, bfy, T, THETA, HEAVE, DSTEP1, 0,
                                          0)
        v4 = (xdm_x, ydm_x,
              zdm_x) = self.neutral_plane(bfx, bfy, T, THETA, HEAVE, -DSTEP1,
                                          0, 0)

        # Absolute-frame panel endpoint positions for time t
        afx = x_neut + point_vectors(Nc, Ns, v1, v2, v3, v4)[0] * bfz
        afy = y_neut + point_vectors(Nc, Ns, v1, v2, v3, v4)[1] * bfz
        afz = z_neut + point_vectors(Nc, Ns, v1, v2, v3, v4)[2] * bfz

        # Absolute-frame panel midpoint positions
        x_mid = (afx[1:, :-1] + afx[:-1, :-1]) / 2
        y_mid = (afy[1:, :-1] + afy[:-1, :-1]) / 2
        z_mid = (afz[1:, :-1] + afz[:-1, :-1]) / 2

        # Collocation points are the points where impermeable boundary condition is forced
        # They should be shifted inside or outside of the boundary depending on the dirichlet or neumann condition
        # Shifting surface collocation points some percent of the height from the neutral axis
        # Normal vectors point outward but positive S is inward, so the shift must be subtracted from the panel midpoints
        afx_col = x_mid - self.S * panel_vectors(bfx, bfy,
                                                 bfz)[0] * np.absolute(bfz_col)
        afy_col = y_mid - self.S * panel_vectors(bfy, bfy,
                                                 bfz)[1] * np.absolute(bfz_col)
        afz_col = z_mid - self.S * panel_vectors(bfz, bfy,
                                                 bfz)[2] * np.absolute(bfz_col)

        self.AF.x = afx
        self.AF.y = afy
        self.AF.z = afz
        self.AF.x_col = afx_col
        self.AF.y_col = afy_col
        self.AF.z_col = afz_col
        self.AF.x_mid[:, :, 0] = x_mid
        self.AF.y_mid[:, :, 0] = y_mid
        self.AF.z_mid[:, :, 0] = z_mid
        self.AF.x_neut = x_neut
        self.AF.y_neut = y_neut
        self.AF.z_neut = z_neut
        # Location of leading edge (currently pitching motion only)
        self.AF.x_le = V0 * T
        self.AF.y_le = 0
        self.AF.z_le = HEAVE
Beispiel #22
0
def wake_rollup(Swimmers, DEL_T, i, P):
    """Performs wake rollup on the swimmers' wake panels.

    Args:
        Swimmers: List of Swimmer objects being simulated.
        DEL_T: Time step length.
        i: Time step number.
    """
    if (P['SW_ROLLUP']):
        # Wake panels initialize when i==1
        if i == 0:
            pass

        else:
            NT = i  # Number of targets (wake panel points that are rolling up)
            for SwimT in Swimmers:
                SwimT.Wake.vx = np.zeros(NT)
                SwimT.Wake.vz = np.zeros(NT)

                wake_x_midT = 0.5 * (SwimT.Wake.x[1:i + 1] + SwimT.Wake.x[:i])
                wake_z_midT = 0.5 * (SwimT.Wake.z[1:i + 1] + SwimT.Wake.z[:i])

                target = np.vstack((wake_x_midT, wake_z_midT))

                for SwimI in Swimmers:
                    wake_x_midI = 0.5 * (SwimI.Wake.x[1:i + 1] +
                                         SwimI.Wake.x[:i])
                    wake_z_midI = 0.5 * (SwimI.Wake.z[1:i + 1] +
                                         SwimI.Wake.z[:i])
                    edge_x_mid = 0.5 * (SwimI.Edge.x[1] + SwimI.Edge.x[0])
                    edge_z_mid = 0.5 * (SwimI.Edge.z[1] + SwimI.Edge.z[0])

                    ed_places = np.vstack((edge_x_mid, edge_z_mid))
                    bd_places = np.vstack(
                        (SwimT.Body.AF.x_col, SwimT.Body.AF.z_col))
                    bs_places = np.vstack(
                        (SwimT.Body.AF.x_mid[0, :], SwimT.Body.AF.z_mid[0, :]))
                    wd_places = np.vstack((wake_x_midI, wake_z_midI))

                    (nx_b, nz_b,
                     lbpanel) = panel_vectors(SwimI.Body.AF.x,
                                              SwimI.Body.AF.z)[2:]
                    (nx_e, nz_e,
                     lepanel) = panel_vectors(SwimI.Edge.x, SwimI.Edge.z)[2:]
                    (nx_w, nz_w,
                     lwpanel) = panel_vectors(SwimI.Wake.x[:i + 1],
                                              SwimI.Wake.z[:i + 1])[2:]

                    n_b = np.vstack((nx_b, nz_b))
                    n_e = np.vstack((nx_e, nz_e))
                    n_w = np.vstack((nx_w, nz_w))

                    # Body source influence on wake velocity
                    u_bs = np.real(
                        fmm_part(
                            "G",
                            iprec=5,
                            kernel=0,
                            sources=bs_places.T,
                            target=target.T,
                            mop_charge=SwimI.Body.sigma * lbpanel)) / np.pi
                    SwimT.Wake.vx += 2. * u_bs[:, 0]
                    SwimT.Wake.vz += -2. * u_bs[:, 1]

                    # Body doublet influence on wake velocity
                    u_bd = np.real(
                        fmm_part("G",
                                 iprec=5,
                                 kernel=0,
                                 sources=bd_places.T,
                                 target=target.T,
                                 dipvec=n_b.T,
                                 dip_charge=SwimI.Body.mu * lbpanel)) / np.pi
                    SwimT.Wake.vx += 2. * u_bd[:, 0]
                    SwimT.Wake.vz += -2. * u_bd[:, 1]

                    # TE panel influence on wake velocity
                    u_te = np.real(
                        fmm_part("G",
                                 iprec=5,
                                 kernel=0,
                                 sources=ed_places.T,
                                 target=target.T,
                                 dipvec=n_e.T,
                                 dip_charge=SwimI.Edge.mu * lepanel)) / np.pi
                    SwimT.Wake.vx += 2. * u_te[:, 0]
                    SwimT.Wake.vz += -2. * u_te[:, 1]

                    # Wake double influence on wake velocity
                    u_w = np.real(
                        fmm_part("G",
                                 iprec=5,
                                 kernel=0,
                                 sources=wd_places.T,
                                 target=target.T,
                                 dipvec=n_w.T,
                                 dip_charge=SwimI.Wake.mu[1:i + 1] *
                                 lwpanel)) / np.pi
                    u_w = np.nan_to_num(u_w)
                    SwimT.Wake.vx += 2. * u_w[:, 0]
                    SwimT.Wake.vz += -2. * u_w[:, 1]

            for Swim in Swimmers:
                # Modify wake with the total induced velocity
                Swim.Wake.x[1:i + 1] += Swim.Wake.vx * DEL_T
                Swim.Wake.z[1:i + 1] += Swim.Wake.vz * DEL_T
Beispiel #23
0
def solve_phi(Swimmers, P, i, outerCorr=0):
    """Solves the boundary integral equation using a Kutta condition and the
    Fast Multipole Method.

    Args:
        Swimmers: List of Swimmer objects being simulated.
        RHO: Fluid density.
        DEL_T: Time step length.
        i: Time step number.
    """
    for Swim in Swimmers:
        if (outerCorr <= 1):
            # mu_past used in differencing for pressure
            Swim.Body.mu_past[1:4, :] = Swim.Body.mu_past[0:3, :]
            Swim.Body.mu_past[0, :] = Swim.Body.mu

    (sigma_all, mu_w_all, a_b, a_e, b_e) = influence_matrices(Swimmers, i)

    for SwimI in Swimmers:
        a_e[:, SwimI.i_b] = -b_e[:, SwimI.i_e]
        a_e[:, SwimI.i_b + SwimI.Body.N - 1] = b_e[:, SwimI.i_e]
    a = a_b + a_e

    # Prepare FMM inputs
    b_places = np.vstack(
        (Swimmers[0].Body.AF.x_mid[0, :], Swimmers[0].Body.AF.z_mid[0, :]))
    target = np.vstack((Swimmers[0].Body.AF.x_col, Swimmers[0].Body.AF.z_col))
    lpanel = panel_vectors(Swimmers[0].Body.AF.x, Swimmers[0].Body.AF.z)[-1]
    if (i > 0):
        w_places = np.vstack(
            (0.5 * (Swimmers[0].Wake.x[1:i + 1] + Swimmers[0].Wake.x[:i]),
             0.5 * (Swimmers[0].Wake.z[1:i + 1] + Swimmers[0].Wake.z[:i])))
        (nx, nz, lwpanel) = panel_vectors(Swimmers[0].Wake.x[:i + 1],
                                          Swimmers[0].Wake.z[:i + 1])[2:]
        n_w = np.vstack((nx, nz))

    # Get right-hand side
    b_body = np.real(
        fmm_part("P",
                 iprec=5,
                 kernel=0,
                 sources=b_places.T,
                 target=target.T,
                 mop_charge=sigma_all * lpanel)) / 2. / np.pi
    if i == 0:
        b = -b_body
    else:
        b_wake = np.real(
            fmm_part("P",
                     iprec=5,
                     kernel=0,
                     sources=w_places.T,
                     target=target.T,
                     dipvec=n_w.T,
                     dip_charge=mu_w_all * lwpanel)) / 2. / np.pi
        b = -b_body - b_wake

    # Solve for bodies' doublet strengths using explicit Kutta
    mu_b_all = np.linalg.solve(a, b)

    for Swim in Swimmers:
        Swim.Body.pressure(P, i)

        Swim.mu_guess = np.empty(2)  # [0] is current guess, [1] is previous
        Swim.delta_p = np.empty(2)  # [0] is current delta_p, [1] is previous
        Swim.Body.mu[:] = mu_b_all[Swim.i_b:Swim.i_b + Swim.Body.N]
        Swim.mu_guess[0] = Swim.Body.mu[-1] - Swim.Body.mu[0]

        Swim.Edge.mu = Swim.mu_guess[0]
        Swim.Edge.gamma[0] = -Swim.Edge.mu
        Swim.Edge.gamma[1] = Swim.Edge.mu

        # Get gamma of body panels for use in wake rollup
        Swim.Body.gamma[0] = -Swim.Body.mu[0]
        Swim.Body.gamma[1:-1] = Swim.Body.mu[:-1] - Swim.Body.mu[1:]
        Swim.Body.gamma[-1] = Swim.Body.mu[-1]
Beispiel #24
0
    def setSpringForce(self, Body, Solid, PyFEA, P, outerCorr, delFs, i_t):
        # Superposing the structural displacements
        if (outerCorr > 1):
            Solid.nodes[:,0] += (self.nodeDispl[:,0] - self.nodeDisplOld[:,0])
            Solid.nodes[:,1] += (self.nodeDispl[:,1] - self.nodeDisplOld[:,1])         
            
        if (outerCorr <= 1):
            # Updating the new kinematics
            Solid.nodes[:,0] = (Solid.nodesNew[:,0] - Solid.nodesNew[0,0])*np.cos(P['THETA'][i_t])
            Solid.nodes[:,1] = P['HEAVE'][i_t] + (Solid.nodesNew[:,0] - Solid.nodesNew[0,0])*np.sin(P['THETA'][i_t])
            
            # Calculating the shift in node positions with the swimming velocity
            nodeDelxp = Body.AF.x_le * np.ones((Solid.Nelements + 1,1))
#            nodeDelzp = Body.AF.z_le * np.ones((Solid.Nelements + 1,1))
            
            #Superposiing the kinematics and swimming translations
            Solid.nodes[:,0] = Solid.nodes[:,0] + nodeDelxp.T
#            Solid.nodes[:,1] = Solid.nodes[:,1] + nodeDelzp.T          
            
        # Determine the load conditons from the fluid solver
        # Calculate the panel lengths and normal vectors
        (nx,nz,lp) = panel_vectors(Body.AF.x,Body.AF.z)[2:5]
        
        # Calculate the force magnitude acting on the panel due to pressure,
        # then calculate the x-z components of this force
        magPF = Body.p * lp * 1.
        pF = np.zeros((Body.N,3))
        if P['SW_VISC_DRAG']:
            pF[:,0] = (magPF.T * nx.T * -1.) + delFs[:,0]
            pF[:,2] = (magPF.T * nz.T * -1.) + delFs[:,1]
        else:
            pF[:,0] = magPF.T * nx.T * -1.
            pF[:,2] = magPF.T * nz.T * -1.
        
        # Calculating the moment about the leading edge
        r = np.zeros((Body.N, 3))
        r[:,0] = Body.AF.x_mid[0,:].T - Body.AF.x_le
        r[:,2] = Body.AF.z_mid[0,:].T - Body.AF.z_le
        delM_le = np.cross(r, pF)
        Nf = -np.sum(delM_le[:,1])
        
        # Calculating the inertial torque resulting from the vertical 
        # acceleration of the leading edge
        Ni = -P['RHO_S'] * Solid.tmax * P['C']**2 * np.pi**2 * P['F']**2 * np.cos(PyFEA.theta_n) * P['INERTIA'][i_t]
        
        # Calculating the moment of intertia about the leading edge. An extra 
        # 0.5 is multiplied in to approximate the teardrop geometry's mass.
        I = 0.5 * PyFEA.RHO_S * Solid.tmax * P['C']**3 / 3.
        
        # Define spring and dampening constants
        kappa_1 = P['KAPPA_1']
        kappa_2 = P['KAPPA_2']
        zeta  = P['ZETA']
        
        if (i_t <= 1 and outerCorr <= 1):
            PyFEA.theta_n           = 0.
            PyFEA.thetaDot_n        = 0.
            PyFEA.thetaDotDot_n     = 0.
            PyFEA.theta_nPlus       = 0.
            PyFEA.thetaDot_nPlus    = 0.
            PyFEA.thetaDotDot_nPlus = 0.            
        elif (i_t > 0 and outerCorr <= 1):
            PyFEA.theta_n           = 0.
            PyFEA.thetaDot_n        = 0.
            PyFEA.thetaDotDot_n     = 0.
            PyFEA.theta_n           = np.copy(PyFEA.theta_nPlus)
            PyFEA.thetaDot_n        = np.copy(PyFEA.thetaDot_nPlus)
            PyFEA.thetaDotDot_n     = np.copy(PyFEA.thetaDotDot_nPlus)
        
        PyFEA.I     = np.copy(I)
        PyFEA.kappa_1 = np.copy(kappa_1)
        PyFEA.kappa_2 = np.copy(kappa_2)
        PyFEA.zeta  = np.copy(zeta)
        PyFEA.Nf    = np.copy(Nf)
        PyFEA.Ni    = np.copy(Ni)
    def surface_kinematics(self, DSTEP, TSTEP, THETA_MINUS, THETA_PLUS,
                           HEAVE_MINUS, HEAVE_PLUS, DEL_T, T, i):
        """Calculates the body-frame surface velocities of body panels.

        Also finds the body panel source strengths based on these surface
        velocities.

        Args:
            DSTEP, TSTEP: Incremental distance/time passed into neutral_axis().
            DEL_T: Time step length.
            T: Time of current step.
            i: Time step number.
            THETA_MINUS: Pitching angle minus a small time difference (TSTEP)
            THETA_PLUS: Pitching angle plus a small time difference (TSTEP)
        """
        if i == 0:

            x_col = self.BF.x_col
            z_col = self.BF.z_col

            # Panel midpoint velocity calculations
            # Calculating the surface positions at tplus(tp) and tminus(tm)
            (xtpneut, ztpneut) = self.neutral_axis(x_col, T, THETA_PLUS,
                                                   HEAVE_PLUS, 0)
            (xtpdp, ztpdp) = self.neutral_axis(x_col, T, THETA_PLUS,
                                               HEAVE_PLUS, DSTEP)
            (xtpdm, ztpdm) = self.neutral_axis(x_col, T, THETA_PLUS,
                                               HEAVE_PLUS, -DSTEP)
            (xtmneut, ztmneut) = self.neutral_axis(x_col, T, THETA_MINUS,
                                                   HEAVE_MINUS, 0)
            (xtmdp, ztmdp) = self.neutral_axis(x_col, T, THETA_MINUS,
                                               HEAVE_MINUS, DSTEP)
            (xtmdm, ztmdm) = self.neutral_axis(x_col, T, THETA_MINUS,
                                               HEAVE_MINUS, -DSTEP)

            # Displaced airfoil's panel midpoints for times tplus(tp) and tminus(tm)
            xctp = xtpneut + point_vectors(xtpdp, xtpdm, ztpdp,
                                           ztpdm)[2] * z_col
            xctm = xtmneut + point_vectors(xtmdp, xtmdm, ztmdp,
                                           ztmdm)[2] * z_col

            zctp = ztpneut + point_vectors(xtpdp, xtpdm, ztpdp,
                                           ztpdm)[3] * z_col
            zctm = ztmneut + point_vectors(xtmdp, xtmdm, ztmdp,
                                           ztmdm)[3] * z_col

            # Velocity calculations on the surface panel midpoints
            self.vx = (xctp - xctm) / (2 * TSTEP)
            self.vz = (zctp - zctm) / (2 * TSTEP)

        elif i == 1:
            # First-order backwards differencing of body collocation point positions
            self.vx = (self.AF.x_mid[0, :] -
                       self.AF.x_mid[1, :]) / DEL_T - self.V0
            self.vz = (self.AF.z_mid[0, :] - self.AF.z_mid[1, :]) / DEL_T

        else:
            # Second-order backwards differencing of body collocation point positions
            self.vx = (3 * self.AF.x_mid[0, :] - 4 * self.AF.x_mid[1, :] +
                       self.AF.x_mid[2, :]) / (2 * DEL_T) - self.V0
            self.vz = (3 * self.AF.z_mid[0, :] - 4 * self.AF.z_mid[1, :] +
                       self.AF.z_mid[2, :]) / (2 * DEL_T)

        # Body source strengths with normal vector pointing outward (overall sigma pointing outward)
        (nx, nz) = panel_vectors(self.AF.x, self.AF.z)[2:4]
        self.sigma = nx * (self.V0 + self.vx) + nz * self.vz
    def surface_kinematics(self, DSTEP1, DSTEP2, DSTEP3, TSTEP, THETA_MINUS, THETA_PLUS, HEAVE_MINUS, HEAVE_PLUS, DEL_T, T, i):
        """Calculates the body-frame surface velocities of body panels.

        Also finds the body panel source strengths based on these surface
        velocities.

        Args:
            DSTEP, TSTEP: Incremental distance/time passed into neutral_axis().
            DEL_T: Time step length.
            T: Time of current step.
            i: Time step number.
            THETA_MINUS: Pitching angle minus a small time difference (TSTEP)
            THETA_PLUS: Pitching angle plus a small time difference (TSTEP)
        """
        Nc = self.BF.x_mid.shape[0]
        Ns = self.BF.x_mid.shape[1]        
        
        if i == 0:
            x_col = self.BF.x_mid
            y_col = self.BF.y_mid
            z_col = self.BF.z_mid

            # Panel midpoint velocity calculations
            # Calculating the surface positions at tplus(tp) and tminus(tm)
            (xtpneut, ytpneut, ztpneut) = self.neutral_plane(x_col, y_col, T, THETA_PLUS, HEAVE_PLUS, 0, 0, 0)
            
            (xtpdp_y, ytpdp_y, ztpdp_y) = self.neutral_plane(x_col, y_col, T, THETA_PLUS, HEAVE_PLUS, 0, DSTEP2, DSTEP3)
            (xtpdp_x, ytpdp_x, ztpdp_x) = self.neutral_plane(x_col, y_col, T, THETA_PLUS, HEAVE_PLUS, DSTEP1, 0, 0)
            
            (xtpdm_y, ytpdm_y, ztpdm_y) = self.neutral_plane(x_col, y_col, T, THETA_PLUS, HEAVE_PLUS, 0, -DSTEP2, -DSTEP3)
            (xtpdm_x, ytpdm_x, ztpdm_x) = self.neutral_plane(x_col, y_col, T, THETA_PLUS, HEAVE_PLUS, -DSTEP1, 0, 0)
            
            (xtmneut, ytmneut, ztmneut) = self.neutral_plane(x_col, y_col, T, THETA_MINUS, HEAVE_MINUS, 0, 0, 0)
            
            (xtmdp_y, ytmdp_y, ztmdp_y) = self.neutral_plane(x_col, y_col, T, THETA_MINUS, HEAVE_MINUS, 0, DSTEP2, DSTEP3)
            (xtmdp_x, ytmdp_x, ztmdp_x) = self.neutral_plane(x_col, y_col, T, THETA_MINUS, HEAVE_MINUS, DSTEP1, 0, 0)
            
            (xtmdm_y, ytmdm_y, ztmdm_y) = self.neutral_plane(x_col, y_col, T, THETA_MINUS, HEAVE_MINUS, 0, -DSTEP2, -DSTEP3)
            (xtmdm_x, ytmdm_x, ztmdm_x) = self.neutral_plane(x_col, y_col, T, THETA_MINUS, HEAVE_MINUS, -DSTEP1, 0, 0)

            # Displaced airfoil's panel midpoints for times tplus(tp) and tminus(tm)
            xctp = xtpneut + point_vectors(Nc, Ns, (xtpdp_y, ytpdp_y, ztpdp_y), (xtpdm_y, ytpdm_y, ztpdm_y), (xtpdp_x, ytpdp_x, ztpdp_x), (xtpdm_x, ytpdm_x, ztpdm_x))[0]*z_col
            xctm = xtmneut + point_vectors(Nc, Ns, (xtmdp_y, ytmdp_y, ztmdp_y), (xtmdm_y, ytmdm_y, ztmdm_y), (xtmdp_x, ytmdp_x, ztmdp_x), (xtmdm_x, ytmdm_x, ztmdm_x))[0]*z_col

            yctp = ytpneut + point_vectors(Nc, Ns, (xtpdp_y, ytpdp_y, ztpdp_y), (xtpdm_y, ytpdm_y, ztpdm_y), (xtpdp_x, ytpdp_x, ztpdp_x), (xtpdm_x, ytpdm_x, ztpdm_x))[1]*z_col
            yctm = ytmneut + point_vectors(Nc, Ns, (xtmdp_y, ytmdp_y, ztmdp_y), (xtmdm_y, ytmdm_y, ztmdm_y), (xtmdp_x, ytmdp_x, ztmdp_x), (xtmdm_x, ytmdm_x, ztmdm_x))[1]*z_col
            
            zctp = ztpneut + point_vectors(Nc, Ns, (xtpdp_y, ytpdp_y, ztpdp_y), (xtpdm_y, ytpdm_y, ztpdm_y), (xtpdp_x, ytpdp_x, ztpdp_x), (xtpdm_x, ytpdm_x, ztpdm_x))[2]*z_col
            zctm = ztmneut + point_vectors(Nc, Ns, (xtmdp_y, ytmdp_y, ztmdp_y), (xtmdm_y, ytmdm_y, ztmdm_y), (xtmdp_x, ytmdp_x, ztmdp_x), (xtmdm_x, ytmdm_x, ztmdm_x))[2]*z_col

            # Velocity calculations on the surface panel midpoints
            self.vx = (xctp - xctm)/(2*TSTEP)
            self.vy = (yctp - yctm)/(2*TSTEP)
            self.vz = (zctp - zctm)/(2*TSTEP)

        elif i == 1:
            # First-order backwards differencing of body collocation point positions
            self.vx = (self.AF.x_mid[:,:,0]-self.AF.x_mid[:,:,1])/DEL_T - self.V0
            self.vy = (self.AF.y_mid[:,:,0]-self.AF.y_mid[:,:,1])/DEL_T
            self.vz = (self.AF.z_mid[:,:,0]-self.AF.z_mid[:,:,1])/DEL_T

        else:
            # Second-order backwards differencing of body collocation point positions
            self.vx = (3*self.AF.x_mid[:,:,0]-4*self.AF.x_mid[:,:,1]+self.AF.x_mid[:,:,2])/(2*DEL_T) - self.V0
            self.vy = (3*self.AF.y_mid[:,:,0]-4*self.AF.y_mid[:,:,1]+self.AF.y_mid[:,:,2])/(2*DEL_T)
            self.vz = (3*self.AF.z_mid[:,:,0]-4*self.AF.z_mid[:,:,1]+self.AF.z_mid[:,:,2])/(2*DEL_T)

#        # Body source strengths with normal vector pointing outward (overall sigma pointing outward)
        (nx, ny, nz) = panel_vectors(self.AF.x, self.AF.y, self.AF.z)[0:3]
        self.sigma = nx*(self.V0 + self.vx) + ny*self.vy + nz*self.vz
def wake_rollup(Swimmers, DEL_T, i):
    """Performs wake rollup on the swimmers' wake panels.

    Args:
        Swimmers: List of Swimmer objects being simulated.
        DEL_T: Time step length.
        i: Time step number.
    """
    # Wake panels initialize when i==1
    if i == 0:
        pass

    else:
        NT = i # Number of targets (wake panel points that are rolling up)
        for SwimT in Swimmers:
            SwimT.Wake.vx = np.zeros(NT)
            SwimT.Wake.vz = np.zeros(NT)
            DELTA_CORE = SwimT.DELTA_CORE
            for SwimI in Swimmers:
                # Coordinate transformation for body panels influencing wake
                (xp1, xp2, zp) = transformation(SwimT.Wake.x[1:i+1], SwimT.Wake.z[1:i+1], SwimI.Body.AF.x, SwimI.Body.AF.z)

                # Angle of normal vector with respect to global z-axis
                (nx, nz) = panel_vectors(SwimI.Body.AF.x, SwimI.Body.AF.z)[2:4]
                beta = np.arctan2(-nx, nz)

                # Katz-Plotkin eqns 10.20 and 10.21 for body source influence
                dummy1 = np.log((xp1**2+zp**2)/(xp2**2+zp**2))/(4*np.pi)
                dummy2 = (np.arctan2(zp,xp2)-np.arctan2(zp,xp1))/(2*np.pi)

                # Rotate back to global coordinates
                dummy3 = dummy1*np.cos(beta) - dummy2*np.sin(beta)
                dummy4 = dummy1*np.sin(beta) + dummy2*np.cos(beta)

                # Finish eqns 10.20 and 10.21 for induced velocity by multiplying with sigma
                SwimT.Wake.vx += np.dot(dummy3, SwimI.Body.sigma)
                SwimT.Wake.vz += np.dot(dummy4, SwimI.Body.sigma)

                # Formation of (x-x0) and (z-z0) matrices, similar to xp1/xp2/zp but coordinate transformation is not necessary
                NI = SwimI.Body.N+1
                xp = np.repeat(SwimT.Wake.x[1:i+1,np.newaxis], NI, 1) - np.repeat(SwimI.Body.AF.x[:,np.newaxis].T, NT, 0)
                zp = np.repeat(SwimT.Wake.z[1:i+1,np.newaxis], NI, 1) - np.repeat(SwimI.Body.AF.z[:,np.newaxis].T, NT, 0)

                # Find distance r_b between each influence/target
                r_b = np.sqrt(xp**2+zp**2)

                # Katz-Plotkin eqns 10.9 and 10.10 for body doublet (represented as point vortices) influence
                dummy1 = zp/(2*np.pi*(r_b**2+DELTA_CORE**2))
                dummy2 = -xp/(2*np.pi*(r_b**2+DELTA_CORE**2))

                # Finish eqns 10.9 and 10.10 by multiplying with Body.gamma, add to induced velocity
                SwimT.Wake.vx += np.dot(dummy1, SwimI.Body.gamma)
                SwimT.Wake.vz += np.dot(dummy2, SwimI.Body.gamma)

                # Formation of (x-x0) and (z-z0) matrices, similar to xp1/xp2/zp but coordinate transformation is not necessary
                NI = SwimI.Edge.N+1
                xp = np.repeat(SwimT.Wake.x[1:i+1,np.newaxis], NI, 1) - np.repeat(SwimI.Edge.x[:,np.newaxis].T, NT, 0)
                zp = np.repeat(SwimT.Wake.z[1:i+1,np.newaxis], NI, 1) - np.repeat(SwimI.Edge.z[:,np.newaxis].T, NT, 0)

                # Find distance r_e between each influence/target
                r_e = np.sqrt(xp**2+zp**2)

                # Katz-Plotkin eqns 10.9 and 10.10 for edge (as point vortices) influence
                dummy1 = zp/(2*np.pi*(r_e**2+DELTA_CORE**2))
                dummy2 = -xp/(2*np.pi*(r_e**2+DELTA_CORE**2))

                # Finish eqns 10.9 and 10.10 by multiplying with Edge.gamma, add to induced velocity
                SwimT.Wake.vx += np.dot(dummy1, SwimI.Edge.gamma)
                SwimT.Wake.vz += np.dot(dummy2, SwimI.Edge.gamma)

                # Formation of (x-x0) and (z-z0) matrices, similar to xp1/xp2/zp but coordinate transformation is not necessary
                NI = i+1
                xp = np.repeat(SwimT.Wake.x[1:i+1,np.newaxis], NI, 1) - np.repeat(SwimI.Wake.x[:i+1,np.newaxis].T, NT, 0)
                zp = np.repeat(SwimT.Wake.z[1:i+1,np.newaxis], NI, 1) - np.repeat(SwimI.Wake.z[:i+1,np.newaxis].T, NT, 0)

                # Find distance r_w between each influence/target
                r_w = np.sqrt(xp**2+zp**2)

                # Katz-Plotkin eqns 10.9 and 10.10 for wake (as point vortices) influence
                dummy1 = zp/(2*np.pi*(r_w**2+DELTA_CORE**2))
                dummy2 = -xp/(2*np.pi*(r_w**2+DELTA_CORE**2))

                # Finish eqns 10.9 and 10.10 by multiplying with Wake.gamma, add to induced velocity
                SwimT.Wake.vx += np.dot(dummy1, SwimI.Wake.gamma[:i+1])
                SwimT.Wake.vz += np.dot(dummy2, SwimI.Wake.gamma[:i+1])

        for Swim in Swimmers:
            # Modify wake with the total induced velocity
            Swim.Wake.x[1:i+1] += Swim.Wake.vx*DEL_T
            Swim.Wake.z[1:i+1] += Swim.Wake.vz*DEL_T
    def pressure(self, P, i, stencil_npts=5):
        """Calculates the pressure distribution along the body's surface.

        Args:
            RHO: Fluid density.
            DEL_T: Time step length.
            i: Time step number.
        """
        RHO = P['RHO']
        DEL_T = P['DEL_T']
        SW_4PRESSURE = P['SW_4PRESSURE']

        (tx, tz, nx, nz, lpanel) = panel_vectors(self.AF.x, self.AF.z)

        # Defining stencil
        if (stencil_npts == 5):
            stencil_chordwise = np.zeros((self.N, 5), dtype=int)
            stencil_chordwise[0:2, :] = np.array([[0, 1, 2, 3, 4],
                                                  [-1, 0, 1, 2, 3]])
            stencil_chordwise[2:-2, :] = np.tile(np.array([-2, -1, 0, 1, 2]),
                                                 (self.N - 4, 1))
            stencil_chordwise[-2:, :] = np.array([[-3, -2, -1, 0, 1],
                                                  [-4, -3, -2, -1, 0]])
        else:
            if (stencil_npts != 3):
                print '+-----------------------------------------------------------------------------+'
                print '| WARNING! There are only three- and five-point stencils available.           |'
                print '|          Defaulting to the three-point stencil.                             |'
                print '+-----------------------------------------------------------------------------+'
            stencil_chordwise = np.zeros((self.N, 3))
            stencil_chordwise[0, :] = np.array([0, 1, 2])
            stencil_chordwise[1:-1, :] = np.repeat(np.array([-1, 0, 1]),
                                                   self.N - 2,
                                                   axis=0)
            stencil_chordwise[-1, :] = np.array([-2, -1, 0])

        # Tangential panel velocity dmu/dl
        dmu_dl = np.empty(self.N)
        for j in xrange(self.N):
            # Defining stencil depending on chordwise element
            stencil = np.copy(stencil_chordwise[j, :])
            pan_elem = j + stencil

            # Calling finite difference approximations based on stencil (3-point and 5-point available)
            dmu_dl[j] = finite_diff(self.mu[pan_elem], lpanel[pan_elem],
                                    stencil)

        # Potential change dmu/dt, second-order differencing after first time step
        if i == 0:
            dmu_dt = self.mu / DEL_T
        elif i == 1:
            dmu_dt = (self.mu - self.mu_past[0, :]) / DEL_T
        elif (i > 3 and SW_4PRESSURE):
            dmu_dt = ((25. / 12.) * self.mu - 4. * self.mu_past[0, :] +
                      3. * self.mu_past[1, :] -
                      (4. / 3.) * self.mu_past[2, :] +
                      (1. / 4.) * self.mu_past[3, :]) / DEL_T
        else:
            dmu_dt = (3. * self.mu - 4. * self.mu_past[0, :] +
                      self.mu_past[1, :]) / (2. * DEL_T)

        # Unsteady pressure calculation (from Matlab code)
        qpx_tot = dmu_dl * tx + self.sigma * nx
        qpz_tot = dmu_dl * tz + self.sigma * nz

        self.p_s = -RHO * (qpx_tot**2 + qpz_tot**2) / 2.
        self.p_us = RHO * dmu_dt + RHO * (qpx_tot * (self.V + self.vx) +
                                          qpz_tot * self.vz)
        self.p = self.p_s + self.p_us
        self.cp = self.p / (0.5 * RHO * self.V**2)
Beispiel #29
0
    def setInterfaceForce(self, Solid, Body, PyFEA, THETA, HEAVE, outerCorr,
                          SW_VISC_DRAG, delFs, SW_INTERP_MTD, C, i_t):
        """
        Updates the structural mesh position, calculates the traction forces on
        the free nodes, and determines the initial condisitons for the timestep.
        
        Args:
            Solid (object): A solid object created from the solid class.
            Body (object): A body object created from the swimmer class.
            PyFEA (object): A FEA solver object created from the PyFEA class.
            t (float): Current simulation time.
            TSTEP (flaot): Small, incremental distance/time offsets.
            outerCorr (int): Current FSI subiteration number.
            SW_VISC_DRAG (bool): Used to determine 
                if viscous forces should be included.
            delFs (float): NumPy array of viscous force components.
            SW_INTERP_MTD (bool): Used to determine if linear or cubic spline 
                interpolation between fluid and solid domains should be used.
            C (float): Body chord length.
            i_t (int): Current time-step number.       
        """
        # Superposing the structural displacements
        if (outerCorr > 1):
            Solid.nodes[:,
                        0] += (self.nodeDispl[:, 0] - self.nodeDisplOld[:, 0])
            Solid.nodes[:,
                        1] += (self.nodeDispl[:, 1] - self.nodeDisplOld[:, 1])

        if (outerCorr <= 1):
            # Updating the new kinematics
            Solid.nodes[:, 0] = (Solid.nodesNew[:, 0] -
                                 Solid.nodesNew[0, 0]) * np.cos(THETA)
            Solid.nodes[:, 1] = HEAVE + (Solid.nodesNew[:, 0] -
                                         Solid.nodesNew[0, 0]) * np.sin(THETA)

            # Calculating the shift in node positions with the swimming velocity
            nodeDelxp = Body.AF.x_le * np.ones((Solid.Nelements + 1, 1))
            #            nodeDelzp = Body.AF.z_le * np.ones((Solid.Nelements + 1,1))

            #Superposiing the kinematics and swimming translations
            Solid.nodes[:, 0] = Solid.nodes[:, 0] + nodeDelxp.T
#            Solid.nodes[:,1] = Solid.nodes[:,1] + nodeDelzp.T

# Determine the load conditons from the fluid solver
# Calculate the panel lengths and normal vectors
        (nx, nz, lp) = panel_vectors(Body.AF.x, Body.AF.z)[2:5]

        # Calculate the force magnitude acting on the panel due to pressure,
        # then calculate the x-z components of this force
        magPF = Body.p * lp * 1.
        pF = np.zeros((Body.N, 2))
        if (SW_VISC_DRAG == 1):
            pF[:, 0] = (magPF.T * nx.T * -1.) + delFs[:, 0]
            pF[:, 1] = (magPF.T * nz.T * -1.) + delFs[:, 1]
        else:
            pF[:, 0] = magPF.T * nx.T * -1.
            pF[:, 1] = magPF.T * nz.T * -1.

        # Determine the moment arm between top and bottom panel points, and
        # collapse force and moments to the camber line
        colM = np.zeros((0.5 * Body.N, 1))
        colPF = np.zeros((0.5 * Body.N, 2))
        meanPt = np.zeros((0.5 * Body.N, 2))
        for i in xrange(int(0.5 * Body.N)):
            meanPt[i, 0] = 0.5 * (Body.AF.x_mid[0, i] +
                                  Body.AF.x_mid[0, -(i + 1)])
            meanPt[i, 1] = 0.5 * (Body.AF.z_mid[0, i] +
                                  Body.AF.z_mid[0, -(i + 1)])
            colPF[i, :] = pF[i, :] + pF[-(i + 1), :]
            colM[i,:] = -1. * pF[i,0] * (Body.AF.z_mid[0,i] - meanPt[i,1]) + \
                   pF[i,1] * (Body.AF.x_mid[0,i] - meanPt[i,0]) + \
                   -1. * pF[-(i+1),0] * (Body.AF.z_mid[0,-(i+1)] - meanPt[i,1]) + \
                   pF[-(i+1),1] * (Body.AF.x_mid[0,-(i+1)] - meanPt[i,0])

        colPF = np.flipud(colPF)
        colM = np.flipud(colM)

        # Interpolate the collapsed forces and moments onto the structural mesh
        nodalInput = np.zeros((Solid.Nnodes, 6))
        if (SW_INTERP_MTD == True):
            f1 = extrap1d(
                interp1d(Solid.meanline_c0[0.5 * Body.N:], colPF[:, 0]))
            f2 = extrap1d(
                interp1d(Solid.meanline_c0[0.5 * Body.N:], colPF[:, 1]))
            f3 = extrap1d(
                interp1d(Solid.meanline_c0[0.5 * Body.N:], colM[:, 0]))
            nodalInput[:, 0] = f1(Solid.nodes[:, 2])
            nodalInput[:, 1] = f2(Solid.nodes[:, 2])
            nodalInput[:, 5] = f3(Solid.nodes[:, 2])
#            nodalInput[:,0] = np.interp(Solid.nodes[:,2], Solid.meanline_c0[0.5*Body.N:], colPF[:,0], left=0, right=0)
#            nodalInput[:,1] = np.interp(Solid.nodes[:,2], Solid.meanline_c0[0.5*Body.N:], colPF[:,1], left=0, right=0)
#            nodalInput[:,5] = np.interp(Solid.nodes[:,2], Solid.meanline_c0[0.5*Body.N:], colM[:,0], left=0, right=0)
        else:
            nodalInput[:, 0] = spline(Solid.meanline_c0[0.5 * Body.N:],
                                      colPF[:, 0], Solid.nodes[:, 2])
            nodalInput[:, 1] = spline(Solid.meanline_c0[0.5 * Body.N:],
                                      colPF[:, 1], Solid.nodes[:, 2])
            nodalInput[:, 5] = spline(Solid.meanline_c0[0.5 * Body.N:],
                                      colM[:, 0], Solid.nodes[:, 2])

        # Rotate force components into the relative cooridnate system
        (nodalInput[:, 0],
         nodalInput[:, 1]) = self.rotatePts(nodalInput[:, 0], nodalInput[:, 1],
                                            -THETA)

        # Create the load matrix
        Fload = np.zeros((3 * (Solid.Nnodes), 1))
        Fload[0::3, 0] = np.copy(nodalInput[:, 0])
        Fload[1::3, 0] = np.copy(nodalInput[:, 1])
        Fload[2::3, 0] = np.copy(nodalInput[:, 5])

        # Create element area matrix
        A = np.copy(Solid.tBeamStruct[:, 0])

        # Create area moment of inertia matrix
        I = 1. * Solid.tBeamStruct[:, 0]**3 / 12

        # Initial element length
        l_0 = C / Solid.Nelements

        # Initial displacements and velocities
        #        if (i_t <= 1 and outerCorr <= 1):
        temp = 3 * Solid.fixedCounter
        if (i_t <= 1 and outerCorr <= 1):
            PyFEA.U_n = np.zeros((3 * Solid.Nnodes, 1))
            PyFEA.Udot_n = np.zeros((3 * Solid.Nnodes, 1))
            PyFEA.UdotDot_n = np.zeros((3 * Solid.Nnodes - temp, 1))
            PyFEA.U_nPlus = np.zeros((3 * Solid.Nnodes - temp, 1))
            PyFEA.Udot_nPlus = np.zeros((3 * Solid.Nnodes - temp, 1))
            PyFEA.UdotDot_nPlus = np.zeros((3 * Solid.Nnodes - temp, 1))
        elif (i_t > 0 and outerCorr <= 1):
            PyFEA.U_n = np.zeros((3 * Solid.Nnodes, 1))
            PyFEA.Udot_n = np.zeros((3 * Solid.Nnodes, 1))
            PyFEA.UdotDot_n = np.zeros((3 * Solid.Nnodes - temp, 1))
            PyFEA.U_n[temp:, 0] = PyFEA.U_nPlus.T
            PyFEA.Udot_n[temp:, 0] = PyFEA.Udot_nPlus.T
            PyFEA.UdotDot_n = PyFEA.Udot_nPlus

        PyFEA.Fload = np.copy(Fload)
        PyFEA.A = np.copy(A)
        PyFEA.I = np.copy(I)
        PyFEA.l = l_0 * np.ones(Solid.Nelements)
Beispiel #30
0
    def setSpringForce(self, Body, Solid, PyFEA, P, outerCorr, delFs, i_t):
        # Superposing the structural displacements
        if (outerCorr > 1):
            Solid.nodes[:,
                        0] += (self.nodeDispl[:, 0] - self.nodeDisplOld[:, 0])
            Solid.nodes[:,
                        1] += (self.nodeDispl[:, 1] - self.nodeDisplOld[:, 1])

        if (outerCorr <= 1):
            # Updating the new kinematics
            Solid.nodes[:,
                        0] = (Solid.nodesNew[:, 0] -
                              Solid.nodesNew[0, 0]) * np.cos(P['THETA'][i_t])
            Solid.nodes[:,
                        1] = P['HEAVE'][i_t] + (Solid.nodesNew[:, 0] -
                                                Solid.nodesNew[0, 0]) * np.sin(
                                                    P['THETA'][i_t])

            # Calculating the shift in node positions with the swimming velocity
            nodeDelxp = Body.AF.x_le * np.ones((Solid.Nelements + 1, 1))
            #            nodeDelzp = Body.AF.z_le * np.ones((Solid.Nelements + 1,1))

            #Superposiing the kinematics and swimming translations
            Solid.nodes[:, 0] = Solid.nodes[:, 0] + nodeDelxp.T
#            Solid.nodes[:,1] = Solid.nodes[:,1] + nodeDelzp.T

# Determine the load conditons from the fluid solver
# Calculate the panel lengths and normal vectors
        (nx, nz, lp) = panel_vectors(Body.AF.x, Body.AF.z)[2:5]

        # Calculate the force magnitude acting on the panel due to pressure,
        # then calculate the x-z components of this force
        magPF = Body.p * lp * 1.
        pF = np.zeros((Body.N, 3))
        if P['SW_VISC_DRAG']:
            pF[:, 0] = (magPF.T * nx.T * -1.) + delFs[:, 0]
            pF[:, 2] = (magPF.T * nz.T * -1.) + delFs[:, 1]
        else:
            pF[:, 0] = magPF.T * nx.T * -1.
            pF[:, 2] = magPF.T * nz.T * -1.

        # Calculating the moment about the leading edge
        r = np.zeros((Body.N, 3))
        r[:, 0] = Body.AF.x_mid[0, :].T - Body.AF.x_le
        r[:, 2] = Body.AF.z_mid[0, :].T - Body.AF.z_le
        delM_le = np.cross(r, pF)
        Nf = -np.sum(delM_le[:, 1])

        # Calculating the inertial torque resulting from the vertical
        # acceleration of the leading edge
        Ni = -P['RHO_S'] * Solid.tmax * P['C']**2 * np.pi**2 * P[
            'F']**2 * np.cos(PyFEA.theta_n) * P['INERTIA'][i_t]

        # Calculating the moment of intertia about the leading edge. An extra
        # 0.5 is multiplied in to approximate the teardrop geometry's mass.
        I = 0.5 * PyFEA.RHO_S * Solid.tmax * P['C']**3 / 3.

        # Define spring and dampening constants
        kappa_1 = P['KAPPA_1']
        kappa_2 = P['KAPPA_2']
        zeta = P['ZETA']

        if (i_t <= 1 and outerCorr <= 1):
            PyFEA.theta_n = 0.
            PyFEA.thetaDot_n = 0.
            PyFEA.thetaDotDot_n = 0.
            PyFEA.theta_nPlus = 0.
            PyFEA.thetaDot_nPlus = 0.
            PyFEA.thetaDotDot_nPlus = 0.
        elif (i_t > 0 and outerCorr <= 1):
            PyFEA.theta_n = 0.
            PyFEA.thetaDot_n = 0.
            PyFEA.thetaDotDot_n = 0.
            PyFEA.theta_n = np.copy(PyFEA.theta_nPlus)
            PyFEA.thetaDot_n = np.copy(PyFEA.thetaDot_nPlus)
            PyFEA.thetaDotDot_n = np.copy(PyFEA.thetaDotDot_nPlus)

        PyFEA.I = np.copy(I)
        PyFEA.kappa_1 = np.copy(kappa_1)
        PyFEA.kappa_2 = np.copy(kappa_2)
        PyFEA.zeta = np.copy(zeta)
        PyFEA.Nf = np.copy(Nf)
        PyFEA.Ni = np.copy(Ni)