def write_input_files(self, N_batches=1): 'Write ABAQUS input files and batch script(s)' # Open list of batch files batchfiles = [] for b in range(N_batches): fname = '{0:s}/_run_{1:d}.bat'.format(self.out_dir, b) batchfiles.append(open(fname, 'w')) pp_script = open('{0:s}/_postproc.bat'.format(self.out_dir), 'w') b = 0 for jobname, j in self.db.iterrows(): w = self.wheel_from_row(j) mm = ModeMatrix(w) # Apply tension if j['spk_T'] == 0.: w.apply_tension(0.001) else: w.apply_tension(j['spk_T']) # Choose total radial displacement if j['sim_u2'] == 'auto': # Estimate radial displacement to failure for truss wheel Pc_est = mm.calc_lat_stiff() * w.rim.radius u_rad = 1.5 * Pc_est / mm.calc_rad_stiff() else: u_rad = j['sim_u2'] # Write ABAQUS input files write_abaqus_pre(self.out_dir + '/' + jobname + '_preT.inp', w, j) write_abaqus_exp(self.out_dir + '/' + jobname + '_collapse.inp', w, j, u_rad) # Write to batch file bf = batchfiles[b] bf.write('call abaqus interactive ') bf.write('job={0:s}_preT input={0:s}_preT.inp\n'.format(jobname)) bf.write('call abaqus interactive ') bf.write( 'job={0:s}_collapse input={0:s}_collapse.inp oldjob={0:s}_preT\n' .format(jobname)) # Next batchfile b = (b + 1) % N_batches # Write entry to postprocess script pp_script.write('call abaqus python postproc_rad_buckling.py ' + '{0:s}_collapse.odb\n'.format(jobname)) # Close batch files for f in batchfiles: f.close()
def calc_tor_stiff(wheel, theta=0., N=20, smeared_spokes=True, tension=True, buckling=True, coupling=True, r0=False): 'Calculate torsional (wind-up) stiffness in [N/rad].' mm = ModeMatrix(wheel, N=N) F_ext = mm.F_ext(theta, [0., 0., 1., 0.]) d = np.zeros(F_ext.shape) K = (mm.K_rim(tension=buckling, r0=r0) + mm.K_spk(tension=tension, smeared_spokes=smeared_spokes)) if coupling: d = np.linalg.solve(K, F_ext) else: ix_uc = mm.get_ix_uncoupled(dim='radial') K = mm.get_K_uncoupled(K=K, dim='radial') d[ix_uc] = np.linalg.solve(K, F_ext[ix_uc]) return wheel.rim.radius / mm.B_theta(theta).dot(d)[2]
def calc_lat_stiff(wheel, theta=0., N=20, smeared_spokes=True, tension=True, buckling=True, coupling=False, r0=False): 'Calculate lateral stiffness.' mm = ModeMatrix(wheel, N=N) F_ext = mm.F_ext(0., [1., 0., 0., 0.]) d = np.zeros(F_ext.shape) K = (mm.K_rim(tension=buckling, r0=r0) + mm.K_spk(tension=tension, smeared_spokes=smeared_spokes)) if coupling: d = np.linalg.solve(K, F_ext) else: ix_uc = mm.get_ix_uncoupled(dim='lateral') K = mm.get_K_uncoupled(K=K, dim='lateral') d[ix_uc] = np.linalg.solve(K, F_ext[ix_uc]) return 1. / mm.B_theta(0.).dot(d)[0]
def calc_buckling_tension_modematrix(smeared_spokes=True, coupling=True, r0=True): 'Estimate buckling tension from condition number of stiffness matrix.' mm = ModeMatrix(wheel, N=N) def neg_cond(T): wheel.apply_tension(T) K = (mm.K_rim(buckling=True, r0=r0) + mm.K_spk(smeared_spokes=smeared_spokes)) if not coupling: K = mm.get_K_uncoupled(buckling=True, smeared_spokes=smeared_spokes) return -np.linalg.cond(K) # Find approximate buckling tension from linear analytical solution Tc_approx = calc_buckling_tension(wheel, approx='linear') # Maximize the condition number as a function of tension res = minimize(fun=neg_cond, x0=[Tc_approx], method='Nelder-Mead', options={'maxiter': 50}) return res.x[0]
def extract_results(self): 'Extract results and calculated quantities from ABAQUS output' def spoke_buckle_load(pd_data): 'Get load at which spokes start to buckle' return pd_data.RF3[np.nonzero(pd_data.n_buckled)[0][0]] for i in self.db.index: print('.', end='') j = self.db.loc[i] w = self.wheel_from_row(j) mm = ModeMatrix(w) try: # Buckling tension Tc, nc = calc_buckling_tension(w) self.db.at[i, 'Tc'] = Tc self.db.at[i, 'nc'] = nc # Get load-deflection data if j['sim_type'] == 'exp': pd_fname = self.out_dir + '/' + j.name + '_collapse_Pd.csv' elif j['sim_type'] == 'riks': pd_fname = self.out_dir + '/' + j.name + '_riks_Pd.csv' pd_data = pd.read_csv(pd_fname) pd_data.columns = ['Time', 'U3', 'RF3', 'n_buckled'] # Stiffness w.apply_tension(0.01) K_lat_0 = mm.calc_lat_stiff(smeared_spokes=True, coupling=False) K_rad_0 = mm.calc_rad_stiff(smeared_spokes=False, coupling=False) self.db.at[i, 'K_lat_0'] = K_lat_0 self.db.at[i, 'K_rad_0'] = K_rad_0 # Critical loads self.db.at[i, 'Pc_max'] = max(pd_data.RF3) self.db.at[i, 'Pc_spk'] = spoke_buckle_load(pd_data) except Exception as e: print('Error on {0:s}: {1:s}'.format(j.name, str(e))) continue
def calc_buckling_tension_modematrix(wheel, smeared_spokes=False, coupling=True, r0=True, N=24): 'Estimate buckling tension from condition number of stiffness matrix.' mm = ModeMatrix(wheel, N=N) K_matl = (mm.K_rim_matl(r0=r0) + mm.K_spk(tension=False, smeared_spokes=smeared_spokes)) K_geom = (mm.K_rim_geom(r0=r0) - mm.K_spk_geom(smeared_spokes=smeared_spokes)) # Solve generalized eigienvalue problem: # (K_matl + T*K_geom) if coupling: w, v = eig(K_matl, K_geom) else: w, v = eig(mm.get_K_uncoupled(K_matl), mm.get_K_uncoupled(K_geom)) return np.min(np.real(w)[np.real(w) > 0])
def calc_rad_stiff(wheel): 'Calculate radial stiffness.' # Create a ModeMatrix model with 24 modes mm = ModeMatrix(wheel, N=24) # Calculate stiffness matrix K = mm.K_rim(tension=True) + mm.K_spk(smeared_spokes=False, tension=True) # Create a unit radial load pointing radially inwards at theta=0 F_ext = mm.F_ext(0., np.array([0., 1., 0., 0.])) # Solve for the mode coefficients dm = np.linalg.solve(K, F_ext) return 1e-6 / mm.rim_def_rad(0., dm)[0]
def calc_rot_stiff(wheel): 'Calculate rotational (wind-up) stiffness.' # Create a ModeMatrix model with 24 modes mm = ModeMatrix(wheel, N=24) # Calculate stiffness matrix K = mm.K_rim(tension=True) + mm.K_spk(smeared_spokes=False, tension=True) # Create a unit tangential load at theta=0 F_ext = mm.F_ext(0., np.array([0., 0., 1., 0.])) # Solve for the mode coefficients dm = np.linalg.solve(K, F_ext) return 1e-3*np.pi/180*wheel.rim.radius / mm.rim_def_tan(0., dm)[0]
def calc_lat_stiff(wheel): 'Calculate lateral (side-load) stiffness.' # Create a ModeMatrix model with 24 modes mm = ModeMatrix(wheel, N=24) # Calculate stiffness matrix K = mm.K_rim(tension=True) + mm.K_spk(smeared_spokes=False, tension=True) # Create a unit lateral load at theta=0 F_ext = mm.F_ext(0., np.array([1., 0., 0., 0.])) # Solve for the mode coefficients dm = np.linalg.solve(K, F_ext) return 1e-3 / mm.rim_def_lat(0., dm)[0]
# Create an example wheel and rim wheel = BicycleWheel() wheel.hub = Hub(width=0.05, diameter=0.05) wheel.rim = Rim(radius=0.3, area=100e-6, I_lat=200. / 69e9, I_rad=100. / 69e9, J_tor=25. / 26e9, I_warp=0.0, young_mod=69e9, shear_mod=26e9) wheel.lace_cross(n_spokes=36, n_cross=3, diameter=2.0e-3, young_mod=210e9) # Create a ModeMatrix model with 24 modes mm = ModeMatrix(wheel, N=24) # Create a 500 Newton pointing radially inwards at theta=0 F_ext = mm.F_ext(0., np.array([0., 500., 0., 0.])) # Calculate stiffness matrix K = mm.K_rim(tension=False) + mm.K_spk(smeared_spokes=False, tension=False) # Solve for the mode coefficients dm = np.linalg.solve(K, F_ext) # Get radial deflection theta = np.linspace(-np.pi, np.pi, 100) rad_def = mm.rim_def_rad(theta, dm) # Calculate change in spoke tensions
wheel.hub = Hub(diameter=0.050, width=0.05) wheel.rim = Rim(radius=0.3, area=100e-6, I_lat=200./69e9, I_rad=100./69e9, J_tor=25./26e9, I_warp=0.0, young_mod=69e9, shear_mod=26e9) diam_flange = np.linspace(0.01, 0.1, 10) rot_stiff = [] for d in diam_flange: # Create hub and spokes for each flange diameter wheel.hub = Hub(width=0.025, diameter=d) wheel.lace_cross(n_spokes=36, n_cross=3, diameter=2.0e-3, young_mod=210e9) # Create a ModeMatrix model with 24 modes mm = ModeMatrix(wheel, N=24) # Create a unit tangential force F_ext = mm.F_ext(0., np.array([0., 0., 1., 0.])) # Calculate stiffness matrix K = mm.K_rim(tension=False) + mm.K_spk(smeared_spokes=True, tension=False) # Solve for the mode coefficients dm = np.linalg.solve(K, F_ext) # Calculate the rotational stiffness rot_stiff.append(np.pi/180*wheel.rim.radius/mm.rim_def_tan(0., dm)[0]) plt.plot(diam_flange * 100, rot_stiff, 'ro') plt.xlabel('Flange diameter [cm]')
from bikewheelcalc import BicycleWheel, Rim, Hub, ModeMatrix import matplotlib.pyplot as plt import numpy as np # Create an example wheel and rim wheel = BicycleWheel() wheel.hub = Hub(width=0.05, diameter=0.05) wheel.rim = Rim(radius=0.3, area=100e-6, I_lat=200./69e9, I_rad=100./69e9, J_tor=25./26e9, I_warp=0.0, young_mod=69e9, shear_mod=26e9) wheel.lace_cross(n_spokes=36, n_cross=3, diameter=2.0e-3, young_mod=210e9) # Create a ModeMatrix model with 24 modes mm = ModeMatrix(wheel, N=24) # Create a 500 Newton pointing radially inwards at theta=0 F_ext = mm.F_ext(0., np.array([0., 500., 0., 0.])) # Calculate stiffness matrix K = mm.K_rim(tension=False) + mm.K_spk(smeared_spokes=False, tension=False) # Solve for the mode coefficients dm = np.linalg.solve(K, F_ext) # Get radial deflection theta = np.linspace(-np.pi, np.pi, 100) rad_def = mm.rim_def_rad(theta, dm) # Calculate change in spoke tensions
def extract_results(self): 'Extract results and calculated quantities from ABAQUS output' def buckling_load_southwell(pd_data): 'Get critical buckling load from Southwell plot' pass def buckling_load_nonlin(pd_data): 'Get critical buckling from departure from linearity' # Fit straight line to first 5% of data N = int(np.ceil(0.05 * len(pd_data))) pf = np.polyfit(pd_data['U2'][:N], pd_data['RF2'][:N], 1) err = (np.polyval(pf, pd_data['U2']) - pd_data['RF2']) /\ np.mean(pd_data['RF2']) return pd_data['RF2'][np.argmax(np.abs(err) > 0.02)] def calc_T_nb(w, K_lat_0, K_rad_0, Tc, form=1): 'Calculate minimum spoke tension for no spoke buckling' R = w.rim.radius EA = w.spokes[0].EA alpha = w.spokes[0].alpha ls = w.spokes[0].length if form == 2: # Quadratic approximation for K_lat(T) x = K_rad_0 * Tc * ls / (2 * EA * K_lat_0 * R * np.cos(alpha)) return np.sqrt(1 + x**2) - x else: # Linear approximation for K_lat(T) return 1.0 / (1 + K_rad_0 * ls * Tc / (K_lat_0 * R * EA * np.cos(alpha))) def calc_P_nb(w, K_lat_0, K_rad_0, Tc, form=1): 'Critical load at the critical no-buckling tension' R = w.rim.radius EA = w.spokes[0].EA alpha = w.spokes[0].alpha ls = w.spokes[0].length if form == 2: # Quadratic approximation for K_lat(T) x = K_rad_0 * Tc * ls / (2 * EA * K_lat_0 * R * np.cos(alpha)) T_nb = np.sqrt(1 + x**2) - x return K_lat_0 * R * (1 - T_nb**2) else: # Linear approximation for K_lat(T) return K_lat_0 * R / (1 + EA / Tc * K_lat_0 / K_rad_0) for i in self.db.index: print('.', end='') j = self.db.loc[i] w = self.wheel_from_row(j) mm = ModeMatrix(w) try: # Buckling tension Tc, nc = calc_buckling_tension(w) self.db.at[i, 'Tc'] = Tc self.db.at[i, 'nc'] = nc # Get load-deflection data pd_data = pd.read_csv(self.out_dir + '/' + j.name + '_collapse_Pd.csv') pd_data.columns = ['Time', 'U2', 'RF2', 'U3', 'n_buckled'] # Stiffness at zero tension w.apply_tension(0.01) K_lat_0 = mm.calc_lat_stiff(smeared_spokes=True, coupling=False) K_rad_0 = mm.calc_rad_stiff(smeared_spokes=False, coupling=False) w.apply_tension(j['spk_T']) K_lat = mm.calc_lat_stiff(smeared_spokes=True, coupling=False) self.db.at[i, 'K_lat_0'] = K_lat_0 self.db.at[i, 'K_rad_0'] = K_rad_0 self.db.at[i, 'K_lat'] = K_lat # Radial buckling load self.db.at[i, 'Pc_max'] = max(pd_data.RF2) self.db.at[i, 'Pc_nonlin'] = buckling_load_nonlin(pd_data) self.db.at[i, 'T_nb'] = calc_T_nb(w, K_lat_0, K_rad_0, Tc) self.db.at[i, 'Pc_nb'] = calc_P_nb(w, K_lat_0, K_rad_0, Tc) self.db.at[i, 'T_nb_2'] = calc_T_nb(w, K_lat_0, K_rad_0, Tc, form=2) self.db.at[i, 'Pc_nb_2'] = calc_P_nb(w, K_lat_0, K_rad_0, Tc, form=2) except Exception as e: print('Error on {0:s}: {1:s}'.format(j.name, str(e))) continue