def add_beam_hinges(dict_of_hinges, dict_of_hinges_2): # obtain nonlinear hinge properties data = read_nonlinear_hinge_properties() # dict_of_hinges = {real joint: (new joint, zero length element ID, orientation)} # iterate through all the hinges and add the uniaxial material and zero length element to the opensees model for key, value in dict_of_hinges.items(): node_R = key node_C = value[0] matTag = value[1] dirn = value[2] row = data.loc[data['Hinge NAME'] == dict_of_hinges_2[matTag]] K0 = row['K0'].values[0] as_Plus = row['as_Plus'].values[0] as_Neg = row['as_Neg'].values[0] My_Plus = row['My_Plus'].values[0] My_Neg = row['My_Neg'].values[0] Lamda_S = row['Lamda_S'].values[0] Lamda_C = row['Lamda_C'].values[0] Lamda_A = row['Lamda_A'].values[0] Lamda_K = row['Lamda_K'].values[0] c_S = row['c_S'].values[0] c_C = row['c_C'].values[0] c_A = row['c_A'].values[0] c_K = row['c_K'].values[0] theta_p_Plus = row['theta_p_Plus'].values[0] theta_p_Neg = row['theta_p_Neg'].values[0] theta_pc_Plus = row['theta_pc_Plus'].values[0] theta_pc_Neg = row['theta_pc_Neg'].values[0] Res_Pos = row['Res_Pos'].values[0] Res_Neg = row['Res_Neg'].values[0] theta_u_Plus = row['theta_u_Plus'].values[0] theta_u_Neg = row['theta_u_Neg'].values[0] D_Plus = row['D_Plus'].values[0] D_Neg = row['D_Neg'].values[0] nFactor = row['nFactor'].values[0] # define the uniaxial material op.uniaxialMaterial('Bilin', matTag, K0, as_Plus, as_Neg, My_Plus, My_Neg, Lamda_S, Lamda_C, Lamda_A, Lamda_K, c_S, c_C, c_A, c_K, theta_p_Plus, theta_p_Neg, theta_pc_Plus, theta_pc_Neg, Res_Pos, Res_Neg, theta_u_Plus, theta_u_Neg, D_Plus, D_Neg, nFactor) # add the zero length element op.element('zeroLength', matTag, node_R, node_C, '-mat', matTag, '-dir', dirn, '-doRayleigh', 1) # constrain the nodes connecting the rero lengrth element - all DOFs are constrained except the major bending op.equalDOF(node_R, node_C, 1, 2, 3, int(9 - dirn), 6) op.region(key, matTag) return
def ops_node(): i = 1 for _i in nodes_high: for _j in nodes_width: ops.node(i, _j, 0, _i) i = i + 1 for _i in range(1, 7): ops.fix(_i, 1, 1, 1, 1, 1, 1) for _i in range(1, 67, 6): ops.equalDOF(_i, _i + 1, 1, 2, 3, 4, 5, 6) for _i in range(5, 71, 6): ops.equalDOF(_i, _i + 1, 1, 2, 3, 4, 5, 6)
def get_inelastic_response(fb, asig, extra_time=0.0, xi=0.05, analysis_dt=0.001): """ Run seismic analysis of a nonlinear FrameBuilding :param fb: FrameBuilding object :param asig: AccSignal object :param extra_time: float, additional analysis time after end of ground motion :param xi: damping ratio :param analysis_dt: time step to perform the analysis :return: """ op.wipe() op.model('basic', '-ndm', 2, '-ndf', 3) # 2 dimensions, 3 dof per node q_floor = 10000. # kPa trib_width = fb.floor_length trib_mass_per_length = q_floor * trib_width / 9.8 # Establish nodes and set mass based on trib area # Nodes named as: C<column-number>-S<storey-number>, first column starts at C1-S0 = ground level left nd = OrderedDict() col_xs = np.cumsum(fb.bay_lengths) col_xs = np.insert(col_xs, 0, 0) n_cols = len(col_xs) sto_ys = fb.heights sto_ys = np.insert(sto_ys, 0, 0) for cc in range(1, n_cols + 1): for ss in range(fb.n_storeys + 1): n_i = cc * 100 + ss nd["C%i-S%i" % (cc, ss)] = n_i op.node(n_i, col_xs[cc - 1], sto_ys[ss]) if ss != 0: if cc == 1: node_mass = trib_mass_per_length * fb.bay_lengths[0] / 2 elif cc == n_cols: node_mass = trib_mass_per_length * fb.bay_lengths[-1] / 2 else: node_mass = trib_mass_per_length * (fb.bay_lengths[cc - 2] + fb.bay_lengths[cc - 1] / 2) op.mass(n_i, node_mass) # Set all nodes on a storey to have the same displacement for ss in range(0, fb.n_storeys + 1): for cc in range(1, n_cols + 1): op.equalDOF(nd["C%i-S%i" % (1, ss)], nd["C%i-S%i" % (cc, ss)], opc.X) # Fix all base nodes for cc in range(1, n_cols + 1): op.fix(nd["C%i-S%i" % (cc, 0)], opc.FIXED, opc.FIXED, opc.FIXED) # Coordinate transformation geo_tag = 1 trans_args = [] op.geomTransf("Linear", geo_tag, *[]) l_hinge = fb.bay_lengths[0] * 0.1 # Define material e_conc = 30.0e6 i_beams = 0.4 * fb.beam_widths * fb.beam_depths ** 3 / 12 i_columns = 0.5 * fb.column_widths * fb.column_depths ** 3 / 12 a_beams = fb.beam_widths * fb.beam_depths a_columns = fb.column_widths * fb.column_depths ei_beams = e_conc * i_beams ei_columns = e_conc * i_columns eps_yield = 300.0e6 / 200e9 phi_y_col = calc_yield_curvature(fb.column_depths, eps_yield) phi_y_beam = calc_yield_curvature(fb.beam_depths, eps_yield) # Define beams and columns md = OrderedDict() # material dict sd = OrderedDict() # section dict ed = OrderedDict() # element dict # Columns named as: C<column-number>-S<storey-number>, first column starts at C1-S0 = ground floor left # Beams named as: B<bay-number>-S<storey-number>, first beam starts at B1-S1 = first storey left (foundation at S0) for ss in range(fb.n_storeys): # set columns for cc in range(1, fb.n_cols + 1): ele_i = cc * 100 + ss md["C%i-S%i" % (cc, ss)] = ele_i sd["C%i-S%i" % (cc, ss)] = ele_i ed["C%i-S%i" % (cc, ss)] = ele_i mat_props = elastic_bilin(ei_columns[ss][cc - 1], 0.05 * ei_columns[ss][cc - 1], phi_y_col[ss][cc - 1]) #print(opc.ELASTIC_BILIN, ele_i, *mat_props) op.uniaxialMaterial(opc.ELASTIC_BILIN, ele_i, *mat_props) # op.uniaxialMaterial("Elastic", ele_i, ei_columns[ss][cc - 1]) node_numbers = [nd["C%i-S%i" % (cc, ss)], nd["C%i-S%i" % (cc, ss + 1)]] op.element(opc.ELASTIC_BEAM_COLUMN, ele_i, *node_numbers, a_columns[ss - 1][cc - 1], e_conc, i_columns[ss - 1][cc - 1], geo_tag ) # Set beams for bb in range(1, fb.n_bays + 1): ele_i = bb * 10000 + ss md["B%i-S%i" % (bb, ss)] = ele_i sd["B%i-S%i" % (bb, ss)] = ele_i ed["B%i-S%i" % (bb, ss)] = ele_i mat_props = elastic_bilin(ei_beams[ss][bb - 1], 0.05 * ei_beams[ss][bb - 1], phi_y_beam[ss][bb - 1]) op.uniaxialMaterial(opc.ELASTIC_BILIN, ele_i, *mat_props) # op.uniaxialMaterial("Elastic", ele_i, ei_beams[ss][bb - 1]) node_numbers = [nd["C%i-S%i" % (bb, ss + 1)], nd["C%i-S%i" % (bb + 1, ss + 1)]] print((opc.BEAM_WITH_HINGES, ele_i, *node_numbers, sd["B%i-S%i" % (bb, ss)], l_hinge, sd["B%i-S%i" % (bb, ss)], l_hinge, sd["B%i-S%i" % (bb, ss)], geo_tag )) # Old definition # op.element(opc.BEAM_WITH_HINGES, ele_i, # *[nd["C%i-S%i" % (bb, ss - 1)], nd["C%i-S%i" % (bb + 1, ss)]], # sd["B%i-S%i" % (bb, ss)], l_hinge, # sd["B%i-S%i" % (bb, ss)], l_hinge, # e_conc, # a_beams[ss - 1][bb - 1], # i_beams[ss - 1][bb - 1], geo_tag # ) # New definition # op.element(opc.BEAM_WITH_HINGES, ele_i, # *node_numbers, # sd["B%i-S%i" % (bb, ss)], l_hinge, # sd["B%i-S%i" % (bb, ss)], l_hinge, # sd["B%i-S%i" % (bb, ss)], geo_tag # TODO: make this elastic # # ) # Elastic definition op.element(opc.ELASTIC_BEAM_COLUMN, ele_i, *node_numbers, a_beams[ss - 1][bb - 1], e_conc, i_beams[ss - 1][bb - 1], geo_tag ) # Define the dynamic analysis load_tag_dynamic = 1 pattern_tag_dynamic = 1 values = list(-1 * asig.values) # should be negative op.timeSeries('Path', load_tag_dynamic, '-dt', asig.dt, '-values', *values) op.pattern('UniformExcitation', pattern_tag_dynamic, opc.X, '-accel', load_tag_dynamic) # set damping based on first eigen mode angular_freq2 = op.eigen('-fullGenLapack', 1) if hasattr(angular_freq2, '__len__'): angular_freq2 = angular_freq2[0] angular_freq = angular_freq2 ** 0.5 if isinstance(angular_freq, complex): raise ValueError("Angular frequency is complex, issue with stiffness or mass") alpha_m = 0.0 beta_k = 2 * xi / angular_freq beta_k_comm = 0.0 beta_k_init = 0.0 period = angular_freq / 2 / np.pi print("period: ", period) op.rayleigh(alpha_m, beta_k, beta_k_init, beta_k_comm) # Run the dynamic analysis op.wipeAnalysis() op.algorithm('Newton') op.system('SparseGeneral') op.numberer('RCM') op.constraints('Transformation') op.integrator('Newmark', 0.5, 0.25) op.analysis('Transient') #op.test("NormDispIncr", 1.0e-1, 2, 0) tol = 1.0e-10 iter = 10 op.test('EnergyIncr', tol, iter, 0, 2) # TODO: make this test work analysis_time = (len(values) - 1) * asig.dt + extra_time outputs = { "time": [], "rel_disp": [], "rel_accel": [], "rel_vel": [], "force": [] } print("Analysis starting") while op.getTime() < analysis_time: curr_time = op.getTime() op.analyze(1, analysis_dt) outputs["time"].append(curr_time) outputs["rel_disp"].append(op.nodeDisp(nd["C%i-S%i" % (1, fb.n_storeys)], opc.X)) outputs["rel_vel"].append(op.nodeVel(nd["C%i-S%i" % (1, fb.n_storeys)], opc.X)) outputs["rel_accel"].append(op.nodeAccel(nd["C%i-S%i" % (1, fb.n_storeys)], opc.X)) op.reactions() react = 0 for cc in range(1, fb.n_cols): react += -op.nodeReaction(nd["C%i-S%i" % (cc, 0)], opc.X) outputs["force"].append(react) # Should be negative since diff node op.wipe() for item in outputs: outputs[item] = np.array(outputs[item]) return outputs
ops.element('quad', 9, 11, 16, 17, 12, 1, 'PlaneStress', 1) ops.element('quad', 10, 12, 17, 18, 13, 1, 'PlaneStress', 1) ops.element('quad', 11, 13, 18, 19, 14, 1, 'PlaneStress', 1) ops.element('quad', 12, 14, 19, 20, 15, 1, 'PlaneStress', 1) ops.element('quad', 13, 16, 21, 22, 17, 1, 'PlaneStress', 1) ops.element('quad', 14, 17, 22, 23, 18, 1, 'PlaneStress', 1) ops.element('quad', 15, 18, 23, 24, 19, 1, 'PlaneStress', 1) ops.element('quad', 16, 19, 24, 25, 20, 1, 'PlaneStress', 1) ops.fix(1, 1, 1) ops.fix(6, 1, 1) ops.fix(11, 1, 1) ops.fix(16, 1, 1) ops.fix(21, 1, 1) ops.equalDOF(2, 22, 1, 2) ops.equalDOF(3, 23, 1, 2) ops.equalDOF(4, 24, 1, 2) ops.equalDOF(5, 25, 1, 2) ops.timeSeries('Linear', 1) ops.pattern('Plain', 1, 1) ops.load(15, 0., -1.) ops.analysis('Static') ops.analyze(1) # - plot model plt.figure() opsv.plot_model() plt.axis('equal')
def analisis_opensees(path, permutaciones): #helper, #win ops.wipe() # bucle para generar los x análisis for i in range(len(permutaciones)): perfil = str(permutaciones[i][0]) nf = permutaciones[i][2] amort = permutaciones[i][3] den = permutaciones[i][4] vel = permutaciones[i][5] capas = len(permutaciones[i][6]) nstep = permutaciones[i][30] dt = float(permutaciones[i][31]) # creación de elementos sElemX = permutaciones[i][1] # elementos en X sElemZ = permutaciones[i][46] # espesor en Z # ============================================================================= # ######## geometría de la columna ###### # ============================================================================= # límite entre capas limite_capa = [] anterior = 0 for j in range(capas): espesor = permutaciones[i][8][j] limite_capa.append(espesor + anterior) anterior = limite_capa[j] print('Límite de capa: ' + str(limite_capa[j])) # creación de elementos y nodos en x nElemX = 1 # elementos en x nNodeX = 2 * nElemX + 1 # nodos en x # creación de elementos y nodos para z nElemZ = 1 # creación de elementos y nodos en Y y totales nElemY = [] # elementos en y sElemY = [] # dimension en y nElemT = 0 for j in range(capas): espesor = permutaciones[i][8][j] nElemY.append(2 * espesor) nElemT += nElemY[j] print('Elementos en capa ' + str(j + 1) + ': ' + str(nElemY[j])) sElemY.append(permutaciones[i][8][j] / nElemY[j]) print('Tamaño de los elementos en capa ' + str(j + 1) + ': ' + str(sElemY[j]) + '\n') # number of nodes in vertical direction in each layer nNodeY = [] # dimension en y nNodeT = 0 s = 0 for j in range(capas - 1): nNodeY.append(4 * nElemY[j]) nNodeT += nNodeY[j] s += 1 print('Nodos en capa ' + str(j + 1) + ': ' + str(nNodeY[j])) nNodeY.append(4 * (nElemY[-1] + 1)) nNodeT += nNodeY[-1] print('Nodos en capa ' + str(s + 1) + ': ' + str(nNodeY[s])) print('Nodos totales: ' + str(nNodeT)) #win.ui.progressBar.setValue(15) # ============================================================================= # ######### Crear nodos del suelo ########## # ============================================================================= # creación de nodos de presión de poros ops.model('basic', '-ndm', 3, '-ndf', 4) with open(path + '/Post-proceso/' + perfil + '/ppNodesInfo.dat', 'w') as f: count = 0.0 yCoord = 0.0 nodos = [] dryNode = [] altura_nf = 10 - nf for k in range(capas): for j in range(0, int(nNodeY[k]), 4): ops.node(j + count + 1, 0.0, yCoord, 0.0) ops.node(j + count + 2, 0.0, yCoord, sElemZ) ops.node(j + count + 3, sElemX, yCoord, sElemZ) ops.node(j + count + 4, sElemX, yCoord, 0.0) f.write( str(int(j + count + 1)) + '\t' + str(0.0) + '\t' + str(yCoord) + '\t' + str(0.0) + '\n') f.write( str(int(j + count + 2)) + '\t' + str(0.0) + '\t' + str(yCoord) + '\t' + str(sElemZ) + '\n') f.write( str(int(j + count + 3)) + '\t' + str(sElemX) + '\t' + str(yCoord) + '\t' + str(sElemZ) + '\n') f.write( str(int(j + count + 4)) + '\t' + str(sElemX) + '\t' + str(yCoord) + '\t' + str(0.0) + '\n') nodos.append(str(j + count + 1)) nodos.append(str(j + count + 2)) nodos.append(str(j + count + 3)) nodos.append(str(j + count + 4)) #designate node sobre la superficie de agua if yCoord >= altura_nf: dryNode.append(j + count + 1) dryNode.append(j + count + 2) dryNode.append(j + count + 3) dryNode.append(j + count + 4) yCoord = (yCoord + sElemY[k]) count = (count + nNodeY[k]) print("Finished creating all soil nodes...") # ============================================================================= # ####### Condiciones de contorno en la base de la columna ######### # ============================================================================= ops.fix(1, *[0, 1, 1, 0]) ops.fix(2, *[0, 1, 1, 0]) ops.fix(3, *[0, 1, 1, 0]) ops.fix(4, *[0, 1, 1, 0]) ops.equalDOF(1, 2, 1) ops.equalDOF(1, 3, 1) ops.equalDOF(1, 4, 1) print('Fin de creación de nodos de la base de la columna\n\n') # ============================================================================= # ####### Condiciones de contorno en los nudos restantes ######### # ============================================================================= count = 0 for k in range(5, int(nNodeT + 1), 4): ops.equalDOF(k, k + 1, *[1, 2, 3]) ops.equalDOF(k, k + 2, *[1, 2, 3]) ops.equalDOF(k, k + 3, *[1, 2, 3]) print('Fin de creación equalDOF para nodos de presión de poros\n\n') for j in range(len(dryNode)): ops.fix(dryNode[j], *[0, 0, 0, 1]) print("Finished creating all soil boundary conditions...") # ============================================================================= # ####### crear elemento y material de suelo ######### # ============================================================================= cargas = [] for j in range(capas): pendiente = permutaciones[i][9][j] slope = math.atan(pendiente / 100) tipo_suelo = permutaciones[i][6][j] rho = permutaciones[i][10][j] Gr = permutaciones[i][12][j] Br = permutaciones[i][13][j] fric = permutaciones[i][15][j] refpress = permutaciones[i][18][j] gmax = permutaciones[i][19][j] presscoef = permutaciones[i][20][j] surf = permutaciones[i][21][j] ev = permutaciones[i][22][j] cc1 = permutaciones[i][23][j] cc3 = permutaciones[i][24][j] cd1 = permutaciones[i][25][j] cd3 = permutaciones[i][26][j] ptang = permutaciones[i][27][j] coh = permutaciones[i][28][j] if tipo_suelo == 'No cohesivo': if float(surf) > 0: ops.nDMaterial('PressureDependMultiYield02', j + 1, 3.0, rho, Gr, Br, fric, gmax, refpress, presscoef, ptang, cc1, cc3, cd1, cd3, float(surf), 5.0, 3.0, *[1.0, 0.0], ev, *[0.9, 0.02, 0.7, 101.0]) else: ops.nDMaterial('PressureDependMultiYield02', j + 1, 3.0, rho, Gr, Br, fric, gmax, refpress, presscoef, ptang, cc1, cc3, cd1, cd3, float(surf), *permutaciones[i][29][j], 5.0, 3.0, *[1.0, 0.0], ev, *[0.9, 0.02, 0.7, 101.0]) cargas.append( [0.0, -9.81 * math.cos(slope), -9.81 * math.sin(slope)]) print('Fin de la creación de material de suelo\n\n') #----------------------------------------------------------------------------------------- # 5. CREATE SOIL ELEMENTS #----------------------------------------------------------------------------------------- count = 0 alpha = 1.5e-6 with open(path + '/Post-proceso/' + perfil + '/ppElemInfo.dat', 'w') as f: # crear elemento de suelo for k in range(capas): for j in range(int(nElemY[k])): nI = 4 * (j + count + 1) - 3 nJ = nI + 1 nK = nI + 2 nL = nI + 3 nM = nI + 4 nN = nI + 5 nO = nI + 6 nP = nI + 7 f.write( str(j + count + 1) + '\t' + str(nI) + '\t' + str(nJ) + '\t' + str(nK) + '\t' + str(nL) + '\t' + str(nM) + '\t' + str(nN) + '\t' + str(nO) + '\t' + str(nP) + '\n') Bc = permutaciones[i][14][k] ev = permutaciones[i][22][k] ops.element('SSPbrickUP', (j + count + 1), *[nI, nJ, nK, nL, nM, nN, nO, nP], (k + 1), float(Bc), 1.0, 1.0, 1.0, 1.0, float(ev), alpha, cargas[k][0], cargas[k][1], cargas[k][2]) count = (count + int(nElemY[k])) print('Fin de la creación del elemento del suelo\n\n') #win.ui.progressBar.setValue(25) # ============================================================================= # ######### Amortiguamiento de Lysmer ########## # ============================================================================= ops.model('basic', '-ndm', 3, '-ndf', 3) # definir nodos y coordenadas del amortiguamiento dashF = nNodeT + 1 dashX = nNodeT + 2 dashZ = nNodeT + 3 ops.node(dashF, 0.0, 0.0, 0.0) ops.node(dashX, 0.0, 0.0, 0.0) ops.node(dashZ, 0.0, 0.0, 0.0) # definir restricciones para los nodos de amortiguamiento ops.fix(dashF, 1, 1, 1) ops.fix(dashX, 0, 1, 1) ops.fix(dashZ, 1, 1, 0) # definir equalDOF para el amortiguamiento en la base del suelo ops.equalDOF(1, dashX, 1) ops.equalDOF(1, dashZ, 3) print( 'Fin de la creación de condiciones de contorno de los nodos de amortiguamiento\n\n' ) # definir el material de amortiguamiento colArea = sElemX * sElemZ dashpotCoeff = vel * den * colArea ops.uniaxialMaterial('Viscous', capas + 1, dashpotCoeff, 1.0) # definir el elemento ops.element('zeroLength', nElemT + 1, *[dashF, dashX], '-mat', capas + 1, '-dir', *[1]) ops.element('zeroLength', nElemT + 2, *[dashF, dashZ], '-mat', capas + 1, '-dir', *[3]) print('Fin de la creación del elemento de amortiguamiento\n\n') #----------------------------------------------------------------------------------------- # 9. DEFINE ANALYSIS PARAMETERS #----------------------------------------------------------------------------------------- # amortiguamiento de Rayleigh # frecuencia menor omega1 = 2 * math.pi * 0.2 # frecuencia mayor omega2 = 2 * math.pi * 20 a0 = 2.0 * (amort / 100) * omega1 * omega2 / (omega1 + omega2) a1 = 2.0 * (amort / 100) / (omega1 + omega2) print('Coeficientes de amortiguamiento' + '\n' + 'a0: ' + format(a0, '.6f') + '\n' + 'a1: ' + format(a1, '.6f') + '\n\n') #win.ui.progressBar.setValue(35) # ============================================================================= # ######## Determinación de análisis estático ######### # ============================================================================= #---DETERMINE STABLE ANALYSIS TIME STEP USING CFL CONDITION # se determina a partir de un análisis transitorio de largo tiempo duration = nstep * dt # tamaño mínimo del elemento y velocidad máxima minSize = sElemY[0] vsMax = permutaciones[i][11][0] for j in range(1, capas): if sElemY[j] < minSize: minSize = sElemY[j] if permutaciones[i][11][j] > vsMax: vsMax = permutaciones[i][11][j] # trial analysis time step kTrial = minSize / (vsMax**0.5) # tiempo de análisis y pasos de tiempo if dt <= kTrial: nStep = nstep dT = dt else: nStep = int(math.floor(duration / kTrial) + 1) dT = duration / nStep print('Número de pasos en el análisis: ' + str(nStep) + '\n') print('Incremento de tiempo: ' + str(dT) + '\n\n') #---------------------------------------------------------------------------------------- # 7. GRAVITY ANALYSIS #----------------------------------------------------------------------------------------- ops.model('basic', '-ndm', 3, '-ndf', 4) ops.updateMaterialStage('-material', int(k + 1), '-stage', 0) # algoritmo de análisis estático ops.constraints(permutaciones[i][32][0], float(permutaciones[i][32][1]), float(permutaciones[i][32][2])) ops.test(permutaciones[i][34][0], float(permutaciones[i][34][1]), int(permutaciones[i][34][2]), int(permutaciones[i][34][3])) ops.algorithm(permutaciones[i][38][0]) ops.numberer(permutaciones[i][33][0]) ops.system(permutaciones[i][36][0]) ops.integrator(permutaciones[i][35][0], float(permutaciones[i][35][1]), float(permutaciones[i][35][2])) ops.analysis(permutaciones[i][37][0]) print('Inicio de análisis estático elástico\n\n') ops.start() ops.analyze(20, 5.0e2) print('Fin de análisis estático elástico\n\n') #win.ui.progressBar.setValue(40) # update materials to consider plastic behavior # ============================================================================= ops.updateMaterialStage('-material', int(k + 1), '-stage', 1) # ============================================================================= # plastic gravity loading print('Inicio de análisis estático plástico\n\n') ok = ops.analyze(40, 5.0e-2) if ok != 0: error = 'Error de convergencia en análisis estático de modelo' + str( perfil) + '\n\n' print(error) break print('Fin de análisis estático plástico\n\n') #----------------------------------------------------------------------------------------- # 11. UPDATE ELEMENT PERMEABILITY VALUES FOR POST-GRAVITY ANALYSIS #----------------------------------------------------------------------------------------- ini = 1 aum = 0 sum = 0 for j in range(capas): #Layer 3 ops.setParameter( '-val', permutaciones[i][16][j], ['-eleRange', int(ini + aum), int(nElemY[j] + sum)], 'xPerm') ops.setParameter( '-val', permutaciones[i][17][j], ['-eleRange', int(ini + aum), int(nElemY[j] + sum)], 'yPerm') ops.setParameter( '-val', permutaciones[i][16][j], ['-eleRange', int(ini + aum), int(nElemY[j] + sum)], 'zPerm') ini = nElemY[j] + sum sum += nElemY[j] aum = 1 print("Finished updating permeabilities for dynamic analysis...") # ============================================================================= # ########### Grabadores dinámicos ########## # ============================================================================= ops.setTime(0.0) ops.wipeAnalysis() ops.remove('recorders') # tiempo de la grabadora recDT = 10 * dt path_acel = path + '/Post-proceso/' + perfil + '/dinamico/aceleraciones/' ops.recorder('Node', '-file', path_acel + 'accelerationx.out', '-time', '-dT', recDT, '-node', *nodos, '-dof', 1, 'accel') print('Fin de creación de grabadores\n\n') #win.ui.progressBar.setValue(50) # ============================================================================= # ######### Determinación de análisis dinámico ########## # ============================================================================= # objeto de serie temporal para el historial de fuerza path_vel = path + '/Pre-proceso/' + perfil + '/TREASISL2.txt' ops.timeSeries('Path', 1, '-dt', dt, '-filePath', path_vel, '-factor', dashpotCoeff) ops.pattern('Plain', 10, 1) ops.load(1, *[1.0, 0.0, 0.0, 0.0]) #CAMBIO REALIZADO OJO print('Fin de creación de carga dinámica\n\n') # algoritmo de análisis dinámico ops.constraints(permutaciones[i][39][0], float(permutaciones[i][39][1]), float(permutaciones[i][39][2])) ops.test(permutaciones[i][41][0], float(permutaciones[i][41][1]), int(permutaciones[i][41][2]), int(permutaciones[i][41][3])) ops.algorithm(permutaciones[i][45][0]) ops.numberer(permutaciones[i][40][0]) ops.system(permutaciones[i][43][0]) ops.integrator(permutaciones[i][42][0], float(permutaciones[i][42][1]), float(permutaciones[i][42][2])) ops.analysis(permutaciones[i][44][0]) # ============================================================================= # ops.rayleigh(a0, a1, 0.0, 0.0) # ============================================================================= print('Inicio de análisis dinámico\n\n') #win.ui.progressBar.setValue(85) ok = ops.analyze(nStep, dT) if ok != 0: error = 'Error de convergencia en análisis dinámico de modelo' + str( permutaciones[i][0]) + '\n\n' print(error) curTime = ops.getTime() mTime = curTime print('cursTime:' + str(curTime)) curStep = (curTime / dT) print('cursStep:' + str(curStep)) rStep = (nStep - curStep) * 2.0 remStep = int(nStep - curStep) * 2.0 print('remSTep:' + str(curStep)) dT = (dT / 2) print('dT:' + str(dT)) ops.analyze(remStep, dT) if ok != 0: error = 'Error de convergencia en análisis dinámico de modelo' + str( permutaciones[i][0]) + '\n\n' print(error) curTime = ops.getTime() print('cursTime:' + str(curTime)) curStep = (curTime - mTime) / dT print('cursStep:' + str(curStep)) remStep = int(rStep - curStep) * 2 print('remSTep:' + str(curStep)) dT = (dT / 2) print('dT:' + str(dT)) ops.analyze(remStep, dT) print('Fin de análisis dinámico\n\n') ops.wipe()
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
def RunAnalysis(): AnalysisType = 'Pushover' # Pushover Gravity ## ------------------------------ ## Start of model generation ## ----------------------------- # remove existing model ops.wipe() # set modelbuilder ops.model('basic', '-ndm', 2, '-ndf', 3) import math ############################################ ### Units and Constants ################### ############################################ inch = 1 kip = 1 sec = 1 # Dependent units sq_in = inch * inch ksi = kip / sq_in ft = 12 * inch # Constants g = 386.2 * inch / (sec * sec) pi = math.acos(-1) ####################################### ##### Dimensions ####################################### # Dimensions Input H_story = 10.0 * ft W_bayX = 16.0 * ft W_bayY_ab = 5.0 * ft + 10.0 * inch W_bayY_bc = 8.0 * ft + 4.0 * inch W_bayY_cd = 5.0 * ft + 10.0 * inch # Calculated dimensions W_structure = W_bayY_ab + W_bayY_bc + W_bayY_cd ################ ### Material ################ # Steel02 Material matTag = 1 matConnAx = 2 matConnRot = 3 Fy = 60.0 * ksi # Yield stress Es = 29000.0 * ksi # Modulus of Elasticity of Steel v = 0.2 # Poisson's ratio Gs = Es / (1 + v) # Shear modulus b = 0.10 # Strain hardening ratio params = [18.0, 0.925, 0.15] # R0,cR1,cR2 R0 = 18.0 cR1 = 0.925 cR2 = 0.15 a1 = 0.05 a2 = 1.00 a3 = 0.05 a4 = 1.0 sigInit = 0.0 alpha = 0.05 ops.uniaxialMaterial('Steel02', matTag, Fy, Es, b, R0, cR1, cR2, a1, a2, a3, a4, sigInit) # ################## # ## Sections # ################## colSecTag1 = 1 colSecTag2 = 2 beamSecTag1 = 3 beamSecTag2 = 4 beamSecTag3 = 5 # COMMAND: section('WFSection2d', secTag, matTag, d, tw, bf, tf, Nfw, Nff) ops.section('WFSection2d', colSecTag1, matTag, 10.5 * inch, 0.26 * inch, 5.77 * inch, 0.44 * inch, 15, 16) # outer Column ops.section('WFSection2d', colSecTag2, matTag, 10.5 * inch, 0.26 * inch, 5.77 * inch, 0.44 * inch, 15, 16) # Inner Column ops.section('WFSection2d', beamSecTag1, matTag, 8.3 * inch, 0.44 * inch, 8.11 * inch, 0.685 * inch, 15, 15) # outer Beam ops.section('WFSection2d', beamSecTag2, matTag, 8.2 * inch, 0.40 * inch, 8.01 * inch, 0.650 * inch, 15, 15) # Inner Beam ops.section('WFSection2d', beamSecTag3, matTag, 8.0 * inch, 0.40 * inch, 7.89 * inch, 0.600 * inch, 15, 15) # Inner Beam # Beam size - W10x26 Abeam = 7.61 * inch * inch IbeamY = 144. * (inch**4) # Inertia along horizontal axis IbeamZ = 14.1 * (inch**4) # inertia along vertical axis # BRB input data Acore = 2.25 * inch Aend = 10.0 * inch LR_BRB = 0.55 # ########################### # ##### Nodes # ########################### # Create All main nodes ops.node(1, 0.0, 0.0) ops.node(2, W_bayX, 0.0) ops.node(3, 2 * W_bayX, 0.0) ops.node(11, 0.0, H_story) ops.node(12, W_bayX, H_story) ops.node(13, 2 * W_bayX, H_story) ops.node(21, 0.0, 2 * H_story) ops.node(22, W_bayX, 2 * H_story) ops.node(23, 2 * W_bayX, 2 * H_story) ops.node(31, 0.0, 3 * H_story) ops.node(32, W_bayX, 3 * H_story) ops.node(33, 2 * W_bayX, 3 * H_story) # Beam Connection nodes ops.node(1101, 0.0, H_story) ops.node(1201, W_bayX, H_story) ops.node(1202, W_bayX, H_story) ops.node(1301, 2 * W_bayX, H_story) ops.node(2101, 0.0, 2 * H_story) ops.node(2201, W_bayX, 2 * H_story) ops.node(2202, W_bayX, 2 * H_story) ops.node(2301, 2 * W_bayX, 2 * H_story) ops.node(3101, 0.0, 3 * H_story) ops.node(3201, W_bayX, 3 * H_story) ops.node(3202, W_bayX, 3 * H_story) ops.node(3301, 2 * W_bayX, 3 * H_story) # ############### # Constraints # ############### ops.fix(1, 1, 1, 1) ops.fix(2, 1, 1, 1) ops.fix(3, 1, 1, 1) # ####################### # ### Elements # ####################### # ### Assign beam-integration tags ColIntTag1 = 1 ColIntTag2 = 2 BeamIntTag1 = 3 BeamIntTag2 = 4 BeamIntTag3 = 5 ops.beamIntegration('Lobatto', ColIntTag1, colSecTag1, 4) ops.beamIntegration('Lobatto', ColIntTag2, colSecTag2, 4) ops.beamIntegration('Lobatto', BeamIntTag1, beamSecTag1, 4) ops.beamIntegration('Lobatto', BeamIntTag2, beamSecTag2, 4) ops.beamIntegration('Lobatto', BeamIntTag3, beamSecTag3, 4) # Assign geometric transformation ColTransfTag = 1 BeamTranfTag = 2 ops.geomTransf('PDelta', ColTransfTag) ops.geomTransf('Linear', BeamTranfTag) # Assign Elements ############## # ## Add non-linear column elements ops.element('forceBeamColumn', 1, 1, 11, ColTransfTag, ColIntTag1, '-mass', 0.0) ops.element('forceBeamColumn', 2, 2, 12, ColTransfTag, ColIntTag2, '-mass', 0.0) ops.element('forceBeamColumn', 3, 3, 13, ColTransfTag, ColIntTag1, '-mass', 0.0) ops.element('forceBeamColumn', 11, 11, 21, ColTransfTag, ColIntTag1, '-mass', 0.0) ops.element('forceBeamColumn', 12, 12, 22, ColTransfTag, ColIntTag2, '-mass', 0.0) ops.element('forceBeamColumn', 13, 13, 23, ColTransfTag, ColIntTag1, '-mass', 0.0) ops.element('forceBeamColumn', 21, 21, 31, ColTransfTag, ColIntTag1, '-mass', 0.0) ops.element('forceBeamColumn', 22, 22, 32, ColTransfTag, ColIntTag2, '-mass', 0.0) ops.element('forceBeamColumn', 23, 23, 33, ColTransfTag, ColIntTag1, '-mass', 0.0) # ### Add linear main beam elements, along x-axis #element('elasticBeamColumn', 101, 1101, 1201, Abeam, Es, Gs, Jbeam, IbeamY, IbeamZ, beamTransfTag, '-mass', 0.0) ops.element('forceBeamColumn', 101, 1101, 1201, BeamTranfTag, BeamIntTag1, '-mass', 0.0) ops.element('forceBeamColumn', 102, 1202, 1301, BeamTranfTag, BeamIntTag1, '-mass', 0.0) ops.element('forceBeamColumn', 201, 2101, 2201, BeamTranfTag, BeamIntTag2, '-mass', 0.0) ops.element('forceBeamColumn', 202, 2202, 2301, BeamTranfTag, BeamIntTag2, '-mass', 0.0) ops.element('forceBeamColumn', 301, 3101, 3201, BeamTranfTag, BeamIntTag3, '-mass', 0.0) ops.element('forceBeamColumn', 302, 3202, 3301, BeamTranfTag, BeamIntTag3, '-mass', 0.0) # Assign constraints between beam end nodes and column nodes (RIgid beam column connections) ops.equalDOF(11, 1101, 1, 2, 3) ops.equalDOF(12, 1201, 1, 2, 3) ops.equalDOF(12, 1202, 1, 2, 3) ops.equalDOF(13, 1301, 1, 2, 3) ops.equalDOF(21, 2101, 1, 2, 3) ops.equalDOF(22, 2201, 1, 2, 3) ops.equalDOF(22, 2202, 1, 2, 3) ops.equalDOF(23, 2301, 1, 2, 3) ops.equalDOF(31, 3101, 1, 2, 3) ops.equalDOF(32, 3201, 1, 2, 3) ops.equalDOF(32, 3202, 1, 2, 3) ops.equalDOF(33, 3301, 1, 2, 3) AllNodes = ops.getNodeTags() massX = 0.49 for nodes in AllNodes: ops.mass(nodes, massX, massX, 0.00001) ################ ## Gravity Load ################ # create TimeSeries ops.timeSeries("Linear", 1) # create a plain load pattern ops.pattern("Plain", 1, 1) # Create the nodal load ops.load(11, 0.0, -5.0 * kip, 0.0) ops.load(12, 0.0, -6.0 * kip, 0.0) ops.load(13, 0.0, -5.0 * kip, 0.0) ops.load(21, 0., -5. * kip, 0.0) ops.load(22, 0., -6. * kip, 0.0) ops.load(23, 0., -5. * kip, 0.0) ops.load(31, 0., -5. * kip, 0.0) ops.load(32, 0., -6. * kip, 0.0) ops.load(33, 0., -5. * kip, 0.0) ############################### ### PUSHOVER ANALYSIS ############################### if (AnalysisType == "Pushover"): print("<<<< Running Pushover Analysis >>>>") # Create load pattern for pushover analysis # create a plain load pattern ops.pattern("Plain", 2, 1) ops.load(11, 1.61, 0.0, 0.0) ops.load(21, 3.22, 0.0, 0.0) ops.load(31, 4.83, 0.0, 0.0) ControlNode = 31 ControlDOF = 1 MaxDisp = 0.15 * H_story DispIncr = 0.1 NstepsPush = int(MaxDisp / DispIncr) Model = 'test' LoadCase = 'Pushover' dt = 0.2 opp.createODB(Model, LoadCase, Nmodes=3) ops.system("ProfileSPD") ops.numberer("Plain") ops.constraints("Plain") ops.integrator("DisplacementControl", ControlNode, ControlDOF, DispIncr) ops.algorithm("Newton") ops.test('NormUnbalance', 1e-8, 10) ops.analysis("Static") # analyze(NstepsPush) ops.analyze(100) print("Pushover analysis complete")
def test_PortalFrame2d(): # set some properties print("================================================") print("PortalFrame2d.py: Verification 2d Elastic Frame") print(" - eigenvalue and static pushover analysis") ops.wipe() ops.model('Basic', '-ndm', 2) # properties # units kip, ft numBay = 2 numFloor = 7 bayWidth = 360.0 storyHeights = [162.0, 162.0, 156.0, 156.0, 156.0, 156.0, 156.0] E = 29500.0 massX = 0.49 M = 0. coordTransf = "Linear" # Linear, PDelta, Corotational massType = "-lMass" # -lMass, -cMass beams = [ 'W24X160', 'W24X160', 'W24X130', 'W24X130', 'W24X110', 'W24X110', 'W24X110' ] eColumn = [ 'W14X246', 'W14X246', 'W14X246', 'W14X211', 'W14X211', 'W14X176', 'W14X176' ] iColumn = [ 'W14X287', 'W14X287', 'W14X287', 'W14X246', 'W14X246', 'W14X211', 'W14X211' ] columns = [eColumn, iColumn, eColumn] WSection = { 'W14X176': [51.7, 2150.], 'W14X211': [62.1, 2670.], 'W14X246': [72.3, 3230.], 'W14X287': [84.4, 3910.], 'W24X110': [32.5, 3330.], 'W24X130': [38.3, 4020.], 'W24X160': [47.1, 5120.] } nodeTag = 1 # procedure to read def ElasticBeamColumn(eleTag, iNode, jNode, sectType, E, transfTag, M, massType): found = 0 prop = WSection[sectType] A = prop[0] I = prop[1] ops.element('elasticBeamColumn', eleTag, iNode, jNode, A, E, I, transfTag, '-mass', M, massType) # add the nodes # - floor at a time yLoc = 0. for j in range(0, numFloor + 1): xLoc = 0. for i in range(0, numBay + 1): ops.node(nodeTag, xLoc, yLoc) xLoc += bayWidth nodeTag += 1 if j < numFloor: storyHeight = storyHeights[j] yLoc += storyHeight # fix first floor ops.fix(1, 1, 1, 1) ops.fix(2, 1, 1, 1) ops.fix(3, 1, 1, 1) #rigid floor constraint & masses nodeTagR = 5 nodeTag = 4 for j in range(1, numFloor + 1): for i in range(0, numBay + 1): if nodeTag != nodeTagR: ops.equalDOF(nodeTagR, nodeTag, 1) else: ops.mass(nodeTagR, massX, 1.0e-10, 1.0e-10) nodeTag += 1 nodeTagR += numBay + 1 # add the columns # add column element ops.geomTransf(coordTransf, 1) eleTag = 1 for j in range(0, numBay + 1): end1 = j + 1 end2 = end1 + numBay + 1 thisColumn = columns[j] for i in range(0, numFloor): secType = thisColumn[i] ElasticBeamColumn(eleTag, end1, end2, secType, E, 1, M, massType) end1 = end2 end2 += numBay + 1 eleTag += 1 # add beam elements for j in range(1, numFloor + 1): end1 = (numBay + 1) * j + 1 end2 = end1 + 1 secType = beams[j - 1] for i in range(0, numBay): ElasticBeamColumn(eleTag, end1, end2, secType, E, 1, M, massType) end1 = end2 end2 = end1 + 1 eleTag += 1 # calculate eigenvalues & print results numEigen = 7 eigenValues = ops.eigen(numEigen) PI = 2 * asin(1.0) # # apply loads for static analysis & perform analysis # ops.timeSeries('Linear', 1) ops.pattern('Plain', 1, 1) ops.load(22, 20.0, 0., 0.) ops.load(19, 15.0, 0., 0.) ops.load(16, 12.5, 0., 0.) ops.load(13, 10.0, 0., 0.) ops.load(10, 7.5, 0., 0.) ops.load(7, 5.0, 0., 0.) ops.load(4, 2.5, 0., 0.) ops.integrator('LoadControl', 1.0) ops.algorithm('Linear') ops.analysis('Static') ops.analyze(1) # determine PASS/FAILURE of test ok = 0 # # print pretty output of comparsions # # SAP2000 SeismoStruct comparisonResults = [[ 1.2732, 0.4313, 0.2420, 0.1602, 0.1190, 0.0951, 0.0795 ], [1.2732, 0.4313, 0.2420, 0.1602, 0.1190, 0.0951, 0.0795]] print("\n\nPeriod Comparisons:") print('{:>10}{:>15}{:>15}{:>15}'.format('Period', 'OpenSees', 'SAP2000', 'SeismoStruct')) #formatString {%10s%15.5f%15.4f%15.4f} for i in range(0, numEigen): lamb = eigenValues[i] period = 2 * PI / sqrt(lamb) print('{:>10}{:>15.5f}{:>15.4f}{:>15.4f}'.format( i + 1, period, comparisonResults[0][i], comparisonResults[1][i])) resultOther = comparisonResults[0][i] if abs(period - resultOther) > 9.99e-5: ok = -1 # print table of camparsion # Parameter SAP2000 SeismoStruct comparisonResults = [[ "Disp Top", "Axial Force Bottom Left", "Moment Bottom Left" ], [1.45076, 69.99, 2324.68], [1.451, 70.01, 2324.71]] tolerances = [9.99e-6, 9.99e-3, 9.99e-3] print("\n\nSatic Analysis Result Comparisons:") print('{:>30}{:>15}{:>15}{:>15}'.format('Parameter', 'OpenSees', 'SAP2000', 'SeismoStruct')) for i in range(3): response = ops.eleResponse(1, 'forces') if i == 0: result = ops.nodeDisp(22, 1) elif i == 1: result = abs(response[1]) else: result = response[2] print('{:>30}{:>15.3f}{:>15.2f}{:>15.2f}'.format( comparisonResults[0][i], result, comparisonResults[1][i], comparisonResults[2][i])) resultOther = comparisonResults[1][i] tol = tolerances[i] if abs(result - resultOther) > tol: ok = -1 print("failed-> ", i, abs(result - resultOther), tol) assert ok == 0
def test_EigenAnal_twoStoryShearFrame7(): ops.wipe() #input m = 100.0/386.0 numModes = 2 #material Ac = 63.41 Ic = 320.0 E = 30000.0 Ib = 10e+12 Ab = 63.41 #geometry L = 288. h = 144. # define the model #--------------------------------- #model builder ops.model('BasicBuilder', '-ndm', 2, '-ndf', 3) # nodal coordinates: ops.node(1, 0., 0.) ops.node(2, L, 0. ) ops.node(3, 0., h ) ops.node(4, L, h ) ops.node(5, 0., 2*h) ops.node(6, L, 2*h) # Single point constraints -- Boundary Conditions ops.fix(1, 1, 1, 1) ops.fix(2, 1, 1, 1) # MP constraints ops.equalDOF(3, 4, 2, 3) ops.equalDOF(5, 6, 2, 3) # assign mass ops.mass(3, m, 0., 0. ) ops.mass(4, m, 0., 0. ) ops.mass(5, m/2., 0., 0. ) ops.mass(6, m/2., 0., 0. ) # define geometric transformation: TransfTag = 1 ops.geomTransf('Linear', TransfTag ) # define elements: # columns ops.element('elasticBeamColumn',1, 1, 3, Ac, E, 2.*Ic, TransfTag) ops.element('elasticBeamColumn',2, 3, 5, Ac, E, Ic , TransfTag) ops.element('elasticBeamColumn',3, 2, 4, Ac, E, 2.*Ic, TransfTag) ops.element('elasticBeamColumn',4, 4, 6, Ac, E, Ic , TransfTag) # beams ops.element('elasticBeamColumn',5, 3, 4, Ab, E, Ib , TransfTag) ops.element('elasticBeamColumn',6, 5, 6, Ab, E, Ib , TransfTag) # record eigenvectors #---------------------- # for { k 1 } { k <= numModes } { incr k } { # recorder Node -file format "modes/mode%i.out" k -nodeRange 1 6 -dof 1 2 3 "eigen k" # } # perform eigen analysis #----------------------------- lamb = ops.eigen(numModes) # calculate frequencies and periods of the structure #--------------------------------------------------- omega = [] f = [] T = [] pi = 3.141593 for lam in lamb : print("labmbda = ", lam) omega.append(math.sqrt(lam)) f.append(math.sqrt(lam)/(2*pi)) T.append((2*pi)/math.sqrt(lam)) print("periods are ", T) # write the output file cosisting of periods #-------------------------------------------- period = "Periods.txt" Periods = open(period, "w") for t in T: Periods.write(repr(t)+'\n') Periods.close() # create display for mode shapes #--------------------------------- # windowTitle xLoc yLoc xPixels yPixels # recorder display "Mode Shape 1" 10 10 500 500 -wipe # prp h h 1 # projection reference point (prp) defines the center of projection (viewer eye) # vup 0 1 0 # view-up vector (vup) # vpn 0 0 1 # view-plane normal (vpn) # viewWindow -200 200 -200 200 # coordiantes of the window relative to prp # display -1 5 20 # the 1st arg. is the tag for display mode (ex. -1 is for the first mode shape) # the 2nd arg. is magnification factor for nodes, the 3rd arg. is magnif. factor of deformed shape # recorder display "Mode Shape 2" 10 510 500 500 -wipe # prp h h 1 # vup 0 1 0 # vpn 0 0 1 # viewWindow -200 200 -200 200 # display -2 5 20 # Run a one step gravity load with no loading (to record eigenvectors) #----------------------------------------------------------------------- ops.integrator('LoadControl', 0.0, 1, 0.0, 0.0) # Convergence test # tolerance maxIter displayCode ops.test('EnergyIncr', 1.0e-10, 100, 0) # Solution algorithm ops.algorithm('Newton') # DOF numberer ops.numberer('RCM') # Constraint handler ops.constraints('Transformation') # System of equations solver ops.system('ProfileSPD') ops.analysis('Static') res = ops.analyze(1) if res < 0: print("Modal analysis failed") # get values of eigenvectors for translational DOFs #--------------------------------------------------- f11 = ops.nodeEigenvector(3, 1, 1) f21 = ops.nodeEigenvector(5, 1, 1) f12 = ops.nodeEigenvector(3, 2, 1) f22 = ops.nodeEigenvector(5, 2, 1) print("eigenvector 1: ", [f11/f21, f21/f21]) print("eigenvector 2: ", [f12/f22, f22/f22]) assert abs(T[0]-0.5148773207872785)<1e-12 and abs(T[1]-0.25743866038265584)<1e-12 and abs(f11/f21-0.49999999998933464)<1e-12 and abs(f21/f21-1.0)<1e-12 and abs(f12/f22+1.0000000000213303)<1e-12 and abs(f22/f22-1.0)<1e-12 print("==========================================")
def get_inelastic_response(mass, k_spring, f_yield, motion, dt, xi=0.05, r_post=0.0): """ Run seismic analysis of a nonlinear SDOF :param mass: SDOF mass :param k_spring: spring stiffness :param f_yield: yield strength :param motion: list, acceleration values :param dt: float, time step of acceleration values :param xi: damping ratio :param r_post: post-yield stiffness :return: """ opy.wipe() opy.model('basic', '-ndm', 2, '-ndf', 3) # 2 dimensions, 3 dof per node # Establish nodes bot_node = 1 top_node = 2 opy.node(bot_node, 0., 0.) opy.node(top_node, 0., 0.) # Fix bottom node opy.fix(top_node, opc.FREE, opc.FIXED, opc.FIXED) opy.fix(bot_node, opc.FIXED, opc.FIXED, opc.FIXED) # Set out-of-plane DOFs to be slaved opy.equalDOF(1, 2, *[2, 3]) # nodal mass (weight / g): opy.mass(top_node, mass, 0., 0.) # Define material bilinear_mat_tag = 1 mat_type = "Steel01" mat_props = [f_yield, k_spring, r_post] opy.uniaxialMaterial(mat_type, bilinear_mat_tag, *mat_props) # Assign zero length element beam_tag = 1 opy.element('zeroLength', beam_tag, bot_node, top_node, "-mat", bilinear_mat_tag, "-dir", 1, '-doRayleigh', 1) # Define the dynamic analysis load_tag_dynamic = 1 pattern_tag_dynamic = 1 values = list(-1 * motion) # should be negative opy.timeSeries('Path', load_tag_dynamic, '-dt', dt, '-values', *values) opy.pattern('UniformExcitation', pattern_tag_dynamic, opc.X, '-accel', load_tag_dynamic) # set damping based on first eigen mode angular_freq2 = opy.eigen('-fullGenLapack', 1) if hasattr(angular_freq2, '__len__'): angular_freq2 = angular_freq2[0] angular_freq = angular_freq2**0.5 alpha_m = 0.0 beta_k = 2 * xi / angular_freq beta_k_comm = 0.0 beta_k_init = 0.0 opy.rayleigh(alpha_m, beta_k, beta_k_init, beta_k_comm) # Run the dynamic analysis opy.wipeAnalysis() opy.algorithm('Newton') opy.system('SparseGeneral') opy.numberer('RCM') opy.constraints('Transformation') opy.integrator('Newmark', 0.5, 0.25) opy.analysis('Transient') tol = 1.0e-10 iterations = 10 opy.test('EnergyIncr', tol, iterations, 0, 2) analysis_time = (len(values) - 1) * dt analysis_dt = 0.001 outputs = { "time": [], "rel_disp": [], "rel_accel": [], "rel_vel": [], "force": [] } while opy.getTime() < analysis_time: curr_time = opy.getTime() opy.analyze(1, analysis_dt) outputs["time"].append(curr_time) outputs["rel_disp"].append(opy.nodeDisp(top_node, 1)) outputs["rel_vel"].append(opy.nodeVel(top_node, 1)) outputs["rel_accel"].append(opy.nodeAccel(top_node, 1)) opy.reactions() outputs["force"].append( -opy.nodeReaction(bot_node, 1)) # Negative since diff node opy.wipe() for item in outputs: outputs[item] = np.array(outputs[item]) return outputs
def get_inelastic_response(mass, k_spring, f_yield, motion, dt, xi=0.05, r_post=0.0): """ Run seismic analysis of a nonlinear SDOF :param mass: SDOF mass :param k_spring: spring stiffness :param f_yield: yield strength :param motion: list, acceleration values :param dt: float, time step of acceleration values :param xi: damping ratio :param r_post: post-yield stiffness :return: """ osi = o3.OpenSeesInstance(ndm=2) # Establish nodes bot_node = o3.node.Node(osi, 0, 0) top_node = o3.node.Node(osi, 0, 0) # Fix bottom node opy.fix(top_node.tag, o3.cc.FREE, o3.cc.FIXED, o3.cc.FIXED) opy.fix(bot_node.tag, o3.cc.FIXED, o3.cc.FIXED, o3.cc.FIXED) # Set out-of-plane DOFs to be slaved opy.equalDOF(top_node.tag, bot_node.tag, *[o3.cc.Y, o3.cc.ROTZ]) # nodal mass (weight / g): opy.mass(top_node.tag, mass, 0., 0.) # Define material bilinear_mat = o3.uniaxial_material.Steel01(osi, fy=f_yield, e0=k_spring, b=r_post) # Assign zero length element, # Note: pass actual node and material objects into element o3.element.ZeroLength(osi, [bot_node, top_node], mats=[bilinear_mat], dirs=[o3.cc.DOF2D_X], r_flag=1) # Define the dynamic analysis load_tag_dynamic = 1 pattern_tag_dynamic = 1 values = list(-1 * motion) # should be negative opy.timeSeries('Path', load_tag_dynamic, '-dt', dt, '-values', *values) opy.pattern('UniformExcitation', pattern_tag_dynamic, o3.cc.X, '-accel', load_tag_dynamic) # set damping based on first eigen mode angular_freq2 = opy.eigen('-fullGenLapack', 1) if hasattr(angular_freq2, '__len__'): angular_freq2 = angular_freq2[0] angular_freq = angular_freq2**0.5 beta_k = 2 * xi / angular_freq o3.rayleigh.Rayleigh(osi, alpha_m=0.0, beta_k=beta_k, beta_k_init=0.0, beta_k_comm=0.0) # Run the dynamic analysis opy.wipeAnalysis() newmark_gamma = 0.5 newmark_beta = 0.25 o3.algorithm.Newton(osi) o3.constraints.Transformation(osi) o3.algorithm.Newton(osi) o3.numberer.RCM(osi) o3.system.SparseGeneral(osi) o3.integrator.Newmark(osi, newmark_gamma, newmark_beta) o3.analysis.Transient(osi) o3.test_check.EnergyIncr(osi, tol=1.0e-10, max_iter=10) analysis_time = (len(values) - 1) * dt analysis_dt = 0.001 outputs = { "time": [], "rel_disp": [], "rel_accel": [], "rel_vel": [], "force": [] } while opy.getTime() < analysis_time: curr_time = opy.getTime() opy.analyze(1, analysis_dt) outputs["time"].append(curr_time) outputs["rel_disp"].append(opy.nodeDisp(top_node.tag, o3.cc.X)) outputs["rel_vel"].append(opy.nodeVel(top_node.tag, o3.cc.X)) outputs["rel_accel"].append(opy.nodeAccel(top_node.tag, o3.cc.X)) opy.reactions() outputs["force"].append(-opy.nodeReaction( bot_node.tag, o3.cc.X)) # Negative since diff node opy.wipe() for item in outputs: outputs[item] = np.array(outputs[item]) return outputs
# create fixity at pile head (location of loading) op.fix(200 + nNodePile, 0, 1, 0, 1, 0, 1) # create fixities for remaining pile nodes for i in range(201, 200 + nNodePile): op.fix(i, 0, 1, 0, 1, 0, 1) print("Finished creating all pile node fixities...") #---------------------------------------------------------- # define equal dof between pile and spring nodes #---------------------------------------------------------- for i in range(1, nNodeEmbed + 1): op.equalDOF(200 + i, 100 + i, 1, 3) print("Finished creating all equal degrees of freedom...") #---------------------------------------------------------- # pile section #---------------------------------------------------------- ########################################################################################################################################################################## ######################################################################################################################################################################### #---------------------------------------------------------- # create elastic pile section #---------------------------------------------------------- secTag = 1
for row in range(wall_constraint_organizer.shape[0]): if wall_constraint_organizer[row,0]!= 0: end_column= np.where(wall_constraint_organizer[row,:] == 0)[0][0] for column in range(end_column): wall_constraint_data[row,column]= np.where(original_wall_data_arr[:,2] == wall_constraint_organizer[row,column])[0][0]+1 check= np.zeros((1000,2)) check_row= 0 for row in range(wall_constraint_data.shape[0]): if wall_constraint_data[row,0]!= 0: end_column= np.where(wall_constraint_data[row,:] == 0)[0][0] for column in range(1,end_column): for floor in range(num_story): ops.equalDOF(int(wall_constraint_data[row,0]+1000*(floor+2)), int(wall_constraint_data[row,column]+1000*(floor+2)),3,4,5) check[check_row,0]= wall_constraint_data[row,0]+1000*(floor+2) check[check_row,1]= wall_constraint_data[row,column]+1000*(floor+2) check_row= check_row+1 # ============================================================================= # Define Coordinate Transformation # ============================================================================= ops.geomTransf('Linear', 1, 1, 0, 0) # ============================================================================= # Define Elements # ============================================================================= #in local coordinate system: 0.J 1.Iz 2.Iy moment_of_inertia= np.zeros((wall.shape[0],3))