tmp

# -*- coding: utf-8 -*-
"""VLM.ipynb

Automatically generated by Colab.

Original file is located at
    https://colab.research.google.com/drive/1M5P0QMl-ksPZJ7MXuaPVcVsL7hJz84VI
"""

import numpy as np
import pandas as pd
from scipy.linalg import solve
from scipy.spatial.transform import Rotation
import math
import matplotlib.pyplot as plt
import matplotlib.gridspec as gridspec  # サブプロットのレイアウト用のgridspecモジュール
import cmath

class VLM:
    def __init__(self, alpha, V, rho, Sref=None, b=None, AR=None, taperRatio=None, cr=None, sweep025=0, dihedral=0, iw=0, washout=0, airfoil='0012'):
        self.alpha = math.radians(alpha) # 迎角 [deg]
        self.V = V # 対気速度 [m/s]
        self.rho = rho # 空気密度 [kg/m^3]

        self.Sref = Sref # 面積 [m^2]
        self.b = b # スパン [m]
        self.AR = AR # アスペクト比 [m]
        self.swp = math.radians(sweep025) # 1/4コードライン後退角
        self.tr = taperRatio # テーパー比
        self.dh = math.radians(dihedral) #上反角
        self.cr = cr # 翼根コード長 [m]
        self.iw = iw # 翼根取付角 [deg]
        self.washout = washout # ねじり下げ [deg]
        self.tbarc = 0.12 # 翼厚比 [-]
        self.cMAC = None # 平均空力翼弦長 [m]
        self.yMAC = None
        self.x25MAC = None
        self.airfoil = airfoil # NACA 4-digit airfoil

        self.nx = 16
        self.ny = 10 # セミスパン方向分割数
        self.nSTA = 2 * self.ny + 1
        self.nPanel = 2 * self.ny * self.nx
        self.chord = None
        self.x = np.zeros((self.nSTA) * self.nx + self.nSTA)
        self.y = np.zeros((self.nSTA) * self.nx + self.nSTA)
        self.z = np.zeros((self.nSTA) * self.nx + self.nSTA)
        self.cp0 = np.zeros((self.nPanel,3))
        self.sp1 = np.zeros((self.nPanel,3))
        self.sp2 = np.zeros((self.nPanel,3))
        self.dzdx = np.zeros(self.nPanel)
        self.dS = np.zeros(self.nPanel)
        self.normV = np.zeros((self.nPanel,3))
        self.circulation = None
        self.Cp = None

    def calculate_geom(self):
        if self.Sref is None:
          self.Sref = self.AR * self.b
        if self.b is None:
          self.b = np.sqrt(self.AR * self.S)
        if self.AR is None:
          self.AR = self.b ** 2 /self.Sref

        if self.cr is None:
          self.cr = self.Sref / (1 + self.tr) / (self.b / 2)
        if self.tr is None:
          self.tr = self.Sref / self.cr / (self.b / 2) - 1

        self.cMAC = (2/3)*self.cr*(1+self.tr+self.tr**2)/(1+self.tr)
        self.yMAC = (1/3)*(1+2*self.tr)/(1+self.tr)*(self.b/2)

        ySTA = self.b * (np.arange(self.nSTA)-self.ny)/(self.nSTA-1)
        self.chord = self.cr * (1 + (self.tr - 1) * abs(ySTA)/(self.b/2))

        return

    def calculate_mesh(self):

        ySTA = self.b * (np.arange(self.nSTA)-self.ny)/(self.nSTA-1)
        theta = (self.iw + self.washout * abs(ySTA / (self.b / 2)))

        m = float(self.airfoil[0])/100
        p = float(self.airfoil[1])/10

        xc = (1-np.cos(np.pi/2*(np.arange(self.nx+1)/self.nx)))
        yc = np.zeros_like(xc)
        zc = np.where(xc < p, m / max(p**2, 1e-5) * (2*p*xc - xc**2), m / ((1-p)**2) *((1-2*p)+2*p*xc-xc**2))

        for i in range(self.nSTA):
            n1 = (i+0)*(self.nx+1)
            n2 = (i+1)*(self.nx+1)

            rot = Rotation.from_euler('Y', theta[i], degrees=True)
            coord = rot.apply(np.stack([xc-0.25, yc, zc],axis=1))

            self.x[n1:n2] = coord[:,0] * self.chord[i] + np.abs(ySTA[i]) * np.sin(self.swp)
            self.y[n1:n2] = coord[:,1] * self.chord[i] + ySTA[i] * np.cos(self.dh)
            self.z[n1:n2] = coord[:,2] * self.chord[i] + np.abs(ySTA[i]) * np.sin(self.dh)

        #self.x -= np.max(self.x)

        sinD = math.sin(self.dh)
        cosD = math.cos(self.dh)
        sinE = np.sin(self.dzdx)
        cosE = np.cos(self.dzdx)

        self.normV = np.array([-sinE*cosD,-cosE*sinD,cosE*cosD]).T

        coord = np.stack([self.x,self.y,self.z],axis=1)

        coord_cp = coord[:-1] * 0.25 + coord[1:] * 0.75
        coord_sp = coord[:-1] * 0.75 + coord[1:] * 0.25
        coord_diff = np.diff(coord, axis=0)
        coord_norm = np.sqrt(np.sum(coord_diff**2,axis=1))

        for i in range(2 * self.ny):
            for j in range(self.nx):

                n1 = i * self.nx + j
                m1 = (i+0) * (self.nx + 1) + j
                m2 = (i+1) * (self.nx + 1) + j

                self.cp0[n1] = (coord_cp[m1] + coord_cp[m2]) / 2
                self.sp1[n1] = coord_sp[m1]
                self.sp2[n1] = coord_sp[m2]

                self.dzdx[n1] = math.atan2((coord_diff[m1,2] + coord_diff[m2,2]) / 2, (coord_diff[m1,0] + coord_diff[m2,0]) / 2)
                self.dS[n1] = (coord_norm[m1]+coord_norm[m2]) * np.abs(coord[m1,1]-coord[m2,1])/2

        return

    def calculate_Cij(self,cp):

        csp1 = cp.reshape(-1,1,3) - self.sp1.reshape(1,-1,3)
        csp2 = cp.reshape(-1,1,3) - self.sp2.reshape(1,-1,3)
        sp21 = self.sp2 - self.sp1

        dx1, dy1, dz1 = csp1[:,:,0], csp1[:,:,1], csp1[:,:,2]
        dx2, dy2, dz2 = csp2[:,:,0], csp2[:,:,1], csp2[:,:,2]
        dx21, dy21, dz21 = sp21[:,0], sp21[:,1], sp21[:,2]

        r1 = np.sqrt(dx1 ** 2 + dy1 ** 2 + dz1 ** 2)
        r2 = np.sqrt(dx2 ** 2 + dy2 ** 2 + dz2 ** 2)
        r21 = ((dy1*dz2-dz1*dy2)**2+(dz1*dx2-dx1*dz2)**2+(dx1*dy2-dy1*dx2)**2)

        Aij = (dy1*dz2-dz1*dy2)/r21 * ((dx21*dx1+dy21*dy1+dz21*dz1)/r1-(dx21*dx2+dy21*dy2+dz21*dz2)/r2)
        Bij = (dz1*dx2-dx1*dz2)/r21 * ((dx21*dx1+dy21*dy1+dz21*dz1)/r1-(dx21*dx2+dy21*dy2+dz21*dz2)/r2) - dz1/(dz1**2+dy1**2)*(1+dx1/r1) + dz2/(dz2**2+dy2**2)*(1+dx2/r2)
        Cij = (dx1*dy2-dy1*dx2)/r21 * ((dx21*dx1+dy21*dy1+dz21*dz1)/r1-(dx21*dx2+dy21*dy2+dz21*dz2)/r2) - dy1/(dz1**2+dy1**2)*(1+dx1/r1) + dy2/(dz2**2+dy2**2)*(1+dx2/r2)

        return Aij, Bij, Cij

    def solve_equation(self, Aij,Bij,Cij):

        cosD = math.cos(self.dh)
        matrix1 = Aij * self.normV[:,0].T + Bij * self.normV[:,1].T + Cij * self.normV[:,2].T # * self.cMAC
        matrix2 = -4 * np.pi * self.V * np.sin(self.alpha - self.dzdx) * cosD

        self.circulation = solve(matrix1, matrix2)

        return

    def calculate_section_coeff(self):
        wall = self.cp0 # + surf * self.cMAC * 0.001 *  self.normV
        Aij, Bij, Cij = self.calculate_Cij(wall)

        ui = (1 / (4 * math.pi)) * (Aij @ self.circulation)
        vi = (1 / (4 * math.pi)) * (Bij @ self.circulation)
        wi = (1 / (4 * math.pi)) * (Cij @ self.circulation)

        Vx = -self.V*math.cos(self.alpha)
        Vz = -self.V*math.sin(self.alpha)
        Vwall = np.sqrt((Vx+ui)**2 + vi**2 + (Vz+wi)**2)
        self.Cp = 1 - (Vwall/self.V)**2

        pn = -self.Cp * self.dS * np.cos(self.dzdx)
        pt =  self.Cp * self.dS * np.sin(self.dzdx)
        x = wall[:,0]
        z = wall[:,2]

        cl = 2 * np.sum(pn * math.cos(self.alpha) - pt * math.sin(self.alpha))
        cm = 2 * -np.sum(pn * x + pt * z)
        cd = 2 * np.sum(pn * math.sin(self.alpha) + pt * math.cos(self.alpha))

        cl /= self.Sref
        cd /= self.Sref
        cm /= (self.Sref * self.cMAC)

        print(cl,cm,cd)

        return cl, cd, cm

    def plot_3d(self):

        fig = plt.figure()  # 図のサイズを指定して作成
        ax = fig.add_subplot(111, projection='3d')  # 3Dプロット用のサブプロットを追加
        #ax.plot_wireframe(self.cp0[:,0].reshape(2*self.ny,-1), self.cp0[:,1].reshape(2*self.ny,-1), self.cp0[:,2].reshape(2*self.ny,-1), color='blue')  # 3Dプロット
        #ax.plot_wireframe(self.cp0[:,0].reshape(2*self.ny,-1), self.cp0[:,1].reshape(2*self.ny,-1), self.circulation.reshape(2*self.ny,-1), color='red')  # 3Dプロット
        #ax.plot_wireframe(self.cp0[:,0].reshape(2*self.ny,-1), self.cp0[:,1].reshape(2*self.ny,-1), self.Cp.reshape(2*self.ny,-1), color='red')  # 3Dプロット
        ax.plot_wireframe(self.x.reshape(2*self.ny+1,-1), self.y.reshape(2*self.ny+1,-1), self.z.reshape(2*self.ny+1,-1), color='black')  # 3Dプロット
        ax.set_aspect('equal')

    def run(self):
        # VLMの計算を実行
        #self.calculate_chord()
        self.calculate_geom()
        self.calculate_mesh()
        Aij, Bij, Cij = self.calculate_Cij(self.cp0)
        #print(Cij)

        self.solve_equation(Aij,Bij,Cij)

        cl, cd, cm = self.calculate_section_coeff()
        self.plot_3d()

        fig = plt.figure(figsize=(16/2, 9/2))  # 図のサイズを指定して作成
        ax = fig.add_subplot(111)  # 3Dプロット用のサブプロットを追加
        #ax.scatter(x.reshape(self.nx+1,-1)[:,:-1], y.reshape(self.nx+1,-1)[:,:-1], Cp.T, color='blue')  # 3Dプロット
        #ax.scatter(np.concatenate([np.flip(x.reshape(2*self.ny+1,-1)[:-1,:]),x.reshape(2*self.ny+1,-1)[:-1,1:]],axis=1), np.concatenate([np.flip(y.reshape(2*self.ny+1,-1)[:-1,:]),y.reshape(2*self.ny+1,-1)[:-1,1:]],axis=1), Cp_list, color='blue')  # 3Dプロット
        #ax.plot(self.x.reshape(-1,self.nx+1)[:-1,:-1].T, self.Cp[0].reshape(-1,self.nx).T, '.-', color='blue')
        #ax.plot(self.x.reshape(-1,self.nx+1).T, self.z.reshape(-1,self.nx+1).T, '.-', color='red')
        ax.plot(self.cp0[:,0].reshape(-1,self.nx).T, self.Cp.reshape(-1,self.nx).T, '.-', color='red')

        #ax.plot(self.cp0[:,0], self.cp0[:,2], '.-', color='blue')
        #wall = self.cp0 + 1 * 0.1 *  self.normV
        #ax.plot(wall[:,0], wall[:,2], '.-', color='red')
        #wall = self.cp0 -1 * 0.1 *  self.normV
        #ax.plot(wall[:,0], wall[:,2], '.-', color='green')
        #ax.set_aspect('equal')
#        print(cl)

if __name__ == "__main__":
    vlm = VLM(alpha=1, Sref=10, b=10, dihedral=5, sweep025=30, taperRatio=1, airfoil='4412', iw=0,washout=0, V=30, rho=1.225)
    vlm.run()



質問・感想・意見などあれば気軽にTwitterのDMかコメントお願いします!
スポンサーリンク