Exemplo n.º 1
0
 def test_dofset_reset(self):
     dof = DofSet()
     self.assertTrue(dof.count() == 0)
     dof.reset(True)
     self.assertTrue(dof.count() == 6)
     dof.reset()
     self.assertTrue(dof.count() == 0)
Exemplo n.º 2
0
 def test_dofset_reset(self):
     dof = DofSet()
     self.assertTrue(dof.count() == 0)
     dof.reset(True)
     self.assertTrue(dof.count() == 6)
     dof.reset()
     self.assertTrue(dof.count() == 0)
Exemplo n.º 3
0
    def __init__(self, n1, n2, material=None, properties=None):
        BaseBeam.__init__(self)

        self.nodeCount = 2
        self.name = 'Structural 3D Truss'

        self.dofSet = DofSet(Dx=True, Dy=True, Dz=True)

        self.nodes = (n1, n2)
        self.material = material
        self.loads = List()

        if properties is None:
            properties = Properties()
        self.properties = properties
Exemplo n.º 4
0
 def test_dofset_inplace(self):
     dof1 = DofSet(Dx=True,Dy=True,Dz=True)
     dof2 = DofSet(Dx=True,Dy=True,Dz=True,Rx=True,Ry=True,Rz=True)
     dof1 &= dof2
     self.assertTrue(dof1.count() == 3)
     self.assertTrue(dof1.is3DSolid())
     self.assertTrue(not dof1.is3DShell())
     self.assertTrue(dof1.elementDimension() == 3)
     
     dof1 = DofSet(Dx=True,Dy=True,Dz=True)
     dof2 = DofSet(Dx=True,Dy=True,Dz=True,Rx=True,Ry=True,Rz=True)
     dof1 |= dof2
     self.assertTrue(dof1.count() == 6)
     self.assertTrue(not dof1.is3DSolid())
     self.assertTrue(dof1.is3DShell())
     self.assertTrue(dof1.elementDimension() == 3)
Exemplo n.º 5
0
 def test_dofset_2d(self):
     dof1 = DofSet(Dx=True,Dy=True,Dz=False)
     self.assertTrue(dof1.count() == 2)
     self.assertTrue(not dof1.is3DSolid())
     self.assertTrue(not dof1.is3DShell())
     self.assertTrue(dof1.elementDimension() == 2)
     
     dof2 = DofSet(Dx=True,Dy=True,Dz=True,Rx=True,Ry=True,Rz=True)
     
     dofa = dof1 & dof2
     self.assertTrue(dofa.count() == 2)
     self.assertTrue(not dofa.is3DSolid())
     self.assertTrue(not dofa.is3DShell())
     self.assertTrue(dofa.elementDimension() == 2)
     
     dofo = dof1 | dof2
     self.assertTrue(dofo.count() == 6)
     self.assertTrue(not dofo.is3DSolid())
     self.assertTrue(dofo.is3DShell())
     self.assertTrue(dofo.elementDimension() == 3)
Exemplo n.º 6
0
 def __init__(self, n1, n2, material = None, properties = None):
     BaseBeam.__init__(self)
     
     self.nodeCount = 2
     self.name = 'Structural 3D Truss'
     
     self.dofSet = DofSet(Dx=True, Dy=True, Dz=True)
     
     self.nodes = (n1,n2)
     self.material = material
     self.loads = List()
     
     if properties is None:
         properties = Properties()
     self.properties = properties
Exemplo n.º 7
0
    def test_dofset_2d(self):
        dof1 = DofSet(Dx=True, Dy=True, Dz=False)
        self.assertTrue(dof1.count() == 2)
        self.assertTrue(not dof1.is3DSolid())
        self.assertTrue(not dof1.is3DShell())
        self.assertTrue(dof1.elementDimension() == 2)

        dof2 = DofSet(Dx=True, Dy=True, Dz=True, Rx=True, Ry=True, Rz=True)

        dofa = dof1 & dof2
        self.assertTrue(dofa.count() == 2)
        self.assertTrue(not dofa.is3DSolid())
        self.assertTrue(not dofa.is3DShell())
        self.assertTrue(dofa.elementDimension() == 2)

        dofo = dof1 | dof2
        self.assertTrue(dofo.count() == 6)
        self.assertTrue(not dofo.is3DSolid())
        self.assertTrue(dofo.is3DShell())
        self.assertTrue(dofo.elementDimension() == 3)
Exemplo n.º 8
0
 def test_dofset_dofPos(self):
     dof = DofSet(Dx=True,Dy=True,Dz=True)
     self.assertTrue(dof.dofPos(3) == 2)
     
     dof = DofSet(Dx=False,Dy=False,Dz=False,Rx=True,Ry=True,Rz=True)
     self.assertTrue(dof.dofPos(3) == 5)
Exemplo n.º 9
0
    def test_dofset_dofPos(self):
        dof = DofSet(Dx=True, Dy=True, Dz=True)
        self.assertTrue(dof.dofPos(3) == 2)

        dof = DofSet(Dx=False, Dy=False, Dz=False, Rx=True, Ry=True, Rz=True)
        self.assertTrue(dof.dofPos(3) == 5)
