plot3d 1.6.4__tar.gz → 1.6.7__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: plot3d
3
- Version: 1.6.4
3
+ Version: 1.6.7
4
4
  Summary: Plot3D python utilities for reading and writing and also finding connectivity between blocks
5
5
  Author: Paht Juangphanich
6
6
  Author-email: paht.juangphanich@nasa.gov
@@ -1,13 +1,13 @@
1
- from .block import Block, reduce_blocks
2
- from .blockfunctions import rotate_block,get_outer_bounds,block_connection_matrix
3
- from .connectivity import find_matching_blocks, get_face_intersection, connectivity_fast, face_matches_to_dict
4
- from .face import Face
5
- from .facefunctions import create_face_from_diagonals, get_outer_faces, find_connected_faces, find_bounding_faces,split_face,find_face_nearest_point,match_faces_dict_to_list,outer_face_dict_to_list,find_closest_block
6
- from .read import read_plot3D, read_ap_nasa
7
- from .write import write_plot3D
8
- from .differencing import find_edges, find_face_edges
9
- from .periodicity import periodicity, periodicity_fast, create_rotation_matrix, rotated_periodicity, translational_periodicity
10
- from .point_match import point_match
11
- from .split_block import split_blocks, Direction
12
- from .listfunctions import unique_pairs
13
- from .graph import block_to_graph,get_face_vertex_indices,get_starting_vertex,add_connectivity_to_graph
1
+ from .block import Block, reduce_blocks
2
+ from .blockfunctions import rotate_block,get_outer_bounds,block_connection_matrix
3
+ from .connectivity import find_matching_blocks, get_face_intersection, connectivity_fast, face_matches_to_dict
4
+ from .face import Face
5
+ from .facefunctions import create_face_from_diagonals, get_outer_faces, find_connected_faces, find_bounding_faces,split_face,find_face_nearest_point,match_faces_dict_to_list,outer_face_dict_to_list,find_closest_block
6
+ from .read import read_plot3D, read_ap_nasa
7
+ from .write import write_plot3D
8
+ from .differencing import find_edges, find_face_edges
9
+ from .periodicity import periodicity, periodicity_fast, create_rotation_matrix, rotated_periodicity, translational_periodicity
10
+ from .point_match import point_match
11
+ from .split_block import split_blocks, Direction
12
+ from .listfunctions import unique_pairs
13
+ from .graph import block_to_graph,get_face_vertex_indices,get_starting_vertex,add_connectivity_to_graph, block_connectivity_to_graph
@@ -1,254 +1,264 @@
1
- import numpy as np
2
- import math
3
- from tqdm import trange
4
- from typing import List
5
-
6
- class Block:
7
- """Plot3D Block definition
8
- """
9
- def __init__(self, X:np.ndarray,Y:np.ndarray,Z:np.ndarray):
10
- """Initializes the block using all the X,Y,Z coordinates of the block
11
-
12
- Args:
13
- X (np.ndarray): All the X coordinates (i,j,k)
14
- Y (np.ndarray): All the Y coordinates (i,j,k)
15
- Z (np.ndarray): All the Z coordinates (i,j,k)
16
-
17
- """
18
- self.IMAX,self.JMAX,self.KMAX = X.shape;
19
- self.X = X
20
- self.Y = Y
21
- self.Z = Z
22
- # Centroid
23
- self.cx = np.mean(X)
24
- self.cy = np.mean(Y)
25
- self.cz = np.mean(Z)
26
-
27
-
28
- def scale(self,factor:float):
29
- """Scales a mesh by a certain factor
30
-
31
- Args:
32
- factor (float): _description_
33
- """
34
-
35
- self.X *= factor
36
- self.Y *= factor
37
- self.Z *= factor
38
-
39
- def shift(self,shift_amount:float,direction:str="z"):
40
- """shifts the blocks by a certain amount
41
-
42
- Args:
43
- shift_amount (float): _description_
44
- direction (str, optional): _description_. Defaults to "z".
45
- """
46
- if direction.lower() == 'z':
47
- self.Z +=shift_amount
48
- elif direction.lower() == 'y':
49
- self.Y +=shift_amount
50
- elif direction.lower() == 'x':
51
- self.X +=shift_amount
52
-
53
- def cylindrical(self):
54
- """Converts the block to cylindrical coordinate system. The rotation axis is assumed to be "x" direction
55
- """
56
- self.r = np.sqrt(self.Z*self.Z + self.Y*self.Y)
57
- self.theta = np.arctan2(self.Y,self.Z)
58
-
59
- def cell_volumes(self):
60
- """Compute volume of all cells
61
-
62
- Returns:
63
- numpy.ndarray: volume of all cells
64
-
65
- Reference:
66
- Davies, D.E. and Salmond, D.J., "Calculation of the Volume of a General Hexahedron for Flow Predicitons", AIAA Journal, vol. 23, No. 6, pp. 954-956, June 1985. It is (supposedly) exact for a hexahedral whose faces are bi-linear surfaces (i.e., the simplest surface that can be fit through the four nodes defining the face).
67
- """
68
- X = self.X
69
- Y = self.Y
70
- Z = self.Z
71
- a = [np.zeros(shape=(self.IMAX,self.JMAX,self.KMAX)) for _ in range(9)]
72
- # face csi=const
73
- for k in range(1,self.KMAX):
74
- for j in range(1,self.JMAX):
75
- for i in range(self.IMAX): # csi-const
76
- dx1 = X[i,j,k-1] - X[i,j-1,k]
77
- dy1 = Y[i,j,k-1] - Y[i,j-1,k]
78
- dz1 = Z[i,j,k-1] - Z[i,j-1,k]
79
-
80
- dx2 = X[i,j,k] - X[i,j-1,k-1]
81
- dy2 = Y[i,j,k] - Y[i,j-1,k-1]
82
- dz2 = Z[i,j,k] - Z[i,j-1,k-1]
83
-
84
- ax = dy1*dz2 - dz1*dy2
85
- ay = dz1*dx2 - dx1*dz2
86
- az = dx1*dy2 - dy1*dx2
87
-
88
- a[0][i,j,k] = ax*0.5
89
- a[1][i,j,k] = ay*0.5
90
- a[2][i,j,k] = az*0.5
91
-
92
-
93
- for k in range(1,self.KMAX):
94
- for j in range(self.JMAX): # face eta=const
95
- for i in range(1,self.IMAX):
96
- dx1 = X[i,j,k] - X[i-1,j,k-1]
97
- dy1 = Y[i,j,k] - Y[i-1,j,k-1]
98
- dz1 = Z[i,j,k] - Z[i-1,j,k-1]
99
-
100
- dx2 = X[i,j,k-1] - X[i-1,j,k]
101
- dy2 = Y[i,j,k-1] - Y[i-1,j,k]
102
- dz2 = Z[i,j,k-1] - Z[i-1,j,k]
103
-
104
- ax = dy1*dz2 - dz1*dy2
105
- ay = dz1*dx2 - dx1*dz2
106
- az = dx1*dy2 - dy1*dx2
107
-
108
- a[3][i,j,k] = ax*0.5
109
- a[4][i,j,k] = ay*0.5
110
- a[5][i,j,k] = az*0.5
111
-
112
- # face zit=const
113
- for k in range(self.KMAX): # zit=const
114
- for j in range(1,self.JMAX):
115
- for i in range(1,self.IMAX):
116
- dx1 = X[i,j,k] - X[i-1,j-1,k]
117
- dy1 = Y[i,j,k] - Y[i-1,j-1,k]
118
- dz1 = Z[i,j,k] - Z[i-1,j-1,k]
119
-
120
- dx2 = X[i-1,j,k] - X[i,j-1,k]
121
- dy2 = Y[i-1,j,k] - Y[i,j-1,k]
122
- dz2 = Z[i-1,j,k] - Z[i,j-1,k]
123
-
124
- ax = dy1*dz2 - dz1*dy2
125
- ay = dz1*dx2 - dx1*dz2
126
- az = dx1*dy2 - dy1*dx2
127
-
128
- a[6][i,j,k] = ax*0.5
129
- a[7][i,j,k] = ay*0.5
130
- a[8][i,j,k] = az*0.5
131
-
132
- cf = np.zeros(shape=(6,3))
133
- v = np.zeros(shape=(self.IMAX,self.JMAX,self.KMAX))
134
-
135
- for k in trange(1,self.KMAX,desc='Calculating the volumes'):
136
- for j in range(1,self.JMAX):
137
- for i in range(1,self.IMAX):
138
- cf[0,0] = X[i-1,j-1,k-1] + X[i-1,j-1,k] + X[i-1,j,k-1] + X[i-1,j,k]
139
- cf[0,1] = Y[i-1,j-1,k-1] + Y[i-1,j-1,k] + Y[i-1,j,k-1] + Y[i-1,j,k]
140
- cf[0,2] = Z[i-1,j-1,k-1] + Z[i-1,j-1,k] + Z[i-1,j,k-1] + Z[i-1,j,k]
141
- cf[1,0] = X[i,j-1,k-1] + X[i,j-1,k] + X[i,j,k-1] + X[i,j,k]
142
- cf[1,1] = Y[i,j-1,k-1] + Y[i,j-1,k] + Y[i,j,k-1] + Y[i,j,k]
143
- cf[1,2] = Z[i,j-1,k-1] + Z[i,j-1,k] + Z[i,j,k-1] + Z[i,j,k]
144
- cf[2,0] = X[i-1,j-1,k-1] + X[i-1,j-1,k] + X[i,j-1,k-1] + X[i,j-1,k]
145
- cf[2,1] = Y[i-1,j-1,k-1] + Y[i-1,j-1,k] + Y[i,j-1,k-1] + Y[i,j-1,k]
146
- cf[2,2] = Z[i-1,j-1,k-1] + Z[i-1,j-1,k] + Z[i,j-1,k-1] + Z[i,j-1,k]
147
- cf[3,0] = X[i-1,j,k-1] + X[i-1,j,k] + X[i,j,k-1] + X[i,j,k]
148
- cf[3,1] = Y[i-1,j,k-1] + Y[i-1,j,k] + Y[i,j,k-1] + Y[i,j,k]
149
- cf[3,2] = Z[i-1,j,k-1] + Z[i-1,j,k] + Z[i,j,k-1] + Z[i,j,k]
150
- cf[4,0] = X[i-1,j-1,k-1] + X[i-1,j,k-1] + X[i,j-1,k-1] + X[i,j,k-1]
151
- cf[4,1] = Y[i-1,j-1,k-1] + Y[i-1,j,k-1] + Y[i,j-1,k-1] + Y[i,j,k-1]
152
- cf[4,2] = Z[i-1,j-1,k-1] + Z[i-1,j,k-1] + Z[i,j-1,k-1] + Z[i,j,k-1]
153
- cf[5,0] = X[i-1,j-1,k] + X[i-1,j,k] + X[i,j-1,k] + X[i,j,k]
154
- cf[5,1] = Y[i-1,j-1,k] + Y[i-1,j,k] + Y[i,j-1,k] + Y[i,j,k]
155
- cf[5,2] = Z[i-1,j-1,k] + Z[i-1,j,k] + Z[i,j-1,k] + Z[i,j,k]
156
-
157
- vol12=0
158
- for n in range(0,2): # n = 0,1
159
- for l in range(0,3): # l = 0,1,2
160
- vol12 += math.pow(-1,n+1) *(
161
- +cf[n,l]*a[l][i-1+n,j,k]
162
- +cf[2+n,l]*a[3+l][i,j-1+n,k]
163
- +cf[4+n,l]*a[6+l][i,j,k-1+n])
164
- v[i,j,k]= vol12/12
165
- return v
166
-
167
- def checkCollinearity(v1:np.ndarray, v2:np.ndarray):
168
- # Calculate their cross product
169
- cross_P = np.cross(v1,v2)
170
-
171
- # Check if their cross product
172
- # is a NULL Vector or not
173
- if (cross_P[0] == 0 and
174
- cross_P[1] == 0 and
175
- cross_P[2] == 0):
176
- return True
177
- else:
178
- return False
179
-
180
- def calculate_outward_normals(block:Block):
181
- # Calculate Normals
182
- X = block.X
183
- Y = block.Y
184
- Z = block.Z
185
- imax = block.IMAX
186
- jmax = block.JMAX
187
- kmax = block.KMAX
188
- # IMAX - Normal should be out of the page
189
- # Normals I direction: IMIN https://www.khronos.org/opengl/wiki/Calculating_a_Surface_Normal
190
- x = [X[0,0,0],X[0,jmax,0],X[0,0,kmax]]
191
- y = [Y[0,0,0],Y[0,jmax,0],Y[0,0,kmax]]
192
- z = [Z[0,0,0],Z[0,jmax,0],Z[0,0,kmax]]
193
- u = np.array([x[1]-x[0],y[1]-y[0],z[1]-z[0]])
194
- v = np.array([x[2]-x[0],y[2]-y[0],z[2]-z[0]])
195
- n_imin = np.cross(v1,v2)
196
-
197
- # Normals I direction: IMAX
198
- x = [X[imax,0,0],X[imax,jmax,0],X[imax,0,kmax]]
199
- y = [Y[imax,0,0],Y[imax,jmax,0],Y[imax,0,kmax]]
200
- z = [Z[imax,0,0],Z[imax,jmax,0],Z[imax,0,kmax]]
201
- v1 = np.array([x[1]-x[0],y[1]-y[0],z[1]-z[0]])
202
- v2 = np.array([x[2]-x[0],y[2]-y[0],z[2]-z[0]])
203
- n_imax = np.cross(v1,v2)
204
-
205
- # Normals J direction: JMIN
206
- x = [X[0,0,0],X[imax,0,0],X[0,0,kmax]]
207
- y = [Y[0,0,0],Y[imax,0,0],Y[0,0,kmax]]
208
- z = [Z[0,0,0],Z[imax,0,0],Z[0,0,kmax]]
209
- v1 = np.array([x[1]-x[0],y[1]-y[0],z[1]-z[0]])
210
- v2 = np.array([x[2]-x[0],y[2]-y[0],z[2]-z[0]])
211
- n_jmin = np.cross(v1,v2)
212
-
213
- # Normals J direction: JMAX
214
- x = [X[0,jmax,0],X[imax,jmax,0],X[0,jmax,kmax]]
215
- y = [Y[0,jmax,0],Y[imax,jmax,0],Y[0,jmax,kmax]]
216
- z = [Z[0,jmax,0],Z[imax,jmax,0],Z[0,jmax,kmax]]
217
- v1 = np.array([x[1]-x[0],y[1]-y[0],z[1]-z[0]])
218
- v2 = np.array([x[2]-x[0],y[2]-y[0],z[2]-z[0]])
219
- n_jmax = np.cross(v1,v2)
220
-
221
- # Normals K direction: KMIN
222
- x = [X[imax,0,0],X[0,jmax,0],X[0,0,0]]
223
- y = [Y[imax,0,0],Y[0,jmax,0],Y[0,0,0]]
224
- z = [Z[imax,0,0],Z[0,jmax,0],Z[0,0,0]]
225
- v1 = np.array([x[1]-x[0],y[1]-y[0],z[1]-z[0]])
226
- v2 = np.array([x[2]-x[0],y[2]-y[0],z[2]-z[0]])
227
- n_kmin = np.cross(v1,v2)
228
-
229
- # Normals K direction: KMAX
230
- x = [X[imax,0,kmax],X[0,jmax,kmax],X[0,0,kmax]]
231
- y = [Y[imax,0,kmax],Y[0,jmax,kmax],Y[0,0,kmax]]
232
- z = [Z[imax,0,kmax],Z[0,jmax,kmax],Z[0,0,kmax]]
233
- v1 = np.array([x[1]-x[0],y[1]-y[0],z[1]-z[0]])
234
- v2 = np.array([x[2]-x[0],y[2]-y[0],z[2]-z[0]])
235
- n_kmax = np.cross(v1,v2)
236
-
237
- return n_imin,n_jmin,n_kmin,n_imax,n_jmax,n_kmax
238
-
239
- def reduce_blocks(blocks:List[Block],factor:int):
240
- """reduce the blocks by a factor of (factor)
241
-
242
- Args:
243
- blocks (List[Block]): list of blocks to reduce in size
244
- factor (int, optional): Number of indicies to skip . Defaults to 2.
245
-
246
- Returns:
247
- [type]: [description]
248
- """
249
- for i in range(len(blocks)):
250
- blocks[i].X = blocks[i].X[::factor,::factor,::factor]
251
- blocks[i].Y = blocks[i].Y[::factor,::factor,::factor]
252
- blocks[i].Z = blocks[i].Z[::factor,::factor,::factor]
253
- blocks[i].IMAX,blocks[i].JMAX,blocks[i].KMAX = blocks[i].X.shape
254
- return blocks
1
+ import numpy as np
2
+ import math
3
+ from tqdm import trange
4
+ from typing import List
5
+
6
+ class Block:
7
+ """Plot3D Block definition
8
+ """
9
+ def __init__(self, X:np.ndarray,Y:np.ndarray,Z:np.ndarray):
10
+ """Initializes the block using all the X,Y,Z coordinates of the block
11
+
12
+ Args:
13
+ X (np.ndarray): All the X coordinates (i,j,k)
14
+ Y (np.ndarray): All the Y coordinates (i,j,k)
15
+ Z (np.ndarray): All the Z coordinates (i,j,k)
16
+
17
+ """
18
+ self.IMAX,self.JMAX,self.KMAX = X.shape;
19
+ self.X = X
20
+ self.Y = Y
21
+ self.Z = Z
22
+ # Centroid
23
+ self.cx = np.mean(X)
24
+ self.cy = np.mean(Y)
25
+ self.cz = np.mean(Z)
26
+
27
+
28
+ def scale(self,factor:float):
29
+ """Scales a mesh by a certain factor
30
+
31
+ Args:
32
+ factor (float): _description_
33
+ """
34
+
35
+ self.X *= factor
36
+ self.Y *= factor
37
+ self.Z *= factor
38
+
39
+ def shift(self,shift_amount:float,direction:str="z"):
40
+ """shifts the blocks by a certain amount
41
+
42
+ Args:
43
+ shift_amount (float): _description_
44
+ direction (str, optional): _description_. Defaults to "z".
45
+ """
46
+ if direction.lower() == 'z':
47
+ self.Z +=shift_amount
48
+ elif direction.lower() == 'y':
49
+ self.Y +=shift_amount
50
+ elif direction.lower() == 'x':
51
+ self.X +=shift_amount
52
+
53
+ def cylindrical(self):
54
+ """Converts the block to cylindrical coordinate system. The rotation axis is assumed to be "x" direction
55
+ """
56
+ self.r = np.sqrt(self.Z*self.Z + self.Y*self.Y)
57
+ self.theta = np.arctan2(self.Y,self.Z)
58
+
59
+ def cell_volumes(self):
60
+ """Compute volume of all cells
61
+
62
+ Returns:
63
+ numpy.ndarray: volume of all cells
64
+
65
+ Reference:
66
+ Davies, D.E. and Salmond, D.J., "Calculation of the Volume of a General Hexahedron for Flow Predicitons", AIAA Journal, vol. 23, No. 6, pp. 954-956, June 1985. It is (supposedly) exact for a hexahedral whose faces are bi-linear surfaces (i.e., the simplest surface that can be fit through the four nodes defining the face).
67
+ """
68
+ X = self.X
69
+ Y = self.Y
70
+ Z = self.Z
71
+ a = [np.zeros(shape=(self.IMAX,self.JMAX,self.KMAX)) for _ in range(9)]
72
+ # face csi=const
73
+ for k in range(1,self.KMAX):
74
+ for j in range(1,self.JMAX):
75
+ for i in range(self.IMAX): # csi-const
76
+ dx1 = X[i,j,k-1] - X[i,j-1,k]
77
+ dy1 = Y[i,j,k-1] - Y[i,j-1,k]
78
+ dz1 = Z[i,j,k-1] - Z[i,j-1,k]
79
+
80
+ dx2 = X[i,j,k] - X[i,j-1,k-1]
81
+ dy2 = Y[i,j,k] - Y[i,j-1,k-1]
82
+ dz2 = Z[i,j,k] - Z[i,j-1,k-1]
83
+
84
+ ax = dy1*dz2 - dz1*dy2
85
+ ay = dz1*dx2 - dx1*dz2
86
+ az = dx1*dy2 - dy1*dx2
87
+
88
+ a[0][i,j,k] = ax*0.5
89
+ a[1][i,j,k] = ay*0.5
90
+ a[2][i,j,k] = az*0.5
91
+
92
+
93
+ for k in range(1,self.KMAX):
94
+ for j in range(self.JMAX): # face eta=const
95
+ for i in range(1,self.IMAX):
96
+ dx1 = X[i,j,k] - X[i-1,j,k-1]
97
+ dy1 = Y[i,j,k] - Y[i-1,j,k-1]
98
+ dz1 = Z[i,j,k] - Z[i-1,j,k-1]
99
+
100
+ dx2 = X[i,j,k-1] - X[i-1,j,k]
101
+ dy2 = Y[i,j,k-1] - Y[i-1,j,k]
102
+ dz2 = Z[i,j,k-1] - Z[i-1,j,k]
103
+
104
+ ax = dy1*dz2 - dz1*dy2
105
+ ay = dz1*dx2 - dx1*dz2
106
+ az = dx1*dy2 - dy1*dx2
107
+
108
+ a[3][i,j,k] = ax*0.5
109
+ a[4][i,j,k] = ay*0.5
110
+ a[5][i,j,k] = az*0.5
111
+
112
+ # face zit=const
113
+ for k in range(self.KMAX): # zit=const
114
+ for j in range(1,self.JMAX):
115
+ for i in range(1,self.IMAX):
116
+ dx1 = X[i,j,k] - X[i-1,j-1,k]
117
+ dy1 = Y[i,j,k] - Y[i-1,j-1,k]
118
+ dz1 = Z[i,j,k] - Z[i-1,j-1,k]
119
+
120
+ dx2 = X[i-1,j,k] - X[i,j-1,k]
121
+ dy2 = Y[i-1,j,k] - Y[i,j-1,k]
122
+ dz2 = Z[i-1,j,k] - Z[i,j-1,k]
123
+
124
+ ax = dy1*dz2 - dz1*dy2
125
+ ay = dz1*dx2 - dx1*dz2
126
+ az = dx1*dy2 - dy1*dx2
127
+
128
+ a[6][i,j,k] = ax*0.5
129
+ a[7][i,j,k] = ay*0.5
130
+ a[8][i,j,k] = az*0.5
131
+
132
+ cf = np.zeros(shape=(6,3))
133
+ v = np.zeros(shape=(self.IMAX,self.JMAX,self.KMAX))
134
+
135
+ for k in trange(1,self.KMAX,desc='Calculating the volumes'):
136
+ for j in range(1,self.JMAX):
137
+ for i in range(1,self.IMAX):
138
+ cf[0,0] = X[i-1,j-1,k-1] + X[i-1,j-1,k] + X[i-1,j,k-1] + X[i-1,j,k]
139
+ cf[0,1] = Y[i-1,j-1,k-1] + Y[i-1,j-1,k] + Y[i-1,j,k-1] + Y[i-1,j,k]
140
+ cf[0,2] = Z[i-1,j-1,k-1] + Z[i-1,j-1,k] + Z[i-1,j,k-1] + Z[i-1,j,k]
141
+ cf[1,0] = X[i,j-1,k-1] + X[i,j-1,k] + X[i,j,k-1] + X[i,j,k]
142
+ cf[1,1] = Y[i,j-1,k-1] + Y[i,j-1,k] + Y[i,j,k-1] + Y[i,j,k]
143
+ cf[1,2] = Z[i,j-1,k-1] + Z[i,j-1,k] + Z[i,j,k-1] + Z[i,j,k]
144
+ cf[2,0] = X[i-1,j-1,k-1] + X[i-1,j-1,k] + X[i,j-1,k-1] + X[i,j-1,k]
145
+ cf[2,1] = Y[i-1,j-1,k-1] + Y[i-1,j-1,k] + Y[i,j-1,k-1] + Y[i,j-1,k]
146
+ cf[2,2] = Z[i-1,j-1,k-1] + Z[i-1,j-1,k] + Z[i,j-1,k-1] + Z[i,j-1,k]
147
+ cf[3,0] = X[i-1,j,k-1] + X[i-1,j,k] + X[i,j,k-1] + X[i,j,k]
148
+ cf[3,1] = Y[i-1,j,k-1] + Y[i-1,j,k] + Y[i,j,k-1] + Y[i,j,k]
149
+ cf[3,2] = Z[i-1,j,k-1] + Z[i-1,j,k] + Z[i,j,k-1] + Z[i,j,k]
150
+ cf[4,0] = X[i-1,j-1,k-1] + X[i-1,j,k-1] + X[i,j-1,k-1] + X[i,j,k-1]
151
+ cf[4,1] = Y[i-1,j-1,k-1] + Y[i-1,j,k-1] + Y[i,j-1,k-1] + Y[i,j,k-1]
152
+ cf[4,2] = Z[i-1,j-1,k-1] + Z[i-1,j,k-1] + Z[i,j-1,k-1] + Z[i,j,k-1]
153
+ cf[5,0] = X[i-1,j-1,k] + X[i-1,j,k] + X[i,j-1,k] + X[i,j,k]
154
+ cf[5,1] = Y[i-1,j-1,k] + Y[i-1,j,k] + Y[i,j-1,k] + Y[i,j,k]
155
+ cf[5,2] = Z[i-1,j-1,k] + Z[i-1,j,k] + Z[i,j-1,k] + Z[i,j,k]
156
+
157
+ vol12=0
158
+ for n in range(0,2): # n = 0,1
159
+ for l in range(0,3): # l = 0,1,2
160
+ vol12 += math.pow(-1,n+1) *(
161
+ +cf[n,l]*a[l][i-1+n,j,k]
162
+ +cf[2+n,l]*a[3+l][i,j-1+n,k]
163
+ +cf[4+n,l]*a[6+l][i,j,k-1+n])
164
+ v[i,j,k]= vol12/12
165
+ return v
166
+
167
+ @property
168
+ def size(self)->int:
169
+ """returns the total number of nodes
170
+
171
+ Returns:
172
+ int: number of nodes
173
+ """
174
+ return self.IMAX*self.JMAX*self.KMAX
175
+
176
+ def checkCollinearity(v1:np.ndarray, v2:np.ndarray):
177
+ # Calculate their cross product
178
+ cross_P = np.cross(v1,v2)
179
+
180
+ # Check if their cross product
181
+ # is a NULL Vector or not
182
+ if (cross_P[0] == 0 and
183
+ cross_P[1] == 0 and
184
+ cross_P[2] == 0):
185
+ return True
186
+ else:
187
+ return False
188
+
189
+ def calculate_outward_normals(block:Block):
190
+ # Calculate Normals
191
+ X = block.X
192
+ Y = block.Y
193
+ Z = block.Z
194
+ imax = block.IMAX
195
+ jmax = block.JMAX
196
+ kmax = block.KMAX
197
+ # IMAX - Normal should be out of the page
198
+ # Normals I direction: IMIN https://www.khronos.org/opengl/wiki/Calculating_a_Surface_Normal
199
+ x = [X[0,0,0],X[0,jmax,0],X[0,0,kmax]]
200
+ y = [Y[0,0,0],Y[0,jmax,0],Y[0,0,kmax]]
201
+ z = [Z[0,0,0],Z[0,jmax,0],Z[0,0,kmax]]
202
+ u = np.array([x[1]-x[0],y[1]-y[0],z[1]-z[0]])
203
+ v = np.array([x[2]-x[0],y[2]-y[0],z[2]-z[0]])
204
+ n_imin = np.cross(v1,v2)
205
+
206
+ # Normals I direction: IMAX
207
+ x = [X[imax,0,0],X[imax,jmax,0],X[imax,0,kmax]]
208
+ y = [Y[imax,0,0],Y[imax,jmax,0],Y[imax,0,kmax]]
209
+ z = [Z[imax,0,0],Z[imax,jmax,0],Z[imax,0,kmax]]
210
+ v1 = np.array([x[1]-x[0],y[1]-y[0],z[1]-z[0]])
211
+ v2 = np.array([x[2]-x[0],y[2]-y[0],z[2]-z[0]])
212
+ n_imax = np.cross(v1,v2)
213
+
214
+ # Normals J direction: JMIN
215
+ x = [X[0,0,0],X[imax,0,0],X[0,0,kmax]]
216
+ y = [Y[0,0,0],Y[imax,0,0],Y[0,0,kmax]]
217
+ z = [Z[0,0,0],Z[imax,0,0],Z[0,0,kmax]]
218
+ v1 = np.array([x[1]-x[0],y[1]-y[0],z[1]-z[0]])
219
+ v2 = np.array([x[2]-x[0],y[2]-y[0],z[2]-z[0]])
220
+ n_jmin = np.cross(v1,v2)
221
+
222
+ # Normals J direction: JMAX
223
+ x = [X[0,jmax,0],X[imax,jmax,0],X[0,jmax,kmax]]
224
+ y = [Y[0,jmax,0],Y[imax,jmax,0],Y[0,jmax,kmax]]
225
+ z = [Z[0,jmax,0],Z[imax,jmax,0],Z[0,jmax,kmax]]
226
+ v1 = np.array([x[1]-x[0],y[1]-y[0],z[1]-z[0]])
227
+ v2 = np.array([x[2]-x[0],y[2]-y[0],z[2]-z[0]])
228
+ n_jmax = np.cross(v1,v2)
229
+
230
+ # Normals K direction: KMIN
231
+ x = [X[imax,0,0],X[0,jmax,0],X[0,0,0]]
232
+ y = [Y[imax,0,0],Y[0,jmax,0],Y[0,0,0]]
233
+ z = [Z[imax,0,0],Z[0,jmax,0],Z[0,0,0]]
234
+ v1 = np.array([x[1]-x[0],y[1]-y[0],z[1]-z[0]])
235
+ v2 = np.array([x[2]-x[0],y[2]-y[0],z[2]-z[0]])
236
+ n_kmin = np.cross(v1,v2)
237
+
238
+ # Normals K direction: KMAX
239
+ x = [X[imax,0,kmax],X[0,jmax,kmax],X[0,0,kmax]]
240
+ y = [Y[imax,0,kmax],Y[0,jmax,kmax],Y[0,0,kmax]]
241
+ z = [Z[imax,0,kmax],Z[0,jmax,kmax],Z[0,0,kmax]]
242
+ v1 = np.array([x[1]-x[0],y[1]-y[0],z[1]-z[0]])
243
+ v2 = np.array([x[2]-x[0],y[2]-y[0],z[2]-z[0]])
244
+ n_kmax = np.cross(v1,v2)
245
+
246
+ return n_imin,n_jmin,n_kmin,n_imax,n_jmax,n_kmax
247
+
248
+ def reduce_blocks(blocks:List[Block],factor:int):
249
+ """reduce the blocks by a factor of (factor)
250
+
251
+ Args:
252
+ blocks (List[Block]): list of blocks to reduce in size
253
+ factor (int, optional): Number of indicies to skip . Defaults to 2.
254
+
255
+ Returns:
256
+ [type]: [description]
257
+ """
258
+ for i in range(len(blocks)):
259
+ blocks[i].X = blocks[i].X[::factor,::factor,::factor]
260
+ blocks[i].Y = blocks[i].Y[::factor,::factor,::factor]
261
+ blocks[i].Z = blocks[i].Z[::factor,::factor,::factor]
262
+ blocks[i].IMAX,blocks[i].JMAX,blocks[i].KMAX = blocks[i].X.shape
263
+ return blocks
264
+