def hello(): x = request.args.get('x') y = request.args.get('y') Re = float(request.args.get('Re')) M = float(request.args.get('M')) Alpha = float(request.args.get('Alpha')) x = x.split() y = y.split() ctrlX = [float(ele) for ele in x] ctrlY = [float(ele) for ele in y] bezierX, bezierY = airfoil(ctrlX, ctrlY, 16) xf = XFoil() xf.Re = Re xf.M = 0 xf.max_iter = 100 xf.airfoil = Airfoil(np.array(bezierX), np.array(bezierY)) aero = xf.a(Alpha) xcp, cp = xf.get_cp_distribution() y = savgol_filter(cp, 5, 2) for i in range(30): y = savgol_filter(y, 5, 2) LD = aero[0] / aero[1] vol = PolyArea(bezierX, bezierY) print(len(xcp)) return jsonify(result=str(round(aero[0], 3)) + " " + str(round(aero[1], 3)) + " " + str(round(aero[2], 3)) + " " + str(round(LD, 2)) + " " + str(round(vol, 3)), xcp=xcp.tolist(), cp=y.tolist())
def get_cl(coord, xf=None, angle=5): if xf is None: xf = XFoil() xf.print = False xf.Re = 3e6 xf.max_iter = 100 datax, datay = coord.reshape(2, -1) xf.airfoil = Airfoil(x=datax, y=datay) c = xf.a(angle) cl= c[0] return cl
def get_torque(angular_velocity): torque_sum_small = 0 torque_sum_large = 0 w = angular_velocity for key, value in dfdict.items(): value["blade_velocity"] = value['r_position'] * w value["relative_velocity"] = round( math.sqrt(value["blade_velocity"]**2 + value["wind_velocity"]**2), 2) value["arctan"] = math.degrees( math.atan2(value["wind_velocity"], value["blade_velocity"])) aoa = round(value["arctan"] - value["pitch_angle"], 2) value["angle_of_attack"] = aoa re_n = round( value["relative_velocity"] * value["chord_length"] / 0.00001511, 3) value["Reynolds_number"] = re_n xf = XFoil() if key < 13: xf.airfoil = naca6409 else: xf.airfoil = naca2412 xf.Re = re_n xf.max_iter = 100 xf.n_crit = 9.00 xf.xtr = [1.00, 1.00] xf.M = 0 value["Cl"], value["Cd"], value["Cm"], value["Cp"] = xf.a(aoa) force_reference = 0.5 * density * value["relative_velocity"]**2 if math.isnan(value["Cl"]): value["torque"] = 0 else: lift = value["Cl"] * force_reference * 0.0125 * value[ 'chord_length'] drag = value["Cd"] * force_reference * 0.0125 * value[ 'chord_length'] value["torque"] = value["r_position"] * ( lift * math.sin(math.radians(value["pitch_angle"])) - drag * math.cos(math.radians(value["pitch_angle"]))) if key < 13: torque_sum_small += value["torque"] else: pass if key > 0: torque_sum_large += value["torque"] else: pass df2 = pd.DataFrame.from_dict(dfdict, orient="index") df_collection.append(df2) torque_sum_avg = 0.5 * (torque_sum_small + torque_sum_large) return torque_sum_avg
def total_dict(angular_velocity): torque_sum = 0 w = angular_velocity for key, value in dfdict.items(): value["blade_velocity"] = value['r_position'] * w value["relative_velocity"] = round( math.sqrt(value["blade_velocity"]**2 + value["wind_velocity"]**2), 2) value["arctan"] = math.degrees( math.atan2(value["wind_velocity"], value["blade_velocity"])) aoa = round(value["arctan"] - value["pitch_angle"], 1) value["angle_of_attack"] = aoa re_n = round(value["relative_velocity"] * value["chord_length"] / 0.00001511) value["Reynolds_number"] = re_n xf = XFoil() if key < 13: xf.airfoil = naca6409 else: xf.airfoil = naca2412 xf.Re = round(re_n / 100) * 100 xf.max_iter = 200 xf.n_crit = 9.00 xf.xtr = [1.00, 1.00] xf.M = 0 c_l, c_d, c_m, c_p = xf.a(aoa) force_reference = 0.5 * density * value["relative_velocity"]**2 if math.isnan(c_l): pass else: value["Cl"] = c_l value["Cd"] = c_d value["Cm"] = c_m value["Cp"] = c_p lift = c_l * force_reference * 0.0125 * value['chord_length'] drag = c_d * force_reference * 0.0125 * value['chord_length'] value["lift"] = lift value["drag"] = drag # value["torque"] = value["r_position"] * lift * math.sin(math.radians(value["pitch_angle"])) torque = value["r_position"] * ( lift * math.sin(math.radians(value["pitch_angle"])) - drag * math.cos(math.radians(value["pitch_angle"]))) value["torque"] = torque torque_sum += torque xf.reset_bls() # detailed_df = pd.DataFrame.from_dict(dfdict, orient="index") # print(detailed_df) print(torque_sum, angular_velocity) return dfdict, torque_sum
def evaluate(self,individual): DELTA = 1e10 #---------------------------------- #遺伝子に基づいて新翼型を生成 #---------------------------------- #遺伝子に基づきスプライン翼型を作成 x = individual[:int(len(individual)/2)] x.insert(0,1.0) x.insert(int(len(x)/2)+1,0.0) x.append(1.0) y = individual[int(len(individual)/2):] if not (all([u - d > 0 for u, d in zip(y[:int(len(y)/2)], y[int(len(y)/2):])]) or all([u - d < 0 for u, d in zip(y[:int(len(y)/2)], y[int(len(y)/2):])])): print("crossed") return [DELTA*10]*self.NOBJ y.insert(0,0.0) y.insert(int(len(y)/2)+1,0.0) y.append(0.0) newdat = fc.spline_foil(x, y, 200) shape_dat = fc.shape_dat([[a, b] for a, b in zip(newdat[0][::-1], newdat[1][::-1])]) #翼型の形に関する情報を取得する foil_para = fc.get_foil_para(shape_dat) mt, mta, mc, mca, s, crossed, bd, bt, bc, smooth, td = foil_para # mt: 最大翼厚(百分率) # mta: 最大翼厚位置(百分率) # mc: 最大キャンバー(百分率) # mca: 最大きゃんばー位置(百分率) # s: 翼型の下面における、最大y座標-最小y座標 # crossed: 翼型が交差しているならTrue,それ以外ならFalse # bd: 翼型の粗さ(大きいほど粗い) # bt: 翼厚分布の粗さ(大きいほど粗い) # bc: キャンバー分布の粗さ(大きいほど粗い) # smooth: 無視 # td: 翼厚分布 if crossed: print("crossed_a") return [DELTA*10]*self.NOBJ else: print("hi_a") #新しい翼型をAerofoilオブジェクトに適用 datx = np.array(newdat[0][::-1]) daty = np.array(newdat[1][::-1]) newfoil = Airfoil(x = datx, y = daty) #翼型の形に関する拘束条件 penalty = 0 if not all([t >= 0.0035 for t in td[10:80]]): penalty += 100 * (sum([abs(t - 0.0035)*10 for t in td[15:85] if t - 0.0035 < 0])) if not all([t <= 0.015 for t in td[:15]]): penalty += 100 * (sum([abs(t - 0.015)*10 for t in td[:15] if t > 0.015])) if mta > 0.4: penalty += 100 * (mta - 0.4) if mc < 0.0: penalty += 100 * (-mc) if datx[0] > 1.002 or datx[0] < 0.998: print("invalid foil") return [DELTA*10]*self.NOBJ #---------------------------------- #新翼型の解析 #---------------------------------- try: xf = XFoil() #レイノルズ数の設定 xf.airfoil = newfoil xf.Re = self.re xf.print = False xf.max_iter = 40 #xf.polar = "polar" + id #境界要素法計算時1ステップにおける計算回数 #xf.repanel(n_nodes = 180) #計算結果格納 #result = xf.OneAlpha() cl, cd, cm, cp = xf.a(5.0) #---------------------------------- #目的値 #---------------------------------- if cl >= 0: obj1 = 1/cl else: obj1 = self.delta obj2 = cd except Exception as e: obj1,obj2=[DELTA]*self.NOBJ traceback.print_exc() if (np.isnan(obj1)): obj1 = DELTA if (np.isnan(obj2)): obj2 = DELTA return [obj1 + penalty, obj2 + penalty]
class XFoilEnv(gym.Env): """ Description: A pole is attached by an un-actuated joint to a cart, which moves along a frictionless track. The pendulum starts upright, and the goal is to prevent it from falling over by increasing and reducing the cart's velocity. Source: This environment corresponds to the version of the cart-pole problem described by Barto, Sutton, and Anderson Observation: Type: Box(4) Num Observation Min Max 0 Cart Position -4.8 4.8 1 Cart Velocity -Inf Inf 2 Pole Angle -24 deg 24 deg 3 Pole Velocity At Tip -Inf Inf Actions: Type: Discrete(2) Num Action 0 Push cart to the left 1 Push cart to the right Note: The amount the velocity that is reduced or increased is not fixed; it depends on the angle the pole is pointing. This is because the center of gravity of the pole increases the amount of energy needed to move the cart underneath it Reward: Reward is 1 for every step taken, including the termination step Starting State: All observations are assigned a uniform random value in [-0.05..0.05] Episode Termination: Pole Angle is more than 12 degrees Cart Position is more than 2.4 (center of the cart reaches the edge of the display) Episode length is greater than 200 Solved Requirements Considered solved when the average reward is greater than or equal to 195.0 over 100 consecutive trials. """ metadata = { 'render.modes': ['human', 'rgb_array'], 'video.frames_per_second' : 50 } def __init__(self): self.xf = XFoil() self.min_action = np.array([0.1, 0.05, 1.0, 0.05, 0.4, 1.0, 0.0]) self.max_action = np.array([0.4, 0.4, 3.0, 3.0, 8.0, 10.0, 10.0]) ''' 測試開始, 可省略測試''' # (.01, .4), (.05, .4), (1, 3), (0.05, 3), (0.4, 8), (1, 10) # self.xf.airfoil = naca0012 # k = [0.08813299, 0.28250898, 2.80168427, 2.56204214, 1.48703742, 8.53824561] # k = [0.34422, 0.38976, 1.1, 2.9989, 1.6071, 9.9649] k = [0.1584, 0.1565, 2.1241, 1.8255, 11.6983, 3.827] # org # k = [0.1784, 0.1365, 2.1201, 1.8057, 3.8071, 11.7009] # k = [0.1472, 0.1638, 2.1041, 1.8156, 3.8141, 11.6808] # k = [0.1784, 0.1365, 2.1201, 1.8057, 3.8071, 11.7009] # k = [0.1783, 0.1366, 2.1283, 1.8073, 3.8325, 11.7176] # k = [0.25840, 0.14474, 2.22410, 1.92550, 11.59984, 3.92623] airfoil = construct_airfoil(*k) x, y = get_coords_plain(airfoil._spline(100)) self.xf.airfoil = Airfoil(x=x, y=y) # test_airfoil = NACA4(2, 3, 15) # a = test_airfoil.max_thickness() # self.xf.airfoil = test_airfoil.get_coords() self.xf.Re = 1e6 self.xf.M = 0.04 self.xf.print = False cl, cd, cm, cp = self.xf.a(9) x = np.array(x, dtype='float32') y = np.array(y,dtype='float32') # reward = cl/cd reward = cl ''' 測試結束, 可省略測試''' # cl, cd, cm, cp = self.xf.a(12.2357) # self.action_space = spaces.Discrete(30) self.action_space = spaces.Box(self.min_action, self.max_action, dtype=np.float32) # high = np.array([100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0]) high = np.array([100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0, 100.0]) self.observation_space = spaces.Box(-high, high, dtype=np.float32) #創建state大小(25,f22機翼,b3cl.cd.aoa) self.seed() self.viewer = None self.state = None self.steps_beyond_done = None def seed(self, seed=None): self.np_random, seed = seeding.np_random(seed) return [seed] def step(self, action): # assert self.action_space.contains(action), "%r (%s) invalid"%(action, type(action)) ''' action 包含 6 個機翼形狀控制參數以及 1 個攻角''' angular = action[6] k = action[0:6] '''將機翼控制座標傳入 airfoil, 並計算翼面之座標''' airfoil = construct_airfoil(*k) x, y = get_coords_plain(airfoil._spline(100)) '''將座標傳入 xfoil ''' self.xf.airfoil = Airfoil(x=x, y=y) # state = self.state self.xf.Re = 1e6 self.xf.M = 0.04 '''計算 cl, cd, cm, cp 當角度為 angular 時''' cl, cd, cm, cp = self.xf.a(angular) '''如果結果不穩定, 有無限大之值, 重設 state''' if np.isnan(cl) or np.isnan(cd) or np.isnan(cm) or np.isnan(cp): reward = -10.0 # self.state = self.reset() done = 0 else: '''如果結果穩定, 結束這個 weight 的計算''' '''升力最佳或升阻比最佳在此設定''' # reward = cl/cd reward = cl '''從機翼座標裡抽取 11 點當作 state''' x1, y1 = get_coords_plain(airfoil._spline(6)) '''state : 22 個機翼形狀值, 1 個角度, 1 個 cl, cd''' # self.state = np.append(np.append(np.append(np.append(x1, y1),angular), cl), cd) # self.state = np.append(np.append(x1, y1),angular) self.state = np.append(x1, y1) done = 1 return np.array(self.state), reward, done, {} def step1(self, action): # assert self.action_space.contains(action), "%r (%s) invalid"%(action, type(action)) angular = action[6] k = action[0:6] airfoil = construct_airfoil(*k) x, y = get_coords_plain(airfoil._spline(100)) x1, y1 = get_coords_plain(airfoil._spline(6)) self.xf.airfoil = Airfoil(x=x, y=y) # state = self.state self.xf.Re = 1e6 self.xf.M = 0.04 cl, cd, cm, cp = self.xf.a(angular) if np.isnan(cl) or np.isnan(cd) or np.isnan(cm) or np.isnan(cp): # reward = np.nan reward = -10 # self.state = self.reset() done = 0 else: # reward = cl/cd reward = cl done = 1 # self.state = np.append(np.append(np.append(np.append(x1, y1),angular), cl), cd) # self.state = np.append(np.append(x1, y1),angular) self.state = np.append(x1, y1) return np.array(self.state), reward, done, x, y def reset(self): # (.01, .4), (.05, .4), (1, 3), (0.05, 3), (0.4, 8), (1, 10) # 0.08813299, 0.28250898, 2.80168427, 2.56204214, 1.48703742, 8.53824561 '''為了避免 state 有無窮大的值, 所以設定decays範圍''' # decays = [1.0, 0.5, 0.25, 0.125, 0.0625] decays = [1.0, 0.999, 0.995, 0.99, 0.95, 0.9, 0.5] for decay in decays: tmp1 = self.np_random.uniform(low=-1.0, high=1.0, size=(7,)) # tmp = tmp * [0.39, 0.35, 2.0, 2.95, 7.6, 9, 10] + [0.01, 0.05, 1, 0.05, 0.4, 1, 0] # tmp = tmp * [0.01, 0.1, 0.5, 0.5, 0.1, 1.0, 5] + [0.08813299, 0.28250898, 2.50168427, 2.56, 1.487, 8.54, 0] # k = [0.1584, 0.1565, 2.1241, 1.8255, 3.827, 11.6983] '''從標準NACA5410開始找''' tmp1 = tmp1 * decay tmp = tmp1 * [0.12, 0.12, 0.12, 0.12, 0.12, 0.12, 5] + [0.1584, 0.1565, 2.1241, 1.8255, 11.6983, 3.827, 6] airfoil = construct_airfoil(*tmp) x, y = get_coords_plain(airfoil._spline(100)) self.xf.airfoil = Airfoil(x=x, y=y) self.xf.Re = 1e6 self.xf.M = 0.04 cl, cd, cm, cp = self.xf.a(tmp[6]) if not np.isnan(cl): break x, y = get_coords_plain(airfoil._spline(6)) self.xf.Re = 1e6 self.xf.M = 0.04 # self.state = np.append(np.append(np.append(np.append(x, y), tmp1[6]), cl), cd) # self.state = np.append(np.append(x, y), tmp1[6]) self.state = np.append(x, y) self.steps_beyond_done = None return np.array(self.state) def render(self, mode='human'): return None def close(self): if self.viewer: self.viewer.close() self.viewer = None
def feature_xfoil(cst_u, cst_l, t, Minf: float, Re, AoA, n_crit=0.1, fname='feature-xfoil.txt'): ''' Evaluate by xfoil and extract features. Inputs: --- cst-u, cst-l: list of upper/lower CST coefficients of the airfoil. \n t: airfoil thickness or None \n Minf: free stream Mach number for wall Mach number calculation \n Re, AoA (deg): flight condition (s), float or list, for Xfoil \n n_crit: critical amplification ratio for transition in xfoil \n fname: output file name. If None, then no output \n ### Dependencies: cst-modeling3d, xfoil ''' from cst_modeling.foil import cst_foil from xfoil import XFoil from xfoil.model import Airfoil #TODO: Build foil #! 201 is the maximum amount of points that xfoil can handle #! tail = 0.001 is to avoid point overlap xx, yu, yl, t0, R0 = cst_foil(201, cst_u, cst_l, x=None, t=t, tail=0.001) #! xfoil do not support leading edge of (0,0) on both upper and lower surface x = np.array(list(reversed(xx[1:])) + xx[1:]) y = np.array(list(reversed(yu[1:])) + yl[1:]) foil = Airfoil(x, y) #TODO: Xfoil xf = XFoil() xf.print = False xf.airfoil = foil xf.max_iter = 40 #* Transition by power law xf.n_crit = n_crit #TODO: Xfoil calculation if not isinstance(Re, list): Re = [Re] AoA = [AoA] n = len(Re) for i in range(n): xf.reset_bls() if Re[i] is not None: xf.Re = Re[i] cl, cd, cm, cp = xf.a(AoA[i]) x, cp = xf.get_cp_distribution() print(xf.Re, AoA[i], cl) #* Extract features fF = PhysicalXfoil(Minf, AoA[i], Re[i]) fF.setdata(x, y, cp) fF.extract_features() #* Output if fname is None: continue if i == 0: f = open(fname, 'w') else: f = open(fname, 'a') f.write('\n') f.write('%10s %15.6f \n' % ('Minf', Minf)) f.write('%10s %15.6f \n' % ('AoA', AoA[i])) f.write('%10s %15.6f \n' % ('Re', Re[i] / 1e6)) f.write('%10s %15.6f \n' % ('CL', cl)) f.write('%10s %15.6f \n' % ('Cd', cd)) f.write('%10s %15.6f \n' % ('Cm', cm)) f.close() fF.output_features(fname=fname, append=True)
#TODO: Xfoil xf = XFoil() xf.print = False xf.max_iter = 40 xf.airfoil = foil xf.xtr = [0.0, 0.0] Minf = 0.2 AoA = 8.0 Re = 1e7 fname = 'feature-xfoil.txt' xf.M = Minf xf.Re = Re cl, cd, cm, cp = xf.a(AoA) x, cp = xf.get_cp_distribution() with open(fname, 'w') as f: f.write('%10s %15.6f \n'%('Minf', Minf)) f.write('%10s %15.6f \n'%('AoA', AoA)) f.write('%10s %15.6f \n'%('Re', Re/1e6)) f.write('%10s %15.6f \n'%('CL', cl)) f.write('%10s %15.6f \n'%('Cd', cd)) f.write('%10s %15.6f \n'%('Cm', cm)) fF = PhysicalXfoil(Minf, AoA, Re) fF.setdata(x,y,cp) fF.extract_features() fF.output_features(fname=fname, append=True)