$1^{st}$-Order Linear Solution


In [2]:
from salib import extend, NBImporter
import numpy as np
from collections import defaultdict

In [3]:
from Frame2D_Base import Frame2D, ResultSet
import Frame2D_Input
import Frame2D_Display
from MemberLoads import EF


Compiling notebook file 'Frame2D_Display.ipynb' to python.

In [4]:
##test:
f = Frame2D('frame-1')
f.input_all()

Analysis


In [5]:
@extend
class Frame2D:
    
    def buildK(self):
        K = np.mat(np.zeros((self.ndof,self.ndof)))
        for memb in self.members.values():
            Kl = memb.localK()
            Tm = memb.transform()
            Kg = Tm.T * Kl * Tm
            dofnums = memb.nodej.dofnums + memb.nodek.dofnums
            K[np.ix_(dofnums,dofnums)] += Kg
        return K

In [6]:
##test:
K = f.buildK()
K


Out[6]:
matrix([[  3.39581250e+05,   0.00000000e+00,   0.00000000e+00,
          -3.37500000e+05,   0.00000000e+00,   0.00000000e+00,
           0.00000000e+00,  -2.08125000e+03,   0.00000000e+00,
           8.32500000e+06,   0.00000000e+00,   0.00000000e+00],
        [  0.00000000e+00,   6.17287500e+05,   9.15000000e+06,
           0.00000000e+00,  -2.28750000e+03,   9.15000000e+06,
           0.00000000e+00,   0.00000000e+00,  -6.15000000e+05,
           0.00000000e+00,   0.00000000e+00,   0.00000000e+00],
        [  0.00000000e+00,   9.15000000e+06,   4.88000000e+10,
           0.00000000e+00,  -9.15000000e+06,   2.44000000e+10,
           0.00000000e+00,   0.00000000e+00,   0.00000000e+00,
           0.00000000e+00,   0.00000000e+00,   0.00000000e+00],
        [ -3.37500000e+05,   0.00000000e+00,   0.00000000e+00,
           3.39581250e+05,   0.00000000e+00,   0.00000000e+00,
           8.32500000e+06,   0.00000000e+00,   0.00000000e+00,
           0.00000000e+00,  -2.08125000e+03,   0.00000000e+00],
        [  0.00000000e+00,  -2.28750000e+03,  -9.15000000e+06,
           0.00000000e+00,   6.17287500e+05,  -9.15000000e+06,
           0.00000000e+00,   0.00000000e+00,   0.00000000e+00,
           0.00000000e+00,   0.00000000e+00,  -6.15000000e+05],
        [  0.00000000e+00,   9.15000000e+06,   2.44000000e+10,
           0.00000000e+00,  -9.15000000e+06,   4.88000000e+10,
           0.00000000e+00,   0.00000000e+00,   0.00000000e+00,
           0.00000000e+00,   0.00000000e+00,   0.00000000e+00],
        [  0.00000000e+00,   0.00000000e+00,   0.00000000e+00,
           8.32500000e+06,   0.00000000e+00,   0.00000000e+00,
           3.33000000e+10,   0.00000000e+00,   0.00000000e+00,
           0.00000000e+00,  -8.32500000e+06,   0.00000000e+00],
        [ -2.08125000e+03,   0.00000000e+00,   0.00000000e+00,
           0.00000000e+00,   0.00000000e+00,   0.00000000e+00,
           0.00000000e+00,   2.08125000e+03,   0.00000000e+00,
          -8.32500000e+06,   0.00000000e+00,   0.00000000e+00],
        [  0.00000000e+00,  -6.15000000e+05,   0.00000000e+00,
           0.00000000e+00,   0.00000000e+00,   0.00000000e+00,
           0.00000000e+00,   0.00000000e+00,   6.15000000e+05,
           0.00000000e+00,   0.00000000e+00,   0.00000000e+00],
        [  8.32500000e+06,   0.00000000e+00,   0.00000000e+00,
           0.00000000e+00,   0.00000000e+00,   0.00000000e+00,
           0.00000000e+00,  -8.32500000e+06,   0.00000000e+00,
           3.33000000e+10,   0.00000000e+00,   0.00000000e+00],
        [  0.00000000e+00,   0.00000000e+00,   0.00000000e+00,
          -2.08125000e+03,   0.00000000e+00,   0.00000000e+00,
          -8.32500000e+06,   0.00000000e+00,   0.00000000e+00,
           0.00000000e+00,   2.08125000e+03,   0.00000000e+00],
        [  0.00000000e+00,   0.00000000e+00,   0.00000000e+00,
           0.00000000e+00,  -6.15000000e+05,   0.00000000e+00,
           0.00000000e+00,   0.00000000e+00,   0.00000000e+00,
           0.00000000e+00,   0.00000000e+00,   6.15000000e+05]])

