Source code for sharpy.linear.src.gridmapping

"""Mapping methods for bound surface panels

S. Maraniello, 19 May 2018
"""

import numpy as np
import sharpy.utils.cout_utils as cout


[docs]class AeroGridMap(): """ Produces mapping between panels, segment and vertices of a surface. Grid elements are identified through the indices (m,n), where: - m: chordwise index - n: spanwise index The same indexing is applied to panel, vertices and segments. Elements: - panels=(M,N) - vertices=(M+1,N+1) - segments: these are divided in segments developing along the chordwise and spanwise directions. - chordwise: (M,N+1) - spanwise: (M+1,N) Mapping structures: - Mpv: for each panel (mp,np) returns the chord/span-wise indices of its vertices, (mv,nv). This has size (M,N,4,2) - Mps: maps each panel (mp,np) to the ii-th segment. This has size (M,N,4,2) # - Mps_extr: for each panel (m,n) returns the indices of the extrema of each side # of the panel. Note: - mapping matrices are stored as np.int16 or np.int32 arrays """ def __init__(self, M: 'number of chord-wise', N: 'number of span-wise'): ### init self.M = M self.N = N self.K = M * N # panels number self.Kzeta = (M + 1) * (N + 1) # vertices number ### format self.intxx = np.int16 if self.Kzeta > np.iinfo(np.int16).max: self.intxx = np.int32 ### shapes for multi-dimensional arrays self.shape_pan_scal = (M, N) self.shape_pan_vect = (3, M, N) self.shape_vert_scal = (M + 1, N + 1) self.shape_vert_vect = (3, M + 1, N + 1) # local mapping segment/vertices of a panel self.svec = np.array([0, 1, 2, 3], dtype=self.intxx) # seg. number self.avec = np.array([0, 1, 2, 3], dtype=self.intxx) # 1st vertex of seg. self.bvec = np.array([1, 2, 3, 0], dtype=self.intxx) # 2nd vertex of seg. # deltas to convert panel (m,n) to vertices (m,n) indices. For each # vertex of the panel: # m_ver,n_ver = m+self.dmver, n+self.dnver self.dmver = np.array([0, 1, 1, 0], dtype=self.intxx) self.dnver = np.array([0, 0, 1, 1], dtype=self.intxx) ### variables 1D <-> nD mapping # # example: # A=np.random.rand(3,4,5) # a=A.reshape(-1,order='C') # Na=len(a) # ind_1d=range(Na) # ind_3d=np.unravel_index(ind_1d,A.shape) # ind_1d=np.ravel_multi_index(ind_3d,A.shape) # a[range(Na)]==a[ind_1d]==A[ind_3d] # vectors defined at vertices self.ind_1d_vert_vert = range(3 * self.Kzeta) self.ind_3d_vert_vect = np.unravel_index(self.ind_1d_vert_vert, shape=self.shape_vert_vect, order='C') # scalars defined at panels self.ind_1d_pan_scal = range(self.K) self.ind_2d_pan_scal = np.unravel_index(self.ind_1d_pan_scal, shape=self.shape_pan_scal, order='C') # ### mapping to/from 1D arrays # self.maps.ind_vector_vertices_to_3d= # self.maps.ind_vector_vertices_to_1d= # self.maps.ind_scalar_panel_to_3d= # self.maps.ind_scalar_panel_to_1d= def map_all(self): self.map_panels_to_vertices() self.map_panels_to_segments() self.map_vertices_to_panels() # ------------------------------------------------------ panels to vertices
[docs] def map_panels_to_vertices_1D_scalar(self): """ Mapping: - FROM: the index of a scalar quantity defined at panel collocation point and stored in 1D array. - TO: index of a scalar quantity defined at vertices and stored in 1D The Mpv1d_scalar has size (K,4) where: [1d index of panel, index of vertex 0,1,2 or 3] """ self.Mpv1d_scalar = np.zeros((self.K, 4), dtype=self.intxx) # Map: panels 1D -> 3d if not hasattr(self, 'Mpv'): self.map_panels_to_vertices() mn_panels = np.unravel_index(range(self.K), shape=self.shape_pan_scal, order='C') # Mpv_new=self.Mpv[mn_panels] # from k to vertices for kk in range(self.K): # map from kk-th panel to vertices (m,n) mpv = self.Mpv[mn_panels[0][kk], mn_panels[1][kk], :, :] # loop through vertices for vv in range(4): self.Mpv1d_scalar[kk, vv] = np.ravel_multi_index(mpv[vv, :], dims=self.shape_vert_scal, order='C')
[docs] def map_panels_to_vertices(self): """ Mapping from panel of vertices. self.Mpv is a (M,N,4,2) array such that its element are: [m, n, local_vertex_number, spanwise/chordwise indices of vertex] """ M, N = self.M, self.N self.Mpv = np.zeros((M, N, 4, 2), dtype=self.intxx) for mm in range(M): for nn in range(N): self.Mpv[mm, nn, :, :] = self.from_panel_to_vertices(mm, nn)
[docs] def from_panel_to_vertices(self, m: 'chordwise index', n: 'spanwise index'): """ From panel of indices (m,n) to indices of vertices """ # mpv=np.zeros((4,2),dtype=self.intxx) # mpv[0,:]=m ,n # mpv[1,:]=m+1,n # mpv[2,:]=m+1,n+1 # mpv[3,:]=m ,n+1 mpv = np.array([m + self.dmver, n + self.dnver]).T return mpv
# ------------------------------------------------------ vertices to panels
[docs] def map_vertices_to_panels_1D_scalar(self): """ Mapping: - FROM: the index of a scalar quantity defined at vertices and stored in 1D array. - TO: index of a scalar quantity defined at panels and stored in 1D The Mpv1d_scalar has size (Kzeta,4) where: [1d index of vertex, index of vertex 0,1,2 or 3 w.r.t. panel] """ self.Mvp1d_scalar = np.zeros((self.Kzeta, 4), dtype=self.intxx) # Map: vertices 1D -> 3d if not hasattr(self, 'Mvp'): self.map_vertices_to_panels() mn_vertices = np.unravel_index(range(self.Kzeta), shape=self.shape_vert_scal, order='C') for kk in range(self.Kzeta): # map from kk-th vertex to panels (m,n) mvp = self.Mvp[mn_vertices[0][kk], mn_vertices[1][kk], :, :] # loop through vertex local order for vv in range(4): # check if vertex is vv-th for any panel if np.all(mvp[vv, :] != -1): self.Mvp1d_scalar[kk, vv] = np.ravel_multi_index(mvp[vv, :], dims=self.shape_pan_scal, order='C') else: self.Mvp1d_scalar[kk, vv] = -1
[docs] def map_vertices_to_panels(self): """ Maps from vertices to panels. Produces a (M+1,N+1,4,2) array, associating vertices to panels. Its elements are: [m vertex, n vertex, vertex local index, chordwise/spanwise panel indices] """ M, N = self.M, self.N self.Mvp = np.zeros((M + 1, N + 1, 4, 2), dtype=self.intxx) for mm in range(M + 1): for nn in range(N + 1): self.Mvp[mm, nn, :, :] = self.from_vertex_to_panel(mm, nn) # remove out of grid panels mmvec_rem = self.Mvp[mm, nn, :, 0] >= M nnvec_rem = self.Mvp[mm, nn, :, 1] >= N self.Mvp[mm, nn, mmvec_rem, 0] = -1 self.Mvp[mm, nn, nnvec_rem, 1] = -1
[docs] def from_vertex_to_panel(self, m: 'chordwise index', n: 'spanwise index'): """ Returns the panel for which the vertex is locally numbered as 0,1,2,3. Returns a (4,2) array such that its elements are: [vv_local,(m,n) of panel] where vv_local is the local verteix number. Important: indices -1 are possible is the vertex does not have local index 0,1,2 or 3 with respect to any panel. """ mvp = np.zeros((4, 2), dtype=self.intxx) mvp[0, :] = [m, n] mvp[1, :] = [m - 1, n] mvp[2, :] = [m - 1, n - 1] mvp[3, :] = [m, n - 1] return mvp
# ------------------------------------------------------ panels to segments
[docs] def map_panels_to_segments(self): """ Mapping from panel of segments. self.Mpv is a (M,N,4,2) array such that: [m, n, local_segment_number, chordwise/spanwise index of segment,] """ M, N = self.M, self.N self.Mps = np.zeros((M, N, 4, 2), dtype=self.intxx) for mm in range(M): for nn in range(N): self.Mps[mm, nn, :, :] = self.from_panel_to_segments(mm, nn)
[docs] def from_panel_to_segments(self, m: 'chordwise index', n: 'spanwise index'): """ For each panel (m,n) it provides the ms,ns indices of each segment. """ mps = np.zeros((4, 2), dtype=np.int32) mps[0, :] = m, n mps[1, :] = m + 1, n mps[2, :] = m, n + 1 mps[3, :] = m, n return mps
# # ---------------------------------------------- panels to segments extrema # def map_panels_to_segments(self): # """ # Mapping from panel of segments. self.Mpv is a (M,N,4,2,2) array such # that: # [m, n, local_segment_number, # spanwise/chordwise indices of vertex 0, # spanwise/chordwise indices of vertex 1] # """ # M,N=self.M,self.N # self.Mps=np.zeros((M,N,4,2,2),dtype=self.intxx) # for mm in range(M): # for nn in range(N): # self.Mps[mm,nn,:,:,:]=self.from_panel_to_segments(mm,nn) # def from_panel_to_segments(self,m:'chordwise index',n:'spanwise index'): # """ # For each panel (m,n) it provides the indices of the extrema of each # segment. # [segment number,indices extrema 0,indices extrema 1] # """ # mpv=self.from_panel_to_vertices(m,n) # mps=np.zeros((4,2,2),dtype=np.int32) # mps[0,0,:],mps[0,1,:]=mpv[0,:],mpv[1,:] # mps[1,0,:],mps[1,1,:]=mpv[1,:],mpv[2,:] # mps[2,0,:],mps[2,1,:]=mpv[2,:],mpv[3,:] # mps[3,0,:],mps[3,1,:]=mpv[3,:],mpv[0,:] # return mps if __name__ == '__main__': M, N = 3, 5 Map = AeroGridMap(M, N) ### multi-dimensional mapping Map.map_panels_to_vertices() Map.map_panels_to_segments() Map.map_vertices_to_panels() # 1D mappings Map.map_panels_to_vertices_1D_scalar() Map.map_vertices_to_panels_1D_scalar()