def add_nodes(joints_df, mass_df, list_new_joints, dict_of_hinges): # Identify the joints that were auto created by ETABS (like COM joints) points_df = joints_df[joints_df.IsAuto == 'Yes'].copy() # create joints in opensees mdoel joints_df.apply(lambda row: op.node(row.UniqueName, row.X, row.Y, row.Z), axis='columns') # add restraints to the joints joints_df.apply( lambda row: op.fix(row.UniqueName, *[int(r) for r in row.Restraints]), axis='columns') # special joint restraints for the COM joints points_df.apply(lambda row: op.fix(row.UniqueName, *[0, 0, 1, 1, 1, 0]), axis='columns') op.constraints('Transformation') # if the model diaphragm is rigid, define rigidity on each floor if rigid_dia: # obtain the list of floors in terms of the elevation (Z coordinate) floor_list = set(joints_df[joints_df.Z > joints_df.Z.min()].Z) # iterate through each floor to define rigid diaphragm for floor in floor_list: nodes_list = list( joints_df.loc[joints_df.Z == floor]['UniqueName']) remove_list = list(set(nodes_list) & set(list_new_joints)) + list( dict_of_hinges.keys()) nodes = [i for i in nodes_list if i not in remove_list] op.rigidDiaphragm(3, *nodes) # apply mass to the respective nodes mass_df.apply(lambda row: op.mass(row.PointElm, row.UX, row.UY, row.UZ, row .RX, row.RY, row.RZ), axis='columns') return
def RunAnalysis(): AnalysisType = 'Pushover' # Pushover Gravity ## ------------------------------ ## Start of model generation ## ----------------------------- # remove existing model ops.wipe() # set modelbuilder ops.model('basic', '-ndm', 2, '-ndf', 3) import math ############################################ ### Units and Constants ################### ############################################ inch = 1 kip = 1 sec = 1 # Dependent units sq_in = inch * inch ksi = kip / sq_in ft = 12 * inch # Constants g = 386.2 * inch / (sec * sec) pi = math.acos(-1) ####################################### ##### Dimensions ####################################### # Dimensions Input H_story = 10.0 * ft W_bayX = 16.0 * ft W_bayY_ab = 5.0 * ft + 10.0 * inch W_bayY_bc = 8.0 * ft + 4.0 * inch W_bayY_cd = 5.0 * ft + 10.0 * inch # Calculated dimensions W_structure = W_bayY_ab + W_bayY_bc + W_bayY_cd ################ ### Material ################ # Steel02 Material matTag = 1 matConnAx = 2 matConnRot = 3 Fy = 60.0 * ksi # Yield stress Es = 29000.0 * ksi # Modulus of Elasticity of Steel v = 0.2 # Poisson's ratio Gs = Es / (1 + v) # Shear modulus b = 0.10 # Strain hardening ratio params = [18.0, 0.925, 0.15] # R0,cR1,cR2 R0 = 18.0 cR1 = 0.925 cR2 = 0.15 a1 = 0.05 a2 = 1.00 a3 = 0.05 a4 = 1.0 sigInit = 0.0 alpha = 0.05 ops.uniaxialMaterial('Steel02', matTag, Fy, Es, b, R0, cR1, cR2, a1, a2, a3, a4, sigInit) # ################## # ## Sections # ################## colSecTag1 = 1 colSecTag2 = 2 beamSecTag1 = 3 beamSecTag2 = 4 beamSecTag3 = 5 # COMMAND: section('WFSection2d', secTag, matTag, d, tw, bf, tf, Nfw, Nff) ops.section('WFSection2d', colSecTag1, matTag, 10.5 * inch, 0.26 * inch, 5.77 * inch, 0.44 * inch, 15, 16) # outer Column ops.section('WFSection2d', colSecTag2, matTag, 10.5 * inch, 0.26 * inch, 5.77 * inch, 0.44 * inch, 15, 16) # Inner Column ops.section('WFSection2d', beamSecTag1, matTag, 8.3 * inch, 0.44 * inch, 8.11 * inch, 0.685 * inch, 15, 15) # outer Beam ops.section('WFSection2d', beamSecTag2, matTag, 8.2 * inch, 0.40 * inch, 8.01 * inch, 0.650 * inch, 15, 15) # Inner Beam ops.section('WFSection2d', beamSecTag3, matTag, 8.0 * inch, 0.40 * inch, 7.89 * inch, 0.600 * inch, 15, 15) # Inner Beam # Beam size - W10x26 Abeam = 7.61 * inch * inch IbeamY = 144. * (inch**4) # Inertia along horizontal axis IbeamZ = 14.1 * (inch**4) # inertia along vertical axis # BRB input data Acore = 2.25 * inch Aend = 10.0 * inch LR_BRB = 0.55 # ########################### # ##### Nodes # ########################### # Create All main nodes ops.node(1, 0.0, 0.0) ops.node(2, W_bayX, 0.0) ops.node(3, 2 * W_bayX, 0.0) ops.node(11, 0.0, H_story) ops.node(12, W_bayX, H_story) ops.node(13, 2 * W_bayX, H_story) ops.node(21, 0.0, 2 * H_story) ops.node(22, W_bayX, 2 * H_story) ops.node(23, 2 * W_bayX, 2 * H_story) ops.node(31, 0.0, 3 * H_story) ops.node(32, W_bayX, 3 * H_story) ops.node(33, 2 * W_bayX, 3 * H_story) # Beam Connection nodes ops.node(1101, 0.0, H_story) ops.node(1201, W_bayX, H_story) ops.node(1202, W_bayX, H_story) ops.node(1301, 2 * W_bayX, H_story) ops.node(2101, 0.0, 2 * H_story) ops.node(2201, W_bayX, 2 * H_story) ops.node(2202, W_bayX, 2 * H_story) ops.node(2301, 2 * W_bayX, 2 * H_story) ops.node(3101, 0.0, 3 * H_story) ops.node(3201, W_bayX, 3 * H_story) ops.node(3202, W_bayX, 3 * H_story) ops.node(3301, 2 * W_bayX, 3 * H_story) # ############### # Constraints # ############### ops.fix(1, 1, 1, 1) ops.fix(2, 1, 1, 1) ops.fix(3, 1, 1, 1) # ####################### # ### Elements # ####################### # ### Assign beam-integration tags ColIntTag1 = 1 ColIntTag2 = 2 BeamIntTag1 = 3 BeamIntTag2 = 4 BeamIntTag3 = 5 ops.beamIntegration('Lobatto', ColIntTag1, colSecTag1, 4) ops.beamIntegration('Lobatto', ColIntTag2, colSecTag2, 4) ops.beamIntegration('Lobatto', BeamIntTag1, beamSecTag1, 4) ops.beamIntegration('Lobatto', BeamIntTag2, beamSecTag2, 4) ops.beamIntegration('Lobatto', BeamIntTag3, beamSecTag3, 4) # Assign geometric transformation ColTransfTag = 1 BeamTranfTag = 2 ops.geomTransf('PDelta', ColTransfTag) ops.geomTransf('Linear', BeamTranfTag) # Assign Elements ############## # ## Add non-linear column elements ops.element('forceBeamColumn', 1, 1, 11, ColTransfTag, ColIntTag1, '-mass', 0.0) ops.element('forceBeamColumn', 2, 2, 12, ColTransfTag, ColIntTag2, '-mass', 0.0) ops.element('forceBeamColumn', 3, 3, 13, ColTransfTag, ColIntTag1, '-mass', 0.0) ops.element('forceBeamColumn', 11, 11, 21, ColTransfTag, ColIntTag1, '-mass', 0.0) ops.element('forceBeamColumn', 12, 12, 22, ColTransfTag, ColIntTag2, '-mass', 0.0) ops.element('forceBeamColumn', 13, 13, 23, ColTransfTag, ColIntTag1, '-mass', 0.0) ops.element('forceBeamColumn', 21, 21, 31, ColTransfTag, ColIntTag1, '-mass', 0.0) ops.element('forceBeamColumn', 22, 22, 32, ColTransfTag, ColIntTag2, '-mass', 0.0) ops.element('forceBeamColumn', 23, 23, 33, ColTransfTag, ColIntTag1, '-mass', 0.0) # ### Add linear main beam elements, along x-axis #element('elasticBeamColumn', 101, 1101, 1201, Abeam, Es, Gs, Jbeam, IbeamY, IbeamZ, beamTransfTag, '-mass', 0.0) ops.element('forceBeamColumn', 101, 1101, 1201, BeamTranfTag, BeamIntTag1, '-mass', 0.0) ops.element('forceBeamColumn', 102, 1202, 1301, BeamTranfTag, BeamIntTag1, '-mass', 0.0) ops.element('forceBeamColumn', 201, 2101, 2201, BeamTranfTag, BeamIntTag2, '-mass', 0.0) ops.element('forceBeamColumn', 202, 2202, 2301, BeamTranfTag, BeamIntTag2, '-mass', 0.0) ops.element('forceBeamColumn', 301, 3101, 3201, BeamTranfTag, BeamIntTag3, '-mass', 0.0) ops.element('forceBeamColumn', 302, 3202, 3301, BeamTranfTag, BeamIntTag3, '-mass', 0.0) # Assign constraints between beam end nodes and column nodes (RIgid beam column connections) ops.equalDOF(11, 1101, 1, 2, 3) ops.equalDOF(12, 1201, 1, 2, 3) ops.equalDOF(12, 1202, 1, 2, 3) ops.equalDOF(13, 1301, 1, 2, 3) ops.equalDOF(21, 2101, 1, 2, 3) ops.equalDOF(22, 2201, 1, 2, 3) ops.equalDOF(22, 2202, 1, 2, 3) ops.equalDOF(23, 2301, 1, 2, 3) ops.equalDOF(31, 3101, 1, 2, 3) ops.equalDOF(32, 3201, 1, 2, 3) ops.equalDOF(32, 3202, 1, 2, 3) ops.equalDOF(33, 3301, 1, 2, 3) AllNodes = ops.getNodeTags() massX = 0.49 for nodes in AllNodes: ops.mass(nodes, massX, massX, 0.00001) ################ ## Gravity Load ################ # create TimeSeries ops.timeSeries("Linear", 1) # create a plain load pattern ops.pattern("Plain", 1, 1) # Create the nodal load ops.load(11, 0.0, -5.0 * kip, 0.0) ops.load(12, 0.0, -6.0 * kip, 0.0) ops.load(13, 0.0, -5.0 * kip, 0.0) ops.load(21, 0., -5. * kip, 0.0) ops.load(22, 0., -6. * kip, 0.0) ops.load(23, 0., -5. * kip, 0.0) ops.load(31, 0., -5. * kip, 0.0) ops.load(32, 0., -6. * kip, 0.0) ops.load(33, 0., -5. * kip, 0.0) ############################### ### PUSHOVER ANALYSIS ############################### if (AnalysisType == "Pushover"): print("<<<< Running Pushover Analysis >>>>") # Create load pattern for pushover analysis # create a plain load pattern ops.pattern("Plain", 2, 1) ops.load(11, 1.61, 0.0, 0.0) ops.load(21, 3.22, 0.0, 0.0) ops.load(31, 4.83, 0.0, 0.0) ControlNode = 31 ControlDOF = 1 MaxDisp = 0.15 * H_story DispIncr = 0.1 NstepsPush = int(MaxDisp / DispIncr) Model = 'test' LoadCase = 'Pushover' dt = 0.2 opp.createODB(Model, LoadCase, Nmodes=3) ops.system("ProfileSPD") ops.numberer("Plain") ops.constraints("Plain") ops.integrator("DisplacementControl", ControlNode, ControlDOF, DispIncr) ops.algorithm("Newton") ops.test('NormUnbalance', 1e-8, 10) ops.analysis("Static") # analyze(NstepsPush) ops.analyze(100) print("Pushover analysis complete")
E = 25.0e6 G = 9615384.6 # Lx, Ly, Lz = 4., 3., 5. Lx, Ly, Lz = 4., 4., 4. ops.node(1, 0., 0., 0.) ops.node(2, 0., 0., Lz) ops.node(3, Lx, 0., Lz) ops.node(4, Lx, Ly, Lz) ops.fix(1, 1, 1, 1, 1, 1, 1) lmass = 200. ops.mass(2, lmass, lmass, lmass, 0.001, 0.001, 0.001) ops.mass(3, lmass, lmass, lmass, 0.001, 0.001, 0.001) ops.mass(4, lmass, lmass, lmass, 0.001, 0.001, 0.001) gTTagz = 1 gTTagx = 2 gTTagy = 3 coordTransf = 'Linear' ops.geomTransf(coordTransf, gTTagz, 0., -1., 0.) ops.geomTransf(coordTransf, gTTagx, 0., -1., 0.) ops.geomTransf(coordTransf, gTTagy, 1., 0., 0.) ops.element('elasticBeamColumn', 1, 1, 2, A, E, G, J, Iy, Iz, gTTagz) ops.element('elasticBeamColumn', 2, 2, 3, A, E, G, J, Iy, Iz, gTTagx) ops.element('elasticBeamColumn', 3, 3, 4, A, E, G, J, Iy, Iz, gTTagy)
def test_PortalFrame2d(): # set some properties print("================================================") print("PortalFrame2d.py: Verification 2d Elastic Frame") print(" - eigenvalue and static pushover analysis") ops.wipe() ops.model('Basic', '-ndm', 2) # properties # units kip, ft numBay = 2 numFloor = 7 bayWidth = 360.0 storyHeights = [162.0, 162.0, 156.0, 156.0, 156.0, 156.0, 156.0] E = 29500.0 massX = 0.49 M = 0. coordTransf = "Linear" # Linear, PDelta, Corotational massType = "-lMass" # -lMass, -cMass beams = [ 'W24X160', 'W24X160', 'W24X130', 'W24X130', 'W24X110', 'W24X110', 'W24X110' ] eColumn = [ 'W14X246', 'W14X246', 'W14X246', 'W14X211', 'W14X211', 'W14X176', 'W14X176' ] iColumn = [ 'W14X287', 'W14X287', 'W14X287', 'W14X246', 'W14X246', 'W14X211', 'W14X211' ] columns = [eColumn, iColumn, eColumn] WSection = { 'W14X176': [51.7, 2150.], 'W14X211': [62.1, 2670.], 'W14X246': [72.3, 3230.], 'W14X287': [84.4, 3910.], 'W24X110': [32.5, 3330.], 'W24X130': [38.3, 4020.], 'W24X160': [47.1, 5120.] } nodeTag = 1 # procedure to read 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) # add the nodes # - floor at a time yLoc = 0. for j in range(0, numFloor + 1): xLoc = 0. for i in range(0, numBay + 1): ops.node(nodeTag, xLoc, yLoc) xLoc += bayWidth nodeTag += 1 if j < numFloor: storyHeight = storyHeights[j] yLoc += storyHeight # fix first floor ops.fix(1, 1, 1, 1) ops.fix(2, 1, 1, 1) ops.fix(3, 1, 1, 1) #rigid floor constraint & masses nodeTagR = 5 nodeTag = 4 for j in range(1, numFloor + 1): for i in range(0, numBay + 1): if nodeTag != nodeTagR: ops.equalDOF(nodeTagR, nodeTag, 1) else: ops.mass(nodeTagR, massX, 1.0e-10, 1.0e-10) nodeTag += 1 nodeTagR += numBay + 1 # add the columns # add column element ops.geomTransf(coordTransf, 1) eleTag = 1 for j in range(0, numBay + 1): end1 = j + 1 end2 = end1 + numBay + 1 thisColumn = columns[j] for i in range(0, numFloor): secType = thisColumn[i] ElasticBeamColumn(eleTag, end1, end2, secType, E, 1, M, massType) end1 = end2 end2 += numBay + 1 eleTag += 1 # add beam elements for j in range(1, numFloor + 1): end1 = (numBay + 1) * j + 1 end2 = end1 + 1 secType = beams[j - 1] for i in range(0, numBay): ElasticBeamColumn(eleTag, end1, end2, secType, E, 1, M, massType) end1 = end2 end2 = end1 + 1 eleTag += 1 # calculate eigenvalues & print results numEigen = 7 eigenValues = ops.eigen(numEigen) PI = 2 * asin(1.0) # # apply loads for static analysis & perform analysis # ops.timeSeries('Linear', 1) ops.pattern('Plain', 1, 1) ops.load(22, 20.0, 0., 0.) ops.load(19, 15.0, 0., 0.) ops.load(16, 12.5, 0., 0.) ops.load(13, 10.0, 0., 0.) ops.load(10, 7.5, 0., 0.) ops.load(7, 5.0, 0., 0.) ops.load(4, 2.5, 0., 0.) ops.integrator('LoadControl', 1.0) ops.algorithm('Linear') ops.analysis('Static') ops.analyze(1) # determine PASS/FAILURE of test ok = 0 # # print pretty output of comparsions # # SAP2000 SeismoStruct comparisonResults = [[ 1.2732, 0.4313, 0.2420, 0.1602, 0.1190, 0.0951, 0.0795 ], [1.2732, 0.4313, 0.2420, 0.1602, 0.1190, 0.0951, 0.0795]] print("\n\nPeriod Comparisons:") print('{:>10}{:>15}{:>15}{:>15}'.format('Period', 'OpenSees', 'SAP2000', 'SeismoStruct')) #formatString {%10s%15.5f%15.4f%15.4f} for i in range(0, numEigen): lamb = eigenValues[i] period = 2 * PI / sqrt(lamb) print('{:>10}{:>15.5f}{:>15.4f}{:>15.4f}'.format( i + 1, period, comparisonResults[0][i], comparisonResults[1][i])) resultOther = comparisonResults[0][i] if abs(period - resultOther) > 9.99e-5: ok = -1 # print table of camparsion # Parameter SAP2000 SeismoStruct comparisonResults = [[ "Disp Top", "Axial Force Bottom Left", "Moment Bottom Left" ], [1.45076, 69.99, 2324.68], [1.451, 70.01, 2324.71]] tolerances = [9.99e-6, 9.99e-3, 9.99e-3] print("\n\nSatic Analysis Result Comparisons:") print('{:>30}{:>15}{:>15}{:>15}'.format('Parameter', 'OpenSees', 'SAP2000', 'SeismoStruct')) for i in range(3): response = ops.eleResponse(1, 'forces') if i == 0: result = ops.nodeDisp(22, 1) elif i == 1: result = abs(response[1]) else: result = response[2] print('{:>30}{:>15.3f}{:>15.2f}{:>15.2f}'.format( comparisonResults[0][i], result, comparisonResults[1][i], comparisonResults[2][i])) resultOther = comparisonResults[1][i] tol = tolerances[i] if abs(result - resultOther) > tol: ok = -1 print("failed-> ", i, abs(result - resultOther), tol) assert ok == 0
def test_EigenAnal_twoStoryFrame1(): ops.wipe() #input m = 100.0 / 386.0 numModes = 2 #material A = 63.41 I = 320.0 E = 29000.0 #geometry L = 240. h = 120. # define the model #--------------------------------- #model builder ops.model('BasicBuilder', '-ndm', 2, '-ndf', 3) # nodal coordinates: ops.node(1, 0., 0.) ops.node(2, L, 0.) ops.node(3, 0., h) ops.node(4, L, h) ops.node(5, 0., 2 * h) ops.node(6, L, 2 * h) # Single point constraints -- Boundary Conditions ops.fix(1, 1, 1, 1) ops.fix(2, 1, 1, 1) # assign mass ops.mass(3, m, 0., 0.) ops.mass(4, m, 0., 0.) ops.mass(5, m / 2., 0., 0.) ops.mass(6, m / 2., 0., 0.) # define geometric transformation: TransfTag = 1 ops.geomTransf('Linear', TransfTag) # define elements: # columns ops.element('elasticBeamColumn', 1, 1, 3, A, E, 2. * I, TransfTag) ops.element('elasticBeamColumn', 2, 3, 5, A, E, I, TransfTag) ops.element('elasticBeamColumn', 3, 2, 4, A, E, 2. * I, TransfTag) ops.element('elasticBeamColumn', 4, 4, 6, A, E, I, TransfTag) # beams ops.element('elasticBeamColumn', 5, 3, 4, A, E, 2 * I, TransfTag) ops.element('elasticBeamColumn', 6, 5, 6, A, E, I, TransfTag) # record eigenvectors #---------------------- # for { k 1 } { k <= numModes } { incr k } { # recorder Node -file format "modes/mode%i.out" k -nodeRange 1 6 -dof 1 2 3 "eigen k" # } # perform eigen analysis #----------------------------- lamb = ops.eigen(numModes) # calculate frequencies and periods of the structure #--------------------------------------------------- omega = [] f = [] T = [] pi = 3.141593 for lam in lamb: print("labmbda = ", lam) omega.append(math.sqrt(lam)) f.append(math.sqrt(lam) / (2 * pi)) T.append((2 * pi) / math.sqrt(lam)) print("periods are ", T) # write the output file cosisting of periods #-------------------------------------------- period = "Periods.txt" Periods = open(period, "w") for t in T: Periods.write(repr(t) + '\n') Periods.close() # create display for mode shapes #--------------------------------- # windowTitle xLoc yLoc xPixels yPixels # recorder display "Mode Shape 1" 10 10 500 500 -wipe # prp h h 1 # projection reference point (prp) defines the center of projection (viewer eye) # vup 0 1 0 # view-up vector (vup) # vpn 0 0 1 # view-plane normal (vpn) # viewWindow -200 200 -200 200 # coordiantes of the window relative to prp # display -1 5 20 # the 1st arg. is the tag for display mode (ex. -1 is for the first mode shape) # the 2nd arg. is magnification factor for nodes, the 3rd arg. is magnif. factor of deformed shape # recorder display "Mode Shape 2" 10 510 500 500 -wipe # prp h h 1 # vup 0 1 0 # vpn 0 0 1 # viewWindow -200 200 -200 200 # display -2 5 20 # Run a one step gravity load with no loading (to record eigenvectors) #----------------------------------------------------------------------- ops.integrator('LoadControl', 0.0, 1, 0.0, 0.0) # Convergence test # tolerance maxIter displayCode ops.test('EnergyIncr', 1.0e-10, 100, 0) # Solution algorithm ops.algorithm('Newton') # DOF numberer ops.numberer('RCM') # Constraint handler ops.constraints('Transformation') # System of equations solver ops.system('ProfileSPD') ops.analysis('Static') res = ops.analyze(1) if res < 0: print("Modal analysis failed") # get values of eigenvectors for translational DOFs #--------------------------------------------------- f11 = ops.nodeEigenvector(3, 1, 1) f21 = ops.nodeEigenvector(5, 1, 1) f12 = ops.nodeEigenvector(3, 2, 1) f22 = ops.nodeEigenvector(5, 2, 1) print("eigenvector 1: ", [f11 / f21, f21 / f21]) print("eigenvector 2: ", [f12 / f22, f22 / f22]) assert abs(T[0] - 0.628538768190688) < 1e-12 and abs( T[1] - 0.2359388635361575) < 1e-12 and abs( f11 / f21 - 0.3869004256389493) < 1e-12 and abs( f21 / f21 - 1.0) < 1e-12 and abs(f12 / f22 + 1.2923221761110006 ) < 1e-12 and abs(f22 / f22 - 1.0) < 1e-12
def get_inelastic_response(mass, k_spring, f_yield, motion, dt, xi=0.05, r_post=0.0): """ Run seismic analysis of a nonlinear SDOF :param mass: SDOF mass :param k_spring: spring stiffness :param f_yield: yield strength :param motion: list, acceleration values :param dt: float, time step of acceleration values :param xi: damping ratio :param r_post: post-yield stiffness :return: """ opy.wipe() opy.model('basic', '-ndm', 2, '-ndf', 3) # 2 dimensions, 3 dof per node # Establish nodes bot_node = 1 top_node = 2 opy.node(bot_node, 0., 0.) opy.node(top_node, 0., 0.) # Fix bottom node opy.fix(top_node, opc.FREE, opc.FIXED, opc.FIXED) opy.fix(bot_node, opc.FIXED, opc.FIXED, opc.FIXED) # Set out-of-plane DOFs to be slaved opy.equalDOF(1, 2, *[2, 3]) # nodal mass (weight / g): opy.mass(top_node, mass, 0., 0.) # Define material bilinear_mat_tag = 1 mat_type = "Steel01" mat_props = [f_yield, k_spring, r_post] opy.uniaxialMaterial(mat_type, bilinear_mat_tag, *mat_props) # Assign zero length element beam_tag = 1 opy.element('zeroLength', beam_tag, bot_node, top_node, "-mat", bilinear_mat_tag, "-dir", 1, '-doRayleigh', 1) # Define the dynamic analysis load_tag_dynamic = 1 pattern_tag_dynamic = 1 values = list(-1 * motion) # should be negative opy.timeSeries('Path', load_tag_dynamic, '-dt', dt, '-values', *values) opy.pattern('UniformExcitation', pattern_tag_dynamic, opc.X, '-accel', load_tag_dynamic) # set damping based on first eigen mode angular_freq2 = opy.eigen('-fullGenLapack', 1) if hasattr(angular_freq2, '__len__'): angular_freq2 = angular_freq2[0] angular_freq = angular_freq2**0.5 alpha_m = 0.0 beta_k = 2 * xi / angular_freq beta_k_comm = 0.0 beta_k_init = 0.0 opy.rayleigh(alpha_m, beta_k, beta_k_init, beta_k_comm) # Run the dynamic analysis opy.wipeAnalysis() opy.algorithm('Newton') opy.system('SparseGeneral') opy.numberer('RCM') opy.constraints('Transformation') opy.integrator('Newmark', 0.5, 0.25) opy.analysis('Transient') tol = 1.0e-10 iterations = 10 opy.test('EnergyIncr', tol, iterations, 0, 2) analysis_time = (len(values) - 1) * dt analysis_dt = 0.001 outputs = { "time": [], "rel_disp": [], "rel_accel": [], "rel_vel": [], "force": [] } while opy.getTime() < analysis_time: curr_time = opy.getTime() opy.analyze(1, analysis_dt) outputs["time"].append(curr_time) outputs["rel_disp"].append(opy.nodeDisp(top_node, 1)) outputs["rel_vel"].append(opy.nodeVel(top_node, 1)) outputs["rel_accel"].append(opy.nodeAccel(top_node, 1)) opy.reactions() outputs["force"].append( -opy.nodeReaction(bot_node, 1)) # Negative since diff node opy.wipe() for item in outputs: outputs[item] = np.array(outputs[item]) return outputs
#print(path1) h = 432.0 w = 504.0 op.node(1, 0.0, 0.0) op.node(2, h, 0.0) op.node(3, 0.0, w) op.node(4, h, w) op.fix(1, 1,1,1) op.fix(2, 1,1,1) op.fix(3, 0,0,0) op.fix(4, 0,0,0) op.mass(3, 5.18, 0.0, 0.0) op.mass(4, 5.18, 0.0, 0.0) op.geomTransf('Linear', 1) A = 3600000000.0 E = 4227.0 Iz = 1080000.0 A1 = 5760000000.0 Iz1 = 4423680.0 op.element('elasticBeamColumn', 1, 1, 3, A, E, Iz, 1) op.element('elasticBeamColumn', 2, 2, 4, A, E, Iz, 1) op.element('elasticBeamColumn', 3, 3, 4, A1, E, Iz1, 1) op.recorder('Node', '-file', 'Data-1b/DFree.out','-time', '-node', 3,4, '-dof', 1,2,3, 'disp') op.recorder('Node', '-file', 'Data-1b/DBase.out','-time', '-node', 1,2, '-dof', 1,2,3, 'disp')
ABeam = HBeam * BBeam IzCol = (BCol * math.pow(HCol, 3)) / 12 # Column moment of inertia IzBeam = (BBeam * math.pow(HBeam, 3)) / 12 # Beam moment of inertia op.node(1, 0.0, 0.0) op.node(2, LBeam, 0.0) op.node(3, 0.0, LCol) op.node(4, LBeam, LCol) op.fix(1, 1, 1, 0) op.fix(2, 1, 1, 0) IDctrlNode = 2 IDctrlDOF = 1 op.mass(3, Mass, 0.0, 0.0) op.mass(4, Mass, 0.0, 0.0) ColSecTag = 1 # assign a tag number to the column section BeamSecTag = 2 # assign a tag number to the beam section coverCol = 6.0 * inch # Column cover to reinforcing steel NA. numBarsCol = 10 # number of longitudinal-reinforcement bars in column. (symmetric top & bot) barAreaCol = 2.25 * inch2 # area of longitudinal-reinforcement bars # MATERIAL parameters IDconcU = 1 # material ID tag -- unconfined cover concrete (here used for complete section) IDreinf = 2 # material ID tag -- reinforcement # nominal concrete compressive strength fc = -4.0 * ksi # CONCRETE Compressive Strength (+Tension, -Compression)
def get_inelastic_response(mass, k_spring, f_yield, motion, dt, xi=0.05, r_post=0.0): """ Run seismic analysis of a nonlinear SDOF :param mass: SDOF mass :param k_spring: spring stiffness :param f_yield: yield strength :param motion: list, acceleration values :param dt: float, time step of acceleration values :param xi: damping ratio :param r_post: post-yield stiffness :return: """ osi = o3.OpenSeesInstance(ndm=2) # Establish nodes bot_node = o3.node.Node(osi, 0, 0) top_node = o3.node.Node(osi, 0, 0) # Fix bottom node opy.fix(top_node.tag, o3.cc.FREE, o3.cc.FIXED, o3.cc.FIXED) opy.fix(bot_node.tag, o3.cc.FIXED, o3.cc.FIXED, o3.cc.FIXED) # Set out-of-plane DOFs to be slaved opy.equalDOF(top_node.tag, bot_node.tag, *[o3.cc.Y, o3.cc.ROTZ]) # nodal mass (weight / g): opy.mass(top_node.tag, mass, 0., 0.) # Define material bilinear_mat = o3.uniaxial_material.Steel01(osi, fy=f_yield, e0=k_spring, b=r_post) # Assign zero length element, # Note: pass actual node and material objects into element o3.element.ZeroLength(osi, [bot_node, top_node], mats=[bilinear_mat], dirs=[o3.cc.DOF2D_X], r_flag=1) # Define the dynamic analysis load_tag_dynamic = 1 pattern_tag_dynamic = 1 values = list(-1 * motion) # should be negative opy.timeSeries('Path', load_tag_dynamic, '-dt', dt, '-values', *values) opy.pattern('UniformExcitation', pattern_tag_dynamic, o3.cc.X, '-accel', load_tag_dynamic) # set damping based on first eigen mode angular_freq2 = opy.eigen('-fullGenLapack', 1) if hasattr(angular_freq2, '__len__'): angular_freq2 = angular_freq2[0] angular_freq = angular_freq2**0.5 beta_k = 2 * xi / angular_freq o3.rayleigh.Rayleigh(osi, alpha_m=0.0, beta_k=beta_k, beta_k_init=0.0, beta_k_comm=0.0) # Run the dynamic analysis opy.wipeAnalysis() newmark_gamma = 0.5 newmark_beta = 0.25 o3.algorithm.Newton(osi) o3.constraints.Transformation(osi) o3.algorithm.Newton(osi) o3.numberer.RCM(osi) o3.system.SparseGeneral(osi) o3.integrator.Newmark(osi, newmark_gamma, newmark_beta) o3.analysis.Transient(osi) o3.test_check.EnergyIncr(osi, tol=1.0e-10, max_iter=10) analysis_time = (len(values) - 1) * dt analysis_dt = 0.001 outputs = { "time": [], "rel_disp": [], "rel_accel": [], "rel_vel": [], "force": [] } while opy.getTime() < analysis_time: curr_time = opy.getTime() opy.analyze(1, analysis_dt) outputs["time"].append(curr_time) outputs["rel_disp"].append(opy.nodeDisp(top_node.tag, o3.cc.X)) outputs["rel_vel"].append(opy.nodeVel(top_node.tag, o3.cc.X)) outputs["rel_accel"].append(opy.nodeAccel(top_node.tag, o3.cc.X)) opy.reactions() outputs["force"].append(-opy.nodeReaction( bot_node.tag, o3.cc.X)) # Negative since diff node opy.wipe() for item in outputs: outputs[item] = np.array(outputs[item]) return outputs
# loaded nodes mid = int(((nx + 1) * (ny + 1) + 1) / 2) side1 = int((nx + 2) / 2) side2 = int((nx + 1) * (ny + 1) - side1 + 1) # generate the nodes and elements # numX numY startNode startEle eleType eleArgs? coords? ops.block2D(nx, ny, 1, 1, "ShellMITC4", 1, 1, -20.0, 0.0, 0.0, 2, -20.0, 0.0, 40.0, 3, 20.0, 0.0, 40.0, 4, 20.0, 0.0, 0.0, 5, -10.0, 10.0, 20.0, 7, 10.0, 10.0, 20.0, 9, 0.0, 10.0, 20.0) # define the boundary conditions ops.fixZ(0.0, 1, 1, 1, 0, 1, 1) ops.fixZ(40.0, 1, 1, 1, 0, 1, 1) ops.mass(20, 10.0, 10.0, 10.0, 0.0, 0.0, 0.0) # create a Linear time series ops.timeSeries("Linear", 1) # add some loads ops.pattern("Plain", 1, 1, "-fact", 1.0) ops.load(mid, 0.0, -0.50, 0.0, 0.0, 0.0, 0.0) ops.load(side1, 0.0, -0.25, 0.0, 0.0, 0.0, 0.0) ops.load(side2, 0.0, -0.25, 0.0, 0.0, 0.0, 0.0) # ------------------------ # Start of static analysis # ------------------------ # Load control with variable load steps # init Jd min max
def RectCFSTSteelHysteretic(length: float, secHeight: float, secWidth: float, thickness: float, concrete_grade: float, steel_grade: float, axial_load_ratio: float, disp_control: Iterable[float]): '''Peakstress: concrete peak stress \n crushstress: concrete crush stress ''' #disp input # dispControl=[3,-3,7,-7,14,-14,14,-14,14,-14,28,-28,28,-28,28,-28,42,-42,42,-42,42,-42,56,-56,0] dispControl = tuple(disp_control) #Geometry # length=740 # secHeight=100 # secWidth=100 # thickness=7 #Materials ##steel_tube point1Steel, point2Steel, point3Steel = [460, 0.00309], [460, 0.02721 ], [530, 0.26969] point1SteelNegative, point2SteelNegative, point3SteelNegative = [ -460, -0.00309 ], [-460, -0.02721], [-736, -0.26969] pinchX = 0.2 pinchY = 0.7 damagedFactor = 0.01 densitySteel = 7.8 / 1000000000 ##concrete peakPointConcrete, crushPointConcrete = [-221.76, -0.0102], [-195, -0.051] unloadingLambda = 0.2 tensileStrength = 5.6 tensilePostStiffness = 0.01 densityConcrete = 2.4 / 1000000000 #axialLoadRatio # axialLoadRatio=0.4 #fix condition Fixed = 1 #section parameter areaConcrete = (secHeight - 2 * thickness) * (secWidth - 2 * thickness) areaSteel = secWidth * secHeight - areaConcrete # fck,Ec,nuConcrete=128.1,4.34*10000,0.21 # fy,epsilonSteely,Es,nuSteel=444.6,3067/1000000,1.99*100000,0.29 fck = peakPointConcrete[0] fy = point1Steel[0] #Computate parameter axialLoad = (areaConcrete * fck + areaSteel * fy) * axial_load_ratio #loading control parameter # for item in dispControlPercentage: # dispControl.append(item*length) # dispControl.append(-item*length) # print('displist:'dispControl) #wipe and build a model ops.wipe() ops.model('basic', '-ndm', 2, '-ndf', 3) #node coordinates meshNumLength = 5 meshVerticalSize = length / meshNumLength meshSteelSize = 10 nodes = [(i + 1, meshVerticalSize * i) for i in range(int(length / meshVerticalSize) + 1)] for item in nodes: ops.node(item[0], 0, item[1]) #boundary condition ops.fix(1, 1, 1, 1) # if bool(Fixed): # ops.fix(int(length/meshVerticalSize)+1,0,0,1) ##uppper constrain condition: free or no-rotation #mass defination(concentrate mass to nodes) nodeMassSteel = areaSteel * meshVerticalSize * densitySteel nodeMassConcrete = areaConcrete * meshVerticalSize * densityConcrete nodeMass = nodeMassSteel + nodeMassConcrete for i in range(len(nodes) - 1): arg = [0., nodeMass, 0.] ops.mass(i + 2, *arg) #transformation: ops.geomTransf('Linear', 1) #material defination ##steel ops.uniaxialMaterial('Hysteretic', 1001, *point1Steel, *point2Steel, *point3Steel, *point1SteelNegative, *point2SteelNegative, *point3SteelNegative, pinchX, pinchY, damagedFactor, 0, 0.0) ##concrete ##using concrete01 #peakPointConcrete,crushPointConcrete=[110.6,0.00544],[22.11,0.09145] #ops.uniaxialMaterial('Concrete01',1,*peakPointConcrete,*crushPointConcrete) ###using concrete02 ops.uniaxialMaterial('Concrete02', 1, *peakPointConcrete, *crushPointConcrete, unloadingLambda, tensileStrength, tensilePostStiffness) #section defination ops.section('Fiber', 1) ##inner concrete fiber fiberPointI, fiberPointJ = [ -(secHeight - 2 * thickness) / 2, -(secWidth - 2 * thickness) / 2 ], [(secHeight - 2 * thickness) / 2, (secWidth - 2 * thickness) / 2] ops.patch('rect', 1, 10, 1, *fiberPointI, *fiberPointJ ) # https://opensees.berkeley.edu/wiki/index.php/Patch_Command ##outside steel fiber steelFiberProperty = { 'height': meshSteelSize, 'area': meshSteelSize * thickness } steelFiberPropertyLeftAndRight = { 'height': secWidth, 'area': secWidth * thickness } ###left and right leftEdgeFiberY, rightEdgeFiberY = -( secHeight - 2 * thickness) / 2 - thickness / 2, ( secHeight - 2 * thickness) / 2 + thickness / 2 #rightEdgeFiberY might be wrong leftandRightEdgeFiberZ = [ -secWidth / 2 + steelFiberPropertyLeftAndRight['height'] * (1 / 2 + N) for N in range(int(secWidth / steelFiberPropertyLeftAndRight['height'])) ] ###up and down upEdgeFiberZ, downEdgeFiberZ = -( secWidth - 2 * thickness) / 2 - thickness / 2, ( secWidth - 2 * thickness) / 2 + thickness / 2 upandDownEdgeFiberY = [ -secHeight / 2 + thickness + steelFiberProperty['height'] * (1 / 2 + N) for N in range( int((secHeight - 2 * thickness) / steelFiberProperty['height'])) ] for i in leftandRightEdgeFiberZ: i = float(i) ops.fiber(float(leftEdgeFiberY), i, steelFiberPropertyLeftAndRight['area'], 1001) ops.fiber(float(rightEdgeFiberY), i, steelFiberPropertyLeftAndRight['area'], 1001) for j in upandDownEdgeFiberY: j = float(j) ops.fiber(j, float(upEdgeFiberZ), steelFiberProperty['area'], 1001) ops.fiber(j, float(downEdgeFiberZ), steelFiberProperty['area'], 1001) #beamInergration defination ops.beamIntegration('NewtonCotes', 1, 1, 5) #element defination for i in range(len(nodes) - 1): ops.element('dispBeamColumn', i + 1, i + 1, i + 2, 1, 1) #recorders ops.recorder('Node', '-file', 'topLateralDisp.txt', '-time', '-node', int(length / meshVerticalSize + 1), '-dof', 1, 2, 'disp') ops.recorder('Node', '-file', 'topLateralForce.txt', '-time', '-node', int(length / meshVerticalSize + 1), '-dof', 1, 2, 'reaction') ops.recorder('Element', '-file', 'topElementForce.txt', '-time', '-ele', int(length / meshVerticalSize), 'force') #gravity load ops.timeSeries('Linear', 1) ops.pattern('Plain', 1, 1) ops.load(int(length / meshVerticalSize + 1), 0, axialLoad, 0) ops.constraints('Plain') ops.numberer('RCM') ops.system('BandGeneral') ##convertage test tolerant, allowedIteralStep = 1 / 1000000, 6000 ops.test('NormDispIncr', tolerant, allowedIteralStep) ops.algorithm('Newton') ops.integrator('LoadControl', 0.1) ops.analysis('Static') ops.analyze(10) ops.loadConst('-time', 0) #lateraldisp analysis ops.pattern('Plain', 2, 1) ops.load(int(length / meshVerticalSize + 1), 100, 0, 0) for i in range(len(dispControl)): if i == 0: ops.integrator('DisplacementControl', int(length / meshVerticalSize + 1), 1, 0.1) ops.analyze(int(dispControl[i] / 0.1)) # print('Working on disp round',i) else: if dispControl[i] >= 0: ops.integrator('DisplacementControl', int(length / meshVerticalSize + 1), 1, 0.1) ops.analyze(int( abs(dispControl[i] - dispControl[i - 1]) / 0.1)) # print('Working on disp round',i) else: ops.integrator('DisplacementControl', int(length / meshVerticalSize + 1), 1, -0.1) ops.analyze(int( abs(dispControl[i] - dispControl[i - 1]) / 0.1))
def RunAnalysis(): # ---------------------------- # Start of model generation # ---------------------------- # remove existing model ops.wipe() ops.model("BasicBuilder", "-ndm", 3, "-ndf", 6) # set default units ops.defaultUnits("-force", "kip", "-length", "in", "-time", "sec", "-temp", "F") # Define the section # ------------------ # secTag E nu h rho ops.section("ElasticMembranePlateSection", 1, 3.0E3, 0.25, 1.175, 1.27) # Define geometry # --------------- # these should both be even nx = 10 ny = 2 # loaded nodes mid = int(((nx + 1) * (ny + 1) + 1) / 2) side1 = int((nx + 2) / 2) side2 = int((nx + 1) * (ny + 1) - side1 + 1) # generate the nodes and elements # numX numY startNode startEle eleType eleArgs? coords? ops.block2D(nx, ny, 1, 1, "ShellMITC4", 1, 1, -20.0, 0.0, 0.0, 2, -20.0, 0.0, 40.0, 3, 20.0, 0.0, 40.0, 4, 20.0, 0.0, 0.0, 5, -10.0, 10.0, 20.0, 7, 10.0, 10.0, 20.0, 9, 0.0, 10.0, 20.0) # define the boundary conditions ops.fixZ(0.0, 1, 1, 1, 0, 1, 1) ops.fixZ(40.0, 1, 1, 1, 0, 1, 1) ops.mass(20, 10.0, 10.0, 10.0, 0.0, 0.0, 0.0) # create a Linear time series ops.timeSeries("Linear", 1) # add some loads ops.pattern("Plain", 1, 1, "-fact", 1.0) ops.load(mid, 0.0, -0.50, 0.0, 0.0, 0.0, 0.0) ops.load(side1, 0.0, -0.25, 0.0, 0.0, 0.0, 0.0) ops.load(side2, 0.0, -0.25, 0.0, 0.0, 0.0, 0.0) # ------------------------ # Start of static analysis # ------------------------ # Load control with variable load steps # init Jd min max ops.integrator("LoadControl", 1.0, 1, 1.0, 10.0) ops.test("EnergyIncr", 1.0E-10, 20, 0) ops.algorithm("Newton") ops.numberer("RCM") ops.constraints("Plain") ops.system("SparseGeneral", "-piv") ops.analysis("Static") ops.analyze(5) # --------------------------------------- # Create and Perform the dynamic analysis # --------------------------------------- # Remove the static analysis & reset the time to 0.0 ops.wipeAnalysis() ops.setTime(0.0) # Now remove the loads and let the beam vibrate ops.remove("loadPattern", 1) Model = 'test' LoadCase = 'Transient' LoadCase2 = 'Transient_5s' opp.createODB(Model, LoadCase, Nmodes=3, recorders=[]) opp.createODB(Model, LoadCase2, Nmodes=3, deltaT=5., recorders=[]) # Create the transient analysis ops.test("EnergyIncr", 1.0E-10, 20, 0) ops.algorithm("Newton") ops.numberer("RCM") ops.constraints("Plain") ops.system("SparseGeneral", "-piv") ops.integrator("Newmark", 0.50, 0.25) ops.analysis("Transient") # Perform the transient analysis (20 sec) ops.analyze(100, 0.2)
M = 0. coordTransf = "Linear" # Linear, PDelta, Corotational massType = "-lMass" # -lMass, -cMass nodeTag = 1 # add the nodes # - floor at a time zLoc = 0. for k in range(0, numFloor + 1): xLoc = 0. for i in range(0, numBayX + 1): yLoc = 0. for j in range(0, numBayY + 1): ops.node(nodeTag, xLoc, yLoc, zLoc) ops.mass(nodeTag, massX, massX, 0.01, 1.0e-10, 1.0e-10, 1.0e-10) if k == 0: ops.fix(nodeTag, 1, 1, 1, 1, 1, 1) yLoc += bayWidthY nodeTag += 1 xLoc += bayWidthX if k < numFloor: storyHeight = storyHeights[k] zLoc += storyHeight # add column element ops.geomTransf(coordTransf, 1, 1, 0, 0)
# beam integration inteTag = 1 numpts = 2 ops.beamIntegration('Legendre', inteTag, secTag, numpts) # beam mesh beamTag = 6 ndf = 3 ops.mesh('line', beamTag, 2, 12, 13, beam_id, ndf, h, 'dispBeamColumn', transfTag, inteTag) ndmass = bmass / len(ops.getNodeTags('-mesh', beamTag)) for nd in ops.getNodeTags('-mesh', beamTag): ops.mass(nd, ndmass, ndmass, 0.0) # fluid mesh fluidTag = 4 ndf = 2 ops.mesh('line', 1, 10, 4, 5, 8, 9, 10, 11, 7, 6, 12, 2, wall_id, ndf, h) ops.mesh('line', 2, 3, 2, 1, 4, wall_id, ndf, h) ops.mesh('line', 3, 3, 2, 3, 4, water_bound_id, ndf, h) eleArgs = ['PFEMElementBubble', rho, mu, b1, b2, thk, kappa] ops.mesh('tri', fluidTag, 2, 2, 3, water_body_id, ndf, h, *eleArgs) # wall mesh wallTag = 5 ops.mesh('tri', wallTag, 2, 1, 2, wall_id, ndf, h)
def test_Ex1aCanti2DEQmodif(): # SET UP ---------------------------------------------------------------------------- ops.wipe() # clear opensees model ops.model('basic', '-ndm', 2, '-ndf', 3) # 2 dimensions, 3 dof per node # file mkdir data # create data directory # define GEOMETRY ------------------------------------------------------------- # nodal coordinates: ops.node(1, 0., 0.) # node#, X Y ops.node(2, 0., 432.) # Single point constraints -- Boundary Conditions ops.fix(1, 1, 1, 1) # node DX DY RZ # nodal masses: ops.mass(2, 5.18, 0., 0.) # node#, Mx My Mz, Mass=Weight/g. # Define ELEMENTS ------------------------------------------------------------- # define geometric transformation: performs a linear geometric transformation of beam stiffness and resisting force from the basic system to the global-coordinate system ops.geomTransf('Linear', 1) # associate a tag to transformation # connectivity: ops.element('elasticBeamColumn', 1, 1, 2, 3600.0, 3225.0, 1080000.0, 1) # define GRAVITY ------------------------------------------------------------- ops.timeSeries('Linear', 1) ops.pattern( 'Plain', 1, 1, ) ops.load(2, 0., -2000., 0.) # node#, FX FY MZ -- superstructure-weight ops.constraints('Plain') # how it handles boundary conditions ops.numberer( 'Plain' ) # renumber dof's to minimize band-width (optimization), if you want to ops.system( 'BandGeneral' ) # how to store and solve the system of equations in the analysis ops.algorithm('Linear') # use Linear algorithm for linear analysis ops.integrator( 'LoadControl', 0.1 ) # determine the next time step for an analysis, # apply gravity in 10 steps ops.analysis('Static') # define type of analysis static or transient ops.analyze(10) # perform gravity analysis ops.loadConst('-time', 0.0) # hold gravity constant and restart time # DYNAMIC ground-motion analysis ------------------------------------------------------------- # create load pattern G = 386.0 ops.timeSeries( 'Path', 2, '-dt', 0.005, '-filePath', 'A10000.dat', '-factor', G ) # define acceleration vector from file (dt=0.005 is associated with the input file gm) ops.pattern( 'UniformExcitation', 2, 1, '-accel', 2) # define where and how (pattern tag, dof) acceleration is applied # set damping based on first eigen mode evals = ops.eigen('-fullGenLapack', 1) freq = evals[0]**0.5 dampRatio = 0.02 ops.rayleigh(0., 0., 0., 2 * dampRatio / freq) # display displacement shape of the column # recorder display "Displaced shape" 10 10 500 500 -wipe # prp 200. 50. 1 # vup 0 1 0 # vpn 0 0 1 # display 1 5 40 # create the analysis ops.wipeAnalysis() # clear previously-define analysis parameters ops.constraints('Plain') # how it handles boundary conditions ops.numberer( 'Plain' ) # renumber dof's to minimize band-width (optimization), if you want to ops.system( 'BandGeneral' ) # how to store and solve the system of equations in the analysis ops.algorithm('Linear') # use Linear algorithm for linear analysis ops.integrator('Newmark', 0.5, 0.25) # determine the next time step for an analysis ops.analysis('Transient') # define type of analysis: time-dependent ops.analyze(3995, 0.01) # apply 3995 0.01-sec time steps in analysis u2 = ops.nodeDisp(2, 2) print("u2 = ", u2) assert abs(u2 + 0.07441860465116277579) < 1e-12 ops.wipe() print("=========================================")
def __init__(self): # AIが取れるアクションの設定 self.action = np.array([ 0, 0.02, 0.03, 0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1 ]) self.naction = len(self.action) self.beta = 1 / 4 # 1質点系モデル self.T0 = 4 self.h = self.action[0] self.hs = [self.h] self.m = 100 self.k = 4 * np.pi**2 * self.m / self.T0**2 # 入力地震動 self.dt = 0.02 to_meter = 0.01 # cmをmに変換する値 self.wave_url = 'https://github.com/kakemotokeita/dqn-seismic-control/blob/master/wave/sample.csv' with urllib.request.urlopen(self.wave_url) as wave_file: self.wave_data = np.loadtxt( wave_file, usecols=(0, ), delimiter=',', skiprows=3) * to_meter # OpenSees設定 op.wipe() op.model('basic', '-ndm', 2, '-ndf', 3) # 2 dimensions, 3 dof per node # 節点 self.bot_node = 1 self.top_node = 2 op.node(self.bot_node, 0., 0.) op.node(self.top_node, 0., 0.) # 境界条件 op.fix(self.top_node, FREE, FIXED, FIXED) op.fix(self.bot_node, FIXED, FIXED, FIXED) op.equalDOF(1, 2, *[Y, ROTZ]) # 質量 op.mass(self.top_node, self.m, 0., 0.) # 弾性剛性 elastic_mat_tag = 1 Fy = 1e10 E0 = self.k b = 1.0 op.uniaxialMaterial('Steel01', elastic_mat_tag, Fy, E0, b) # Assign zero length element beam_tag = 1 op.element('zeroLength', beam_tag, self.bot_node, self.top_node, "-mat", elastic_mat_tag, "-dir", 1, '-doRayleigh', 1) # Define the dynamic analysis load_tag_dynamic = 1 pattern_tag_dynamic = 1 self.values = list(-1 * self.wave_data) # should be negative op.timeSeries('Path', load_tag_dynamic, '-dt', self.dt, '-values', *self.values) op.pattern('UniformExcitation', pattern_tag_dynamic, X, '-accel', load_tag_dynamic) # 減衰の設定 self.w0 = op.eigen('-fullGenLapack', 1)[0]**0.5 self.alpha_m = 0.0 self.beta_k = 2 * self.h / self.w0 self.beta_k_init = 0.0 self.beta_k_comm = 0.0 op.rayleigh(self.alpha_m, self.beta_k, self.beta_k_init, self.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') tol = 1.0e-10 iterations = 10 op.test('EnergyIncr', tol, iterations, 0, 2) self.i_pre = 0 self.i = 0 self.i_next = 0 self.time = 0 self.analysis_time = (len(self.values) - 1) * self.dt self.dis = 0 self.vel = 0 self.acc = 0 self.a_acc = 0 self.force = 0 self.resp = { "time": [], "dis": [], "acc": [], "a_acc": [], "vel": [], "force": [], } self.done = False
BCol = 5.0 * ft # Column Width PCol = Weight # nodal dead-load weight per column #g = 386.4 Mass = PCol / g ACol = HCol * BCol # cross-sectional area IzCol = (BCol * math.pow(HCol, 3)) / 12 # Column moment of inertia op.node(1, 0.0, 0.0) op.node(2, 0.0, LCol) op.fix(1, 1, 1, 1) IDctrlNode = 2 IDctrlDOF = 1 op.mass(2, Mass, 1e-9, 0.0) ColSecTag = 1 # assign a tag number to the column section coverCol = 5.0 * inch # Column cover to reinforcing steel NA. numBarsCol = 20 # number of longitudinal-reinforcement bars in column. (symmetric top & bot) barAreaCol = 2.25 * inch2 # area of longitudinal-reinforcement bars # MATERIAL parameters IDconcU = 1 # material ID tag -- unconfined cover concrete (here used for complete section) IDreinf = 2 # material ID tag -- reinforcement # nominal concrete compressive strength fc = -4.0 * ksi # CONCRETE Compressive Strength (+Tension, -Compression) Ec = 57 * ksi * math.sqrt( -fc / psi) # Concrete Elastic Modulus (the term in sqr root needs to be in psi
def build_model(model_params): """ Generates OpenSeesPy model of an elastic cantilever and runs gravity analysis. Assumes that length is measured in inches and acceleration in in/s2 Parameters ---------- NumberOfStories: int Number of stories StructureType: string Type of structural system - expects one of the HAZUS structure classes PlanArea: float Area of the structure's footprint """ # Assumptions h_story = 12 # Story height [ft] w_story = 200 # Story weight [psf] # constants for unit conversion ft = 1.0 inch = 12.0 m = 3.28084 ft2 = 1.0 inch2 = inch**2. m2 = m**2. psf = 1.0 Nsm = 4.88242 # N per square meter stories = model_params["NumberOfStories"] node_tags = list(range(stories + 1)) # The fundamental period is approximated as per ASCE 7-16 12.8.2.1 h_n = stories * h_story # [ft] if model_params['StructureType'] in [ 'S1', ]: # steel moment-resisting frames C_t = 0.028 x = 0.8 elif model_params['StructureType'] in [ 'C1', ]: # concrete moment-resisting frames C_t = 0.016 x = 0.9 elif model_params['StructureType'] in ['BRBF', 'ECBF']: # steel eccentrically braced frames or # steel buckling-restrained braced frame C_t = 0.03 x = 0.75 else: C_t = 0.02 x = 0.75 T1 = C_t * h_n**x # Eq 12.8-7 in ASCE 7-16 # check the units units = model_params["units"] if 'length' in units.keys(): if units['length'] == 'm': G = 9.81 h_story = h_story * m w_story = w_story * Nsm elif units['length'] == 'ft': G = 32.174 h_story = h_story * ft w_story = w_story / ft2 else: # elif units['length'] == 'in': G = 386.1 h_story = h_story * inch w_story = w_story / inch2 # The weight at each story is assumed to be identical W = model_params["PlanArea"] * w_story m = W / G # We calculate stiffness assuming half of the mass vibrates at the top K = ((m * stories) / 2.) / (T1 / (2 * pi))**2. # set model dimensions and degrees of freedom ops.model('basic', '-ndm', 3, '-ndf', 6) # define an elastic and a rigid material elastic_tag = 100 rigid_tag = 110 ops.uniaxialMaterial('Elastic', elastic_tag, K) ops.uniaxialMaterial('Elastic', rigid_tag, 1.e9) # define pattern for gravity loads ops.timeSeries('Linear', 1) ops.pattern('Plain', 101, 1) for story in range(0, stories + 1): # define nodes ops.node(node_tags[story], 0., 0., story * h_story) # define fixities if story == 0: ops.fix(node_tags[0], 1, 1, 1, 1, 1, 1) else: ops.fix(node_tags[story], 0, 0, 0, 1, 1, 1) # define elements if story > 0: element_tag = 1000 + story - 1 ops.element('twoNodeLink', element_tag, node_tags[story - 1], node_tags[story], '-mat', rigid_tag, elastic_tag, elastic_tag, '-dir', 1, 2, 3, '-orient', 0., 0., 1., 0., 1., 0., '-doRayleigh') # define masses ops.mass(node_tags[story], m, m, m, 0., 0., 0.) # define loads ops.load(node_tags[story], 0., 0., -W, 0., 0., 0.) # define damping based on first eigenmode damp_ratio = 0.05 angular_freq = ops.eigen(1)[0]**0.5 beta_k = 2 * damp_ratio / angular_freq ops.rayleigh(0., beta_k, 0., 0.) # run gravity analysis tol = 1e-8 # convergence tolerance for test iter = 100 # max number of iterations nstep = 100 # apply gravity loads in 10 steps incr = 1. / nstep # first load increment # analysis settings ops.constraints( 'Transformation' ) # enforce boundary conditions using transformation constraint handler ops.numberer( 'RCM') # renumbers dof's to minimize band-width (optimization) ops.system( 'BandGeneral' ) # stores system of equations as 1D array of size bandwidth x number of unknowns ops.test( 'EnergyIncr', tol, iter, 0 ) # tests for convergence using dot product of solution vector and norm of right-hand side of matrix equation ops.algorithm( 'Newton' ) # use Newton's solution algorithm: updates tangent stiffness at every iteration ops.integrator( 'LoadControl', incr ) # determine the next time step for an analysis # apply gravity in 10 steps ops.analysis('Static') # define type of analysis, static or transient ops.analyze(nstep) # perform gravity analysis # after gravity analysis, change time and tolerance for the dynamic analysis ops.loadConst('-time', 0.0)
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
ops.section('Elastic', secTag, E, A, Iz) # beam integration inteTag = 1 numpts = 2 ops.beamIntegration('Legendre', inteTag, secTag, numpts) coltag = 3 eleArgs = ['dispBeamColumn', transfTag, inteTag] ops.mesh('line', coltag, 2, 1, 2, sid, ndf, h, *eleArgs) # mass sNodes = ops.getNodeTags('-mesh', coltag) bmass = bmass / len(sNodes) for nd in sNodes: ops.mass(int(nd), bmass, bmass, 0.0) # background mesh lower = [-h, -h] upper = [5 * L, 3 * L] ops.mesh('bg', h, *lower, *upper, '-structure', sid, len(sNodes), *sNodes, '-structure', sid, len(wallNodes), *wallNodes) print('num nodes =', len(ops.getNodeTags())) print('num particles =', nx * ny) # create constraint object ops.constraints('Plain') # create numberer object