Example #1
0
def localElasticForces(PosDef, PsiDef, 
                          PosIni, PsiIni,
                          XBELEM, NodeList):
    """@brief Approximate shear force and moments from local strain and
    stiffness matrix.
    
    @param PosDef Deformed nodal coordinates.
    @param PsiDef Deformed nodal rotation vectors.
    @param XBELEM Xbeam element derived type containing element data.
    @param NodeList List of element numbers for strain approximation,
            starts from zero.
    @warning Untested.
    """
    
    F = np.zeros((len(NodeList),6))
    strains = localStrains(PosDef, PsiDef, 
                           PosIni, PsiIni,
                           XBELEM, NodeList)
    iOut = 0 # Output index
    for iNode in NodeList:
        iElem, iiElem = iNode2iElem(iNode, PosDef.shape[0]-1, XBELEM.NumNodes[0])
        del iiElem
        elemStrain = strains[iOut,:]
        elemK = XBELEM.Stiff[iElem*6:(iElem+1)*6,:]
        F[iOut,:] = np.dot(elemK,elemStrain)
        iOut += 1
    # END of iElem
    return F
Example #2
0
def CoincidentGridForce(XBINPUT, PsiDefor, Section, AeroForces,
                        BeamForces, PsiA_G=np.zeros(3)):

    """@brief Calculates aero forces and moments on the beam nodes from those on
    the aerodynamic grid.
    @param XBINPUT Beam input options.
    @param PsiDefor Array of beam nodal rotations.
    @param Section Array containing sectional camberline coordinates.
    @param AeroForces Aerodynamic grid forces to be mapped to beam nodes.
    @param BeamForces BeamForces to overwrite.
    @param PsiA_G Attitude of a-frame w.r.t earth. Default zero.
    
    @details All Beam forces calculated in in a-frame, while aero forces 
    are defined in earth frame."""
    
    # Zero beam forces.
    BeamForces[:,:] = 0.0
    
    # Get transformation matrix between a-frame and earth. 
    CGa = Psi2TransMat(PsiA_G) # project from a -> G
    CaG = CGa.T                # project from G -> a
    
    # Num Nodes
    NumNodes = XBINPUT.NumNodesTot
    
    # Get number of nodes per beam element.
    NumNodesElem = XBINPUT.NumNodesElem
    
    # Loop along beam length.
    for iNode in range(NumNodes):
        
        iElem, iiElem = iNode2iElem(iNode, NumNodes, NumNodesElem)
        
        # Calculate transformation matrix for each node.
        CaB = Psi2TransMat(PsiDefor[iElem,iiElem,:])
        
        # Loop through each sectional coordinate.
        for jSection in range(Section.shape[0]):
            
            # Get Section coord and AeroForce in a-frame.
            Section_A = np.dot(CaB,Section[jSection,:])
            AeroForce_A = np.dot(CaG,AeroForces[jSection][iNode][:])
            
            # Calc moment.
            BeamForces[iNode,3:] += np.cross(Section_A,
                                             AeroForce_A)
            
            # Calc force.
            BeamForces[iNode,:3] += AeroForce_A
Example #3
0
def CoincidentGridForce(XBINPUT, PsiDefor, Section, AeroForces, BeamForces):
    """@brief Calculates aero forces and moments on the beam nodes from those on
    the aerodynamic grid.
    @param XBINPUT Beam input options.
    @param PsiDefor Array of beam nodal rotations.
    @param Section Array containing sectional camberline coordinates.
    @param AeroForces Aerodynamic grid forces to be mapped to beam nodes.
    @param BeamForces BeamForces to overwrite.
    
    @details All Beam forces calculated in in a-frame, while aero forces 
    are defined in earth frame."""

    # Zero beam forces.
    BeamForces[:, :] = 0.0

    # Get transformation matrix between a-frame and earth.
    CGa = Psi2TransMat(XBINPUT.PsiA_G)
    CaG = CGa.T

    # Num Nodes
    NumNodes = XBINPUT.NumNodesTot

    # Get number of nodes per beam element.
    NumNodesElem = XBINPUT.NumNodesElem

    # Loop along beam length.
    for iNode in range(NumNodes):

        iElem, iiElem = iNode2iElem(iNode, NumNodes, NumNodesElem)

        # Calculate transformation matrix for each node.
        CaB = Psi2TransMat(PsiDefor[iElem, iiElem, :])

        # Loop through each sectional coordinate.
        for jSection in range(Section.shape[0]):

            # Get Section coord and AeroForce in a-frame.
            Section_A = np.dot(CaB, Section[jSection, :])
            AeroForce_A = np.dot(CaG, AeroForces[jSection][iNode][:])

            # Calc moment.
            BeamForces[iNode, 3:] += np.cross(Section_A, AeroForce_A)

            # Calc force.
            BeamForces[iNode, :3] += AeroForce_A
Example #4
0
        # Initialize PosDefor, PsiDefor
        PosDefor = np.zeros((N + 1, 3), dtype=ct.c_double, order='F')
        PosDeforElem = np.zeros((NumElems, 3, 3), dtype=ct.c_double, order='F')
        PsiDefor = np.zeros((NumElems, 3, 3), dtype=ct.c_double, order='F')

        data = np.loadtxt(refFile, skiprows=2)
        i0 = 0
        for iElem in range(NumElems):
            for i in range(numNodesElem):
                PosDeforElem[iElem, i, :] = data[i0, 2:5]
                PsiDefor[iElem, i, :] = data[i0, 5:8]
                i0 += 1

        # extract nodal information (PosDefor)
        for iNode in range(N + 1):
            iElem, iiElem = iNode2iElem(iNode, N + 1, numNodesElem)
            PosDefor[iNode, :] = PosDeforElem[iElem, iiElem, :]

        # get reference circulation strengths
        refFile = Settings.OutputDir + 'M' + str(M) + 'N' + str(
            N) + '_V25_alpha' + str(int(alpha * 180.0 / np.pi)) + '_Gamma0'
        myDict = loadmat(refFile)
        gam0 = myDict['Gamma0']

        eta0 = (PosDefor, PsiDefor, gam0)
    else:
        eta0 = None

    # Generate a history of beam DoF motions (in A-frame)
    if beamDOFmotion:
        delEtaHisty = np.zeros((12 * N, len(Time)))
Example #5
0
def CoincidentGrid(PosDefor,
                   PsiDefor,
                   Section,
                   VelA_A,
                   OmegaA_A,
                   PosDotDef,
                   PsiDotDef,
                   XBINPUT,
                   AeroGrid,
                   AeroVels,
                   OriginA_G=None,
                   PsiA_G=None,
                   ctrlSurf=None):
    """@brief Creates aero grid and velocities 
    based on beam nodal information.
    @param PosDefor Array of beam nodal displacements.
    @param PsiDefor Array of beam nodal rotations.
    @param Section Array containing sectional camberline coordinates.
    @param VelA_A Velocity of a-frame projected in a-frame.
    @param OmegaA_A Angular vel of a-frame projected in a-frame.
    @param PosDotDef Array of beam nodal velocities.
    @param PsiDotDef Array of beam nodal angular velocities.
    @param XBINPUT Beam input options.
    @param AeroGrid Aerodynamic grid to be updated.
    @param AeroVels Aerodynamic grid velocities to be updated
    @param OriginA_G Origin of a-frame.
    @param PsiA_G Attitude of a-frame w.r.t earth.
    @param ctrlSurf Control surface definition. 
    
    @details AeroGrid and AeroVels are projected in G-frame.
    """

    NumNodes = PosDefor.shape[0]
    NumNodesElem = XBINPUT.NumNodesElem

    for iNode in range(PosDefor.shape[0]):
        # Work out what element we are in.
        iElem, iiElem = iNode2iElem(iNode, NumNodes, NumNodesElem)

        # Calculate transformation matrix for each node.
        CaB = Psi2TransMat(PsiDefor[iElem, iiElem, :])

        # Loop through section coordinates.
        for jSection in range(Section.shape[0]):
            # Calculate instantaneous aero grid points
            AeroGrid[jSection,iNode,:] = PosDefor[iNode,:] \
                                         + np.dot(CaB,Section[jSection,:])

            # Calculate inertial angular velocity of B-frame projected in
            # the B-frame.
            Omega_B_B = (np.dot(Tangential(PsiDefor[iElem, iiElem, :]),
                                PsiDotDef[iElem, iiElem, :]) +
                         np.dot(CaB.T, OmegaA_A))

            # Calculate inertial velocity at grid points (projected in A-frame).
            AeroVels[jSection, iNode, :] = (
                VelA_A + np.dot(Skew(OmegaA_A), PosDefor[iNode, :]) +
                PosDotDef[iNode, :] +
                np.dot(CaB, np.dot(Skew(Omega_B_B), Section[jSection, :])))

            if (ctrlSurf != None and jSection > ctrlSurf.iMin
                    and jSection <= ctrlSurf.iMax and iNode >= ctrlSurf.jMin
                    and iNode <= ctrlSurf.jMax):
                # Apply changes to Zeta and ZetaDot in a-frame due to control
                # surface movement.

                # Check if control surface indices are within range of grid
                assert (ctrlSurf.iMin >= 0), 'CtrlSurf iMin less then zero'
                assert (ctrlSurf.iMax < Section.shape[0]), (
                    'CtrlSurf iMax ' + 'greater than section iMax')
                assert (ctrlSurf.jMin >= 0), 'CtrlSurf jMin less then zero'
                assert (ctrlSurf.jMax < PosDefor.shape[0]), (
                    'CtrlSurf jMax ' + 'greater than section jMax')

                # Determine hinge point
                hingePoint = Section[ctrlSurf.iMin, :]

                # Use a CRV to define rotation in sectional frame
                hingeRot = np.array([ctrlSurf.beta, 0.0, 0.0])
                hingeRotDot = np.array([ctrlSurf.betaDot, 0.0, 0.0])

                # Find lever arm from hinge point
                leverArm = Section[jSection, :] - hingePoint

                # Deformed position of node in B-frame
                CBBnew = Psi2TransMat(hingeRot)
                newSectionPoint = hingePoint + np.dot(CBBnew, leverArm)

                # Overwrite corresponding element in Aerogrid
                AeroGrid[jSection, iNode, :] = (PosDefor[iNode, :] +
                                                np.dot(CaB, newSectionPoint))

                # Overwrite corresponding element in AeroVels
                # There is an extra velocity contribution due to the rotation
                # of the hinge, with reference frame Bnew. Hence,
                # CBBnew * ( Omega_Bnew_Bnew X Point__Bnew), which is the
                # velocity at a point on the flap due to the rotation
                # of the hinge projected in the B-frame. is added.
                # Note: Skew(hingeRotDot) is an acceptable definition of the
                # angular rate as it corresponds to planar motion within the
                # section. In general Skew(T(\psi)\dot{\psi}) is required.
                # Warning: should omega_Bnew_Bnew  (Skew(hingeRotDot))
                # be an inertial velocity?
                AeroVels[jSection, iNode, :] = (
                    VelA_A + np.dot(Skew(OmegaA_A), PosDefor[iNode, :]) +
                    PosDotDef[iNode, :] + np.dot(
                        CaB,
                        np.dot(Skew(Omega_B_B), newSectionPoint) +
                        np.dot(CBBnew, np.dot(Skew(hingeRotDot), leverArm))))

        #END for jSection
    #END for iNode

    if ((OriginA_G is not None) and (PsiA_G is not None)):
        # Get transformation from a-frame to earth frame.
        CaG = Psi2TransMat(PsiA_G)
        CGa = CaG.T

        # Add the origin to grids in earth frame and transform velocities.
        for iNode in range(PosDefor.shape[0]):
            for jSection in range(Section.shape[0]):
                AeroGrid[jSection,iNode,:] = OriginA_G + \
                                             np.dot(
                                             CGa, AeroGrid[jSection,iNode,:])

                AeroVels[jSection,
                         iNode, :] = np.dot(CGa, AeroVels[jSection, iNode, :])
