def add_frames(frames_df, frame_props_df): # function to identify and assign beam and columns their respective tags def determine_tag(label): if 'C' in label: tag = col_transf_tag else: tag = beam_transf_tag return tag # construct a coordinate-transformation object, which transforms beam and column element # stiffness and resisting force from the basic system to the global-coordinate system. op.geomTransf(coordTransf, col_transf_tag, 1, 0, 0) op.geomTransf(coordTransf, beam_transf_tag, 0, 0, 1) # add all the frame elements which are oriented with the major axis frames_df[frames_df.Angle == 0.00].apply(lambda row: op.element('ElasticTimoshenkoBeam' , row.UniqueName, \ row.PointI , row.PointJ, \ E, G , frame_props_df.loc[row.Prop, 'Area'], \ frame_props_df.loc[row.Prop, 'J'] , frame_props_df.loc[row.Prop, 'I33'] , \ frame_props_df.loc[row.Prop, 'I22'] , frame_props_df.loc[row.Prop, 'As3'] , \ frame_props_df.loc[row.Prop, 'As2'] , determine_tag(row.Label) , \ '-mass' , M, massType), axis='columns') # add all the frame elements which are oriented perpandicular to the major axis by switching the properties in the two aixs frames_df[frames_df.Angle == 90.0].apply(lambda row: op.element('ElasticTimoshenkoBeam' , row.UniqueName, \ row.PointI , row.PointJ, \ E, G , frame_props_df.loc[row.Prop, 'Area'], \ frame_props_df.loc[row.Prop, 'J'] , frame_props_df.loc[row.Prop, 'I22'] , \ frame_props_df.loc[row.Prop, 'I33'] , frame_props_df.loc[row.Prop, 'As2'] , \ frame_props_df.loc[row.Prop, 'As3'] , determine_tag(row.Label) , \ '-mass' , M, massType), axis='columns') return
def ops_element(): ''' define element ''' # 壳区域 # 保护层单元 i = 1 for _i in [1, 12]: for n in range(_i, 650+_i, 13): ops.element('ShellMITC4', i, n, n+1, n+14, n+13, 1) i = i + 1 # 边缘约束区 for _i in [2, 3, 10, 11]: for n in range(_i, 650+_i, 13): ops.element('ShellMITC4', i, n, n+1, n+14, n+13, 2) i = i + 1 # 中部区域 for _i in range(4, 10): for n in range(_i, 650+_i, 13): ops.element('ShellMITC4', i, n, n+1, n+14, n+13, 2) i = i + 1 # 杆区域 for _i in [2, 12]: for n in range(_i, 650+_i, 13): ops.element('dispBeamColumn', i, n, n + 13, 1, 1) i = i + 1 for _i in [3, 4, 10, 11]: for n in range(_i, 650+_i, 13): ops.element('dispBeamColumn', i, n, n + 13, 1, 2) i = i + 1 pass
def test_beam_integration_mid_point_w_steel01(): lp_i = 0.1 lp_j = 0.2 op.wipe() op.model('basic', '-ndm', 2, '-ndf', 3) # 2 dimensions, 3 dof per node section1_id = 1 section2_id = 2 section3_id = 3 uniaxial_steel01_section(section1_id) uniaxial_steel01_section(section2_id) uniaxial_steel01_section(section3_id) integ_tag = 1 op.beamIntegration('HingeMidpoint', integ_tag, section1_id, lp_i, section2_id, lp_j, section3_id) with_force_beam_column = 1 if with_force_beam_column: # Establish nodes bot_node = 1 top_node = 2 transf_tag = 1 op.geomTransf('Linear', transf_tag, *[]) op.node(bot_node, 0., 0.) op.node(top_node, 0., 5.) ele_i = 1 op.element('forceBeamColumn', ele_i, bot_node, top_node, transf_tag, integ_tag)
def run(arg_1, arg_2, arg_3, arg_4): ops.reset() ops.wipe() ops.model('basic', '-ndm', 3, '-ndf', 6) ops.node(1, 0.0, 0.0, 0.0) ops.node(2, 0.0, 3.2, 0.0) ops.fix(1, 1, 1, 1, 1, 1, 1) ops.uniaxialMaterial('Concrete01', 1, -80.0e6, -0.002, 0.0, -0.005) ops.section('Fiber', 1, '-GJ', 1) ops.patch('rect', 1, 10, 10, -0.8, -0.1, 0.8, 0.1) ops.geomTransf('Linear', 1, 0, 0, 1) ops.beamIntegration('Legendre', 1, 1, 10) ops.element('dispBeamColumn', 1, 1, 2, 1, 1) ops.timeSeries('Linear', 1) ops.pattern('Plain', 1, 1) ops.load(2, 0, -24586.24, 0, 0, 0, 0) ops.constraints('Plain') ops.numberer('RCM') ops.system('UmfPack') ops.test('NormDispIncr', 1.0e-6, 2000) ops.algorithm('Newton') ops.integrator('LoadControl', 0.01) ops.analysis('Static') ops.analyze(100) ops.wipeAnalysis() ops.loadConst('-time', 0.0) ops.recorder('Node', '-file', 'disp.out', ' -time', '-node', 2, '-dof', 1, 'disp') ops.recorder('Node', '-file', 'react.out', '-time ', '-node', 2, '-dof', 1, 'reaction') ops.timeSeries('Linear', 2) ops.pattern('Plain', 2, 2) ops.load(2, 11500, 0, 0, 0, 0, 0) ops.constraints('Plain') ops.numberer('RCM') ops.system('UmfPack') ops.test('NormDispIncr', 1.0, 2000) ops.algorithm('Newton') ops.integrator('LoadControl', 0.01) ops.analysis('Static') # ops.analyze(100) step = 100 data = np.zeros((step, 2)) for i in range(step): ops.analyze(1) data[i, 0] = ops.nodeDisp(2, 1) data[i, 1] = ops.getLoadFactor(2) * 11500 return data
def ops_element(): i = 1 for _i in range(1, 11): print(f'element = {i}, node = {_i},{_i + 1}') ops.element('SFI_MVLEM', i, _i, _i + 1, 5, 0.4, '-thick', 200, 200, 200, 200, 200, '-width', 200, 200, 200, 200, 200, '-mat', 5, 6, 6, 6, 5) i = i + 1
def define_force_beam_column(ele_i, integ_tag): # Establish nodes bot_node = 1 top_node = 2 transf_tag = 1 op.geomTransf('Linear', transf_tag, *[]) op.node(bot_node, 0., 0.) op.node(top_node, 0., 5.) op.element('forceBeamColumn', ele_i, bot_node, top_node, transf_tag, integ_tag)
def Model_Build(x, y, A, E): ''' Description ----------- This function is used to determine the basic parameters of the structural problem at hand. Parameters ---------- x : LIST OF FLOATS The list of the coordinates of the nodes along the x-axis. y : LIST OF FLOATS The list of the coordinates of the nodes along the y-axis. A : LIST OF FLOATS The list with the materials used for the different elements. E : FLOAT The modulus of elesticity of the elements. Returns ------- None. ''' # Delete existing model. ops.wipe() # Define the model. ops.model('basic', '-ndm', 2, '-ndf', 3) # Define materials. ops.uniaxialMaterial('Elastic', 1, E) # Define the nodes. m = len(x) [ops.node(i + 1, *[x[i], y[i]]) for i in range(m)] # Fix the nodes. fixxity = [[0, 0, 1], [0, 1, 1], [1, 0, 1], [1, 1, 1]] [ ops.fix(i + 1, *fixxity[3]) if i + 1 != 4 else ops.fix(i + 1, *fixxity[0]) for i in range(m) ] # Define elements. conn = [[1, 4], [2, 4], [3, 4]] [ ops.element('Truss', i + 1, *conn[i], A[1], 1) if i != 0 else ops.element('Truss', i + 1, *conn[i], A[0], 1) for i in range(len(conn)) ] # Plot model. opsplt.plot_model()
def add_beam_hinges(dict_of_hinges, dict_of_hinges_2): # obtain nonlinear hinge properties data = read_nonlinear_hinge_properties() # dict_of_hinges = {real joint: (new joint, zero length element ID, orientation)} # iterate through all the hinges and add the uniaxial material and zero length element to the opensees model for key, value in dict_of_hinges.items(): node_R = key node_C = value[0] matTag = value[1] dirn = value[2] row = data.loc[data['Hinge NAME'] == dict_of_hinges_2[matTag]] K0 = row['K0'].values[0] as_Plus = row['as_Plus'].values[0] as_Neg = row['as_Neg'].values[0] My_Plus = row['My_Plus'].values[0] My_Neg = row['My_Neg'].values[0] Lamda_S = row['Lamda_S'].values[0] Lamda_C = row['Lamda_C'].values[0] Lamda_A = row['Lamda_A'].values[0] Lamda_K = row['Lamda_K'].values[0] c_S = row['c_S'].values[0] c_C = row['c_C'].values[0] c_A = row['c_A'].values[0] c_K = row['c_K'].values[0] theta_p_Plus = row['theta_p_Plus'].values[0] theta_p_Neg = row['theta_p_Neg'].values[0] theta_pc_Plus = row['theta_pc_Plus'].values[0] theta_pc_Neg = row['theta_pc_Neg'].values[0] Res_Pos = row['Res_Pos'].values[0] Res_Neg = row['Res_Neg'].values[0] theta_u_Plus = row['theta_u_Plus'].values[0] theta_u_Neg = row['theta_u_Neg'].values[0] D_Plus = row['D_Plus'].values[0] D_Neg = row['D_Neg'].values[0] nFactor = row['nFactor'].values[0] # define the uniaxial material op.uniaxialMaterial('Bilin', matTag, K0, as_Plus, as_Neg, My_Plus, My_Neg, Lamda_S, Lamda_C, Lamda_A, Lamda_K, c_S, c_C, c_A, c_K, theta_p_Plus, theta_p_Neg, theta_pc_Plus, theta_pc_Neg, Res_Pos, Res_Neg, theta_u_Plus, theta_u_Neg, D_Plus, D_Neg, nFactor) # add the zero length element op.element('zeroLength', matTag, node_R, node_C, '-mat', matTag, '-dir', dirn, '-doRayleigh', 1) # constrain the nodes connecting the rero lengrth element - all DOFs are constrained except the major bending op.equalDOF(node_R, node_C, 1, 2, 3, int(9 - dirn), 6) op.region(key, matTag) return
def ElasticBeamColumn(eleTag, iNode, jNode, sectType, E, transfTag, M, massType): found = 0 prop = WSection[sectType] A = prop[0] I = prop[1] ops.element('elasticBeamColumn', eleTag, iNode, jNode, A, E, I, transfTag, '-mass', M, massType)
def elements(A, E, analysis_type): matTag = 10 ops.uniaxialMaterial('Elastic', matTag, E) ########################################################################## eleTag = 1 member_type = 'Truss' if analysis_type != 'Linear': member_type = 'corotTruss' ops.element(member_type, eleTag, *[1, 2], A, matTag)
def create_FEM(self, component_id, node_i, node_j): """ Create the representation of the truss component in OpenSEES. Parameters ---------- component_id: int The element id assigned to the component in OpenSEES. node_i: int The id of the start node of the component in OpenSEES. node_j: int The id of the end node of the component in OpenSEES. """ ops.element('corotTruss', component_id, node_i, node_j, self.A_cs, self.material.id, '-doRayleigh', 1)
def connections(member_type, A, matTag, i, eleTag): ops.element(member_type, eleTag, *[i, i + 1], A, matTag) ops.element(member_type, eleTag + 1, *[i, i + 2], A, matTag) ops.element(member_type, eleTag + 2, *[i, i + 3], A, matTag) ops.element(member_type, eleTag + 3, *[i + 1, i + 3], A, matTag) eleTag += 4 return eleTag
def buildModel(K, periodStruct, dampRatio): wn = 2.0 * PI / periodStruct m = K / (wn * wn) ops.wipe() ops.model('basic', '-ndm', 1, '-ndf', 1) ops.node(1, 0.) ops.node(2, 0., '-mass', m) ops.uniaxialMaterial('Elastic', 1, K) ops.element('zeroLength', 1, 1, 2, '-mat', 1, '-dir', 1) ops.fix(1, 1) # add damping using rayleigh damping on the mass term a0 = 2.0 * wn * dampRatio ops.rayleigh(a0, 0., 0., 0.)
def MomentCurvature(secTag, axialLoad, maxK, numIncr=100): # Define two nodes at (0,0) ops.node(1, 0.0, 0.0) ops.node(2, 0.0, 0.0) # Fix all degrees of freedom except axial and bending ops.fix(1, 1, 1, 1) ops.fix(2, 0, 1, 0) # Define element # tag ndI ndJ secTag ops.element('zeroLengthSection', 1, 1, 2, secTag) # Define constant axial load ops.timeSeries('Constant', 1) ops.pattern('Plain', 1, 1) ops.load(2, axialLoad, 0.0, 0.0) # Define analysis parameters ops.integrator('LoadControl', 0.0) ops.system('SparseGeneral', '-piv') ops.test('NormUnbalance', 1e-9, 10) ops.numberer('Plain') ops.constraints('Plain') ops.algorithm('Newton') ops.analysis('Static') # Do one analysis for constant axial load ops.analyze(1) # Define reference moment ops.timeSeries('Linear', 2) ops.pattern('Plain', 2, 2) ops.load(2, 0.0, 0.0, 1.0) # Compute curvature increment dK = maxK / numIncr # Use displacement control at node 2 for section analysis ops.integrator('DisplacementControl', 2, 3, dK, 1, dK, dK) # Do the section analysis ops.analyze(numIncr)
def DiscretizeMember(ndI,ndJ,numEle,eleType,integrTag,transfTag,nodeTag,eleTag): nodeList = [] eleList = [] if numEle <= 1: ops.element(eleType,eleTag,ndI,ndJ,transfTag,integrTag) eleList.append(eleTag) return eleList,nodeList Xi = ops.nodeCoord(ndI,'X') Yi = ops.nodeCoord(ndI,'Y') Xj = ops.nodeCoord(ndJ,'X') Yj = ops.nodeCoord(ndJ,'Y') dX = (Xj-Xi)/numEle dY = (Yj-Yi)/numEle threeD = True if len(ops.nodeCoord(ndI)) < 3: threeD = False else: Zi = ops.nodeCoord(ndI,'Z') Zj = ops.nodeCoord(ndJ,'Z') dZ = (Zj-Zi)/numEle nodes = [None]*(numEle+1) nodes[0] = ndI nodes[numEle] = ndJ for i in range(1,numEle): if threeD: ops.node(nodeTag,Xi+i*dX,Yi+i*dY,Zi+i*dZ) else: ops.node(nodeTag,Xi+i*dX,Yi+i*dY) nodes[i] = nodeTag nodeList.append(nodeTag) nodeTag = nodeTag+1 #print(eleType,eleTag,ndI,nodes[1],transfTag,integrTag) ops.element(eleType,eleTag,ndI,nodes[1],transfTag,integrTag) eleList.append(eleTag) eleTag = eleTag + 1 for i in range(1,numEle-1): ops.element(eleType,eleTag,nodes[i],nodes[i+1],transfTag,integrTag) eleList.append(eleTag) eleTag = eleTag + 1 ops.element(eleType,eleTag,nodes[numEle-1],ndJ,transfTag,integrTag) eleList.append(eleTag) eleTag = eleTag + 1 return eleList,nodeList
def elements(coords, A, E, analysis_type): matTag = 10 ops.uniaxialMaterial('Elastic', matTag, E) ########################################################################## eleTag = 1 member_type = 'Truss' if analysis_type != 'Linear': member_type = 'corotTruss' temp = len(coords) - 3 for i in range(0, temp, 2): eleTag = connections(member_type, A, matTag, i, eleTag) temp += 1 ops.element(member_type, eleTag, *[temp, temp + 1], A, matTag)
def set_element(): ''' @Brief set element ''' for i in range(1, 3): for j in range(1, 8): ops.element('ShellMITC4', i * 1000 + j, i * 1000 + j, (i + 1) * 1000 + j, (i + 1) * 1000 + (j + 1), i * 1000 + (j + 1), 1) logger.info("Shell %d = [%d, %d, %d, %d] confined region", i * 1000 + j, i * 1000 + j, (i + 1) * 1000 + j, (i + 1) * 1000 + (j + 1), i * 1000 + (j + 1)) ops.element('ShellMITC4', (i + 4) * 1000 + j, (i + 4) * 1000 + j, (i + 5) * 1000 + j, (i + 5) * 1000 + (j + 1), (i + 4) * 1000 + (j + 1), 1) logger.info("Shell %d = [%d, %d, %d, %d] confined region", (i + 4) * 1000 + j, (i + 4) * 1000 + j, (i + 5) * 1000 + j, (i + 5) * 1000 + (j + 1), (i + 4) * 1000 + (j + 1)) for i in range(3, 5): for j in range(1, 8): ops.element('ShellMITC4', i * 1000 + j, i * 1000 + j, (i + 1) * 1000 + j, (i + 1) * 1000 + (j + 1), i * 1000 + (j + 1), 2) logger.info("Shell %d = [%d, %d, %d, %d] middle region", i * 1000 + j, i * 1000 + j, (i + 1) * 1000 + j, (i + 1) * 1000 + (j + 1), i * 1000 + (j + 1)) for i in range(1, 3): for j in range(1, 8): ops.element('Truss', i * 100 + j, i * 1000 + j, i * 1000 + (j + 1), 223.53e-6, 1) logger.info( "Truss %d = [%d, %d] cross-sectional area = %f, confined region", i * 100 + j, i * 1000 + j, i * 1000 + (j + 1), 223.53e-6) ops.element('Truss', (i + 5) * 100 + j, (i + 5) * 1000 + j, (i + 5) * 1000 + (j + 1), 223.53e-6, 1) logger.info( "Truss %d = [%d, %d] cross-sectional area = %f, confined region", (i + 5) * 100 + j, (i + 5) * 1000 + j, (i + 5) * 1000 + (j + 1), 223.53e-6)
def GetModel(A1, A2): x1 = 0. y1 = 0. x2 = 12.*ft y2 = 0. x3 = 14.*ft y3 = 0. x4 = 6.*ft y4 = 8.*ft # create nodes op.node(1, x1, y1) op.node(2, x2, y2) op.node(3, x3, y3) op.node(4, x4, y4) # set boundary condition op.fix(1, 1, 1, 1) op.fix(2, 1, 1, 1) op.fix(3, 1, 1, 1) op.fix(4, 0, 0, 1) # define elements # op.element('Truss', eleTag, *eleNodes, A, matTag[, '-rho', rho][, '-cMass', cFlag][, '-doRayleigh', rFlag]) op.element("Truss", 1, 1, 4, A1, 1) op.element("Truss", 2, 2, 4, A2, 1) op.element("Truss", 3, 3, 4, A2, 1)
def elements(Nnodes, L, A, E, Iz): # Define the number of elements: Nelems = Nnodes - 1 ########################################################################## # Define the geometric nonlinearity: TransfTag = 1 ops.geomTransf('Corotational', TransfTag) ########################################################################## # Define the elements: [ ops.element('elasticBeamColumn', i + 1, *[i + 1, i + 2], A, E, Iz, TransfTag) for i in range(Nelems) ]
def ops_element(): ops.beamIntegration('Legendre', 1, 2, 9) ops.geomTransf('Linear', 1, 0, -1, 0) i = 1 for _i in range(0, 56, 6): for _j in range(_i + 2, _i + 5): # print(f'element = {i}, node = {_j},{_j + 1},{_j + 7},{_j + 6 }') ops.element("ShellNLDKGQ", i, _j, _j + 1, _j + 7, _j + 6, 1) i = i + 1 for _k in range(1, 61, 6): # print(f'element = {i}, node = {_k},{_k + 6}') ops.element('dispBeamColumn', i, _k, _k + 6, 1, 1) i = i + 1 for _l in range(6, 66, 6): # print(f'element = {i}, node = {_l},{_l + 6}') ops.element('dispBeamColumn', i, _l, _l + 6, 1, 1) i = i + 1
def ops_element(): ''' define element ''' # 壳区域 # 边缘约束区 i = 1 for _i in [1, 2, 6, 7]: for n in range(_i, 80 + _i, 8): ops.element('ShellMITC4', i, n, n + 1, n + 9, n + 8, 1) i = i + 1 # 中部区域 for _i in [3, 4, 5]: for n in range(_i, 80 + _i, 8): ops.element('ShellMITC4', i, n, n + 1, n + 9, n + 8, 2) i = i + 1 # 杆区域 for _i in [1, 8]: for n in range(_i, 80 + _i, 8): ops.element('dispBeamColumn', i, n, n + 8, 1, 1) i = i + 1 for _i in [1, 2, 3, 5, 6, 8]: for n in range(_i, 80 + _i, 8): ops.element('dispBeamColumn', i, n, n + 8, 1, 2) i = i + 1
def get_Model(coords): ''' Summary ------- Parameters ---------- coords : TYPE DESCRIPTION. Returns ------- None. ''' # Define nodes: N = coords.shape[0] [ops.node(i + 1, *coords[i, :]) for i in range(N)] # Fix base point: fixxity = [1, 1, 1] # The base is fully fixxed. ops.fix(1, *fixxity) # Define elements: transfTag = 1 # testing. #transfTag = 10 # actual. integrationTag = 1 # testing. #integrationTag = 10 # actual. # element('forceBeamColumn', eleTag, *eleNodes, transfTag, integrationTag, '-iter', maxIter=10, tol=1e-12) #ops.element('forceBeamColumn', i, *[i, i + 1], transfTag, integrationTag, '-iter', 30, 1e-12) [ ops.element('forceBeamColumn', i, *[i, i + 1], transfTag, integrationTag, '-iter', 30, 1e-12) for i in range(1, N) ] print('Model built.')
def ops_element(): ''' define element ''' # 壳区域 # 边缘约束区 i = 1 for _i in [1, 2, 6, 7]: for n in range(_i, 80+_i, 8): ops.element('ShellMITC4', i, n, n+1, n+9, n+8, 1) i = i + 1 # 中部区域 for _i in [3, 4, 5]: for n in range(_i, 80+_i, 8): ops.element('ShellMITC4', i, n, n+1, n+9, n+8, 2) i = i + 1 # 杆区域 for _i in [1, 8]: for n in range(_i, 80+_i, 8): ops.element('Truss', i, n, n + 8, 6.28e-4, 3) i = i + 1
def buildModel(): nodeX = np.array([0., 0., 0., 0.]) nodeY = np.array([0., 1., 2., 3.]) Nnode = len(nodeX) # Define Nodes for ii in range(Nnode): tag = int(ii + 1) op.node(tag, nodeX[ii], nodeY[ii]) # Assign boundary constraints op.fix(1, 1, 1, 1) # define Element # element('forceBeamColumn', eleTag, *eleNodes, transfTag, integrationTag, '-iter', maxIter=10, tol=1e-12, '-mass', mass=0.0) op.element('forceBeamColumn', 1, *[1, 2], 1, 2, '-iter', 30, 1e-12) op.element('forceBeamColumn', 2, *[2, 3], 1, 2, '-iter', 30, 1e-12) op.element('forceBeamColumn', 3, *[3, 4], 1, 2, '-iter', 30, 1e-12) pass
mTg = 1 nu = 0.15 # Poisson's ratio of soil E = 2460000*N/cm**2 ops.nDMaterial('ElasticIsotropic', mTg, E, nu) # espesor de los elementos B = 0.25*m # construccion de nodos for i in range(nNode): ops.node(i+1, *Node[i][1:]) # construccion de elementos for i in range(nEle): if (Ele[i][0] == 1): ops.element('quad', i+1, *Ele[i][2:], B, 'PlaneStress', Ele[i][0]) # condiciones de frontera boundFix(nNode, Node) ops.timeSeries('Linear',1) ops.pattern('Plain',1,1) fx = 0 fy = -10*kN ops.load(2, fx, fy) #for i in range(nNode): # if (Node[i][0] == 2): # ops.load(i+1, fx, fy) ops.system('FullGeneral') # probar otros solvers: 'UmfPack' 'SparseSYM' ops.numberer('Plain')
def get_inelastic_response(fb, asig, extra_time=0.0, xi=0.05, analysis_dt=0.001): """ Run seismic analysis of a nonlinear FrameBuilding :param fb: FrameBuilding object :param asig: AccSignal object :param extra_time: float, additional analysis time after end of ground motion :param xi: damping ratio :param analysis_dt: time step to perform the analysis :return: """ op.wipe() op.model('basic', '-ndm', 2, '-ndf', 3) # 2 dimensions, 3 dof per node q_floor = 10000. # kPa trib_width = fb.floor_length trib_mass_per_length = q_floor * trib_width / 9.8 # Establish nodes and set mass based on trib area # Nodes named as: C<column-number>-S<storey-number>, first column starts at C1-S0 = ground level left nd = OrderedDict() col_xs = np.cumsum(fb.bay_lengths) col_xs = np.insert(col_xs, 0, 0) n_cols = len(col_xs) sto_ys = fb.heights sto_ys = np.insert(sto_ys, 0, 0) for cc in range(1, n_cols + 1): for ss in range(fb.n_storeys + 1): n_i = cc * 100 + ss nd["C%i-S%i" % (cc, ss)] = n_i op.node(n_i, col_xs[cc - 1], sto_ys[ss]) if ss != 0: if cc == 1: node_mass = trib_mass_per_length * fb.bay_lengths[0] / 2 elif cc == n_cols: node_mass = trib_mass_per_length * fb.bay_lengths[-1] / 2 else: node_mass = trib_mass_per_length * (fb.bay_lengths[cc - 2] + fb.bay_lengths[cc - 1] / 2) op.mass(n_i, node_mass) # Set all nodes on a storey to have the same displacement for ss in range(0, fb.n_storeys + 1): for cc in range(1, n_cols + 1): op.equalDOF(nd["C%i-S%i" % (1, ss)], nd["C%i-S%i" % (cc, ss)], opc.X) # Fix all base nodes for cc in range(1, n_cols + 1): op.fix(nd["C%i-S%i" % (cc, 0)], opc.FIXED, opc.FIXED, opc.FIXED) # Coordinate transformation geo_tag = 1 trans_args = [] op.geomTransf("Linear", geo_tag, *[]) l_hinge = fb.bay_lengths[0] * 0.1 # Define material e_conc = 30.0e6 i_beams = 0.4 * fb.beam_widths * fb.beam_depths ** 3 / 12 i_columns = 0.5 * fb.column_widths * fb.column_depths ** 3 / 12 a_beams = fb.beam_widths * fb.beam_depths a_columns = fb.column_widths * fb.column_depths ei_beams = e_conc * i_beams ei_columns = e_conc * i_columns eps_yield = 300.0e6 / 200e9 phi_y_col = calc_yield_curvature(fb.column_depths, eps_yield) phi_y_beam = calc_yield_curvature(fb.beam_depths, eps_yield) # Define beams and columns md = OrderedDict() # material dict sd = OrderedDict() # section dict ed = OrderedDict() # element dict # Columns named as: C<column-number>-S<storey-number>, first column starts at C1-S0 = ground floor left # Beams named as: B<bay-number>-S<storey-number>, first beam starts at B1-S1 = first storey left (foundation at S0) for ss in range(fb.n_storeys): # set columns for cc in range(1, fb.n_cols + 1): ele_i = cc * 100 + ss md["C%i-S%i" % (cc, ss)] = ele_i sd["C%i-S%i" % (cc, ss)] = ele_i ed["C%i-S%i" % (cc, ss)] = ele_i mat_props = elastic_bilin(ei_columns[ss][cc - 1], 0.05 * ei_columns[ss][cc - 1], phi_y_col[ss][cc - 1]) #print(opc.ELASTIC_BILIN, ele_i, *mat_props) op.uniaxialMaterial(opc.ELASTIC_BILIN, ele_i, *mat_props) # op.uniaxialMaterial("Elastic", ele_i, ei_columns[ss][cc - 1]) node_numbers = [nd["C%i-S%i" % (cc, ss)], nd["C%i-S%i" % (cc, ss + 1)]] op.element(opc.ELASTIC_BEAM_COLUMN, ele_i, *node_numbers, a_columns[ss - 1][cc - 1], e_conc, i_columns[ss - 1][cc - 1], geo_tag ) # Set beams for bb in range(1, fb.n_bays + 1): ele_i = bb * 10000 + ss md["B%i-S%i" % (bb, ss)] = ele_i sd["B%i-S%i" % (bb, ss)] = ele_i ed["B%i-S%i" % (bb, ss)] = ele_i mat_props = elastic_bilin(ei_beams[ss][bb - 1], 0.05 * ei_beams[ss][bb - 1], phi_y_beam[ss][bb - 1]) op.uniaxialMaterial(opc.ELASTIC_BILIN, ele_i, *mat_props) # op.uniaxialMaterial("Elastic", ele_i, ei_beams[ss][bb - 1]) node_numbers = [nd["C%i-S%i" % (bb, ss + 1)], nd["C%i-S%i" % (bb + 1, ss + 1)]] print((opc.BEAM_WITH_HINGES, ele_i, *node_numbers, sd["B%i-S%i" % (bb, ss)], l_hinge, sd["B%i-S%i" % (bb, ss)], l_hinge, sd["B%i-S%i" % (bb, ss)], geo_tag )) # Old definition # op.element(opc.BEAM_WITH_HINGES, ele_i, # *[nd["C%i-S%i" % (bb, ss - 1)], nd["C%i-S%i" % (bb + 1, ss)]], # sd["B%i-S%i" % (bb, ss)], l_hinge, # sd["B%i-S%i" % (bb, ss)], l_hinge, # e_conc, # a_beams[ss - 1][bb - 1], # i_beams[ss - 1][bb - 1], geo_tag # ) # New definition # op.element(opc.BEAM_WITH_HINGES, ele_i, # *node_numbers, # sd["B%i-S%i" % (bb, ss)], l_hinge, # sd["B%i-S%i" % (bb, ss)], l_hinge, # sd["B%i-S%i" % (bb, ss)], geo_tag # TODO: make this elastic # # ) # Elastic definition op.element(opc.ELASTIC_BEAM_COLUMN, ele_i, *node_numbers, a_beams[ss - 1][bb - 1], e_conc, i_beams[ss - 1][bb - 1], geo_tag ) # Define the dynamic analysis load_tag_dynamic = 1 pattern_tag_dynamic = 1 values = list(-1 * asig.values) # should be negative op.timeSeries('Path', load_tag_dynamic, '-dt', asig.dt, '-values', *values) op.pattern('UniformExcitation', pattern_tag_dynamic, opc.X, '-accel', load_tag_dynamic) # set damping based on first eigen mode angular_freq2 = op.eigen('-fullGenLapack', 1) if hasattr(angular_freq2, '__len__'): angular_freq2 = angular_freq2[0] angular_freq = angular_freq2 ** 0.5 if isinstance(angular_freq, complex): raise ValueError("Angular frequency is complex, issue with stiffness or mass") alpha_m = 0.0 beta_k = 2 * xi / angular_freq beta_k_comm = 0.0 beta_k_init = 0.0 period = angular_freq / 2 / np.pi print("period: ", period) op.rayleigh(alpha_m, beta_k, beta_k_init, beta_k_comm) # Run the dynamic analysis op.wipeAnalysis() op.algorithm('Newton') op.system('SparseGeneral') op.numberer('RCM') op.constraints('Transformation') op.integrator('Newmark', 0.5, 0.25) op.analysis('Transient') #op.test("NormDispIncr", 1.0e-1, 2, 0) tol = 1.0e-10 iter = 10 op.test('EnergyIncr', tol, iter, 0, 2) # TODO: make this test work analysis_time = (len(values) - 1) * asig.dt + extra_time outputs = { "time": [], "rel_disp": [], "rel_accel": [], "rel_vel": [], "force": [] } print("Analysis starting") while op.getTime() < analysis_time: curr_time = op.getTime() op.analyze(1, analysis_dt) outputs["time"].append(curr_time) outputs["rel_disp"].append(op.nodeDisp(nd["C%i-S%i" % (1, fb.n_storeys)], opc.X)) outputs["rel_vel"].append(op.nodeVel(nd["C%i-S%i" % (1, fb.n_storeys)], opc.X)) outputs["rel_accel"].append(op.nodeAccel(nd["C%i-S%i" % (1, fb.n_storeys)], opc.X)) op.reactions() react = 0 for cc in range(1, fb.n_cols): react += -op.nodeReaction(nd["C%i-S%i" % (cc, 0)], opc.X) outputs["force"].append(react) # Should be negative since diff node op.wipe() for item in outputs: outputs[item] = np.array(outputs[item]) return outputs
op.layer('straight', IDreinf, numBarsCol, barAreaCol, -coreY, coreZ, -coreY, -coreZ) op.layer('straight', IDreinf, numBarsCol, barAreaCol, coreY, coreZ, coreY, -coreZ) # BEAM section: op.section('Elastic', BeamSecTag, Ec, ABeam, IzBeam) # elastic beam section) ColTransfTag = 1 BeamTransfTag = 2 op.geomTransf('Linear', ColTransfTag) op.geomTransf('Linear', BeamTransfTag) numIntgrPts = 5 op.element('nonlinearBeamColumn', 1, 1, 3, numIntgrPts, ColSecTag, ColTransfTag) op.element('nonlinearBeamColumn', 2, 2, 4, numIntgrPts, ColSecTag, ColTransfTag) op.element('nonlinearBeamColumn', 3, 3, 4, numIntgrPts, BeamSecTag, BeamTransfTag) op.recorder('Node', '-file', 'Data-4-inelasticFiber/DFree.out', '-time', '-node', 3, 4, '-dof', 1, 2, 3, 'disp') op.recorder('Node', '-file', 'Data-4-inelasticFiber/DBase.out', '-time', '-node', 1, 2, '-dof', 1, 2, 3, 'disp') op.recorder('Node', '-file', 'Data-4-inelasticFiber/RBase.out', '-time', '-node', 1, 2, '-dof', 1, 2, 3, 'reaction') #op.recorder('Drift', '-file', 'Data-4-inelasticFiber/Drift.out','-time', '-node', 1, '-dof', 1,2,3, 'disp') op.recorder('Element', '-file', 'Data-4-inelasticFiber/FCol.out', '-time', '-ele', 1, 2, 'globalForce')
def get_pile_m(pile_z0=0, pile_z1=-30, pile_d=2, m0=7.5, pile_f=0, pile_m=0): pile_h = pile_z0 - pile_z1 pile_a = np.pi * (pile_d / 2) ** 2 pile_i = np.pi * pile_d ** 4 / 64 pile_b1 = 0.9 * (1.5 + 0.5 / pile_d) * 1 * pile_d # 建立模型 ops.wipe() ops.model('basic', '-ndm', 2, '-ndf', 3) # 建立节点 node_z = np.linspace(pile_z0, pile_z1, elem_num + 1) for i, j in enumerate(node_z): ops.node(i + 1, 0, j) ops.node(i + 201, 0, j) # 约束 for i in range(len(node_z)): ops.fix(i + 1, 0, 1, 0) ops.fix(i + 201, 1, 1, 1) # 建立材料 ops.uniaxialMaterial('Elastic', 1, 3e4) for i in range(len(node_z)): pile_depth = i * (pile_h / elem_num) pile_depth_nominal = 10 if pile_depth <= 10 else pile_depth soil_k = m0 * pile_depth_nominal * pile_b1 * (pile_h / elem_num) if i == 0: ops.uniaxialMaterial('Elastic', 100 + i, soil_k / 2) continue ops.uniaxialMaterial('Elastic', 100 + i, soil_k) # 装配 ops.geomTransf('Linear', 1) # 建立单元 for i in range(elem_num): ops.element('elasticBeamColumn', i + 1, i + 1, i + 2, pile_a, 3e10, pile_i, 1) # 建立弹簧 for i in range(len(node_z)): ops.element('zeroLength', i + 201, i + 1, i + 201, '-mat', 100 + i, '-dir', 1) ops.timeSeries('Linear', 1) ops.pattern('Plain', 1, 1) ops.load(1, pile_f, 0, pile_m) ops.system('BandGeneral') ops.numberer('Plain') ops.constraints('Plain') ops.integrator('LoadControl', 0.01) ops.test('EnergyIncr', 1e-6, 200) ops.algorithm('Newton') ops.analysis('Static') ops.analyze(100) # 绘制位移图 node_disp = [] for i in range(101): node_disp.append(ops.nodeDisp(i + 1)) node_disp = np.array(node_disp) * 1000 plt.figure() plt.subplot(121) for i, j in enumerate(node_z): if abs(node_disp[:, 0][i]) > max(abs(node_disp[:, 0])) / 50: if i == 0: plt.plot([0, node_disp[:, 0][i]], [j, j], linewidth=1.5, color='grey') else: plt.plot([0, node_disp[:, 0][i]], [j, j], linewidth=0.7, color='grey') if abs(node_disp[:, 0][i]) == max(abs(node_disp[:, 0])): plt.annotate(f'{node_disp[:, 0][i]:.1f} mm', xy=(node_disp[:, 0][i], j), xytext=(0.3, 0.5), textcoords='axes fraction', bbox=dict(boxstyle="round", fc="0.8"), arrowprops=dict(arrowstyle='->', connectionstyle="arc3,rad=-0.3")) plt.plot([0, 0], [node_z[0], node_z[-1]], linewidth=1.5, color='dimgray') plt.plot(node_disp[:, 0], node_z, linewidth=1.5, color='midnightblue') plt.xlabel('Displacement(mm)') plt.ylabel('Pile Depth(m)') # 绘制弯矩图 elem_m = [] for i in range(100): elem_m.append(ops.eleForce(i + 1)) elem_m = np.array(elem_m) / 1000 plt.subplot(122) for i, j in enumerate(node_z[:-1]): if abs(elem_m[:, 2][i]) > max(abs(elem_m[:, 2])) / 50: if i == 0: plt.plot([0, elem_m[:, 2][i]], [j, j], linewidth=1.5, color='grey') else: plt.plot([0, elem_m[:, 2][i]], [j, j], linewidth=0.7, color='grey') if abs(elem_m[:, 2][i]) == max(abs(elem_m[:, 2])): plt.annotate(f'{elem_m[:, 2][i]:.1f} kN.m', xy=(elem_m[:, 2][i], j), xytext=(0.5, 0.5), textcoords='axes fraction', bbox=dict(boxstyle="round", fc="0.8"), arrowprops=dict(arrowstyle='->', connectionstyle="arc3,rad=0.3")) plt.plot([0, 0], [node_z[0], node_z[-1]], linewidth=1.5, color='dimgray') plt.plot(elem_m[:, 2], node_z[:-1], linewidth=1.5, color='brown') plt.xlabel('Moment(kN.m)') # plt.ylabel('Pile Depth(m)') plt.show() return abs(max(elem_m[:, 2]))
def get_multi_pile_m( pile_layout, cap_edge=0, cap_thickness=2, pile_z0=-2.5, pile_z1=-30, pile_d=2, m0=7500000, top_f=0.0, top_h=0.0, top_m=0.0 ): if cap_edge == 0: if pile_d <= 1: cap_edge = max(0.25, 0.5 * pile_d) else: cap_edge = max(0.5, 0.3 * pile_d) cap_w = max(pile_layout[0]) - min(pile_layout[0]) + pile_d + cap_edge * 2 cap_l = max(pile_layout[1]) - min(pile_layout[1]) + pile_d + cap_edge * 2 top_f += cap_w * cap_l * cap_thickness * 26e3 # 承台自重 top_f += (cap_w * cap_l) * (-pile_z0 - cap_thickness) * 15e3 # 盖梁重量 pile_rows = len(pile_layout[1]) # 桩排数 top_f /= pile_rows # 桩顶力分配 top_h /= pile_rows # 桩顶水平力分配 top_m /= pile_rows # 桩顶弯矩分配 cap_i = cap_l * cap_thickness ** 3 / 12 / pile_rows # 承台横向刚度 pile_h = pile_z0 - pile_z1 pile_a = np.pi * (pile_d / 2) ** 2 pile_i = np.pi * pile_d ** 4 / 64 pile_b1 = 0.9 * (1.5 + 0.5 / pile_d) * 1 * pile_d # 建立模型 ops.wipe() ops.model('basic', '-ndm', 2, '-ndf', 3) # 建立节点 cap_bot = pile_z0 # ops.node(1, 0, cap_top) # 承台竖向节点 if 0 not in pile_layout[0]: ops.node(2, 0, cap_bot) # 建立桩基节点 node_z = np.linspace(pile_z0, pile_z1, elem_num + 1) for i, j in enumerate(pile_layout[0]): node_start = 100 + i * 300 for m, n in enumerate(node_z): ops.node(node_start + m + 1, j, n) ops.node(node_start + m + 151, j, n) nodes = {} for i in ops.getNodeTags(): nodes[i] = ops.nodeCoord(i) # 建立约束 for i, j in enumerate(pile_layout[0]): node_start = 100 + i * 300 for m, n in enumerate(node_z): ops.fix(node_start + m + 151, 1, 1, 1) if n == node_z[-1]: ops.fix(node_start + m + 1, 1, 1, 1) # 建立材料 for i in range(len(node_z)): pile_depth = i * (pile_h / elem_num) pile_depth_nominal = 10 if pile_depth <= 10 else pile_depth soil_k = m0 * pile_depth_nominal * pile_b1 * (pile_h / elem_num) if i == 0: ops.uniaxialMaterial('Elastic', 1 + i, soil_k / 2) continue ops.uniaxialMaterial('Elastic', 1 + i, soil_k) # 装配 ops.geomTransf('Linear', 1) # 建立单元 if len(pile_layout[0]) > 1: # 承台横向单元 cap_nodes = [] for i in nodes: if nodes[i][1] == cap_bot: if len(cap_nodes) == 0: cap_nodes.append(i) elif nodes[i][0] != nodes[cap_nodes[-1]][0]: cap_nodes.append(i) cap_nodes = sorted(cap_nodes, key=lambda x: nodes[x][0]) for i, j in enumerate(cap_nodes[:-1]): ops.element('elasticBeamColumn', 10 + i, j, cap_nodes[i+1], cap_l * cap_thickness, 3e10, cap_i, 1) pile_elem = [] for i, j in enumerate(pile_layout[0]): # 桩基单元 node_start = 100 + i * 300 pile_elem_i = [] for m, n in enumerate(node_z): if n != pile_z1: ops.element('elasticBeamColumn', node_start + m + 1, node_start + m + 1, node_start + m + 2, pile_a, 3e10, pile_i, 1) pile_elem_i.append(node_start + m + 1) ops.element('zeroLength', node_start + m + 151, node_start + m + 151, node_start + m + 1, '-mat', 1 + m, '-dir', 1) pile_elem.append(pile_elem_i) ops.timeSeries('Linear', 1) ops.pattern('Plain', 1, 1) for i in nodes: if nodes[i] == [0, pile_z0]: ops.load(i, -top_h, -top_f, top_m) # 加载 ops.system('BandGeneral') ops.numberer('Plain') ops.constraints('Plain') ops.integrator('LoadControl', 0.01) ops.test('EnergyIncr', 1e-6, 200) ops.algorithm('Newton') ops.analysis('Static') ops.analyze(100) node_disp = {} for i in ops.getNodeTags(): node_disp[i] = [j * 1000 for j in ops.nodeDisp(i)] elem_m = {} for i in pile_elem: for j in i: elem_m[j] = [k / 1000 for k in ops.eleForce(j)] plt.figure() for i, j in enumerate(pile_elem): plt.subplot(f'1{len(pile_elem)}{i+1}') if i == 0: plt.ylabel('Pile Depth(m)') node_disp_x = [] for m, n in enumerate(j): node_1 = ops.eleNodes(n)[0] if m == 0: plt.plot([0, node_disp[node_1][0]], [nodes[node_1][1], nodes[node_1][1]], linewidth=1.5, color='grey') else: plt.plot([0, node_disp[node_1][0]], [nodes[node_1][1], nodes[node_1][1]], linewidth=0.7, color='grey') node_disp_x.append(node_disp[node_1][0]) for m, n in enumerate(j): node_1 = ops.eleNodes(n)[0] if abs(node_disp[node_1][0]) == max([abs(i) for i in node_disp_x]): side = 1 if node_disp[node_1][0] > 0 else -1 plt.annotate(f'{node_disp[node_1][0]:.1f} mm', xy=(node_disp[node_1][0], nodes[node_1][1]), xytext=(0.4 + 0.1 * side, 0.5), textcoords='axes fraction', bbox=dict(boxstyle="round", fc="0.8"), arrowprops=dict(arrowstyle='->', connectionstyle=f"arc3,rad={side * 0.3}")) break plt.plot([0, 0], [node_z[0], node_z[-1]], linewidth=1.5, color='dimgray') plt.plot(node_disp_x, node_z[:-1], linewidth=1.5, color='midnightblue') plt.xlabel(f'Displacement_{i+1} (mm)') plt.show() plt.figure() for i, j in enumerate(pile_elem): plt.subplot(f'1{len(pile_elem)}{i + 1}') if i == 0: plt.ylabel('Pile Depth(m)') elem_mi = [] for m, n in enumerate(j): node_1 = ops.eleNodes(n)[0] if m == 0: plt.plot([0, elem_m[n][2]], [nodes[node_1][1], nodes[node_1][1]], linewidth=1.5, color='grey') else: plt.plot([0, elem_m[n][2]], [nodes[node_1][1], nodes[node_1][1]], linewidth=0.7, color='grey') elem_mi.append(elem_m[n][2]) for m, n in enumerate(j): node_1 = ops.eleNodes(n)[0] if abs(elem_m[n][2]) == max([abs(i) for i in elem_mi]): side = 1 if elem_m[n][2] > 0 else -1 plt.annotate(f'{elem_m[n][2]:.1f} kN.m', xy=(elem_m[n][2], nodes[node_1][1]), xytext=(0.4 + 0.1 * side, 0.5), textcoords='axes fraction', bbox=dict(boxstyle="round", fc="0.8"), arrowprops=dict(arrowstyle='->', connectionstyle=f"arc3,rad={side * 0.3}")) break plt.plot([0, 0], [node_z[0], node_z[-1]], linewidth=1.5, color='dimgray') plt.plot(elem_mi, node_z[:-1], linewidth=1.5, color='brown') plt.xlabel(f'Moment_{i + 1} (kN.m)') plt.show() return pile_elem, elem_m
nfY = 16 # number of fibers for concrete in y-direction nfZ = 4 # number of fibers for concrete in z-direction op.section('Fiber', ColSecTag) op.patch('quad', IDconcU, nfZ, nfY, -coverY, coverZ, -coverY, -coverZ, coverY, -coverZ, coverY, coverZ) # Define the concrete patch op.layer('straight', IDreinf, numBarsCol, barAreaCol, -coreY, coreZ, -coreY, -coreZ) op.layer('straight', IDreinf, numBarsCol, barAreaCol, coreY, coreZ, coreY, -coreZ) ColTransfTag = 1 op.geomTransf('Linear', ColTransfTag) numIntgrPts = 5 eleTag = 1 op.element('nonlinearBeamColumn', eleTag, 1, 2, numIntgrPts, ColSecTag, ColTransfTag) op.recorder('Node', '-file', 'Data-3-inelastic/DFree.out', '-time', '-node', 2, '-dof', 1, 2, 3, 'disp') op.recorder('Node', '-file', 'Data-3-inelastic/DBase.out', '-time', '-node', 1, '-dof', 1, 2, 3, 'disp') op.recorder('Node', '-file', 'Data-3-inelastic/RBase.out', '-time', '-node', 1, '-dof', 1, 2, 3, 'reaction') #op.recorder('Drift', '-file', 'Data-3-inelastic/Drift.out','-time', '-node', 1, '-dof', 1,2,3, 'disp') op.recorder('Element', '-file', 'Data-3-inelastic/FCol.out', '-time', '-ele', 1, 'globalForce') op.recorder('Element', '-file', 'Data-3-inelastic/ForceColSec1.out', '-time', '-ele', 1, 'section', 1, 'force') #op.recorder('Element', '-file', 'Data-3-inelastic/DCol.out','-time', '-ele', 1, 'deformations') #defining gravity loads