def run(out_folder): osi = o3.OpenSeesInstance(ndm=2, ndf=2, state=3) x_centre = 0.0 y_centre = 0.0 top_node = o3.node.Node(osi, x_centre, y_centre) o3db = connect_to_db_and_obj_holder('db/truss_ops') # o3db = O3ObjectDatabase() o3db.add_obj(top_node, 'top_node') bot_nodes = [] sf_eles = [] o3.Mass(osi, top_node, 10, 10) fy = 500 k = 1.0e4 b = 0.1 pro_params = [5, 0.925, 0.15] # sf_mat = o3.uniaxial_material.SteelMPF(osi, fy, fy, k, b, b, params=pro_params) sf_mat = o3.uniaxial_material.Elastic(osi, k) diff_pos = 0.5 depth = 1 bot_nodes.append(o3.node.Node(osi, x_centre - diff_pos, y_centre - depth)) o3.Fix2DOF(osi, bot_nodes[0], o3.cc.FIXED, o3.cc.FIXED) bot_nodes.append(o3.node.Node(osi, x_centre + diff_pos, y_centre - depth)) o3.Fix2DOF(osi, bot_nodes[1], o3.cc.FIXED, o3.cc.FIXED) sf_eles.append( o3.element.Truss(osi, [top_node, bot_nodes[0]], big_a=1.0, mat=sf_mat)) sf_eles.append( o3.element.Truss(osi, [top_node, bot_nodes[1]], big_a=1.0, mat=sf_mat)) o3db.add_objs(sf_eles, 'sf_eles') save_db_state_and_objs(1, o3db)
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 o3.Fix3DOF(osi, top_node, o3.cc.FREE, o3.cc.FIXED, o3.cc.FIXED) o3.Fix3DOF(osi, bot_node, o3.cc.FIXED, o3.cc.FIXED, o3.cc.FIXED) # Set out-of-plane DOFs to be slaved o3.EqualDOF(osi, top_node, bot_node, [o3.cc.Y, o3.cc.DOF2D_ROTZ]) # nodal mass (weight / g): o3.Mass(osi, top_node, 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 values = list(-1 * motion) # should be negative acc_series = o3.time_series.Path(osi, dt, values) o3.pattern.UniformExcitation(osi, o3.cc.X, accel_series=acc_series) # set damping based on first eigen mode angular_freq2 = o3.get_eigen(osi, solver='fullGenLapack', n=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 o3.wipe_analysis(osi) 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": [], "force": []} o3.record(osi) curr_time = o3.get_time(osi) while curr_time < analysis_time: outputs["time"].append(curr_time) outputs["rel_disp"].append(o3.get_node_disp(osi, top_node, o3.cc.X)) outputs["rel_accel"].append(o3.get_node_accel(osi, top_node, o3.cc.X)) o3.gen_reactions(osi) outputs["force"].append(-o3.get_node_reaction( osi, bot_node, o3.cc.X)) # Negative since diff node o3.analyze(osi, 1, analysis_dt) curr_time = o3.get_time(osi) o3.wipe(osi) for item in outputs: outputs[item] = np.array(outputs[item]) return outputs
def get_response(bd, asig, dtype, l_ph): """ Compute the response of a nonlinear lollipop on a foundation with linear/nonlinear soil Units are N, m, s :param bd: SDOF building object :param asig: Acceleration signal object :return: """ osi = o3.OpenSeesInstance(ndm=2, state=3) # Establish nodes top_ss_node = o3.node.Node(osi, 0, bd.h_eff) bot_ss_node = o3.node.Node(osi, 0, 0) # Fix bottom node o3.Fix3DOF(osi, bot_ss_node, o3.cc.FIXED, o3.cc.FIXED, o3.cc.FIXED) # nodal mass (weight / g): o3.Mass(osi, top_ss_node, bd.mass_eff, 0.0, 0) # Define a column element with a plastic hinge at base transf = o3.geom_transf.Linear2D(osi, []) # can change for P-delta effects area = 1.0 e_mod = 200.0e9 iz = bd.k_eff * bd.h_eff ** 3 / (3 * e_mod) ele_nodes = [bot_ss_node, top_ss_node] # Superstructure element vert_ele = o3.element.ElasticBeamColumn2D(osi, ele_nodes, area=area, e_mod=e_mod, iz=iz, transf=transf) omega = 2 * np.pi / bd.t_fixed # define superstructure damping using rotational spring approach from Millen et al. (2017) to avoid double damping if dtype == 'rot_dashpot': cxx = bd.xi * 2 * np.sqrt(bd.mass_eff * bd.k_eff) equiv_c_rot = cxx * (2.0 / 3) ** 2 * bd.h_eff ** 2 ss_rot_dashpot_mat = o3.uniaxial_material.Viscous(osi, equiv_c_rot, alpha=1.) sfi_dashpot_ele = o3.element.TwoNodeLink(osi, [bot_ss_node, top_ss_node], mats=[ss_rot_dashpot_mat], dirs=[o3.cc.DOF2D_ROTZ]) elif dtype == 'horz_dashpot': cxx = bd.xi * 2 * np.sqrt(bd.mass_eff * bd.k_eff) ss_rot_dashpot_mat = o3.uniaxial_material.Viscous(osi, cxx, alpha=1.) sfi_dashpot_ele = o3.element.ZeroLength(osi, [bot_ss_node, top_ss_node], mats=[ss_rot_dashpot_mat], dirs=[o3.cc.X]) else: beta_k = 2 * bd.xi / omega o3.rayleigh.Rayleigh(osi, 0, 0, beta_k_init=beta_k, beta_k_comm=0.0) # Define the input motion for the dynamic analysis acc_series = o3.time_series.Path(osi, dt=asig.dt, values=-asig.values) # should be negative o3.pattern.UniformExcitation(osi, dir=o3.cc.X, accel_series=acc_series) print('loaded gm') o3.wipe_analysis(osi) o3.algorithm.Newton(osi) o3.system.SparseGeneral(osi) o3.numberer.RCM(osi) o3.constraints.Transformation(osi) o3.integrator.Newmark(osi, 0.5, 0.25) o3.analysis.Transient(osi) o3.test_check.NormDispIncr(osi, tol=1.0e-6, max_iter=10) analysis_time = asig.time[-1] analysis_dt = 0.001 # define outputs of analysis od = { "time": o3.recorder.TimeToArrayCache(osi), "rel_deck_disp": o3.recorder.NodeToArrayCache(osi, top_ss_node, [o3.cc.DOF2D_X], 'disp'), "deck_accel": o3.recorder.NodeToArrayCache(osi, top_ss_node, [o3.cc.DOF2D_X], 'accel'), "deck_rot": o3.recorder.NodeToArrayCache(osi, top_ss_node, [o3.cc.DOF2D_ROTZ], 'disp'), "chord_rots": o3.recorder.ElementToArrayCache(osi, vert_ele, arg_vals=['chordRotation']), "col_forces": o3.recorder.ElementToArrayCache(osi, vert_ele, arg_vals=['force']), } if dtype in ['rot_dashpot', 'horz_dashpot']: od['dashpot_force'] = o3.recorder.ElementToArrayCache(osi, sfi_dashpot_ele, arg_vals=['force']) o3.analyze(osi, int(analysis_time / analysis_dt), analysis_dt) o3.wipe(osi) for item in od: od[item] = od[item].collect() od['col_shear'] = -od['col_forces'][:, 0] od['col_moment'] = od['col_forces'][:, 2] od['hinge_rotation'] = od['chord_rots'][:, 1] od['hinge_rotation1'] = -od['chord_rots'][:, 2] del od['col_forces'] del od['chord_rots'] return od
def run_analysis(asig, period, xi, f_yield, etype): # Load a ground motion # Define inelastic SDOF mass = 1.0 r_post = 0.0 # Initialise OpenSees instance osi = o3.OpenSeesInstance(ndm=2, state=0) # Establish nodes bot_node = o3.node.Node(osi, 0, 0) top_node = o3.node.Node(osi, 0, 0) # Fix bottom node o3.Fix3DOF(osi, top_node, o3.cc.FREE, o3.cc.FIXED, o3.cc.FIXED) o3.Fix3DOF(osi, bot_node, o3.cc.FIXED, o3.cc.FIXED, o3.cc.FIXED) # Set out-of-plane DOFs to be slaved o3.EqualDOF(osi, top_node, bot_node, [o3.cc.Y, o3.cc.ROTZ]) # nodal mass (weight / g): o3.Mass(osi, top_node, mass, 0., 0.) # Define material k_spring = 4 * np.pi**2 * mass / period**2 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 # Define the dynamic analysis acc_series = o3.time_series.Path(osi, dt=asig.dt, values=-1 * asig.values) # should be negative o3.pattern.UniformExcitation(osi, dir=o3.cc.X, accel_series=acc_series) # set damping based on first eigen mode angular_freqs = np.array(o3.get_eigen(osi, solver='fullGenLapack', n=1))**0.5 beta_k = 2 * xi / angular_freqs[0] print('angular_freqs: ', angular_freqs) periods = 2 * np.pi / angular_freqs 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 o3.wipe_analysis(osi) # Run the dynamic analysis o3.constraints.Transformation(osi) o3.test_check.NormDispIncr(osi, tol=1.0e-6, max_iter=35, p_flag=0) o3.numberer.RCM(osi) if etype == 'implicit': o3.algorithm.Newton(osi) o3.system.SparseGeneral(osi) o3.integrator.Newmark(osi, gamma=0.5, beta=0.25) analysis_dt = 0.01 else: o3.algorithm.Linear(osi, factor_once=True) o3.system.FullGeneral(osi) if etype == 'newmark_explicit': o3.integrator.NewmarkExplicit(osi, gamma=0.6) explicit_dt = periods[0] / np.pi / 32 elif etype == 'central_difference': o3.integrator.CentralDifference(osi) o3.opy.integrator('HHTExplicit') explicit_dt = periods[0] / np.pi / 16 # 0.5 is a factor of safety elif etype == 'explicit_difference': o3.integrator.ExplicitDifference(osi) explicit_dt = periods[0] / np.pi / 32 else: raise ValueError(etype) print('explicit_dt: ', explicit_dt) analysis_dt = explicit_dt o3.analysis.Transient(osi) analysis_time = asig.time[-1] outputs = { "time": [], "rel_disp": [], "rel_accel": [], "rel_vel": [], "force": [] } while o3.get_time(osi) < analysis_time: o3.analyze(osi, 1, analysis_dt) curr_time = o3.get_time(osi) outputs["time"].append(curr_time) outputs["rel_disp"].append(o3.get_node_disp(osi, top_node, o3.cc.X)) outputs["rel_vel"].append(o3.get_node_vel(osi, top_node, o3.cc.X)) outputs["rel_accel"].append(o3.get_node_accel(osi, top_node, o3.cc.X)) o3.gen_reactions(osi) outputs["force"].append(-o3.get_node_reaction( osi, bot_node, o3.cc.X)) # Negative since diff node o3.wipe(osi) for item in outputs: outputs[item] = np.array(outputs[item]) return outputs
def run(out_folder): osi = o3.OpenSeesInstance(ndm=2, ndf=2, state=3) x_centre = 0.0 y_centre = 0.0 top_node = o3.node.Node(osi, x_centre, y_centre) fd_area = 1 fd_e_mod = 1e9 fd_iz = 1e6 top_nodes = [] bot_nodes = [] sf_eles = [] fd_eles = [] o3.Mass(osi, top_node, 10, 10) fy = 500 k = 1.0e4 b = 0.1 pro_params = [5, 0.925, 0.15] sf_mat = o3.uniaxial_material.SteelMPF(osi, fy, fy, k, b, b, params=pro_params) diff_pos = 0.5 depth = 1 bot_nodes.append(o3.node.Node(osi, x_centre - diff_pos, y_centre - depth)) o3.Fix2DOF(osi, bot_nodes[0], o3.cc.FIXED, o3.cc.FIXED) bot_nodes.append(o3.node.Node(osi, x_centre + diff_pos, y_centre - depth)) o3.Fix2DOF(osi, bot_nodes[1], o3.cc.FIXED, o3.cc.FIXED) top_nodes.append(o3.node.Node(osi, x_centre, y_centre)) sf_eles.append( o3.element.Truss(osi, [top_nodes[0], bot_nodes[0]], big_a=1.0, mat=sf_mat)) sf_eles.append( o3.element.Truss(osi, [top_nodes[0], bot_nodes[1]], big_a=1.0, mat=sf_mat)) o3.EqualDOF(osi, top_node, top_nodes[0], dofs=[o3.cc.DOF2D_X, o3.cc.DOF2D_Y]) ts0 = o3.time_series.Linear(osi, factor=1) o3.pattern.Plain(osi, ts0) o3.Load(osi, top_node, [100, -500]) o3.constraints.Transformation(osi) o3.test_check.NormDispIncr(osi, tol=1.0e-6, max_iter=35, p_flag=0) o3.algorithm.Newton(osi) o3.numberer.RCM(osi) o3.system.FullGeneral(osi) n_steps_gravity = 15 d_gravity = 1. / n_steps_gravity o3.integrator.LoadControl(osi, d_gravity, num_iter=10) # o3.rayleigh.Rayleigh(osi, a0, a1, 0.0, 0.0) o3.analysis.Static(osi) o3r = o3.results.Results2D(cache_path=out_folder, dynamic=True) o3r.pseudo_dt = 0.1 o3r.start_recorders(osi, dt=0.1) nr = o3.recorder.NodeToArrayCache(osi, top_node, [o3.cc.DOF2D_X, o3.cc.DOF2D_Y], 'disp') er = o3.recorder.ElementToArrayCache(osi, sf_eles[0], arg_vals=['force']) for i in range(n_steps_gravity): o3.analyze(osi, num_inc=1) o3.load_constant(osi, time=0.0) import o3seespy.extensions o3.extensions.to_py_file(osi, 'ofile.py') print('init_disp: ', o3.get_node_disp(osi, top_node, o3.cc.DOF2D_Y)) print('init_disp: ', o3.get_node_disp(osi, top_nodes[0], o3.cc.DOF2D_Y)) print('init_disp: ', o3.get_node_disp(osi, top_nodes[-1], o3.cc.DOF2D_Y)) o3.wipe(osi) o3r.save_to_cache() # o3r.coords = o3.get_all_node_coords(osi) # o3r.ele2node_tags = o3.get_all_ele_node_tags_as_dict(osi) data = nr.collect() edata = er.collect() # bf, sps = plt.subplots(nrows=2) # sps[0].plot(data[:, 0]) # sps[0].plot(data[:, 1]) # sps[1].plot(edata[:, 0]) # # sps[0].plot(data[1]) # plt.show() o3r.load_from_cache() o3plot.replot(o3r)
def run(show=0): # Load a ground motion record_filename = 'test_motion_dt0p01.txt' asig = eqsig.load_asig(ap.MODULE_DATA_PATH + 'gms/' + record_filename, m=0.5) # Define inelastic SDOF period = 1.0 xi = 0.05 mass = 1.0 f_yield = 1.5 # Reduce this to make it nonlinear r_post = 0.0 # Initialise OpenSees instance osi = o3.OpenSeesInstance(ndm=2, state=0) # Establish nodes bot_node = o3.node.Node(osi, 0, 0) top_node = o3.node.Node(osi, 0, 0) # Fix bottom node o3.Fix3DOF(osi, top_node, o3.cc.FREE, o3.cc.FIXED, o3.cc.FIXED) o3.Fix3DOF(osi, bot_node, o3.cc.FIXED, o3.cc.FIXED, o3.cc.FIXED) # Set out-of-plane DOFs to be slaved o3.EqualDOF(osi, top_node, bot_node, [o3.cc.Y, o3.cc.ROTZ]) # nodal mass (weight / g): o3.Mass(osi, top_node, mass, 0., 0.) # Define material k_spring = 4 * np.pi**2 * mass / period**2 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 # Define the dynamic analysis acc_series = o3.time_series.Path(osi, dt=asig.dt, values=-1 * asig.values) # should be negative o3.pattern.UniformExcitation(osi, dir=o3.cc.X, accel_series=acc_series) # set damping based on first eigen mode angular_freq = o3.get_eigen(osi, solver='fullGenLapack', n=1)[0]**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 o3.wipe_analysis(osi) # Run the dynamic analysis o3.algorithm.Newton(osi) o3.system.SparseGeneral(osi) o3.numberer.RCM(osi) o3.constraints.Transformation(osi) o3.integrator.Newmark(osi, gamma=0.5, beta=0.25) o3.analysis.Transient(osi) o3.test_check.EnergyIncr(osi, tol=1.0e-10, max_iter=10) analysis_time = asig.time[-1] analysis_dt = 0.001 outputs = { "time": [], "rel_disp": [], "rel_accel": [], "rel_vel": [], "force": [] } while o3.get_time(osi) < analysis_time: o3.analyze(osi, 1, analysis_dt) curr_time = o3.get_time(osi) outputs["time"].append(curr_time) outputs["rel_disp"].append(o3.get_node_disp(osi, top_node, o3.cc.X)) outputs["rel_vel"].append(o3.get_node_vel(osi, top_node, o3.cc.X)) outputs["rel_accel"].append(o3.get_node_accel(osi, top_node, o3.cc.X)) o3.gen_reactions(osi) outputs["force"].append(-o3.get_node_reaction( osi, bot_node, o3.cc.X)) # Negative since diff node o3.wipe(osi) for item in outputs: outputs[item] = np.array(outputs[item]) if show: import matplotlib.pyplot as plt plt.plot(outputs['time'], outputs['rel_disp'], label='o3seespy') periods = np.array([period]) # Compare closed form elastic solution from eqsig import sdof resp_u, resp_v, resp_a = sdof.response_series(motion=asig.values, dt=asig.dt, periods=periods, xi=xi) plt.plot(asig.time, resp_u[0], ls='--', label='Elastic') plt.legend() plt.show()
def get_elastic_response(mass, k_spring, 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 motion: array_like, 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, state=3) height = 5. # Establish nodes bot_node = o3.node.Node(osi, 0, 0) top_node = o3.node.Node(osi, 0, height) # Fix bottom node o3.Fix3DOF(osi, top_node, o3.cc.FREE, o3.cc.FIXED, o3.cc.FREE) o3.Fix3DOF(osi, bot_node, o3.cc.FIXED, o3.cc.FIXED, o3.cc.FIXED) # Set out-of-plane DOFs to be slaved o3.EqualDOF(osi, top_node, bot_node, [o3.cc.Y]) # nodal mass (weight / g): o3.Mass(osi, top_node, mass, 0., 0.) # Define material transf = o3.geom_transf.Linear2D(osi, []) area = 1.0 e_mod = 1.0e6 iz = k_spring * height ** 3 / (3 * e_mod) ele_nodes = [bot_node, top_node] ele = o3.element.ElasticBeamColumn2D(osi, ele_nodes, area=area, e_mod=e_mod, iz=iz, transf=transf) # Define the dynamic analysis acc_series = o3.time_series.Path(osi, dt=dt, values=-motion) # should be negative o3.pattern.UniformExcitation(osi, dir=o3.cc.X, accel_series=acc_series) # set damping based on first eigen mode angular_freq = o3.get_eigen(osi, solver='fullGenLapack', n=1)[0] ** 0.5 response_period = 2 * np.pi / angular_freq print('response_period: ', response_period) 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 o3.wipe_analysis(osi) o3.algorithm.Newton(osi) o3.system.SparseGeneral(osi) o3.numberer.RCM(osi) o3.constraints.Transformation(osi) o3.integrator.Newmark(osi, 0.5, 0.25) o3.analysis.Transient(osi) o3.extensions.to_py_file(osi, 'simple.py') o3.test_check.EnergyIncr(osi, tol=1.0e-10, max_iter=10) analysis_time = (len(motion) - 1) * dt analysis_dt = 0.001 outputs = { "time": [], "rel_disp": [], "rel_accel": [], "rel_vel": [], "force": [] } while o3.get_time(osi) < analysis_time: o3.analyze(osi, 1, analysis_dt) curr_time = o3.get_time(osi) outputs["time"].append(curr_time) outputs["rel_disp"].append(o3.get_node_disp(osi, top_node, o3.cc.X)) outputs["rel_vel"].append(o3.get_node_vel(osi, top_node, o3.cc.X)) outputs["rel_accel"].append(o3.get_node_accel(osi, top_node, o3.cc.X)) o3.gen_reactions(osi) outputs["force"].append(o3.get_ele_response(osi, ele, 'force')) o3.wipe(osi) for item in outputs: outputs[item] = np.array(outputs[item]) return outputs
def get_response(bd, asig, l_ph): """ Compute the response of a nonlinear lollipop on a foundation with linear/nonlinear soil Units are N, m, s :param bd: SDOF building object :param asig: Acceleration signal object :return: """ osi = o3.OpenSeesInstance(ndm=2, state=3) # Establish nodes top_ss_node = o3.node.Node(osi, 0, bd.h_eff) bot_ss_node = o3.node.Node(osi, 0, 0) # Fix bottom node o3.Fix3DOF(osi, bot_ss_node, o3.cc.FIXED, o3.cc.FIXED, o3.cc.FIXED) # nodal mass (weight / g): o3.Mass(osi, top_ss_node, bd.mass_eff, 0.0, 0) # Define a column element with a plastic hinge at base transf = o3.geom_transf.Linear2D(osi, []) # can change for P-delta effects area = 1.0 e_mod = 200.0e9 iz = bd.k_eff * bd.h_eff**3 / (3 * e_mod) ele_nodes = [bot_ss_node, top_ss_node] # Superstructure element elastic_sect = o3.section.Elastic2D(osi, e_mod, area, iz) integ = o3.beam_integration.HingeMidpoint(osi, elastic_sect, l_ph, elastic_sect, l_ph, elastic_sect) vert_ele = o3.element.ForceBeamColumn(osi, ele_nodes, transf, integ) omega = 2 * np.pi / bd.t_fixed beta_k = 2 * bd.xi / omega o3.rayleigh.Rayleigh(osi, 0, 0, beta_k_init=beta_k, beta_k_comm=0.0) # Define the input motion for the dynamic analysis acc_series = o3.time_series.Path(osi, dt=asig.dt, values=-asig.values) # should be negative o3.pattern.UniformExcitation(osi, dir=o3.cc.X, accel_series=acc_series) print('loaded gm') o3.wipe_analysis(osi) o3.algorithm.Newton(osi) o3.system.SparseGeneral(osi) o3.numberer.RCM(osi) o3.constraints.Transformation(osi) o3.integrator.Newmark(osi, 0.5, 0.25) o3.analysis.Transient(osi) o3.test_check.NormDispIncr(osi, tol=1.0e-6, max_iter=10) analysis_time = asig.time[-1] analysis_dt = 0.001 # define outputs of analysis od = { "time": o3.recorder.TimeToArrayCache(osi), "rel_deck_disp": o3.recorder.NodeToArrayCache(osi, top_ss_node, [o3.cc.DOF2D_X], 'disp'), "deck_accel": o3.recorder.NodeToArrayCache(osi, top_ss_node, [o3.cc.DOF2D_X], 'accel'), "deck_rot": o3.recorder.NodeToArrayCache(osi, top_ss_node, [o3.cc.DOF2D_ROTZ], 'disp'), "chord_rots": o3.recorder.ElementToArrayCache(osi, vert_ele, arg_vals=['chordRotation']), "col_forces": o3.recorder.ElementToArrayCache(osi, vert_ele, arg_vals=['force']), } o3.analyze(osi, int(analysis_time / analysis_dt), analysis_dt) o3.wipe(osi) for item in od: od[item] = od[item].collect() od['col_shear'] = -od['col_forces'][:, 0] od['col_moment'] = od['col_forces'][:, 2] od['hinge_rotation'] = od['chord_rots'][:, 1] od['hinge_rotation1'] = -od['chord_rots'][:, 2] del od['col_forces'] del od['chord_rots'] return od
def gen_response(period, xi, asig, etype, fos_for_dt=None): # Define inelastic SDOF mass = 1.0 f_yield = 1.5 # Reduce this to make it nonlinear r_post = 0.0 # Initialise OpenSees instance osi = o3.OpenSeesInstance(ndm=2, state=0) # Establish nodes bot_node = o3.node.Node(osi, 0, 0) top_node = o3.node.Node(osi, 0, 0) # Fix bottom node o3.Fix3DOF(osi, top_node, o3.cc.FREE, o3.cc.FIXED, o3.cc.FIXED) o3.Fix3DOF(osi, bot_node, o3.cc.FIXED, o3.cc.FIXED, o3.cc.FIXED) # Set out-of-plane DOFs to be slaved o3.EqualDOF(osi, top_node, bot_node, [o3.cc.Y, o3.cc.ROTZ]) # nodal mass (weight / g): o3.Mass(osi, top_node, mass, 0., 0.) # Define material k_spring = 4 * np.pi**2 * mass / period**2 # bilinear_mat = o3.uniaxial_material.Steel01(osi, fy=f_yield, e0=k_spring, b=r_post) mat = o3.uniaxial_material.Elastic(osi, e_mod=k_spring) # Assign zero length element, # Note: pass actual node and material objects into element o3.element.ZeroLength(osi, [bot_node, top_node], mats=[mat], dirs=[o3.cc.DOF2D_X], r_flag=1) # Define the dynamic analysis # Define the dynamic analysis acc_series = o3.time_series.Path(osi, dt=asig.dt, values=-1 * asig.values) # should be negative o3.pattern.UniformExcitation(osi, dir=o3.cc.X, accel_series=acc_series) # set damping based on first eigen mode angular_freq = o3.get_eigen(osi, solver='fullGenLapack', n=1)[0]**0.5 period = 2 * np.pi / angular_freq 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) o3.set_time(osi, 0.0) # Run the dynamic analysis o3.wipe_analysis(osi) # Run the dynamic analysis o3.numberer.RCM(osi) o3.system.FullGeneral(osi) if etype == 'central_difference': o3.algorithm.Linear(osi, factor_once=True) o3.integrator.CentralDifference(osi) explicit_dt = 2 / angular_freq / fos_for_dt analysis_dt = explicit_dt elif etype == 'implicit': o3.algorithm.Newton(osi) o3.integrator.Newmark(osi, gamma=0.5, beta=0.25) analysis_dt = 0.001 else: raise ValueError() o3.constraints.Transformation(osi) o3.analysis.Transient(osi) o3.test_check.EnergyIncr(osi, tol=1.0e-10, max_iter=10) analysis_time = asig.time[-1] outputs = { "time": [], "rel_disp": [], "rel_accel": [], "rel_vel": [], "force": [] } rec_dt = 0.002 n_incs = int(analysis_dt / rec_dt) n_incs = 1 while o3.get_time(osi) < analysis_time: o3.analyze(osi, n_incs, analysis_dt) curr_time = o3.get_time(osi) outputs["time"].append(curr_time) outputs["rel_disp"].append(o3.get_node_disp(osi, top_node, o3.cc.X)) outputs["rel_vel"].append(o3.get_node_vel(osi, top_node, o3.cc.X)) outputs["rel_accel"].append(o3.get_node_accel(osi, top_node, o3.cc.X)) o3.gen_reactions(osi) outputs["force"].append(-o3.get_node_reaction( osi, bot_node, o3.cc.X)) # Negative since diff node o3.wipe(osi) for item in outputs: outputs[item] = np.array(outputs[item]) return outputs