1from DNDSR
import DNDS, Geom
3import mpi4py.MPI
as pyMPI
6from CartGridField
import CartGridField
11 def __init__(self, mpi: DNDS.MPIInfo, transform=(np.eye(3, 3), np.zeros(3))):
13 self.
_MPI = get_mpi4py_comm_from_MPIInfo(mpi)
15 assert transform[0].shape == (3, 3)
16 assert transform[1].shape == (3,)
24 if not (value[0].shape == (3, 3)
and value[1].shape == (3,)):
25 raise ValueError(
"value shape wrong " + f
"{value}")
26 rotrott = value[0] @ value[0].T
27 err = np.linalg.norm(rotrott - np.eye(3),
"fro")
29 raise ValueError(f
"input not close to rotation: {value[0]}")
30 if np.linalg.norm(rotrott * np.array([[0, 0, 1], [0, 0, 1], [1, 1, 0]])) > 1e-5:
31 raise ValueError(f
"input not 2d rotation: {value[0]}")
35 coordsFatherData = np.array(self.
_mesh.coords.father.data())
36 coordsFatherData = coordsFatherData.reshape((3, -1), order=
"F")
38 coordsMax = coordsFatherData.max(axis=1)
39 coordsMin = coordsFatherData.min(axis=1)
40 self.
_MPI.Allreduce(
None, coordsMax, op=pyMPI.MAX)
41 self.
_MPI.Allreduce(
None, coordsMin, op=pyMPI.MIN)
46 if coord_mesh.ndim == 2:
48 elif coord_mesh.ndim == 1:
57 for name, id
in self.
_name2ID.items():
59 coordsFatherData = np.array(self.
_mesh.coords.father.data())
61 coordsFatherData = coordsFatherData.reshape((3, -1), order=
"F")
63 coordsMax = coordsFatherData.max(axis=1)
64 coordsMin = coordsFatherData.min(axis=1)
65 self.
_MPI.Allreduce(
None, coordsMax, op=pyMPI.MAX)
66 self.
_MPI.Allreduce(
None, coordsMin, op=pyMPI.MIN)
72 return np.concatenate(
74 ).reshape((2, 3), order=
"C")
77 from OversetCartUtil
import obtain_part_local_elem_dists
79 self.
dist_node = obtain_part_local_elem_dists(self, bc_names)
82 """Pack a cell's geometry into a travelling-cell tuple.
85 iCell (int): is local iCell
86 in_phy (bool, optional): in physical instead of mesh space. Defaults to True.
89 tuple[ElemType, int, int, list[int], ndarray]: travelling cell
94 cell2node = np.array(mesh.cell2node[iCell], copy=
False)
96 for iNode
in cell2node:
97 coords.append(np.array(mesh.coords[iNode], copy=
True))
98 coords = np.array(coords).transpose()
100 coords = part.coord_mesh_to_phy(coords)
101 elemInfo = mesh.cellElemInfo[iCell, 0]
102 assert elemInfo.getElemType()
in {
103 Geom.Elem.ElemType.Tri3,
104 Geom.Elem.ElemType.Quad4,
106 travelling_cell = pack_travelling_cell(
107 cellType=elemInfo.getElemType(),
108 cellZone=elemInfo.zone,
109 iCell=mesh.cell2node.trans.LGhostMapping(-1, iCell),
111 mesh.coords.trans.LGhostMapping(-1, iNode)
for iNode
in cell2node
115 return travelling_cell
118 """Return indices and midpoints of faces between cells of differing type.
121 cell_type_arr (DNDS.ArrayEigenVectorPair_1_1_N): per-cell type tag array.
124 (array, array): iFaces (local), midpt coords
129 for iFace
in range(mesh.NumFaceProc()):
130 f2c = mesh.face2cell[iFace].tolist()
131 type_L = cell_type_arr[f2c[0]].tolist()[0]
133 if f2c[1] != DNDS.UnInitIndex:
134 type_R = cell_type_arr[f2c[1]].tolist()[0]
137 faceAtr = mesh.faceElemInfo[iFace, 0]
138 assert faceAtr.getElemType() == Geom.Elem.ElemType.Line2
139 f2n = mesh.face2node[iFace].tolist()
141 np.array(mesh.coords[f2n[0]]) + np.array(mesh.coords[f2n[1]])
144 coords_mid.append(coord_mid[:2])
145 coords_mid = np.array(coords_mid).reshape(-1, 2).T
147 return (np.array(faces, dtype=np.int64), coords_mid)
152 cell_type_arr: DNDS.ArrayEigenVectorPair_1_1_N,
155 highlight_iCells=
set(),
160 highlight_iCells =
set([int(v)
for v
in highlight_iCells])
161 highlight_iCells = MPI.gather(list(highlight_iCells), root=0)
163 highlight_iCells =
set(itertools.chain(*highlight_iCells))
166 travelling_cell_type_list = []
167 for iCell
in range(mesh.NumCell()):
168 cell_type = cell_type_arr[iCell].tolist()[0]
169 travelling_cell_type_list.append(
173 all_cell_types = MPI.gather(travelling_cell_type_list, root=0)
178 import matplotlib.pyplot
as plt
179 import matplotlib.patches
as patches
183 fig = plt.figure(figsize=(8, 6), dpi=320)
185 for cellType, _, iCell, _, coords, osType
in itertools.chain(*all_cell_types):
186 assert cellType
in {Geom.Elem.ElemType.Quad4, Geom.Elem.ElemType.Tri3}
187 if no_hole
and not (osType == 0):
191 polygon = patches.Polygon(
192 coords[:2, :].transpose(),
194 alpha=0.8
if int(iCell)
in highlight_iCells
else 0.2,
196 facecolor=f
"C{int(iPart)}",
197 ls=
"-" if osType == 0
else "none",
200 ax.add_patch(polygon)
204 plt.savefig(f
"part_{iPart}.png")
212 cell_bnds: dict[tuple[int], list[t_travelling_cell_pack]],
213 dist_field: CartGridField,
214 cell_cell_inds: dict[tuple[int], set[int]],
215 cell_cells_on_bnd: dict[tuple[int], list[t_travelling_cell_pack]],
216 cell_bnds_expanded: dict[tuple[int], list[t_travelling_cell_pack]],
237 self.
_MPI = get_mpi4py_comm_from_MPIInfo(mpi)
239 def set_bg(self, parts: list[OversetPart2D], h: float):
242 box = np.zeros((2, 3))
246 partBox = part.xyzMinMax
247 box[0, :] = np.minimum(partBox[0, :], box[0, :])
248 box[1, :] = np.maximum(partBox[1, :], box[1, :])
250 origins = np.zeros(3) * np.nan
256 nInterval = int(np.ceil((upper - lower) / h))
257 assert nInterval >= 0
258 upperV = lower + nInterval * h
259 assert upperV > box[1, iax]
260 xNodes.append(np.linspace(lower, upperV, nInterval + 1, dtype=np.float64))
269 if self.
_mpi.rank == 0:
275 from ProductDecompose
import int_factor_divide
277 nProcAx = int_factor_divide(self.
_mpi.size, 2)
281 nIntervalP = int(np.floor(nIntervals[iax] / nProcAx[iax]))
282 nIntervalPLast = nIntervals[iax] - (nProcAx[iax] - 1) * nIntervalP
283 assert nIntervalPLast >= 0
284 nStartsAx = [i * nIntervalP
for i
in range(nProcAx[iax])] + [
287 assert nStartsAx[-1] - nStartsAx[-2] == nIntervalPLast
288 nStarts.append(np.array(nStartsAx, dtype=np.int64))
301 if self.
_mpi.rank == 0:
304 f
"{self._mpi.rank} nStarts: {self.nStarts4point}, nProcAx: {self.nProcAx}"
308 nPointsPerRank = np.array(
309 [np.array(self.
proc_grid_shape(rank)).prod()
for rank
in range(mpi.size)],
313 nCellsPerRank = np.array(
316 for rank
in range(mpi.size)
322 [self.
rank_to_ax_rank(rank)[0]
for rank
in range(mpi.size)], dtype=np.int32
325 [self.
rank_to_ax_rank(rank)[1]
for rank
in range(mpi.size)], dtype=np.int32
331 ism_expanded, jsm_expanded = np.meshgrid(
334 ijk_ranges_point[iax][0],
335 ijk_ranges_point[iax][1],
344 np.array([ism_expanded, jsm_expanded]),
350 grid_point_expanded_idxs_g = grid_point_expanded_idxs_g[~in_local]
352 np.array(grid_point_expanded_idxs_g, dtype=np.int64)
362 rank = self.
_mpi.rank
378 (nStarts_ax[i][ax_rank[i]], nStarts_ax[i][ax_rank[i] + 1])
for i
in range(2)
386 nStarts_ax[i][ax_rank[i] + 1] - nStarts_ax[i][ax_rank[i]]
395 max(ijk_ranges[iax][0] - 1, 0),
397 ijk_ranges[iax][1] + (2
if is_point
else 1),
399 - (0
if is_point
else 1),
406 return tuple([ijk_ranges[iax][1] - ijk_ranges[iax][0]
for iax
in range(2)])
412 int(index_range[iax][0] - index_range_expanded[iax][0])
for iax
in range(2)
419 (starts[iax], starts[iax] + int(self.
proc_grid_shape(rank, is_point)[iax]))
436 if np.any(ranks < 0)
or np.any(ranks >= self.
_mpi.size):
437 raise ValueError(f
"idx {idx} out of range")
454 if np.any(indexAx < 0)
or np.any(indexAx >= self.
nProcAx[iax]):
456 f
"ijk {ijk[iax]} {ijk} {self.nStarts4point[iax] if is_point else self.nStarts[iax]} {indexAx} out of range"
460 return self.
procMap[tuple(idxs)]
463 self, ijk, is_point=False, in_global=True, ret_global=True, ranks=None
465 if in_global
and ranks
is None:
467 if ranks
is None and not in_global:
468 raise ValueError(
"if input is local, should provide ranks")
477 nStarts_ax_is = nStarts_ax[0][ax_rank_is]
478 nStarts_ax_js = nStarts_ax[1][ax_rank_js]
479 nStarts_ax_jlen = nStarts_ax[1][ax_rank_js + 1] - nStarts_ax_js
482 ijk - np.array([nStarts_ax_is, nStarts_ax_js])
if in_global
else ijk
484 local_idxs = local_ijks[0] * nStarts_ax_jlen + local_ijks[1]
485 global_idxs = start_offsets + local_idxs
486 return global_idxs
if ret_global
else local_idxs
489 self, idx, is_point=False, in_global=True, ret_global=True, ranks=None
491 if in_global
and ranks
is None:
493 if ranks
is None and not in_global:
494 raise ValueError(
"if input is local, should provide ranks")
503 nStarts_ax_is = nStarts_ax[0][ax_rank_is]
504 nStarts_ax_js = nStarts_ax[1][ax_rank_js]
505 nStarts_ax_jlen = nStarts_ax[1][ax_rank_js + 1] - nStarts_ax_js
507 local_idxs = idx - start_offsets
if in_global
else idx
508 local_is = local_idxs // nStarts_ax_jlen
509 local_js = local_idxs % nStarts_ax_jlen
511 ijks = np.array([nStarts_ax_is + local_is, nStarts_ax_js + local_js])
513 ijks = np.array([local_is, local_js])
517 self, rank=None, is_point=False, expanded=False, no_mesh=False
519 grid_range_method = (
522 ijkRanges = grid_range_method(rank=rank, is_point=is_point)
523 iss = np.arange(ijkRanges[0][0], ijkRanges[0][1], dtype=np.int64)
524 jss = np.arange(ijkRanges[1][0], ijkRanges[1][1], dtype=np.int64)
527 ism, jsm = np.meshgrid(iss, jss, indexing=
"ij")
528 ijks = np.array([ism, jsm])
533 :2, np.newaxis, np.newaxis
539 return dict[tuple[int], list[tuple[Geom.Elem.ElemType, int, np.ndarray]]]
549 from OversetCartUtil
import (
550 obtain_proc_local_bg_dists,
551 obtain_proc_local_bg_cell_bnd_elems,
552 expand_proc_local_bg_cell_bnd_elems,
553 obtain_proc_local_bg_cell_cell_elem_inds,
554 obtain_proc_local_bg_cell_elems_with_bnd,
556 dist_field_neg_hole_expansion,
558 from CartUtil
import single_elem_get_box_intersection_2D
562 for iPart, part
in enumerate(parts):
563 proc_bg_mesh_dist = obtain_proc_local_bg_dists(self, part)
564 cell_bnds = obtain_proc_local_bg_cell_bnd_elems(self, part)
565 cell_bnds_expanded = expand_proc_local_bg_cell_bnd_elems(self, cell_bnds)
566 cell_cell_inds = obtain_proc_local_bg_cell_cell_elem_inds(self, part)
569 dist_field.set_main_data(proc_bg_mesh_dist[:, :,
None])
570 dist_field.set_ghost_info(
576 dist_field.trans.startPersistentPull()
577 dist_field.trans.waitPersistentPull()
582 dist_field_neg_hole_expansion(self, part, bc_names, cell_bnds, dist_field)
584 cell_cells_on_bnd = obtain_proc_local_bg_cell_elems_with_bnd(
585 self, part, cell_bnds, cell_cell_inds
596 proc_dist_maps.append(new_dist_map)
598 return proc_dist_maps
601 from OversetCartUtil
import query_dist_from_points
606 self, osPart: OversetPart2D, distMap: DistMap, points: np.ndarray
608 from OversetCartUtil
import query_template_cell_from_points
613 self, parts: list[OversetPart2D], proc_dist_maps: list[DistMap]
615 from OversetCartUtil
import decide_cell_types
621 parts: list[OversetPart2D],
622 proc_dist_maps: list[DistMap],
625 from OversetCartUtil
import decide_point_templates
628 self, parts, proc_dist_maps, points
633 for iPart, item
in enumerate(proc_dist_maps):
634 import matplotlib.pyplot
as plt
635 import matplotlib.patches
as patches
637 cell_bnds, dist_field, cell_cell_inds = (
642 cell_cells_on_bnd = item.cell_cells_on_bnd
644 data = np.array(dist_field.get_expanded_array()[:, :, 0])
645 data = np.minimum(data, cmax)
646 data = np.maximum(data, cmin)
650 fig = plt.figure(figsize=(8, 6), dpi=320)
651 print(f
"{xv.shape}, {yv.shape}, {data.shape}")
652 qmesh = plt.pcolormesh(
663 plt.plot([x, x], [yv[0, 0], yv[0, -1]], c=
"k", lw=lw)
665 plt.plot([xv[-1, 0], xv[0, 0]], [y, y], c=
"k", lw=lw)
666 for type, bcid, _, b2n, coords
in itertools.chain(*cell_bnds.values()):
667 assert type == Geom.Elem.ElemType.Line2
668 plt.plot(coords[0], coords[1], c=
"r", marker=
".", lw=0.1, ms=0.1)
669 for ijks
in cell_bnds.keys():
670 center = (np.array(ijks) + 0.5) * self.
h + self.
origins[:2]
672 center[0], center[1], marker=
"o", ms=5, mfc=
"none", mew=0.3, c=
"k"
675 for ijks
in cell_cell_inds:
676 center = (np.array(ijks) + 0.5) * self.
h + self.
origins[:2]
677 number = len(cell_cell_inds[ijks])
679 center[0], center[1], f
"{number}", va=
"center", ha=
"center", size=4
682 for ijks, elems
in cell_cells_on_bnd.items():
683 for cellType, cellZone, iCell, cell2nodeRow, coords
in elems:
685 Geom.Elem.ElemType.Quad4,
686 Geom.Elem.ElemType.Tri3,
688 for iN
in range(coords.shape[1]):
692 polygon = patches.Polygon(
693 coords[:2, :].transpose(),
696 facecolor=(0.5, 0.2, 0, 0.3),
699 plt.gca().add_patch(polygon)
704 plt.savefig(f
"part_{iPart}_rank_{mpi.rank}.png")
708if __name__ ==
"__main__":
711 from OversetCartManager
import OversetBG2DManager
713 translates = [[0, 0, 0], [1.5, 0, 0]]
716 (np.eye(3, 3), np.array(translates[i]))
for i
in range(len(translates))
722 os.path.dirname(__file__),
728 "CylinderNoFar.cgns",
734 osMan.read_meshes_and_init(mesh_names, transforms)
736 osMan.process_overset(1.0 / 10)
738 osMan.print_proc_dist_maps()
740 osMan.print_full_mesh_type(together=
True)
743 if mpiGlob.rank == 0:
744 _ = osBG.global_ijk_to_rank(
745 np.random.randint(0, min(osBG.grid_shape[0:2]) - 1, size=(2, 32))
752 osBG.global_ijk_to_rank(
753 [v - 1
for v
in osBG.grid_shape], is_point=
False
756 except ValueError
as e:
760 raise RuntimeError(
"not raising value error")
__init__(self, dict[tuple[int], list[t_travelling_cell_pack]] cell_bnds, CartGridField dist_field, dict[tuple[int], set[int]] cell_cell_inds, dict[tuple[int], list[t_travelling_cell_pack]] cell_cells_on_bnd, dict[tuple[int], list[t_travelling_cell_pack]] cell_bnds_expanded)
query_template_cell_from_points(self, OversetPart2D osPart, DistMap distMap, np.ndarray points)
idx_to_ijk(self, idx, is_point=False, in_global=True, ret_global=True, ranks=None)
proc_grid_shape_expanded(self, rank=None, is_point=True)
proc_cell_grid_shape(self, rank=None)
proc_grid_shape(self, rank=None, is_point=True)
ijk_to_idx(self, ijk, is_point=False, in_global=True, ret_global=True, ranks=None)
__init__(self, DNDS.MPIInfo mpi)
proc_grid_core_start_in_local_expanded(self, rank=None, is_point=True)
local_point_grid_shape_expanded
global_idx_to_rank(self, idx, is_point=False)
decide_point_templates(self, list[OversetPart2D] parts, list[DistMap] proc_dist_maps, np.ndarray points)
print_proc_dist_maps(self, list[DistMap] proc_dist_maps, cmin=-1, cmax=10)
proc_grid_ijkarray(self, rank=None, is_point=False, expanded=False, no_mesh=False)
decide_cell_types(self, list[OversetPart2D] parts, list[DistMap] proc_dist_maps)
query_dist_from_points(self, DistMap distMap, np.ndarray points)
obtain_dist_map(self, list[OversetPart2D] parts, bc_names=["WALL"])
proc_grid_range(self, rank=None, is_point=True)
grid_point_expanded_idxs_g
proc_grid_range_expanded(self, rank=None, is_point=True)
global_ijk_to_rank(self, ijk, is_point=False)
proc_grid_core_range_in_local_expanded(self, rank=None, is_point=True)
proc_grid_point_coords(self, expanded=False)
rank_to_ax_rank(self, rank=None)
set_bg(self, list[OversetPart2D] parts, float h)
grid_point_expanded_idxs_g_ijks_local
read_mesh(self, str f_name)
coord_mesh_to_phy(self, coord_mesh)
obtain_dist_node(self, bc_names=["WALL"])
get_holed_faces_midpt(self, DNDS.ArrayEigenVectorPair_1_1_N cell_type_arr)
get_travelling_cell(self, int iCell, bool in_phy=True)
print_full_mesh_type(self, iPart, DNDS.ArrayEigenVectorPair_1_1_N cell_type_arr, no_hole=False, ax=None, highlight_iCells=set())
__init__(self, DNDS.MPIInfo mpi, transform=(np.eye(3, 3), np.zeros(3)))
set(LIBNAME cfv) set(LINKS) set(LINKS_SHARED geom_shared dnds_shared $
Lightweight bundle of an MPI communicator and the calling rank's coordinates.