def _calc_area(self): # Calculates the panel area from the two constituent triangles A = 0.5 * norm( cross(self.vertices[1] - self.vertices[0], self.vertices[2] - self.vertices[0])) return A + 0.5 * norm( cross(self.vertices[2] - self.vertices[0], self.vertices[3] - self.vertices[0]))
def calc_local_coords(self, **kwargs): """Calculates panel local coords (dependent on flow properties). Parameters ---------- M : float Freestream Mach number. """ # Get kwargs M = kwargs["M"] c_0 = kwargs["c_0"] C_0 = kwargs["C_0"] B_0 = kwargs["B_0"] s = kwargs["s"] B = kwargs["B"] # Calculate tangent vector compressible norms (if applicable) if hasattr(self, "t"): self.t_comp_norm = np.zeros(3) for i, t in enumerate(self.t): self.t_comp_norm[i] = inner(t, t)-M**2*inner(c_0, t)**2 # Calculate conormal vector self.n_co = self.n-M**2*inner(c_0, self.n)*c_0 # Check inclination self.n_co = np.einsum('ij,j', B_0, self.n) self._incl = inner(self.n, self.n_co) if abs(self._incl)<1e-10: raise MachInclinedError self._r = np.sign(self._incl) # Get panel coordinate directions v_0 = cross(self.n, c_0) v_0 /= norm(v_0) u_0 = cross(v_0, self.n) u_0 /= norm(u_0) # Calculate transformation matrix # It should be that det(A) = B**2 (see Epton & Magnus pp. E.3-16) self._A = np.zeros((3,3)) denom = abs(self._incl)**-0.5 self._A[0,:] = denom*np.einsum('ij,j', C_0, u_0) self._A[1,:] = self._r*s/B*np.einsum('ij,j', C_0, v_0) self._A[2,:] = B*denom*self.n # Calculate area Jacobian self._J = 1.0/B*denom
def _calc_skewness(self): # Calculates the skewness parameters for this panel (if not triangular) # Get skewness parameters for 4-sided panel if self.N==4: self.C_skew = np.zeros((2,4)) denom = inner(cross(self.midpoints[3]-self.center, self.midpoints[0]-self.center), self.n) self.C_skew[0,0] = inner(cross(self.vertices[0]-self.midpoints[3], self.midpoints[0]-self.center), self.n)/denom self.C_skew[1,0] = inner(cross(self.midpoints[3]-self.center, self.vertices[0]-self.center), self.n)/denom self.C_skew[0,1] = self.C_skew[0,0] self.C_skew[1,1] = -self.C_skew[1,0] self.C_skew[0,2] = -self.C_skew[0,0] self.C_skew[1,2] = -self.C_skew[1,0] self.C_skew[0,3] = -self.C_skew[0,0] self.C_skew[1,3] = self.C_skew[1,0]
def __init__(self, **kwargs): # Store vertices self.vertices = np.zeros((3,3)) self.vertices[0] = kwargs["v0"] self.vertices[1] = kwargs["v1"] self.vertices[2] = kwargs["v2"] self._projected = kwargs.get("projected", False) # Calculate area and normal vector n = cross(self.vertices[1]-self.vertices[0], self.vertices[2]-self.vertices[1]) N = norm(n) self.A = 0.5*N self.n = n/N # Check for zero area in projected panel if self.A<1e-10 and self._projected: self.null_panel = True else: self.null_panel = False # Calculate edge tangents self.t = np.roll(self.vertices, 1, axis=0)-self.vertices self.t /= np.linalg.norm(self.t, axis=1, keepdims=True) self._calc_geom_props()
def _calc_normal(self): # Calculates the panel unit normal vector # Assumes the panel is planar d1 = self.vertices[1] - self.vertices[0] d2 = self.vertices[2] - self.vertices[1] N = cross(d1, d2) return N / norm(N)
def __init__(self, **kwargs): # Store vertices self.vertices = np.zeros((4,3)) self.vertices[0] = kwargs.get("v0") self.vertices[1] = kwargs.get("v1") self.vertices[2] = kwargs.get("v2") self.vertices[3] = kwargs.get("v3", self.vertices[2]) # Will get removed by _check_collapsed_vertices() # Store edge number self.edge = kwargs.get("edge", [0]) # Determine if this is a projected panel self._projected = kwargs.get("projected", False) # Check for collapsed points self._check_collapsed_vertices(kwargs.get("tol", 1e-8)) # Calculate midpoints self.midpoints = 0.5*(self.vertices+np.roll(self.vertices, 1, axis=0)) # Calculate normal vector; this is simpler than the method used in PAN AIR, which is able to handle # the case where the midpoints and center point do not lie in a flat plane [Epton & Magnus section D.2] self.n = cross(self.midpoints[1]-self.midpoints[0], self.midpoints[2]-self.midpoints[1]) self.n /= norm(self.n) # Other calculations self._calc_geom_props() self._calc_skewness() # Setup projected panel if not self._projected: self._initialize_projected_panel() # Initialize subpanels self.subpanels = [] for i in range(self.N): # Outer subpanel self.subpanels.append(Subpanel(v0=self.midpoints[i-1], v1=self.vertices[i], v2=self.midpoints[i], projected=self._projected)) # Inner subpanel self.subpanels.append(Subpanel(v0=self.midpoints[i], v1=self.center, v2=self.midpoints[i-1], projected=self._projected)) # Initialize half panels (only if the panel is not already triangular) if self.N==4: self.half_panels = [] for i in range(self.N): self.half_panels.append(Subpanel(v0=self.vertices[i-2], v1=self.vertices[i-1], v2=self.vertices[i])) else: self.half_panels = False
def __init__(self, **kwargs): # Store vertices self.vertices = np.zeros((3, 3)) self.vertices[0] = kwargs.get("v0") self.vertices[1] = kwargs.get("v1") self.vertices[2] = kwargs.get("v2") self.N = 3 super().__init__(**kwargs) # Set up local coordinate transformation n, _, _ = self.get_info() self.A_t = np.zeros((3, 3)) self.A_t[0] = self.vertices[1] - self.vertices[0] self.A_t[0] /= norm(self.A_t[0]) self.A_t[1] = cross(n, self.A_t[0]) self.A_t[2] = n
def __init__(self, **kwargs): # Store vertices self.vertices = np.zeros((4, 3)) self.vertices[0] = kwargs.get("v0") self.vertices[1] = kwargs.get("v1") self.vertices[2] = kwargs.get("v2") self.vertices[3] = kwargs.get("v3") self.midpoints = 0.5 * (self.vertices + np.roll(self.vertices, 1, axis=0)) self.N = 4 super().__init__(**kwargs) # Set up local coordinate transformation n = self._calc_normal() self.A_t = np.zeros((3, 3)) self.A_t[0] = self.midpoints[1] - self.midpoints[0] self.A_t[0] /= norm(self.A_t[0]) self.A_t[1] = cross(n, self.A_t[0]) self.A_t[2] = n
def _calc_area(self): # Calculates the panel area return 0.5 * norm( cross(self.vertices[1] - self.vertices[0], self.vertices[2] - self.vertices[0]))
def _calc_normal(self): # Calculates the normal based off of the edge midpoints n = cross(self.midpoints[1] - self.midpoints[0], self.midpoints[2] - self.midpoints[1]) return n / norm(n)