In [7]:
@extend
class Frame2D:
    
    def buildP(self,loadcase='all'):
        P = np.mat(np.zeros((self.ndof,1)))
        for node,load,factor in self.iter_nodeloads(loadcase):
            P[node.dofnums] += load.forces * factor
        return P
            
    def buildD(self,loadcase='all'):
        D = np.mat(np.zeros((self.ndof,1)))
        for node,load,factor in self.iter_nodedeltas(loadcase):
            D[node.dofnums] += load.forces * factor
        return D

In [8]:
##test:
f.buildP('one')


Out[8]:
matrix([[-350000.],
        [      0.],
        [      0.],
        [      0.],
        [      0.],
        [      0.],
        [      0.],
        [      0.],
        [      0.],
        [      0.],
        [      0.],
        [      0.]])

In [9]:
@extend
class Frame2D:
    
    def calc_fefs(self,loadcase='all'):
        ll = defaultdict(list)
        for memb,load,factor in self.iter_memberloads(loadcase):
            ll[memb].append((load,factor))
        fef = {memb:memb.fefs(loads) for memb,loads in ll.items()}
        #self.loadcase_fefs[loadcase] = fef
        return fef    

    def buildMP(self,memb_fefs):
        MP = np.mat(np.zeros((self.ndof,1)))
        for memb,mfefs in memb_fefs.items():
            gfefs = memb.Tm.T * mfefs.fefs
            dofnums = memb.nodej.dofnums + memb.nodek.dofnums
            MP[dofnums] -= gfefs
        return MP

In [10]:
@extend
class Frame2D:

    def calculate_mefs(self,rs):
        all_efs = {}
        D = rs.node_displacements
        for memb in self.members.values():
            gn = memb.nodej.dofnums + memb.nodek.dofnums
            med = D[np.ix_(gn)]
            mefs = EF((memb.Kl*memb.Tm)*med)
            fefs = rs.memb_fefs.get(memb,None)
            if fefs is not None:
                mefs += fefs
            all_efs[memb] = mefs
        return all_efs

In [11]:
@extend
class Frame2D:
    
    def pdelta_forces(self,rs):
        D = rs.node_displacements
        pdf = np.mat(np.zeros((self.ndof,1)))
        for m in self.columns:
            ef = rs.member_efs[m].fefs
            efg = m.Tm.T * ef    # end forces in global coords !!! TOO MUCH CALC !!!!
            P = efg[1,0]
            j = m.nodej.dofnums[0]
            k = m.nodek.dofnums[0]
            Delta = D[k,0]-D[j,0]
            H = m.L
            pdf[k,0] += P*Delta/H
            pdf[j,0] -= P*Delta/H
            ##print(m.id,H,j,k,P,Delta,P*Delta/H)
        return pdf

In [12]:
@extend
class Frame2D:
    
    def solve(self,loadcase='all',pdelta=False,maxniter=10):
        
        self.number_dofs()
        K = self.buildK()

        rs = ResultSet(loadcase)
        rs.memb_fefs = self.calc_fefs(loadcase)
        P = rs.node_P = self.buildP(loadcase)
        MP = rs.memb_P = self.buildMP(rs.memb_fefs)
        P = P + MP
        
        D = self.buildD(loadcase)
        
        N = self.nfree
        Kff = K[:N,:N]  # partition the matrices ....
        Kfc = K[:N,N:]
        Kcf = K[N:,:N]
        Kcc = K[N:,N:]
        
        D[:N] = np.linalg.solve(Kff,P[:N] - Kfc*D[N:])  # displacements
        R = Kcf*D[:N] + Kcc*D[N:] - P[N:]    # reactions at the constrained DOFs
        rs.node_displacements = D
        rs.reaction_forces = R   
        rs.member_efs = self.calculate_mefs(rs)
        
        if pdelta:
            niter = 0 
            self.columns = [m for m in self.members.values() if abs(m.dcy) >= 0.95]
            rs.pdelta = True
            while True:
                if niter > maxniter:
                    raise Exception('Too many iterations.  Giving up.  Solution not usable.')
                niter += 1
                Dprev = D.copy()
                
                PDF = self.pdelta_forces(rs)
                PDF[N:] = 0.
        
                D[:N] = np.linalg.solve(Kff,P[:N] + PDF[:N] - Kfc*D[N:])
                rs.node_displacements = D
                rs.member_efs = self.calculate_mefs(rs)
                
                maxD = max(abs(D[:N]))[0,0]
                maxChange = max(abs(D[:N]-Dprev[:N]))[0,0]
                maxP = 100.*maxChange/maxD
                print('iter={}, max D={}, max chg={}, max % chg={}'.format(niter,maxD,maxChange,maxP))
                if maxP < .01:
                    break
            R = Kcf*D[:N] + Kcc*D[N:] - P[N:] # reactions at the constrained DOFs (exclude P-delta forces)
            rs.reaction_forces = R
            rs.pdelta_forces = PDF
            print()
            
        return rs

In [13]:
##test:
f.reset()
f.input_all()
f.print_input()
rs = f.solve('one')


Frame frame-1:
==============


              # of nodal degrees of freedom: 12
  # of constrained nodal degrees of freedom: 5