Exemplo n.º 10
0
    def test_dofset_inplace(self):
        dof1 = DofSet(Dx=True, Dy=True, Dz=True)
        dof2 = DofSet(Dx=True, Dy=True, Dz=True, Rx=True, Ry=True, Rz=True)
        dof1 &= dof2
        self.assertTrue(dof1.count() == 3)
        self.assertTrue(dof1.is3DSolid())
        self.assertTrue(not dof1.is3DShell())
        self.assertTrue(dof1.elementDimension() == 3)

        dof1 = DofSet(Dx=True, Dy=True, Dz=True)
        dof2 = DofSet(Dx=True, Dy=True, Dz=True, Rx=True, Ry=True, Rz=True)
        dof1 |= dof2
        self.assertTrue(dof1.count() == 6)
        self.assertTrue(not dof1.is3DSolid())
        self.assertTrue(dof1.is3DShell())
        self.assertTrue(dof1.elementDimension() == 3)
Exemplo n.º 11
0
class Beam(BaseBeam):
    '''
    2-Node Structural 3D Beam
    '''
    def __init__(self, n1, n2, material = None, properties = None):
        BaseBeam.__init__(self)
        
        self.nodeCount = 2
        self.name = 'Structural 3D Beam'
        
        self.dofSet = DofSet()
        self.dofSet.reset(True)
        
        self.nodes = (n1,n2)
        self.material = material
        self.loads = List()
        
        if properties is None:
            properties = Properties()
        self.properties = properties
    
    def validate(self):
        '''
        Validate beam
        '''
        if self.length() < TINY:
            raise FEError('Beam length is to small')
        
        # check material
        for name in ('E', 'G', 'nu'):
            if name not in self.material:
                raise FEError('Material definition not complete')
            
            if self.material[name] < TINY:
                raise FEError("Material parameter '%s' not correct" % name)
        
        # check profile data
        for name in ('Area', 'Iyy', 'Izz'):
            if name not in self.properties:
                raise FEError('Properties definition not complete')
            
            if self.properties[name] < TINY:
                raise FEError("Properties parameter '%s' not correct" % name)
    
    def calcTe(self):
        '''
        Eval element tranformation matrix
        '''
        # Eval coordinate transformation matrix
        Tl = self.calcT()
        
        # Build the final transformation matrix - a 12x12 matrix
        T = np.zeros((12,12), dtype=float)
        
        for i in range(4):
            for j in range(3):
                for k in range(3):
                    T[j+3*i,k+3*i] = Tl[j,k]
        
        return T
        
    def calcM(self, lumped = False):
        '''
        Eval elemenent consistent mass matrix in global coordinates
        '''
        mat = self.material
        prop = self.properties
        
        L = self.length()
        LL = L*L
        rho = mat["Density"]
        Ax, Iy, Iz = prop["Area"], prop["Iyy"], prop["Izz"]
        
        J = prop.get("Ixx", 0.)
        if J == 0.:
            # Simplification only valid for circular sections
            J = Iy + Iz
            
        M = np.zeros((12,12), dtype=float)
        
        t  =  rho*Ax*L	
        ry =  rho*Iy
        rz =  rho*Iz
        po =  rho*J*L
        
        if lumped:
            t *= .5
            ry *= .5
            rz *= .5
            po *= .5
            
            M[0][0] = M[1][1] = M[2][2] = M[6][6] = M[7][7] = M[8][8] = t

            M[3][3] = M[9][9] = po + ry + rz
            M[4][4] = M[10][10] = po + ry + rz
            M[5][5] = M[11][11] = po + ry + rz

            M[3][4] = M[4][3] = M[9][10] = M[10][9] = po + ry + rz
            M[3][5] = M[5][3] = M[9][11] = M[11][9] = po + ry + rz
            M[4][5] = M[5][4] = M[10][11] = M[11][10] = po + ry + rz

        else:
            M[0][0]  = M[6][6]   = t/3.
            M[1][1]  = M[7][7]   = 13.*t/35. + 6.*rz/(5.*L)
            M[2][2]  = M[8][8]   = 13.*t/35. + 6.*ry/(5.*L)
            M[3][3]  = M[9][9] = po/3.
            M[4][4]  = M[10][10] = t*LL/105. + 2.*L*ry/15.
            M[5][5]  = M[11][11] = t*LL/105. + 2.*L*rz/15.

            M[4][2]  = M[2][4]   = -11.*t*L/210. - ry/10.
            M[5][1]  = M[1][5]   =  11.*t*L/210. + rz/10.
            M[6][0]  = M[0][6]   =  t/6.

            M[7][5]  = M[5][7]   =  13.*t*L/420. - rz/10.
            M[8][4]  = M[4][8]   = -13.*t*L/420. + ry/10.
            M[9][3] = M[3][9]  =  po/6. 
            M[10][2] = M[2][10]  =  13.*t*L/420. - ry/10.
            M[11][1] = M[1][11]  = -13.*t*L/420. + rz/10.

            M[10][8] = M[8][10]  =  11.*t*L/210. + ry/10.
            M[11][7] = M[7][11]  = -11.*t*L/210. - rz/10.

            M[7][1]  = M[1][7]   =  9.*t/70. - 6.*rz/(5.*L)
            M[8][2]  = M[2][8]   =  9.*t/70. - 6.*ry/(5.*L)
            M[10][4] = M[4][10]  = -LL*t/140. - ry*L/30.
            M[11][5] = M[5][11]  = -LL*t/140. - rz*L/30.
        
        T = self.calcTe()
        
        # Evaluate Transformation M = T^T * M * T
        return np.dot(T.T,np.dot(M,T))
        
    def calcKe(self):
        '''
        Eval element stiffness matrix in local coordinates.
        
        Includes transverse shear deformation. If no shear deflection
        constant (ShearZ and ShearY) is set, the displacement considers
        bending deformation only. 
        
        Shear deflection constants for other cross-sections can be found in
        structural handbooks.
        '''
        Ke = np.zeros((12,12), dtype=float)
        
        mat = self.material
        prop = self.properties
        
        L = self.length()
        L2 = L*L
        L3 = L2*L
        
        E, G = mat["E"], mat["G"]
        Ax, Iy, Iz = prop["Area"], prop["Iyy"], prop["Izz"]
        
        J = prop.get("Ixx", 0.)
        if J == 0.:
            # Simplification only valid for circular sections
            J = Iy + Iz
            
        Asy = prop.get("ShearY", 0.)
        Asz = prop.get("ShearZ", 0.)
        
        if Asy != 0. and Asz != 0.:
            Ksy = 12.*E*Iz / (G*Asy*L2)
            Ksz = 12.*E*Iy / (G*Asz*L2)
        else:
            Ksy = Ksz = 0.
        
        Ke[0,0]  = Ke[6,6]   = E*Ax / L
        Ke[1,1]  = Ke[7,7]   = 12.*E*Iz / ( L3*(1.+Ksy) )
        Ke[2,2]  = Ke[8,8]   = 12.*E*Iy / ( L3*(1.+Ksz) )
        Ke[3,3]  = Ke[9,9] = G*J / L
        Ke[4,4]  = Ke[10,10] = (4.+Ksz)*E*Iy / ( L*(1.+Ksz) )
        Ke[5,5]  = Ke[11,11] = (4.+Ksy)*E*Iz / ( L*(1.+Ksy) )

        Ke[4,2]  = Ke[2,4]   = -6.*E*Iy / ( L2*(1.+Ksz) )
        Ke[5,1]  = Ke[1,5]   =  6.*E*Iz / ( L2*(1.+Ksy) )
        Ke[6,0]  = Ke[0,6]   = -Ke[0,0]

        Ke[11,7] = Ke[7,11]  =  Ke[7,5] = Ke[5,7] = -Ke[5,1]
        Ke[10,8] = Ke[8,10]  =  Ke[8,4] = Ke[4,8] = -Ke[4,2]
        Ke[9,3] = Ke[3,9]  = -Ke[3,3]
        Ke[10,2] = Ke[2,10]  =  Ke[4,2]
        Ke[11,1] = Ke[1,11]  =  Ke[5,1]

        Ke[7,1]  = Ke[1,7]   = -Ke[1,1]
        Ke[8,2]  = Ke[2,8]   = -Ke[2,2]
        Ke[10,4] = Ke[4,10]  = (2.-Ksz)*E*Iy / ( L*(1.+Ksz) )
        Ke[11,5] = Ke[5,11]  = (2.-Ksy)*E*Iz / ( L*(1.+Ksy) )
        
        return Ke
        
    def calcK(self):
        '''
        Eval element stiffness matrix in global coordinates.
        '''
        K = self.calcKe()
        T = self.calcTe()
        
        # Evaluate Transformation K = T^T * K * T
        return np.dot(T.T,np.dot(K,T))
    
    def calcStress(self):
        raise NotImplementedError()
        
    def calcNodalForces(self, res = None):
        '''
        Calculate corresponding global forces at nodes from
        line loads
        '''
        res = self.calcLocalNodalForces(res)
        
        Tl = self.calcT()
        
        # Build the final transformation matrix - a 12x12 matrix
        T = np.zeros((12,12), dtype=float)
        
        for i in range(4):
            for j in range(3):
                for k in range(3):
                    T[j+3*i,k+3*i] = Tl[j,k]
        
        res[:] = np.dot(T.T, res)
        
        return res
    
    def calcLocalNodalForces(self, res = None):
        '''
        Calculate corresponding end forces at nodes from
        line loads in local directions
        '''
        if res is None:
            res = np.zeros((self.dofSet.count() * self.nodeCount,), dtype = float)
        
        L = self.length()
        LL = L * L
        
        load = self.calcLocalLoad()
        load *= L
        
        # Nx
        res[0] += .5*load[0]
        res[6] += .5*load[0]
        # Vy
        res[1] += .5*load[1]
        res[7] += .5*load[1]
        # VZ
        res[2] += .5*load[2]
        res[8] += .5*load[2]
        # My
        res[4] -= load[2] * L / 12.
        res[10] += load[2] * L / 12.
        # Mz
        res[5] -= load[1] * L / 12.
        res[11] += load[1] * L / 12.
        
        return res
    
    def calcSectionForces(self, dx = 1e9, sections=None):
        # find number of divisions
        try:
            nx = int(self.length()/dx)
            nx = min(max(1, nx), 100)
        except ZeroDivisionError:
            nx = 1
            dx = self.length()

        if sections is not None:
            nx = sections - 1
            dx = self.length() / (sections - 1)

        res = np.zeros((nx + 1, 7), dtype=float)
        L = self.length()
        
        # Eval local coordinate transformation matrix
        Tl = self.calcT()
        
        # Build the final transformation matrix - a 12x12 matrix
        T = np.zeros((12,12), dtype=float)
        
        for i in range(4):
            for j in range(3):
                for k in range(3):
                    T[j+3*i,k+3*i] = Tl[j,k]
                    
        # nodes flipped?
        n1, n2 = self.nodes
        if n1.cz > n2.cz:
            fac = -1.
        else:
            fac = 1.
        
        # Transform displacements and rotations from global to local coordinates
        d = np.zeros((12,), dtype=float)
        d[:6] = n1.results
        d[6:] = n2.results
        
        if not n1.coordSys is None:
            Tcs = n1.coordSys
            d[:3] = np.dot(Tcs.T, d[:3])
            d[3:6] = np.dot(Tcs.T, d[3:6])
        
        if not n2.coordSys is None:
            Tcs = n2.coordSys
            d[6:9] = np.dot(Tcs.T, d[6:9])
            d[9:12] = np.dot(Tcs.T, d[9:12])
            
        u = np.dot(T, d)
            
        # Stiffness matrix in local coordinates
        Ke = self.calcKe()
        
        # Calculate forces in local directions
        forces = np.dot(Ke, u)
            
        # Correct forces from eqivalent forces line loads
        iforces = self.calcLocalNodalForces()
        forces -= iforces
        
        res[0,0] = 0.
        res[0,1:] = forces[:6]
        
        res[nx,0] = 1.
        res[nx,1:] = -forces[6:]
        
        if nx > 1:
            #  accumulate interior span loads
            load = self.calcLocalLoad()

            _dx = dx
            x = _dx
            for i in range(nx):
                res[i + 1,0] = x/L                       # Position
                res[i + 1,1] = res[i, 1] + load[0]*_dx   # Axial force, Nx
                res[i + 1,2] = res[i, 2] + load[1]*_dx   # Sheare force Vy
                res[i + 1,3] = res[i, 3] + load[2]*_dx   # Sheare force Vz
                res[i + 1,4] = res[i, 4]                 # Torsion, Txx
                
                # correct last step if needed
                if (i + 1)*_dx > L:
                    _dx = L - i*_dx
                
                x += _dx
                
            # trapezoidal integration of shear force for bending momemnt
            _dx = dx

            for i in range(nx):
                res[i + 1,5] = res[i,5] + .5*(res[i + 1, 3] + res[i, 3])*_dx # Myy
                res[i + 1,6] = res[i,6] + fac*.5*(res[i + 1, 2] + res[i, 2])*_dx # Mzz

                # correct last step if needed
                if (i + 1)*_dx > L:
                    _dx = L - i*_dx
            
        return res
Exemplo n.º 12
0
class Truss(BaseBeam):
    '''
    2-Node Structural 3D Truss
    '''
    def __init__(self, n1, n2, material = None, properties = None):
        BaseBeam.__init__(self)
        
        self.nodeCount = 2
        self.name = 'Structural 3D Truss'
        
        self.dofSet = DofSet(Dx=True, Dy=True, Dz=True)
        
        self.nodes = (n1,n2)
        self.material = material
        self.loads = List()
        
        if properties is None:
            properties = Properties()
        self.properties = properties
    
    def __str__(self):
        return '()'
    
    def __repr__(self):
        return '%s%s' % (self.__class__.__name__, str(self))
    
    def validate(self):
        '''
        Validate truss
        '''
        if self.length() < TINY:
            raise FEError('Truss length is to small')
        
        # check material
        for name in ('E',):
            if name not in self.material:
                raise FEError('Material definition not complete')
            
            if self.material[name] < TINY:
                raise FEError("Material parameter '%s' not correct" % name)
        
        # check profile data
        for name in ('Area',):
            if name not in self.properties:
                raise FEError('Properties definition not complete')
            
            if self.properties[name] < TINY:
                raise FEError("Properties parameter '%s' not correct" % name)
    
    def calcLocalNodalForces(self, res = None):
        '''
        Calculate corresponding end forces at nodes from
        line loads in local directions
        '''
        if res is None:
            res = np.zeros((self.dofSet.count() * self.nodeCount,), dtype = float)
        
        load = self.calcLocalLoad()
        
        # Nx
        res[0] += .5*load[0]
        res[3] += .5*load[0]
        # Vy
        res[1] += .5*load[1]
        res[4] += .5*load[1]
        # VZ
        res[2] += .5*load[2]
        res[5] += .5*load[2]
        
        return res
        
    def calcNodalForces(self, res = None):
        '''
        Calculate corresponding global forces at nodes from
        line loads
        '''
        # calculate local forces
        res = self.calcLocalNodalForces(res)
        
        # Transforamtion matrix
        T = self.calcT()
        
        res[0:3] = np.dot(T.T, res[0:3])
        res[3:6] = np.dot(T.T, res[3:6])
        
        return res
    
    def calcM(self, lumped = False):
        '''
        Eval elemenent consistent mass matrix in global coordinates
        '''
        mat = self.material
        prop = self.properties
        
        Ax, rho = prop["Area"], mat['Density']
        n1, n2 = self.nodes
        L = self.length()
        
        # Eval direction cosines in order to transform stiffness matrix
        # from local coords (link direction) to global coordinates
        cxx = ( n2.cx - n1.cx ) / L
        cxy = ( n2.cy - n1.cy ) / L
        cxz = ( n2.cz - n1.cz ) / L
        
        ll = sqrt(cxx**2 + cxy**2)
        if ll != 0.:
            cyx = -cxy/ll 
            cyy = cxx/ll
            cyz = 0.
        else:
            cyx = 0.
            cyy = 1.
            cyz = 0.
        
        czx = cxy*cyz - cxz*cyy;
        czy = -cxx*cyz + cxz*cyx;
        czz = cxx*cyy - cxy*cyx;
        
        # Transforamtion matrix
        T = np.zeros((6,6), dtype=float)
        
        T[0,0] = cxx; T[0,1] = cxy; T[0,2] = cxz
        T[1,0] = cyx; T[1,1] = cyy; T[1,2] = cyz
        T[2,0] = czx; T[2,1] = czy; T[2,2] = czz

        T[3,3] = cxx; T[3,4] = cxy; T[3,5] = cxz
        T[4,3] = cyx; T[4,4] = cyy; T[4,5] = cyz
        T[5,3] = czx; T[5,4] = czy; T[5,5] = czz
        
        # Mass matrix
        M = np.zeros((6,6), dtype=float)
        
        if lumped:
            M[0,0] = 1.; M[5,5] =  1.
            M *= rho * Ax * L / 2.
        else:
            M[0,0] = 2.; M[1,1] =  2.; M[2,2] =  2.
            M[3,3] = 2.; M[4,4] =  2.; M[5,5] =  2.
            M[3,0] = 1.; M[4,1] =  1.; M[5,2] =  1.
            M[0,3] = 1.; M[1,4] =  1.; M[2,5] =  1.
            M *= rho * Ax * L / 6.
        
        # Evaluate Transformation M = T^T * M * T
        return np.dot(T.T,np.dot(M,T))
  
    def calcKe(self):
        '''
        Eval element stiffness matrix in local coordinates
        '''
        mat = self.material
        prop = self.properties
        
        L = self.length()
        Ax, E = prop["Area"], mat["E"]
        
        # Stiffness matrix
        Ke = np.zeros((2,2), dtype=float)
        
        AxEoverL = Ax*E/L
        Ke[0,0] = AxEoverL; Ke[0,1] = -AxEoverL
        Ke[1,0] =-AxEoverL; Ke[1,1] =  AxEoverL
        
        return Ke
    
    def calcK(self):
        '''
        Eval element stiffness matrix in global coordinates.
        '''
        L = self.length()
        n1, n2 = self.nodes
        
        # Transforamtion matrix
        T = np.zeros((2,6), dtype=float)
        
        # Eval direction cosines in order to transform stiffness matrix
        # from local coords (link direction) to global coordinates
        cx = ( n2.cx - n1.cx ) / L
        cy = ( n2.cy - n1.cy ) / L
        cz = ( n2.cz - n1.cz ) / L
        
        T[0,0] = cx; T[0,1] = cy; T[0,2] = cz
        T[1,3] = cx; T[1,4] = cy; T[1,5] = cz
        
        # Stiffness matrix
        K = self.calcKe()
        
        # Evaluate Transformation K = T^T * K * T
        return np.dot(T.T,np.dot(K,T))
    
    def calcStress(self):
        raise NotImplementedError()
        
    def calcSectionForces(self, dx = 1e9):
        '''
        Eval beam section forces in nodes
        '''
        res = np.zeros((2,7), dtype=float)
            
        prop = self.properties
        mat = self.material
        n1, n2 = self.nodes
        
        L = self.length()
        E = mat['E']
        G = mat['G']
        Ax = prop['Area']
        
        # Eval coordinate transformation matrix
        T = self.calcT()
        
        # Transform displacements from global to local coordinates
        u1 = np.dot(T, n1.results[:3])
        u2 = np.dot(T, n2.results[:3])
        
        # Axial force, Nx
        res[0,0] = 0.
        res[0,1] = (-Ax*E/L)*(u2[0] - u1[0])
        
        res[1,0] = 1.
        res[1,1] = -res[0,1]
                    
        return res
