def compute(self, inputs, outputs, discrete_inputs, discrete_outputs): # initialization point # if discrete_inputs['blade_in_overwrite'] != {}: # blade = copy.deepcopy(discrete_inputs['blade_in_overwrite']) # else: blade = copy.deepcopy(self.refBlade) NINPUT = len(blade['ctrl_pts']['r_in']) # Set inputs to update blade geometry Rhub = inputs['hubFraction'] * inputs['bladeLength'] Rtip = Rhub + inputs['bladeLength'] outputs['Rhub'] = Rhub outputs['Rtip'] = Rtip r_in = blade['ctrl_pts']['r_in'] outputs['r_in'] = Rhub + (Rtip - Rhub) * np.array(r_in) blade['ctrl_pts']['bladeLength'] = inputs['bladeLength'] blade['ctrl_pts']['r_in'] = r_in blade['ctrl_pts']['chord_in'] = inputs['chord_in'] blade['ctrl_pts']['theta_in'] = inputs['theta_in'] blade['ctrl_pts']['precurve_in'] = inputs['precurve_in'] blade['ctrl_pts']['presweep_in'] = inputs['presweep_in'] blade['ctrl_pts']['sparT_in'] = inputs['sparT_in'] blade['ctrl_pts']['teT_in'] = inputs['teT_in'] blade['ctrl_pts']['r_max_chord'] = inputs['r_max_chord'] #check that airfoil positions are increasing correct_af_position = False airfoil_position = copy.deepcopy(inputs['airfoil_position']).tolist() for i in reversed(range(1, len(airfoil_position))): if airfoil_position[i] <= airfoil_position[i - 1]: airfoil_position[i - 1] = airfoil_position[i] - 0.001 correct_af_position = True if correct_af_position: blade['outer_shape_bem']['airfoil_position'][ 'grid'] = airfoil_position warning_corrected_airfoil_position = "Airfoil spanwise positions must be increasing. Changed from: %s to: %s" % ( inputs['airfoil_position'].tolist(), airfoil_position) warnings.warn(warning_corrected_airfoil_position) else: blade['outer_shape_bem']['airfoil_position']['grid'] = inputs[ 'airfoil_position'].tolist() # Update refBlade = ReferenceBlade() refBlade.verbose = False refBlade.NINPUT = len(outputs['r_in']) refBlade.NPTS = len(blade['pf']['s']) refBlade.analysis_level = blade['analysis_level'] if blade['analysis_level'] < 3: refBlade.spar_var = blade['precomp']['spar_var'] refBlade.te_var = blade['precomp']['te_var'] blade_out = refBlade.update(blade) # Get geometric outputs outputs['hub_diameter'] = 2.0 * Rhub outputs['r'] = Rhub + (Rtip - Rhub) * np.array(blade_out['pf']['s']) outputs['diameter'] = 2.0 * outputs['r'][-1] outputs['chord'] = blade_out['pf']['chord'] outputs['max_chord'] = max(blade_out['pf']['chord']) outputs['theta'] = blade_out['pf']['theta'] outputs['precurve'] = blade_out['pf']['precurve'] outputs['presweep'] = blade_out['pf']['presweep'] outputs['rthick'] = blade_out['pf']['rthick'] outputs['le_location'] = blade_out['pf']['p_le'] # airfoils = blade_out['airfoils'] outputs['airfoils_cl'] = blade_out['airfoils_cl'] outputs['airfoils_cd'] = blade_out['airfoils_cd'] outputs['airfoils_cm'] = blade_out['airfoils_cm'] outputs['airfoils_aoa'] = blade_out['airfoils_aoa'] outputs['airfoils_Re'] = blade_out['airfoils_Re'] upperCS = blade_out['precomp']['upperCS'] lowerCS = blade_out['precomp']['lowerCS'] websCS = blade_out['precomp']['websCS'] profile = blade_out['precomp']['profile'] materials = blade_out['precomp']['materials'] for i in range(len(profile)): outputs['airfoils_coord_x'][:, i] = blade_out['profile'][:, 0, i] outputs['airfoils_coord_y'][:, i] = blade_out['profile'][:, 1, i] # Assumptions: # - if the composite layer is divided into multiple regions (i.e. if the spar cap is split into 3 regions due to the web locations), # the middle region is selected with int(n_reg/2), note for an even number of regions, this rounds up sector_idx_strain_spar_ss = blade_out['precomp'][ 'sector_idx_strain_spar_ss'] sector_idx_strain_spar_ps = blade_out['precomp'][ 'sector_idx_strain_spar_ps'] sector_idx_strain_te_ss = blade_out['precomp'][ 'sector_idx_strain_te_ss'] sector_idx_strain_te_ps = blade_out['precomp'][ 'sector_idx_strain_te_ps'] # Get Beam Properties beam = PreComp(outputs['r'], outputs['chord'], outputs['theta'], outputs['le_location'], outputs['precurve'], outputs['presweep'], profile, materials, upperCS, lowerCS, websCS, sector_idx_strain_spar_ps, sector_idx_strain_spar_ss, sector_idx_strain_te_ps, sector_idx_strain_te_ss) EIxx, EIyy, GJ, EA, EIxy, x_ec, y_ec, rhoA, rhoJ, Tw_iner, flap_iner, edge_iner = beam.sectionProperties( ) outputs['eps_crit_spar'] = beam.panelBucklingStrain( sector_idx_strain_spar_ss) outputs['eps_crit_te'] = beam.panelBucklingStrain( sector_idx_strain_te_ss) xu_strain_spar, xl_strain_spar, yu_strain_spar, yl_strain_spar = beam.criticalStrainLocations( sector_idx_strain_spar_ss, sector_idx_strain_spar_ps) xu_strain_te, xl_strain_te, yu_strain_te, yl_strain_te = beam.criticalStrainLocations( sector_idx_strain_te_ss, sector_idx_strain_te_ps) outputs['z'] = outputs['r'] outputs['EIxx'] = EIxx outputs['EIyy'] = EIyy outputs['GJ'] = GJ outputs['EA'] = EA outputs['EIxy'] = EIxy outputs['x_ec'] = x_ec outputs['y_ec'] = y_ec outputs['rhoA'] = rhoA outputs['rhoJ'] = rhoJ outputs['Tw_iner'] = Tw_iner outputs['flap_iner'] = flap_iner outputs['edge_iner'] = edge_iner outputs['xu_strain_spar'] = xu_strain_spar outputs['xl_strain_spar'] = xl_strain_spar outputs['yu_strain_spar'] = yu_strain_spar outputs['yl_strain_spar'] = yl_strain_spar outputs['xu_strain_te'] = xu_strain_te outputs['xl_strain_te'] = xl_strain_te outputs['yu_strain_te'] = yu_strain_te outputs['yl_strain_te'] = yl_strain_te # Blade cost model bcm = blade_cost_model( options=self.options ) # <------------- options, import blade cost model bcm.name = blade_out['config']['name'] bcm.materials = materials bcm.upperCS = upperCS bcm.lowerCS = lowerCS bcm.websCS = websCS bcm.profile = profile bcm.chord = outputs['chord'] bcm.r = (outputs['r'] - outputs['Rhub']) / ( outputs['Rtip'] - outputs['Rhub']) * float(inputs['bladeLength']) bcm.bladeLength = float(inputs['bladeLength']) bcm.le_location = outputs['le_location'] blade_cost, blade_mass = bcm.execute_blade_cost_model() outputs['total_blade_cost'] = blade_cost outputs['total_blade_mass'] = blade_mass # discrete_outputs['blade_out'] = blade_out outputs['sparT_in_out'] = inputs['sparT_in']
def compute(self, inputs, outputs, discrete_inputs, discrete_outputs): ############################## def region_stacking(i, idx, start_nd_arc, end_nd_arc, layer_name, layer_thickness, fiber_orientation, layer_mat, material_dict, materials, region_loc): # Recieve start and end of composite sections chordwise, find which composites layers are in each # chordwise regions, generate the precomp composite class instance # error handling to makes sure there were no numeric errors causing values very close too, but not exactly, 0 or 1 start_nd_arc = [ 0. if start_nd_arci != 0. and np.isclose(start_nd_arci, 0.) else start_nd_arci for start_nd_arci in start_nd_arc ] end_nd_arc = [ 0. if end_nd_arci != 0. and np.isclose(end_nd_arci, 0.) else end_nd_arci for end_nd_arci in end_nd_arc ] start_nd_arc = [ 1. if start_nd_arci != 1. and np.isclose(start_nd_arci, 1.) else start_nd_arci for start_nd_arci in start_nd_arc ] end_nd_arc = [ 1. if end_nd_arci != 1. and np.isclose(end_nd_arci, 1.) else end_nd_arci for end_nd_arci in end_nd_arc ] # region end points dp = sorted(list(set(start_nd_arc + end_nd_arc))) #initialize n_plies = [] thk = [] theta = [] mat_idx = [] # loop through division points, find what layers make up the stack between those bounds for i_reg, (dp0, dp1) in enumerate(zip(dp[0:-1], dp[1:])): n_pliesi = [] thki = [] thetai = [] mati = [] for i_sec, start_nd_arci, end_nd_arci in zip( idx, start_nd_arc, end_nd_arc): name = layer_name[i_sec] if start_nd_arci <= dp0 and end_nd_arci >= dp1: if name in region_loc.keys(): if region_loc[name][i] == None: region_loc[name][i] = [i_reg] else: region_loc[name][i].append(i_reg) n_pliesi.append(1.) thki.append(layer_thickness[i_sec]) if fiber_orientation[i_sec] == None: thetai.append(0.) else: thetai.append(fiber_orientation[i_sec]) mati.append(material_dict[layer_mat[i_sec]]) n_plies.append(np.array(n_pliesi)) thk.append(np.array(thki)) theta.append(np.array(thetai)) mat_idx.append(np.array(mati)) # print('----------------------') # print('dp', dp) # print('n_plies', n_plies) # print('thk', thk) # print('theta', theta) # print('mat_idx', mat_idx) # print('materials', materials) sec = CompositeSection(dp, n_plies, thk, theta, mat_idx, materials) return sec, region_loc ############################## def web_stacking(i, web_idx, web_start_nd_arc, web_end_nd_arc, layer_thickness, fiber_orientation, layer_mat, material_dict, materials, flatback, upperCSi): dp = [] n_plies = [] thk = [] theta = [] mat_idx = [] if len(web_idx) > 0: dp = np.mean( (np.abs(web_start_nd_arc), np.abs(web_start_nd_arc)), axis=0).tolist() dp_all = [[-1. * start_nd_arci, -1. * end_nd_arci] for start_nd_arci, end_nd_arci in zip( web_start_nd_arc, web_end_nd_arc)] web_dp, web_ids = np.unique(dp_all, axis=0, return_inverse=True) for webi in np.unique(web_ids): # store variable values (thickness, orientation, material) for layers that make up each web, based on the mapping array web_ids n_pliesi = [ 1. for i_reg, web_idi in zip(web_idx, web_ids) if web_idi == webi ] thki = [ layer_thickness[i_reg] for i_reg, web_idi in zip(web_idx, web_ids) if web_idi == webi ] thetai = [ fiber_orientation[i_reg] for i_reg, web_idi in zip(web_idx, web_ids) if web_idi == webi ] thetai = [ 0. if theta_ij == None else theta_ij for theta_ij in thetai ] mati = [ material_dict[layer_mat[i_reg]] for i_reg, web_idi in zip(web_idx, web_ids) if web_idi == webi ] n_plies.append(np.array(n_pliesi)) thk.append(np.array(thki)) theta.append(np.array(thetai)) mat_idx.append(np.array(mati)) if flatback: dp.append(1.) n_plies.append(upperCSi.n_plies[-1]) thk.append(upperCSi.t[-1]) theta.append(upperCSi.theta[-1]) mat_idx.append(upperCSi.mat_idx[-1]) dp_out = sorted(list(set(dp))) sec = CompositeSection(dp_out, n_plies, thk, theta, mat_idx, materials) return sec ############################## layer_name = self.options['modeling_options']['blade']['layer_name'] layer_mat = self.options['modeling_options']['blade']['layer_mat'] upperCS = [None] * self.n_span lowerCS = [None] * self.n_span websCS = [None] * self.n_span profile = [None] * self.n_span # Check that the layer to be optimized actually exist te_ss_var_ok = False te_ps_var_ok = False spar_cap_ss_var_ok = False spar_cap_ps_var_ok = False for i_layer in range(self.n_layers): if layer_name[i_layer] == self.te_ss_var: te_ss_var_ok = True if layer_name[i_layer] == self.te_ps_var: te_ps_var_ok = True if layer_name[i_layer] == self.spar_cap_ss_var: spar_cap_ss_var_ok = True if layer_name[i_layer] == self.spar_cap_ps_var: spar_cap_ps_var_ok = True if te_ss_var_ok == False: print( 'The layer at the trailing edge suction side is set to be optimized, but does not exist in the input yaml. Please check.' ) if te_ps_var_ok == False: print( 'The layer at the trailing edge pressure side is set to be optimized, but does not exist in the input yaml. Please check.' ) if spar_cap_ss_var_ok == False: print( 'The layer at the spar cap suction side is set to be optimized, but does not exist in the input yaml. Please check.' ) if spar_cap_ps_var_ok == False: print( 'The layer at the spar cap pressure side is set to be optimized, but does not exist in the input yaml. Please check.' ) region_loc_vars = [ self.te_ss_var, self.te_ps_var, self.spar_cap_ss_var, self.spar_cap_ps_var ] region_loc_ss = { } # track precomp regions for user selected composite layers region_loc_ps = {} for var in region_loc_vars: region_loc_ss[var] = [None] * self.n_span region_loc_ps[var] = [None] * self.n_span ## Materials material_dict = {} materials = [] for i_mat in range(self.n_mat): materials.append( Orthotropic2DMaterial(inputs['E'][i_mat, 0], inputs['E'][i_mat, 1], inputs['G'][i_mat, 0], inputs['nu'][i_mat, 0], inputs['rho'][i_mat], discrete_inputs['mat_name'][i_mat])) material_dict[discrete_inputs['mat_name'][i_mat]] = i_mat ## Spanwise for i in range(self.n_span): # time0 = time.time() ## Profiles # rotate profile_i = inputs['coord_xy_interp'][i, :, :] profile_i_rot = np.column_stack( rotate(inputs['pitch_axis'][i], 0., profile_i[:, 0], profile_i[:, 1], np.radians(inputs['theta'][i]))) # import matplotlib.pyplot as plt # plt.plot(profile_i[:,0], profile_i[:,1]) # plt.plot(profile_i_rot[:,0], profile_i_rot[:,1]) # plt.axis('equal') # plt.title(i) # plt.show() # normalize profile_i_rot[:, 0] -= min(profile_i_rot[:, 0]) profile_i_rot = profile_i_rot / max(profile_i_rot[:, 0]) profile_i_rot_precomp = copy.copy(profile_i_rot) idx_s = 0 idx_le_precomp = np.argmax(profile_i_rot_precomp[:, 0]) if idx_le_precomp != 0: if profile_i_rot_precomp[0, 0] == profile_i_rot_precomp[-1, 0]: idx_s = 1 profile_i_rot_precomp = np.row_stack( (profile_i_rot_precomp[idx_le_precomp:], profile_i_rot_precomp[idx_s:idx_le_precomp, :])) profile_i_rot_precomp[:, 1] -= profile_i_rot_precomp[ np.argmin(profile_i_rot_precomp[:, 0]), 1] # # renormalize profile_i_rot_precomp[:, 0] -= min(profile_i_rot_precomp[:, 0]) profile_i_rot_precomp = profile_i_rot_precomp / max( profile_i_rot_precomp[:, 0]) if profile_i_rot_precomp[-1, 0] != 1.: profile_i_rot_precomp = np.row_stack( (profile_i_rot_precomp, profile_i_rot_precomp[0, :])) # 'web' at trailing edge needed for flatback airfoils if profile_i_rot_precomp[0, 1] != profile_i_rot_precomp[ -1, 1] and profile_i_rot_precomp[ 0, 0] == profile_i_rot_precomp[-1, 0]: flatback = True else: flatback = False profile[i] = Profile.initWithTEtoTEdata( profile_i_rot_precomp[:, 0], profile_i_rot_precomp[:, 1]) # import matplotlib.pyplot as plt # plt.plot(profile_i_rot_precomp[:,0], profile_i_rot_precomp[:,1]) # plt.axis('equal') # plt.title(i) # plt.show() idx_le = np.argmin(profile_i_rot[:, 0]) profile_i_arc = arc_length(profile_i_rot) arc_L = profile_i_arc[-1] profile_i_arc /= arc_L loc_LE = profile_i_arc[idx_le] len_PS = 1. - loc_LE ## Composites ss_idx = [] ss_start_nd_arc = [] ss_end_nd_arc = [] ps_idx = [] ps_start_nd_arc = [] ps_end_nd_arc = [] web_start_nd_arc = [] web_end_nd_arc = [] web_idx = [] # Determine spanwise composite layer elements that are non-zero at this spanwise location, # determine their chord-wise start and end location on the pressure and suctions side spline_arc2xnd = PchipInterpolator(profile_i_arc, profile_i_rot[:, 0]) # time1 = time.time() for idx_sec in range(self.n_layers): if discrete_inputs['definition_layer'][idx_sec] != 10: if inputs['layer_thickness'][idx_sec, i] != 0.: if inputs['layer_start_nd'][ idx_sec, i] < loc_LE or inputs['layer_end_nd'][ idx_sec, i] < loc_LE: ss_idx.append(idx_sec) if inputs['layer_start_nd'][idx_sec, i] < loc_LE: # ss_start_nd_arc.append(sec['start_nd_arc']['values'][i]) ss_end_nd_arc_temp = float( spline_arc2xnd( inputs['layer_start_nd'][idx_sec, i])) if ss_end_nd_arc_temp > 1 or ss_end_nd_arc_temp < 0: exit( 'Error in the definition of material ' + layer_name[idx_sec] + '. It cannot fit in the section number ' + str(i) + ' at span location ' + str(inputs['r'][i] / inputs['r'][-1] * 100.) + ' %.') if ss_end_nd_arc_temp == profile_i_rot[ 0, 0] and profile_i_rot[0, 0] != 1.: ss_end_nd_arc_temp = 1. ss_end_nd_arc.append(ss_end_nd_arc_temp) else: ss_end_nd_arc.append(1.) # ss_end_nd_arc.append(min(sec['end_nd_arc']['values'][i], loc_LE)/loc_LE) if inputs['layer_end_nd'][idx_sec, i] < loc_LE: ss_start_nd_arc.append( float( spline_arc2xnd( inputs['layer_end_nd'][idx_sec, i]))) else: ss_start_nd_arc.append(0.) if inputs['layer_start_nd'][ idx_sec, i] > loc_LE or inputs['layer_end_nd'][ idx_sec, i] > loc_LE: ps_idx.append(idx_sec) # ps_start_nd_arc.append((max(sec['start_nd_arc']['values'][i], loc_LE)-loc_LE)/len_PS) # ps_end_nd_arc.append((min(sec['end_nd_arc']['values'][i], 1.)-loc_LE)/len_PS) if inputs['layer_start_nd'][ idx_sec, i] > loc_LE and inputs['layer_end_nd'][ idx_sec, i] < loc_LE: # ps_start_nd_arc.append(float(remap2grid(profile_i_arc, profile_i_rot[:,0], sec['start_nd_arc']['values'][i]))) ps_end_nd_arc.append(1.) else: ps_end_nd_arc_temp = float( spline_arc2xnd( inputs['layer_end_nd'][idx_sec, i])) if np.isclose(ps_end_nd_arc_temp, profile_i_rot[-1, 0] ) and profile_i_rot[-1, 0] != 1.: ps_end_nd_arc_temp = 1. ps_end_nd_arc.append(ps_end_nd_arc_temp) if inputs['layer_start_nd'][idx_sec, i] < loc_LE: ps_start_nd_arc.append(0.) else: ps_start_nd_arc.append( float( spline_arc2xnd( inputs['layer_start_nd'][idx_sec, i]))) else: target_idx = inputs['layer_web'][idx_sec] - 1 if inputs['layer_thickness'][idx_sec, i] != 0.: web_idx.append(idx_sec) start_nd_arc = float( spline_arc2xnd( inputs['web_start_nd'][int(target_idx), i])) end_nd_arc = float( spline_arc2xnd( inputs['web_end_nd'][int(target_idx), i])) web_start_nd_arc.append(start_nd_arc) web_end_nd_arc.append(end_nd_arc) # time1 = time.time() - time1 # print(time1) # generate the Precomp composite stacks for chordwise regions if np.min([ss_start_nd_arc, ss_end_nd_arc]) < 0 or np.max( [ss_start_nd_arc, ss_end_nd_arc]) > 1: print('Error in the layer definition at station number ' + str(i)) exit() upperCS[i], region_loc_ss = region_stacking( i, ss_idx, ss_start_nd_arc, ss_end_nd_arc, layer_name, inputs['layer_thickness'][:, i], inputs['fiber_orientation'][:, i], layer_mat, material_dict, materials, region_loc_ss) lowerCS[i], region_loc_ps = region_stacking( i, ps_idx, ps_start_nd_arc, ps_end_nd_arc, layer_name, inputs['layer_thickness'][:, i], inputs['fiber_orientation'][:, i], layer_mat, material_dict, materials, region_loc_ps) if len(web_idx) > 0 or flatback: websCS[i] = web_stacking(i, web_idx, web_start_nd_arc, web_end_nd_arc, inputs['layer_thickness'][:, i], inputs['fiber_orientation'][:, i], layer_mat, material_dict, materials, flatback, upperCS[i]) else: websCS[i] = CompositeSection([], [], [], [], [], []) sector_idx_strain_spar_cap_ss = [ None if regs == None else regs[int(len(regs) / 2)] for regs in region_loc_ss[self.spar_cap_ss_var] ] sector_idx_strain_spar_cap_ps = [ None if regs == None else regs[int(len(regs) / 2)] for regs in region_loc_ps[self.spar_cap_ps_var] ] sector_idx_strain_te_ss = [ None if regs == None else regs[int(len(regs) / 2)] for regs in region_loc_ss[self.te_ss_var] ] sector_idx_strain_te_ps = [ None if regs == None else regs[int(len(regs) / 2)] for regs in region_loc_ps[self.te_ps_var] ] # Get Beam Properties beam = PreComp(inputs['r'], inputs['chord'], np.zeros_like( inputs['r']), inputs['pitch_axis'], inputs['precurve'], inputs['presweep'], profile, materials, upperCS, lowerCS, websCS, sector_idx_strain_spar_cap_ps, sector_idx_strain_spar_cap_ss, sector_idx_strain_te_ps, sector_idx_strain_te_ss) EIxx, EIyy, GJ, EA, EIxy, x_ec, y_ec, rhoA, area, rhoJ, Tw_iner, flap_iner, edge_iner, x_tc, y_tc, x_sc, y_sc, x_cg, y_cg = beam.sectionProperties( ) # outputs['eps_crit_spar'] = beam.panelBucklingStrain(sector_idx_strain_spar_cap_ss) # outputs['eps_crit_te'] = beam.panelBucklingStrain(sector_idx_strain_te_ss) xu_strain_spar, xl_strain_spar, yu_strain_spar, yl_strain_spar = beam.criticalStrainLocations( sector_idx_strain_spar_cap_ss, sector_idx_strain_spar_cap_ps) xu_strain_te, xl_strain_te, yu_strain_te, yl_strain_te = beam.criticalStrainLocations( sector_idx_strain_te_ss, sector_idx_strain_te_ps) # Store what materials make up the composites for SC/TE for i in range(self.n_span): for j in range(self.n_mat): if sector_idx_strain_spar_cap_ss[i]: if j in upperCS[i].mat_idx[ sector_idx_strain_spar_cap_ss[i]]: outputs['sc_ss_mats'][i, j] = 1. if sector_idx_strain_spar_cap_ps[i]: if j in lowerCS[i].mat_idx[ sector_idx_strain_spar_cap_ps[i]]: outputs['sc_ps_mats'][i, j] = 1. if sector_idx_strain_te_ss[i]: if j in upperCS[i].mat_idx[sector_idx_strain_te_ss[i]]: outputs['te_ss_mats'][i, j] = 1. if sector_idx_strain_te_ps[i]: if j in lowerCS[i].mat_idx[sector_idx_strain_te_ps[i]]: outputs['te_ps_mats'][i, j] = 1. outputs['z'] = inputs['r'] outputs['EIxx'] = EIxx outputs['EIyy'] = EIyy outputs['GJ'] = GJ outputs['EA'] = EA outputs['EIxy'] = EIxy outputs['x_ec'] = x_ec outputs['y_ec'] = y_ec outputs['rhoA'] = rhoA outputs['A'] = area outputs['rhoJ'] = rhoJ outputs['Tw_iner'] = Tw_iner outputs['flap_iner'] = flap_iner outputs['edge_iner'] = edge_iner outputs["x_tc"] = x_tc outputs["y_tc"] = y_tc outputs["x_sc"] = x_sc outputs["y_sc"] = y_sc outputs["x_cg"] = x_cg outputs["y_cg"] = y_cg outputs['xu_strain_spar'] = xu_strain_spar outputs['xl_strain_spar'] = xl_strain_spar outputs['yu_strain_spar'] = yu_strain_spar outputs['yl_strain_spar'] = yl_strain_spar outputs['xu_strain_te'] = xu_strain_te outputs['xl_strain_te'] = xl_strain_te outputs['yu_strain_te'] = yu_strain_te outputs['yl_strain_te'] = yl_strain_te # Compute mass and inertia of blade and rotor blade_mass = np.trapz(rhoA, inputs['r']) blade_moment_of_inertia = np.trapz(rhoA * inputs['r']**2., inputs['r']) tilt = inputs['uptilt'] n_blades = discrete_inputs['n_blades'] mass_all_blades = n_blades * blade_mass Ibeam = n_blades * blade_moment_of_inertia Ixx = Ibeam Iyy = Ibeam / 2.0 # azimuthal average for 2 blades, exact for 3+ Izz = Ibeam / 2.0 Ixy = 0.0 Ixz = 0.0 Iyz = 0.0 # azimuthal average for 2 blades, exact for 3+ # rotate to yaw c.s. I = DirectionVector(Ixx, Iyy, Izz).hubToYaw( tilt) # because off-diagonal components are all zero I_all_blades = np.r_[I.x, I.y, I.z, Ixy, Ixz, Iyz] outputs['blade_mass'] = blade_mass outputs['blade_moment_of_inertia'] = blade_moment_of_inertia outputs['mass_all_blades'] = mass_all_blades outputs['I_all_blades'] = I_all_blades # Placeholder - rotor cost bcm = blade_cost_model(verbosity=self.verbosity) bcm.name = '' bcm.materials = {} bcm.mat_options = {} bcm.mat_options['core_mat_id'] = np.zeros(self.n_mat) bcm.mat_options['coating_mat_id'] = -1 bcm.mat_options['le_reinf_mat_id'] = -1 bcm.mat_options['te_reinf_mat_id'] = -1 for i_mat in range(self.n_mat): name = discrete_inputs['mat_name'][i_mat] # if name != 'resin': bcm.materials[name] = {} bcm.materials[name]['id'] = i_mat + 1 bcm.materials[name]['name'] = discrete_inputs['mat_name'][i_mat] bcm.materials[name]['density'] = inputs['rho'][i_mat] bcm.materials[name]['unit_cost'] = inputs['unit_cost'][i_mat] bcm.materials[name]['waste'] = inputs['waste'][i_mat] * 100. if discrete_inputs['component_id'][i_mat] > 1: # It's a composite bcm.materials[name]['fiber_density'] = inputs['rho_fiber'][ i_mat] bcm.materials[name]['area_density_dry'] = inputs[ 'rho_area_dry'][i_mat] bcm.materials[name]['fvf'] = inputs['fvf'][i_mat] * 100. bcm.materials[name]['fwf'] = inputs['fwf'][i_mat] * 100. bcm.materials[name]['ply_t'] = inputs['ply_t'][i_mat] if discrete_inputs['component_id'][ i_mat] > 3: # The material does not need to be cut@station bcm.materials[name]['cut@station'] = 'N' else: bcm.materials[name]['cut@station'] = 'Y' bcm.materials[name]['roll_mass'] = inputs['roll_mass'][ i_mat] else: bcm.materials[name]['fvf'] = 100. bcm.materials[name]['fwf'] = 100. bcm.materials[name]['cut@station'] = 'N' if discrete_inputs['component_id'][i_mat] <= 0: bcm.materials[name]['ply_t'] = inputs['ply_t'][i_mat] if discrete_inputs['component_id'][i_mat] == 0: bcm.mat_options['coating_mat_id'] = bcm.materials[name][ 'id'] # Assigning the material to the coating elif discrete_inputs['component_id'][i_mat] == 1: bcm.mat_options['core_mat_id'][ bcm.materials[name]['id'] - 1] = 1 # Assigning the material to the core elif discrete_inputs['component_id'][i_mat] == 2: bcm.mat_options['skin_mat_id'] = bcm.materials[name][ 'id'] # Assigning the material to the shell skin elif discrete_inputs['component_id'][i_mat] == 3: bcm.mat_options['skinwebs_mat_id'] = bcm.materials[name][ 'id'] # Assigning the material to the webs skin elif discrete_inputs['component_id'][i_mat] == 4: bcm.mat_options['sc_mat_id'] = bcm.materials[name][ 'id'] # Assigning the material to the spar caps elif discrete_inputs['component_id'][i_mat] == 5: bcm.mat_options['le_reinf_mat_id'] = bcm.materials[name][ 'id'] # Assigning the material to the le reinf bcm.mat_options['te_reinf_mat_id'] = bcm.materials[name][ 'id'] # Assigning the material to the te reinf bcm.upperCS = upperCS bcm.lowerCS = lowerCS bcm.websCS = websCS bcm.profile = profile bcm.chord = inputs['chord'] bcm.r = inputs['r'] - inputs['r'][0] bcm.bladeLength = inputs['r'][-1] - inputs['r'][0] bcm.le_location = inputs['pitch_axis'] blade_cost, blade_mass = bcm.execute_blade_cost_model() outputs['total_blade_cost'] = blade_cost outputs['total_blade_mass'] = blade_mass