Input Data


In [18]:
from __future__ import print_function

In [38]:
from salib import extend, import_notebooks
from Tables import Table, DataSet
from Nodes import Node
from Members import Member
from LoadSets import LoadSet, LoadCombination
from NodeLoads import makeNodeLoad
from MemberLoads import makeMemberLoad
from collections import OrderedDict, defaultdict
import numpy as np
import pandas as pd

In [20]:
from Frame2D_Base import Frame2D

In [21]:
@extend
class Frame2D:
    
    COLUMNS_xxx = [] # list of column names for table 'xxx'
        
    def get_table(self,tablename,extrasok=False,optional=False):
        columns = getattr(self,'COLUMNS_'+tablename)
        index = getattr(self,'INDEX_'+tablename,None)
        validatefn = getattr(self,'validate_'+tablename,None)
        processfn = getattr(self,'process_'+tablename,None)
        t = DataSet.get_table(tablename,columns=columns,optional=optional)
        if index is not None:
            t.set_index(index,inplace=True)
        if validatefn:
            validatefn(t)
        if processfn:
            processfn(t)
        return t
    
    def check_duplicates(self,table,displayname):
        if table.index.has_duplicates:
            dups = table.index.get_duplicates()
            raise ValueError("Duplicate {}{}: {}"
                             .format(displayname,'' if len(dups) == 1 else 's',', '.join(dups)))

In [22]:
##test:
f = Frame2D()

Test Frame

Nodes


In [23]:
%%Table nodes
NODEID,X,Y,Z
A,0.,0.,5000.
B,0,4000,5000
C,8000,4000,5000
D,8000,0,5000

In [24]:
@extend
class Frame2D:
    
    COLUMNS_nodes = ['NODEID','X','Y']
    INDEX_nodes = 'NODEID'
    
    def validate_nodes(self,data):
        self.check_duplicates(data,'node id')
        nulls = data[data.isnull().any(axis=1)].index.values.tolist()
        if nulls:
            raise ValueError("X or Y Coordinate data missing for node{}: {}".format('' if len(nulls) == 1 else 's',', '.join(nulls)))
                    
    def process_nodes(self,data):
        pass
                
    def get_node(self,id):
        try:
            return self.nodes.ix[id]
        except KeyError:
            raise Exception('Node not defined: {}'.format(id))

In [25]:
##test:
f.nodes = f.get_table('nodes')
f.nodes


Out[25]:
X Y
NODEID
A 0 0
B 0 4000
C 8000 4000
D 8000 0

In [26]:
##test:
n = f.get_node('C')
n


Out[26]:
X    8000
Y    4000
Name: C, dtype: float64

In [27]:
n.name


Out[27]:
'C'

Supports


In [73]:
%%Table supports
NODEID,C0,C1,C2
A,FX,FY,MZ
D,FY,FX

In [74]:
def isnan(x):
    if x is None:
        return True
    try:
        return np.isnan(x)
    except TypeError:
        return False

In [75]:
@extend
class Frame2D:
    
    COLUMNS_supports = ('NODEID','C0','C1','C2')
    
    def input_supports(self):
        table = self.get_table('supports')
        for ix,row in table.data.iterrows():
            node = self.get_node(row.NODEID)
            for c in [row.C0,row.C1,row.C2]:
                if not isnan(c):
                    node.add_constraint(c)
        self.rawdata.supports = table
        
    def validate_supports(self,table):
        col = table['NODEID']
        invalid = col.apply(lambda x: x not in self.nodes.index)
        if any(invalid):
            bad = col[invalid].tolist()
            raise ValueError("Invalid nodeid in supports table: {}".format(bad))

In [76]:
##test:
s = f.get_table('supports')
s


Out[76]:
NODEID C0 C1 C2
0 A FX FY MZ
1 D FY FX NaN

In [77]:
##test:
t = f.nodes
r = t.merge(s,left_index=True,right_on='NODEID',how='outer').set_index('NODEID')
r


Out[77]:
X Y C0 C1 C2
NODEID
A 0 0 FX FY MZ
B 0 4000 NaN NaN NaN
C 8000 4000 NaN NaN NaN
D 8000 0 FY FX NaN

In [78]:
v = s['NODEID'].apply(lambda x: x not in t.index)
v


Out[78]:
0    False
1    False
Name: NODEID, dtype: bool

In [79]:
any(v)


Out[79]:
False

In [80]:
##test:
def makeset(*args):
    return set([x for x in args if not pd.isnull(x)])
r['Constraints'] = np.vectorize(makeset)(r['C0'],r['C1'],r['C2'])
r[['X','Y','Constraints']]


Out[80]:
X Y Constraints
NODEID
A 0 0 set([FX, FY, MZ])
B 0 4000 set([])
C 8000 4000 set([])
D 8000 0 set([FX, FY])

Members


In [ ]:
%%Table members
MEMBERID,NODEJ,NODEK
AB,A,B
BC,B,C
CD,C,D

