Exemple #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)
Exemple #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)
Exemple #3
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
Exemple #4
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