def evaluate(self, *args, **kwarg): """This is used to execute the evaluate functions of the analyses stored in the container. Assumptions: None Source: N/A Inputs: None Outputs: Results of the Evaluate Functions Properties Used: N/A """ results = Results() for tag, analysis in self.items(): if hasattr(analysis, 'evaluate'): result = analysis.evaluate(*args, **kwarg) else: result = analysis(*args, **kwarg) results[tag] = result return results
def evaluate(self, state, settings, geometry): """Evaluates preset processes for each component. Assumptions: None Source: N/A Inputs: state (passed to an evaluation function) setting (passed to an evaluation function) geometry (used to get keys and passed to an evaluation function) Outputs: None Properties Used: self.geometry_key <string> """ geometry_items = geometry.deep_get(self.geometry_key) results = Results() for key, this_geometry in geometry_items.items(): result = Process.evaluate(self, state, settings, this_geometry) results[key] = result return results
def miscellaneous_drag_aircraft_ESDU(state, settings, geometry): """Computes the miscellaneous drag associated with an aircraft Assumptions: Basic fit Source: ESDU 94044, figure 1 Inputs: state.conditions.freestream.mach_number [Unitless] (actual values not used) geometry.reference_area [m^2] geometry.wings.areas.wetted [m^2] geometry.fuselages.areas.wetted [m^2] geometry.propulsor.areas.wetted [m^2] geometry.propulsor.number_of_engines [Unitless] Outputs: cd_excrescence (drag) [Unitless] Properties Used: N/A """ # unpack inputs conditions = state.conditions configuration = settings Sref = geometry.reference_area ones_1col = conditions.freestream.mach_number * 0. + 1 # Estimating total wetted area swet_tot = 0. for wing in geometry.wings: swet_tot += wing.areas.wetted for fuselage in geometry.fuselages: swet_tot += fuselage.areas.wetted for propulsor in geometry.propulsors: swet_tot += propulsor.areas.wetted * propulsor.number_of_engines swet_tot *= 1.10 # Estimating excrescence drag, based in ESDU 94044, figure 1 D_q = 0.40 * (0.0184 + 0.000469 * swet_tot - 1.13 * 10**-7 * swet_tot**2) cd_excrescence = D_q / Sref # ------------------------------------------------------------------ # The final result # ------------------------------------------------------------------ # dump to results conditions.aerodynamics.drag_breakdown.miscellaneous = Results( total_wetted_area=swet_tot, reference_area=Sref, total=cd_excrescence * ones_1col, ) return cd_excrescence * ones_1col
def parasite_drag_pylon(state,settings,geometry): """ SUAVE.Methods.parasite_drag_pylon(conditions,configuration,geometry): Simplified estimation, considering pylon drag a fraction of the nacelle drag Inputs: conditions - data dictionary for output dump configuration - not in use geometry - SUave type vehicle Outpus: cd_misc - returns the miscellaneous drag associated with the vehicle Assumptions: simplified estimation, considering pylon drag a fraction of the nacelle drag """ # unpack conditions = state.conditions configuration = settings pylon_factor = 0.20 # 20% of propulsor drag n_propulsors = len(geometry.propulsors) # number of propulsive system in vehicle (NOT # of ENGINES) pylon_parasite_drag = 0.00 pylon_wetted_area = 0.00 pylon_cf = 0.00 pylon_compr_fact = 0.00 pylon_rey_fact = 0.00 pylon_FF = 0.00 # Estimating pylon drag for propulsor in geometry.propulsors: ref_area = propulsor.nacelle_diameter**2 / 4 * np.pi pylon_parasite_drag += pylon_factor * conditions.aerodynamics.drag_breakdown.parasite[propulsor.tag].parasite_drag_coefficient* (ref_area/geometry.reference_area * propulsor.number_of_engines) pylon_wetted_area += pylon_factor * conditions.aerodynamics.drag_breakdown.parasite[propulsor.tag].wetted_area * propulsor.number_of_engines pylon_cf += conditions.aerodynamics.drag_breakdown.parasite[propulsor.tag].skin_friction_coefficient pylon_compr_fact += conditions.aerodynamics.drag_breakdown.parasite[propulsor.tag].compressibility_factor pylon_rey_fact += conditions.aerodynamics.drag_breakdown.parasite[propulsor.tag].reynolds_factor pylon_FF += conditions.aerodynamics.drag_breakdown.parasite[propulsor.tag].form_factor pylon_cf /= n_propulsors pylon_compr_fact /= n_propulsors pylon_rey_fact /= n_propulsors pylon_FF /= n_propulsors # dump data to conditions pylon_result = Results( wetted_area = pylon_wetted_area , reference_area = geometry.reference_area , parasite_drag_coefficient = pylon_parasite_drag , skin_friction_coefficient = pylon_cf , compressibility_factor = pylon_compr_fact , reynolds_factor = pylon_rey_fact , form_factor = pylon_FF , ) conditions.aerodynamics.drag_breakdown.parasite['pylon'] = pylon_result return pylon_parasite_drag
def wave_drag_lift(conditions, configuration, wing): """Computes wave drag due to lift Assumptions: Simplified equations Source: http://adg.stanford.edu/aa241/drag/ssdragcalc.html Inputs: conditions.freestream.mach_number [Unitless] conditions.aerodynamics.lift_coefficient [Unitless] wing.total_length [m] wing.areas.reference [m^2] Outputs: wave_drag_lift [Unitless] Properties Used: N/A """ # Unpack freestream = conditions.freestream total_length = wing.total_length Sref = wing.areas.reference # Conditions Mc = freestream.mach_number * 1.0 # Length-wise aspect ratio ARL = total_length**2 / Sref # Lift coefficient if wing.vertical: CL = np.zeros_like(conditions.aerodynamics.lift_coefficient) else: # get wing specific CL CL = conditions.aerodynamics.lift_breakdown.inviscid_wings_lift[ wing.tag] # Computations x = np.pi * ARL / 4 beta = np.array([[0.0]] * len(Mc)) beta[Mc >= 1.05] = np.sqrt(Mc[Mc >= 1.05]**2 - 1) wave_drag_lift = np.array([[0.0]] * len(Mc)) wave_drag_lift[Mc >= 1.05] = CL[Mc >= 1.05]**2 * x / 4 * ( np.sqrt(1 + (beta[Mc >= 1.05] / x)**2) - 1) wave_drag_lift[0:len(Mc[Mc >= 1.05]), 0] = wave_drag_lift[Mc >= 1.05] # Dump data to conditions wave_lift_result = Results( reference_area=Sref, wave_drag_lift_coefficient=wave_drag_lift, length_AR=ARL, ) return wave_drag_lift
def parasite_drag_propulsor(state, settings, geometry): """ SUAVE.Methods.parasite_drag_propulsor(conditions,configuration,propulsor) computes the parasite drag associated with a propulsor Inputs: Outputs: Assumptions: """ # unpack inputs conditions = state.conditions configuration = settings propulsor = geometry Sref = propulsor.nacelle_diameter**2. / 4. * np.pi Swet = propulsor.areas.wetted l_prop = propulsor.engine_length d_prop = propulsor.nacelle_diameter # conditions freestream = conditions.freestream Mc = freestream.mach_number Tc = freestream.temperature re = freestream.reynolds_number # reynolds number Re_prop = re * l_prop # skin friction coefficient cf_prop, k_comp, k_reyn = compressible_turbulent_flat_plate( Re_prop, Mc, Tc) ## form factor according to Raymer equation (pg 283 of Aircraft Design: A Conceptual Approach) k_prop = 1 + 0.35 / (float(l_prop) / float(d_prop)) # find the final result propulsor_parasite_drag = k_prop * cf_prop * Swet / Sref # dump data to conditions propulsor_result = Results( wetted_area=Swet, reference_area=Sref, parasite_drag_coefficient=propulsor_parasite_drag, skin_friction_coefficient=cf_prop, compressibility_factor=k_comp, reynolds_factor=k_reyn, form_factor=k_prop, ) conditions.aerodynamics.drag_breakdown.parasite[ propulsor.tag] = propulsor_result return propulsor_parasite_drag
def evaluate(self,*args,**kwarg): results = Results() for tag,analysis in self.items(): if hasattr(analysis,'evaluate'): result = analysis.evaluate(*args,**kwarg) else: result = analysis(*args,**kwarg) results[tag] = result return results
def evaluate(self, state, settings, geometry): geometry_items = geometry.deep_get(self.geometry_key) results = Results() for key, this_geometry in geometry_items.items(): result = Process.evaluate(self, state, settings, this_geometry) results[key] = result return results
def miscellaneous_drag_aircraft_ESDU(state,settings,geometry): """ SUAVE.Methods.miscellaneous_drag_aircraft_ESDU(conditions,configuration,geometry): computes the miscellaneous drag based in ESDU 94044, figure 1 Inputs: conditions - data dictionary for output dump configuration - not in use geometry - SUave type vehicle Outpus: cd_misc - returns the miscellaneous drag associated with the vehicle Assumptions: if needed """ # unpack inputs conditions = state.conditions configuration = settings Sref = geometry.reference_area ones_1col = conditions.freestream.mach_number *0.+1 # Estimating total wetted area swet_tot = 0. for wing in geometry.wings: swet_tot += wing.areas.wetted for fuselage in geometry.fuselages: swet_tot += fuselage.areas.wetted for propulsor in geometry.propulsors: swet_tot += propulsor.areas.wetted * propulsor.number_of_engines swet_tot *= 1.10 # Estimating excrescence drag, based in ESDU 94044, figure 1 D_q = 0.40* (0.0184 + 0.000469 * swet_tot - 1.13*10**-7 * swet_tot ** 2) cd_excrescence = D_q / Sref # ------------------------------------------------------------------ # The final result # ------------------------------------------------------------------ # dump to results conditions.aerodynamics.drag_breakdown.miscellaneous = Results( total_wetted_area = swet_tot, reference_area = Sref , total = cd_excrescence *ones_1col, ) return cd_excrescence *ones_1col
def wave_drag_lift(conditions, configuration, wing): """ SUAVE.Methods.wave_drag_lift(conditions,configuration,wing) computes the wave drag due to lift Based on http://adg.stanford.edu/aa241/drag/ssdragcalc.html Inputs: - SUave wing - Sref - wing reference area - Mc - mach number - CL - coefficient of lift - total_length - length of the wing root Outputs: - CD due to wave drag from the wing Assumptions: - Supersonic mach numbers - Reference area of passed wing is desired for CD """ # Unpack freestream = conditions.freestream total_length = wing.total_length Sref = wing.areas.reference # Conditions Mc = freestream.mach_number * 1.0 # Length-wise aspect ratio ARL = total_length**2 / Sref # Lift coefficient CL = conditions.aerodynamics.lift_coefficient * 1.0 # Computations x = np.pi * ARL / 4 beta = np.array([[0.0]] * len(Mc)) beta[Mc >= 1.05] = np.sqrt(Mc[Mc >= 1.05]**2 - 1) wave_drag_lift = np.array([[0.0]] * len(Mc)) wave_drag_lift[Mc >= 1.05] = CL[Mc >= 1.05]**2 * x / 4 * ( np.sqrt(1 + (beta[Mc >= 1.05] / x)**2) - 1) wave_drag_lift[0:len(Mc[Mc >= 1.05]), 0] = wave_drag_lift[Mc >= 1.05] # Dump data to conditions wave_lift_result = Results( reference_area=Sref, wave_drag_lift_coefficient=wave_drag_lift, length_AR=ARL, ) return wave_drag_lift
def parasite_drag_aircraft(conditions,configuration,geometry): """ SUAVE.Methods.parasite_drag_aircraft(aircraft,segment,Cl,cdi_inv,cdp,fd_ws) computes the parasite_drag_aircraft associated with an aircraft Inputs: Outputs: Assumptions: based on a set of fits """ # unpack inputs wings = geometry.wings fuselages = geometry.fuselages propulsors = geometry.propulsors vehicle_reference_area = geometry.reference_area drag_breakdown = conditions.aerodynamics.drag_breakdown # the drag to be returned total_parasite_drag = 0.0 # start conditions node drag_breakdown.parasite = Results() # from wings for wing in wings.values(): parasite_drag = parasite_drag_wing(conditions,configuration,wing) conditions.aerodynamics.drag_breakdown.parasite[wing.tag].parasite_drag_coefficient = parasite_drag * wing.areas.reference/vehicle_reference_area total_parasite_drag += parasite_drag * wing.areas.reference/vehicle_reference_area # from fuselage for fuselage in fuselages.values(): parasite_drag = parasite_drag_fuselage(conditions,configuration,fuselage) conditions.aerodynamics.drag_breakdown.parasite[fuselage.tag].parasite_drag_coefficient = parasite_drag * fuselage.areas.front_projected/vehicle_reference_area total_parasite_drag += parasite_drag * fuselage.areas.front_projected/vehicle_reference_area # from propulsors for propulsor in propulsors.values(): parasite_drag = parasite_drag_propulsor(conditions,configuration,propulsor) ref_area = propulsor.nacelle_diameter**2 / 4 * np.pi conditions.aerodynamics.drag_breakdown.parasite[propulsor.tag].parasite_drag_coefficient = parasite_drag * ref_area/vehicle_reference_area * propulsor.number_of_engines total_parasite_drag += parasite_drag * ref_area/vehicle_reference_area * propulsor.number_of_engines # dump to condtitions drag_breakdown.parasite.total = total_parasite_drag return total_parasite_drag
def induced_drag_aircraft(state,settings,geometry): """Determines induced drag for the full aircraft Assumptions: Based on fits Source: adg.stanford.edu (Stanford AA241 A/B Course Notes) Inputs: state.conditions.aerodynamics.lift_coefficient [Unitless] state.conditions.aerodynamics.drag_breakdown.parasite.total [Unitless] configuration.oswald_efficiency_factor [Unitless] configuration.viscous_lift_dependent_drag_factor [Unitless] geometry.wings['main_wing'].span_efficiency [Unitless] geometry.wings['main_wing'].aspect_ratio [Unitless] Outputs: total_induced_drag [Unitless] Properties Used: N/A """ # unpack inputs conditions = state.conditions configuration = settings aircraft_lift = conditions.aerodynamics.lift_coefficient e = configuration.oswald_efficiency_factor K = configuration.viscous_lift_dependent_drag_factor wing_e = geometry.wings['main_wing'].span_efficiency ar = geometry.wings['main_wing'].aspect_ratio CDp = state.conditions.aerodynamics.drag_breakdown.parasite.total if e == None: e = 1/((1/wing_e)+np.pi*ar*K*CDp) total_induced_drag = aircraft_lift**2 / (np.pi*ar*e) # store data try: conditions.aerodynamics.drag_breakdown.induced = Results( total = total_induced_drag , efficiency_factor = e , aspect_ratio = ar , ) except: print("Drag Polar Mode") return total_induced_drag
def evaluate(self, condtitions): """Evaluate the Geometry analysis. Assumptions: None Source: N/A Inputs: None Outputs: Results of the Geometry Analysis Properties Used: N/A """ return Results()
def evaluate(self, conditions): """Evaluate the Structures analysis. Assumptions: None Source: N/A Inputs: None Outputs: Results of the Structures Analysis Properties Used: N/A """ return Results()
def evaluate(self, *args, **kwarg): """This is used to execute the analysis' specific algorithms. Assumptions: None Source: N/A Inputs: None Outputs: None Properties Used: N/A """ raise NotImplementedError return Results()
def induced_drag_aircraft(state, settings, geometry): """ SUAVE.Methods.induced_drag_aircraft(conditions,configuration,geometry) computes the induced drag associated with a wing Inputs: Outputs: Assumptions: based on a set of fits """ # unpack inputs conditions = state.conditions configuration = settings aircraft_lift = conditions.aerodynamics.lift_coefficient e = configuration.oswald_efficiency_factor K = configuration.viscous_lift_dependent_drag_factor wing_e = geometry.wings['main_wing'].span_efficiency ar = geometry.wings['main_wing'].aspect_ratio CDp = state.conditions.aerodynamics.drag_breakdown.parasite.total if e == None: e = 1 / ((1 / wing_e) + np.pi * ar * K * CDp) total_induced_drag = aircraft_lift**2 / (np.pi * ar * e) # store data try: conditions.aerodynamics.drag_breakdown.induced = Results( total=total_induced_drag, efficiency_factor=e, aspect_ratio=ar, ) except: print("Drag Polar Mode") return total_induced_drag
def evaluate(self, conditions): """Evaluate the stability analysis. Assumptions: None Source: N/A Inputs: None Outputs: results Properties Used: N/A """ results = Results() return results
def fuselage_correction(state, settings, geometry): # unpack fus_correction = settings.fuselage_lift_correction Mc = state.conditions.freestream.mach_number AoA = state.conditions.aerodynamics.angle_of_attack wings_lift_comp = state.conditions.aerodynamics.lift_coefficient # total lift, accounting one fuselage aircraft_lift_total = wings_lift_comp * fus_correction # store results lift_results = Results( total=aircraft_lift_total, compressible_wings=wings_lift_comp, ) state.conditions.aerodynamics.lift_coefficient = aircraft_lift_total return aircraft_lift_total
def parasite_drag_fuselage(state, settings, geometry): """ SUAVE.Methods.parasite_drag_fuselage(conditions,configuration,fuselage) computes the parasite drag associated with a fuselage Inputs: Outputs: Assumptions: """ # unpack inputs conditions = state.conditions configuration = settings fuselage = geometry form_factor = configuration.fuselage_parasite_drag_form_factor freestream = conditions.freestream Sref = fuselage.areas.front_projected Swet = fuselage.areas.wetted l_fus = fuselage.lengths.total d_fus = fuselage.effective_diameter # conditions Mc = freestream.mach_number Tc = freestream.temperature re = freestream.reynolds_number # reynolds number Re_fus = re * (l_fus) # skin friction coefficient cf_fus, k_comp, k_reyn = compressible_turbulent_flat_plate(Re_fus, Mc, Tc) # form factor for cylindrical bodies d_d = float(d_fus) / float(l_fus) D = np.sqrt(1 - (1 - Mc**2) * d_d**2) a = 2 * (1 - Mc**2) * (d_d**2) * (np.arctanh(D) - D) / (D**3) du_max_u = a / ((2 - a) * (1 - Mc**2)**0.5) k_fus = (1 + form_factor * du_max_u)**2 # find the final result fuselage_parasite_drag = k_fus * cf_fus * Swet / Sref # dump data to conditions fuselage_result = Results( wetted_area=Swet, reference_area=Sref, parasite_drag_coefficient=fuselage_parasite_drag, skin_friction_coefficient=cf_fus, compressibility_factor=k_comp, reynolds_factor=k_reyn, form_factor=k_fus, ) state.conditions.aerodynamics.drag_breakdown.parasite[ fuselage.tag] = fuselage_result return fuselage_parasite_drag
def windmilling_drag(geometry,state): """Computes windmilling drag for turbofan engines Assumptions: None Source: http://www.dept.aoe.vt.edu/~mason/Mason_f/AskinThesis2002_13.pdf Inputs: geometry. max_mach_operational [Unitless] reference_area [m^2] wings.sref [m^2] propulsors. areas.wetted [m^2] nacelle_diameter [m^2] engine_length [m^2] Outputs: windmilling_drag_coefficient [Unitless] Properties Used: N/A """ # ============================================== # Unpack # ============================================== vehicle = geometry # Defining reference area if vehicle.reference_area: reference_area = vehicle.reference_area else: n_wing = 0 for wing in vehicle.wings: if not isinstance(wing,Wings.Main_Wing): continue n_wing = n_wing + 1 reference_area = wing.sref if n_wing > 1: print ' More than one Main_Wing in the vehicle. Last one will be considered.' elif n_wing == 0: print 'No Main_Wing defined! Using the 1st wing found' for wing in vehicle.wings: if not isinstance(wing,Wings.Wing): continue reference_area = wing.sref break # getting geometric data from engine (estimating when not available) for idx,propulsor in enumerate(vehicle.propulsors): try: swet_nac = propulsor.areas.wetted except: try: D_nac = propulsor.nacelle_diameter if propulsor.engine_length <> 0.: l_nac = propulsor.engine_length else: try: MMO = vehicle.max_mach_operational except: MMO = 0.84 D_nac_in = D_nac / Units.inches l_nac = (2.36 * D_nac_in - 0.01*(D_nac_in*MMO)**2) * Units.inches except AttributeError: print 'Error calculating windmilling drag. Engine dimensions missing.' swet_nac = 5.62 * D_nac * l_nac # Compute windmilling_drag_coefficient = 0.007274 * swet_nac / reference_area # dump data to state windmilling_result = Results( wetted_area = swet_nac , windmilling_drag_coefficient = windmilling_drag_coefficient , ) state.conditions.aerodynamics.drag_breakdown.windmilling_drag = windmilling_result return windmilling_drag_coefficient
def miscellaneous_drag_aircraft(state, settings, geometry): """Computes the miscellaneous drag associated with an aircraft Assumptions: Basic fit Source: adg.stanford.edu (Stanford AA241 A/B Course Notes) Inputs: configuration.trim_drag_correction_factor [Unitless] geometry.propulsors.nacelle_diameter [m] geometry.reference_area [m^2] geometry.wings['main_wing'].aspect_ratio [Unitless] state.conditions.freestream.mach_number [Unitless] (actual values are not used) Outputs: total_miscellaneous_drag [Unitless] Properties Used: N/A """ # unpack inputs configuration = settings trim_correction_factor = configuration.trim_drag_correction_factor propulsors = geometry.propulsors vehicle_reference_area = geometry.reference_area ones_1col = state.conditions.freestream.mach_number * 0. + 1 conditions = state.conditions # ------------------------------------------------------------------ # Control surface gap drag # ------------------------------------------------------------------ #f_gaps_w=0.0002*(numpy.cos(sweep_w))**2*S_affected_w #f_gaps_h=0.0002*(numpy.cos(sweep_h))**2*S_affected_h #f_gaps_v=0.0002*(numpy.cos(sweep_v))**2*S_affected_v #f_gapst = f_gaps_w + f_gaps_h + f_gaps_v # TODO: do this correctly total_gap_drag = 0.000 # ------------------------------------------------------------------ # Nacelle base drag # ------------------------------------------------------------------ total_nacelle_base_drag = 0.0 nacelle_base_drag_results = Results() for propulsor in propulsors.values(): # calculate nacelle_base_drag = 0.5 / 12. * np.pi * propulsor.nacelle_diameter * 0.2 / vehicle_reference_area # dump nacelle_base_drag_results[ propulsor.tag] = nacelle_base_drag * ones_1col # increment total_nacelle_base_drag += nacelle_base_drag # ------------------------------------------------------------------ # Fuselage upsweep drag # ------------------------------------------------------------------ fuselage_upsweep_drag = 0.006 / vehicle_reference_area # ------------------------------------------------------------------ # Fuselage base drag # ------------------------------------------------------------------ fuselage_base_drag = 0.0 # ------------------------------------------------------------------ # The final result # ------------------------------------------------------------------ total_miscellaneous_drag = total_gap_drag \ + total_nacelle_base_drag \ + fuselage_upsweep_drag \ + fuselage_base_drag # dump to results conditions.aerodynamics.drag_breakdown.miscellaneous = Results( fuselage_upsweep=fuselage_upsweep_drag * ones_1col, nacelle_base=nacelle_base_drag_results, fuselage_base=fuselage_base_drag * ones_1col, control_gaps=total_gap_drag * ones_1col, total=total_miscellaneous_drag * ones_1col, ) return total_miscellaneous_drag * ones_1col
def parasite_drag_propulsor(state, settings, geometry): """Computes the parasite drag due to the propulsor Assumptions: Basic fit Source: adg.stanford.edu (Stanford AA241 A/B Course Notes) Inputs: state.conditions.freestream. mach_number [Unitless] temperature [K] reynolds_number [Unitless] geometry. nacelle_diameter [m^2] areas.wetted [m^2] engine_length [m] Outputs: propulsor_parasite_drag [Unitless] Properties Used: N/A """ # unpack inputs conditions = state.conditions configuration = settings propulsor = geometry Sref = propulsor.nacelle_diameter**2. / 4. * np.pi Swet = propulsor.areas.wetted l_prop = propulsor.engine_length d_prop = propulsor.nacelle_diameter # conditions freestream = conditions.freestream Mc = freestream.mach_number Tc = freestream.temperature re = freestream.reynolds_number # reynolds number Re_prop = re * l_prop # skin friction coefficient cf_prop, k_comp, k_reyn = compressible_turbulent_flat_plate( Re_prop, Mc, Tc) ## form factor according to Raymer equation (pg 283 of Aircraft Design: A Conceptual Approach) k_prop = 1 + 0.35 / (float(l_prop) / float(d_prop)) # find the final result propulsor_parasite_drag = k_prop * cf_prop * Swet / Sref # dump data to conditions propulsor_result = Results( wetted_area=Swet, reference_area=Sref, parasite_drag_coefficient=propulsor_parasite_drag, skin_friction_coefficient=cf_prop, compressibility_factor=k_comp, reynolds_factor=k_reyn, form_factor=k_prop, ) conditions.aerodynamics.drag_breakdown.parasite[ propulsor.tag] = propulsor_result return propulsor_parasite_drag
def pre_stall_coefficients(state,settings,geometry): """Uses the AERODAS method to determine prestall parameters for lift and drag for a single wing Assumptions: None Source: NASA TR: "Models of Lift and Drag Coefficients of Stalled and Unstalled Airfoils in Wind Turbines and Wind Tunnels" by D. A. Spera Inputs: state.conditions.aerodynamics.angle_of_attack settings.section_zero_lift_angle_of_attack geometry. section. angle_attack_max_prestall_lift zero_lift_drag_coefficient pre_stall_maximum_drag_coefficient_angle pre_stall_maximum_lift_coefficient pre_stall_lift_curve_slope pre_stall_maximum_lift_drag_coefficient Outputs: CL1 (coefficient of lift) [Unitless] CD1 (coefficient of drag) [Unitless] (packed in state.conditions.aerodynamics.pre_stall_coefficients[geometry.tag]) Properties Used: N/A """ # unpack inputs wing = geometry alpha = state.conditions.aerodynamics.angle_of_attack * 1.0 A0 = settings.section_zero_lift_angle_of_attack ACL1 = wing.section.angle_attack_max_prestall_lift ACD1 = wing.pre_stall_maximum_drag_coefficient_angle CL1max = wing.pre_stall_maximum_lift_coefficient CD0 = wing.section.zero_lift_drag_coefficient S1 = wing.pre_stall_lift_curve_slope CD1max = wing.pre_stall_maximum_lift_drag_coefficient if wing.vertical == True: alpha = 0. * np.ones_like(alpha) # Equation 6c RCL1 = S1*(ACL1-A0)-CL1max RCL1[RCL1<=0] = 1.e-16 # Equation 6d N1 = 1 + CL1max/RCL1 # Equation 6a or 6b depending on the alpha CL1 = 0.0 * np.ones_like(state.conditions.freestream.altitude) CL1[alpha>A0] = S1*(alpha[alpha>A0]-A0)-RCL1[alpha>A0]*((alpha[alpha>A0]-A0)/(ACL1[alpha>A0]-A0))**N1[alpha>A0] CL1[alpha==A0] = 0.0 CL1[alpha<A0] = S1*(alpha[alpha<A0]-A0)+RCL1[alpha<A0]*((A0-alpha[alpha<A0])/(ACL1[alpha<A0]-A0))**N1[alpha<A0] # M what is m? M = 2.0 # Does this need changing # Equation 7a con = np.logical_and((2*A0-ACD1)<=alpha,alpha<=ACD1) CD1 = np.ones_like(state.conditions.freestream.altitude) CD1[con] = CD0[con] + (CD1max[con]-CD0[con])*((alpha[con] -A0)/(ACD1[con]-A0))**M # Equation 7b CD1[np.logical_not(con)] = 0. # Pack outputs wing_result = Results( lift_coefficient = CL1, drag_coefficient = CD1 ) state.conditions.aerodynamics.pre_stall_coefficients[wing.tag] = wing_result return CL1, CD1
def evaluate(self, conditions): results = Results() return results
def parasite_drag_propulsor(state, settings, geometry): """Computes the parasite drag due to the propulsor Assumptions: Basic fit Source: Raymer equation (pg 283 of Aircraft Design: A Conceptual Approach) (subsonic) http://adg.stanford.edu/aa241/drag/BODYFORMFACTOR.HTML (supersonic) Inputs: state.conditions.freestream. mach_number [Unitless] temperature [K] reynolds_number [Unitless] geometry. nacelle_diameter [m^2] areas.wetted [m^2] engine_length [m] state.conditions.aerodynamics.drag_breakdown. compressible.main_wing.divergence_mach [Unitless] Outputs: propulsor_parasite_drag [Unitless] Properties Used: N/A """ # unpack inputs conditions = state.conditions configuration = settings propulsor = geometry freestream = conditions.freestream Sref = propulsor.nacelle_diameter**2 / 4 * np.pi Swet = propulsor.areas.wetted l_prop = propulsor.engine_length d_prop = propulsor.nacelle_diameter # conditions freestream = conditions.freestream Mc = freestream.mach_number Tc = freestream.temperature re = freestream.reynolds_number # reynolds number Re_prop = re * l_prop # skin friction coefficient cf_prop, k_comp, k_reyn = compressible_turbulent_flat_plate( Re_prop, Mc, Tc) k_prop = np.array([[0.0]] * len(Mc)) # assume that the drag divergence mach number of the propulsor matches the main wing Mdiv = state.conditions.aerodynamics.drag_breakdown.compressible.main_wing.divergence_mach # form factor according to Raymer equation (pg 283 of Aircraft Design: A Conceptual Approach) k_prop_sub = 1. + 0.35 / (float(l_prop) / float(d_prop)) # for supersonic flow (http://adg.stanford.edu/aa241/drag/BODYFORMFACTOR.HTML) k_prop_sup = 1. sb_mask = (Mc <= Mdiv) tn_mask = ((Mc > Mdiv) & (Mc < 1.05)) sp_mask = (Mc >= 1.05) k_prop[sb_mask] = k_prop_sub # basic interpolation for transonic k_prop[tn_mask] = (k_prop_sup - k_prop_sub) * ( Mc[tn_mask] - Mdiv[tn_mask]) / (1.05 - Mdiv[tn_mask]) + k_prop_sub k_prop[sp_mask] = k_prop_sup # -------------------------------------------------------- # find the final result propulsor_parasite_drag = k_prop * cf_prop * Swet / Sref # -------------------------------------------------------- # dump data to conditions propulsor_result = Results( wetted_area=Swet, reference_area=Sref, parasite_drag_coefficient=propulsor_parasite_drag, skin_friction_coefficient=cf_prop, compressibility_factor=k_comp, reynolds_factor=k_reyn, form_factor=k_prop, ) state.conditions.aerodynamics.drag_breakdown.parasite[ propulsor.tag] = propulsor_result return propulsor_parasite_drag
def parasite_drag_pylon(state,settings,geometry): """Computes the parasite drag due to pylons as a proportion of the propulsor drag Assumptions: Basic fit Source: adg.stanford.edu (Stanford AA241 A/B Course Notes) Inputs: conditions.aerodynamics.drag_breakdown.parasite[propulsor.tag]. form_factor [Unitless] compressibility_factor [Unitless] skin_friction_coefficient [Unitless] wetted_area [m^2] parasite_drag_coefficient [Unitless] reynolds_number [Unitless] geometry.reference_area [m^2] geometry.propulsors. nacelle_diameter [m] number_of_engines [Unitless] Outputs: propulsor_parasite_drag [Unitless] Properties Used: N/A """ # unpack conditions = state.conditions configuration = settings pylon_factor = 0.20 # 20% of propulsor drag n_propulsors = len(geometry.propulsors) # number of propulsive system in vehicle (NOT # of ENGINES) pylon_parasite_drag = 0.00 pylon_wetted_area = 0.00 pylon_cf = 0.00 pylon_compr_fact = 0.00 pylon_rey_fact = 0.00 pylon_FF = 0.00 # Estimating pylon drag for propulsor in geometry.propulsors: ref_area = propulsor.nacelle_diameter**2 / 4 * np.pi pylon_parasite_drag += pylon_factor * conditions.aerodynamics.drag_breakdown.parasite[propulsor.tag].parasite_drag_coefficient* (ref_area/geometry.reference_area * propulsor.number_of_engines) pylon_wetted_area += pylon_factor * conditions.aerodynamics.drag_breakdown.parasite[propulsor.tag].wetted_area * propulsor.number_of_engines pylon_cf += conditions.aerodynamics.drag_breakdown.parasite[propulsor.tag].skin_friction_coefficient pylon_compr_fact += conditions.aerodynamics.drag_breakdown.parasite[propulsor.tag].compressibility_factor pylon_rey_fact += conditions.aerodynamics.drag_breakdown.parasite[propulsor.tag].reynolds_factor pylon_FF += conditions.aerodynamics.drag_breakdown.parasite[propulsor.tag].form_factor pylon_cf /= n_propulsors pylon_compr_fact /= n_propulsors pylon_rey_fact /= n_propulsors pylon_FF /= n_propulsors # dump data to conditions pylon_result = Results( wetted_area = pylon_wetted_area , reference_area = geometry.reference_area , parasite_drag_coefficient = pylon_parasite_drag , skin_friction_coefficient = pylon_cf , compressibility_factor = pylon_compr_fact , reynolds_factor = pylon_rey_fact , form_factor = pylon_FF , ) conditions.aerodynamics.drag_breakdown.parasite['pylon'] = pylon_result return pylon_parasite_drag
def compressibility_drag_wing(state, settings, geometry): """ SUAVE.Methods.compressibility_drag_wing(conditions,configuration,geometry) computes the induced drag associated with a wing Inputs: Outputs: Assumptions: based on a set of fits """ # unpack conditions = state.conditions configuration = settings wing = geometry if wing.tag == 'main_wing': wing_lifts = conditions.aerodynamics.lift_breakdown.compressible_wings # currently the total aircraft lift elif wing.vertical: wing_lifts = 0 else: wing_lifts = 0.15 * conditions.aerodynamics.lift_breakdown.compressible_wings mach = conditions.freestream.mach_number drag_breakdown = conditions.aerodynamics.drag_breakdown # start result total_compressibility_drag = 0.0 # unpack wing t_c_w = wing.thickness_to_chord sweep_w = wing.sweeps.quarter_chord # Currently uses vortex lattice model on all wings if wing.tag == 'main_wing': cl_w = wing_lifts else: cl_w = 0 cos_sweep = np.cos(sweep_w) # get effective Cl and sweep tc = t_c_w / (cos_sweep) cl = cl_w / (cos_sweep * cos_sweep) # compressibility drag based on regressed fits from AA241 mcc_cos_ws = 0.922321524499352 \ - 1.153885166170620*tc \ - 0.304541067183461*cl \ + 0.332881324404729*tc*tc \ + 0.467317361111105*tc*cl \ + 0.087490431201549*cl*cl # crest-critical mach number, corrected for wing sweep mcc = mcc_cos_ws / cos_sweep # divergence mach number MDiv = mcc * (1.02 + 0.08 * (1 - cos_sweep)) # divergence ratio mo_mc = mach / mcc # compressibility correlation, Shevell dcdc_cos3g = 0.0019 * mo_mc**14.641 # compressibility drag cd_c = dcdc_cos3g * cos_sweep * cos_sweep * cos_sweep # increment #total_compressibility_drag += cd_c # dump data to conditions wing_results = Results( compressibility_drag=cd_c, thickness_to_chord=tc, wing_sweep=sweep_w, crest_critical=mcc, divergence_mach=MDiv, ) drag_breakdown.compressible[wing.tag] = wing_results return total_compressibility_drag
def parasite_drag_fuselage(state, settings, geometry): """Computes the parasite drag due to the fuselage Assumptions: Basic fit Source: adg.stanford.edu (Stanford AA241 A/B Course Notes) Inputs: state.conditions.freestream. mach_number [Unitless] temperature [K] reynolds_number [Unitless] settings.fuselage_parasite_drag_form_factor [Unitless] geometry.fuselage. areas.front_projected [m^2] areas.wetted [m^2] lengths.total [m] effective_diameter [m] Outputs: fuselage_parasite_drag [Unitless] Properties Used: N/A """ # unpack inputs configuration = settings form_factor = configuration.fuselage_parasite_drag_form_factor fuselage = geometry freestream = state.conditions.freestream Sref = fuselage.areas.front_projected Swet = fuselage.areas.wetted l_fus = fuselage.lengths.total d_fus = fuselage.effective_diameter # conditions Mc = freestream.mach_number Tc = freestream.temperature re = freestream.reynolds_number # reynolds number Re_fus = re * (l_fus) # skin friction coefficient cf_fus, k_comp, k_reyn = compressible_turbulent_flat_plate(Re_fus, Mc, Tc) # form factor for cylindrical bodies d_d = float(d_fus) / float(l_fus) D = np.array([[0.0]] * len(Mc)) a = np.array([[0.0]] * len(Mc)) du_max_u = np.array([[0.0]] * len(Mc)) k_fus = np.array([[0.0]] * len(Mc)) D[Mc < 0.95] = np.sqrt(1 - (1 - Mc[Mc < 0.95]**2) * d_d**2) a[Mc < 0.95] = 2 * (1 - Mc[Mc < 0.95]**2) * (d_d**2) * ( np.arctanh(D[Mc < 0.95]) - D[Mc < 0.95]) / (D[Mc < 0.95]**3) du_max_u[Mc < 0.95] = a[Mc < 0.95] / ((2 - a[Mc < 0.95]) * (1 - Mc[Mc < 0.95]**2)**0.5) D[Mc >= 0.95] = np.sqrt(1 - d_d**2) a[Mc >= 0.95] = 2 * (d_d**2) * (np.arctanh(D[Mc >= 0.95]) - D[Mc >= 0.95]) / (D[Mc >= 0.95]**3) du_max_u[Mc >= 0.95] = a[Mc >= 0.95] / ((2 - a[Mc >= 0.95])) k_fus = (1 + form_factor * du_max_u)**2 fuselage_parasite_drag = k_fus * cf_fus * Swet / Sref # dump data to conditions fuselage_result = Results( wetted_area=Swet, reference_area=Sref, parasite_drag_coefficient=fuselage_parasite_drag, skin_friction_coefficient=cf_fus, compressibility_factor=k_comp, reynolds_factor=k_reyn, form_factor=k_fus, ) try: state.conditions.aerodynamics.drag_breakdown.parasite[ fuselage.tag] = fuselage_result except: print("Drag Polar Mode fuse parasite") return fuselage_parasite_drag
def evaluate(self, condtitions): return Results()
def compressibility_drag_total(state, settings, geometry): """Computes compressibility drag for full aircraft including volume drag through OpenVSP Assumptions: None Source: adg.stanford.edu (Stanford AA241 A/B Course Notes) Inputs: settings.number_slices settings.number_rotations state.conditions.aerodynamics. lift_breakdown.compressible_wings [-] state.conditions.freestream.mach_number [-] geometry.wings.*.tag Outputs: drag_breakdown.compressible[wing.tag]. divergence_mach [-] drag_breakdown.compressible.total [-] drag_breakdown.compressible.total_volume [-] drag_breakdown.compressible.total_lift [-] cd_c [-] Total compressibility drag Properties Used: N/A """ # Unpack conditions = state.conditions configuration = settings number_slices = settings.number_slices number_rotations = settings.number_rotations wings = geometry.wings fuselages = geometry.fuselages propulsor_name = geometry.propulsors.keys()[ 0] #obtain the key for the propulsor for assignment purposes propulsor = geometry.propulsors[propulsor_name] Mc = conditions.freestream.mach_number drag_breakdown = conditions.aerodynamics.drag_breakdown # Initialize result drag_breakdown.compressible = Results() # Use main wing reference area for drag coefficients Sref_main = geometry.reference_area drag99_total = np.zeros(np.shape(Mc)) drag105_total = np.zeros(np.shape(Mc)) # Iterate through wings for k in wings.keys(): wing = wings[k] # initialize array to correct length cd_c = np.array([[0.0]] * len(Mc)) mcc = np.array([[0.0]] * len(Mc)) MDiv = np.array([[0.0]] * len(Mc)) # Get main fuselage data - note that name of fuselage is important here # This should be changed to be general main_fuselage = fuselages['fuselage'] # Get number of engines data num_engines = propulsor.number_of_engines # Get the lift coefficient of the wing. # Note that this is not the total CL cl = conditions.aerodynamics.lift_breakdown.compressible_wings # Calculate compressibility drag at Mach 0.99 and 1.05 for interpolation between # dummy variables are unused function outputs (drag99, dummy1, dummy2) = drag_div(np.array([[0.99]] * len(Mc)), wing, k, cl, Sref_main) cdc_l = lift_wave_drag(conditions, configuration, wing, k, Sref_main, True) drag99_total = drag99_total + drag99 drag105_total = drag105_total + cdc_l try: old_array = np.load('volume_drag_data_' + geometry.tag + '.npy') file_exists = True except: file_exists = False old_array = np.array([[-1, -1]]) if np.any(old_array[:, 0] == 1.05): cd_c_v = np.array([[float(old_array[old_array[:, 0] == 1.05, 1])]]) else: cd_c_v = wave_drag_volume(conditions, geometry, True) if file_exists: pass else: new_save_row = np.array([[1.05, cd_c_v]]) np.save('volume_drag_data_' + geometry.tag + '.npy', new_save_row) drag105 = drag105_total + cd_c_v * np.ones(np.shape(Mc)) drag99 = drag99_total cd_c_l = np.array([[0.0]] * len(Mc)) # For subsonic mach numbers, use drag divergence correlations to find the drag for k in wings.keys(): wing = wings[k] (a, b, c) = drag_div(Mc[Mc <= 0.99], wing, k, cl[Mc <= 0.99], Sref_main) cd_c[Mc <= 0.99] = cd_c[Mc <= 0.99] + a mcc[Mc <= 0.99] = b MDiv[Mc <= 0.99] = c drag_breakdown.compressible[wing.tag] = Data() drag_breakdown.compressible[wing.tag].divergence_mach = MDiv cd_c_l = lift_wave_drag(conditions, configuration, wing, k, Sref_main, False) + cd_c_l # For mach numbers close to 1, use an interpolation to avoid intensive calculations cd_c[Mc > 0.99] = drag99[Mc > 0.99] + (drag105[Mc > 0.99] - drag99[ Mc > 0.99]) * (Mc[Mc > 0.99] - 0.99) / (1.05 - 0.99) # Use wave drag equations at supersonic values. The cutoff for this function is 1.05 # Only the supsonic results are returned with nonzero values cd_c_v = wave_drag_volume(conditions, geometry, False, num_slices=number_slices, num_rots=number_rotations) cd_c[Mc >= 1.05] = cd_c_l[Mc >= 1.05] + cd_c_v[Mc >= 1.05] # Save drag breakdown drag_breakdown.compressible.total = cd_c drag_breakdown.compressible.total_volume = cd_c_v drag_breakdown.compressible.total_lift = cd_c_l return cd_c