From f48c0bcfbfad8e165ce9c86f703869b6f3f218d0 Mon Sep 17 00:00:00 2001 From: Racheal Erhard Date: Thu, 24 Feb 2022 06:47:39 -0800 Subject: [PATCH 1/6] updating nomenclature --- trunk/SUAVE/Input_Output/VTK/save_prop_vtk.py | 2 +- .../Propulsion/Rotor_Wake/Fidelity_Zero/__init__.py | 4 ++-- ...ty.py => compute_fidelity_zero_induced_velocity.py} | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) rename trunk/SUAVE/Methods/Propulsion/Rotor_Wake/Fidelity_Zero/{compute_bevw_induced_velocity.py => compute_fidelity_zero_induced_velocity.py} (91%) diff --git a/trunk/SUAVE/Input_Output/VTK/save_prop_vtk.py b/trunk/SUAVE/Input_Output/VTK/save_prop_vtk.py index 4326430cc2..6ad5c8318f 100644 --- a/trunk/SUAVE/Input_Output/VTK/save_prop_vtk.py +++ b/trunk/SUAVE/Input_Output/VTK/save_prop_vtk.py @@ -339,7 +339,7 @@ def generate_lofted_propeller_points(prop): a_o = prop.start_angle n_r = len(b) # number radial points - n_a_loft = prop.number_points_around_airfoil # number points around airfoil + n_a_loft = prop.vtk_airfoil_points # number points around airfoil theta = np.linspace(0,2*np.pi,num_B+1)[:-1] # azimuthal stations # create empty data structure for storing propeller geometries diff --git a/trunk/SUAVE/Methods/Propulsion/Rotor_Wake/Fidelity_Zero/__init__.py b/trunk/SUAVE/Methods/Propulsion/Rotor_Wake/Fidelity_Zero/__init__.py index 7fd4dba9d4..884bd3ab90 100644 --- a/trunk/SUAVE/Methods/Propulsion/Rotor_Wake/Fidelity_Zero/__init__.py +++ b/trunk/SUAVE/Methods/Propulsion/Rotor_Wake/Fidelity_Zero/__init__.py @@ -1,5 +1,5 @@ ## @defgroup Methods-Aerodynamics-Rotor_Wake-Fidelity_Zero # Rotor wake methods that are directly specified by analyses. -from .compute_bevw_induced_velocity import compute_bevw_induced_velocity -from .compute_wake_contraction_matrix import compute_wake_contraction_matrix \ No newline at end of file +from .compute_fidelity_zero_induced_velocity import compute_fidelity_zero_induced_velocity +from .compute_wake_contraction_matrix import compute_wake_contraction_matrix \ No newline at end of file diff --git a/trunk/SUAVE/Methods/Propulsion/Rotor_Wake/Fidelity_Zero/compute_bevw_induced_velocity.py b/trunk/SUAVE/Methods/Propulsion/Rotor_Wake/Fidelity_Zero/compute_fidelity_zero_induced_velocity.py similarity index 91% rename from trunk/SUAVE/Methods/Propulsion/Rotor_Wake/Fidelity_Zero/compute_bevw_induced_velocity.py rename to trunk/SUAVE/Methods/Propulsion/Rotor_Wake/Fidelity_Zero/compute_fidelity_zero_induced_velocity.py index 2c230c16f8..9fb211db74 100644 --- a/trunk/SUAVE/Methods/Propulsion/Rotor_Wake/Fidelity_Zero/compute_bevw_induced_velocity.py +++ b/trunk/SUAVE/Methods/Propulsion/Rotor_Wake/Fidelity_Zero/compute_fidelity_zero_induced_velocity.py @@ -1,5 +1,5 @@ ## @ingroup Methods-Aerodynamics-Common-Fidelity_Zero-Lift -# compute_bevw_induced_velocity.py +# compute_fidelity_zero_induced_velocity.py # # Created: Jun 2021, R. Erhard @@ -13,7 +13,7 @@ from SUAVE.Components import Wings ## @ingroup Methods-Aerodynamics-Common-Fidelity_Zero-Lift -def compute_bevw_induced_velocity(props,geometry,cpts,conditions,identical_flag,wing_instance=None): +def compute_fidelity_zero_induced_velocity(props,geometry,cpts,conditions,identical_flag,wing_instance=None): """ This computes the velocity induced by the BEVW wake on lifting surface control points @@ -56,11 +56,11 @@ def compute_bevw_induced_velocity(props,geometry,cpts,conditions,identical_flag, kd = 1 + s/(np.sqrt(s**2 + R**2)) if nmw ==1: pass - #print("No wing specified for wake analysis in compute_bevw_induced_velocity. Main wing is used.") + #print("No wing specified for wake analysis in compute_fidelity_zero_induced_velocity. Main wing is used.") elif nmw>1: - print("No wing specified for wake analysis in compute_bevw_induced_velocity. Multiple main wings, using the last one.") + print("No wing specified for wake analysis in compute_fidelity_zero_induced_velocity. Multiple main wings, using the last one.") else: - print("No wing specified for wake analysis in compute_bevw_induced_velocity. No main_wing defined! Using last wing found.") + print("No wing specified for wake analysis in compute_fidelity_zero_induced_velocity. No main_wing defined! Using last wing found.") s = wing.origin[0][0] - prop.origin[0][0] kd = 1 + s/(np.sqrt(s**2 + R**2)) From 7328f077ac90171067fae9dd38a1988938a3cf91 Mon Sep 17 00:00:00 2001 From: Racheal Erhard Date: Thu, 24 Feb 2022 08:34:56 -0800 Subject: [PATCH 2/6] temp --- .../Propulsion/Rotor_Wake_Fidelity_Zero.py | 55 +++++++++++- .../Fidelity_Zero/Lift/extract_wing_VD.py | 50 +++++++++++ .../compute_fidelity_zero_induced_velocity.py | 43 +++------ .../compute_fidelity_zero_slipstream.py | 90 +++++++++++++++++++ 4 files changed, 206 insertions(+), 32 deletions(-) create mode 100644 trunk/SUAVE/Methods/Aerodynamics/Common/Fidelity_Zero/Lift/extract_wing_VD.py create mode 100644 trunk/SUAVE/Methods/Propulsion/Rotor_Wake/Fidelity_Zero/compute_fidelity_zero_slipstream.py diff --git a/trunk/SUAVE/Analyses/Propulsion/Rotor_Wake_Fidelity_Zero.py b/trunk/SUAVE/Analyses/Propulsion/Rotor_Wake_Fidelity_Zero.py index de0b932bed..89bc4a667c 100644 --- a/trunk/SUAVE/Analyses/Propulsion/Rotor_Wake_Fidelity_Zero.py +++ b/trunk/SUAVE/Analyses/Propulsion/Rotor_Wake_Fidelity_Zero.py @@ -11,9 +11,12 @@ from SUAVE.Components.Energy.Energy_Component import Energy_Component +from SUAVE.Components import Wings from SUAVE.Methods.Propulsion.Rotor_Wake.Fidelity_Zero.fidelity_zero_wake_convergence import fidelity_zero_wake_convergence -from SUAVE.Methods.Propulsion.Rotor_Wake.Fidelity_Zero.compute_bevw_induced_velocity import compute_bevw_induced_velocity +from SUAVE.Methods.Propulsion.Rotor_Wake.Fidelity_Zero.compute_fidelity_zero_induced_velocity import compute_fidelity_zero_induced_velocity +from SUAVE.Methods.Propulsion.Rotor_Wake.Fidelity_Zero.compute_fidelity_zero_slipstream import compute_fidelity_zero_slipstream +from SUAVE.Methods.Aerodynamics.Common.Fidelity_Zero.Lift.extract_wing_VD import extract_wing_collocation_points # ---------------------------------------------------------------------- # Generalized Rotor Class @@ -88,6 +91,54 @@ def evaluate(self,rotor,wake_inputs,conditions): return va, vt + def evaluate_slipstream(self,rotor,geometry,wing_instance=None): + """ + Evaluates the velocities induced by the rotor on a specified wing of the vehicle. + If no wing instance is specified, uses main wing or last available wing in geometry. + + Assumptions: + None + + Source: + N/A + + Inputs: + self - rotor wake + rotor - rotor + geometry - vehicle geometry + + Outputs: + prop_V_wake_ind - induced velocity from rotor wake at (VD.XC, VD.YC, VD.ZC) + + Properties Used: + None + """ + # Check for wing if wing instance is unspecified + if wing_instance == None: + nmw = 0 + # check for main wing + for i,wing in enumerate(geometry.wings): + if not isinstance(wing,Wings.Main_Wing): continue + nmw +=1 + wing_instance = wing + wing_instance_idx = i + if nmw == 1: + pass + elif nmw>1: + print("No wing specified for slipstream analysis. Multiple main wings in vehicle, using the last one.") + else: + print("No wing specified for slipstream analysis. No main wing defined, using the last wing in vehicle.") + wing_instance = wing + wing_instance_idx = i + + # Isolate the VD components corresponding to this wing instance + wing_CPs = extract_wing_collocation_points(geometry, wing_instance_idx) + + # Evaluate rotor slipstream effect on specified wing instance + compute_fidelity_zero_slipstream(wing_CPs,rotor,wing_instance) + + return + def evaluate_wake_velocities(self,rotor,network,geometry,conditions,VD,num_ctrl_pts): """ Links the rotor wake to compute the wake-induced velocities at the vortex distribution @@ -122,7 +173,7 @@ def evaluate_wake_velocities(self,rotor,network,geometry,conditions,VD,num_ctrl_ else: rots = Data() rots.append(rotor) - rot_V_wake_ind = compute_bevw_induced_velocity(rots,geometry,num_ctrl_pts,conditions,identical_flag) + rot_V_wake_ind = compute_fidelity_zero_induced_velocity(rots,geometry,num_ctrl_pts,conditions,identical_flag) return rot_V_wake_ind \ No newline at end of file diff --git a/trunk/SUAVE/Methods/Aerodynamics/Common/Fidelity_Zero/Lift/extract_wing_VD.py b/trunk/SUAVE/Methods/Aerodynamics/Common/Fidelity_Zero/Lift/extract_wing_VD.py new file mode 100644 index 0000000000..ede0ce5cb3 --- /dev/null +++ b/trunk/SUAVE/Methods/Aerodynamics/Common/Fidelity_Zero/Lift/extract_wing_VD.py @@ -0,0 +1,50 @@ +## @ingroup Methods-Aerodynamics-Common-Fidelity_Zero-Lift +# extract_wing_collocation_points.py +# +# Created: Feb 2022, R. Erhard +# Modified: + +# ---------------------------------------------------------------------- +# Imports +# ---------------------------------------------------------------------- + +# package imports +import numpy as np +from SUAVE.Core import Data + +## @ingroup Methods-Aerodynamics-Common-Fidelity_Zero-Lift +def extract_wing_collocation_points(geometry, wing_instance_idx): + + """ This extracts the collocation points of the vehicle vortex distribution + belonging to the specified wing instance index. This is used for + + Source: + None + + Inputs: + geometry - SUAVE vehicle + wing_instance - wing instance to extract VD for + + Outputs: + None + + Properties Used: + N/A + """ + + # unpack + VD = geometry.vortex_distribution + n_w = VD.n_w + n_cp = VD.n_cp + n_sw = VD.n_sw + n_cw = VD.n_cw + + VD_wing = Data() + VD_wing.XC = VD.XC + VD_wing.YC = VD.YC + VD_wing.ZC = VD.ZC + + + return VD_wing + + diff --git a/trunk/SUAVE/Methods/Propulsion/Rotor_Wake/Fidelity_Zero/compute_fidelity_zero_induced_velocity.py b/trunk/SUAVE/Methods/Propulsion/Rotor_Wake/Fidelity_Zero/compute_fidelity_zero_induced_velocity.py index 9fb211db74..7974d30047 100644 --- a/trunk/SUAVE/Methods/Propulsion/Rotor_Wake/Fidelity_Zero/compute_fidelity_zero_induced_velocity.py +++ b/trunk/SUAVE/Methods/Propulsion/Rotor_Wake/Fidelity_Zero/compute_fidelity_zero_induced_velocity.py @@ -10,12 +10,11 @@ # package imports import numpy as np from scipy.interpolate import interp1d -from SUAVE.Components import Wings ## @ingroup Methods-Aerodynamics-Common-Fidelity_Zero-Lift -def compute_fidelity_zero_induced_velocity(props,geometry,cpts,conditions,identical_flag,wing_instance=None): - """ This computes the velocity induced by the BEVW wake - on lifting surface control points +def compute_fidelity_zero_induced_velocity(evaluation_points, ): + """ This computes the velocity induced by the fidelity zero wake + on specified evaluation points. Assumptions: The wake contracts following formulation by McCormick. @@ -24,7 +23,11 @@ def compute_fidelity_zero_induced_velocity(props,geometry,cpts,conditions,identi Contraction factor: McCormick 1969, Aerodynamics of V/STOL Flight Inputs: - prop - propeller or rotor data structure [Unitless] + evaluation_points. + XC - X-location of evaluation points (vehicle frame) [m] + YC - Y-location of evaluation points (vehicle frame) [m] + ZC - Z-location of evaluation points (vehicle frame) [m] + geometry - SUAVE vehicle [Unitless] cpts - control points in segment [Unitless] Properties Used: @@ -32,7 +35,6 @@ def compute_fidelity_zero_induced_velocity(props,geometry,cpts,conditions,identi """ # extract vortex distribution - VD = geometry.vortex_distribution # initialize propeller wake induced velocities prop_V_wake_ind = np.zeros((cpts,VD.n_cp,3)) @@ -46,27 +48,8 @@ def compute_fidelity_zero_induced_velocity(props,geometry,cpts,conditions,identi prop_outputs = props[prop_key].outputs R = prop.tip_radius - # contraction factor by McCormick - if wing_instance == None: - nmw = 0 - for wing in geometry.wings: - if not isinstance(wing,Wings.Main_Wing): continue - nmw = nmw+1 - s = wing.origin[0][0] - prop.origin[0][0] - kd = 1 + s/(np.sqrt(s**2 + R**2)) - if nmw ==1: - pass - #print("No wing specified for wake analysis in compute_fidelity_zero_induced_velocity. Main wing is used.") - elif nmw>1: - print("No wing specified for wake analysis in compute_fidelity_zero_induced_velocity. Multiple main wings, using the last one.") - else: - print("No wing specified for wake analysis in compute_fidelity_zero_induced_velocity. No main_wing defined! Using last wing found.") - s = wing.origin[0][0] - prop.origin[0][0] - kd = 1 + s/(np.sqrt(s**2 + R**2)) - - else: - s = wing_instance.origin[0][0] - prop.origin[0][0] - kd = 1 + s/(np.sqrt(s**2 + R**2)) + s = evaluation_points.XC - prop.origin[0][0] + kd = 1 + s/(np.sqrt(s**2 + R**2)) # extract radial and azimuthal velocities at blade va = kd*prop_outputs.blade_axial_induced_velocity[0] @@ -79,10 +62,10 @@ def compute_fidelity_zero_induced_velocity(props,geometry,cpts,conditions,identi prop_y_range = np.append(inboard_r, outboard_r) # within this range, add an induced x- and z- velocity from propeller wake - bool_inboard = ( VD.YC > inboard_r[0] ) * ( VD.YC < inboard_r[-1] ) - bool_outboard = ( VD.YC > outboard_r[0] ) * ( VD.YC < outboard_r[-1] ) + bool_inboard = ( evaluation_points.YC > inboard_r[0] ) * ( evaluation_points.YC < inboard_r[-1] ) + bool_outboard = ( evaluation_points.YC > outboard_r[0] ) * ( evaluation_points.YC < outboard_r[-1] ) bool_in_range = bool_inboard + bool_outboard - YC_in_range = VD.YC[bool_in_range] + YC_in_range = evaluation_points.YC[bool_in_range] va_y_range = np.append(np.flipud(va), va) vt_y_range = np.append(np.flipud(vt), vt)*prop.rotation diff --git a/trunk/SUAVE/Methods/Propulsion/Rotor_Wake/Fidelity_Zero/compute_fidelity_zero_slipstream.py b/trunk/SUAVE/Methods/Propulsion/Rotor_Wake/Fidelity_Zero/compute_fidelity_zero_slipstream.py new file mode 100644 index 0000000000..918c311d32 --- /dev/null +++ b/trunk/SUAVE/Methods/Propulsion/Rotor_Wake/Fidelity_Zero/compute_fidelity_zero_slipstream.py @@ -0,0 +1,90 @@ +## @ingroup Methods-Aerodynamics-Common-Fidelity_Zero-Lift +# compute_fidelity_zero_slipstream.py +# +# Created: Jun 2021, R. Erhard + +# ---------------------------------------------------------------------- +# Imports +# ---------------------------------------------------------------------- + +# package imports +import numpy as np +from scipy.interpolate import interp1d + +## @ingroup Methods-Aerodynamics-Common-Fidelity_Zero-Lift +def compute_fidelity_zero_slipstream(props,geometry,cpts,conditions,identical_flag,wing_instance=None): + """ This computes the velocity induced by the BEVW wake + on lifting surface control points + + Assumptions: + The wake contracts following formulation by McCormick. + + Source: + Contraction factor: McCormick 1969, Aerodynamics of V/STOL Flight + + Inputs: + prop - propeller or rotor data structure [Unitless] + geometry - SUAVE vehicle [Unitless] + cpts - control points in segment [Unitless] + Properties Used: + N/A + """ + + # extract vortex distribution + VD = geometry.vortex_distribution # this needs to be just for the wing_instance + + # initialize propeller wake induced velocities + prop_V_wake_ind = np.zeros((cpts,VD.n_cp,3)) + + for i,prop in enumerate(props): + if identical_flag: + idx = 0 + else: + idx = i + prop_key = list(props.keys())[idx] + prop_outputs = props[prop_key].outputs + R = prop.tip_radius + + # contraction factor by McCormick + s = wing_instance.origin[0][0] - prop.origin[0][0] + kd = 1 + s/(np.sqrt(s**2 + R**2)) + + # extract radial and azimuthal velocities at blade + va = kd*prop_outputs.blade_axial_induced_velocity[0] + vt = kd*prop_outputs.blade_tangential_induced_velocity[0] + r = prop_outputs.disc_radial_distribution[0,:,0] + + hub_y_center = prop.origin[0][1] + inboard_r = np.flip(hub_y_center - r) + outboard_r = hub_y_center + r + prop_y_range = np.append(inboard_r, outboard_r) + + # within this range, add an induced x- and z- velocity from propeller wake + bool_inboard = ( VD.YC > inboard_r[0] ) * ( VD.YC < inboard_r[-1] ) + bool_outboard = ( VD.YC > outboard_r[0] ) * ( VD.YC < outboard_r[-1] ) + bool_in_range = bool_inboard + bool_outboard + YC_in_range = VD.YC[bool_in_range] + + va_y_range = np.append(np.flipud(va), va) + vt_y_range = np.append(np.flipud(vt), vt)*prop.rotation + va_interp = interp1d(prop_y_range, va_y_range) + vt_interp = interp1d(prop_y_range, vt_y_range) + + y_vals = YC_in_range + val_ids = np.where(bool_in_range==True) + + # preallocate va_new and vt_new + va_new = va_interp((y_vals)) + vt_new = np.zeros(np.size(val_ids)) + + # invert inboard vt values + inboard_bools = (y_vals < hub_y_center) + vt_new[inboard_bools] = -vt_interp((y_vals[inboard_bools])) + vt_new[inboard_bools==False] = vt_interp((y_vals[inboard_bools==False])) + + prop_V_wake_ind[0,val_ids,0] = va_new # axial induced velocity + prop_V_wake_ind[0,val_ids,1] = 0 # spanwise induced velocity; in line with prop, so 0 + prop_V_wake_ind[0,val_ids,2] = vt_new # vertical induced velocity + + return prop_V_wake_ind + From 35f58aa2127b418f222b5355ad9f49751e8d440e Mon Sep 17 00:00:00 2001 From: Racheal Erhard Date: Fri, 25 Feb 2022 05:18:42 -0800 Subject: [PATCH 3/6] separating fidelity zero induced velocity from slipstream analysis --- .../Propulsion/Rotor_Wake_Fidelity_Zero.py | 32 +++++++------------ .../Fidelity_Zero/Lift/compute_RHS_matrix.py | 4 +-- .../compute_fidelity_zero_induced_velocity.py | 7 ++-- 3 files changed, 18 insertions(+), 25 deletions(-) diff --git a/trunk/SUAVE/Analyses/Propulsion/Rotor_Wake_Fidelity_Zero.py b/trunk/SUAVE/Analyses/Propulsion/Rotor_Wake_Fidelity_Zero.py index 89bc4a667c..01cbd10c86 100644 --- a/trunk/SUAVE/Analyses/Propulsion/Rotor_Wake_Fidelity_Zero.py +++ b/trunk/SUAVE/Analyses/Propulsion/Rotor_Wake_Fidelity_Zero.py @@ -14,7 +14,6 @@ from SUAVE.Components import Wings from SUAVE.Methods.Propulsion.Rotor_Wake.Fidelity_Zero.fidelity_zero_wake_convergence import fidelity_zero_wake_convergence from SUAVE.Methods.Propulsion.Rotor_Wake.Fidelity_Zero.compute_fidelity_zero_induced_velocity import compute_fidelity_zero_induced_velocity -from SUAVE.Methods.Propulsion.Rotor_Wake.Fidelity_Zero.compute_fidelity_zero_slipstream import compute_fidelity_zero_slipstream from SUAVE.Methods.Aerodynamics.Common.Fidelity_Zero.Lift.extract_wing_VD import extract_wing_collocation_points @@ -135,14 +134,14 @@ def evaluate_slipstream(self,rotor,geometry,wing_instance=None): wing_CPs = extract_wing_collocation_points(geometry, wing_instance_idx) # Evaluate rotor slipstream effect on specified wing instance - compute_fidelity_zero_slipstream(wing_CPs,rotor,wing_instance) + rot_V_wake_ind = self.evaluate_wake_velocities(rotor, geometry, wing_CPs) - return + return rot_V_wake_ind - def evaluate_wake_velocities(self,rotor,network,geometry,conditions,VD,num_ctrl_pts): + def evaluate_wake_velocities(self,rotor,evaluation_points): """ - Links the rotor wake to compute the wake-induced velocities at the vortex distribution - control points. + Links the rotor wake to compute the wake-induced velocities at the specified + evaluation points. Assumptions: None @@ -151,13 +150,9 @@ def evaluate_wake_velocities(self,rotor,network,geometry,conditions,VD,num_ctrl_ N/A Inputs: - self - rotor wake - rotor - rotor - network - propulsion network - geometry - vehicle geometry - conditions - conditions - VD - vortex distribution - num_ctrl_pts - number of analysis control points + self - rotor wake + rotor - rotor + evaluation_points - points at which to evaluate the rotor wake-induced velocities Outputs: prop_V_wake_ind - induced velocity from rotor wake at (VD.XC, VD.YC, VD.ZC) @@ -166,14 +161,9 @@ def evaluate_wake_velocities(self,rotor,network,geometry,conditions,VD,num_ctrl_ None """ - identical_flag = network.identical_propellers - - if network.number_of_propeller_engines == None: - pass - else: - rots = Data() - rots.append(rotor) - rot_V_wake_ind = compute_fidelity_zero_induced_velocity(rots,geometry,num_ctrl_pts,conditions,identical_flag) + rots = Data() + rots.append(rotor) + rot_V_wake_ind = compute_fidelity_zero_induced_velocity(evaluation_points,rots) return rot_V_wake_ind \ No newline at end of file diff --git a/trunk/SUAVE/Methods/Aerodynamics/Common/Fidelity_Zero/Lift/compute_RHS_matrix.py b/trunk/SUAVE/Methods/Aerodynamics/Common/Fidelity_Zero/Lift/compute_RHS_matrix.py index 7ed66de280..09fd7019e1 100644 --- a/trunk/SUAVE/Methods/Aerodynamics/Common/Fidelity_Zero/Lift/compute_RHS_matrix.py +++ b/trunk/SUAVE/Methods/Aerodynamics/Common/Fidelity_Zero/Lift/compute_RHS_matrix.py @@ -94,7 +94,7 @@ def compute_RHS_matrix(delta,phi,conditions,settings,geometry,propeller_wake_mod prop_V_wake_ind = np.zeros((num_ctrl_pts,num_eval_pts,3)) for p in props: - prop_V_wake_ind += p.Wake.evaluate_wake_velocities(p,network,geometry,conditions,VD,num_ctrl_pts) + prop_V_wake_ind += p.Wake.evaluate_slipstream(p,geometry) if 'lift_rotors' in network.keys(): @@ -103,7 +103,7 @@ def compute_RHS_matrix(delta,phi,conditions,settings,geometry,propeller_wake_mod rot_V_wake_ind = np.zeros((num_ctrl_pts,num_eval_pts,3)) for r in rots: - rot_V_wake_ind += r.Wake.evaluate_wake_velocities(r,network,geometry,conditions,VD,num_ctrl_pts) + rot_V_wake_ind += r.Wake.evaluate_slipstream(r,geometry) # update the total induced velocity distribution diff --git a/trunk/SUAVE/Methods/Propulsion/Rotor_Wake/Fidelity_Zero/compute_fidelity_zero_induced_velocity.py b/trunk/SUAVE/Methods/Propulsion/Rotor_Wake/Fidelity_Zero/compute_fidelity_zero_induced_velocity.py index 7974d30047..fe4bc4c3ab 100644 --- a/trunk/SUAVE/Methods/Propulsion/Rotor_Wake/Fidelity_Zero/compute_fidelity_zero_induced_velocity.py +++ b/trunk/SUAVE/Methods/Propulsion/Rotor_Wake/Fidelity_Zero/compute_fidelity_zero_induced_velocity.py @@ -12,7 +12,7 @@ from scipy.interpolate import interp1d ## @ingroup Methods-Aerodynamics-Common-Fidelity_Zero-Lift -def compute_fidelity_zero_induced_velocity(evaluation_points, ): +def compute_fidelity_zero_induced_velocity(evaluation_points, props, identical_flag=False): """ This computes the velocity induced by the fidelity zero wake on specified evaluation points. @@ -35,9 +35,10 @@ def compute_fidelity_zero_induced_velocity(evaluation_points, ): """ # extract vortex distribution + n_cp = len(evaluation_points.XC) # initialize propeller wake induced velocities - prop_V_wake_ind = np.zeros((cpts,VD.n_cp,3)) + prop_V_wake_ind = np.zeros((1,n_cp,3)) for i,prop in enumerate(props): if identical_flag: @@ -56,6 +57,7 @@ def compute_fidelity_zero_induced_velocity(evaluation_points, ): vt = kd*prop_outputs.blade_tangential_induced_velocity[0] r = prop_outputs.disc_radial_distribution[0,:,0] + # Ignore points within hub or outside tip radius hub_y_center = prop.origin[0][1] inboard_r = np.flip(hub_y_center - r) outboard_r = hub_y_center + r @@ -66,6 +68,7 @@ def compute_fidelity_zero_induced_velocity(evaluation_points, ): bool_outboard = ( evaluation_points.YC > outboard_r[0] ) * ( evaluation_points.YC < outboard_r[-1] ) bool_in_range = bool_inboard + bool_outboard YC_in_range = evaluation_points.YC[bool_in_range] + va_y_range = np.append(np.flipud(va), va) vt_y_range = np.append(np.flipud(vt), vt)*prop.rotation From 0efe1a7a53617407117aa99d8074a40b5dcef175 Mon Sep 17 00:00:00 2001 From: Racheal Erhard Date: Fri, 25 Feb 2022 06:27:33 -0800 Subject: [PATCH 4/6] finalized slipstream change for fidelity zero --- .../Propulsion/Rotor_Wake_Fidelity_Zero.py | 20 ++++++---- .../Fidelity_Zero/Lift/compute_RHS_matrix.py | 4 +- .../Fidelity_Zero/Lift/extract_wing_VD.py | 39 ++++++++++++++----- .../compute_fidelity_zero_induced_velocity.py | 4 +- 4 files changed, 46 insertions(+), 21 deletions(-) diff --git a/trunk/SUAVE/Analyses/Propulsion/Rotor_Wake_Fidelity_Zero.py b/trunk/SUAVE/Analyses/Propulsion/Rotor_Wake_Fidelity_Zero.py index 01cbd10c86..386ba1d126 100644 --- a/trunk/SUAVE/Analyses/Propulsion/Rotor_Wake_Fidelity_Zero.py +++ b/trunk/SUAVE/Analyses/Propulsion/Rotor_Wake_Fidelity_Zero.py @@ -17,6 +17,7 @@ from SUAVE.Methods.Aerodynamics.Common.Fidelity_Zero.Lift.extract_wing_VD import extract_wing_collocation_points +import numpy as np # ---------------------------------------------------------------------- # Generalized Rotor Class # ---------------------------------------------------------------------- @@ -90,7 +91,7 @@ def evaluate(self,rotor,wake_inputs,conditions): return va, vt - def evaluate_slipstream(self,rotor,geometry,wing_instance=None): + def evaluate_slipstream(self,rotor,geometry,ctrl_pts,wing_instance=None): """ Evaluates the velocities induced by the rotor on a specified wing of the vehicle. If no wing instance is specified, uses main wing or last available wing in geometry. @@ -107,7 +108,7 @@ def evaluate_slipstream(self,rotor,geometry,wing_instance=None): geometry - vehicle geometry Outputs: - prop_V_wake_ind - induced velocity from rotor wake at (VD.XC, VD.YC, VD.ZC) + wake_V_ind - induced velocity from rotor wake at (VD.XC, VD.YC, VD.ZC) Properties Used: None @@ -131,14 +132,19 @@ def evaluate_slipstream(self,rotor,geometry,wing_instance=None): wing_instance_idx = i # Isolate the VD components corresponding to this wing instance - wing_CPs = extract_wing_collocation_points(geometry, wing_instance_idx) + wing_CPs, slipstream_vd_ids = extract_wing_collocation_points(geometry, wing_instance_idx) # Evaluate rotor slipstream effect on specified wing instance - rot_V_wake_ind = self.evaluate_wake_velocities(rotor, geometry, wing_CPs) + rot_V_wake_ind = self.evaluate_wake_velocities(rotor, wing_CPs,ctrl_pts) + + # Expand + wake_V_ind = np.zeros((ctrl_pts,geometry.vortex_distribution.n_cp,3)) + wake_V_ind[:,slipstream_vd_ids,:] = rot_V_wake_ind + - return rot_V_wake_ind + return wake_V_ind - def evaluate_wake_velocities(self,rotor,evaluation_points): + def evaluate_wake_velocities(self,rotor,evaluation_points,ctrl_pts): """ Links the rotor wake to compute the wake-induced velocities at the specified evaluation points. @@ -163,7 +169,7 @@ def evaluate_wake_velocities(self,rotor,evaluation_points): rots = Data() rots.append(rotor) - rot_V_wake_ind = compute_fidelity_zero_induced_velocity(evaluation_points,rots) + rot_V_wake_ind = compute_fidelity_zero_induced_velocity(evaluation_points,rots,ctrl_pts) return rot_V_wake_ind \ No newline at end of file diff --git a/trunk/SUAVE/Methods/Aerodynamics/Common/Fidelity_Zero/Lift/compute_RHS_matrix.py b/trunk/SUAVE/Methods/Aerodynamics/Common/Fidelity_Zero/Lift/compute_RHS_matrix.py index 09fd7019e1..8a107f0188 100644 --- a/trunk/SUAVE/Methods/Aerodynamics/Common/Fidelity_Zero/Lift/compute_RHS_matrix.py +++ b/trunk/SUAVE/Methods/Aerodynamics/Common/Fidelity_Zero/Lift/compute_RHS_matrix.py @@ -94,7 +94,7 @@ def compute_RHS_matrix(delta,phi,conditions,settings,geometry,propeller_wake_mod prop_V_wake_ind = np.zeros((num_ctrl_pts,num_eval_pts,3)) for p in props: - prop_V_wake_ind += p.Wake.evaluate_slipstream(p,geometry) + prop_V_wake_ind += p.Wake.evaluate_slipstream(p,geometry,num_ctrl_pts) if 'lift_rotors' in network.keys(): @@ -103,7 +103,7 @@ def compute_RHS_matrix(delta,phi,conditions,settings,geometry,propeller_wake_mod rot_V_wake_ind = np.zeros((num_ctrl_pts,num_eval_pts,3)) for r in rots: - rot_V_wake_ind += r.Wake.evaluate_slipstream(r,geometry) + rot_V_wake_ind += r.Wake.evaluate_slipstream(r,geometry,num_ctrl_pts) # update the total induced velocity distribution diff --git a/trunk/SUAVE/Methods/Aerodynamics/Common/Fidelity_Zero/Lift/extract_wing_VD.py b/trunk/SUAVE/Methods/Aerodynamics/Common/Fidelity_Zero/Lift/extract_wing_VD.py index ede0ce5cb3..db8c910bfc 100644 --- a/trunk/SUAVE/Methods/Aerodynamics/Common/Fidelity_Zero/Lift/extract_wing_VD.py +++ b/trunk/SUAVE/Methods/Aerodynamics/Common/Fidelity_Zero/Lift/extract_wing_VD.py @@ -31,20 +31,39 @@ def extract_wing_collocation_points(geometry, wing_instance_idx): Properties Used: N/A """ - - # unpack - VD = geometry.vortex_distribution - n_w = VD.n_w - n_cp = VD.n_cp + # unpack vortex distribution properties + VD = geometry.vortex_distribution n_sw = VD.n_sw n_cw = VD.n_cw + + VD_wing = Data() + vd_i = 0 # count of current VD wing elements + j = 0 # count of current VD wing index + size = n_cw * n_sw - VD_wing = Data() - VD_wing.XC = VD.XC - VD_wing.YC = VD.YC - VD_wing.ZC = VD.ZC + for idx,wing in enumerate(geometry.wings): + + if wing.symmetric: + wing_cp_size = size[j] + size[j+1] + j += 2 + else: + wing_cp_size = size[j] + j += 1 + + if idx == wing_instance_idx: + # store the VD corresponding to this wing + VD_wing.XC = VD.XC[vd_i : vd_i + wing_cp_size] + VD_wing.YC = VD.YC[vd_i : vd_i + wing_cp_size] + VD_wing.ZC = VD.ZC[vd_i : vd_i + wing_cp_size] + + ids = (np.linspace(vd_i, vd_i+wing_cp_size-1, wing_cp_size)).astype(int) + + vd_i += wing_cp_size + + # extract VD elements for vd_ele + - return VD_wing + return VD_wing, ids diff --git a/trunk/SUAVE/Methods/Propulsion/Rotor_Wake/Fidelity_Zero/compute_fidelity_zero_induced_velocity.py b/trunk/SUAVE/Methods/Propulsion/Rotor_Wake/Fidelity_Zero/compute_fidelity_zero_induced_velocity.py index fe4bc4c3ab..41b9ceb34a 100644 --- a/trunk/SUAVE/Methods/Propulsion/Rotor_Wake/Fidelity_Zero/compute_fidelity_zero_induced_velocity.py +++ b/trunk/SUAVE/Methods/Propulsion/Rotor_Wake/Fidelity_Zero/compute_fidelity_zero_induced_velocity.py @@ -12,7 +12,7 @@ from scipy.interpolate import interp1d ## @ingroup Methods-Aerodynamics-Common-Fidelity_Zero-Lift -def compute_fidelity_zero_induced_velocity(evaluation_points, props, identical_flag=False): +def compute_fidelity_zero_induced_velocity(evaluation_points, props, ctrl_pts, identical_flag=False): """ This computes the velocity induced by the fidelity zero wake on specified evaluation points. @@ -38,7 +38,7 @@ def compute_fidelity_zero_induced_velocity(evaluation_points, props, identical_f n_cp = len(evaluation_points.XC) # initialize propeller wake induced velocities - prop_V_wake_ind = np.zeros((1,n_cp,3)) + prop_V_wake_ind = np.zeros((ctrl_pts,n_cp,3)) for i,prop in enumerate(props): if identical_flag: From ec4a2b2cfe45c41f2f25227e89e470e5f4d6fc9a Mon Sep 17 00:00:00 2001 From: Racheal Erhard Date: Fri, 25 Feb 2022 06:58:39 -0800 Subject: [PATCH 5/6] update to slipstream evaluation analysis and methods for fidelity one wakes --- .../scripts/slipstream/slipstream_test.py | 22 +++---- .../Propulsion/Rotor_Wake_Fidelity_One.py | 63 +++++++++++++++++-- .../Fidelity_Zero/Lift/extract_wing_VD.py | 7 ++- .../compute_fidelity_zero_induced_velocity.py | 27 ++++---- 4 files changed, 87 insertions(+), 32 deletions(-) diff --git a/regression/scripts/slipstream/slipstream_test.py b/regression/scripts/slipstream/slipstream_test.py index 27d172586f..e94f86d2c1 100644 --- a/regression/scripts/slipstream/slipstream_test.py +++ b/regression/scripts/slipstream/slipstream_test.py @@ -117,14 +117,14 @@ def regress_1b(results, configs): sectional_lift_coeff = results.segments.cruise.conditions.aerodynamics.lift_breakdown.inviscid_wings_sectional[0] # lift coefficient and sectional lift coefficient check - lift_coefficient_true = 0.43754861958748476 - sectional_lift_coeff_true = np.array([ 4.40811415e-01, 3.58447605e-01, 3.53758756e-01, 3.05402561e-01, - 5.87270843e-02, 4.49276571e-01, 3.95135393e-01, 3.67274586e-01, - 3.11407447e-01, 5.99032728e-02, -6.60176707e-02, -6.27939836e-02, - -5.54634997e-02, -4.12681130e-02, -2.43572153e-02, -7.26029863e-02, - -7.03806008e-02, -6.17510582e-02, -4.64116740e-02, -2.76739451e-02, - 3.50749550e-07, 1.99325526e-09, 1.55733197e-09, 4.01202494e-09, - 2.44844282e-09]) + lift_coefficient_true = 0.43754882067868917 + sectional_lift_coeff_true = np.array([ 4.40783762e-01, 3.58418575e-01, 3.53731767e-01, 3.05377941e-01, + 5.87221701e-02, 4.49249435e-01, 3.95108681e-01, 3.67248534e-01, + 3.11383278e-01, 5.98984462e-02, -6.58338027e-02, -6.26213370e-02, + -5.53134063e-02, -4.11543791e-02, -2.42887824e-02, -7.24163411e-02, + -7.02015156e-02, -6.15927770e-02, -4.62903773e-02, -2.76006287e-02, + 3.50583837e-07, 1.98446900e-09, 1.57066352e-09, 4.03406286e-09, + 2.45046493e-09]) diff_CL = np.abs(lift_coefficient - lift_coefficient_true) print('CL difference') @@ -208,9 +208,9 @@ def Lift_Rotor_Slipstream(wake_fidelity): def regress_2(results): - CL_truth = 0.41609632 - CDi_truth = 0.00826812 - CM_truth = 0.3235729 + CL_truth = 0.41618253 + CDi_truth = 0.00703032 + CM_truth = 0.32351636 CL = results.CL CDi = results.CDi diff --git a/trunk/SUAVE/Analyses/Propulsion/Rotor_Wake_Fidelity_One.py b/trunk/SUAVE/Analyses/Propulsion/Rotor_Wake_Fidelity_One.py index cf5ed186da..6a28928313 100644 --- a/trunk/SUAVE/Analyses/Propulsion/Rotor_Wake_Fidelity_One.py +++ b/trunk/SUAVE/Analyses/Propulsion/Rotor_Wake_Fidelity_One.py @@ -8,14 +8,17 @@ # Imports # ---------------------------------------------------------------------- from SUAVE.Core import Data +from SUAVE.Components import Wings from SUAVE.Components.Energy.Energy_Component import Energy_Component from SUAVE.Analyses.Propulsion.Rotor_Wake_Fidelity_Zero import Rotor_Wake_Fidelity_Zero from SUAVE.Methods.Propulsion.Rotor_Wake.Fidelity_One.fidelity_one_wake_convergence import fidelity_one_wake_convergence from SUAVE.Methods.Propulsion.Rotor_Wake.Fidelity_One.compute_wake_induced_velocity import compute_wake_induced_velocity +from SUAVE.Methods.Aerodynamics.Common.Fidelity_Zero.Lift.extract_wing_VD import extract_wing_collocation_points + # package imports import copy - +import numpy as np # ---------------------------------------------------------------------- # Generalized Rotor Class # ---------------------------------------------------------------------- @@ -153,7 +156,60 @@ def evaluate(self,rotor,wake_inputs,conditions): return va, vt - def evaluate_wake_velocities(self,rotor,network,geometry,conditions,VD,num_ctrl_pts): + def evaluate_slipstream(self,rotor,geometry,ctrl_pts,wing_instance=None): + """ + Evaluates the velocities induced by the rotor on a specified wing of the vehicle. + If no wing instance is specified, uses main wing or last available wing in geometry. + + Assumptions: + None + + Source: + N/A + + Inputs: + self - rotor wake + rotor - rotor + geometry - vehicle geometry + + Outputs: + wake_V_ind - induced velocity from rotor wake at (VD.XC, VD.YC, VD.ZC) + + Properties Used: + None + """ + # Check for wing if wing instance is unspecified + if wing_instance == None: + nmw = 0 + # check for main wing + for i,wing in enumerate(geometry.wings): + if not isinstance(wing,Wings.Main_Wing): continue + nmw +=1 + wing_instance = wing + wing_instance_idx = i + if nmw == 1: + pass + elif nmw>1: + print("No wing specified for slipstream analysis. Multiple main wings in vehicle, using the last one.") + else: + print("No wing specified for slipstream analysis. No main wing defined, using the last wing in vehicle.") + wing_instance = wing + wing_instance_idx = i + + # Isolate the VD components corresponding to this wing instance + wing_CPs, slipstream_vd_ids = extract_wing_collocation_points(geometry, wing_instance_idx) + + # Evaluate rotor slipstream effect on specified wing instance + rot_V_wake_ind = self.evaluate_wake_velocities(rotor, wing_CPs, ctrl_pts) + + # Expand + wake_V_ind = np.zeros((ctrl_pts,geometry.vortex_distribution.n_cp,3)) + wake_V_ind[:,slipstream_vd_ids,:] = rot_V_wake_ind + + + return wake_V_ind + + def evaluate_wake_velocities(self,rotor,VD,num_ctrl_pts): """ Links the rotor wake to compute the wake-induced velocities at the vortex distribution control points. @@ -167,9 +223,6 @@ def evaluate_wake_velocities(self,rotor,network,geometry,conditions,VD,num_ctrl_ Inputs: self - rotor wake rotor - rotor - network - propulsion network - geometry - vehicle geometry - conditions - conditions VD - vortex distribution num_ctrl_pts - number of analysis control points diff --git a/trunk/SUAVE/Methods/Aerodynamics/Common/Fidelity_Zero/Lift/extract_wing_VD.py b/trunk/SUAVE/Methods/Aerodynamics/Common/Fidelity_Zero/Lift/extract_wing_VD.py index db8c910bfc..2eb2d91454 100644 --- a/trunk/SUAVE/Methods/Aerodynamics/Common/Fidelity_Zero/Lift/extract_wing_VD.py +++ b/trunk/SUAVE/Methods/Aerodynamics/Common/Fidelity_Zero/Lift/extract_wing_VD.py @@ -52,9 +52,10 @@ def extract_wing_collocation_points(geometry, wing_instance_idx): if idx == wing_instance_idx: # store the VD corresponding to this wing - VD_wing.XC = VD.XC[vd_i : vd_i + wing_cp_size] - VD_wing.YC = VD.YC[vd_i : vd_i + wing_cp_size] - VD_wing.ZC = VD.ZC[vd_i : vd_i + wing_cp_size] + VD_wing.XC = VD.XC[vd_i : vd_i + wing_cp_size] + VD_wing.YC = VD.YC[vd_i : vd_i + wing_cp_size] + VD_wing.ZC = VD.ZC[vd_i : vd_i + wing_cp_size] + VD_wing.n_cp = len(VD_wing.XC) ids = (np.linspace(vd_i, vd_i+wing_cp_size-1, wing_cp_size)).astype(int) diff --git a/trunk/SUAVE/Methods/Propulsion/Rotor_Wake/Fidelity_Zero/compute_fidelity_zero_induced_velocity.py b/trunk/SUAVE/Methods/Propulsion/Rotor_Wake/Fidelity_Zero/compute_fidelity_zero_induced_velocity.py index 41b9ceb34a..5efa98c244 100644 --- a/trunk/SUAVE/Methods/Propulsion/Rotor_Wake/Fidelity_Zero/compute_fidelity_zero_induced_velocity.py +++ b/trunk/SUAVE/Methods/Propulsion/Rotor_Wake/Fidelity_Zero/compute_fidelity_zero_induced_velocity.py @@ -48,14 +48,7 @@ def compute_fidelity_zero_induced_velocity(evaluation_points, props, ctrl_pts, i prop_key = list(props.keys())[idx] prop_outputs = props[prop_key].outputs R = prop.tip_radius - - s = evaluation_points.XC - prop.origin[0][0] - kd = 1 + s/(np.sqrt(s**2 + R**2)) - - # extract radial and azimuthal velocities at blade - va = kd*prop_outputs.blade_axial_induced_velocity[0] - vt = kd*prop_outputs.blade_tangential_induced_velocity[0] - r = prop_outputs.disc_radial_distribution[0,:,0] + r = prop_outputs.disc_radial_distribution[0,:,0] # Ignore points within hub or outside tip radius hub_y_center = prop.origin[0][1] @@ -69,23 +62,31 @@ def compute_fidelity_zero_induced_velocity(evaluation_points, props, ctrl_pts, i bool_in_range = bool_inboard + bool_outboard YC_in_range = evaluation_points.YC[bool_in_range] + y_vals = YC_in_range + val_ids = np.where(bool_in_range==True) + + s = evaluation_points.XC[val_ids] - prop.origin[0][0] + kd = 1 + s/(np.sqrt(s**2 + R**2)) + + # extract radial and azimuthal velocities at blade + va = prop_outputs.blade_axial_induced_velocity[0] + vt = prop_outputs.blade_tangential_induced_velocity[0] + va_y_range = np.append(np.flipud(va), va) vt_y_range = np.append(np.flipud(vt), vt)*prop.rotation va_interp = interp1d(prop_y_range, va_y_range) vt_interp = interp1d(prop_y_range, vt_y_range) - y_vals = YC_in_range - val_ids = np.where(bool_in_range==True) # preallocate va_new and vt_new - va_new = va_interp((y_vals)) + va_new = kd*va_interp((y_vals)) vt_new = np.zeros(np.size(val_ids)) # invert inboard vt values inboard_bools = (y_vals < hub_y_center) - vt_new[inboard_bools] = -vt_interp((y_vals[inboard_bools])) - vt_new[inboard_bools==False] = vt_interp((y_vals[inboard_bools==False])) + vt_new[inboard_bools] = -kd[inboard_bools]*vt_interp((y_vals[inboard_bools])) + vt_new[inboard_bools==False] = kd[inboard_bools==False]*vt_interp((y_vals[inboard_bools==False])) prop_V_wake_ind[0,val_ids,0] = va_new # axial induced velocity prop_V_wake_ind[0,val_ids,1] = 0 # spanwise induced velocity; in line with prop, so 0 From 8d53a9a52f0e2fb505a2934c61bf6c42d0daee42 Mon Sep 17 00:00:00 2001 From: Racheal Erhard Date: Fri, 25 Feb 2022 07:25:29 -0800 Subject: [PATCH 6/6] removing unnecessary script --- .../Fidelity_Zero/Lift/extract_wing_VD.py | 3 - .../compute_fidelity_zero_slipstream.py | 90 ------------------- 2 files changed, 93 deletions(-) delete mode 100644 trunk/SUAVE/Methods/Propulsion/Rotor_Wake/Fidelity_Zero/compute_fidelity_zero_slipstream.py diff --git a/trunk/SUAVE/Methods/Aerodynamics/Common/Fidelity_Zero/Lift/extract_wing_VD.py b/trunk/SUAVE/Methods/Aerodynamics/Common/Fidelity_Zero/Lift/extract_wing_VD.py index 2eb2d91454..fb7516de77 100644 --- a/trunk/SUAVE/Methods/Aerodynamics/Common/Fidelity_Zero/Lift/extract_wing_VD.py +++ b/trunk/SUAVE/Methods/Aerodynamics/Common/Fidelity_Zero/Lift/extract_wing_VD.py @@ -61,9 +61,6 @@ def extract_wing_collocation_points(geometry, wing_instance_idx): vd_i += wing_cp_size - # extract VD elements for vd_ele - - return VD_wing, ids diff --git a/trunk/SUAVE/Methods/Propulsion/Rotor_Wake/Fidelity_Zero/compute_fidelity_zero_slipstream.py b/trunk/SUAVE/Methods/Propulsion/Rotor_Wake/Fidelity_Zero/compute_fidelity_zero_slipstream.py deleted file mode 100644 index 918c311d32..0000000000 --- a/trunk/SUAVE/Methods/Propulsion/Rotor_Wake/Fidelity_Zero/compute_fidelity_zero_slipstream.py +++ /dev/null @@ -1,90 +0,0 @@ -## @ingroup Methods-Aerodynamics-Common-Fidelity_Zero-Lift -# compute_fidelity_zero_slipstream.py -# -# Created: Jun 2021, R. Erhard - -# ---------------------------------------------------------------------- -# Imports -# ---------------------------------------------------------------------- - -# package imports -import numpy as np -from scipy.interpolate import interp1d - -## @ingroup Methods-Aerodynamics-Common-Fidelity_Zero-Lift -def compute_fidelity_zero_slipstream(props,geometry,cpts,conditions,identical_flag,wing_instance=None): - """ This computes the velocity induced by the BEVW wake - on lifting surface control points - - Assumptions: - The wake contracts following formulation by McCormick. - - Source: - Contraction factor: McCormick 1969, Aerodynamics of V/STOL Flight - - Inputs: - prop - propeller or rotor data structure [Unitless] - geometry - SUAVE vehicle [Unitless] - cpts - control points in segment [Unitless] - Properties Used: - N/A - """ - - # extract vortex distribution - VD = geometry.vortex_distribution # this needs to be just for the wing_instance - - # initialize propeller wake induced velocities - prop_V_wake_ind = np.zeros((cpts,VD.n_cp,3)) - - for i,prop in enumerate(props): - if identical_flag: - idx = 0 - else: - idx = i - prop_key = list(props.keys())[idx] - prop_outputs = props[prop_key].outputs - R = prop.tip_radius - - # contraction factor by McCormick - s = wing_instance.origin[0][0] - prop.origin[0][0] - kd = 1 + s/(np.sqrt(s**2 + R**2)) - - # extract radial and azimuthal velocities at blade - va = kd*prop_outputs.blade_axial_induced_velocity[0] - vt = kd*prop_outputs.blade_tangential_induced_velocity[0] - r = prop_outputs.disc_radial_distribution[0,:,0] - - hub_y_center = prop.origin[0][1] - inboard_r = np.flip(hub_y_center - r) - outboard_r = hub_y_center + r - prop_y_range = np.append(inboard_r, outboard_r) - - # within this range, add an induced x- and z- velocity from propeller wake - bool_inboard = ( VD.YC > inboard_r[0] ) * ( VD.YC < inboard_r[-1] ) - bool_outboard = ( VD.YC > outboard_r[0] ) * ( VD.YC < outboard_r[-1] ) - bool_in_range = bool_inboard + bool_outboard - YC_in_range = VD.YC[bool_in_range] - - va_y_range = np.append(np.flipud(va), va) - vt_y_range = np.append(np.flipud(vt), vt)*prop.rotation - va_interp = interp1d(prop_y_range, va_y_range) - vt_interp = interp1d(prop_y_range, vt_y_range) - - y_vals = YC_in_range - val_ids = np.where(bool_in_range==True) - - # preallocate va_new and vt_new - va_new = va_interp((y_vals)) - vt_new = np.zeros(np.size(val_ids)) - - # invert inboard vt values - inboard_bools = (y_vals < hub_y_center) - vt_new[inboard_bools] = -vt_interp((y_vals[inboard_bools])) - vt_new[inboard_bools==False] = vt_interp((y_vals[inboard_bools==False])) - - prop_V_wake_ind[0,val_ids,0] = va_new # axial induced velocity - prop_V_wake_ind[0,val_ids,1] = 0 # spanwise induced velocity; in line with prop, so 0 - prop_V_wake_ind[0,val_ids,2] = vt_new # vertical induced velocity - - return prop_V_wake_ind -