Example #6
0
def localStrains(PosDef, PsiDef,
                   PosIni, PsiIni,
                   XBELEM, NodeList,
                   SO3 = False):
    """@brief Approximate strains at the midpoint of nodes.
    
    @param PosDef Deformed nodal coordinates.
    @param PsiDef Deformed nodal rotation vectors.
    @param PosIni Initial (undeformed) nodal coordinates.
    @param PsiIni Initial (undeformed) nodal rotation vectors.
    @param XBELEM Xbeam element derived type containing element data.
    @param NodeList List of node numbers for strain approximation at adjacent
            midpoint in the direction of increasing node index,
            starts from zero:
            0---x---1---x---2---x---3-- ... --(NumNodes-1)
            Strains are calculated at the x to the right of selected nodes.
    @param SO3 Flag for use of the SO(3) manifold in CRV interpolation.
    
    @details Assumes that all nodes are either two- or three- noded. 
    @warning Untested.
    """
    
    strains = np.zeros((len(NodeList),6))
    NumNodes = PosDef.shape[0]-1
    NumNodesElem = XBELEM.NumNodes[0]
    iOut = 0 # Output index
    for iNode in NodeList:
        if iNode == NumNodes or iNode == -1:
            raise ValueError("Midpoint strain requested beyond final node.")
        
        iElem, iiElem = iNode2iElem(iNode, NumNodes, NumNodesElem)
        
        if NumNodesElem == 2:
            if SO3 == True:
                # Consistent calculation of midpoint strains using SO(3) manifold.
                raise NotImplementedError("SO(3) manifold strains.")
            else:
                # Using fortran routines
                R0 = np.zeros((2,6))
                R0[0,:3] = PosIni[iNode,:]
                R0[0,3:] = PsiIni[iElem,iiElem,:]
                R0[1,:3] = PosIni[iNode+1,:]
                R0[1,3:] = PsiIni[iElem,iiElem+1,:]
                
                Ri = np.zeros((2,6))
                Ri[0,:3] = PosDef[iNode,:]
                Ri[0,3:] = PsiDef[iElem,iiElem,:]
                Ri[1,:3] = PosDef[iNode+1,:]
                Ri[1,3:] = PsiDef[iElem,iiElem+1,:]
            
                # Midpoint
                z = 0.0
                
                strainz = Cbeam3_strainz(R0, Ri, z)
            # END if SO3            
            
        elif NumNodesElem == 3:
            if SO3 == True:
                raise NotImplementedError("Only available for 2-noded just now.")
            else:
                # Using fortran routines
                R0 = np.zeros((3,6))
                R0[0,:3] = PosIni[2*iElem,:]
                R0[1,:3] = PosIni[2*iElem+2,:]
                R0[2,:3] = PosIni[2*iElem+1,:]
                R0[:,3:] = PsiIni[iElem]
                
                Ri = np.zeros((3,6))
                Ri[0,:3] = PosDef[2*iElem,:]
                Ri[1,:3] = PosDef[2*iElem+2,:]
                Ri[2,:3] = PosDef[2*iElem+1,:]
                Ri[:,3:] = PsiDef[iElem]
                
                if iiElem == 0:
                    z = -0.5 # mid-point adjacent to node iNode
                elif iiElem == 1:
                    z = 0.5 # mid-point adjacent to node iNode
                elif iiElem == 2:
                    raise ValueError("iiElem only 0, 1 for adjacent midpoint" +
                                     "calculation.")
                else:
                    raise ValueError("iiElem can only take 0, 1 or 2 for " +
                                     "3-noded elements.")
                
                strainz = Cbeam3_strainz(R0, Ri, z)
            # END if SO(3)
        else:
            raise ValueError("Only 2- or 3-noded elements are supported.")
        
        strains[iOut,:] = strainz
        
        iOut += 1
    # END for iElem
    return strains
