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 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 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
# condiciones de frontera boundFix(nNode, Node) # fuerza dinamica ti = 0 * s tf = 0.2 * s fr = 10 * Hz prd = 1 / fr ops.timeSeries('Trig', 1, ti, tf, prd) # https://openseespydoc.readthedocs.io/en/latest/src/pathTs.html ops.pattern('UniformExcitation', 1, 1, '-accel', 1) # https://openseespydoc.readthedocs.io/en/latest/src/uniformExcitation.html # amortiguamiento de rayleigh ops.rayleigh(*setRayParam(0.05, 0.05, 0.2, 20)) # analysis commands ops.constraints('Plain') ops.numberer('Plain') ops.system('UmfPack') ops.algorithm('Linear') ops.integrator('Newmark', 0.5, 0.25) ops.analysis('Transient') # analisis # ops.analyze(400,0.001) ops.start() for i in range(400): ops.analyze(1, 0.001) print(i)
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
import InelasticFiberSection #applying Dynamic Ground motion analysis Tol = 1e-8 GMdirection = 1 GMfile = 'BM68elc.acc' GMfact = 1.0 Lambda = op.eigen('-fullGenLapack', 1) # eigenvalue mode 1 Omega = math.pow(Lambda, 0.5) betaKcomm = 2 * (0.02 / Omega) xDamp = 0.02 # 2% damping ratio alphaM = 0.0 # M-prop. damping; D = alphaM*M betaKcurr = 0.0 # K-proportional damping; +beatKcurr*KCurrent betaKinit = 0.0 # initial-stiffness proportional damping +beatKinit*Kini op.rayleigh(alphaM, betaKcurr, betaKinit, betaKcomm) # RAYLEIGH damping # Uniform EXCITATION: acceleration input IDloadTag = 400 # load tag dt = 0.01 # time step for input ground motion GMfatt = 1.0 # data in input file is in g Unifts -- ACCELERATION TH maxNumIter = 10 op.timeSeries('Path', 2, '-dt', dt, '-filePath', GMfile, '-factor', GMfact) op.pattern('UniformExcitation', IDloadTag, GMdirection, '-accel', 2) op.wipeAnalysis() op.constraints('Transformation') op.numberer('Plain') op.system('BandGeneral') op.test('EnergyIncr', Tol, maxNumIter) op.algorithm('ModifiedNewton')
# Set some parameters record = 'elCentro' # Permform the conversion from SMD record to OpenSees record dt, nPts = ReadRecord.ReadRecord(record + '.at2', record + '.dat') # Set time series to be passed to uniform excitation ops.timeSeries('Path', 7, '-filePath', record + '.dat', '-dt', dt, '-factor', g) # Create UniformExcitation load pattern # tag dir ops.pattern('UniformExcitation', 7, 1, '-accel', 7) # set the rayleigh damping factors for nodes & elements ops.rayleigh(0.4274, 0.005827, 0.0, 0.0) # Delete the old analysis and all it's component objects ops.wipeAnalysis() # Create the system of equation, a banded general storage scheme ops.system('BandGeneral') # Create the constraint handler, a plain handler as homogeneous boundary ops.constraints('Transformation') # Create the convergence test, the norm of the residual with a tolerance of # 1e-12 and a max number of iterations of 10 ops.test('NormDispIncr', 1.0e-4, 100) # Create the solution algorithm, a Newton-Raphson algorithm
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 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 run_dynamic_analysis_w_rayleigh_damping(dict_of_hinges, dict_of_disp_nodes, dict_of_rxn_nodes, zeta, initialOrTangent='initial', parent_dir=os.getcwd()): # remove any existing analysis data op.wipeAnalysis() # define a time series to add the ground motion op.timeSeries('Path', 2, '-dt', 0.01, '-filePath', 'BM68elc.acc', '-factor', 3.0 * g) op.pattern('UniformExcitation', 2, 1, '-accel', 2) # uncomment/comment the code below to run bideirectional/unidirectional ground motion analysis # op.timeSeries('Path', 3, '-dt', 0.01, '-filePath', 'BM68elc.acc', '-factor', 1.0*g) # op.pattern('UniformExcitation', 3, 2, '-accel', 3) op.constraints('Transformation') op.numberer('RCM') op.system('UmfPack') # op.test('NormDispIncr', 1e-2, 100000, 0, 0) op.test('EnergyIncr', 1e-4, 1e4, 0, 2) # available set of algorithms if the default fails backup_algos = { 'Modified Newton w/ Initial Stiffness': ['ModifiedNewton', '-initial'], 'Newton with Line Search': [ 'NewtonLineSearch', 'tol', 1e-3, 'maxIter', 1e5, 'maxEta', 10, 'minEta', 1e-2 ], } # define the default algorithm to be used for this analysis op.algorithm('KrylovNewton', 'maxDim', 3) # define the integrator to be used for this analysis from the set of available integrators in opensees alpha = 0.67 op.integrator( 'HHT', alpha) # can be either of: ('HHT', alpha), ('Newmark', 0.5, 0.25) # define the type of analysis to be performed op.analysis('Transient') # obtain the modal analysis eigenValues = modal_response(numEigen) # get periods from the modal analsis periods = 2 * math.pi / np.sqrt(eigenValues) w1 = (eigenValues[0]**0.5) w2 = (eigenValues[0]**0.5) / 0.384 a0 = zeta * 2 * w1 * w2 / (w1 + w2) a1 = zeta * 2 / (w1 + w2) print('\nRayleigh Damping Coefficients:') print(f'\talpha: {a0}') print(f'\tbeta : {a1}\n') if initialOrTangent == 'tangent': op.rayleigh(a0, a1, 0, 0) else: op.rayleigh(a0, 0, a1, 0) # setup to record analysis data setup_recorders(dict_of_disp_nodes, dict_of_rxn_nodes, dict_of_hinges, initialOrTangent, parent_dir) total_run_time = 50 # seconds time_step = 0.01 # seconds total_num_of_steps = total_run_time / time_step # default initialization of constants to be used in the execution loop failed = 0 time = 0 algo = 'Krylov-Newton' pbar = tqdm(total=total_num_of_steps) # execution loop # this execution loop tries to use krylov-Newton until it works, when this fails it iterate through set of # algorithms until it finds a solution, if it is not able to find a solution with any algorithm, the loop ends. # Whereas if it is able to find a solution with any of the algorithms, it switches back to krylov-Newton while time <= total_run_time and failed == 0: failed = op.analyze(1, time_step) if failed: print(f'\n{algo} failed. Trying other algorithms...') for alg, algo_args in backup_algos.items(): print(f'\nTrying {alg}...') op.algorithm(*algo_args) failed = op.analyze(1, time_step) if failed: continue else: algo = 'Krylov-Newton' print(f'\n{alg} worked.\n\nMoving back to {algo}') op.algorithm('KrylovNewton', 'maxDim', 3) break print(''.center(100, '-')) pbar.update(1) time = op.getTime() op.wipe() # move output files to results directory list_of_out_files = [ fname for fname in os.listdir() if fname.endswith('.out') ] for fname in list_of_out_files: shutil.move(os.path.join(os.getcwd(), fname), os.path.join(parent_dir, fname)) return periods, eigenValues
def test_DynAnal_BeamWithQuadElements(): ops.wipe() # clear opensees model # create data directory # file mkdir Data #----------------------------- # Define the model # ---------------------------- # Create ModelBuilder with 2 dimensions and 2 DOF/node ops.model('BasicBuilder', '-ndm', 2, '-ndf', 2) # create the material ops.nDMaterial('ElasticIsotropic', 1, 1000.0, 0.25, 3.0) # set type of quadrilateral element (uncomment one of the three options) Quad = 'quad' #set Quad bbarQuad #set Quad enhancedQuad # set up the arguments for the three considered elements if Quad == "enhancedQuad": eleArgs = "PlaneStress2D 1" if Quad == "quad": eleArgs = "1 PlaneStress2D 1" if Quad == "bbarQuad": eleArgs = "1" # set up the number of elements in x (nx) and y (ny) direction nx = 16 # NOTE: nx MUST BE EVEN FOR THIS EXAMPLE ny = 4 # define numbering of node at the left support (bn), and the two nodes at load application (l1, l2) bn = nx + 1 l1 = int(nx / 2 + 1) l2 = int(l1 + ny * (nx + 1)) # create the nodes and elements using the block2D command ops.block2D(nx, ny, 1, 1, Quad, 1., 'PlaneStress2D', 1, 1, 0., 0., 2, 40., 0., 3, 40., 10., 4, 0., 10.) # define boundary conditions ops.fix(1, 1, 1) ops.fix(bn, 0, 1) # define the recorder #--------------------- # recorder Node -file Data/Node.out -time -node l1 -dof 2 disp # define load pattern #--------------------- ops.timeSeries('Linear', 1) ops.pattern('Plain', 1, 1) ops.load(l1, 0.0, -1.0) ops.load(l2, 0.0, -1.0) # -------------------------------------------------------------------- # Start of static analysis (creation of the analysis & analysis itself) # -------------------------------------------------------------------- # Load control with variable load steps # init Jd min max ops.integrator('LoadControl', 1.0, 1, 1.0, 10.0) # Convergence test # tolerance maxIter displayCode ops.test('EnergyIncr', 1.0e-12, 10, 0) # Solution algorithm ops.algorithm('Newton') # DOF numberer ops.numberer('RCM') # Cosntraint handler ops.constraints('Plain') # System of equations solver ops.system('ProfileSPD') # Type of analysis analysis ops.analysis('Static') # Perform the analysis ops.analyze(10) # -------------------------- # End of static analysis # -------------------------- # ------------------------------------- # create display for transient analysis #-------------------------------------- # windowTitle xLoc yLoc xPixels yPixels # recorder display "Simply Supported Beam" 10 10 800 200 -wipe # prp 20 5.0 1.0 # 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 -30 30 -10 10 # coordiantes of the window relative to prp # display 10 0 5 # the 1st arg. is the tag for display mode # the 2nd arg. is magnification factor for nodes, the 3rd arg. is magnif. factor of deformed shape # --------------------------------------- # Create and Perform the dynamic analysis # --------------------------------------- #define damping evals = ops.eigen(1) ops.rayleigh(0., 0., 0., 2 * 0.02 / sqrt(evals[0])) # 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) uy1 = ops.nodeDisp(9, 2) print("uy(9) = ", uy1) # Create the transient analysis ops.test('EnergyIncr', 1.0e-12, 10, 0) ops.algorithm('Newton') ops.numberer('RCM') ops.constraints('Plain') ops.integrator('Newmark', 0.5, 0.25) ops.system('BandGeneral') ops.analysis('Transient') # Perform the transient analysis (50 sec) ops.analyze(1500, 0.5) uy2 = ops.nodeDisp(9, 2) print("uy(9) = ", uy2) assert abs(uy1 + 0.39426414168933876514) < 1e-12 and abs( uy2 + 0.00736847273806807632) < 1e-12 print("========================================")
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("=========================================")
KcurrSwitch = 1.0 KcommSwitch = 0.0 KinitSwitch = 0.0 lambdaI = 3.8846291886219655 lambdaJ = 64.78437186628662 omegaI = pow(lambdaI, 0.5) omegaJ = pow(lambdaJ, 0.5) alphaM = MpropSwitch * xDamp * (2 * omegaI * omegaJ) / (omegaI + omegaJ) betaKcurr = KcurrSwitch * 2 * xDamp / (omegaI + omegaJ) betaKcomm = KcommSwitch * 2 * xDamp / (omegaI + omegaJ) betaKinit = KinitSwitch * 2 * xDamp / (omegaI + omegaJ) ops.rayleigh(alphaM, betaKcurr, betaKinit, betaKcomm) print("\n已创建rayleigh") # ============================================================================= # clear all Analysis object # ============================================================================= ops.wipeAnalysis() # ============================================================================= # create timeSeries # ============================================================================= IDloadTag = 1001 iGMfile = pd.read_csv("GMX.txt", header=None) iGMdirection = 1 iGMfact = "210*10" dt = 0.01
def run_nlth_analysis_on_sdof_ops_py(capacity_curve, gmr, damping, degradation): cap_df = pd.DataFrame(capacity_curve) if any(cap_df.duplicated()): warnings.warn( "Warning: Duplicated pairs have been found in capacity curve!") ops.wipe() ops.model('basic', '-ndm', 1, '-ndf', 1) d_cap = capacity_curve[:, 0] f_cap = capacity_curve[:, 1] * 9.81 f_vec = np.zeros([5, 1]) d_vec = np.zeros([5, 1]) if len(f_cap) == 3: #bilinear curve f_vec[1] = f_cap[1] f_vec[4] = f_cap[-1] d_vec[1] = d_cap[1] d_vec[4] = d_cap[-1] d_vec[2] = d_vec[1] + (d_vec[4] - d_vec[1]) / 3 d_vec[3] = d_vec[1] + 2 * ((d_vec[4] - d_vec[1]) / 3) f_vec[2] = np.interp(d_vec[2], d_cap, f_cap) f_vec[3] = np.interp(d_vec[3], d_cap, f_cap) elif len(f_cap) == 4: f_vec[1] = f_cap[1] f_vec[4] = f_cap[-1] d_vec[1] = d_cap[1] d_vec[4] = d_cap[-1] f_vec[2] = f_cap[2] d_vec[2] = d_cap[2] d_vec[3] = np.mean([d_vec[2], d_vec[-1]]) f_vec[3] = np.interp(d_vec[3], d_cap, f_cap) elif len(f_cap) == 5: f_vec[1] = f_cap[1] f_vec[4] = f_cap[-1] d_vec[1] = d_cap[1] d_vec[4] = d_cap[-1] f_vec[2] = f_cap[2] d_vec[2] = d_cap[2] f_vec[3] = f_cap[3] d_vec[3] = d_cap[3] matTag_pinching = 10 if degradation == True: matargs = [ f_vec[1, 0], d_vec[1, 0], f_vec[2, 0], d_vec[2, 0], f_vec[3, 0], d_vec[3, 0], f_vec[4, 0], d_vec[4, 0], -1 * f_vec[1, 0], -1 * d_vec[1, 0], -1 * f_vec[2, 0], -1 * d_vec[2, 0], -1 * f_vec[3, 0], -1 * d_vec[3, 0], -1 * f_vec[4, 0], -1 * d_vec[4, 0], 0.5, 0.25, 0.05, 0.5, 0.25, 0.05, 0, 0.1, 0, 0, 0.2, 0, 0.1, 0, 0, 0.2, 0, 0.4, 0, 0.4, 0.9, 10, 'energy' ] else: matargs = [ f_vec[1, 0], d_vec[1, 0], f_vec[2, 0], d_vec[2, 0], f_vec[3, 0], d_vec[3, 0], f_vec[4, 0], d_vec[4, 0], -1 * f_vec[1, 0], -1 * d_vec[1, 0], -1 * f_vec[2, 0], -1 * d_vec[2, 0], -1 * f_vec[3, 0], -1 * d_vec[3, 0], -1 * f_vec[4, 0], -1 * d_vec[4, 0], 0.5, 0.25, 0.05, 0.5, 0.25, 0.05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 'energy' ] ops.uniaxialMaterial('Pinching4', matTag_pinching, *matargs) matTag_minmax = int(matTag_pinching / 10) ops.uniaxialMaterial('MinMax', matTag_minmax, matTag_pinching, '-min', -1 * d_vec[4, 0], '-max', d_vec[4, 0]) mx = 1 kx = f_vec[1, 0] / d_vec[1, 0] omega = np.sqrt(kx / mx) dt = gmr[1, 0] - gmr[0, 0] ops.node(1, 0) ops.node(2, 0, '-mass', float(mx)) ops.fix(1, 1) ops.element('zeroLength', 1, 1, 2, "-mat", matTag_minmax, "-dir", 1, '-doRayleigh', 1) gmr_values = gmr[:, 1] * 9.81 gmr_times = gmr[:, 0] ops.timeSeries('Path', 2, '-values', *gmr_values, '-time', *gmr_times) ops.pattern('UniformExcitation', 2, 1, '-accel', 2) ops.constraints('Plain') ops.numberer('RCM') ops.test('NormDispIncr', 1e-6, 50) ops.algorithm('Newton') ops.system('BandGeneral') ops.integrator('Newmark', 0.5, 0.25) ops.analysis('Transient') t_final = gmr[-1, 0] t_current = ops.getTime() ok = 0 #betaKinit=2*damping/omega alphaM = 2 * damping * omega time = [t_current] disps = [0.0] accels = [0.0] #ops.rayleigh(0,0,betaKinit,0) ops.rayleigh(alphaM, 0, 0, 0) # mass proportional damping while ok == 0 and t_current < t_final: ok = ops.analyze(1, dt) if ok != 0: print( "regular newton failed ... lets try an initail stiffness for this step" ) ops.test('NormDispIncr', 1.0e-6, 100, 0) ops.algorithm('ModifiedNewton', '-initial') ok = ops.analyze(1, dt) if ok != 0: print("reducing dt by 10") ndt = dt / 10 ok = ops.analyze(10, ndt) if ok == 0: print("that worked ... back to regular settings") ops.test('NormDispIncr', 1e-6, 50) ops.test('NormDispIncr', 1e-6, 50) t_current = ops.getTime() time.append(t_current) disps.append(ops.nodeDisp(2, 1)) accels.append(ops.nodeAccel(2, 1)) if ok != 0: print('NLTHA did not converge!') return time, disps, accels
op.integrator('LoadControl', 0.1) op.analysis('Static') op.analyze(10) op.loadConst('-time', 0.0) #applying Dynamic Ground motion analysis op.timeSeries('Path', 2, '-dt', 0.01, '-filePath', 'BM68elc.acc', '-factor', 1.0) op.pattern('UniformExcitation', 2, 1, '-accel', 2) #how to give accelseriesTag? eigen = op. eigen('-fullGenLapack', 1) import math power = math.pow(eigen, 0.5) betaKcomm = 2 * (0.02/power) op.rayleigh(0.0, 0.0, 0.0, betaKcomm) op.wipeAnalysis() op.constraints('Plain') op.numberer('Plain') op.system('BandGeneral') op.test('NormDispIncr', 1e-8, 10) op.algorithm('Newton') op.integrator('Newmark', 0.5, 0.25) op.analysis('Transient') op.analyze(1000, 0.02) u3 = op.nodeDisp(3, 1) print("u2 = ", u3) op.wipe()