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]
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)')
# tracing : A = calculate_shape_coefficients_tracing(AC_u0, ValX, ValY, 0.5, 1.,c_C, deltaz) # structurally_consistent : Au_C, Al_C, c_C, spar_thicknesses = calculate_dependent_shape_coefficients( A[1:], psi_spars, Au_P, Al_P, deltaz, c_P, morphing=morphing_direction) error = abs((AC_u0-Au_C[0])/AC_u0) print 'Iteration: ' + str(counter) + ', Error: ' +str(error) AC_u0 = Au_C[0] counter += 1 #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ # Plotting : #~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 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', lw=2) plt.plot(x, y['l'],'b',label = None, lw=2) # Print shape for parent x = np.linspace(0, c_P, 1000) 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] intersections_y_parent = [0]
import numpy as np import matplotlib.pyplot as plt import xfoil_module as xf from CST_module import * from aero_module import Reynolds from 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] Au = [0.172802, 0.167353, 0.130747, 0.172053, 0.112797, 0.168891] Al = Au # c_avian = 0.36 #m # deltaz = 0.0093943568219451313*c_avian c_avian = 1. deltaz = 0 airfoil = 'avian' x = create_x(1., distribution='linear') y = CST(x, 1., [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) print 'Reynolds: ', Reynolds(10000, 30, c_avian) Data = xf.find_coefficients(airfoil, 0., Reynolds=Reynolds(10000, 30, c_avian), iteration=100, NACA=False) print Data
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 / c_P) AC_l0 = np.sqrt(c_P / c_C) * Al_P[0] # 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) # 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 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) 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
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_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=20) plt.ylabel('$c^C$', fontsize=20) 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=20) plt.ylabel(r'$\xi^C$', fontsize=20) plt.legend() plt.show() # Plot for several testing calculat_psi_goal plt.figure() x = np.linspace(0., 1., 11) psi_goal_list = [] for x_i in x: Au_C[0] = x_i
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, 'initial_chord':1., 'x_LE_initial':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], sweep['x_LE_initial'], 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 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] + .5*sweep_distribution[j] 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]
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] if __name__ == '__main__': from mpl_toolkits.mplot3d import Axes3D import matplotlib.pyplot as plt from matplotlib import cm # B = [[1,1], [1.,1]] B = [[1], [1]] x = np.linspace(0,1) initial_chord = .5 span = 4. chord_distribution = CST(x, initial_chord, span, Au=[1.], Al=None, N1=1., N2=1.) [X,Y,Z_u, Z_l] = CST_3D(B, B, mesh =(50,50), span=span, N={'eta':[0,1], 'N1':[.5, .5], 'N2':[.5, .5]}, chord = {'eta':[0,1], 'A':[1.], 'N1':1., 'N2':1, 'initial_chord':1.}, sweep = {'eta':[0,1], 'A':[1.], 'N1':1, 'N2':1., 'initial_chord':1., 'x_LE_initial':-2}) fig = plt.figure() ax = fig.gca(projection='3d') surf_u = ax.plot_surface(X, Z_u, Y, cmap=plt.get_cmap('jet'), linewidth=0, antialiased=False) surf_l = ax.plot_surface(X, Z_l, Y, cmap=plt.get_cmap('jet'), linewidth=0, antialiased=False) # cset = ax.contour(X, Z_u, Y, zdir='z', offset=0, cmap=cm.coolwarm) # cset = ax.contour(X, Z_l, Y, zdir='z', offset=0, cmap=cm.coolwarm) # cset = ax.contour(X, Z_u, Y, zdir='x', offset=-.1, cmap=cm.coolwarm)
from 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)