Exemplo n.º 13
0
class Beam(BaseBeam):
    '''
    2-Node Structural 3D Beam
    '''
    def __init__(self, n1, n2, material=None, properties=None):
        BaseBeam.__init__(self)

        self.nodeCount = 2
        self.name = 'Structural 3D Beam'

        self.dofSet = DofSet()
        self.dofSet.reset(True)

        self.nodes = (n1, n2)
        self.material = material
        self.loads = List()

        if properties is None:
            properties = Properties()
        self.properties = properties

    def validate(self):
        '''
        Validate beam
        '''
        if self.length() < TINY:
            raise FEError('Beam length is to small')

        # check material
        for name in ('E', 'G', 'nu'):
            if name not in self.material:
                raise FEError('Material definition not complete')

            if self.material[name] < TINY:
                raise FEError("Material parameter '%s' not correct" % name)

        # check profile data
        for name in ('Area', 'Iyy', 'Izz'):
            if name not in self.properties:
                raise FEError('Properties definition not complete')

            if self.properties[name] < TINY:
                raise FEError("Properties parameter '%s' not correct" % name)

    def calcTe(self):
        '''
        Eval element tranformation matrix
        '''
        # Eval coordinate transformation matrix
        Tl = self.calcT()

        # Build the final transformation matrix - a 12x12 matrix
        T = np.zeros((12, 12), dtype=float)

        for i in range(4):
            for j in range(3):
                for k in range(3):
                    T[j + 3 * i, k + 3 * i] = Tl[j, k]

        return T

    def calcM(self, lumped=False):
        '''
        Eval elemenent consistent mass matrix in global coordinates
        '''
        mat = self.material
        prop = self.properties

        L = self.length()
        LL = L * L
        rho = mat["Density"]
        Ax, Iy, Iz = prop["Area"], prop["Iyy"], prop["Izz"]

        J = prop.get("Ixx", 0.)
        if J == 0.:
            # Simplification only valid for circular sections
            J = Iy + Iz

        M = np.zeros((12, 12), dtype=float)

        t = rho * Ax * L
        ry = rho * Iy
        rz = rho * Iz
        po = rho * J * L

        if lumped:
            t *= .5
            ry *= .5
            rz *= .5
            po *= .5

            M[0][0] = M[1][1] = M[2][2] = M[6][6] = M[7][7] = M[8][8] = t

            M[3][3] = M[9][9] = po + ry + rz
            M[4][4] = M[10][10] = po + ry + rz
            M[5][5] = M[11][11] = po + ry + rz

            M[3][4] = M[4][3] = M[9][10] = M[10][9] = po + ry + rz
            M[3][5] = M[5][3] = M[9][11] = M[11][9] = po + ry + rz
            M[4][5] = M[5][4] = M[10][11] = M[11][10] = po + ry + rz

        else:
            M[0][0] = M[6][6] = t / 3.
            M[1][1] = M[7][7] = 13. * t / 35. + 6. * rz / (5. * L)
            M[2][2] = M[8][8] = 13. * t / 35. + 6. * ry / (5. * L)
            M[3][3] = M[9][9] = po / 3.
            M[4][4] = M[10][10] = t * LL / 105. + 2. * L * ry / 15.
            M[5][5] = M[11][11] = t * LL / 105. + 2. * L * rz / 15.

            M[4][2] = M[2][4] = -11. * t * L / 210. - ry / 10.
            M[5][1] = M[1][5] = 11. * t * L / 210. + rz / 10.
            M[6][0] = M[0][6] = t / 6.

            M[7][5] = M[5][7] = 13. * t * L / 420. - rz / 10.
            M[8][4] = M[4][8] = -13. * t * L / 420. + ry / 10.
            M[9][3] = M[3][9] = po / 6.
            M[10][2] = M[2][10] = 13. * t * L / 420. - ry / 10.
            M[11][1] = M[1][11] = -13. * t * L / 420. + rz / 10.

            M[10][8] = M[8][10] = 11. * t * L / 210. + ry / 10.
            M[11][7] = M[7][11] = -11. * t * L / 210. - rz / 10.

            M[7][1] = M[1][7] = 9. * t / 70. - 6. * rz / (5. * L)
            M[8][2] = M[2][8] = 9. * t / 70. - 6. * ry / (5. * L)
            M[10][4] = M[4][10] = -LL * t / 140. - ry * L / 30.
            M[11][5] = M[5][11] = -LL * t / 140. - rz * L / 30.

        T = self.calcTe()

        # Evaluate Transformation M = T^T * M * T
        return np.dot(T.T, np.dot(M, T))

    def calcKe(self):
        '''
        Eval element stiffness matrix in local coordinates.
        
        Includes transverse shear deformation. If no shear deflection
        constant (ShearZ and ShearY) is set, the displacement considers
        bending deformation only. 
        
        Shear deflection constants for other cross-sections can be found in
        structural handbooks.
        '''
        Ke = np.zeros((12, 12), dtype=float)

        mat = self.material
        prop = self.properties

        L = self.length()
        L2 = L * L
        L3 = L2 * L

        E, G = mat["E"], mat["G"]
        Ax, Iy, Iz = prop["Area"], prop["Iyy"], prop["Izz"]

        J = prop.get("Ixx", 0.)
        if J == 0.:
            # Simplification only valid for circular sections
            J = Iy + Iz

        Asy = prop.get("ShearY", 0.)
        Asz = prop.get("ShearZ", 0.)

        if Asy != 0. and Asz != 0.:
            Ksy = 12. * E * Iz / (G * Asy * L2)
            Ksz = 12. * E * Iy / (G * Asz * L2)
        else:
            Ksy = Ksz = 0.

        Ke[0, 0] = Ke[6, 6] = E * Ax / L
        Ke[1, 1] = Ke[7, 7] = 12. * E * Iz / (L3 * (1. + Ksy))
        Ke[2, 2] = Ke[8, 8] = 12. * E * Iy / (L3 * (1. + Ksz))
        Ke[3, 3] = Ke[9, 9] = G * J / L
        Ke[4, 4] = Ke[10, 10] = (4. + Ksz) * E * Iy / (L * (1. + Ksz))
        Ke[5, 5] = Ke[11, 11] = (4. + Ksy) * E * Iz / (L * (1. + Ksy))

        Ke[4, 2] = Ke[2, 4] = -6. * E * Iy / (L2 * (1. + Ksz))
        Ke[5, 1] = Ke[1, 5] = 6. * E * Iz / (L2 * (1. + Ksy))
        Ke[6, 0] = Ke[0, 6] = -Ke[0, 0]

        Ke[11, 7] = Ke[7, 11] = Ke[7, 5] = Ke[5, 7] = -Ke[5, 1]
        Ke[10, 8] = Ke[8, 10] = Ke[8, 4] = Ke[4, 8] = -Ke[4, 2]
        Ke[9, 3] = Ke[3, 9] = -Ke[3, 3]
        Ke[10, 2] = Ke[2, 10] = Ke[4, 2]
        Ke[11, 1] = Ke[1, 11] = Ke[5, 1]

        Ke[7, 1] = Ke[1, 7] = -Ke[1, 1]
        Ke[8, 2] = Ke[2, 8] = -Ke[2, 2]
        Ke[10, 4] = Ke[4, 10] = (2. - Ksz) * E * Iy / (L * (1. + Ksz))
        Ke[11, 5] = Ke[5, 11] = (2. - Ksy) * E * Iz / (L * (1. + Ksy))

        return Ke

    def calcK(self):
        '''
        Eval element stiffness matrix in global coordinates.
        '''
        K = self.calcKe()
        T = self.calcTe()

        # Evaluate Transformation K = T^T * K * T
        return np.dot(T.T, np.dot(K, T))

    def calcStress(self):
        raise NotImplementedError()

    def calcNodalForces(self, res=None):
        '''
        Calculate corresponding global forces at nodes from
        line loads
        '''
        res = self.calcLocalNodalForces(res)

        Tl = self.calcT()

        # Build the final transformation matrix - a 12x12 matrix
        T = np.zeros((12, 12), dtype=float)

        for i in range(4):
            for j in range(3):
                for k in range(3):
                    T[j + 3 * i, k + 3 * i] = Tl[j, k]

        res[:] = np.dot(T.T, res)

        return res

    def calcLocalNodalForces(self, res=None):
        '''
        Calculate corresponding end forces at nodes from
        line loads in local directions
        '''
        if res is None:
            res = np.zeros((self.dofSet.count() * self.nodeCount, ),
                           dtype=float)

        L = self.length()
        LL = L * L

        load = self.calcLocalLoad()
        load *= L

        # Nx
        res[0] += .5 * load[0]
        res[6] += .5 * load[0]
        # Vy
        res[1] += .5 * load[1]
        res[7] += .5 * load[1]
        # VZ
        res[2] += .5 * load[2]
        res[8] += .5 * load[2]
        # My
        res[4] -= load[2] * L / 12.
        res[10] += load[2] * L / 12.
        # Mz
        res[5] -= load[1] * L / 12.
        res[11] += load[1] * L / 12.

        return res

    def calcSectionForces(self, dx=1e9):
        # find number of divisions
        try:
            nx = int(self.length() / dx)
            nx = min(max(1, nx), 100)
        except ZeroDivisionError:
            nx = 1
            dx = self.length()

        res = np.zeros((nx + 1, 7), dtype=float)
        L = self.length()

        # Eval local coordinate transformation matrix
        Tl = self.calcT()

        # Build the final transformation matrix - a 12x12 matrix
        T = np.zeros((12, 12), dtype=float)

        for i in range(4):
            for j in range(3):
                for k in range(3):
                    T[j + 3 * i, k + 3 * i] = Tl[j, k]

        # nodes flipped?
        n1, n2 = self.nodes
        if n1.cz > n2.cz:
            fac = -1.
        else:
            fac = 1.

        # Transform displacements and rotations from global to local coordinates
        d = np.zeros((12, ), dtype=float)
        d[:6] = n1.results
        d[6:] = n2.results

        if not n1.coordSys is None:
            Tcs = n1.coordSys
            d[:3] = np.dot(Tcs.T, d[:3])
            d[3:6] = np.dot(Tcs.T, d[3:6])

        if not n2.coordSys is None:
            Tcs = n2.coordSys
            d[6:9] = np.dot(Tcs.T, d[6:9])
            d[9:12] = np.dot(Tcs.T, d[9:12])

        u = np.dot(T, d)

        # Stiffness matrix in local coordinates
        Ke = self.calcKe()

        # Calculate forces in local directions
        forces = np.dot(Ke, u)

        # Correct forces from eqivalent forces line loads
        iforces = self.calcLocalNodalForces()
        forces -= iforces

        res[0, 0] = 0.
        res[0, 1:] = forces[:6]

        res[nx, 0] = 1.
        res[nx, 1:] = -forces[6:]

        if nx > 1:
            #  accumulate interior span loads
            load = self.calcLocalLoad()

            _dx = dx
            x = _dx
            for i in range(nx):
                res[i + 1, 0] = x / L  # Position
                res[i + 1, 1] = res[i, 1] + load[0] * _dx  # Axial force, Nx
                res[i + 1, 2] = res[i, 2] + load[1] * _dx  # Sheare force Vy
                res[i + 1, 3] = res[i, 3] + load[2] * _dx  # Sheare force Vz
                res[i + 1, 4] = res[i, 4]  # Torsion, Txx

                # correct last step if needed
                if (i + 1) * _dx > L:
                    _dx = L - i * _dx

                x += _dx

            # trapezoidal integration of shear force for bending momemnt
            _dx = dx
            for i in range(nx):
                res[i + 1,
                    5] = res[i,
                             5] + .5 * (res[i + 1, 3] + res[i, 3]) * _dx  # Myy
                res[i + 1, 6] = res[i, 6] + fac * .5 * (res[i + 1, 2] +
                                                        res[i, 2]) * _dx  # Mzz

                # correct last step if needed
                if (i + 1) * _dx > L:
                    _dx = L - i * _dx

        return res
Exemplo n.º 14
0
class Truss(BaseBeam):
    '''
    2-Node Structural 3D Truss
    '''
    def __init__(self, n1, n2, material=None, properties=None):
        BaseBeam.__init__(self)

        self.nodeCount = 2
        self.name = 'Structural 3D Truss'

        self.dofSet = DofSet(Dx=True, Dy=True, Dz=True)

        self.nodes = (n1, n2)
        self.material = material
        self.loads = List()

        if properties is None:
            properties = Properties()
        self.properties = properties

    def __str__(self):
        return '()'

    def __repr__(self):
        return '%s%s' % (self.__class__.__name__, str(self))

    def validate(self):
        '''
        Validate truss
        '''
        if self.length() < TINY:
            raise FEError('Truss length is to small')

        # check material
        for name in ('E', ):
            if name not in self.material:
                raise FEError('Material definition not complete')

            if self.material[name] < TINY:
                raise FEError("Material parameter '%s' not correct" % name)

        # check profile data
        for name in ('Area', ):
            if name not in self.properties:
                raise FEError('Properties definition not complete')

            if self.properties[name] < TINY:
                raise FEError("Properties parameter '%s' not correct" % name)

    def calcLocalNodalForces(self, res=None):
        '''
        Calculate corresponding end forces at nodes from
        line loads in local directions
        '''
        if res is None:
            res = np.zeros((self.dofSet.count() * self.nodeCount, ),
                           dtype=float)

        load = self.calcLocalLoad()

        # Nx
        res[0] += .5 * load[0]
        res[3] += .5 * load[0]
        # Vy
        res[1] += .5 * load[1]
        res[4] += .5 * load[1]
        # VZ
        res[2] += .5 * load[2]
        res[5] += .5 * load[2]

        return res

    def calcNodalForces(self, res=None):
        '''
        Calculate corresponding global forces at nodes from
        line loads
        '''
        # calculate local forces
        res = self.calcLocalNodalForces(res)

        # Transforamtion matrix
        T = self.calcT()

        res[0:3] = np.dot(T.T, res[0:3])
        res[3:6] = np.dot(T.T, res[3:6])

        return res

    def calcM(self, lumped=False):
        '''
        Eval elemenent consistent mass matrix in global coordinates
        '''
        mat = self.material
        prop = self.properties

        Ax, rho = prop["Area"], mat['Density']
        n1, n2 = self.nodes
        L = self.length()

        # Eval direction cosines in order to transform stiffness matrix
        # from local coords (link direction) to global coordinates
        cxx = (n2.cx - n1.cx) / L
        cxy = (n2.cy - n1.cy) / L
        cxz = (n2.cz - n1.cz) / L

        ll = sqrt(cxx**2 + cxy**2)
        if ll != 0.:
            cyx = -cxy / ll
            cyy = cxx / ll
            cyz = 0.
        else:
            cyx = 0.
            cyy = 1.
            cyz = 0.

        czx = cxy * cyz - cxz * cyy
        czy = -cxx * cyz + cxz * cyx
        czz = cxx * cyy - cxy * cyx

        # Transforamtion matrix
        T = np.zeros((6, 6), dtype=float)

        T[0, 0] = cxx
        T[0, 1] = cxy
        T[0, 2] = cxz
        T[1, 0] = cyx
        T[1, 1] = cyy
        T[1, 2] = cyz
        T[2, 0] = czx
        T[2, 1] = czy
        T[2, 2] = czz

        T[3, 3] = cxx
        T[3, 4] = cxy
        T[3, 5] = cxz
        T[4, 3] = cyx
        T[4, 4] = cyy
        T[4, 5] = cyz
        T[5, 3] = czx
        T[5, 4] = czy
        T[5, 5] = czz

        # Mass matrix
        M = np.zeros((6, 6), dtype=float)

        if lumped:
            M[0, 0] = 1.
            M[5, 5] = 1.
            M *= rho * Ax * L / 2.
        else:
            M[0, 0] = 2.
            M[1, 1] = 2.
            M[2, 2] = 2.
            M[3, 3] = 2.
            M[4, 4] = 2.
            M[5, 5] = 2.
            M[3, 0] = 1.
            M[4, 1] = 1.
            M[5, 2] = 1.
            M[0, 3] = 1.
            M[1, 4] = 1.
            M[2, 5] = 1.
            M *= rho * Ax * L / 6.

        # Evaluate Transformation M = T^T * M * T
        return np.dot(T.T, np.dot(M, T))

    def calcKe(self):
        '''
        Eval element stiffness matrix in local coordinates
        '''
        mat = self.material
        prop = self.properties

        L = self.length()
        Ax, E = prop["Area"], mat["E"]

        # Stiffness matrix
        Ke = np.zeros((2, 2), dtype=float)

        AxEoverL = Ax * E / L
        Ke[0, 0] = AxEoverL
        Ke[0, 1] = -AxEoverL
        Ke[1, 0] = -AxEoverL
        Ke[1, 1] = AxEoverL

        return Ke

    def calcK(self):
        '''
        Eval element stiffness matrix in global coordinates.
        '''
        L = self.length()
        n1, n2 = self.nodes

        # Transforamtion matrix
        T = np.zeros((2, 6), dtype=float)

        # Eval direction cosines in order to transform stiffness matrix
        # from local coords (link direction) to global coordinates
        cx = (n2.cx - n1.cx) / L
        cy = (n2.cy - n1.cy) / L
        cz = (n2.cz - n1.cz) / L

        T[0, 0] = cx
        T[0, 1] = cy
        T[0, 2] = cz
        T[1, 3] = cx
        T[1, 4] = cy
        T[1, 5] = cz

        # Stiffness matrix
        K = self.calcKe()

        # Evaluate Transformation K = T^T * K * T
        return np.dot(T.T, np.dot(K, T))

    def calcStress(self):
        raise NotImplementedError()

    def calcSectionForces(self, dx=1e9):
        '''
        Eval beam section forces in nodes
        '''
        res = np.zeros((2, 7), dtype=float)

        prop = self.properties
        mat = self.material
        n1, n2 = self.nodes

        L = self.length()
        E = mat['E']
        G = mat['G']
        Ax = prop['Area']

        # Eval coordinate transformation matrix
        T = self.calcT()

        # Transform displacements from global to local coordinates
        u1 = np.dot(T, n1.results[:3])
        u2 = np.dot(T, n2.results[:3])

        # Axial force, Nx
        res[0, 0] = 0.
        res[0, 1] = (-Ax * E / L) * (u2[0] - u1[0])

        res[1, 0] = 1.
        res[1, 1] = -res[0, 1]

        return res