def test_RCFrameGravity(): ops.wipe() exec(open('RCFrameGravity.py', 'r').read()) u3 = ops.nodeDisp(3, 2) u4 = ops.nodeDisp(4, 2) assert abs(u3 + 0.0183736) < 1e-6 and abs(u4 + 0.0183736) < 1e-6
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 run(arg_1, arg_2, arg_3, arg_4): ops.reset() ops.wipe() ops.model('basic', '-ndm', 3, '-ndf', 6) ops.node(1, 0.0, 0.0, 0.0) ops.node(2, 0.0, 3.2, 0.0) ops.fix(1, 1, 1, 1, 1, 1, 1) ops.uniaxialMaterial('Concrete01', 1, -80.0e6, -0.002, 0.0, -0.005) ops.section('Fiber', 1, '-GJ', 1) ops.patch('rect', 1, 10, 10, -0.8, -0.1, 0.8, 0.1) ops.geomTransf('Linear', 1, 0, 0, 1) ops.beamIntegration('Legendre', 1, 1, 10) ops.element('dispBeamColumn', 1, 1, 2, 1, 1) ops.timeSeries('Linear', 1) ops.pattern('Plain', 1, 1) ops.load(2, 0, -24586.24, 0, 0, 0, 0) ops.constraints('Plain') ops.numberer('RCM') ops.system('UmfPack') ops.test('NormDispIncr', 1.0e-6, 2000) ops.algorithm('Newton') ops.integrator('LoadControl', 0.01) ops.analysis('Static') ops.analyze(100) ops.wipeAnalysis() ops.loadConst('-time', 0.0) ops.recorder('Node', '-file', 'disp.out', ' -time', '-node', 2, '-dof', 1, 'disp') ops.recorder('Node', '-file', 'react.out', '-time ', '-node', 2, '-dof', 1, 'reaction') ops.timeSeries('Linear', 2) ops.pattern('Plain', 2, 2) ops.load(2, 11500, 0, 0, 0, 0, 0) ops.constraints('Plain') ops.numberer('RCM') ops.system('UmfPack') ops.test('NormDispIncr', 1.0, 2000) ops.algorithm('Newton') ops.integrator('LoadControl', 0.01) ops.analysis('Static') # ops.analyze(100) step = 100 data = np.zeros((step, 2)) for i in range(step): ops.analyze(1) data[i, 0] = ops.nodeDisp(2, 1) data[i, 1] = ops.getLoadFactor(2) * 11500 return data
def get_node_coords_and_disp(): node_coords = dict() node_disp = dict() node_tags = ops.getNodeTags() for i in node_tags: node_coords[i] = ops.nodeCoord(i) node_disp[i] = ops.nodeDisp(i) return (node_coords,node_disp)
def material_response(self, material, demand): """ Calculate the response of a material to a given load history. Parameters ---------- material: Material The material object to analyze. demand: DemandProtocol The load history the material shall be exposed to. Returns ------- response: DataFrame The DataFrame includes columns for strain (eps) and stress (sig). """ # initialize the analysis self._initialize() # define the structure struct = SDOF(Truss(material, l_tot=1., A_cs=1.)) struct.create_FEM(damping=False) id_ctrl_node = struct.ctrl_node load_dir = 1 # define the loading ops.timeSeries('Linear', 1) ops.pattern('Plain', 1, 1) if self.ndf == 1 and self.ndm == 1: ops.load(id_ctrl_node, 1.) # configure the analysis ops.constraints('Plain') ops.numberer('RCM') ops.system('UmfPack') ops.test('NormDispIncr', 1e-10, 100) ops.algorithm('NewtonLineSearch', '-maxIter', 100) # initialize the arrays for results result_size = demand.length response = pd.DataFrame(np.zeros((result_size + 1, 2)), columns=['eps', 'sig']) # perform the analysis for i, disp_incr in enumerate(demand.increments): ops.integrator('DisplacementControl', id_ctrl_node, load_dir, disp_incr) ops.analysis('Static') ops.analyze(1) response.loc[i + 1, 'eps'] = ops.nodeDisp(id_ctrl_node, load_dir) # response.loc[i+1, 'sig'] = ops.eleResponse(1, 'axialForce')[0] #![4] response.loc[i + 1, 'sig'] = ops.eleResponse(1, 'axialForce') #![4] return response
def PushoverLcD(dispMax): ControlNode = 4 ControlNodeDof = 1 du = 0.00002 * m # Define time series # timeSeries('Constant', tag, '-factor', factor=1.0) op.timeSeries('Constant', 1) op.timeSeries('Linear', 2) # define loads op.pattern('Plain', 1, 2) op.sp(ControlNode, ControlNodeDof, du) # Define Analysis Options # create SOE op.system("BandGeneral") # create DOF number op.numberer("Plain") # create constraint handler op.constraints("Transformation") # create integrator op.integrator("LoadControl", 1) # create algorithm op.algorithm("Newton") # create analysis object op.analysis("Static") # Create Test op.test('NormDispIncr', 1. * 10**-6, 50) # Run Analysis op.record() # ok = op.analyze(Nsteps) nn = 0 while (op.nodeDisp(ControlNode, ControlNodeDof) < dispMax): ok = op.analyze(1) if ok != 0: ok = BasicAnalysisLoop(ok, nn) if ok != 0: print("Analysis failed at load factor:", nn) break nn = +1 print() print("# Analysis Complete #")
def plot_deformed_shape(self, xlim, ylim, scale=1, arrow_len=10, arrow_width=2, save=''): ''' Plot deformed shape of the model. Args: xlim: A list of left and right limits of the x axis. ylim: A list of bottom and top limits of the y axis. scale: A float scale of the displayed deformations (default=1). arrow_len: An integer length of the load arrows displayed (default=10). arrow_width: An integer head width of the load arrows displayed (default=2). save: A string indicating save path for the figure (default='', meaning that the figure will NOT be saved by default). ''' fig, ax = plt.subplots(dpi=75) ax.set_axis_off() ax.grid(True, which='both', alpha=0.5) ax.axhline(y=0, color='k', lw=1) opsv.plot_defo(scale, fmt_undefo='k-', fmt_interp='k--') ax.axis('equal') ax.set(xlim=xlim, ylim=ylim) node_list = ops.getNodeTags() node_disp = np.array([ops.nodeDisp(n) for n in node_list]) node_coord = np.array([ops.nodeCoord(n) for n in node_list]) new_coord = node_disp[:, :-1] * scale + node_coord for node, Px, Py, M in self.loads: c = new_coord[node_list.index(node), :] ax.annotate('', xytext=(c[0] + abs(Px) * arrow_len, c[1] + abs(Py) * arrow_len), xy=(c[0], c[1]), arrowprops=dict(arrowstyle=f'-|>, \ head_width={arrow_width/5},\ head_length={arrow_width/2}', lw=arrow_width, fc='orangered', ec='orangered')) if save: fig.savefig(save, transparent=True) plt.show()
def run_analysis(): # build the model ops.model('basic', '-ndm', 2, '-ndf', 2) ops.node(1, 0, 0) ops.node(2, 4000, 0) ops.node(3, 8000, 0) ops.node(4, 12000, 0) ops.node(5, 4000, 4000) ops.node(6, 8000, 4000) ops.fix(1, 1, 1) ops.fix(4, 0, 1) ops.uniaxialMaterial('Elastic', 1, E) ops.element('truss', 1, 1, 2, Ao, 1) ops.element('truss', 2, 2, 3, Ao, 1) ops.element('truss', 3, 3, 4, Ao, 1) ops.element('truss', 4, 1, 5, Au, 1) ops.element('truss', 5, 5, 6, Au, 1) ops.element('truss', 6, 6, 4, Au, 1) ops.element('truss', 7, 2, 5, Ao, 1) ops.element('truss', 8, 3, 6, Ao, 1) ops.element('truss', 9, 5, 3, Ao, 1) ops.timeSeries('Linear', 1) ops.pattern('Plain', 1, 1) ops.load(2, 0, -P) ops.load(3, 0, -P) # build and perform the analysis ops.algorithm('Linear') ops.integrator('LoadControl', 1.0) ops.system('ProfileSPD') ops.numberer('RCM') ops.constraints('Plain') ops.analysis('Static') ops.analyze(1) node_disp = [[ops.nodeDisp(node_i, dof_j) for dof_j in [1, 2]] for node_i in range(1, 7)] return node_disp
def test_Truss(): # remove existing model ops.wipe() # set modelbuilder ops.model('basic', '-ndm', 2, '-ndf', 2) # create nodes ops.node(1, 0.0, 0.0) ops.node(2, 144.0, 0.0) ops.node(3, 168.0, 0.0) ops.node(4, 72.0, 96.0) # set boundary condition ops.fix(1, 1, 1) ops.fix(2, 1, 1) ops.fix(3, 1, 1) # define materials ops.uniaxialMaterial("Elastic", 1, 3000.0) # define elements ops.element("Truss", 1, 1, 4, 10.0, 1) ops.element("Truss", 2, 2, 4, 5.0, 1) ops.element("Truss", 3, 3, 4, 5.0, 1) # create TimeSeries ops.timeSeries("Linear", 1) # create a plain load pattern ops.pattern("Plain", 1, 1) # Create the nodal load - command: load nodeID xForce yForce ops.load(4, 100.0, -50.0) # ------------------------------ # Start of analysis generation # ------------------------------ # create SOE ops.system("BandSPD") # create DOF number ops.numberer("Plain") # create constraint handler ops.constraints("Plain") # create integrator ops.integrator("LoadControl", 1.0) # create algorithm ops.algorithm("Linear") # create analysis object ops.analysis("Static") # perform the analysis ops.analyze(1) ux = ops.nodeDisp(4, 1) uy = ops.nodeDisp(4, 2) assert abs(ux - 0.53009277713228375450) < 1e-12 and abs( uy + 0.17789363846931768864) < 1e-12
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)
"regular newton failed .. lets try an initail stiffness for this step" ) ops.test('NormDispIncr', 1.0e-12, 100, 0) ops.algorithm('ModifiedNewton', '-initial') ok = ops.analyze(1, .01) if ok == 0: print("that worked .. back to regular newton") ops.test('NormDispIncr', 1.0e-12, 10) ops.algorithm('Newton') tCurrent = ops.getTime() print(f'{tCurrent} [s] analyzed of {tFinal}') time.append(tCurrent) u3.append(ops.nodeDisp(2999, 1)) # Perform an eigenvalue analysis eigenValues = ops.eigen(numEigen) print("eigen values at end of transient:", eigenValues) results = open('results.out', 'a+') if ok == 0: results.write('PASSED : RCFrameEarthquake.py\n') print("Passed!") else: results.write('FAILED : RCFrameEarthquake.py\n') print("Failed!") results.close()
ops.nDMaterial('ElasticIsotropic', 1, 3000.0, 0.3) eleArgs = ['tri31', 1.0, 'PlaneStress', 1] ops.mesh('quad', 5, 4, 1, 4, 2, 3, sid, ndf, meshsize, *eleArgs) if pid == 0: ops.fix(pid, 1, 1) ops.fix(np + pid + 1, 1, 1) if pid == np - 1: ops.timeSeries('Linear', 1) ops.pattern('Plain', 1, 1) ops.load(np + pid + 2, 0.0, -1.0) ops.constraints('Transformation') ops.numberer('ParallelPlain') ops.system('Mumps') ops.test('NormDispIncr', 1e-6, 6) ops.algorithm('Newton') ops.integrator('LoadControl', 1.0) ops.analysis('Static') ops.stop() ops.start() ops.analyze(1) if pid == np - 1: print('Node', pid + 1, ops.nodeDisp(pid + 1)) ops.stop()
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 get_multi_pile_m( pile_layout, cap_edge=0, cap_thickness=2, pile_z0=-2.5, pile_z1=-30, pile_d=2, m0=7500000, top_f=0.0, top_h=0.0, top_m=0.0 ): if cap_edge == 0: if pile_d <= 1: cap_edge = max(0.25, 0.5 * pile_d) else: cap_edge = max(0.5, 0.3 * pile_d) cap_w = max(pile_layout[0]) - min(pile_layout[0]) + pile_d + cap_edge * 2 cap_l = max(pile_layout[1]) - min(pile_layout[1]) + pile_d + cap_edge * 2 top_f += cap_w * cap_l * cap_thickness * 26e3 # 承台自重 top_f += (cap_w * cap_l) * (-pile_z0 - cap_thickness) * 15e3 # 盖梁重量 pile_rows = len(pile_layout[1]) # 桩排数 top_f /= pile_rows # 桩顶力分配 top_h /= pile_rows # 桩顶水平力分配 top_m /= pile_rows # 桩顶弯矩分配 cap_i = cap_l * cap_thickness ** 3 / 12 / pile_rows # 承台横向刚度 pile_h = pile_z0 - pile_z1 pile_a = np.pi * (pile_d / 2) ** 2 pile_i = np.pi * pile_d ** 4 / 64 pile_b1 = 0.9 * (1.5 + 0.5 / pile_d) * 1 * pile_d # 建立模型 ops.wipe() ops.model('basic', '-ndm', 2, '-ndf', 3) # 建立节点 cap_bot = pile_z0 # ops.node(1, 0, cap_top) # 承台竖向节点 if 0 not in pile_layout[0]: ops.node(2, 0, cap_bot) # 建立桩基节点 node_z = np.linspace(pile_z0, pile_z1, elem_num + 1) for i, j in enumerate(pile_layout[0]): node_start = 100 + i * 300 for m, n in enumerate(node_z): ops.node(node_start + m + 1, j, n) ops.node(node_start + m + 151, j, n) nodes = {} for i in ops.getNodeTags(): nodes[i] = ops.nodeCoord(i) # 建立约束 for i, j in enumerate(pile_layout[0]): node_start = 100 + i * 300 for m, n in enumerate(node_z): ops.fix(node_start + m + 151, 1, 1, 1) if n == node_z[-1]: ops.fix(node_start + m + 1, 1, 1, 1) # 建立材料 for i in range(len(node_z)): pile_depth = i * (pile_h / elem_num) pile_depth_nominal = 10 if pile_depth <= 10 else pile_depth soil_k = m0 * pile_depth_nominal * pile_b1 * (pile_h / elem_num) if i == 0: ops.uniaxialMaterial('Elastic', 1 + i, soil_k / 2) continue ops.uniaxialMaterial('Elastic', 1 + i, soil_k) # 装配 ops.geomTransf('Linear', 1) # 建立单元 if len(pile_layout[0]) > 1: # 承台横向单元 cap_nodes = [] for i in nodes: if nodes[i][1] == cap_bot: if len(cap_nodes) == 0: cap_nodes.append(i) elif nodes[i][0] != nodes[cap_nodes[-1]][0]: cap_nodes.append(i) cap_nodes = sorted(cap_nodes, key=lambda x: nodes[x][0]) for i, j in enumerate(cap_nodes[:-1]): ops.element('elasticBeamColumn', 10 + i, j, cap_nodes[i+1], cap_l * cap_thickness, 3e10, cap_i, 1) pile_elem = [] for i, j in enumerate(pile_layout[0]): # 桩基单元 node_start = 100 + i * 300 pile_elem_i = [] for m, n in enumerate(node_z): if n != pile_z1: ops.element('elasticBeamColumn', node_start + m + 1, node_start + m + 1, node_start + m + 2, pile_a, 3e10, pile_i, 1) pile_elem_i.append(node_start + m + 1) ops.element('zeroLength', node_start + m + 151, node_start + m + 151, node_start + m + 1, '-mat', 1 + m, '-dir', 1) pile_elem.append(pile_elem_i) ops.timeSeries('Linear', 1) ops.pattern('Plain', 1, 1) for i in nodes: if nodes[i] == [0, pile_z0]: ops.load(i, -top_h, -top_f, top_m) # 加载 ops.system('BandGeneral') ops.numberer('Plain') ops.constraints('Plain') ops.integrator('LoadControl', 0.01) ops.test('EnergyIncr', 1e-6, 200) ops.algorithm('Newton') ops.analysis('Static') ops.analyze(100) node_disp = {} for i in ops.getNodeTags(): node_disp[i] = [j * 1000 for j in ops.nodeDisp(i)] elem_m = {} for i in pile_elem: for j in i: elem_m[j] = [k / 1000 for k in ops.eleForce(j)] plt.figure() for i, j in enumerate(pile_elem): plt.subplot(f'1{len(pile_elem)}{i+1}') if i == 0: plt.ylabel('Pile Depth(m)') node_disp_x = [] for m, n in enumerate(j): node_1 = ops.eleNodes(n)[0] if m == 0: plt.plot([0, node_disp[node_1][0]], [nodes[node_1][1], nodes[node_1][1]], linewidth=1.5, color='grey') else: plt.plot([0, node_disp[node_1][0]], [nodes[node_1][1], nodes[node_1][1]], linewidth=0.7, color='grey') node_disp_x.append(node_disp[node_1][0]) for m, n in enumerate(j): node_1 = ops.eleNodes(n)[0] if abs(node_disp[node_1][0]) == max([abs(i) for i in node_disp_x]): side = 1 if node_disp[node_1][0] > 0 else -1 plt.annotate(f'{node_disp[node_1][0]:.1f} mm', xy=(node_disp[node_1][0], nodes[node_1][1]), xytext=(0.4 + 0.1 * side, 0.5), textcoords='axes fraction', bbox=dict(boxstyle="round", fc="0.8"), arrowprops=dict(arrowstyle='->', connectionstyle=f"arc3,rad={side * 0.3}")) break plt.plot([0, 0], [node_z[0], node_z[-1]], linewidth=1.5, color='dimgray') plt.plot(node_disp_x, node_z[:-1], linewidth=1.5, color='midnightblue') plt.xlabel(f'Displacement_{i+1} (mm)') plt.show() plt.figure() for i, j in enumerate(pile_elem): plt.subplot(f'1{len(pile_elem)}{i + 1}') if i == 0: plt.ylabel('Pile Depth(m)') elem_mi = [] for m, n in enumerate(j): node_1 = ops.eleNodes(n)[0] if m == 0: plt.plot([0, elem_m[n][2]], [nodes[node_1][1], nodes[node_1][1]], linewidth=1.5, color='grey') else: plt.plot([0, elem_m[n][2]], [nodes[node_1][1], nodes[node_1][1]], linewidth=0.7, color='grey') elem_mi.append(elem_m[n][2]) for m, n in enumerate(j): node_1 = ops.eleNodes(n)[0] if abs(elem_m[n][2]) == max([abs(i) for i in elem_mi]): side = 1 if elem_m[n][2] > 0 else -1 plt.annotate(f'{elem_m[n][2]:.1f} kN.m', xy=(elem_m[n][2], nodes[node_1][1]), xytext=(0.4 + 0.1 * side, 0.5), textcoords='axes fraction', bbox=dict(boxstyle="round", fc="0.8"), arrowprops=dict(arrowstyle='->', connectionstyle=f"arc3,rad={side * 0.3}")) break plt.plot([0, 0], [node_z[0], node_z[-1]], linewidth=1.5, color='dimgray') plt.plot(elem_mi, node_z[:-1], linewidth=1.5, color='brown') plt.xlabel(f'Moment_{i + 1} (kN.m)') plt.show() return pile_elem, elem_m
lowerBound = 1*inches**2 upperBound = 20*inches**2 Narea = 20 trialAreas = np.linspace(lowerBound,upperBound,Narea) outputDisp = np.zeros([Narea,Narea]) for ii, A1 in enumerate(trialAreas): for jj, A2 in enumerate(trialAreas): GetSections(E) GetModel(A1,A2) RunGravityAnalysis(Py) outputDisp[ii,jj] = op.nodeDisp(4,2) op.wipe() shiftOutput = np.abs(outputDisp - targetDisp) [[MinIndexA1] ,[MinIndexA2] ] = np.where(shiftOutput == np.min(shiftOutput)) A1Optimal = trialAreas[MinIndexA1] A2Optimal = trialAreas[MinIndexA2]
ops.fix(2, 1, 1) ops.fix(3, 1, 1) ops.element('Truss', 2, 2, 4, 5.0, 1) ops.element('Truss', 3, 3, 4, 5.0, 1) ops.constraints('Transformation') ops.numberer('ParallelPlain') ops.system('Mumps') ops.test('NormDispIncr', 1e-6, 6, 2) ops.algorithm('Newton') ops.integrator('LoadControl', 0.1) ops.analysis('Static') ops.analyze(10) print('Node 4: ', [ops.nodeCoord(4), ops.nodeDisp(4)]) ops.loadConst('-time', 0.0) if pid == 0: ops.pattern('Plain', 2, 1) ops.load(4, 1.0, 0.0) ops.domainChange() ops.integrator('ParallelDisplacementControl', 4, 1, 0.1) ops.analyze(10) print('Node 4: ', [ops.nodeCoord(4), ops.nodeDisp(4)]) ops.stop()
ops.element('Truss', 1, 1, 4, 10.0, 1) ops.timeSeries('Linear', 1) ops.pattern('Plain', 1, 1) ops.load(4, 100.0, -50.0) ops.element('Truss', 2, 2, 4, 5.0, 1) ops.element('Truss', 3, 3, 4, 5.0, 1) ops.constraints('Transformation') ops.numberer('ParallelPlain') ops.system('Umfpack') ops.test('NormDispIncr', 1e-6, 6) ops.algorithm('Newton') ops.integrator('LoadControl', 0.1) ops.analysis('Static') ops.analyze(10) if pid == 0: print('Processor 0') print('Node 4 (E =', E, ') Disp :', ops.nodeDisp(4)) ops.barrier() if pid == 1: print('Processor 1') print('Node 4 (E =', E, ') Disp :', ops.nodeDisp(4)) ops.stop()
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 test_PlanarTruss(): A = 10.0 E = 3000. L = 200.0 alpha = 30.0 P = 200.0 sigmaYP = 60.0 pi = 2.0*asin(1.0) alphaRad = alpha*pi/180. cosA = cos(alphaRad) sinA = sin(alphaRad) # EXACT RESULTS per Popov F1 = P/(2*cosA*cosA*cosA + 1) F2 = F1*cosA*cosA disp = -F1*L/(A*E) # create the finite element model ops.wipe() ops.model('Basic', '-ndm', 2, '-ndf', 2) dX = L*tan(alphaRad) ops.node( 1, 0.0, 0.0) ops.node( 2, dX, 0.0) ops.node( 3, 2.0*dX, 0.0) ops.node( 4, dX, -L ) ops.fix( 1, 1, 1) ops.fix( 2, 1, 1) ops.fix( 3, 1, 1) ops.uniaxialMaterial('Elastic', 1, E) ops.element('Truss', 1, 1, 4, A, 1) ops.element('Truss', 2, 2, 4, A, 1) ops.element('Truss', 3, 3, 4, A, 1) ops.timeSeries('Linear', 1) ops.pattern('Plain', 1, 1) ops.load( 4, 0., -P) ops.numberer( 'Plain') ops.constraints( 'Plain') ops.algorithm( 'Linear') ops.system('ProfileSPD') ops.integrator('LoadControl', 1.0) ops.analysis('Static') ops.analyze(1) # determine PASS/FAILURE of test testOK = 0 # # print table of camparsion # comparisonResults = F2, F1, F2 print("\nElement Force Comparison:") tol = 1.0e-6 print('{:>10}{:>15}{:>15}'.format('Element','OpenSees','Popov')) for i in range(1,4): exactResult = comparisonResults[i-1] eleForce = ops.eleResponse(i, 'axialForce') print('{:>10d}{:>15.4f}{:>15.4f}'.format(i, eleForce[0], exactResult)) if abs(eleForce[0]-exactResult) > tol: testOK = -1 print("failed force-> ", abs(eleForce[0]-exactResult), " ", tol) print("\nDisplacement Comparison:") osDisp = ops.nodeDisp( 4, 2) print('{:>10}{:>15.8f}{:>10}{:>15.8f}'.format('OpenSees:',osDisp,'Exact:', disp)) if abs(osDisp-disp) > tol: testOK = -1 print("failed linear disp") print("\n\n - NonLinear (Example2.23)") #EXACT # Exact per Popov PA = (sigmaYP*A) * (1.0+2*cosA*cosA*cosA) dispA = PA/P*disp PB = (sigmaYP*A) * (1.0+2*cosA) dispB = dispA / (cosA*cosA) # create the new finite element model for nonlinear case # will apply failure loads and calculate displacements ops.wipe() ops.model('Basic', '-ndm', 2, '-ndf', 2) ops.node( 1, 0.0, 0.0) ops.node( 2, dX, 0.0) ops.node( 3, 2.0*dX, 0.0) ops.node( 4, dX, -L ) ops.fix( 1, 1, 1) ops.fix( 2, 1, 1) ops.fix( 3, 1, 1) ops.uniaxialMaterial( 'ElasticPP', 1, E, sigmaYP/E) ops.element('Truss', 1, 1, 4, A, 1) ops.element('Truss', 2, 2, 4, A, 1) ops.element('Truss', 3, 3, 4, A, 1) ops.timeSeries( 'Path', 1, '-dt', 1.0, '-values', 0.0, PA, PB, PB) ops.pattern('Plain', 1, 1) ops.load( 4, 0., -1.0) ops.numberer('Plain') ops.constraints('Plain') ops.algorithm('Linear') ops.system('ProfileSPD') ops.integrator('LoadControl', 1.0) ops.analysis('Static') ops.analyze(1) osDispA = ops.nodeDisp( 4, 2) #print node 4 #print ele ops.analyze(1) osDispB = ops.nodeDisp( 4, 2) #print node 4 #print ele # determine PASS/FAILURE of test testOK = 0 print("\nDisplacement Comparison:") print("elastic limit state:") osDisp = ops.nodeDisp( 4, 2) print('{:>10}{:>15.8f}{:>10}{:>15.8f}'.format('OpenSees:',osDispA,'Exact:',dispA)) if abs(osDispA-dispA) > tol: testOK = -1 print("failed nonlineaer elastic limit disp") print("collapse limit state:") print('{:>10}{:>15.8f}{:>10}{:>15.8f}'.format('OpenSees:',osDispB,'Exact:',dispB)) if abs(osDispB-dispB) > tol: testOK = -1 print("failed nonlineaer collapse limit disp") assert testOK == 0
def run_analysis(GM_dt, GM_npts, TS_List, EDP_specs, model_params): """ Run dynamic analysis for a time history and return a dictionary of envelope EDPs. Assumes that length is measured in inches and acceleration in in/s2 Parameters ---------- GM_dt: float Time step of time series GM_npts: float Number of points in time series TS_List: float 1x2 list where first component is a list of accelerations in the X direction, the second component is a list of accelerations in the Y direction. EDP_specs: dict """ stories = model_params["NumberOfStories"] node_tags = list(range(stories + 1)) height = ops.nodeCoord(node_tags[-1], 3) - ops.nodeCoord(node_tags[0], 3) # define parameters for dynamic analysis dt = GM_dt # time increment for analysis GMX = TS_List[0] # list of GM accelerations in X direction GMY = TS_List[1] # list of GM accelerations in Y direction driftLimit = 0.20 # interstory drift limit indicating collapse tol = 1.e-08 # tolerance criteria to check for convergence maxiter = 30 # max number of iterations to check subSteps = 2 # number of subdivisions in cases of ill convergence # pad shorter record with zeros (free vibration) such that two horizontal records are the same length nsteps = max(len(GMX), len(GMY)) for GM in [GMX, GMY]: if len(GM) < nsteps: diff = nsteps - len(GM) GM.extend(np.zeros(diff)) # initialize dictionary of envelope EDPs envelopeDict = {} for edp in EDP_specs: envelopeDict[edp] = {} for loc in EDP_specs[edp]: envelopeDict[edp][loc] = np.zeros(len( EDP_specs[edp][loc])).tolist() #print(envelopeDict) # initialize dictionary of time history EDPs time_analysis = np.zeros(nsteps * 5) acc_history = {} for floor in range(stories + 1): acc_history.update( {floor: { 1: time_analysis.copy(), 2: time_analysis.copy() }}) ops.wipeAnalysis() ops.constraints( 'Transformation' ) # handles boundary conditions based on transformation equation method ops.numberer('RCM') # renumber dof's to minimize band-width (optimization) ops.system('UmfPack' ) # constructs sparse system of equations using UmfPack solver ops.test( 'NormDispIncr', tol, maxiter ) # tests for convergence using norm of left-hand side of matrix equation ops.algorithm( 'NewtonLineSearch' ) # use Newton's solution algorithm: updates tangent stiffness at every iteration ops.integrator( 'Newmark', 0.5, 0.25) # Newmark average acceleration method for numerical integration ops.analysis('Transient') # define type of analysis: time-dependent # initialize variables maxDiv = 1024 minDiv = subSteps step = 0 ok = 0 breaker = 0 count = 0 while step < nsteps and ok == 0 and breaker == 0: step = step + 1 # take 1 step ok = 2 div = minDiv length = maxDiv while div <= maxDiv and length > 0 and breaker == 0: stepSize = dt / div # perform analysis for one increment; will return 0 if no convergence issues ok = ops.analyze(1, stepSize) if ok == 0: count = count + 1 length = length - maxDiv / div floor = 1 while floor <= stories: # check if drift limits are satisfied # check X direction drifts (direction 1) drift_x = abs( ops.nodeDisp(node_tags[1], 1) - ops.nodeDisp(node_tags[0], 1)) / height if drift_x >= driftLimit: breaker = 1 # check Y direction drifts (direction 2) drift_y = abs( ops.nodeDisp(node_tags[1], 2) - ops.nodeDisp(node_tags[0], 2)) / height if drift_y >= driftLimit: breaker = 1 # save parameter values in recording dictionaries at every step time_analysis[count] = time_analysis[count - 1] + stepSize envelopeDict['PID'][floor][0] = max( drift_x, envelopeDict['PID'][floor][0]) envelopeDict['PID'][floor][1] = max( drift_y, envelopeDict['PID'][floor][1]) floor = floor + 1 for floor in range(stories + 1): for dof in [1, 2]: acc_history[floor][dof][count] = ops.nodeAccel( node_tags[floor], dof) else: div = div * 2 print("Number of increments increased to ", str(div)) # end analysis once drift limit has been reached if breaker == 1: ok = 1 print("Collapse drift has been reached") print("Number of analysis steps completed: {}".format(count)) # remove extra zeros from the end of the time history time_analysis = time_analysis[1:count + 1] # generate time array from recording time_record = np.linspace(0, nsteps * dt, num=nsteps, endpoint=False) # remove extra zeros from accel time history, add GM to obtain absolute a # acceleration, and record envelope value GMX_interp = np.interp(time_analysis, time_record, GMX) GMY_interp = np.interp(time_analysis, time_record, GMY) for floor in range(0, stories + 1): # X direction envelopeDict['PFA'][floor][0] = max( abs(np.asarray(acc_history[floor][1][1:count + 1]) + GMX_interp)) # Y direction envelopeDict['PFA'][floor][1] = max( abs(np.asarray(acc_history[floor][2][1:count + 1]) + GMY_interp)) return envelopeDict
def run_sensitivity_pushover_analysis(ctrlNode, baseNodes, dof, Dincr, max_disp, SensParam, IOflag=False): """ Run pushover analysis with sensitivity """ ops.wipeAnalysis() start_time = time.time() ops.loadConst("-time", 0.0) title("Running Displacement-Control Pushover Sensitivity Analysis ...") testType = "NormDispIncr" # EnergyIncr tolInit = 1.0E-8 iterInit = 10 # Set the initial Max Number of Iterations algorithmType = "Newton" # Set the algorithm type ops.system("BandGeneral") ops.constraints("Transformation") ops.numberer("RCM") ops.test(testType, tolInit, iterInit) ops.algorithm(algorithmType) # Change the integration scheme to be displacement control # node dof init Jd min max ops.integrator("DisplacementControl", ctrlNode, dof, Dincr) ops.analysis("Static") ops.sensitivityAlgorithm( "-computeAtEachStep" ) # automatically compute sensitivity at the end of each step if IOflag: print( f"Single Pushover: Push node {ctrlNode} to {max_disp} {LunitTXT}.\n" ) # Set some parameters tCurrent = ops.getTime() currentStep = 1 outputs = { "time": np.array([]), "disp": np.array([]), "force": np.array([]), } for sens in SensParam: outputs[f"sensLambda_{sens}"] = np.array([]), nodeList = [] for node in baseNodes: nodeList.append(f"- ops.nodeReaction({node}, dof) ") nodeList = "".join(nodeList) currentDisp = ops.nodeDisp(ctrlNode, dof) ok = 0 while ok == 0 and currentDisp < max_disp: ops.reactions() ok = ops.analyze(1) tCurrent = ops.getTime() currentDisp = ops.nodeDisp(ctrlNode, dof) if IOflag: print( f"Current displacement ==> {ops.nodeDisp(ctrlNode, dof):.3f} {LunitTXT}" ) # if the analysis fails try initial tangent iteration if ok != 0: print("\n==> Trying relaxed convergence...") ops.test(testType, tolInit / 0.01, iterInit * 50) ok = ops.analyze(1) if ok == 0: print("==> that worked ... back to default analysis...\n") ops.test(testType, tolInit, iterInit) if ok != 0: print("\n==> Trying Newton with initial then current...") ops.test(testType, tolInit / 0.01, iterInit * 50) ops.algorithm("Newton", "-initialThenCurrent") ok = ops.analyze(1) if ok == 0: print("==> that worked ... back to default analysis...\n") ops.algorithm(algorithmType) ops.test(testType, tolInit, iterInit) if ok != 0: print("\n==> Trying ModifiedNewton with initial...") ops.test(testType, tolInit / 0.01, iterInit * 50) ops.algorithm("ModifiedNewton", "-initial") ok = ops.analyze(1) if ok == 0: print("==> that worked ... back to default analysis...\n") ops.algorithm(algorithmType) ops.test(testType, tolInit, iterInit) currentStep += 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"], eval(nodeList)) for sens in SensParam: # sensLambda(patternTag, paramTag) outputs[f"sensLambda_{sens}"] = np.append( outputs[f"sensLambda_{sens}"], ops.sensLambda(1, sens)) # Print a message to indicate if analysis completed succesfully or not if ok == 0: title("Pushover Analysis Completed Successfully!") else: title("Pushover Analysis Completed Failed!") print( f"Analysis elapsed time is {(time.time() - start_time):.3f} seconds.\n" ) return outputs
1: 'KrylovNewton', 2: 'SecantNewton', 4: 'RaphsonNewton', 5: 'PeriodicNewton', 6: 'BFGS', 7: 'Broyden', 8: 'NewtonLineSearch' } for i in test: for j in algorithm: if ok != 0: if j < 4: op.algorithm(algorithm[j], '-initial') else: op.algorithm(algorithm[j]) op.test(test[i], Tol, 1000) ok = op.analyze(Nsteps) print(test[i], algorithm[j], ok) if ok == 0: break else: continue u2 = op.nodeDisp(2, 1) print("u2 = ", u2) op.wipe()
fx = 10 * kN fy = 0 ops.load(8, fx, fy) #for i in range(nNode): # if (Node[i][0] == 2): # ops.load(i+1, fx, fy) ops.system('FullGeneral') # probar otros solvers: 'UmfPack' 'SparseSYM' ops.numberer('Plain') ops.constraints('Plain') ops.integrator('LoadControl', 0.1) ops.algorithm('Linear') ops.analysis('Static') ops.analyze(10) # Grafico de la deformada fig = plt.figure(figsize=(10, 10)) opsv.plot_defo(200) plt.show() # Desplazamiento disp = ops.nodeDisp(8, 2) print(disp) # plot esfuerzos quad 2D fig = plt.figure(figsize=(10, 10)) sig_out = opsv.quad_sig_out_per_node() # componentes: sxx, syy, sxy, svm, s1, s2, angle. (n_nodes x 7) opsv.plot_stress_2d(sig_out[:, 1], mesh_outline=1, cmap='plasma') plt.colorbar() plt.show()
def runAnalysis(k): """ Tests and individual and returns the result of that test. The user should consider if it's possible for the test not to work. """ Fu = 21.1 * 10**3 # k = 2.6*10**6 b = 0.015 R0 = 19 cR1 = .95 cR2 = .15 Fu = 22.3 * 10**3 # k = 2.6*10**6 b = 0.0129 R0 = 3.1 cR1 = .3 cR2 = .01 # 21.1*10**3, 2.6*10**6, 0.015, 19, .95, .15] # 2.25427928e+04 3.33339323e+06 1.96273081e-02 5.46515829e+00 # 6.98429661e-01 5.28210755e-02 # 2.20833537e+04 3.03336982e+06 1.28872130e-02 3.13990345e+00 # 3.36067251e-01 1.04312516e-01 op.wipe() op.model('Basic', '-ndm', 2, '-ndf', 3) ## Analysis Parameters material(s) ## ------------------ LoadProtocol = np.array([ 0.0017, 0.005, 0.0075, 0.012, 0.018, 0.027, 0.04, 0.054, 0.068, 0.072, 0. ]) # Step size dx = 0.0001 op.uniaxialMaterial('Steel02', 1, Fu, k, b, R0, cR1, cR2, 0., 1., 0., 1.) ERelease = 1. op.uniaxialMaterial('Elastic', 2, ERelease, 0.0) ## Define geometric transformation(s) ## ---------------------------------- #geomTransf('Linear',1) op.geomTransf('PDelta', 1) op.beamIntegration('Lobatto', 1, 1, 3) # Define geometry # --------------- op.node(1, 0., 0., '-ndf', 3) op.node(2, 0., 0., '-ndf', 3) op.fix(1, 1, 1, 1) # Define element(s) # ----------------- op.element("zeroLength", 1, 1, 2, '-mat', 1, 2, 2, '-dir', 1, 2, 3, '-orient', 1., 0., 0., 0., 1., 0.) # Define Recorder(s) # ----------------- op.recorder('Node', '-file', 'RFrc.out', '-time', '-nodeRange', 1, 1, '-dof', 1, 'reaction') op.recorder('Node', '-file', 'Disp.out', '-time', '-nodeRange', 2, 2, '-dof', 1, 'disp') # Define Analysis Parameters # ----------------- op.timeSeries('Linear', 1, '-factor', 1.0) op.pattern('Plain', 1, 1, '-fact', 1.) op.load(2, 1., 0.0, 0.0) # op.initialize() op.constraints("Plain") op.numberer("Plain") # System of Equations op.system("UmfPack", '-lvalueFact', 10) # Convergence Test op.test('NormDispIncr', 1. * 10**-8, 25, 0, 2) # Solution Algorithm op.algorithm('Newton') # Integrator op.integrator('DisplacementControl', 2, 1, dx) # Analysis Type op.analysis('Static') ControlNode = 2 ControlNodeDof = 1 op.record() ok = 0 # Define Analysis for x in LoadProtocol: for ii in range(0, 2): # op. op.integrator('DisplacementControl', ControlNode, ControlNodeDof, dx) while (op.nodeDisp(2, 1) < x): ok = op.analyze(1) if ok != 0: print('Ending analysis') op.wipe() return np.array([0, 0]) op.integrator('DisplacementControl', ControlNode, ControlNodeDof, -dx) while (op.nodeDisp(2, 1) > -x): ok = op.analyze(1) if ok != 0: print('Ending analysis') op.wipe() return np.array([0, 0]) op.wipe() fileDispName = os.path.join('Disp.out') fileForceName = os.path.join('RFrc.out') disp = np.loadtxt(fileDispName) RFrc = np.loadtxt(fileForceName) # try: x = disp[:, 1] y = -RFrc[:, 1] xy = np.column_stack([x, y]) return xy
def test_PinchedCylinder(): P = 1 R = 300. L = 600. E = 3e6 thickness = R / 100. uExact = -164.24 * P / (E * thickness) formatString = '{:>20s}{:>15.5e}' print("\n Displacement Under Applied Load:\n") formatString = '{:>20s}{:>10s}{:>15s}{:>15s}{:>15s}' print( formatString.format("Element Type", " mesh ", "OpenSees", "Exact", "%Error")) for shellType in ['ShellMITC4', 'ShellDKGQ', 'ShellNLDKGQ']: for numEle in [4, 16, 32]: ops.wipe() # ---------------------------- # Start of model generation # ---------------------------- ops.model('basic', '-ndm', 3, '-ndf', 6) radius = R length = L / 2. E = 3.0e6 v = 0.3 PI = 3.14159 ops.nDMaterial('ElasticIsotropic', 1, E, v) ops.nDMaterial('PlateFiber', 2, 1) ops.section('PlateFiber', 1, 2, thickness) #section ElasticMembranePlateSection 1 E v thickness 0. nR = numEle nY = numEle tipNode = (nR + 1) * (nY + 1) #create nodes nodeTag = 1 for i in range(nR + 1): theta = i * PI / (2.0 * nR) xLoc = 300 * cos(theta) zLoc = 300 * sin(theta) for j in range(nY + 1): yLoc = j * length / (1.0 * nY) ops.node(nodeTag, xLoc, yLoc, zLoc) nodeTag += 1 #create elements eleTag = 1 for i in range(nR): iNode = i * (nY + 1) + 1 jNode = iNode + 1 lNode = iNode + (nY + 1) kNode = lNode + 1 for j in range(nY): ops.element(shellType, eleTag, iNode, jNode, kNode, lNode, 1) eleTag += 1 iNode += 1 jNode += 1 kNode += 1 lNode += 1 # define the boundary conditions ops.fixX(radius, 0, 0, 1, 1, 1, 0, '-tol', 1.0e-2) ops.fixZ(radius, 1, 0, 0, 0, 1, 1, '-tol', 1.0e-2) ops.fixY(0., 1, 0, 1, 0, 0, 0, '-tol', 1.0e-2) ops.fixY(length, 0, 1, 0, 1, 0, 1, '-tol', 1.0e-2) #define loads ops.timeSeries('Linear', 1) ops.pattern('Plain', 1, 1) ops.load(tipNode, 0., 0., -1. / 4.0, 0., 0., 0.) ops.integrator('LoadControl', 1.0) ops.test('EnergyIncr', 1.0e-10, 20, 0) ops.algorithm('Newton') ops.numberer('RCM') ops.constraints('Plain') ops.system('Umfpack') ops.analysis('Static') ops.analyze(1) res = ops.nodeDisp(tipNode, 3) err = abs(100 * (uExact - res) / uExact) formatString = '{:>20s}{:>5d}{:>3s}{:>2d}{:>15.5e}{:>15.5e}{:>15.2f}' print( formatString.format(shellType, numEle, " x ", numEle, res, uExact, err)) tol = 5.0 if abs(100 * (uExact - res) / uExact) > tol: testOK = 1 else: testOK = 0 assert testOK == 0
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 get_pile_m(pile_z0=0, pile_z1=-30, pile_d=2, m0=7.5, pile_f=0, pile_m=0): pile_h = pile_z0 - pile_z1 pile_a = np.pi * (pile_d / 2) ** 2 pile_i = np.pi * pile_d ** 4 / 64 pile_b1 = 0.9 * (1.5 + 0.5 / pile_d) * 1 * pile_d # 建立模型 ops.wipe() ops.model('basic', '-ndm', 2, '-ndf', 3) # 建立节点 node_z = np.linspace(pile_z0, pile_z1, elem_num + 1) for i, j in enumerate(node_z): ops.node(i + 1, 0, j) ops.node(i + 201, 0, j) # 约束 for i in range(len(node_z)): ops.fix(i + 1, 0, 1, 0) ops.fix(i + 201, 1, 1, 1) # 建立材料 ops.uniaxialMaterial('Elastic', 1, 3e4) for i in range(len(node_z)): pile_depth = i * (pile_h / elem_num) pile_depth_nominal = 10 if pile_depth <= 10 else pile_depth soil_k = m0 * pile_depth_nominal * pile_b1 * (pile_h / elem_num) if i == 0: ops.uniaxialMaterial('Elastic', 100 + i, soil_k / 2) continue ops.uniaxialMaterial('Elastic', 100 + i, soil_k) # 装配 ops.geomTransf('Linear', 1) # 建立单元 for i in range(elem_num): ops.element('elasticBeamColumn', i + 1, i + 1, i + 2, pile_a, 3e10, pile_i, 1) # 建立弹簧 for i in range(len(node_z)): ops.element('zeroLength', i + 201, i + 1, i + 201, '-mat', 100 + i, '-dir', 1) ops.timeSeries('Linear', 1) ops.pattern('Plain', 1, 1) ops.load(1, pile_f, 0, pile_m) ops.system('BandGeneral') ops.numberer('Plain') ops.constraints('Plain') ops.integrator('LoadControl', 0.01) ops.test('EnergyIncr', 1e-6, 200) ops.algorithm('Newton') ops.analysis('Static') ops.analyze(100) # 绘制位移图 node_disp = [] for i in range(101): node_disp.append(ops.nodeDisp(i + 1)) node_disp = np.array(node_disp) * 1000 plt.figure() plt.subplot(121) for i, j in enumerate(node_z): if abs(node_disp[:, 0][i]) > max(abs(node_disp[:, 0])) / 50: if i == 0: plt.plot([0, node_disp[:, 0][i]], [j, j], linewidth=1.5, color='grey') else: plt.plot([0, node_disp[:, 0][i]], [j, j], linewidth=0.7, color='grey') if abs(node_disp[:, 0][i]) == max(abs(node_disp[:, 0])): plt.annotate(f'{node_disp[:, 0][i]:.1f} mm', xy=(node_disp[:, 0][i], j), xytext=(0.3, 0.5), textcoords='axes fraction', bbox=dict(boxstyle="round", fc="0.8"), arrowprops=dict(arrowstyle='->', connectionstyle="arc3,rad=-0.3")) plt.plot([0, 0], [node_z[0], node_z[-1]], linewidth=1.5, color='dimgray') plt.plot(node_disp[:, 0], node_z, linewidth=1.5, color='midnightblue') plt.xlabel('Displacement(mm)') plt.ylabel('Pile Depth(m)') # 绘制弯矩图 elem_m = [] for i in range(100): elem_m.append(ops.eleForce(i + 1)) elem_m = np.array(elem_m) / 1000 plt.subplot(122) for i, j in enumerate(node_z[:-1]): if abs(elem_m[:, 2][i]) > max(abs(elem_m[:, 2])) / 50: if i == 0: plt.plot([0, elem_m[:, 2][i]], [j, j], linewidth=1.5, color='grey') else: plt.plot([0, elem_m[:, 2][i]], [j, j], linewidth=0.7, color='grey') if abs(elem_m[:, 2][i]) == max(abs(elem_m[:, 2])): plt.annotate(f'{elem_m[:, 2][i]:.1f} kN.m', xy=(elem_m[:, 2][i], j), xytext=(0.5, 0.5), textcoords='axes fraction', bbox=dict(boxstyle="round", fc="0.8"), arrowprops=dict(arrowstyle='->', connectionstyle="arc3,rad=0.3")) plt.plot([0, 0], [node_z[0], node_z[-1]], linewidth=1.5, color='dimgray') plt.plot(elem_m[:, 2], node_z[:-1], linewidth=1.5, color='brown') plt.xlabel('Moment(kN.m)') # plt.ylabel('Pile Depth(m)') plt.show() return abs(max(elem_m[:, 2]))
def 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
for i in range(nNode): ops.node(i+1, *Node[i][1:]) # construccion de elementos for i in range(nEle): if (Ele[i][0] == 1): ops.element('quad', i+1, *Ele[i][2:], B, 'PlaneStress', Ele[i][0]) # condiciones de frontera boundFix(nNode, Node) ops.timeSeries('Linear',1) ops.pattern('Plain',1,1) fx = 0 fy = -10*kN ops.load(2, fx, fy) #for i in range(nNode): # if (Node[i][0] == 2): # ops.load(i+1, fx, fy) ops.system('FullGeneral') # probar otros solvers: 'UmfPack' 'SparseSYM' ops.numberer('Plain') ops.constraints('Plain') ops.integrator('LoadControl',1) ops.algorithm('Linear') ops.analysis('Static') ops.analyze(1) # Desplazamiento disp = ops.nodeDisp(2,2) print(disp)
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