Example #7
0
def CoincidentGrid(PosDefor, PsiDefor, Section,
                   VelA_A, OmegaA_A, PosDotDef, PsiDotDef,
                   XBINPUT, AeroGrid, AeroVels,
                   OriginA_a = None,
                   PsiA_G = None,
                   ctrlSurf = None):
    """@brief Creates aero grid and velocities 
    based on beam nodal information.
    @param PosDefor Array of beam nodal displacements.
    @param PsiDefor Array of beam nodal rotations.
    @param Section Array containing sectional camberline coordinates.
    @param VelA_A Velocity of a-frame projected in a-frame.
    @param OmegaA_A Angular vel of a-frame projected in a-frame.
    @param PosDotDef Array of beam nodal velocities.
    @param PsiDotDef Array of beam nodal angular velocities.
    @param XBINPUT Beam input options.
    @param AeroGrid Aerodynamic grid to be updated.
    @param AeroVels Aerodynamic grid velocities to be updated
    @param OriginA_a Origin of a-frame (in a-frame components)
    @param PsiA_G Attitude of a-frame w.r.t earth.
    @param ctrlSurf Control surface definition. 
    
    @details AeroGrid and AeroVels are projected in G-frame.
    """
    
    NumNodes = PosDefor.shape[0]
    NumNodesElem = XBINPUT.NumNodesElem
    if ctrlSurf != None: NumCtrlSurf = len(ctrlSurf)
            
    for iNode in range(PosDefor.shape[0]):
        # Work out what element we are in.
        iElem, iiElem = iNode2iElem(iNode, NumNodes, NumNodesElem)
        
        # Calculate transformation matrix for each node.
        CaB = Psi2TransMat(PsiDefor[iElem,iiElem,:])
        
        # Loop through section coordinates.
        for jSection in range(Section.shape[0]):
            # Calculate instantaneous aero grid points
            AeroGrid[jSection,iNode,:] = PosDefor[iNode,:] \
                                         + np.dot(CaB,Section[jSection,:])
                                         
            # Calculate inertial angular velocity of B-frame projected in 
            # the B-frame.
            Omega_B_B = (np.dot(Tangential(PsiDefor[iElem,iiElem,:]),
                                PsiDotDef[iElem,iiElem,:])
                         + np.dot(CaB.T, OmegaA_A))
                        
            # Calculate inertial velocity at grid points (projected in A-frame).                             
            AeroVels[jSection,iNode,:] = (VelA_A
                        + np.dot(Skew(OmegaA_A),PosDefor[iNode,:])
                        + PosDotDef[iNode,:]
                        + np.dot(CaB, np.dot(
                        Skew(Omega_B_B), Section[jSection,:])))
            