In [ ]:
@extend
class Frame2D:
    
    COLUMNS_members = ('MEMBERID','NODEJ','NODEK')
    
    def input_members(self):
        table = self.get_table('members')
        for ix,m in table.data.iterrows():
            if m.MEMBERID in self.members:
                raise Exception('Multiply defined member: {}'.format(m.MEMBERID))
            memb = Member(m.MEMBERID,self.get_node(m.NODEJ),self.get_node(m.NODEK))
            self.members[memb.id] = memb
        self.rawdata.members = table
            
    def get_member(self,id):
        try:
            return self.members[id]
        except KeyError:
            raise Exception('Member not defined: {}'.format(id))

In [ ]:
##test:
f.input_members()
f.members

In [ ]:
##test:
m = f.get_member('BC')
m.id, m.L, m.dcx, m.dcy

Releases


In [ ]:
%%Table releases
MEMBERID,RELEASE
AB,MZK
CD,MZJ

In [ ]:
@extend
class Frame2D:
    
    COLUMNS_releases = ('MEMBERID','RELEASE')
    
    def input_releases(self):
        table = self.get_table('releases',optional=True)
        for ix,r in table.data.iterrows():
            memb = self.get_member(r.MEMBERID)
            memb.add_release(r.RELEASE)
        self.rawdata.releases = table

In [ ]:
##test:
f.input_releases()

In [ ]:
##test:
vars(f.get_member('AB'))

Properties

If the SST module is loadable, member properties may be specified by giving steel shape designations (such as 'W310x97') in the member properties data. If the module is not available, you may still give $A$ and $I_x$ directly (it only tries to lookup the properties if these two are not provided).


In [ ]:
try:
    from sst import SST
    __SST = SST()
    get_section = __SST.section
except ImportError:
    def get_section(dsg,fields):
        raise ValueError('Cannot lookup property SIZE because SST is not available.  SIZE = {}'.format(dsg))
        ##return [1.] * len(fields.split(',')) # in case you want to do it that way

In [ ]:
%%Table properties
MEMBERID,SIZE,IX,A
BC,W460x106,,
AB,W310x97,,
CD,,

In [ ]:
@extend
class Frame2D:
    
    COLUMNS_properties = ('MEMBERID','SIZE','IX','A')
    
    def input_properties(self):
        table = self.get_table('properties')
        table = self.fill_properties(table)
        for ix,row in table.data.iterrows():
            memb = self.get_member(row.MEMBERID)
            memb.size = row.SIZE
            memb.Ix = row.IX
            memb.A = row.A
        self.rawdata.properties = table
        
    def fill_properties(self,table):
        data = table.data
        prev = None
        for ix,row in data.iterrows():
            nf = 0
            if type(row.SIZE) in [type(''),type(u'')]:
                if isnan(row.IX) or isnan(row.A):
                    Ix,A = get_section(row.SIZE,'Ix,A')
                    if isnan(row.IX):
                        nf += 1
                        data.loc[ix,'IX'] = Ix
                    if isnan(row.A):
                        nf += 1
                        data.loc[ix,'A'] = A
            elif isnan(row.SIZE):
                data.loc[ix,'SIZE'] = '' if nf == 0 else prev
            prev = data.loc[ix,'SIZE']
        table.data = data.fillna(method='ffill')
        return table

In [ ]:
##test:
f.input_properties()

In [ ]:
##test:
vars(f.get_member('CD'))

Node Loads


In [ ]:
%%Table node_loads
LOAD,NODEID,DIRN,F
Wind,B,FX,-200000.

In [ ]:
@extend
class Frame2D:
    
    COLUMNS_node_loads = ('LOAD','NODEID','DIRN','F')
    
    def input_node_loads(self):
        table = self.get_table('node_loads')
        dirns = ['FX','FY','FZ']
        for ix,row in table.data.iterrows():
            n = self.get_node(row.NODEID)
            if row.DIRN not in dirns:
                raise ValueError("Invalid node load direction: {} for load {}, node {}; must be one of '{}'"
                                .format(row.DIRN, row.LOAD, row.NODEID, ', '.join(dirns)))
            if row.DIRN in n.constraints:
                raise ValueError("Constrained node {} {} must not have load applied."
                                .format(row.NODEID,row.DIRN))
            l = makeNodeLoad({row.DIRN:row.F})
            self.nodeloads.append(row.LOAD,n,l)
        self.rawdata.node_loads = table

In [ ]:
##test:
f.input_node_loads()

In [ ]:
##test:
for o,l,fact in f.nodeloads.iterloads('Wind'):
    print(o,l,fact,l*fact)

Support Displacements


In [ ]:
%%Table support_displacements
LOAD,NODEID,DIRN,DELTA
Other,A,DY,-10

In [ ]:
@extend
class Frame2D:
    
    COLUMNS_support_displacements = ('LOAD','NODEID','DIRN','DELTA')
    
    def input_support_displacements(self):
        table = self.get_table('support_displacements',optional=True)
        forns = {'DX':'FX','DY':'FY','RZ':'MZ'}
        for ix,row in table.data.iterrows():
            n = self.get_node(row.NODEID)
            if row.DIRN not in forns:
                raise ValueError("Invalid support displacements direction: {} for load {}, node {}; must be one of '{}'"
                                .format(row.DIRN, row.LOAD, row.NODEID, ', '.join(forns.keys())))
            fd = forns[row.DIRN]
            if fd not in n.constraints:
                raise ValueError("Support displacement, load: '{}'  node: '{}'  dirn: '{}' must be for a constrained node."
                                .format(row.LOAD,row.NODEID,row.DIRN))
            l = makeNodeLoad({fd:row.DELTA})
            self.nodedeltas.append(row.LOAD,n,l)
        self.rawdata.support_displacements = table