# of unconstrained nodal degrees of freedom: 7  (= degree of kinematic indeterminacy)

                               # of members: 3
                             # of reactions: 5
                                 # of nodes: 4
                            # of conditions: 2
           degree of statical indeterminacy: 0



Nodes:
======

Node          X         Y  Constraints  DOF #s
----      -----     -----  -----------  ------
A             0         0  FX,FY,MZ     7,8,9
B             0      4000               0,1,2
C          8000      4000               3,4,5
D          8000         0  FX,FY        10,11,6



Members:
========

Member   Node-J  Node-K    Length       dcx       dcy  Size                Ix           A  Releases
------   ------  ------    ------   -------   -------  --------      --------       -----  --------
AB       A       B         4000.0   0.00000   1.00000  W310x97       2.22e+08       12300  MZK
BC       B       C         8000.0   1.00000   0.00000  W460x106      4.88e+08       13500  
CD       C       D         4000.0   0.00000  -1.00000                2.22e+08       12300  MZJ



Node Loads:
===========

Type      Node      FX          FY          MZ
----      ----  ----------  ----------  ----------
wind      B        -200000           0           0

Member Loads:
=============

Type      Member  Load
----      ------  ----------------
live      BC      UDL(L=8000.0,w=-50)
live      BC      PL(L=8000.0,P=-200000,a=5000.0)

Support Displacements:
======================

Type      Node      DX          DY          TZ
----      ----  ----------  ----------  ----------
other     A              0         -10           0

Load Combinations:
==================

Case   Type      Factor
-----  ----      ------
one    live        1.50
 "     wind        1.75
all    live        1.00
 "     wind        1.00
 "     other       1.00

In [14]:
##test:
f.print_results(rs)


Results for load case: one
++++++++++++++++++++++++++


Node Displacements:
===================

Node        DX         DY      Rotation
----      ------     ------   ---------
A          0.000      0.000   0.0000000
B       -168.168     -0.671  -0.0269748
C       -168.168     -0.793   0.0288654
D          0.000      0.000   0.0420420

Reactions:
==========

Node        FX         FY         MZ  
----     -------    -------    -------
A        350.000    412.500  -1400.000
D         -0.000    487.500      --   

Member End Forces:
==================

          /----- Axial -----/   /----- Shear -----/   /----- Moment ----/
Member       FX J       FX K       FY J       FY K       MZ J       MZ K
------     -------    -------    -------    -------    -------    -------
AB         412.500   -412.500   -350.000    350.000  -1400.000      0.000
BC           0.000      0.000    412.500    487.500     -0.000     -0.000
CD         487.500   -487.500      0.000     -0.000      0.000      0.000

Compare

Compare computed reactions with correct reactions.


In [15]:
##test:
# here are the correct reactions:
R = rs.reaction_forces
R


Out[15]:
matrix([[  3.50000000e+05],
        [  4.12500000e+05],
        [ -1.40000000e+09],
        [ -5.82076609e-11],
        [  4.87500000e+05]])

In [16]:
##test:
CR = np.matrix([350E3,412.5E3,-1400E6,0,487.5E3]).T
(R-CR)/CR


/usr/local/lib/python3.6/dist-packages/ipykernel_launcher.py:3: RuntimeWarning: divide by zero encountered in true_divide
  This is separate from the ipykernel package so we can avoid doing imports until
Out[16]:
matrix([[  5.32184328e-15],
        [  5.88426536e-14],
        [  5.44956752e-15],
        [            -inf],
        [  0.00000000e+00]])

Comparison is good.


In [17]:
##test:
f.reset()
f.input_all()
rs = f.solve('one',pdelta=True)


iter=1, max D=166.653139626114, max chg=1.5757559361157973, max % chg=0.9455303030299955
iter=2, max D=166.67034464055948, max chg=0.017774037422412903, max % chg=0.010664187117836897
iter=3, max D=166.67015631926407, max chg=0.0001947396978323468, max % chg=0.00011684137228461842


In [18]:
##test:
f.print_results(rs)


Results for load case: one
++++++++++++++++++++++++++


Node Displacements:
===================

Node        DX         DY      Rotation
----      ------     ------   ---------
A          0.000      0.000   0.0000000
B       -166.670     -0.671  -0.0269748
C       -166.610     -0.793   0.0288654
D          0.000      0.000   0.0416525

P-Delta Node Forces:
====================

Node        FX         FY         MZ  
----     -------    -------    -------
B        -17.188      0.000   0.0000000
C         20.306      0.000   0.0000000

Reactions:
==========

Node        FX         FY         MZ  
----     -------    -------    -------
A        346.882    412.500  -1387.529
D          0.000    487.500      --   

Member End Forces:
==================

          /----- Axial -----/   /----- Shear -----/   /----- Moment ----/
Member       FX J       FX K       FY J       FY K       MZ J       MZ K
------     -------    -------    -------    -------    -------    -------
AB         412.500   -412.500   -346.882    346.882  -1387.529      0.000
BC         -20.306     20.306    412.500    487.500     -0.000     -0.000
CD         487.500   -487.500      0.000      0.000      0.000      0.000

In [ ]: