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()
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]:
In [26]:
##test:
n = f.get_node('C')
n
Out[26]:
In [27]:
n.name
Out[27]:
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]:
In [77]:
##test:
t = f.nodes
r = t.merge(s,left_index=True,right_on='NODEID',how='outer').set_index('NODEID')
r
Out[77]:
In [78]:
v = s['NODEID'].apply(lambda x: x not in t.index)
v
Out[78]:
In [79]:
any(v)
Out[79]:
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]:
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
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'))
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'))
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)
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]
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)
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)
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)
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
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()
In [ ]:
##test:
Table.CELLDATA
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 [ ]: