DNDSR 0.1.0.dev1+gcd065ad
Distributed Numeric Data Structure for CFV
Loading...
Searching...
No Matches
OversetCartUtil.py
Go to the documentation of this file.
1from OversetCart import *
2from CartUtil import *
3from CartGridField import *
4from GeomUtils import *
5import scipy.spatial
6from ElemInterpolate import elem_get_interpolation_base
7from collections import defaultdict
8
9
10def get_mesh_bnd_elems(osPart: OversetPart2D, includeIDs=None, is_phy=False):
11 mesh = osPart._mesh
12 bnd_elems = []
13 for iB in range(mesh.NumBnd()):
14 bnd2node = np.array(osPart._mesh.bnd2node[iB], copy=False)
15 bElemInfo = mesh.bndElemInfo[iB, 0]
16 if includeIDs is not None and bElemInfo.zone not in includeIDs:
17 continue
18 assert (bnd2node < mesh.NumNodeProc()).all(), str(bnd2node)
19 nodeList = [] #!2d: list of node coords represent a bnd element
20 for n in bnd2node:
21 if is_phy:
22 nodeList.append(
23 osPart.coord_mesh_to_phy(np.array(mesh.coords[n], copy=True))
24 )
25 else:
26 nodeList.append(np.array(mesh.coords[n], copy=True))
27 nodeList = np.array(nodeList).transpose()
28 travelling_bnd_elem = pack_travelling_cell(
29 cellType=bElemInfo.getElemType(),
30 cellZone=bElemInfo.zone,
31 iCell=-1, # set as unknown
32 cell2nodeRow=[mesh.coords.trans.LGhostMapping(-1, n) for n in bnd2node],
33 coords=nodeList,
34 )
35 # bnd_elems.append((bElemInfo.getElemType(), bElemInfo.zone, nodeList))
36 bnd_elems.append(travelling_bnd_elem)
37 return bnd_elems
38
39
41 self: OversetBG2D, osPart: OversetPart2D
42):
43 local_point_dists = {}
44 mesh = osPart._mesh
45 origin = np.array(self.origins[0:2])
46 h = self.h
47 for iCell in range(mesh.NumCell()):
48 cell2node = np.array(mesh.cell2node[iCell], copy=False)
49 assert (cell2node < mesh.NumNodeProc()).all(), str(cell2node)
50 nodeDists = osPart.dist_node[cell2node]
51 coords = []
52 for iNode in cell2node:
53 coords.append(np.array(mesh.coords[iNode], copy=True))
54 coords = np.array(coords).transpose()
55 coords = osPart.coord_mesh_to_phy(coords)
56 elemInfo = mesh.cellElemInfo[iCell, 0]
57 assert elemInfo.getElemType() in {
58 Geom.Elem.ElemType.Tri3,
59 Geom.Elem.ElemType.Quad4,
60 } # coords is now polygon
61 gridPoints = single_elem_get_grid_point_2D(origin, h, coords[0:2, :])
62 gridPointsCoords = origin[:, None] + gridPoints * h
63
64 if gridPoints.size:
65 for iP in range(gridPoints.shape[1]):
66
67 p = np.zeros(3)
68 p[:2] = gridPointsCoords[:, iP]
69 distP = elem_get_interpolation_base(
70 elemInfo.getElemType(), coords, p
71 ).dot(nodeDists)
72 local_point_dists[tuple(gridPoints[:, iP])] = distP
73 return local_point_dists
74
75
76def obtain_part_local_elem_dists(self: OversetPart2D, bc_names=["WALL"]):
77 """for a part to get nodal distance field
78
79 Args:
80 self (OversetPart2D): _description_
81 bc_names (list, optional): _description_. Defaults to ["WALL"].
82
83 Returns:
84 _type_: _description_
85 """
86 mpi = self._mpi
87 MPI = self._MPI
88 bnd_elems_local = get_mesh_bnd_elems(
89 self, [self._name2ID[name] for name in bc_names]
90 )
91 bnd_elems_local_others = MPI.allgather(bnd_elems_local)
92
93 bnd_geoms = []
94 for bnd_part in bnd_elems_local_others:
95 for t, z, _, b2n, coord in bnd_part:
96 assert t == Geom.Elem.ElemType.Line2
97 bnd_geoms.extend([coord[:, 0], coord[:, 1]])
98 tree = scipy.spatial.KDTree(np.array(bnd_geoms))
99
100 mesh = self._mesh
101 dists = np.ones((mesh.NumNodeProc()), dtype=np.float64) * 1e300
102 coordsFatherData = np.array(self._mesh.coords.father.data())
103 coordsFatherData = coordsFatherData.reshape((3, -1), order="F")
104
105 distq, idx = tree.query(coordsFatherData.T)
106 dists[0 : mesh.NumNode()] = distq
107
108 coordsSonData = (
109 np.array(self._mesh.coords.son.data())
110 if self._mesh.coords.son.Size()
111 else np.zeros(0) # why does empty son returns a NULL buffer?
112 )
113 coordsSonData = coordsSonData.reshape((3, -1), order="F")
114
115 distq, idx = tree.query(coordsSonData.T)
116 dists[mesh.NumNode() :] = distq
117 print(f"{mpi.rank}: maxDist: {dists.max()}")
118 return dists
119
120
121def obtain_part_local_dists(self: OversetBG2D, osPart: OversetPart2D):
122 mpi = self._mpi
123 local_point_dists = obtain_part_local_inner_grid_points_dist_dict(self, osPart)
124
125 # print(f"points covered: {mpi.rank}, {len(local_point_dists)}")
126
127 return local_point_dists
128
129
130def obtain_proc_local_bg_dists(self: OversetBG2D, part: OversetPart2D):
131 mpi = self._mpi
132 MPI = self._MPI
133 part_local_dists = obtain_part_local_dists(self, part)
134 part_local_dists_items = list(part_local_dists.items())
135
136 ijkv = np.array([v[0] for v in part_local_dists_items]).transpose()
137 if ijkv.size:
138 ranks = list(self.global_ijk_to_rank(ijkv))
139 else:
140 ranks = []
141 # sendLists = [[]] * self._mpi.size # ! this is wrong!!! the empty lists of each item refs the same
142 sendLists = [[] for _ in range(mpi.size)]
143
144 for i, rank in enumerate(ranks):
145 datac = part_local_dists_items[i]
146 sendLists[rank].append(datac)
147
148 recvLists = MPI.alltoall(sendLists)
149 # print(f"{mpi.rank}, {([len(v) for v in sendLists])}, {len(sendLists)}")
150 # return
151
152 ax_ranks = self.rank_to_ax_rank()
153 proc_bg_mesh_dist = np.ones(self.proc_grid_shape()) * 1e300
154 for recvL in recvLists:
155 # print(recvL)
156 for g_point, v in recvL:
157 for ax in range(2):
158 assert g_point[ax] < self.nStarts4point[ax][ax_ranks[ax] + 1], g_point[
159 ax
160 ]
161 l_point = (
162 g_point[0] - self.nStarts4point[0][ax_ranks[0]],
163 g_point[1] - self.nStarts4point[1][ax_ranks[1]],
164 )
165 proc_bg_mesh_dist[l_point] = v
166 # print(f"proc {mpi.rank}: min dist at grid point: {proc_bg_mesh_dist.min()}")
167 return proc_bg_mesh_dist
168
169
171 self: OversetBG2D,
172 part: OversetPart2D,
173 bc_names: list[str],
174 cell_bnds: OversetBG2D.cell_bnds_type,
175 dist_field: CartGridField,
176):
177 """creates negative hole and expands it
178
179 Args:
180 self (OversetBG2D): _description_
181 part (OversetPart2D): _description_
182 bc_names (list[str]): _description_
183 cell_bnds (OversetBG2D.cell_bnds_type): _description_
184 dist_field (CartGridField): modified to have neg hole
185 """
186 mpi = self._mpi
187 MPI = self._MPI
188
189 dist_expanded_array = dist_field.get_expanded_array()
190
191 offsets = [(0, 0), (1, 0), (0, 1), (1, 1)]
192 for ijk, bnd_list in cell_bnds.items():
193 for type, bcid, _, b2n, coords in bnd_list:
194 assert type == Geom.Elem.ElemType.Line2
195 if bcid in [part._name2ID[name] for name in bc_names]:
196 for offset in offsets:
197 ijkp = tuple([ijk[iax] + offset[iax] for iax in range(2)])
198 ijkp_in_expanded = tuple(
199 [
200 ijkp[iax]
201 - self.proc_grid_range_expanded(is_point=True)[iax][0]
202 for iax in range(2)
203 ]
204 )
205 if dist_expanded_array[ijkp_in_expanded] > 1e299:
206 dist_expanded_array[ijkp_in_expanded] = -100
207 dist_field.set_main_data_from_expanded(dist_expanded_array)
208 dist_field.trans.startPersistentPull()
209 dist_field.trans.waitPersistentPull()
210
211 ijks_expanded = self.proc_grid_ijkarray(is_point=True, expanded=True)
212 ijks_expanded[0] -= self.proc_grid_range_expanded()[0][0]
213 ijks_expanded[1] -= self.proc_grid_range_expanded()[1][0]
214 cr = self.proc_grid_core_range_in_local_expanded(is_point=True)
215 ijks_expanded_core = ijks_expanded[:, cr[0][0] : cr[0][1], cr[1][0] : cr[1][1]]
216 ijks_expanded_core = ijks_expanded_core.reshape((2, -1))
217 ijks_expanded_core_le = np.array([ijks_expanded_core[0] - 1, ijks_expanded_core[1]])
218 ijks_expanded_core_ri = np.array([ijks_expanded_core[0] + 1, ijks_expanded_core[1]])
219 ijks_expanded_core_lo = np.array([ijks_expanded_core[0], ijks_expanded_core[1] - 1])
220 ijks_expanded_core_up = np.array([ijks_expanded_core[0], ijks_expanded_core[1] + 1])
221
222 offsets = [(0, 1), (0, -1), (1, 0), (-1, 0)]
223 for iter in range(10000):
224 dist_expanded_array = dist_field.get_expanded_array()
225 dist_expanded_array_new = np.array(dist_expanded_array)
226 count = 0
227 for ic in range(ijks_expanded_core.shape[1]):
228 ijk = tuple(ijks_expanded_core[:, ic])
229 if dist_expanded_array[ijk] > 1e299:
230 for ijk_nei in [
231 ijks_expanded_core_le[:, ic],
232 ijks_expanded_core_ri[:, ic],
233 ijks_expanded_core_lo[:, ic],
234 ijks_expanded_core_up[:, ic],
235 ]:
236 ijk_nei = tuple(ijk_nei)
237 if (
238 0 <= ijk_nei[0] < dist_expanded_array.shape[0]
239 and 0 <= ijk_nei[1] < dist_expanded_array.shape[1]
240 and dist_expanded_array[ijk_nei] < 0
241 ):
242 count += 1
243 dist_expanded_array_new[ijk] = dist_expanded_array[ijk_nei]
244 count = MPI.allreduce(count, pyMPI.SUM)
245 if mpi.rank == 0:
246 print(f"negative hole: iter [{iter}] Done")
247 if count == 0:
248 break
249 dist_field.set_main_data_from_expanded(dist_expanded_array_new)
250 dist_field.trans.startPersistentPull()
251 dist_field.trans.waitPersistentPull()
252 else:
253 print(f"count left: {count}")
254
255
257 self: OversetBG2D,
258 part: OversetPart2D,
259 cell_bnds: OversetBG2D.cell_bnds_type,
260 cell_cell_inds: dict[tuple[int], set[int]],
261):
262 mpi = self._mpi
263 MPI = self._MPI
264 mesh = part._mesh
265
266 elem_reqs_send = [[] for _ in range(mpi.size)]
267 for ijk in cell_bnds.keys():
268 assert ijk in cell_cell_inds.keys() # have at least 1 elem adjacent to bnd
269 for iCellG in cell_cell_inds[ijk]:
270 ret, rank, val = mesh.cell2node.trans.LGlobalMapping.search(iCellG)
271 assert ret, "search failed"
272 elem_reqs_send[rank].append((ijk, iCellG))
273
274 elem_reqs_recv = MPI.alltoall(elem_reqs_send)
275
276 elem_send = [[] for _ in range(mpi.size)]
277 for rank_send, reqs in enumerate(elem_reqs_recv):
278 for ijk, iCellG in reqs:
279 ret, rank_searched, iCell = mesh.cell2node.trans.LGlobalMapping.search(
280 iCellG
281 )
282 assert ret and rank_searched == mpi.rank, "search failed"
283 elem_send[rank_send].append(
284 (ijk, part.get_travelling_cell(iCell, in_phy=True))
285 )
286 elem_recv = MPI.alltoall(elem_send)
287 # if mpi.rank == 0:
288 # print(elem_recv)
289 cell_cells_on_bnd = defaultdict(list)
290 for ijk, travelling_cell in itertools.chain(*elem_recv):
291 cell_cells_on_bnd[ijk].append(travelling_cell)
292 return cell_cells_on_bnd
293
294
295def obtain_proc_local_bg_cell_bnd_elems(self: OversetBG2D, part: OversetPart2D):
296 mpi = self._mpi
297 MPI = self._MPI
298
299 bnd_elems = get_mesh_bnd_elems(part, is_phy=True) # note we are using phy
300 send_lists = [[] for _ in range(mpi.size)]
301 for travelling_bnd_elem in bnd_elems:
302 type, bcid, _, b2n, coords = travelling_bnd_elem
304 self.origins[:2], self.h, coords[0:2, :]
305 )
306 ranks = self.global_ijk_to_rank(cell_ijks)
307 for ic, rank in enumerate(ranks):
308 send_lists[rank].append((cell_ijks[:, ic], travelling_bnd_elem))
309 recv_lists = MPI.alltoall(send_lists)
310
311 cell_bnds = defaultdict(list)
312 for cell_ijk, travelling_bnd_elem in itertools.chain(*recv_lists):
313 cell_ijk_t = tuple(int(v) for v in cell_ijk)
314 cell_bnds[cell_ijk_t].append(travelling_bnd_elem)
315 return dict(cell_bnds)
316
317
318def expand_proc_local_bg_cell_bnd_elems(self: OversetBG2D, cell_bnds: dict):
319 mpi = self._mpi
320 MPI = self._MPI
321
322 cell_bnds = dict(cell_bnds)
323
324 bg_cell_range = self.proc_grid_range(is_point=False)
325 proc_grid_ijks_expanded = self.proc_grid_ijkarray(expanded=True).reshape(2, -1)
326 ijk_fringe = []
327 for iIJK in range(proc_grid_ijks_expanded.shape[1]):
328 ijk = [int(proc_grid_ijks_expanded[iax, iIJK]) for iax in range(2)]
329 ijkInCore = [
330 bg_cell_range[iax][0] <= ijk[iax] < bg_cell_range[iax][1]
331 for iax in range(2)
332 ]
333 if not (ijkInCore[0] and ijkInCore[1]):
334 ijk_fringe.append(tuple(ijk))
335 ijk_fringe = np.array(ijk_fringe, dtype=np.int64).T
336 ranks = self.global_ijk_to_rank(ijk_fringe)
337 req_lists = [[] for _ in range(mpi.size)]
338 for i, rank in enumerate(ranks):
339 req_lists[rank].append(ijk_fringe[:, i])
340 req_cur = MPI.alltoall(req_lists)
341 send_lists_fringe_cell_bnd = [[] for rank in range(mpi.size)]
342 for rank_source, ijks in enumerate(req_cur):
343 for ijk in ijks:
344 ijk_t = tuple(int(v) for v in ijk)
345 if ijk_t in cell_bnds:
346 send_lists_fringe_cell_bnd[rank_source].append(
347 (ijk_t, cell_bnds[ijk_t])
348 )
349 recv_lists_fringe_cell_bnd = MPI.alltoall(send_lists_fringe_cell_bnd)
350
351 for ijk_t, bnds_list in itertools.chain(*recv_lists_fringe_cell_bnd):
352 assert ijk_t not in cell_bnds
353 cell_bnds[ijk_t] = bnds_list
354
355 return cell_bnds
356
357
358def obtain_proc_local_bg_cell_cell_elem_inds(self: OversetBG2D, part: OversetPart2D):
359
360 mpi = self._mpi
361 MPI = self._MPI
362 mesh = part._mesh
363 origin = self.origins[:2]
364
365 send_list = [[] for _ in range(mpi.size)]
366
367 for iCell in range(mesh.NumCell()):
368 cell2node = np.array(mesh.cell2node[iCell], copy=False)
369 assert (cell2node < mesh.NumNodeProc()).all(), str(cell2node)
370 coords = []
371 for iNode in cell2node:
372 coords.append(np.array(mesh.coords[iNode], copy=True))
373 coords = np.array(coords).transpose()
374 coords = part.coord_mesh_to_phy(coords)
375 elemInfo = mesh.cellElemInfo[iCell, 0]
376 assert elemInfo.getElemType() in {
377 Geom.Elem.ElemType.Tri3,
378 Geom.Elem.ElemType.Quad4,
379 } # coords is now polygon
380 # travelling_cell = pack_travelling_cell(
381 # cellType=elemInfo.getElemType(),
382 # cellZone=elemInfo.zone,
383 # iCell=mesh.cell2node.trans.LGhostMapping(-1, iCell),
384 # cell2nodeRow=[
385 # mesh.coords.trans.LGhostMapping(-1, iNode) for iNode in cell2node
386 # ],
387 # coords=coords,
388 # )
389 # ! we only need indices here not whole travelling cell
390 ijks = single_elem_get_box_intersection_2D(origin, self.h, coords[:2, :])
391 ranks = self.global_ijk_to_rank(ijks, is_point=False)
392 for iC in range(ijks.shape[1]):
393 send_list[ranks[iC]].append(
394 (ijks[:, iC], mesh.cell2node.trans.LGhostMapping(-1, iCell))
395 )
396
397 recv_list = MPI.alltoall(send_list)
398 proc_cell_global_ijk_to_part_cell_dict = defaultdict(list)
399 d = proc_cell_global_ijk_to_part_cell_dict
400 for ijk, iCellG in itertools.chain(*recv_list):
401 ijkt = tuple([int(v) for v in ijk])
402 d[ijkt].append(iCellG)
403
404 for k in d:
405 d[k] = set(sorted(d[k]))
406
407 # if mpi.rank == 0:
408 # print(d)
409
410 return proc_cell_global_ijk_to_part_cell_dict
411
412
414 self: OversetBG2D, distMap: DistMap, points: np.ndarray, rel_tol=1e-8
415):
416 mpi = self._mpi
417 MPI = self._MPI
418 assert points.shape[0] == 2
419 points = np.reshape(points, (2, -1))
420
421 ijks = points_get_grid_cells_2D(self.origins[:2], self.h, points)
422 ranks = self.global_ijk_to_rank(ijks, is_point=False)
423 # print(ranks)
424
425 query_send = [set() for _ in range(mpi.size)]
426 for iq, rank in enumerate(ranks):
427 query_send[rank].add(tuple([int(v) for v in ijks[:, iq]]))
428 query_recv = MPI.alltoall(query_send)
429
430 data_send = [{} for _ in range(mpi.size)]
431
432 proc_grid_point_dists = distMap.dist_field.get_expanded_array()
433
434 for rank_to, queries in enumerate(query_recv):
435 for ijk in queries:
436 ijk_local_p = tuple(
437 [
438 ijk[iax] - self.proc_grid_range_expanded(is_point=True)[iax][0]
439 for iax in range(2)
440 ]
441 )
442 dists = [
443 proc_grid_point_dists[
444 ijk_local_p[0] + disp[0], ijk_local_p[1] + disp[1]
445 ]
446 for disp in [(0, 0), (1, 0), (0, 1), (1, 1)]
447 ]
448 dists = np.array(dists)
449 additional = None
450 if ijk in distMap.cell_bnds:
451 bnd_elems = distMap.cell_bnds[ijk]
452 assert ijk in distMap.cell_cells_on_bnd
453 bnd_cell_elems = distMap.cell_cells_on_bnd[ijk]
454 additional = (bnd_elems, bnd_cell_elems)
455
456 # only boundary-cut bg-cells check neighbour bg-cell for bnd elem
457 ijk_neighs = [
458 (ijk[0] - 1, ijk[1]),
459 (ijk[0] + 1, ijk[1]),
460 (ijk[0], ijk[1] - 1),
461 (ijk[0], ijk[1] + 1),
462 ]
463 for ijk_neigh in ijk_neighs:
464 if (
465 ijk_neigh in distMap.cell_bnds_expanded
466 ): # no need to ensure neigh is a valid ijk
467 additional[0].extend(distMap.cell_bnds_expanded[ijk_neigh])
468
469 assert ijk not in data_send[rank_to]
470 data_send[rank_to][ijk] = (dists, additional)
471
472 data_recv = MPI.alltoall(data_send)
473 data_recv_merged = {k: v for d in data_recv for k, v in d.items()}
474
475 dist_results = np.zeros(points.shape[1]) + 1e300
476 for iq in range(points.shape[1]):
477 ijkt = tuple([int(v) for v in ijks[:, iq]])
478 dists, additional = data_recv_merged[ijkt]
479 if dists.max() < 0:
480 dist_results[iq] = dists.max()
481 continue
482 if dists.min() > 1e299:
483 dist_results[iq] = 1e300
484 continue
485 if ((0 <= dists) & (dists <= 1e299)).all():
486 xyz01 = [
487 (
488 self.origins[iax] + ijkt[iax] * self.h,
489 self.origins[iax] + (ijkt[iax] + 1) * self.h,
490 )
491 for iax in range(2)
492 ]
493 xis = np.array(
494 [(points[iax, iq] - xyz01[iax][0]) / self.h for iax in range(2)],
495 dtype=np.float64,
496 )
497 assert (
498 (0 - rel_tol <= xis) & (xis <= 1 + rel_tol)
499 ).all(), f"{xis}, {points[:, iq]}"
500
501 bases = [
502 np.array(
503 [1 - xis[iax] if offset[iax] == 0 else xis[iax] for iax in range(2)]
504 ).prod()
505 for offset in [(0, 0), (1, 0), (0, 1), (1, 1)]
506 ]
507 dist_results[iq] = np.array(bases).dot(dists)
508 continue
509 assert additional is not None, f"{ijkt}, {iq}, {(dists.min(),dists.max())}"
510 bnd_elems, bnd_cell_elems = additional
511 found_num = 0
512 for ct, _, _, _, coords in bnd_cell_elems: #!check if inside mesh really
514 coords[:2, :], points[0, iq], points[1, iq]
515 )
516 if is_in:
517 found_num += 1
518 break
519 if found_num:
520 if dists.min() < 0:
521 #! exact search!
522 # todo: better exact search
523 distc = 1e300
524 for bct, _, _, _, coords in bnd_elems:
525 p = points[:, iq]
526 edist = np.linalg.vector_norm(
527 coords[:2, :] - p[:, None], axis=0
528 ).min()
529 distc = min(distc, edist)
530 p1 = coords[:2, 0]
531 p2 = coords[:2, 1]
532 x12 = p2 - p1
533 x10 = p - p1
534 xi = x10.dot(x12) / x12.dot(x12)
535 if 0 <= xi and xi <= 1:
536 distM = np.linalg.vector_norm(xi * x12 - x10)
537 distc = min(distc, distM)
538
539 dist_results[iq] = distc
540 # print(distc)
541 if dists.max() > 1e299:
542 dist_results[iq] = dists.min()
543 else:
544 if dists.min() < 0:
545 dist_results[iq] = dists.min()
546 if dists.max() > 1e299:
547 dist_results[iq] = 1e300
548
549 # raise RuntimeWarning("not implemented")
550
551 # print(data_recv_merged)
552 return dist_results
553
554
556 self: OversetBG2D, osPart: OversetPart2D, distMap: DistMap, points: np.ndarray
557):
558 mpi = self._mpi
559 MPI = self._MPI
560 mesh = osPart._mesh
561 points = np.reshape(points, (2, -1))
562
563 ijks = points_get_grid_cells_2D(self.origins[:2], self.h, points)
564 ranks = self.global_ijk_to_rank(ijks, is_point=False)
565
566 query_send = [set() for _ in range(mpi.size)]
567 for iq, rank in enumerate(ranks):
568 query_send[rank].add(tuple([int(v) for v in ijks[:, iq]]))
569 query_recv = MPI.alltoall(query_send)
570
571 data_send = [{} for _ in range(mpi.size)]
572 for rank, query_recv_rank in enumerate(query_recv):
573 for ijk in query_recv_rank:
574 data_send[rank][ijk] = distMap.cell_cell_inds[ijk]
575 data_recv = MPI.alltoall(data_send)
576 ijk_to_cell_data_recv_merged = {k: v for d in data_recv for k, v in d.items()}
577
578 iCellGs = set()
579 for v in ijk_to_cell_data_recv_merged.values():
580 iCellGs.update(v)
581 cell_req_send = [[] for _ in range(mpi.size)]
582 for iCellG in iCellGs:
583 ret, rank, iCell = mesh.cell2node.trans.LGlobalMapping.search(iCellG)
584 assert ret, "search failed"
585 # print(rank)
586 cell_req_send[rank].append((iCell, iCellG))
587 cell_req_recv = MPI.alltoall(cell_req_send)
588 travelling_cell_data_send = []
589 for cell_reqs in cell_req_recv:
590 data_c = []
591 for iCell, iCellG in cell_reqs:
592 data_c.append((iCellG, osPart.get_travelling_cell(iCell, in_phy=True)))
593 travelling_cell_data_send.append(data_c)
594 travelling_cell_data_recv = MPI.alltoall(travelling_cell_data_send)
595 travelling_cell_data_recv_dict = {}
596 for iCellG, travelling_cell in itertools.chain(*travelling_cell_data_recv):
597 travelling_cell_data_recv_dict[iCellG] = travelling_cell
598
599 template_iCellGs = []
600 for iq, rank in enumerate(ranks):
601 ijk_t = tuple([int(v) for v in ijks[:, iq]])
602 cells = [
603 (iCellG, travelling_cell_data_recv_dict[iCellG])
604 for iCellG in ijk_to_cell_data_recv_merged[ijk_t]
605 ]
606 iCellG_template = -1
607 for iCellG, travelling_cell in cells:
608 cellType, cellZone, iCell, cell2nodeRow, coords = travelling_cell
609 assert cellType in {
610 Geom.Elem.ElemType.Quad4,
611 Geom.Elem.ElemType.Tri3,
612 }
614 coords[:2, :], points[0, iq], points[1, iq]
615 )
616 if is_in:
617 iCellG_template = iCellG
618 # assert iCellG_template >= 0, "template query not found"
619 template_iCellGs.append(iCellG_template)
620 return template_iCellGs
621
622
624 self: OversetBG2D, parts: list[OversetPart2D], proc_dist_maps: list[DistMap]
625):
626 mpi = self._mpi
627 MPI = self._MPI
628 check_pairs = []
629 for i in range(len(parts)):
630 for j in range(len(parts)):
631 check_pairs.append((i, j))
632
633 other_dists_nodes = [{} for _ in range(len(parts))]
634 self_dist_nodes = [None] * len(parts)
635
636 for i, j in check_pairs:
637 part_this = parts[i]
638 dist_that = proc_dist_maps[j]
639 mesh = part_this._mesh
640 coordsFatherData = np.array(mesh.coords.father.data())
641 coordsFatherData = coordsFatherData.reshape((3, -1), order="F")
642
643 coordsSonData = (
644 np.array(mesh.coords.son.data())
645 if mesh.coords.son.Size()
646 else np.zeros(0) # why does empty son returns a NULL buffer?
647 )
648 coordsSonData = coordsSonData.reshape((3, -1), order="F")
649
650 coordsFullData = np.concat([coordsFatherData, coordsSonData], axis=1)
651 coordsFullData = part_this.coord_mesh_to_phy(
652 coordsFullData
653 ) # do not forget to physical coord
654 coordsFullData = coordsFullData[:2, :]
655
656 if j == i:
657 self_dist_nodes[i] = self.query_dist_from_points(dist_that, coordsFullData)
658 else:
659 other_dists_nodes[i][j] = self.query_dist_from_points(
660 dist_that, coordsFullData
661 )
662
663 min_dists_nodes_other = []
664 for i, other_set in enumerate(other_dists_nodes):
665 part_this = parts[i]
666 mesh = part_this._mesh
667 min_dist_other = np.zeros((mesh.NumNodeProc())) + 1e301
668 for other_dist in other_set.values():
669 min_dist_other = np.minimum(min_dist_other, other_dist)
670 # print("===\n" * 3 + f"i{i}, {other_dist.min()}")
671 min_dists_nodes_other.append(min_dist_other)
672
673 cell_type_arrs = []
674
675 for i, part in enumerate(parts):
676 node_is_hole = (
677 self_dist_nodes[i] * 0.9
678 > min_dists_nodes_other[i]
679 # part.dist_node > min_dists_nodes_other[i]
680 )
681 # !using self_dist_nodes[i], not using exact nodal values here, for field consistency
682
683 # print("===\n" * 3 + f"i{i}, {node_is_hole.sum()}, {min_dists_nodes_other[i].min()}")
684 mesh = part._mesh
685 cell_type = np.zeros((mesh.NumCell()))
686 for iCell in range(mesh.NumCell()):
687 c2n = mesh.cell2node[iCell].tolist()
688 c2n_is_hole = node_is_hole[c2n]
689 cell_type[iCell] = 1 if c2n_is_hole.all() else 0
690 cell_type_arr = DNDS.ArrayEigenVectorPair(1)
691 cell_type_arr.father = DNDS.ArrayEigenVector(1, init_args=(mpi,))
692 cell_type_arr.son = DNDS.ArrayEigenVector(1, init_args=(mpi,))
693 cell_type_arr.TransAttach()
694 cell_type_arr.father.Resize(mesh.NumCell())
695 cell_type_arr_father_data_in = np.array(cell_type_arr.father.data(), copy=False)
696 cell_type_arr_father_data_in[:] = cell_type.flat
697 cell_type_arr.trans.BorrowGGIndexing(mesh.cell2node.trans)
698 cell_type_arr.trans.createMPITypes()
699 cell_type_arr.trans.pullOnce()
700 cell_type_arrs.append(cell_type_arr)
701 return (cell_type_arrs, other_dists_nodes)
702
703
705 self: OversetBG2D,
706 parts: list[OversetPart2D],
707 proc_dist_maps: list[DistMap],
708 points: np.ndarray,
709):
710 mpi = self._mpi
711 MPI = self._MPI
712 points = np.reshape(points, (2, -1))
713
714 assert len(parts) == len(proc_dist_maps)
715
716 dists_pts = []
717 for dist_that in proc_dist_maps:
718 dists_pts.append(self.query_dist_from_points(dist_that, points))
719 # print(dists_pts)
720 dist_pts_a = np.array(dists_pts, dtype=np.float64)
721 min_dist_loc = np.argmin(dist_pts_a, axis=0)
722 min_dist = np.min(dist_pts_a, axis=0)
723 inds = np.arange(len(min_dist))
724 iCellGs = np.ones_like(inds) * -1 # at iPart == min_dist_loc
725
726 for i, part in enumerate(parts):
727 inds_c = inds[min_dist_loc == i]
728 points_c = points[:, inds_c]
729 iCellGs[inds_c] = self.query_template_cell_from_points(
730 part, proc_dist_maps[i], points_c
731 )
732
733 return (np.array(min_dist_loc), np.array(iCellGs))
ParArray<real, N> whose operator[] returns an Eigen::Map<Vector>.
single_elem_get_box_intersection_2D(np.ndarray origin, float h, np.ndarray elem, closed=True)
Definition CartUtil.py:190
single_elem_get_grid_point_2D(np.ndarray origin, float h, np.ndarray elem, closed=True)
Definition CartUtil.py:213
points_get_grid_cells_2D(np.ndarray origin, float h, np.ndarray coords)
Definition CartUtil.py:235
points_in_polygon_winding(polygon, x, y, closed=True)
Definition CartUtil.py:60
decide_point_templates(OversetBG2D self, list[OversetPart2D] parts, list[DistMap] proc_dist_maps, np.ndarray points)
query_dist_from_points(OversetBG2D self, DistMap distMap, np.ndarray points, rel_tol=1e-8)
get_mesh_bnd_elems(OversetPart2D osPart, includeIDs=None, is_phy=False)
obtain_part_local_inner_grid_points_dist_dict(OversetBG2D self, OversetPart2D osPart)
obtain_proc_local_bg_cell_cell_elem_inds(OversetBG2D self, OversetPart2D part)
obtain_proc_local_bg_dists(OversetBG2D self, OversetPart2D part)
query_template_cell_from_points(OversetBG2D self, OversetPart2D osPart, DistMap distMap, np.ndarray points)
decide_cell_types(OversetBG2D self, list[OversetPart2D] parts, list[DistMap] proc_dist_maps)
obtain_proc_local_bg_cell_bnd_elems(OversetBG2D self, OversetPart2D part)
expand_proc_local_bg_cell_bnd_elems(OversetBG2D self, dict cell_bnds)
obtain_part_local_elem_dists(OversetPart2D self, bc_names=["WALL"])
obtain_proc_local_bg_cell_elems_with_bnd(OversetBG2D self, OversetPart2D part, OversetBG2D.cell_bnds_type cell_bnds, dict[tuple[int], set[int]] cell_cell_inds)
dist_field_neg_hole_expansion(OversetBG2D self, OversetPart2D part, list[str] bc_names, OversetBG2D.cell_bnds_type cell_bnds, CartGridField dist_field)
obtain_part_local_dists(OversetBG2D self, OversetPart2D osPart)
set(LIBNAME cfv) set(LINKS) set(LINKS_SHARED geom_shared dnds_shared $
Definition CMakeLists.txt:5
Convenience bundle of a father, son, and attached ArrayTransformer.