def step(self, action=0): self.time = op.getTime() assert (self.time < self.analysis_time) # 選ばれたアクションに応じて減衰定数を変化させる self.h = self.action[action] self.hs.append(self.h) self.beta_k = 2 * self.h / self.w0 op.rayleigh(self.alpha_m, self.beta_k, self.beta_k_init, self.beta_k_comm) op.analyze(1, self.dt) op.reactions() self.dis = op.nodeDisp(self.top_node, 1) self.vel = op.nodeVel(self.top_node, 1) self.acc = op.nodeAccel(self.top_node, 1) self.a_acc = self.acc + self.values[self.i] self.force = -op.nodeReaction(self.bot_node, 1) # Negative since diff node self.resp["time"].append(self.time) self.resp["dis"].append(self.dis) self.resp["vel"].append(self.vel) self.resp["acc"].append(self.acc) self.resp["a_acc"].append(self.a_acc) self.resp["force"].append(self.force) next_time = op.getTime() self.done = next_time >= self.analysis_time self.i_pre = self.i self.i += 1 self.i_next = self.i + 1 if not self.done else self.i return self.reward, self.done
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
def test_ElasticFrame(): # # some parameter # PI = 2.0 * asin(1.0) g = 386.4 ft = 12.0 Load1 = 1185.0 Load2 = 1185.0 Load3 = 970.0 # floor masses m1 = Load1 / (4 * g) # 4 nodes per floor m2 = Load2 / (4 * g) m3 = Load3 / (4 * g) # floor distributed loads w1 = Load1 / (90 * ft) # frame 90 ft long w2 = Load2 / (90 * ft) w3 = Load3 / (90 * ft) # ------------------------------ # Start of model generation # ------------------------------ # Remove existing model ops.wipe() # Create ModelBuilder (with two-dimensions and 2 DOF/node) ops.model('BasicBuilder', '-ndm', 2, '-ndf', 3) # Create nodes # ------------ # Create nodes & add to Domain - command: node nodeId xCrd yCrd <-mass massX massY massRz> # NOTE: mass in optional ops.node(1, 0.0, 0.0) ops.node(2, 360.0, 0.0) ops.node(3, 720.0, 0.0) ops.node(4, 1080.0, 0.0) ops.node(5, 0.0, 162.0, '-mass', m1, m1, 0.0) ops.node(6, 360.0, 162.0, '-mass', m1, m1, 0.0) ops.node(7, 720.0, 162.0, '-mass', m1, m1, 0.0) ops.node(8, 1080.0, 162.0, '-mass', m1, m1, 0.0) ops.node(9, 0.0, 324.0, '-mass', m2, m2, 0.0) ops.node(10, 360.0, 324.0, '-mass', m2, m2, 0.0) ops.node(11, 720.0, 324.0, '-mass', m2, m2, 0.0) ops.node(12, 1080.0, 324.0, '-mass', m2, m2, 0.0) ops.node(13, 0.0, 486.0, '-mass', m3, m3, 0.0) ops.node(14, 360.0, 486.0, '-mass', m3, m3, 0.0) ops.node(15, 720.0, 486.0, '-mass', m3, m3, 0.0) ops.node(16, 1080.0, 486.0, '-mass', m3, m3, 0.0) # the boundary conditions - command: fix nodeID xResrnt? yRestrnt? rZRestrnt? ops.fix(1, 1, 1, 1) ops.fix(2, 1, 1, 1) ops.fix(3, 1, 1, 1) ops.fix(4, 1, 1, 1) # Define geometric transformations for beam-column elements ops.geomTransf('Linear', 1) # beams ops.geomTransf('PDelta', 2) # columns # Define elements # Create elastic beam-column - command: element elasticBeamColumn eleID node1 node2 A E Iz geomTransfTag # Define the Columns ops.element('elasticBeamColumn', 1, 1, 5, 75.6, 29000.0, 3400.0, 2) # W14X257 ops.element('elasticBeamColumn', 2, 5, 9, 75.6, 29000.0, 3400.0, 2) # W14X257 ops.element('elasticBeamColumn', 3, 9, 13, 75.6, 29000.0, 3400.0, 2) # W14X257 ops.element('elasticBeamColumn', 4, 2, 6, 91.4, 29000.0, 4330.0, 2) # W14X311 ops.element('elasticBeamColumn', 5, 6, 10, 91.4, 29000.0, 4330.0, 2) # W14X311 ops.element('elasticBeamColumn', 6, 10, 14, 91.4, 29000.0, 4330.0, 2) # W14X311 ops.element('elasticBeamColumn', 7, 3, 7, 91.4, 29000.0, 4330.0, 2) # W14X311 ops.element('elasticBeamColumn', 8, 7, 11, 91.4, 29000.0, 4330.0, 2) # W14X311 ops.element('elasticBeamColumn', 9, 11, 15, 91.4, 29000.0, 4330.0, 2) # W14X311 ops.element('elasticBeamColumn', 10, 4, 8, 75.6, 29000.0, 3400.0, 2) # W14X257 ops.element('elasticBeamColumn', 11, 8, 12, 75.6, 29000.0, 3400.0, 2) # W14X257 ops.element('elasticBeamColumn', 12, 12, 16, 75.6, 29000.0, 3400.0, 2) # W14X257 # Define the Beams ops.element('elasticBeamColumn', 13, 5, 6, 34.7, 29000.0, 5900.0, 1) # W33X118 ops.element('elasticBeamColumn', 14, 6, 7, 34.7, 29000.0, 5900.0, 1) # W33X118 ops.element('elasticBeamColumn', 15, 7, 8, 34.7, 29000.0, 5900.0, 1) # W33X118 ops.element('elasticBeamColumn', 16, 9, 10, 34.2, 29000.0, 4930.0, 1) # W30X116 ops.element('elasticBeamColumn', 17, 10, 11, 34.2, 29000.0, 4930.0, 1) # W30X116 ops.element('elasticBeamColumn', 18, 11, 12, 34.2, 29000.0, 4930.0, 1) # W30X116 ops.element('elasticBeamColumn', 19, 13, 14, 20.1, 29000.0, 1830.0, 1) # W24X68 ops.element('elasticBeamColumn', 20, 14, 15, 20.1, 29000.0, 1830.0, 1) # W24X68 ops.element('elasticBeamColumn', 21, 15, 16, 20.1, 29000.0, 1830.0, 1) # W24X68 # Define loads for Gravity Analysis # --------------------------------- #create a Linear TimeSeries (load factor varies linearly with time): command timeSeries Linear tag ops.timeSeries('Linear', 1) # Create a Plain load pattern with a linear TimeSeries: # command pattern Plain tag timeSeriesTag { loads } ops.pattern('Plain', 1, 1) ops.eleLoad('-ele', 13, 14, 15, '-type', '-beamUniform', -w1) ops.eleLoad('-ele', 16, 17, 18, '-type', '-beamUniform', -w2) ops.eleLoad('-ele', 19, 20, 21, '-type', '-beamUniform', -w3) # --------------------------------- # Create Analysis for Gravity Loads # --------------------------------- # Create the system of equation, a SPD using a band storage scheme ops.system('BandSPD') # Create the DOF numberer, the reverse Cuthill-McKee algorithm ops.numberer('RCM') # Create the constraint handler, a Plain handler is used as h**o constraints ops.constraints('Plain') # Create the integration scheme, the LoadControl scheme using steps of 1.0 ops.integrator('LoadControl', 1.0) # Create the solution algorithm, a Linear algorithm is created ops.test('NormDispIncr', 1.0e-10, 6) ops.algorithm('Newton') # create the analysis object ops.analysis('Static') # --------------------------------- # Perform Gravity Analysis # --------------------------------- ops.analyze(1) # print "node 5: nodeDisp 5" # print "node 6: nodeDisp 6" # print "node 7: nodeDisp 7" # print "node 8: nodeDisp 8" # print "node 9: nodeDisp 9" # print "node 10: nodeDisp 10" # --------------------------------- # Check Equilibrium # --------------------------------- # invoke command to determine nodal reactions ops.reactions() node1Rxn = ops.nodeReaction( 1 ) # nodeReaction command returns nodal reactions for specified node in a list node2Rxn = ops.nodeReaction(2) node3Rxn = ops.nodeReaction(3) node4Rxn = ops.nodeReaction(4) inputedFy = -Load1 - Load2 - Load3 # loads added negative Fy diren to ele computedFx = node1Rxn[0] + node2Rxn[0] + node3Rxn[0] + node4Rxn[0] computedFy = node1Rxn[1] + node2Rxn[1] + node3Rxn[1] + node4Rxn[1] print("\nEqilibrium Check After Gravity:") print("SumX: Inputed: 0.0 + Computed:", computedFx, " = ", 0.0 + computedFx) print("SumY: Inputed: ", inputedFy, " + Computed: ", computedFy, " = ", inputedFy + computedFy) # --------------------------------- # Lateral Load # --------------------------------- # gravity loads constant and time in domain to e 0.0 ops.loadConst('-time', 0.0) ops.timeSeries('Linear', 2) ops.pattern('Plain', 2, 2) ops.load(13, 220.0, 0.0, 0.0) ops.load(9, 180.0, 0.0, 0.0) ops.load(5, 90.0, 0.0, 0.0) # --------------------------------- # Create Recorder # --------------------------------- #recorder Element -file EleForces.out -ele 1 4 7 10 forces # --------------------------------- # Perform Lateral Analysis # --------------------------------- ops.analyze(1) # print "node 5: nodeDisp 5" # print "node 6: nodeDisp 6" # print "node 7: nodeDisp 7" # print "node 8: nodeDisp 8" # print "node 9: nodeDisp 9" # print "node 10: nodeDisp 10" # --------------------------------- # Check Equilibrium # --------------------------------- ops.reactions() node1Rxn = ops.nodeReaction( 1 ) # =nodeReaction( command returns nodal reactions for specified node in a list node2Rxn = ops.nodeReaction(2) node3Rxn = ops.nodeReaction(3) node4Rxn = ops.nodeReaction(4) inputedFx = 220.0 + 180.0 + 90.0 computedFx = node1Rxn[0] + node2Rxn[0] + node3Rxn[0] + node4Rxn[0] computedFy = node1Rxn[1] + node2Rxn[1] + node3Rxn[1] + node4Rxn[1] print("\nEqilibrium Check After Lateral Loads:") print("SumX: Inputed: ", inputedFx, " + Computed: ", computedFx, " = ", inputedFx + computedFx) print("SumY: Inputed: ", inputedFy, " + Computed: ", computedFy, " = ", inputedFy + computedFy) # print ele information for columns at base #print ele 1 4 7 10 # --------------------------------- # Check Eigenvalues # --------------------------------- eigenValues = ops.eigen(5) print("\nEigenvalues:") eigenValue = eigenValues[0] T1 = 2 * PI / sqrt(eigenValue) print("T1 = ", T1) eigenValue = eigenValues[1] T2 = 2 * PI / sqrt(eigenValue) print("T2 = ", T2) eigenValue = eigenValues[2] T3 = 2 * PI / sqrt(eigenValue) print("T3 = ", T3) eigenValue = eigenValues[3] T4 = 2 * PI / sqrt(eigenValue) print("T4 = ", T4) eigenValue = eigenValues[4] T5 = 2 * PI / sqrt(eigenValue) print("T5 = ", T5) assert abs(T1 - 1.0401120938612862) < 1e-12 and abs( T2 - 0.3526488583606463 ) < 1e-12 and abs(T3 - 0.1930409642350476) < 1e-12 and abs( T4 - 0.15628823050715784) < 1e-12 and abs(T5 - 0.13080166151268388) < 1e-12 #recorder Node -file eigenvector.out -nodeRange 5 16 -dof 1 2 3 eigen 0 #record print("==========================")
def NSProcedure(ndm, ndf, NbaysX, NbaysZ, NStr, XbayL, ZbayL, StoryH, lon, lat, SHL, Vso, gamma_soil, nu_soil, Re, fpc, Ec, gamma_conc, fy, E0, bsteel, ColTransfType, BeamEffFact, ColEffFact, g, Qsd, Ql, Qlr, EMs, R, Ie, StrType, BldTypCo, BldTypCm, DsgnType, dirs, directory): # The Nonlinear Static Procdure is executed in order to get responses # of a defined building. import openseespy.opensees as ops import OPSDefsMOD as OPSDMOD import OPSDefsAN as OPSDAN from timeit import default_timer as timer import ASCE716Seismic as ASCE716 import ASCE4117 import matplotlib.pyplot as plt import pickle import numpy as np for mm in range(len(NbaysX)): for nn in range(len(NStr)): for oo in range(len(Vso)): Teff = np.zeros( (len(dirs) )) # [s][LIST] effective lateral period of building. for ii in range(len(dirs)): time_o = timer() # Some previous definitions # ---------------------------- if DsgnType in ('conv_dsgn'): flex = 'no' elif DsgnType in ('ssi_dsgn'): flex = 'yes' # SiteClass = ASCE716.detSiteClass(Vso[oo]) # Unpicklin' some stored parameters from design process. # ------------------------------------------------------ workpath = directory + '\\RegularDesign\\' + str(NbaysX[mm])+'BayX'+str(NbaysZ)+\ 'BayZ'+str(NStr[nn])+'FLRS'+str(Vso[oo])+'.pickle' with open(workpath, 'rb') as f: ColDims, Colreinf, XBDims, XBreinf, ZBDims, ZBreinf, _, _, _, _, _, _, _, _, _, _ = pickle.load( f) # Calculation of height vector # ------------------------------ if flex in ('Y', 'YES', 'Yes', 'yES', 'yes', 'y'): # [m][LIST] with level height starting from first level or from base if foundation flexibility is included. hx = [0.0001] else: hx = [] for i in range(NStr[nn]): hx.append((i + 1) * StoryH) # Plan Dimensions of Building B = NbaysZ * ZbayL # [m] short side of building plan. L = NbaysX[mm] * XbayL # [m] long side of building plan. # Determination of MCEr spectral acceleration parameters # ------------------------------------------------------ (Sxs, Sx1) = ASCE4117.detSxi(lon, lat, Vso[oo], SHL) # MODELING OF THE STRUCTURE USING OPENSEESPY # =========================================== ops.wipe() OPSDMOD.ModelGen(ndm, ndf) OPSDMOD.NodeGen(NbaysX[mm], NbaysZ, XbayL, ZbayL, StoryH, NStr[nn], flex) OPSDMOD.MastNodeGen(NbaysX[mm], NbaysZ, XbayL, ZbayL, StoryH, NStr[nn], flex, coords=0) OPSDMOD.SPConstGen(NbaysX[mm], NbaysZ, flex) OPSDMOD.MPConstGen(NbaysX[mm], NbaysZ, NStr[nn], flex) OPSDMOD.MatGenRCB(fpc, Ec, fy, E0, bsteel) # OPSDMOD.GeomTransGen(ColTransfType,XBD=[min(XBDims[:,0]),min(XBDims[:,1])],\ # ZBD=[min(ZBDims[:,0]),min(ZBDims[:,1])],\ # ColD=[min(ColDims[:,0]),min(ColDims[:,1])]) OPSDMOD.GeomTransGen( ColTransfType, ColD=[min(ColDims[:, 0]), min(ColDims[:, 1])]) # OPSDMOD.GeomTransGen(ColTransfType) if flex in ('Y', 'YES', 'Yes', 'yES', 'yes', 'y'): # Interface elements generation for foundation flexibility considerations. # ========================================================================= # Materials generation: stiffness constants accounting for soil flexibility. # --------------------------------------------------------------------------- OPSDMOD.FoundFlexMaterials(NbaysX[mm],NbaysZ,XbayL,ZbayL,Sxs,Vso[oo],gamma_soil,nu_soil,B,L,Re,\ D=0,omega_soil=0,analtype='lat') # Zero-Length elements creation for connecting base nodes. OPSDMOD.FoundFlexZLElements(NbaysX[mm], NbaysZ, XbayL, ZbayL, B, L, Re) OPSDMOD.ElementGen(NbaysX[mm],NbaysZ,XbayL,ZbayL,NStr[nn],StoryH,XBDims,ZBDims,\ ColDims,BeamEffFact,ColEffFact,Ec,fy,EMs,\ XBreinf,ZBreinf,Colreinf,N=5,rec=0.0654,nuconc=0.2,dbar=0.025) [Wx,MassInputMatr] = \ OPSDMOD.LumpedMassGen(NbaysX[mm],NbaysZ,XBDims,ZBDims,ColDims,gamma_conc,g,XbayL,ZbayL,NStr[nn],StoryH,Qsd,flex) W = sum(Wx) # [kN] total weight of the building # GRAVITY LOADS APPLIED TO MODEL ACCORDINGO TO ASCE4117 # ====================================================== # According to ASCE4117 Section 7.2.2, equation (7-3), the combination # of gravitational loads mus be as follows: # Qg = Qd + 0.25*Ql + Qs (7-3) OPSDMOD.DeadLoadGen(NbaysX[mm], NbaysZ, NStr[nn], XBDims, ZBDims, ColDims, gamma_conc) OPSDMOD.SuperDeadLoadGen(NbaysX[mm], NbaysZ, NStr[nn], XbayL, ZbayL, Qsd) OPSDMOD.LiveLoadGen(NbaysX[mm], NbaysZ, NStr[nn], XbayL, ZbayL, 0.25 * Ql, 0.25 * Qlr) # GRAVITY-LOADS-CASE ANALYSIS. # ============================ ops.system('ProfileSPD') ops.constraints('Transformation') ops.numberer('RCM') ops.test('NormDispIncr', 1.0e-4, 100) ops.algorithm('KrylovNewton') ops.integrator('LoadControl', 1) ops.analysis('Static') ops.analyze(1) # Vertical reactions Calculation for verification. # ------------------------------------------------ ops.reactions() YReact = 0 for i in range((NbaysX[mm] + 1) * (NbaysZ + 1)): if flex in ('Y', 'YES', 'Yes', 'yES', 'yes', 'y'): YReact += ops.nodeReaction(int(i + 1), 2) else: YReact += ops.nodeReaction(int(i + 1 + 1e4), 2) # ========================================================================== # MODAL ANALYSIS FOR DETERMINING FUNDAMENTAL PERIOD AND ITS DIRECTION. # ========================================================================== (T, Tmaxver, Mast) = OPSDAN.ModalAnalysis(NStr[nn], B, L, Wx, flex) print(T) # ================== # PUSHOVER ANALYSIS # ================== # Lateral Force used for analysis # -------------------------------- # Using functions from ASCE716Seismic Module. (_,_,_,_,_,_,_,_,_,_,_,FxF,_,_,_) = \ ASCE716.ELFP(Sxs,Sx1,Vso[oo],Wx,R,Ie,hx,StrType,T[0,ii]) # Aplication of forces to the model. # ---------------------------------- ops.loadConst('-time', 0.0) MdeShape = OPSDMOD.POForceGen(NStr[nn], FxF, dirs[ii], flex) # ============================================= # First Execution of the analysis and output results. # ============================================= (results1,dtg1,tgfactor1) = \ OPSDAN.POAnalysisProc(lon,lat,Vso[oo],SHL,NbaysX[mm],NbaysZ,\ NStr[nn],StoryH,R,Ie,BldTypCo,BldTypCm,\ T[0,ii],W,dirs[ii],flex,\ DispIncr=0,beta=0.05,TL=8.,Tf=6.0,Npts=500,Vy=0,Te=0) # [Disp,Force] # ===================================================== # Determining the first approximation of values of Vy # and calculation of effective fundamental period for NSP # ===================================================== (Delta_y, V_y, Delta_d, V_d, Ke, alpha1, alpha2) = \ ASCE4117.IFDC(dtg1,results1) Ki = Mast[ii] * 4 * np.pi**2 / T[ 0, ii]**2 # [kN/m] elastic lateral stiffness of the building. Teff[ii] = T[0, ii] * ( Ki / Ke )**0.5 # [s] effctive fundamental period of building. # ============================================= # Second Execution of the analysis and output results. # ============================================= ops.wipe() OPSDMOD.ModelGen(ndm, ndf) OPSDMOD.NodeGen(NbaysX[mm], NbaysZ, XbayL, ZbayL, StoryH, NStr[nn], flex) OPSDMOD.MastNodeGen(NbaysX[mm], NbaysZ, XbayL, ZbayL, StoryH, NStr[nn], flex, coords=0) OPSDMOD.SPConstGen(NbaysX[mm], NbaysZ, flex) OPSDMOD.MPConstGen(NbaysX[mm], NbaysZ, NStr[nn], flex) OPSDMOD.MatGenRCB(fpc, Ec, fy, E0, bsteel) # OPSDMOD.GeomTransGen(ColTransfType,XBD=[min(XBDims[:,0]),min(XBDims[:,1])],\ # ZBD=[min(ZBDims[:,0]),min(ZBDims[:,1])],\ # ColD=[min(ColDims[:,0]),min(ColDims[:,1])]) OPSDMOD.GeomTransGen( ColTransfType, ColD=[min(ColDims[:, 0]), min(ColDims[:, 1])]) # OPSDMOD.GeomTransGen(ColTransfType) if flex in ('Y', 'YES', 'Yes', 'yES', 'yes', 'y'): # Interface elements generation for foundation flexibility considerations. # ========================================================================= # Materials generation: stiffness constants accounting for soil flexibility. # --------------------------------------------------------------------------- OPSDMOD.FoundFlexMaterials(NbaysX[mm],NbaysZ,XbayL,ZbayL,Sxs,Vso[oo],gamma_soil,nu_soil,B,L,Re,\ D=0,omega_soil=0,analtype='lat') # Zero-Length elements creation for connecting base nodes. OPSDMOD.FoundFlexZLElements(NbaysX[mm], NbaysZ, XbayL, ZbayL, B, L, Re) OPSDMOD.ElementGen(NbaysX[mm],NbaysZ,XbayL,ZbayL,NStr[nn],StoryH,XBDims,ZBDims,\ ColDims,BeamEffFact,ColEffFact,Ec,fy,EMs,\ XBreinf,ZBreinf,Colreinf,N=5,rec=0.0654,nuconc=0.2,dbar=0.025) [Wx,MassInputMatr] = \ OPSDMOD.LumpedMassGen(NbaysX[mm],NbaysZ,XBDims,ZBDims,ColDims,gamma_conc,g,XbayL,ZbayL,NStr[nn],StoryH,Qsd,flex) W = sum(Wx) # [kN] total weight of the building # GRAVITY LOADS APPLIED TO MODEL ACCORDINGO TO ASCE4117 # ====================================================== OPSDMOD.DeadLoadGen(NbaysX[mm], NbaysZ, NStr[nn], XBDims, ZBDims, ColDims, gamma_conc) OPSDMOD.SuperDeadLoadGen(NbaysX[mm], NbaysZ, NStr[nn], XbayL, ZbayL, Qsd) OPSDMOD.LiveLoadGen(NbaysX[mm], NbaysZ, NStr[nn], XbayL, ZbayL, 0.25 * Ql, 0.25 * Qlr) # GRAVITY-LOADS-CASE ANALYSIS. # ============================ ops.system('ProfileSPD') ops.constraints('Transformation') ops.numberer('RCM') ops.test('NormDispIncr', 1.0e-4, 100) ops.algorithm('KrylovNewton') ops.integrator('LoadControl', 1) ops.analysis('Static') ops.analyze(1) # ================== # PUSHOVER ANALYSIS # ================== # Lateral Force used for analysis # -------------------------------- # Using functions from ASCE716Seismic Module. (_,_,_,_,_,_,_,_,_,_,_,FxF,_,_,_) = \ ASCE716.ELFP(Sxs,Sx1,Vso[oo],Wx,R,Ie,hx,StrType,Teff[ii]) # Aplication of forces to the model. # ---------------------------------- ops.loadConst('-time', 0.0) MdeShape = OPSDMOD.POForceGen(NStr[nn], FxF, dirs[ii], flex) # ============================================= # First Execution of the analysis and output results. # ============================================= (results2,dtg2,tgfactor2) = \ OPSDAN.POAnalysisProc(lon,lat,Vso[oo],SHL,NbaysX[mm],NbaysZ,\ NStr[nn],StoryH,R,Ie,BldTypCo,BldTypCm,\ T[0,ii],W,dirs[ii],flex,\ DispIncr=0,beta=0.05,TL=8.,Tf=6.0,Npts=500,Vy=0,Te=Teff[ii]) # [Disp,Force]. # ===================================================== # Determining the "exact" values of Vy # and calculation of effective fundamental period for NSP # ===================================================== (Delta_y, V_y, Delta_d, V_d, Ke, alpha1, alpha2) = \ ASCE4117.IFDC(dtg1,results2) Ki = Mast[ii] * 4 * np.pi**2 / T[ 0, ii]**2 # [kN/m] elastic lateral stiffness of the building. Teff[ii] = T[0, ii] * ( Ki / Ke )**0.5 # [s] effctive fundamental period of building. ttime = timer() - time_o print(f'Elapsed Time {round(ttime/60,2)} [m]') plt.figure() plt.plot(results2[:, 0], results2[:, 1]) plt.grid() print('The mode shape is:') print(MdeShape) return (results1, results2), (dtg1, dtg2), (tgfactor1, tgfactor2), (tgfactor1 * dtg1, tgfactor2 * dtg2)
# ============================ ops.system('ProfileSPD') ops.constraints('Transformation') ops.numberer('RCM') ops.test('NormDispIncr', 1.0e-4, 100) ops.algorithm('KrylovNewton') ops.integrator('LoadControl', 1) ops.analysis('Static') ops.analyze(1) # Vertical reactions Calculation for verification. # ------------------------------------------------ ops.reactions() YReact = 0 for i in range((NbaysX[0] + 1) * (NbaysZ + 1)): if flex in ('Y', 'YES', 'Yes', 'yES', 'yes', 'y'): YReact += ops.nodeReaction(99000 + i + 1, 2) else: YReact += ops.nodeReaction(i + 1, 2) print('>>> Gravity loads applied...') # ========================================================================== # MODAL ANALYSIS FOR DETERMINING FUNDAMENTAL PERIOD AND ITS DIRECTION. # ========================================================================== (Tver, Tmaxver, Mast) = OPSDAN.ModalAnalysis(NStr[0], B, L, Wx, flex) import ASCE716SSI as SSI if flex in ('Y', 'YES', 'Yes', 'yES', 'yes', 'y'): # [m][LIST] with level height starting from first level or from base if foundation flexibility is included. hx = [0.0001] else: hx = []
def run_sensitivity_analysis(ctrlNode, dof, baseNode, SensParam, steps=500, IOflag=False): """ Run load-control sensitivity analysis """ ops.wipeAnalysis() start_time = time.time() title("Running Load-Control Sensitivity Analysis ...") ops.system("BandGeneral") ops.numberer("RCM") ops.constraints("Transformation") ops.test("NormDispIncr", 1.0E-12, 10, 3) ops.algorithm("Newton") # KrylovNewton ops.integrator("LoadControl", 1 / steps) ops.analysis("Static") ops.sensitivityAlgorithm( "-computeAtEachStep" ) # automatically compute sensitivity at the end of each step outputs = { "time": np.array([]), "disp": np.array([]), "force": np.array([]), } for sens in SensParam: outputs[f"sensDisp_{sens}"] = np.array([]), for i in range(steps): ops.reactions() if IOflag: print( f"Single Cycle Response: Step #{i}, Node #{ctrlNode}: {ops.nodeDisp(ctrlNode, dof):.3f} {LunitTXT} / {-ops.nodeReaction(baseNode, dof):.2f} {FunitTXT}." ) ops.analyze(1) tCurrent = ops.getTime() outputs["time"] = np.append(outputs["time"], tCurrent) outputs["disp"] = np.append(outputs["disp"], ops.nodeDisp(ctrlNode, dof)) outputs["force"] = np.append(outputs["force"], -ops.nodeReaction(baseNode, dof)) for sens in SensParam: # sensDisp(patternTag, paramTag) outputs[f"sensDisp_{sens}"] = np.append( outputs[f"sensDisp_{sens}"], ops.sensNodeDisp(ctrlNode, dof, sens)) title("Sensitvity Analysis Completed!") print( f"Analysis elapsed time is {(time.time() - start_time):.3f} seconds.\n" ) return outputs
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
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
print("Finished creating loading object...") #---------------------------------------------------------- # create the analysis #---------------------------------------------------------- op.integrator('LoadControl', 0.05) op.numberer('RCM') op.system('SparseGeneral') op.constraints('Transformation') op.test('NormDispIncr', 1e-5, 20, 1) op.algorithm('Newton') op.analysis('Static') print("Starting Load Application...") op.analyze(201) print("Load Application finished...") #print("Loading Analysis execution time: [expr $endT-$startT] seconds.") #op.wipe op.reactions() Nodereactions = dict() Nodedisplacements = dict() for i in range(201, nodeTag + 1): Nodereactions[i] = op.nodeReaction(i) Nodedisplacements[i] = op.nodeDisp(i) print('Node Reactions are: ', Nodereactions) print('Node Displacements are: ', Nodedisplacements)