#<<<<<<< HEAD
            # Control Surface Update
            if ctrlSurf != None: 
                for cc in range(NumCtrlSurf):
                    if (jSection > ctrlSurf[cc].iMin and jSection <= ctrlSurf[cc].iMax and
                        iNode >= ctrlSurf[cc].jMin and iNode <= ctrlSurf[cc].jMax):
                        
                        # Apply changes to Zeta and ZetaDot in a-frame due to control
                        # surface movement.
                        
                        # Check if control surface indices are within range of grid
                        assert (ctrlSurf[cc].iMin >= 0), 'CtrlSurf iMin less then zero'
                        assert (ctrlSurf[cc].iMax < Section.shape[0]), ('CtrlSurf iMax '
                                + 'greater than section iMax')
                        assert (ctrlSurf[cc].jMin >= 0), 'CtrlSurf jMin less then zero'
                        assert (ctrlSurf[cc].jMax < PosDefor.shape[0]), ('CtrlSurf jMax '
                                + 'greater than section jMax')
                        
                        # Determine hinge point
                        hingePoint = Section[ctrlSurf[cc].iMin,:]
                        
                        # Use a CRV to define rotation in sectional frame
                        hingeRot = np.array([ctrlSurf[cc].beta, 0.0, 0.0])
                        hingeRotDot = np.array([ctrlSurf[cc].betaDot, 0.0, 0.0])
                        #print('Beta detected static: %f' %ctrlSurf[cc].beta)
                        #print('BetaDot detected static: %f' %ctrlSurf[cc].betaDot)
                        #1/0
                        # Find lever arm from hinge point
                        leverArm = Section[jSection,:] - hingePoint
                        
                        # Deformed position of node in B-frame
                        CBBnew = Psi2TransMat(hingeRot)
                        newSectionPoint = hingePoint + np.dot(CBBnew,leverArm)
                        
                        # Overwrite corresponding element in Aerogrid
                        AeroGrid[jSection,iNode,:] = (PosDefor[iNode,:]
                                                      + np.dot(CaB,newSectionPoint))
                        
                        # Overwrite corresponding element in AeroVels
                        # There is an extra velocity contribution due to the rotation 
                        # of the hinge, with reference frame Bnew. Hence, 
                        # CBBnew * ( Omega_Bnew_Bnew X Point__Bnew), which is the
                        # velocity at a point on the flap due to the rotation
                        # of the hinge projected in the B-frame. is added.
                        # Note: Skew(hingeRotDot) is an acceptable definition of the
                        # angular rate as it corresponds to planar motion within the
                        # section. In general Skew(T(\psi)\dot{\psi}) is required.
                        # Warning: should omega_Bnew_Bnew  (Skew(hingeRotDot))
                        # be an inertial velocity?
                        AeroVels[jSection,iNode,:] = (VelA_A
                                + np.dot(Skew(OmegaA_A),PosDefor[iNode,:])
                                + PosDotDef[iNode,:]
                                + np.dot(CaB, 
                                         np.dot(Skew(Omega_B_B), newSectionPoint)
                                         + np.dot(CBBnew,
                                                  np.dot(Skew(hingeRotDot),
                                                         leverArm))))
# #=======
#             if (ctrlSurf != None and 
#                 jSection > ctrlSurf.iMin and jSection <= ctrlSurf.iMax and
#                 iNode >= ctrlSurf.jMin and iNode <= ctrlSurf.jMax):
#                 # Apply changes to Zeta and ZetaDot in a-frame due to control
#                 # surface movement.
                
                # # Check if control surface indices are within range of grid
                # assert (ctrlSurf.iMin >= 0), 'CtrlSurf iMin less then zero'
                # assert (ctrlSurf.iMax < Section.shape[0]), ('CtrlSurf iMax '
                #         + 'greater than section iMax')
                # assert (ctrlSurf.jMin >= 0), 'CtrlSurf jMin less then zero'
                # assert (ctrlSurf.jMax < PosDefor.shape[0]), ('CtrlSurf jMax '
                #         + 'greater than section jMax')
                
                # # Determine hinge point
                # hingePoint = Section[ctrlSurf.iMin,:]
                
                # # Use a CRV to define rotation in sectional frame
                # hingeRot = np.array([ctrlSurf.beta, 0.0, 0.0])
                # hingeRotDot = np.array([ctrlSurf.betaDot, 0.0, 0.0])
                
                # # Find lever arm from hinge point
                # leverArm = Section[jSection,:] - hingePoint
                
                # # Deformed position of node in B-frame
                # CBBnew = Psi2TransMat(hingeRot)
                # newSectionPoint = hingePoint + np.dot(CBBnew,leverArm)
                
                # # Overwrite corresponding element in Aerogrid
                # AeroGrid[jSection,iNode,:] = (PosDefor[iNode,:]
                #                               + np.dot(CaB,newSectionPoint))
                
                # # Overwrite corresponding element in AeroVels
                # # There is an extra velocity contribution due to the rotation 
                # # of the hinge, with reference frame Bnew. Hence, 
                # # CBBnew * ( Omega_Bnew_Bnew X Point__Bnew), which is the
                # # velocity at a point on the flap due to the rotation
                # # of the hinge projected in the B-frame. is added.
                # # Note: Skew(hingeRotDot) is an acceptable definition of the
                # # angular rate as it corresponds to planar motion within the
                # # section. In general Skew(T(\psi)\dot{\psi}) is required.
                # # Warning: should omega_Bnew_Bnew  (Skew(hingeRotDot))
                # # be an inertial velocity?
                # AeroVels[jSection,iNode,:] = (VelA_A
                #         + np.dot(Skew(OmegaA_A),PosDefor[iNode,:])
                #         + PosDotDef[iNode,:]
                #         + np.dot(CaB, 
                #                  np.dot(Skew(Omega_B_B), newSectionPoint)
                #                  + np.dot(CBBnew,
                #                           np.dot(Skew(hingeRotDot),
                #                                  leverArm))))
# >>>>>>> rob/master
                
        #END for jSection
    #END for iNode
    

    if ( (OriginA_a != None) and (PsiA_G != None) ):
        # Get transformation from a-frame to earth frame.
        #CaG = Psi2TransMat(PsiA_G)
        #CGa = CaG.T #] sm: this rotated, doesn't project
        CGa = Psi2TransMat(PsiA_G)
        
        ### sm: convert OriginA_a into FoR G components
        OriginA_G=np.dot(CGa,OriginA_a)
        
        for iNode in range(PosDefor.shape[0]):
            for jSection in range(Section.shape[0]):
                AeroGrid[jSection,iNode,:] = OriginA_G + \
                                             np.dot(
                                             CGa, AeroGrid[jSection,iNode,:])                        
                AeroVels[jSection,iNode,:] = np.dot(
                                             CGa, AeroVels[jSection,iNode,:])
Example #8
0
def CoincidentGrid(PosDefor, PsiDefor, Section,
                   VelA_A, OmegaA_A, PosDotDef, PsiDotDef,
                   XBINPUT, AeroGrid, AeroVels,
                   OriginA_G = None,
                   PsiA_G = None,
                   ctrlSurf = None):
    """@brief Creates aero grid and velocities 
    centred on beam nodes.
    @param PosDefor Array of beam nodal displacements.
    @param PsiDefor Array of beam nodal rotations.
    @param Section Array containing sectional camberline coordinates.
    @param VelA_A Velocity of a-frame projected in a-frame.
    @param OmegaA_A Angular vel of a-frame projected in a-frame.
    @param PosDotDef Array of beam nodal velocities.
    @param PsiDotDef Array of beam nodal angular velocities.
    @param XBINPUT Beam input options.
    @param AeroGrid Aerodynamic grid to be updated.
    @param AeroVels Aerodynamic grid velocities to be updated
    @param OriginA_G Origin of a-frame.
    @param PsiA_G Attitude of a-frame w.r.t earth.
    @param ctrlSurf Control surface definition. 
    
    @details AeroGrid and AeroVels are projected in G-frame.
    """
    
    NumNodes = PosDefor.shape[0]
    NumNodesElem = XBINPUT.NumNodesElem
            
    for iNode in range(PosDefor.shape[0]):
        # Work out what element we are in.
        iElem, iiElem = iNode2iElem(iNode, NumNodes, NumNodesElem)
        
        # Calculate transformation matrix for each node.
        CaB = Psi2TransMat(PsiDefor[iElem,iiElem,:])
        
        # Loop through section coordinates.
        for jSection in range(Section.shape[0]):
            # Calculate instantaneous aero grid points
            AeroGrid[jSection,iNode,:] = PosDefor[iNode,:] \
                                         + np.dot(CaB,Section[jSection,:])
                                         
            # Calculate inertial angular velocity of B-frame projected in 
            # the B-frame.
            Omega_B_B = (np.dot(Tangential(PsiDefor[iElem,iiElem,:]),
                                PsiDotDef[iElem,iiElem,:])
                         + np.dot(CaB.T, OmegaA_A))
                        
            # Calculate inertial velocity at grid points (projected in A-frame).                             
            AeroVels[jSection,iNode,:] = (VelA_A
                        + np.dot(Skew(OmegaA_A),PosDefor[iNode,:])
                        + PosDotDef[iNode,:]
                        + np.dot(CaB, np.dot(
                        Skew(Omega_B_B), Section[jSection,:])))
            
            if (ctrlSurf != None and 
                jSection > ctrlSurf.iMin and jSection <= ctrlSurf.iMax and
                iNode >= ctrlSurf.jMin and iNode <= ctrlSurf.jMax):
                # Apply changes to Zeta and ZetaDot in a-frame due to control
                # surface movement.
                
                # Check if control surface indices are within range of grid
                assert (ctrlSurf.iMin >= 0), 'CtrlSurf iMin less then zero'
                assert (ctrlSurf.iMax < Section.shape[0]), ('CtrlSurf iMax '
                        + 'greater than section iMax')
                assert (ctrlSurf.jMin >= 0), 'CtrlSurf jMin less then zero'
                assert (ctrlSurf.jMax < PosDefor.shape[0]), ('CtrlSurf jMax '
                        + 'greater than section jMax')
                
                # Determine hinge point
                hingePoint = Section[ctrlSurf.iMin,:]
                
                # Use a CRV to define rotation in sectional frame
                hingeRot = np.array([ctrlSurf.beta, 0.0, 0.0])
                hingeRotDot = np.array([ctrlSurf.betaDot, 0.0, 0.0])
                
                # Find lever arm from hinge point
                leverArm = Section[jSection,:] - hingePoint
                
                # Deformed position of node in B-frame
                CBBnew = Psi2TransMat(hingeRot)
                newSectionPoint = hingePoint + np.dot(CBBnew,leverArm)
                
                # Overwrite corresponding element in Aerogrid
                AeroGrid[jSection,iNode,:] = (PosDefor[iNode,:]
                                              + np.dot(CaB,newSectionPoint))
                
                # Overwrite corresponding element in AeroVels
                # There is an extra velocity contribution due to the rotation 
                # of the hinge, with reference frame Bnew. Hence, 
                # CBBnew * ( Omega_Bnew_Bnew X Point__Bnew), which is the
                # velocity at a point on the flap due to the rotation
                # of the hinge projected in the B-frame. is added. 
                AeroVels[jSection,iNode,:] = (VelA_A
                        + np.dot(Skew(OmegaA_A),PosDefor[iNode,:])
                        + PosDotDef[iNode,:]
                        + np.dot(CaB, 
                                 np.dot(Skew(Omega_B_B), newSectionPoint)
                                 + np.dot(CBBnew,
                                          np.dot(Skew(hingeRotDot),
                                                 leverArm))))
                
        #END for jSection
    #END for iNode
    
    if ( (OriginA_G != None) and (PsiA_G != None) ):
        # Get transformation from a-frame to earth frame.
        CaG = Psi2TransMat(PsiA_G)
        CGa = CaG.T
        
        # Add the origin to grids in earth frame and transform velocities.
        for iNode in range(PosDefor.shape[0]):
            for jSection in range(Section.shape[0]):
                AeroGrid[jSection,iNode,:] = OriginA_G + \
                                             np.dot(
                                             CGa, AeroGrid[jSection,iNode,:])
                                             
                AeroVels[jSection,iNode,:] = np.dot(
                                             CGa, AeroVels[jSection,iNode,:])
Example #9
0
     # Initialize PosDefor, PsiDefor
     PosDefor = np.zeros((N+1,3),dtype=ct.c_double, order='F')
     PosDeforElem = np.zeros((NumElems,3,3),dtype=ct.c_double, order='F')
     PsiDefor = np.zeros((NumElems,3,3),dtype=ct.c_double, order='F')
     
     data = np.loadtxt(refFile, skiprows=2)
     i0=0
     for iElem in range(NumElems):
         for i in range(numNodesElem):
             PosDeforElem[iElem,i,:] = data[i0,2:5]
             PsiDefor[iElem,i,:] = data[i0,5:8]
             i0+=1
     
     # extract nodal information (PosDefor)
     for iNode in range(N+1):
         iElem, iiElem = iNode2iElem(iNode, N+1, numNodesElem)
         PosDefor[iNode,:] = PosDeforElem[iElem,iiElem,:]
         
     # get reference circulation strengths
     refFile = Settings.OutputDir + 'M' + str(M) + 'N' + str(N) + '_V25_alpha' + str(int(alpha*180.0/np.pi)) + '_Gamma0'
     myDict = loadmat(refFile)
     gam0 = myDict['Gamma0']
     
     eta0 = (PosDefor, PsiDefor, gam0)
 else:
     eta0 = None
     
 # Generate a history of beam DoF motions (in A-frame)
 if beamDOFmotion:
     delEtaHisty = np.zeros((12*N,len(Time)))
     PosDefHist=np.zeros((N+1,3,len(Time)),dtype=ct.c_double, order='F')
Example #10
0
def localFstifz(PosDef, PsiDef,
                   PosIni, PsiIni,
                   XBELEM, NodeList,
                   SO3 = False):
    """@brief Approximate element stiffness force
    
    @param PosDef Deformed nodal coordinates.
    @param PsiDef Deformed nodal rotation vectors.
    @param PosIni Initial (undeformed) nodal coordinates.
    @param PsiIni Initial (undeformed) nodal rotation vectors.
    @param XBELEM Xbeam element derived type containing element data.
    @param NodeList List of node numbers for strain approximation at adjacent
            midpoint in the direction of increasing node index,
            starts from zero:
            0---x---1---x---2---x---3-- ... --(NumNodes-1)
            Strains are calculated at the x to the right of selected nodes.
    @param SO3 Flag for use of the SO(3) manifold in CRV interpolation.
    
    @details Assumes that all nodes are either two- or three- noded. 
    @warning Untested.
    """
    
    
    from PyBeam.Utils.BeamLib import Cbeam3_fstifz
    
    Fstiff = np.zeros((len(NodeList),6))
    NumNodes = PosDef.shape[0]-1
    NumNodesElem = XBELEM.NumNodes[0]
    iOut = 0 # Output index
    for iNode in NodeList:
        if iNode == NumNodes or iNode == -1:
            raise ValueError("Midpoint strain requested beyond final node.")
        
        iElem, iiElem = iNode2iElem(iNode, NumNodes, NumNodesElem)
        elemK = XBELEM.Stiff[iElem*6:(iElem+1)*6,:]
        
        if NumNodesElem == 2:
            if SO3 == True:
                # Consistent calculation of midpoint strains using SO(3) manifold.
                raise NotImplementedError("SO(3) manifold strains.")
            else:
                # Using fortran routines
                R0 = np.zeros((2,6))
                R0[0,:3] = PosIni[iNode,:]
                R0[0,3:] = PsiIni[iElem,iiElem,:]
                R0[1,:3] = PosIni[iNode+1,:]
                R0[1,3:] = PsiIni[iElem,iiElem+1,:]
                
                Ri = np.zeros((2,6))
                Ri[0,:3] = PosDef[iNode,:]
                Ri[0,3:] = PsiDef[iElem,iiElem,:]
                Ri[1,:3] = PosDef[iNode+1,:]
                Ri[1,3:] = PsiDef[iElem,iiElem+1,:]
            
                # Midpoint
                z = 0.0
                
                fstifz = Cbeam3_fstifz(R0, Ri, elemK, z)
            # END if SO3            
            
        elif NumNodesElem == 3:
            if SO3 == True:
                raise NotImplementedError("Only available for 2-noded just now.")
            else:
                # Using fortran routines
                R0 = np.zeros((3,6))
                R0[0,:3] = PosIni[2*iElem,:]
                R0[1,:3] = PosIni[2*iElem+2,:]
                R0[2,:3] = PosIni[2*iElem+1,:]
                R0[:,3:] = PsiIni[iElem]
                
                Ri = np.zeros((3,6))
                Ri[0,:3] = PosDef[2*iElem,:]
                Ri[1,:3] = PosDef[2*iElem+2,:]
                Ri[2,:3] = PosDef[2*iElem+1,:]
                Ri[:,3:] = PsiDef[iElem]
                
                if iiElem == 0:
                    z = -0.5 # mid-point adjacent to node iNode
                elif iiElem == 1:
                    z = 0.5 # mid-point adjacent to node iNode
                elif iiElem == 2:
                    raise ValueError("iiElem only 0, 1 for adjacent midpoint" +
                                     "calculation.")
                else:
                    raise ValueError("iiElem can only take 0, 1 or 2 for " +
                                     "3-noded elements.")
                
                #----------------------- sm: working only for moments.
                fstifz = Cbeam3_fstifz(R0, Ri, elemK, z)
                
                # link top function
                #cbeam3_fstif = BeamLib.__lib_cbeam3_MOD_cbeam3_fstif
                #
                # prepare I/O
                #ctNNE = ct.c_int(NumNodesElem)
                #ctR0 = np.zeros((,),ct.c_double,'F')
                #ctRi
                #ctKelem
                #ctQstiff = np.zeros( () )
                
                # --------------------- sm end
                
            # END if SO(3)
        else:
            raise ValueError("Only 2- or 3-noded elements are supported.")
        
        Fstiff[iOut,:] = fstifz
        
        iOut += 1
    # END for iElem
    return Fstiff