def compute_applied_axial(self, params): """Compute axial stress for spar from z-axis loading INPUTS: ---------- params : dictionary of input parameters section_mass : float (scalar/vector), mass of each spar section as axial loading increases with spar depth OUTPUTS: ------- stress : float (scalar/vector), axial stress """ # Unpack variables R_od, _ = nodal2sectional(params['d_full']) R_od *= 0.5 t_wall, _ = nodal2sectional(params['t_full']) section_mass = params['section_mass'] m_stack = params['stack_mass_in'] # Middle radius R = R_od - 0.5 * t_wall # Add in weight of sections above it axial_load = m_stack + np.r_[0.0, np.cumsum(section_mass[:-1])] # Divide by shell cross sectional area to get stress return (gravity * axial_load / (2.0 * np.pi * R * t_wall))
def solve_nonlinear(self, params, unknowns, resids): d,_ = nodal2sectional(params['d']) tube = Tube(d,params['t']) unknowns['Az'] = tube.Area unknowns['Asx'] = tube.Asx unknowns['Asy'] = tube.Asy unknowns['Jz'] = tube.J0 unknowns['Ixx'] = tube.Jxx unknowns['Iyy'] = tube.Jyy
def solve_nonlinear(self, params, unknowns, resids): d, _ = nodal2sectional(params['d']) tube = Tube(d, params['t']) unknowns['Az'] = tube.Area unknowns['Asx'] = tube.Asx unknowns['Asy'] = tube.Asy unknowns['Jz'] = tube.J0 unknowns['Ixx'] = tube.Jxx unknowns['Iyy'] = tube.Jyy
def solve_nonlinear(self, params, unknowns, resids): # Unpack some variables axial_stress = params['axial_stress'] shear_stress = params['shear_stress'] hoop_stress = params['hoop_stress'] sigma_y = params['sigma_y'] * np.ones(axial_stress.shape) E = params['E'] * np.ones(axial_stress.shape) L_reinforced = params['L_reinforced'] * np.ones(axial_stress.shape) d,_ = nodal2sectional(params['d']) z_section,_ = nodal2sectional(params['z']) # Frequencies unknowns['structural_frequencies'] = np.zeros(NFREQ) unknowns['structural_frequencies'][0] = params['f1'] unknowns['structural_frequencies'][1] = params['f2'] # von mises stress unknowns['stress'] = Util.vonMisesStressUtilization(axial_stress, hoop_stress, shear_stress, params['gamma_f']*params['gamma_m']*params['gamma_n'], sigma_y) # shell buckling unknowns['shell_buckling'] = Util.shellBucklingEurocode(d, params['t'], axial_stress, hoop_stress, shear_stress, L_reinforced, E, sigma_y, params['gamma_f'], params['gamma_b']) # global buckling tower_height = params['z'][-1] - params['z'][0] M = np.sqrt(params['Mxx']**2 + params['Myy']**2) unknowns['global_buckling'] = Util.bucklingGL(d, params['t'], params['Fz'], M, tower_height, E, sigma_y, params['gamma_f'], params['gamma_b']) # fatigue N_DEL = 365.0*24.0*3600.0*params['life'] * np.ones(len(params['t'])) unknowns['damage'] = np.zeros(N_DEL.shape) if any(params['M_DEL']): M_DEL = np.interp(z_section, params['z_DEL'], params['M_DEL']) unknowns['damage'] = Util.fatigue(M_DEL, N_DEL, d, params['t'], params['m_SN'], params['DC'], params['gamma_fatigue'], stress_factor=1.0, weld_factor=True)
def setUp(self): self.params = {} self.unknowns = {} self.resid = None # For Geometry call self.params['z_full_in'] = np.linspace(0, 50.0, NPTS) self.params['z_param_in'] = np.array([0.0, 20.0, 50.0]) self.params['section_height'] = np.array([20.0, 30.0]) self.params['section_center_of_mass'], _ = nodal2sectional( self.params['z_full_in']) self.params['freeboard'] = 15.0 self.params['fairlead'] = 10.0 self.params['water_depth'] = 100.0 self.params['t_full'] = 0.5 * myones self.params['d_full'] = 2 * 10.0 * myones self.params['stack_mass_in'] = 0.0 self.params['shell_I_keel'] = 10.0 * np.array( [1.0, 1.0, 1.0, 0.0, 0.0, 0.0]) self.params['stiffener_I_keel'] = 20.0 * np.array( [1.0, 1.0, 1.0, 0.0, 0.0, 0.0]) self.params['bulkhead_I_keel'] = 30.0 * np.array( [1.0, 1.0, 1.0, 0.0, 0.0, 0.0]) self.params['water_density'] = 1e3 self.params['bulkhead_mass'] = 10.0 * myones self.params['shell_mass'] = 500.0 * np.ones(NPTS - 1) self.params['stiffener_mass'] = 100.0 * np.ones(NPTS - 1) self.params['column_mass_factor'] = 1.1 self.params['outfitting_mass_fraction'] = 0.05 self.params['permanent_ballast_height'] = 1.0 self.params['permanent_ballast_density'] = 2e3 self.params['mooring_mass'] = 50.0 self.params['mooring_vertical_load'] = 25.0 self.params['mooring_restoring_force'] = 1e5 self.params['mooring_cost'] = 1e4 self.params['ballast_cost_rate'] = 10.0 self.params['tapered_col_cost_rate'] = 100.0 self.params['outfitting_cost_rate'] = 1.0 self.geom = column.ColumnGeometry(NSEC, NPTS) self.set_geometry() self.myspar = column.ColumnProperties(NPTS)
def solve_nonlinear(self, params, unknowns, resids): # Unpack variables R_od, _ = nodal2sectional(params['d_full']) R_od *= 0.5 h_section = np.diff(params['z_full']) t_wall, _ = nodal2sectional(params['t_full']) z_param = params['z_param'] z_section = params['z_section'] t_web = sectionalInterp(z_section, z_param, params['stiffener_web_thickness']) t_flange = sectionalInterp(z_section, z_param, params['stiffener_flange_thickness']) h_web = sectionalInterp(z_section, z_param, params['stiffener_web_height']) w_flange = sectionalInterp(z_section, z_param, params['stiffener_flange_width']) L_stiffener = sectionalInterp(z_section, z_param, params['stiffener_spacing']) E = params['E'] # Young's modulus nu = params['nu'] # Poisson ratio sigma_y = params['yield_stress'] loading = params['loading'] pressure, _ = nodal2sectional(params['pressure']) # Compute applied axial stress simply, like API guidelines (as opposed to running frame3dd) sigma_ax = self.compute_applied_axial(params) (flange_compactness, web_compactness, axial_local_unity, axial_general_unity, external_local_unity, external_general_unity) = shellBuckling_withStiffeners( pressure, sigma_ax, R_od, t_wall, h_section, h_web, t_web, w_flange, t_flange, L_stiffener, E, nu, sigma_y, loading) unknowns['flange_compactness'] = flange_compactness unknowns['web_compactness'] = web_compactness unknowns['axial_local_unity'] = axial_local_unity unknowns['axial_general_unity'] = axial_general_unity unknowns['external_local_unity'] = external_local_unity unknowns['external_general_unity'] = external_general_unity
def setUp(self): self.params = {} self.unknowns = {} self.resid = None self.params['z_full_in'] = np.linspace(0, 50.0, NPTS) self.params['z_param_in'] = np.array([0.0, 20.0, 50.0]) self.params['section_height'] = np.array([20.0, 30.0]) self.params['section_center_of_mass'], _ = nodal2sectional( self.params['z_full_in']) self.params['freeboard'] = 15.0 self.params['fairlead'] = 10.0 self.params['water_depth'] = 100.0 self.geom = column.ColumnGeometry(NSEC, NPTS)
def solve_nonlinear(self, params, unknowns, resids): d,_ = nodal2sectional(params['d']) t = params['t'] # Check if the input was radii instead of diameters and convert if necessary if not self.diamFlag: d *= 2.0 min_d_to_t = params['min_d_to_t'] max_taper = params['max_taper'] unknowns['weldability'] = 1.0 - (d/t)/min_d_to_t d_ratio = d[1:]/d[:-1] manufacturability = np.minimum(d_ratio, 1.0/d_ratio) - max_taper unknowns['manufacturability'] = np.r_[manufacturability, manufacturability[-1]]
def testRegular(self): # Straight column self.cm.solve_nonlinear(self.params, self.unknowns, self.resid) expect = np.pi*(10.**2 - 9.5**2)*5.0*1.5*(50.0/(npts-1)) m = expect*(npts-1) Iax = 0.5*m*(10.**2 + 9.5**2) Ix = (1/12.)*m*(3*(10.**2 + 9.5**2) + 50*50) + m*25*25 # parallel axis on last term z_avg,_ = nodal2sectional(self.params['z_full']) self.assertAlmostEqual(self.unknowns['mass'].sum(), m) npt.assert_almost_equal(self.unknowns['mass'], expect) npt.assert_almost_equal(self.unknowns['section_center_of_mass'], z_avg) self.assertAlmostEqual(self.unknowns['center_of_mass'], 25.0) npt.assert_almost_equal(self.unknowns['I_base'], [Ix, Ix, Iax, 0.0, 0.0, 0.0], decimal=5) '''
def solve_nonlinear(self, params, unknowns, resids): d, _ = nodal2sectional(params['d']) t = params['t'] # Check if the input was radii instead of diameters and convert if necessary if not self.diamFlag: d *= 2.0 min_d_to_t = params['min_d_to_t'] max_taper = params['max_taper'] unknowns['weldability'] = 1.0 - (d / t) / min_d_to_t d_ratio = d[1:] / d[:-1] manufacturability = np.minimum(d_ratio, 1.0 / d_ratio) - max_taper unknowns['manufacturability'] = np.r_[manufacturability, manufacturability[-1]]
def testRegular(self): # Straight column self.cm.solve_nonlinear(self.params, self.unknowns, self.resid) expect = np.pi * (10.**2 - 9.5**2) * 5.0 * 1.5 * (50.0 / (npts - 1)) m = expect * (npts - 1) Iax = 0.5 * m * (10.**2 + 9.5**2) Ix = (1 / 12.) * m * (3 * (10.**2 + 9.5**2) + 50 * 50) + m * 25 * 25 # parallel axis on last term z_avg, _ = nodal2sectional(self.params['z_full']) self.assertAlmostEqual(self.unknowns['mass'].sum(), m) npt.assert_almost_equal(self.unknowns['mass'], expect) npt.assert_almost_equal(self.unknowns['section_center_of_mass'], z_avg) self.assertAlmostEqual(self.unknowns['center_of_mass'], 25.0) npt.assert_almost_equal(self.unknowns['I_base'], [Ix, Ix, Iax, 0.0, 0.0, 0.0], decimal=5) '''
def setUp(self): self.params = {} self.unknowns = {} self.resid = None self.params['z_full_in'] = np.linspace(0, 50.0, NPTS) self.params['z_param_in'] = np.array([0.0, 20.0, 50.0]) self.params['section_height'] = np.array([20.0, 30.0]) self.params['section_center_of_mass'],_ = nodal2sectional( self.params['z_full_in'] ) self.params['freeboard'] = 15.0 self.params['water_depth'] = 100.0 self.params['stiffener_web_thickness'] = np.array([0.5, 0.5]) self.params['stiffener_flange_thickness'] = np.array([0.3, 0.3]) self.params['stiffener_web_height'] = np.array([1.0, 1.0]) self.params['stiffener_flange_width'] = np.array([2.0, 2.0]) self.params['stiffener_spacing'] = np.array([0.1, 0.1]) self.params['Hs'] = 5.0 self.params['max_draft'] = 70.0 self.geom = column.ColumnGeometry(NSEC, NPTS)
def setUp(self): self.params = {} self.unknowns = {} self.resid = None self.params['z_full_in'] = np.linspace(0, 50.0, NPTS) self.params['z_param_in'] = np.array([0.0, 20.0, 50.0]) self.params['section_height'] = np.array([20.0, 30.0]) self.params['section_center_of_mass'], _ = nodal2sectional( self.params['z_full_in']) self.params['freeboard'] = 15.0 self.params['water_depth'] = 100.0 self.params['stiffener_web_thickness'] = np.array([0.5, 0.5]) self.params['stiffener_flange_thickness'] = np.array([0.3, 0.3]) self.params['stiffener_web_height'] = np.array([1.0, 1.0]) self.params['stiffener_flange_width'] = np.array([2.0, 2.0]) self.params['stiffener_spacing'] = np.array([0.1, 0.1]) self.params['Hs'] = 5.0 self.params['max_draft'] = 70.0 self.geom = column.ColumnGeometry(NSEC, NPTS)
def setUp(self): self.params = {} self.unknowns = {} self.resid = None # Use the API 2U Appendix B as a big unit test! ksi_to_si = 6894757.29317831 lbperft3_to_si = 16.0185 ft_to_si = 0.3048 in_to_si = ft_to_si / 12.0 kip_to_si = 4.4482216 * 1e3 onepts = np.ones((NPTS, )) onesec = np.ones((NPTS - 1, )) #onesec0 = np.ones((NSEC,)) self.params['d_full'] = 600 * onepts * in_to_si self.params['t_full'] = 0.75 * onesec * in_to_si self.params['t_web'] = 5. / 8. * onesec * in_to_si self.params['h_web'] = 14.0 * onesec * in_to_si self.params['t_flange'] = 1.0 * onesec * in_to_si self.params['w_flange'] = 10.0 * onesec * in_to_si self.params['L_stiffener'] = 5.0 * onesec * ft_to_si #self.params['section_height'] = 50.0 * onesec0 * ft_to_si self.params['pressure'] = (64.0 * lbperft3_to_si) * g * ( 60 * ft_to_si) * onepts self.params['E'] = 29e3 * ksi_to_si self.params['nu'] = 0.3 self.params['yield_stress'] = 50 * ksi_to_si self.params['wave_height'] = 0.0 # gives only static pressure self.params['stack_mass_in'] = 9000 * kip_to_si / g self.params['section_mass'] = 0.0 * np.ones((NPTS - 1, )) self.params['loading'] = 'radial' self.params['z_full'] = np.linspace(0, 1, NPTS) self.params['z_section'], _ = nodal2sectional(self.params['z_full']) self.params['z_param'] = np.linspace(0, 1, NSEC + 1) self.params['gamma_f'] = 1.0 self.params['gamma_b'] = 1.0 self.buckle = column.ColumnBuckling(NSEC, NPTS)
def setUp(self): self.params = {} self.unknowns = {} self.resid = None # Use the API 2U Appendix B as a big unit test! ksi_to_si = 6894757.29317831 lbperft3_to_si = 16.0185 ft_to_si = 0.3048 in_to_si = ft_to_si / 12.0 kip_to_si = 4.4482216 * 1e3 onepts = np.ones((NPTS,)) onesec = np.ones((NPTS-1,)) #onesec0 = np.ones((NSEC,)) self.params['d_full'] = 600 * onepts * in_to_si self.params['t_full'] = 0.75 * onesec * in_to_si self.params['t_web'] = 5./8. * onesec * in_to_si self.params['h_web'] = 14.0 * onesec * in_to_si self.params['t_flange'] = 1.0 * onesec * in_to_si self.params['w_flange'] = 10.0 * onesec * in_to_si self.params['L_stiffener'] = 5.0 * onesec * ft_to_si #self.params['section_height'] = 50.0 * onesec0 * ft_to_si self.params['pressure'] = (64.0*lbperft3_to_si) * g * (60*ft_to_si) * onepts self.params['E'] = 29e3 * ksi_to_si self.params['nu'] = 0.3 self.params['yield_stress'] = 50 * ksi_to_si self.params['wave_height'] = 0.0 # gives only static pressure self.params['stack_mass_in'] = 9000 * kip_to_si/g self.params['section_mass'] = 0.0 * np.ones((NPTS-1,)) self.params['loading'] = 'radial' self.params['z_full'] = np.linspace(0, 1, NPTS) self.params['z_section'],_ = nodal2sectional( self.params['z_full'] ) self.params['z_param'] = np.linspace(0, 1, NSEC+1) self.params['gamma_f'] = 1.0 self.params['gamma_b'] = 1.0 self.buckle = column.ColumnBuckling(NSEC, NPTS)
def solve_nonlinear(self, params, unknowns, resids): # Unpack variables R_od, _ = nodal2sectional(params['d_full']) # at section nodes R_od *= 0.5 t_wall, _ = nodal2sectional(params['t_full']) # at section nodes z_full = params['z_full'] # at section nodes z_param = params['z_param'] z_section, _ = nodal2sectional(params['z_full']) h_section = np.diff(z_full) t_web = sectionalInterp(z_section, z_param, params['stiffener_web_thickness']) t_flange = sectionalInterp(z_section, z_param, params['stiffener_flange_thickness']) h_web = sectionalInterp(z_section, z_param, params['stiffener_web_height']) w_flange = sectionalInterp(z_section, z_param, params['stiffener_flange_width']) L_stiffener = sectionalInterp(z_section, z_param, params['stiffener_spacing']) rho = params['rho'] # Outer and inner radius of web by section R_wo = R_od - t_wall R_wi = R_wo - h_web # Outer and inner radius of flange by section R_fo = R_wi R_fi = R_fo - t_flange # Material volumes by section V_web = np.pi * (R_wo**2 - R_wi**2) * t_web V_flange = np.pi * (R_fo**2 - R_fi**2) * w_flange # Ring mass by volume by section # Include fudge factor for design features not captured in this simple approach m_web = params['ring_mass_factor'] * rho * V_web m_flange = params['ring_mass_factor'] * rho * V_flange m_ring = m_web + m_flange n_stiff = np.zeros(z_section.shape, dtype=np.int_) # Compute moments of inertia for stiffeners (lumped by section for simplicity) at keel I_web = I_tube(R_wi, R_wo, t_web, m_web) I_flange = I_tube(R_fi, R_fo, w_flange, m_flange) I_ring = I_web + I_flange I_keel = np.zeros((3, 3)) # Now march up the column, adding stiffeners at correct spacing until we are done z_stiff = [] isection = 0 epsilon = 1e-6 while True: if len(z_stiff) == 0: z_march = np.minimum(z_full[isection + 1], z_full[0] + 0.5 * L_stiffener[isection]) + epsilon else: z_march = np.minimum(z_full[isection + 1], z_stiff[-1] + L_stiffener[isection]) + epsilon if z_march >= z_full[-1]: break isection = np.searchsorted(z_full, z_march) - 1 if len(z_stiff) == 0: add_stiff = (z_march - z_full[0]) >= 0.5 * L_stiffener[isection] else: add_stiff = (z_march - z_stiff[-1]) >= L_stiffener[isection] if add_stiff: z_stiff.append(z_march) n_stiff[isection] += 1 R = np.array([0.0, 0.0, (z_march - z_full[0])]) Icg = assembleI(I_ring[isection, :]) I_keel += Icg + m_ring[isection] * (np.dot(R, R) * np.eye(3) - np.outer(R, R)) # Number of stiffener rings per section (height of section divided by spacing) unknowns['stiffener_mass'] = n_stiff * m_ring # Find total number of stiffeners in each original section npts_per = z_section.size / (z_param.size - 1) n_stiff_sec = np.zeros(z_param.size - 1) for k in range(npts_per): n_stiff_sec += n_stiff[k::npts_per] unknowns['number_of_stiffeners'] = n_stiff_sec # Store results unknowns['stiffener_I_keel'] = unassembleI(I_keel) # Create some constraints for reasonable stiffener designs for an optimizer unknowns['flange_spacing_ratio'] = w_flange / (0.5 * L_stiffener) unknowns['stiffener_radius_ratio'] = (h_web + t_flange + t_wall) / R_od
prob['pre1.rna_F'] = np.array([Fx1, Fy1, Fz1]) prob['pre1.rna_M'] = np.array([Mxx1, Myy1, Mzz1]) # # --------------- # # --- loading case 2: max Wind Speed --- prob['wind2.Uref'] = wind_Uref2 prob['pre2.rna_F'] = np.array([Fx2, Fy2, Fz2]) prob['pre2.rna_M' ] = np.array([Mxx2, Myy2, Mzz2]) # # --- run --- prob.run() z,_ = nodal2sectional(prob['z_full']) print('zs=', z) print('ds=', prob['d_full']) print('ts=', prob['t_full']) print('mass (kg) =', prob['tower_mass']) print('cg (m) =', prob['tower_center_of_mass']) print('weldability =', prob['weldability']) print('manufacturability =', prob['manufacturability']) print('\nwind: ', prob['wind1.Uref']) print('f1 (Hz) =', prob['tower1.f1']) print('top_deflection1 (m) =', prob['post1.top_deflection']) print('stress1 =', prob['post1.stress']) print('GL buckling =', prob['post1.global_buckling']) print('Shell buckling =', prob['post1.shell_buckling']) print('damage =', prob['post1.damage'])
def testNodal2Sectional(self): x,dx = util.nodal2sectional(np.array([8.0, 10.0, 12.0])) npt.assert_equal(x, np.array([9.0, 11.0])) npt.assert_equal(dx, np.array([[0.5, 0.5, 0.0],[0.0, 0.5, 0.5]]))
def setUp(self): self.params = {} self.unknowns = {} self.resid = None # For Geometry call self.params['z_full_in'] = np.linspace(0, 50.0, NPTS) self.params['z_param_in'] = np.array([0.0, 20.0, 50.0]) self.params['section_height'] = np.array([20.0, 30.0]) self.params['section_center_of_mass'], _ = nodal2sectional( self.params['z_full_in']) self.params['freeboard'] = 15.0 self.params['fairlead'] = 10.0 self.params['water_depth'] = 100.0 self.params['Hs'] = 5.0 self.params['max_draft'] = 70.0 self.params['t_full'] = 0.5 * secones self.params['d_full'] = 2 * 10.0 * myones self.params['stack_mass_in'] = 0.0 self.params['shell_I_keel'] = 1e5 * np.array( [1.0, 1.0, 1.0, 0.0, 0.0, 0.0]) self.params['stiffener_I_keel'] = 2e5 * np.array( [1.0, 1.0, 1.0, 0.0, 0.0, 0.0]) self.params['bulkhead_I_keel'] = 3e5 * np.array( [1.0, 1.0, 1.0, 0.0, 0.0, 0.0]) self.params['buoyancy_tank_I_keel'] = 5e6 * np.array( [1.0, 1.0, 1.0, 0.0, 0.0, 0.0]) self.params['ballast_I_keel'] = 2e3 * np.array( [1.0, 1.0, 1.0, 0.0, 0.0, 0.0]) self.params['buoyancy_tank_diameter'] = 15.0 self.params['water_density'] = 1e3 self.params['bulkhead_mass'] = 10.0 * myones self.params['shell_mass'] = 500.0 * np.ones(NPTS - 1) self.params['stiffener_mass'] = 100.0 * np.ones(NPTS - 1) self.params['ballast_mass'] = 20.0 * np.ones(NPTS - 1) self.params['ballast_z_cg'] = -35.0 self.params['buoyancy_tank_mass'] = 20.0 self.params['buoyancy_tank_cg'] = -15.0 self.params['buoyancy_tank_location'] = 0.3 self.params['buoyancy_tank_displacement'] = 300.0 self.params['column_mass_factor'] = 1.1 self.params['outfitting_mass_fraction'] = 0.05 self.params['shell_cost'] = 1.0 self.params['stiffener_cost'] = 2.0 self.params['bulkhead_cost'] = 3.0 self.params['buoyancy_tank_cost'] = 4.0 self.params['ballast_cost'] = 5.0 self.params['mooring_mass'] = 50.0 self.params['mooring_vertical_load'] = 25.0 self.params['mooring_restoring_force'] = 1e5 self.params['mooring_cost'] = 1e4 self.params['outfitting_cost_rate'] = 1.0 self.params['stiffener_web_thickness'] = np.array([0.5, 0.5]) self.params['stiffener_flange_thickness'] = np.array([0.3, 0.3]) self.params['stiffener_web_height'] = np.array([1.0, 1.0]) self.params['stiffener_flange_width'] = np.array([2.0, 2.0]) self.params['stiffener_spacing'] = np.array([0.1, 0.1]) self.geom = column.ColumnGeometry(NSEC, NPTS) self.set_geometry() self.mycolumn = column.ColumnProperties(NPTS)
def setUp(self): self.params = {} self.unknowns = {} self.resid = None # For Geometry call self.params['z_full_in'] = np.linspace(0, 50.0, NPTS) self.params['z_param_in'] = np.array([0.0, 20.0, 50.0]) self.params['section_height'] = np.array([20.0, 30.0]) self.params['section_center_of_mass'],_ = nodal2sectional( self.params['z_full_in'] ) self.params['freeboard'] = 15.0 self.params['fairlead'] = 10.0 self.params['water_depth'] = 100.0 self.params['Hs'] = 5.0 self.params['max_draft'] = 70.0 self.params['t_full'] = 0.5*secones self.params['d_full'] = 2*10.0*myones self.params['stack_mass_in'] = 0.0 self.params['shell_I_keel'] = 1e5 * np.array([1.0, 1.0, 1.0, 0.0, 0.0, 0.0]) self.params['stiffener_I_keel'] = 2e5 * np.array([1.0, 1.0, 1.0, 0.0, 0.0, 0.0]) self.params['bulkhead_I_keel'] = 3e5 * np.array([1.0, 1.0, 1.0, 0.0, 0.0, 0.0]) self.params['buoyancy_tank_I_keel'] = 5e6 * np.array([1.0, 1.0, 1.0, 0.0, 0.0, 0.0]) self.params['ballast_I_keel'] = 2e3 * np.array([1.0, 1.0, 1.0, 0.0, 0.0, 0.0]) self.params['buoyancy_tank_diameter'] = 15.0 self.params['water_density'] = 1e3 self.params['bulkhead_mass'] = 10.0*myones self.params['shell_mass'] = 500.0*np.ones(NPTS-1) self.params['stiffener_mass'] = 100.0*np.ones(NPTS-1) self.params['ballast_mass'] = 20.0*np.ones(NPTS-1) self.params['ballast_z_cg'] = -35.0 self.params['buoyancy_tank_mass'] = 20.0 self.params['buoyancy_tank_cg'] = -15.0 self.params['buoyancy_tank_location'] = 0.3 self.params['buoyancy_tank_displacement'] = 300.0 self.params['column_mass_factor'] = 1.1 self.params['outfitting_mass_fraction'] = 0.05 self.params['shell_cost'] = 1.0 self.params['stiffener_cost'] = 2.0 self.params['bulkhead_cost'] = 3.0 self.params['buoyancy_tank_cost'] = 4.0 self.params['ballast_cost'] = 5.0 self.params['mooring_mass'] = 50.0 self.params['mooring_vertical_load'] = 25.0 self.params['mooring_restoring_force'] = 1e5 self.params['mooring_cost'] = 1e4 self.params['outfitting_cost_rate'] = 1.0 self.params['stiffener_web_thickness'] = np.array([0.5, 0.5]) self.params['stiffener_flange_thickness'] = np.array([0.3, 0.3]) self.params['stiffener_web_height'] = np.array([1.0, 1.0]) self.params['stiffener_flange_width'] = np.array([2.0, 2.0]) self.params['stiffener_spacing'] = np.array([0.1, 0.1]) self.geom = column.ColumnGeometry(NSEC, NPTS) self.set_geometry() self.mycolumn = column.ColumnProperties(NPTS)
def solve_nonlinear(self, params, unknowns, resids): # ------- node data ---------------- z = params['z'] n = len(z) node = np.arange(1, n+1) x = np.zeros(n) y = np.zeros(n) r = np.zeros(n) nodes = frame3dd.NodeData(node, x, y, z, r) # ----------------------------------- # ------ reaction data ------------ # rigid base node = params['kidx'] + np.ones(len(params['kidx']), dtype=np.int_) # add one because 0-based index but 1-based node numbering rigid = float('inf') reactions = frame3dd.ReactionData(node, params['kx'], params['ky'], params['kz'], params['ktx'], params['kty'], params['ktz'], rigid) # ----------------------------------- # ------ frame element data ------------ element = np.arange(1, n) N1 = np.arange(1, n) N2 = np.arange(2, n+1) roll = np.zeros(n-1) # average across element b.c. frame3dd uses constant section elements # TODO: Use nodal2sectional Az = params['Az'] Asx = params['Asx'] Asy = params['Asy'] Jz = params['Jz'] Ixx = params['Ixx'] Iyy = params['Iyy'] E = params['E']*np.ones(Az.shape) G = params['G']*np.ones(Az.shape) rho = params['rho']*np.ones(Az.shape) elements = frame3dd.ElementData(element, N1, N2, Az, Asx, Asy, Jz, Ixx, Iyy, E, G, roll, rho) # ----------------------------------- # ------ options ------------ options = frame3dd.Options(params['shear'], params['geom'], params['dx']) # ----------------------------------- # initialize frame3dd object cylinder = frame3dd.Frame(nodes, reactions, elements, options) # ------ add extra mass ------------ # extra node inertia data N = params['midx'] + np.ones(len(params['midx']), dtype=np.int_) cylinder.changeExtraNodeMass(N, params['m'], params['mIxx'], params['mIyy'], params['mIzz'], params['mIxy'], params['mIxz'], params['mIyz'], params['mrhox'], params['mrhoy'], params['mrhoz'], params['addGravityLoadForExtraMass']) # ------------------------------------ # ------- enable dynamic analysis ---------- cylinder.enableDynamics(params['nM'], params['Mmethod'], params['lump'], params['tol'], params['shift']) # ---------------------------- # ------ static load case 1 ------------ # gravity in the X, Y, Z, directions (global) gx = 0.0 gy = 0.0 gz = -gravity load = frame3dd.StaticLoadCase(gx, gy, gz) # point loads nF = params['plidx'] + np.ones(len(params['plidx']), dtype=int) load.changePointLoads(nF, params['Fx'], params['Fy'], params['Fz'], params['Mxx'], params['Myy'], params['Mzz']) # distributed loads Px, Py, Pz = params['Pz'], params['Py'], -params['Px'] # switch to local c.s. z = params['z'] # trapezoidally distributed loads EL = np.arange(1, n) xx1 = xy1 = xz1 = np.zeros(n-1) xx2 = xy2 = xz2 = np.diff(z) - 1e-6 # subtract small number b.c. of precision wx1 = Px[:-1] wx2 = Px[1:] wy1 = Py[:-1] wy2 = Py[1:] wz1 = Pz[:-1] wz2 = Pz[1:] load.changeTrapezoidalLoads(EL, xx1, xx2, wx1, wx2, xy1, xy2, wy1, wy2, xz1, xz2, wz1, wz2) cylinder.addLoadCase(load) # Debugging #cylinder.write('temp.3dd') # ----------------------------------- # run the analysis displacements, forces, reactions, internalForces, mass, modal = cylinder.run() iCase = 0 # mass unknowns['mass'] = mass.struct_mass # natural frequncies unknowns['f1'] = modal.freq[0] unknowns['f2'] = modal.freq[1] # deflections due to loading (from cylinder top and wind/wave loads) unknowns['top_deflection'] = displacements.dx[iCase, n-1] # in yaw-aligned direction # shear and bending, one per element (convert from local to global c.s.) Fz = forces.Nx[iCase, 1::2] Vy = forces.Vy[iCase, 1::2] Vx = -forces.Vz[iCase, 1::2] Mzz = forces.Txx[iCase, 1::2] Myy = forces.Myy[iCase, 1::2] Mxx = -forces.Mzz[iCase, 1::2] # Record total forces and moments unknowns['base_F'] = -1.0 * np.array([reactions.Fx.sum(), reactions.Fy.sum(), reactions.Fz.sum()]) unknowns['base_M'] = -1.0 * np.array([reactions.Mxx.sum(), reactions.Myy.sum(), reactions.Mzz.sum()]) unknowns['Fz_out'] = Fz unknowns['Vx_out'] = Vx unknowns['Vy_out'] = Vy unknowns['Mxx_out'] = Mxx unknowns['Myy_out'] = Myy unknowns['Mzz_out'] = Mzz # axial and shear stress d,_ = nodal2sectional(params['d']) qdyn,_ = nodal2sectional(params['qdyn']) ##R = self.d/2.0 ##x_stress = R*np.cos(self.theta_stress) ##y_stress = R*np.sin(self.theta_stress) ##axial_stress = Fz/self.Az + Mxx/self.Ixx*y_stress - Myy/self.Iyy*x_stress # V = Vy*x_stress/R - Vx*y_stress/R # shear stress orthogonal to direction x,y # shear_stress = 2. * V / self.Az # coefficient of 2 for a hollow circular section, but should be conservative for other shapes unknowns['axial_stress'] = Fz/params['Az'] - np.sqrt(Mxx**2+Myy**2)/params['Iyy']*d/2.0 #More conservative, just use the tilted bending and add total max shear as well at the same point, if you do not like it go back to the previous lines unknowns['shear_stress'] = 2. * np.sqrt(Vx**2+Vy**2) / params['Az'] # coefficient of 2 for a hollow circular section, but should be conservative for other shapes # hoop_stress (Eurocode method) L_reinforced = params['L_reinforced'] * np.ones(Fz.shape) unknowns['hoop_stress_euro'] = hoopStressEurocode(params['z'], d, params['t'], L_reinforced, qdyn) # Simpler hoop stress used in API calculations unknowns['hoop_stress'] = hoopStress(d, params['t'], qdyn)
def testNodal2Sectional(self): x, dx = util.nodal2sectional(np.array([8.0, 10.0, 12.0])) npt.assert_equal(x, np.array([9.0, 11.0])) npt.assert_equal(dx, np.array([[0.5, 0.5, 0.0], [0.0, 0.5, 0.5]]))
def solve_nonlinear(self, params, unknowns, resids): # ------- node data ---------------- z = params['z'] n = len(z) node = np.arange(1, n + 1) x = np.zeros(n) y = np.zeros(n) r = np.zeros(n) nodes = frame3dd.NodeData(node, x, y, z, r) # ----------------------------------- # ------ reaction data ------------ # rigid base node = params['kidx'] + np.ones( len(params['kidx']), dtype=np.int_ ) # add one because 0-based index but 1-based node numbering rigid = float('inf') reactions = frame3dd.ReactionData(node, params['kx'], params['ky'], params['kz'], params['ktx'], params['kty'], params['ktz'], rigid) # ----------------------------------- # ------ frame element data ------------ element = np.arange(1, n) N1 = np.arange(1, n) N2 = np.arange(2, n + 1) roll = np.zeros(n - 1) # average across element b.c. frame3dd uses constant section elements # TODO: Use nodal2sectional Az = params['Az'] Asx = params['Asx'] Asy = params['Asy'] Jz = params['Jz'] Ixx = params['Ixx'] Iyy = params['Iyy'] E = params['E'] * np.ones(Az.shape) G = params['G'] * np.ones(Az.shape) rho = params['rho'] * np.ones(Az.shape) elements = frame3dd.ElementData(element, N1, N2, Az, Asx, Asy, Jz, Ixx, Iyy, E, G, roll, rho) # ----------------------------------- # ------ options ------------ options = frame3dd.Options(params['shear'], params['geom'], params['dx']) # ----------------------------------- # initialize frame3dd object cylinder = frame3dd.Frame(nodes, reactions, elements, options) # ------ add extra mass ------------ # extra node inertia data N = params['midx'] + np.ones(len(params['midx']), dtype=np.int_) cylinder.changeExtraNodeMass(N, params['m'], params['mIxx'], params['mIyy'], params['mIzz'], params['mIxy'], params['mIxz'], params['mIyz'], params['mrhox'], params['mrhoy'], params['mrhoz'], params['addGravityLoadForExtraMass']) # ------------------------------------ # ------- enable dynamic analysis ---------- cylinder.enableDynamics(params['nM'], params['Mmethod'], params['lump'], params['tol'], params['shift']) # ---------------------------- # ------ static load case 1 ------------ # gravity in the X, Y, Z, directions (global) gx = 0.0 gy = 0.0 gz = -gravity load = frame3dd.StaticLoadCase(gx, gy, gz) # point loads nF = params['plidx'] + np.ones(len(params['plidx']), dtype=int) load.changePointLoads(nF, params['Fx'], params['Fy'], params['Fz'], params['Mxx'], params['Myy'], params['Mzz']) # distributed loads Px, Py, Pz = params['Pz'], params['Py'], -params[ 'Px'] # switch to local c.s. z = params['z'] # trapezoidally distributed loads EL = np.arange(1, n) xx1 = xy1 = xz1 = np.zeros(n - 1) xx2 = xy2 = xz2 = np.diff( z) - 1e-6 # subtract small number b.c. of precision wx1 = Px[:-1] wx2 = Px[1:] wy1 = Py[:-1] wy2 = Py[1:] wz1 = Pz[:-1] wz2 = Pz[1:] load.changeTrapezoidalLoads(EL, xx1, xx2, wx1, wx2, xy1, xy2, wy1, wy2, xz1, xz2, wz1, wz2) cylinder.addLoadCase(load) # Debugging #cylinder.write('temp.3dd') # ----------------------------------- # run the analysis displacements, forces, reactions, internalForces, mass, modal = cylinder.run( ) iCase = 0 # mass unknowns['mass'] = mass.struct_mass # natural frequncies unknowns['f1'] = modal.freq[0] unknowns['f2'] = modal.freq[1] # deflections due to loading (from cylinder top and wind/wave loads) unknowns['top_deflection'] = displacements.dx[ iCase, n - 1] # in yaw-aligned direction # shear and bending, one per element (convert from local to global c.s.) Fz = forces.Nx[iCase, 1::2] Vy = forces.Vy[iCase, 1::2] Vx = -forces.Vz[iCase, 1::2] Mzz = forces.Txx[iCase, 1::2] Myy = forces.Myy[iCase, 1::2] Mxx = -forces.Mzz[iCase, 1::2] # Record total forces and moments unknowns['base_F'] = -1.0 * np.array( [reactions.Fx.sum(), reactions.Fy.sum(), reactions.Fz.sum()]) unknowns['base_M'] = -1.0 * np.array( [reactions.Mxx.sum(), reactions.Myy.sum(), reactions.Mzz.sum()]) unknowns['Fz_out'] = Fz unknowns['Vx_out'] = Vx unknowns['Vy_out'] = Vy unknowns['Mxx_out'] = Mxx unknowns['Myy_out'] = Myy unknowns['Mzz_out'] = Mzz # axial and shear stress d, _ = nodal2sectional(params['d']) qdyn, _ = nodal2sectional(params['qdyn']) ##R = self.d/2.0 ##x_stress = R*np.cos(self.theta_stress) ##y_stress = R*np.sin(self.theta_stress) ##axial_stress = Fz/self.Az + Mxx/self.Ixx*y_stress - Myy/self.Iyy*x_stress # V = Vy*x_stress/R - Vx*y_stress/R # shear stress orthogonal to direction x,y # shear_stress = 2. * V / self.Az # coefficient of 2 for a hollow circular section, but should be conservative for other shapes unknowns['axial_stress'] = Fz / params['Az'] - np.sqrt( Mxx**2 + Myy**2 ) / params[ 'Iyy'] * d / 2.0 #More conservative, just use the tilted bending and add total max shear as well at the same point, if you do not like it go back to the previous lines unknowns['shear_stress'] = 2. * np.sqrt(Vx**2 + Vy**2) / params[ 'Az'] # coefficient of 2 for a hollow circular section, but should be conservative for other shapes # hoop_stress (Eurocode method) L_reinforced = params['L_reinforced'] * np.ones(Fz.shape) unknowns['hoop_stress_euro'] = hoopStressEurocode( params['z'], d, params['t'], L_reinforced, qdyn) # Simpler hoop stress used in API calculations unknowns['hoop_stress'] = hoopStress(d, params['t'], qdyn)