In [ ]:
##test:
f.input_support_displacements()

In [ ]:
##test:
list(f.nodedeltas)[0]

Member Loads


In [ ]:
%%Table member_loads
LOAD,MEMBERID,TYPE,W1,W2,A,B,C
Live,BC,UDL,-50,,,,
Live,BC,PL,-200000,,5000

In [ ]:
@extend
class Frame2D:
    
    COLUMNS_member_loads = ('LOAD','MEMBERID','TYPE','W1','W2','A','B','C')
    
    def input_member_loads(self):
        table = self.get_table('member_loads')
        for ix,row in table.data.iterrows():
            m = self.get_member(row.MEMBERID)
            l = makeMemberLoad(m.L,row)
            self.memberloads.append(row.LOAD,m,l)
        self.rawdata.member_loads = table

In [ ]:
##test:
f.input_member_loads()

In [ ]:
##test:
for o,l,fact in f.memberloads.iterloads('Live'):
    print(o.id,l,fact,l.fefs()*fact)

Load Combinations


In [ ]:
%%Table load_combinations
CASE,LOAD,FACTOR
One,Live,1.5
One,Wind,1.75

In [ ]:
@extend
class Frame2D:
    
    COLUMNS_load_combinations = ('CASE','LOAD','FACTOR')
    
    def input_load_combinations(self):
        table = self.get_table('load_combinations',optional=True)
        if len(table) > 0:
            for ix,row in table.data.iterrows():
                self.loadcombinations.append(row.CASE,row.LOAD,row.FACTOR)
        if 'all' not in self.loadcombinations:
            all = self.nodeloads.names.union(self.memberloads.names)
            all = self.nodedeltas.names.union(all)
            for l in all:
                self.loadcombinations.append('all',l,1.0)
        self.rawdata.load_combinations = table

In [ ]:
##test:
f.input_load_combinations()

In [ ]:
##test:
for o,l,fact in f.loadcombinations.iterloads('One',f.nodeloads):
    print(o.id,l,fact)
for o,l,fact in f.loadcombinations.iterloads('One',f.memberloads):
    print(o.id,l,fact,l.fefs()*fact)

Load Iterators


In [ ]:
@extend
class Frame2D:

    def iter_nodeloads(self,casename):
        for o,l,f in self.loadcombinations.iterloads(casename,self.nodeloads):
            yield o,l,f
    
    def iter_nodedeltas(self,casename):
        for o,l,f in self.loadcombinations.iterloads(casename,self.nodedeltas):
            yield o,l,f
    
    def iter_memberloads(self,casename):
        for o,l,f in self.loadcombinations.iterloads(casename,self.memberloads):
            yield o,l,f

In [ ]:
##test:
for o,l,fact in f.iter_nodeloads('One'):
    print(o.id,l,fact)
for o,l,fact in f.iter_memberloads('One'):
    print(o.id,l,fact)

Number the DOFs


In [ ]:
@extend
class Frame2D:
    
    def number_dofs(self):
        self.ndof = (3*len(self.nodes))
        self.ncons = sum([len(node.constraints) for node in self.nodes.values()])
        self.nfree = self.ndof - self.ncons
        ifree = 0
        icons = self.nfree
        self.dofdesc = [None] * self.ndof
        for node in self.nodes.values():
            for dirn,ix in node.DIRECTIONS.items():
                if dirn in node.constraints:
                    n = icons
                    icons += 1
                else:
                    n = ifree
                    ifree += 1
                node.dofnums[ix] = n
                self.dofdesc[n] = (node,dirn)

In [ ]:
##test:
f.number_dofs()
f.ndof, f.ncons, f.nfree

In [ ]:
##test:
f.dofdesc

In [ ]:
##test:
f.get_node('D').dofnums

Input Everything


In [ ]:
@extend
class Frame2D:
    
    def input_all(self):
        self.input_nodes()
        self.input_supports()
        self.input_members()
        self.input_releases()
        self.input_properties()
        self.input_node_loads()
        self.input_support_displacements()
        self.input_member_loads()
        self.input_load_combinations()
        self.input_finish()
        
    def input_finish(self):
        self.number_dofs()

In [ ]:
##test:
f.reset()
f.input_all()

Accumulated Cell Data


In [ ]:
##test:
Table.CELLDATA

Input From Files


In [ ]:
##test:
f.reset()
Table.set_source('frame-1')
f.input_all()

In [ ]:
##test:
vars(f.rawdata)

In [ ]:
##test:
f.rawdata.nodes.data

In [ ]:
##test:
f.members

In [ ]:
##test:
Table.CELLDATA

In [ ]: