def shape_difference(inputs, optimize_deltaz=False): if optimize_deltaz == True or optimize_deltaz == [True]: y_u = CST(upper['x'], 1, deltasz=inputs[-1] / 2., Au=list(inputs[:n + 1])) y_l = CST(lower['x'], 1, deltasz=inputs[-1] / 2., Al=list(inputs[n + 1:-1])) else: y_u = CST(upper['x'], 1, deltasz=deltaz / 2., Au=list(inputs[:n + 1])) y_l = CST(lower['x'], 1, deltasz=deltaz / 2., Al=list(inputs[n + 1:])) # Vector to be compared with a_u = {'x': upper['x'], 'y': y_u} a_l = {'x': lower['x'], 'y': y_l} b_u = upper b_l = lower return hausdorff_distance_2D(a_u, b_u) + hausdorff_distance_2D( a_l, b_l)
def calculate_spar_distance(psi_baseline, Au_baseline, Au_goal, Al_goal, deltaz, c_goal): """Calculate spar distance (dimensional)""" def f(psi_lower_goal): y_lower_goal = CST(psi_lower_goal * c_goal, c_goal, [deltaz / 2., deltaz / 2.], Au_goal, Al_goal) y_lower_goal = y_lower_goal['l'] return psi_upper_goal + (s[0] / s[1]) * (y_lower_goal - y_upper_goal) / c_goal # Calculate cruise chord c_baseline = calculate_c_baseline(c_goal, Au_baseline, Au_goal, deltaz) # Calculate upper psi at goal airfoil psi_upper_goal = calculate_psi_goal(psi_baseline, Au_baseline, Au_goal, deltaz, c_baseline, c_goal) y_upper_goal = CST(psi_upper_goal * c_goal, c_goal, [deltaz / 2., deltaz / 2.], Au_goal, Al_goal) y_upper_goal = y_upper_goal['u'] # Spar direction s = calculate_spar_direction(psi_baseline, Au_baseline, Au_goal, deltaz, c_goal) # Calculate lower psi and xi at goal airfoil #Because the iterative method can lead to warningdivision by zero after converging, we ignore #the warning np.seterr(divide='ignore', invalid='ignore') psi_lower_goal = optimize.fixed_point( f, [psi_upper_goal]) #, args=(c_L, Au_C, Au_L, deltaz) x_lower_goal = psi_lower_goal * c_goal y_lower_goal = CST(x_lower_goal, c_goal, [deltaz / 2., deltaz / 2.], Au_goal, Al_goal) y_lower_goal = y_lower_goal['l'] return (y_upper_goal - y_lower_goal[0]) / s[1]
def calculate_average_camber(Au, Al, delta_xi): psi = np.linspace(0, 1, 1000) xi = CST(psi, 1., [delta_xi / 2., delta_xi / 2.], Au, Al) camber = (xi['u'] + xi['l']) / 2. return np.average(np.absolute(camber))
def calculate_camber(psi, Au, Al, delta_xi): xi = CST(psi, 1., [delta_xi / 2., delta_xi / 2.], Au, Al) return (xi['u'] + xi['l']) / 2.
def f(psi_lower_goal): y_lower_goal = CST(psi_lower_goal * c_goal, c_goal, [deltaz / 2., deltaz / 2.], Au_goal, Al_goal) y_lower_goal = y_lower_goal['l'] return psi_upper_goal + (s[0] / s[1]) * (y_lower_goal - y_upper_goal) / c_goal
Au_C[0] = x_i c_i = calculate_c_baseline(c_L, Au_C, Au_L, deltaz) c.append(c_i) plt.plot(x, c) plt.xlabel('$A_{u_0}^C$', fontsize=14) plt.ylabel('$c^C$', fontsize=14) plt.grid() plt.show() # Plot airfoils for different Au plt.figure() psi = np.linspace(0, 1, 500) i = 0 for c_i in c: Au_C[0] = x[i] y = CST(psi, 1, [deltaz / 2., deltaz / 2.], Au_C, Al_C) x_plot = np.linspace(0, c_i, 500) plt.plot(x_plot, c_i * y['u'], label='$A_{u_0}$ = %.1f' % x[i]) y_psi = CST(psi_i, 1, [deltaz / 2., deltaz / 2.], Au_C, Al_C) i += 1 plt.xlabel(r'$\psi^C$', fontsize=14) plt.ylabel(r'$\xi^C$', fontsize=14) plt.legend() plt.gca().set_aspect('equal', adjustable='box') plt.grid() plt.show() # Plot for several testing calculat_psi_goal plt.figure() x = np.linspace(0., 1., 6) psi_goal_list = []
AC_u4, AC_u5, psi_spars, Au_P, Al_P, deltaz, c_P, morphing=morphing_direction) #============================================================================== # Plot results #============================================================================== np.set_printoptions(precision=20) # Print shape for children x = np.linspace(0, c_C, 100000) y = CST(x, c_C, deltasz=[deltaz / 2., deltaz / 2.], Al=Al_C, Au=Au_C) plt.plot(x, y['u'], 'b', label='Children', lw=2) plt.plot(x, y['l'], 'b', label=None, lw=2) # Print shape for parent x = np.linspace(0, c_P, 100000) y = CST(x, c_P, deltasz=[deltaz / 2., deltaz / 2.], Al=Al_P, Au=Au_P) plt.plot(x, y['u'], 'r--', label='Parent', lw=2) plt.plot(x, y['l'], 'r--', label=None, lw=2) if morphing_direction == 'forwards': psi_flats = [] intersections_x_children = [0] intersections_y_children = [0] intersections_x_parent = [0]
def calculate_dependent_shape_coefficients(BP_p, BA_p, BP_c, chord_p, sweep_p, twist_p, delta_TE_p, sweep_c, twist_c, eta_sampling, psi_spars, morphing='camber'): """Calculate dependent shape coefficients for children configuration for a 4 order Bernstein polynomial and return the children upper, lower shape coefficients, children chord and spar thicknesses. _P denotes parent parameters""" def calculate_BP_c0(BP_c0, c_P, deltaz, j): Au_C = extract_A(BP_c, j) Au_P = extract_A(BP_p, j) c_C = calculate_c_baseline(c_P, Au_C, Au_P, deltaz) BP_c[0][j] = np.sqrt(c_P / c_C) * Au_P[0] return BP_c[0][j], c_C def extract_A(B, j): # Extracting shape coefficient data for column j A = [] for i in range(n + 1): A.append(B[i][j]) return A # Bersntein Polynomial def K(r, n): K = math.factorial(n) / (math.factorial(r) * math.factorial(n - r)) return K # Bernstein Polynomial orders (n is for psi, and m for eta) n = len(BP_p) - 1 m = len(BP_p[0]) - 1 p = len(psi_spars) q = len(eta_sampling) # print p,q,n,m # Define chord, sweep, and twist functions for parent chord_p = CST(eta_sampling, chord_p['eta'][1], chord_p['initial'], Au=chord_p['A'], N1=chord_p['N1'], N2=chord_p['N2'], deltasLE=chord_p['final']) sweep_p = CST(eta_sampling, sweep_p['eta'][1], deltasz=sweep_p['final'], Au=sweep_p['A'], N1=sweep_p['N1'], N2=sweep_p['N2']) chord_p = chord_p[::-1] sweep_p = sweep_p twist_p = CST(eta_sampling, twist_p['eta'][1], twist_p['initial'], Au=twist_p['A'], N1=twist_p['N1'], N2=twist_p['N2'], deltasLE=twist_p['final']) delta_TE_p = CST(eta_sampling, delta_TE_p['eta'][1], delta_TE_p['initial'], Au=delta_TE_p['A'], N1=delta_TE_p['N1'], N2=delta_TE_p['N2'], deltasLE=delta_TE_p['final']) # Initialize chord, sweep, and twist functions for child chord_c = [] # Initialize child active matrix BA_c = [] for i in range(n + 1): temp = [] for j in range(m + 1): temp.append(0) BA_c.append(temp, ) # Find upper shape coefficient though iterative method since Au_0 is unknown # via fixed point iteration for k in range(q): error = 9999 BP_c0 = BP_p[0][k] while error > 1e-9: before = BP_c0 c_P = chord_p[k] deltaz = delta_TE_p[k] [BP_c0, c_c] = calculate_BP_c0(BP_c0, c_P, deltaz, k) error = abs(BP_c0 - before) BP_c[0][k] = BP_c0 BA_c[0][k] = np.sqrt(c_P / c_c) * BA_p[0][k] chord_c.append(c_c) print(c_c, BP_c0, np.sqrt(c_P / c_c) * BA_p[0][k]) # Calculate thicknessed and tensor C for the constraint linear system problem psi_A_c = [] if morphing == 'camber': f = np.zeros((q, p)) for l in range(q): # Converting everything from 3D to 2D framework Au_P = extract_A(BP_p, l) Al_P = extract_A(BA_p, l) Au_C = extract_A(BP_c, l) c_P = chord_p[l] c_C = chord_c[l] deltaz = delta_TE_p[l] # psi/xi coordinates for lower surface of the children configuration psi_lower_children = [] xi_upper_children = [] # psi_baseline, Au_baseline, Au_goal, deltaz, c_baseline, c_goal psi_upper_children = [] for j in range(len(psi_spars)): psi_upper_children.append( calculate_psi_goal(psi_spars[j], Au_P, Au_C, deltaz, c_P, c_C)) # Calculate xi for upper children. Do not care about lower so just gave it random shape coefficients xi_upper_children = CST( psi_upper_children, 1., deltasz=[deltaz / 2. / c_C, deltaz / 2. / c_C], Al=Au_C, Au=Au_C) xi_upper_children = xi_upper_children['u'] # print xi_upper_children #Debugging section x = np.linspace(0, 1) y = CST(x, 1., deltasz=[deltaz / 2. / c_C, deltaz / 2. / c_C], Al=Au_C, Au=Au_C) # plt.plot(x,y['u']) # plt.scatter(psi_upper_children, xi_upper_children) # plt.grid() # plt.show() # BREAK for k in range(len(psi_spars)): xi_parent = CST(psi_spars, 1., deltasz=[deltaz / 2. / c_P, deltaz / 2. / c_P], Al=Al_P, Au=Au_P) delta_k_P = xi_parent['u'][k] - xi_parent['l'][k] t_k = c_P * (delta_k_P) # Claculate orientation for children s_k = calculate_spar_direction(psi_spars[k], Au_P, Au_C, deltaz, c_C) psi_l_k = psi_upper_children[k] - delta_k_P / c_C * s_k[0] xi_l_k = xi_upper_children[k] - delta_k_P / c_C * s_k[1] psi_lower_children.append(psi_l_k) f_y = 0 for j in range(m + 1): f_y += BA_c[0][j] * ( 1 - psi_l_k)**n * (K(j, m) * eta_sampling[l]**j * (1 - eta_sampling[l])**(m - j)) # print j, eta_sampling[l]**j*(1-eta_sampling[l])**(m-j), BA_c[0][j] f[l][k] = (2 * xi_l_k + psi_l_k * deltaz / c_C) / (2 * (psi_l_k**0.5) * (psi_l_k - 1)) - f_y # print 'f_y',f_y, eta_sampling[l],m,j # Store new children psi values psi_A_c.append(psi_lower_children) # Initialize F (avoiding using numpy) F = np.zeros([q, p, m + 1, n]) # F = [] # for l in range(q): # tempk = [] # for k in range(p): # tempj = [] # for j in range(m+1): # tempi = [] # for i in range(n): # tempi.append(0.0) # tempj.append(tempi) # tempk.append(tempj) # F.append(tempk) #j is the row dimension and i the column dimension in this case for l in range(q): for k in range(p): for j in range(m + 1): for i in range(n): #Because in Python counting starts at 0, need to add 1 to be #coherent for equations ii = i + 1 Sx = K(ii, n) * (psi_A_c[l][k]** ii) * (1 - psi_A_c[l][k])**(n - ii) Sy = K(j, m) * (eta_sampling[l]** j) * (1 - eta_sampling[l])**(m - j) F[l][k][j][i] = Sx * Sy # print len(F), len(F[0]), len(F[0][0]), len(F[0][0][0]) # Unfolding tensor F_matrix = np.zeros((n**2, n**2)) f_vector = np.zeros((n**2, 1)) for l in range(q): for k in range(p): for j in range(m + 1): for i in range(n): ii = n * (l) + k jj = n * (j) + i F_matrix[ii][jj] = F[l][k][j][i] f_vector[ii] = f[l][k] solution = np.linalg.solve(F_matrix, f_vector) for j in range(m + 1): for i in range(n): jj = n * (j) + i BA_c[i + 1][j] = solution[jj][0] print(BA_c) return BA_c, chord_c
def calculate_dependent_shape_coefficients(Au_C_1_to_n, psi_spars, Au_P, Al_P, deltaz, c_P, morphing='backwards'): """Calculate dependent shape coefficients for children configuration for a 4 order Bernstein polynomial and return the children upper, lower shape coefficients, children chord and spar thicknesses. _P denotes parent parameters""" def calculate_AC_u0(AC_u0): Au_C = [AC_u0] + Au_C_1_to_n c_C = calculate_c_baseline(c_P, Au_C, Au_P, deltaz) return np.sqrt(c_P / c_C) * Au_P[0] # Bersntein Polynomial def K(r, n): K = math.factorial(n) / (math.factorial(r) * math.factorial(n - r)) return K # Bernstein Polynomial order n = len(Au_C_1_to_n) # Find upper shape coefficient though iterative method since Au_0 is unknown # via fixed point iteration #AC_u0 = optimize.fixed_point(calculate_AC_u0, Au_P[0]) #print AC_u0 error = 9999 AC_u0 = Au_P[0] while error > 1e-9: before = AC_u0 AC_u0 = calculate_AC_u0(AC_u0) error = abs(AC_u0 - before) # Because the output is an array, need the extra [0] Au_C = [AC_u0] + Au_C_1_to_n # Now that AC_u0 is known we can calculate the actual chord and AC_l0 c_C = calculate_c_baseline(c_P, Au_C, Au_P, deltaz) AC_l0 = np.sqrt(c_P / c_C) * Al_P[0] print(Au_C) print(Au_P) print(Al_P) print(c_C, AC_l0, AC_u0) # print '0 lower shape coefficient: ',AC_l0 # Calculate thicknessed and tensor B for the constraint linear system problem spar_thicknesses = [] A0 = AC_u0 + AC_l0 if morphing == 'backwards': b_list = np.zeros((n, 1)) for j in range(len(psi_spars)): psi_j = psi_spars[j] #Calculate the spar thickness in meters from parent, afterwards, need to #adimensionalize for the goal airfoil by dividing by c_goal t_j = calculate_spar_distance(psi_spars[j], Au_C, Au_P, Al_P, deltaz, c_P) spar_thicknesses.append(t_j) b_list[j] = (t_j / c_C - psi_j * deltaz / c_C) / ( (psi_j**0.5) * (1 - psi_j)) - A0 * (1 - psi_j)**n B = np.zeros((n, n)) #j is the row dimension and i the column dimension in this case for j in range(n): for i in range(n): #Because in Python counting starts at 0, need to add 1 to be #coherent for equations r = i + 1 B[j][i] = K(r, n) * (psi_spars[j]** r) * (1 - psi_spars[j])**(n - r) A_bar = np.dot(inv(B), b_list) Al_C = [AC_l0] for i in range(len(A_bar)): Al_C.append(A_bar[i][0] - Au_C[i + 1]) #extra [0] is necessary because of array elif morphing == 'forwards': f = np.zeros((n, 1)) # psi/xi coordinates for lower surface of the children configuration psi_lower_children = [] xi_lower_children = [] xi_upper_children = [] c_C = calculate_c_baseline(c_P, Au_C, Au_P, deltaz) print(c_C, AC_u0, AC_l0) # psi_baseline, Au_baseline, Au_goal, deltaz, c_baseline, c_goal psi_upper_children = [] for j in range(len(psi_spars)): psi_upper_children.append( calculate_psi_goal(psi_spars[j], Au_P, Au_C, deltaz, c_P, c_C)) # Calculate xi for upper children. Do not care about lower so just gave it random shape coefficients xi_upper_children = CST(psi_upper_children, 1., deltasz=[deltaz / 2. / c_C, deltaz / 2. / c_C], Al=Au_C, Au=Au_C) xi_upper_children = xi_upper_children['u'] # print xi_upper_children #Debugging section x = np.linspace(0, 1) y = CST(x, 1., deltasz=[deltaz / 2. / c_C, deltaz / 2. / c_C], Al=Au_C, Au=Au_C) # plt.plot(x,y['u']) # plt.scatter(psi_upper_children, xi_upper_children) # plt.grid() # plt.show() # BREAK for j in range(len(psi_spars)): xi_parent = CST(psi_spars, 1., deltasz=[deltaz / 2. / c_P, deltaz / 2. / c_P], Al=Al_P, Au=Au_P) delta_j_P = xi_parent['u'][j] - xi_parent['l'][j] t_j = c_P * (delta_j_P) # Claculate orientation for children s_j = calculate_spar_direction(psi_spars[j], Au_P, Au_C, deltaz, c_C) psi_l_j = psi_upper_children[j] - delta_j_P / c_C * s_j[0] xi_l_j = xi_upper_children[j] - delta_j_P / c_C * s_j[1] spar_thicknesses.append(t_j) psi_lower_children.append(psi_l_j) xi_lower_children.append(xi_l_j) f[j] = (2 * xi_l_j + psi_l_j * deltaz / c_C) / ( 2 * (psi_l_j**0.5) * (psi_l_j - 1)) - AC_l0 * (1 - psi_l_j)**n print(psi_lower_children) F = np.zeros((n, n)) #j is the row dimension and i the column dimension in this case for j in range(n): for i in range(n): #Because in Python counting starts at 0, need to add 1 to be #coherent for equations r = i + 1 F[j][i] = K(r, n) * (psi_lower_children[j]** r) * (1 - psi_lower_children[j])**(n - r) print( K(r, n) * (psi_lower_children[j]**r) * (1 - psi_lower_children[j])**(n - r)) A_lower = np.dot(inv(F), f) Al_C = [AC_l0] for i in range(len(A_lower)): Al_C.append( A_lower[i][0]) #extra [0] is necessary because of array return Au_C, Al_C, c_C, spar_thicknesses
def plot_airfoil(AC, psi_spars, c_L, deltaz, Au_L, Al_L, image='plot', iteration=0, return_coordinates=True, dir='current'): import matplotlib.pyplot as plt plt.figure() n = len(Au_L) - 1 Au_C, Al_C, c_C, spar_thicknesses = calculate_dependent_shape_coefficients( AC, psi_spars, Au_L, Al_L, deltaz, c_L, morphing=morphing_direction) #============================================================================== # Plot results #============================================================================== np.set_printoptions(precision=20) x = np.linspace(0, c_C, 1000) y = CST(x, c_C, deltasz=[deltaz / 2., deltaz / 2.], Al=Al_C, Au=Au_C) plt.plot(x, y['u'], 'b', label='Children') plt.plot(x, y['l'], '-b', label=None) # store variables in case return_coordinates is True x = list(x[::-1]) + list(x[1:]) y = list(y['u'][::-1]) + list(y['l'][1:]) children_coordinates = {'x': x, 'y': y} x = np.linspace(0, c_L, 1000) y = CST(x, c_L, deltasz=[deltaz / 2., deltaz / 2.], Al=Al_L, Au=Au_L) plt.plot(x, y['u'], 'r--', label='Parent') plt.plot(x, y['l'], 'r--', label=None) y_limits = y for i in range(len(psi_spars)): psi_i = psi_spars[i] # Calculate psi at landing psi_goal_i = calculate_psi_goal(psi_i, Au_C, Au_L, deltaz, c_C, c_L) x_goal_i = psi_goal_i * c_L # Calculate xi at landing temp = CST(x_goal_i, c_L, [deltaz / 2., deltaz / 2.], Al=Al_L, Au=Au_L) y_goal_i = temp['u'] #calculate spar direction s = calculate_spar_direction(psi_i, Au_C, Au_L, deltaz, c_L) plt.plot([x_goal_i, x_goal_i - spar_thicknesses[i] * s[0]], [y_goal_i, y_goal_i - spar_thicknesses[i] * s[1]], 'r--') y = CST(np.array([psi_i * c_C]), c_C, deltasz=[deltaz / 2., deltaz / 2.], Al=Al_C, Au=Au_C) plt.plot([psi_i * c_C, psi_i * c_C], [y['u'], y['u'] - spar_thicknesses[i]], 'b', label=None) plt.xlabel('$\psi$', fontsize=16) plt.ylabel(r'$\xi$', fontsize=16) plt.grid() plt.legend(loc="upper right") plt.gca().set_aspect('equal', adjustable='box') x1, x2, y1, y2 = plt.axis() plt.axis((x1, x2, y1, 2 * y2)) # plt.axis([-0.005, c_L+0.005, min(y_limits['l'])-0.005, max(y_limits['l'])+0.01]) if image == 'plot': plt.show() elif image == 'save': if dir == 'current': plt.savefig('%03i.png' % (iteration), bbox_inches='tight') else: cwd = os.getcwd() directory = os.path.join(cwd, dir) if not os.path.exists(directory): os.makedirs(directory) filename = os.path.join(directory, '%05i.png' % (iteration)) plt.savefig(filename, bbox_inches='tight') if return_coordinates: return children_coordinates
if y_i >= tip_displacement['y']: print('Y value out of bounds!') A = calculate_shape_coefficients_tracing( A0, other_points['y'], other_points['x'], N1, N2, chord=tip_displacement['y'], EndThickness=tip_displacement['x']) #plotting y = np.linspace(0, tip_displacement['y'], 100000) x = CST(y, tip_displacement['y'], deltasz=tip_displacement['x'], Au=A, N1=N1, N2=N2) plt.plot(x, y) plt.scatter(other_points['x'] + [tip_displacement['x']], other_points['y'] + [tip_displacement['y']]) plt.gca().set_aspect('equal', adjustable='box') plt.show() elif testing == 'structurally_consistent': #============================================================================== # Inputs #============================================================================== # Parameter c_P = 1. #m
def calculate_dependent_shape_coefficients(Au_C_1_to_n, psi_spars, Au_P, Al_P, deltaz, c_P, morphing='backwards', l_LE=0, eps_LE=0): """Calculate dependent shape coefficients for children configuration for a 4 order Bernstein polynomial and return the children upper, lower shape coefficients, children chord and spar thicknesses. _P denotes parent parameters""" def calculate_AC_u0(AC_u0, constant_LE=True): Au_C = [AC_u0] + Au_C_1_to_n if constant_LE: return np.sqrt(c_P / c_C) * Au_P[0] else: return calculate_A0_moving_LE(psi_spars, psi_lower_children[0], Au_P, Au_C, deltaz, c_P, l_LE, eps_LE) # Bersntein Polynomial def K(r, n): K = math.factorial(n) / (math.factorial(r) * math.factorial(n - r)) return K # Bernstein Polynomial order # In case of leading edge radius constraint n = len(Au_C_1_to_n) # Find upper shape coefficient though iterative method since Au_0 is unknown # via fixed point iteration #AC_u0 = optimize.fixed_point(calculate_AC_u0, Au_P[0]) # print AC_u0 error = 9999 psi_lower_children = psi_spars Au_C = [Au_P[0]] + Au_C_1_to_n # [Au_P[0]] + former_chord = c_P while error > 1e-5: former_Au_C = [] for i in range(len(Au_C)): former_Au_C.append(Au_C[i]) # Because the output is an array, need the extra [0] error_A0 = 999 # Now that AC_u0 is known we can calculate the actual chord and AC_l0 # c_C = calculate_c_baseline(c_P, Au_C, Au_P, deltaz/c_P, l_LE, eps_LE, psi_spars[0]) Au_C[0] = calculate_AC_u0(Au_C[0], constant_LE=False) Al_C0 = Au_C[0] c_C = calculate_c_baseline(c_P, Au_C, Au_P, deltaz / c_P, l_LE, eps_LE, psi_spars[0]) #Al_C0 = Au_C[0] # print '0 lower shape coefficient: ',AC_l0 # Calculate thicknessed and tensor B for the constraint linear system problem spar_thicknesses = [] if morphing == 'forwards': f = np.zeros((n, 1)) # psi/xi coordinates for lower surface of the children configuration psi_lower_children = [] xi_lower_children = [] xi_upper_children = [] # psi_baseline, Au_baseline, Au_goal, deltaz, c_baseline, c_goal psi_upper_children = [] for j in range(len(psi_spars)): print(j) psi_upper_children.append( calculate_psi_goal(psi_spars[j], Au_P, Au_C, deltaz, c_P, c_C, l_LE, eps_LE, psi_spars[0])) # Calculate xi for upper children. Do not care about lower so just gave it random shape coefficients xi_upper_children = CST( psi_upper_children, 1., deltasz=[deltaz / 2. / c_C, deltaz / 2. / c_C], Al=Au_C, Au=Au_C) xi_upper_children = xi_upper_children['u'] # print xi_upper_children # Debugging section # x = np.linspace(0,1) # y = CST(x, 1., deltasz= [deltaz/2./c_C, deltaz/2./c_C], Al= Au_C, Au =Au_C) # plt.plot(x,y['u']) # plt.scatter(psi_upper_children, xi_upper_children) # plt.grid() # plt.show() # BREAK print(Au_P, Au_C, len(psi_spars), n) for j in range(len(psi_spars)): xi_parent = CST(psi_spars, 1., deltasz=[deltaz / 2. / c_P, deltaz / 2. / c_P], Al=Al_P, Au=Au_P) delta_j_P = xi_parent['u'][j] - xi_parent['l'][j] t_j = c_P * (delta_j_P) # Claculate orientation for children s_j = calculate_spar_direction(psi_spars[j], Au_P, Au_C, deltaz, c_C, l_LE, eps_LE, psi_spars) psi_l_j = psi_upper_children[j] - delta_j_P / c_C * s_j[0] xi_l_j = xi_upper_children[j] - delta_j_P / c_C * s_j[1] spar_thicknesses.append(t_j) psi_lower_children.append(psi_l_j) xi_lower_children.append(xi_l_j) f[j] = (2*xi_l_j + psi_l_j*deltaz/c_C) / \ (2*(psi_l_j**0.5)*(psi_l_j-1)) - Al_C0*(1-psi_l_j)**n F = np.zeros((n, n)) # j is the row dimension and i the column dimension in this case for j in range(n): for i in range(n): # Because in Python counting starts at 0, need to add 1 to be # coherent for equations r = i + 1 F[j][i] = K(r, n) * (psi_lower_children[j]**r) * ( 1 - psi_lower_children[j])**(n - r) print(F) print(f) A_lower = np.dot(inv(F), f) print('result', A_lower) Al_C = [Al_C0] for i in range(len(A_lower)): Al_C.append( A_lower[i][0]) # extra [0] is necessary because of array error_denominator = 0 print('before', former_Au_C, Au_C) for i in range(len(Au_C)): error_denominator += Au_C[i]**2 error = 0 for i in range(len(Al_C)): error += (former_Au_C[i] - Au_C[i])**2 / error_denominator error = math.sqrt(error) # error = abs(c_C-former_chord)/c_C # AC_u0 = calculate_AC_u0(AC_u0, constant_LE=False) print(error, Al_C, Au_C) # former_chord = c_C return Au_C, Al_C, c_C, spar_thicknesses
def CST_3D(Bu, Bl, span, N={'eta':[0,1], 'N1':[.5, .5], 'N2':[1., 1.], 'chord':[1., 0]}, mesh = (100,100), chord = {'eta':[0,1], 'A':[1.], 'N1':1, 'N2':1, 'initial_chord':1.}, sweep = {'eta':[0,1], 'A':[1.], 'N1':1, 'N2':1, 'x_LE_initial':0, 'x_LE_final':0}): """ - Bu: upper shape coefficients - Bl: lower shape coefficients - mesh: list of number of points in x and y """ def S(B, psi, eta): """ Cross section shape function. Validated for high dimensions. To debug just verify if it turns all ones when B=ones""" def S_i(r, n, psi): """Shape function""" value = K(r,n)*(psi**r)*(1.-psi)**(n-r) return value # Bersntein Polynomial def K(r,n): K=math.factorial(n)/(math.factorial(r)*math.factorial(n-r)) return K Nx = len(B)-1 Ny = len(B[0])-1 output = 0 for i in range(Nx+1): for j in range(Ny+1): output += B[i][j]*S_i(i, Nx, psi)*S_i(j, Ny, eta) return output def C(N, psi, eta): """Class function""" N1 = interp1d(N['eta'], N['N1']) N2 = interp1d(N['eta'], N['N2']) output = ((psi)**N1(eta))*((1.-psi)**N2(eta)) return output psi = np.linspace(0,1,mesh[0]) eta = np.linspace(0,1,mesh[1]) zeta_u = np.zeros(mesh) zeta_l = np.zeros(mesh) for i in range(mesh[0]): for j in range(mesh[1]): zeta_u[j][i] = C(N, psi[i], eta[j])*S(Bu, psi[i], eta[j]) zeta_l[j][i] = -C(N, psi[i], eta[j])*S(Bl, psi[i], eta[j]) print(eta) print(chord['initial_chord']) print(chord['A']) print(chord['N1'], chord['N2']) chord_distribution = CST(eta, chord['eta'][1], chord['initial_chord'], Au=chord['A'], N1=chord['N1'], N2=chord['N2']) sweep_distribution = CST(eta, sweep['eta'][1], deltasz = sweep['x_LE_final']-.5*chord['initial_chord'], Au=sweep['A'], N1=sweep['N1'], N2=sweep['N2']) chord_distribution = chord_distribution[::-1] sweep_distribution = sweep_distribution # taper_function(eta, shape = 'linear', N) x = np.zeros(len(psi)) for i in range(len(x)): x[i] = psi[i]*chord_distribution[i] print(chord_distribution) print(sweep_distribution) print(x) print(psi) y = eta X = np.zeros(mesh) Y = np.zeros(mesh) Z_u = np.zeros(mesh) Z_l = np.zeros(mesh) for i in range(mesh[0]): for j in range(mesh[1]): X[j][i] = psi[i]*chord_distribution[j] - sweep_distribution[j] -.5*chord['initial_chord'] Y[j][i] = span*eta[j] Z_u[j][i] = zeta_u[j][i]*chord_distribution[j] Z_l[j][i] = zeta_l[j][i]*chord_distribution[j] return [X,Y,Z_u,Z_l]
import aeropy.xfoil_module as xf from aeropy.CST.module_2D import * from aeropy.aero_module import Reynolds from aeropy.airfoil_module import CST, create_x Au = [0.23993240191629417, 0.34468227138908186, 0.18125405377549103, 0.35371349126072665, 0.2440815012119143, 0.25724974995738387] Al = [0.18889012559339036, -0.24686758992053115, 0.077569769493868401, -0.547827192265256, -0.0047342206759065641, -0.23994805474814629] c_avian = .36 #m deltaz = 0.0093943568219451313*c_avian airfoil = 'avian' x = create_x(c_avian, distribution = 'linear') y = CST(x, c_avian, [deltaz/2., deltaz/2.], Au = Au, Al= Al) # Create file for Xfoil to read coordinates xf.create_input(x, y['u'], y['l'], airfoil, different_x_upper_lower = False) Data = xf.find_coefficients(airfoil, 2., Reynolds=Reynolds(10000, 30, c_avian), iteration=100, NACA=False) print(Data) psi_u_inflection, psi_l_inflection = find_inflection_points(Au, Al) print('upper: ', psi_u_inflection) print('lower: ', psi_l_inflection) psi = np.linspace(0.001,0.999,100) xi = CST(psi, 1, [deltaz/2., deltaz/2.], Au, Al) plt.plot(psi, xi['u'], 'b', label = 'Upper outer mold line') plt.plot(psi, xi['l'],'b--', label = 'Lower outer mold line')
min_x = min(raw_data['x']) min_index = raw_data['x'].index(min_x) min_y = raw_data['y'][min_index] chord = max(raw_data['x']) - min(raw_data['x']) beta = math.atan((y_TE - min_y) / (x_TE - min_x)) for i in range(len(raw_data['x'])): processed_data['x'].append((raw_data['x'][i] - min_x) / chord) processed_data['y'].append(raw_data['y'][i] / chord) raw_data = processed_data psi = np.linspace(0, 1, 200) xi = CST(psi, 1., [data['deltaz'][n - 1] / 2., data['deltaz'][n - 1] / 2.], Au=data['Au'][n - 1], Al=data['Al'][n - 1]) plt.figure() plt.plot(psi, xi['u'], psi, xi['l']) plt.scatter(raw_data['x'], raw_data['y']) n = 8 plt.xlim(0, 1) x = np.linspace(2, 2 * n, n) plt.gca().set_aspect('equal', adjustable='box') plt.show() plt.figure() plt.plot(x, data['error']) plt.scatter(x, data['error']) plt.xlabel('Number of shape functions') plt.ylabel('Hausdorff distance (adimensional)')