icplot 0.2.3__py3-none-any.whl → 0.2.4__py3-none-any.whl
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.
- icplot/mesh/cell.py +21 -0
- icplot/mesh/mesh.py +22 -2
- icplot/mesh/openfoam/foamfile.py +10 -2
- icplot/mesh/openfoam/polymesh.py +274 -5
- icplot/mesh/shapes.py +122 -4
- icplot/mesh/vertex.py +23 -0
- {icplot-0.2.3.dist-info → icplot-0.2.4.dist-info}/METADATA +1 -1
- {icplot-0.2.3.dist-info → icplot-0.2.4.dist-info}/RECORD +12 -12
- {icplot-0.2.3.dist-info → icplot-0.2.4.dist-info}/WHEEL +0 -0
- {icplot-0.2.3.dist-info → icplot-0.2.4.dist-info}/entry_points.txt +0 -0
- {icplot-0.2.3.dist-info → icplot-0.2.4.dist-info}/licenses/LICENSE +0 -0
- {icplot-0.2.3.dist-info → icplot-0.2.4.dist-info}/top_level.txt +0 -0
icplot/mesh/cell.py
CHANGED
|
@@ -14,6 +14,27 @@ class Cell:
|
|
|
14
14
|
raise NotImplementedError()
|
|
15
15
|
|
|
16
16
|
|
|
17
|
+
def flip_normals(cell: Cell) -> Cell:
|
|
18
|
+
if cell.type == "quad":
|
|
19
|
+
return Cell(type=cell.type, vertices=tuple(reversed(cell.vertices)))
|
|
20
|
+
else:
|
|
21
|
+
raise RuntimeError("Not implemented for this cell type")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def get_hex_faces(cell: Cell) -> tuple[tuple[int, ...], ...]:
|
|
25
|
+
if cell.type != "hex":
|
|
26
|
+
raise RuntimeError("Can only get hex faces for hex cells")
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
(cell.vertices[0], cell.vertices[1], cell.vertices[5], cell.vertices[4]),
|
|
30
|
+
(cell.vertices[1], cell.vertices[2], cell.vertices[6], cell.vertices[5]),
|
|
31
|
+
(cell.vertices[2], cell.vertices[3], cell.vertices[7], cell.vertices[6]),
|
|
32
|
+
(cell.vertices[3], cell.vertices[0], cell.vertices[4], cell.vertices[7]),
|
|
33
|
+
(cell.vertices[0], cell.vertices[3], cell.vertices[2], cell.vertices[1]),
|
|
34
|
+
(cell.vertices[4], cell.vertices[5], cell.vertices[6], cell.vertices[7]),
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
17
38
|
@dataclass(frozen=True)
|
|
18
39
|
class HexCell(Cell):
|
|
19
40
|
"""
|
icplot/mesh/mesh.py
CHANGED
|
@@ -8,8 +8,8 @@ from dataclasses import dataclass
|
|
|
8
8
|
|
|
9
9
|
from icplot.geometry import Point, Vector, Transform, Bounds
|
|
10
10
|
|
|
11
|
-
from .vertex import Vertex
|
|
12
|
-
from .cell import Cell
|
|
11
|
+
from .vertex import Vertex, find_closest_vertex
|
|
12
|
+
from .cell import Cell, flip_normals
|
|
13
13
|
from .edge import Edge, contains_point, get_distance
|
|
14
14
|
|
|
15
15
|
|
|
@@ -52,6 +52,11 @@ class Mesh:
|
|
|
52
52
|
zmax = min(zmax, v.z)
|
|
53
53
|
return Bounds(xmin=xmin, xmax=xmax, ymin=ymin, ymax=ymax, zmin=zmin, zmax=zmax)
|
|
54
54
|
|
|
55
|
+
def flip_normals(self) -> Mesh:
|
|
56
|
+
return Mesh(
|
|
57
|
+
vertices=self.vertices, cells=tuple(flip_normals(c) for c in self.cells)
|
|
58
|
+
)
|
|
59
|
+
|
|
55
60
|
def get_location(self) -> Vector:
|
|
56
61
|
bounds = self.get_bounds()
|
|
57
62
|
return Vector(bounds.xmin, bounds.ymin, bounds.zmin)
|
|
@@ -62,6 +67,12 @@ class Mesh:
|
|
|
62
67
|
vertices=tuple(v.translate(delta) for v in self.vertices), cells=self.cells
|
|
63
68
|
)
|
|
64
69
|
|
|
70
|
+
def move_by(self, x: float, y: float, z: float) -> Mesh:
|
|
71
|
+
delta = Vector(x, y, z)
|
|
72
|
+
return Mesh(
|
|
73
|
+
vertices=tuple(v.translate(delta) for v in self.vertices), cells=self.cells
|
|
74
|
+
)
|
|
75
|
+
|
|
65
76
|
def select_edge(self, p: Point) -> tuple[int, int]:
|
|
66
77
|
|
|
67
78
|
for c in self.cells:
|
|
@@ -70,6 +81,9 @@ class Mesh:
|
|
|
70
81
|
return (e[0], e[1])
|
|
71
82
|
raise RuntimeError("No edge found at selection point")
|
|
72
83
|
|
|
84
|
+
def get_closest_vertex(self, v: Vertex) -> Vertex:
|
|
85
|
+
return find_closest_vertex(self.vertices, v)
|
|
86
|
+
|
|
73
87
|
def get_closest_edge(self, p: Point) -> tuple[int, int]:
|
|
74
88
|
|
|
75
89
|
min_dist = -1.0
|
|
@@ -85,3 +99,9 @@ class Mesh:
|
|
|
85
99
|
min_dist = dist
|
|
86
100
|
closest_edges = (e[0], e[1])
|
|
87
101
|
return closest_edges
|
|
102
|
+
|
|
103
|
+
def copy(self) -> Mesh:
|
|
104
|
+
return Mesh(
|
|
105
|
+
vertices=tuple(Vertex(v.x, v.y, v.z, v.id) for v in self.vertices),
|
|
106
|
+
cells=tuple(Cell(c.vertices, c.type) for c in self.cells),
|
|
107
|
+
)
|
icplot/mesh/openfoam/foamfile.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from dataclasses import dataclass
|
|
1
|
+
from dataclasses import dataclass, field
|
|
2
2
|
from pathlib import Path
|
|
3
3
|
|
|
4
4
|
|
|
@@ -14,8 +14,9 @@ class FoamFile:
|
|
|
14
14
|
body: tuple[str, ...] = ()
|
|
15
15
|
version: float = 2.0
|
|
16
16
|
format: str = "ascii"
|
|
17
|
-
arch: str =
|
|
17
|
+
arch: str = "LSB;label=32;scalar=64"
|
|
18
18
|
foam_class: str = "vectorField"
|
|
19
|
+
meta: dict[str, tuple] = field(default_factory=dict)
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
def write_header(spec: FoamFile) -> str:
|
|
@@ -27,6 +28,13 @@ def write_header(spec: FoamFile) -> str:
|
|
|
27
28
|
output += f"\tclass\t{spec.foam_class};\n"
|
|
28
29
|
output += f'\tlocation\t"{spec.location}";\n'
|
|
29
30
|
output += f"\tobject\t{spec.foam_object};\n"
|
|
31
|
+
if spec.meta:
|
|
32
|
+
output += "\tmeta\n{\n"
|
|
33
|
+
for key, value in spec.meta.items():
|
|
34
|
+
values = list(value)
|
|
35
|
+
value_items = " ".join(str(item) for item in values)
|
|
36
|
+
output += f"\t{key} {len(values)}({value_items});\n"
|
|
37
|
+
output += "}\n"
|
|
30
38
|
output += "}\n\n"
|
|
31
39
|
return output
|
|
32
40
|
|
icplot/mesh/openfoam/polymesh.py
CHANGED
|
@@ -1,19 +1,31 @@
|
|
|
1
1
|
from dataclasses import dataclass
|
|
2
2
|
from pathlib import Path
|
|
3
|
+
from functools import cmp_to_key
|
|
3
4
|
|
|
4
|
-
from icplot.
|
|
5
|
+
from icplot.geometry import Point
|
|
6
|
+
from icplot.mesh import Vertex, Mesh, get_hex_faces
|
|
5
7
|
|
|
6
|
-
from .foamfile import read_foamfile
|
|
8
|
+
from .foamfile import read_foamfile, FoamFile, write_header
|
|
7
9
|
|
|
8
10
|
|
|
9
11
|
@dataclass(frozen=True)
|
|
10
12
|
class Face:
|
|
11
13
|
"""
|
|
12
|
-
A mesh face, which is a sequence of
|
|
14
|
+
A mesh face, which is a sequence of vertices
|
|
13
15
|
"""
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
vertices: tuple[int, ...]
|
|
16
18
|
id: int = -1
|
|
19
|
+
owner: int = -1
|
|
20
|
+
neighbour: int = -1
|
|
21
|
+
|
|
22
|
+
def get_centre(self, mesh: Mesh) -> Point:
|
|
23
|
+
x = sum(mesh.vertices[idx].x for idx in self.vertices)
|
|
24
|
+
y = sum(mesh.vertices[idx].y for idx in self.vertices)
|
|
25
|
+
z = sum(mesh.vertices[idx].z for idx in self.vertices)
|
|
26
|
+
return Point(
|
|
27
|
+
x / len(self.vertices), y / len(self.vertices), z / len(self.vertices)
|
|
28
|
+
)
|
|
17
29
|
|
|
18
30
|
|
|
19
31
|
@dataclass(frozen=True)
|
|
@@ -32,11 +44,25 @@ class Polymesh:
|
|
|
32
44
|
The polymesh
|
|
33
45
|
"""
|
|
34
46
|
|
|
35
|
-
|
|
47
|
+
vertices: tuple[Vertex, ...]
|
|
36
48
|
faces: tuple[Face, ...]
|
|
37
49
|
cells: tuple[Cell, ...]
|
|
38
50
|
|
|
39
51
|
|
|
52
|
+
@dataclass(frozen=True)
|
|
53
|
+
class PolymeshPatch:
|
|
54
|
+
name: str
|
|
55
|
+
faces: tuple[Face, ...]
|
|
56
|
+
startFace: int
|
|
57
|
+
type: str = "patch"
|
|
58
|
+
|
|
59
|
+
def has_face(self, face: Face) -> bool:
|
|
60
|
+
for f in self.faces:
|
|
61
|
+
if f.id == face.id:
|
|
62
|
+
return True
|
|
63
|
+
return False
|
|
64
|
+
|
|
65
|
+
|
|
40
66
|
def read_polymesh(path: Path) -> Polymesh:
|
|
41
67
|
|
|
42
68
|
points_file = read_foamfile(path / "points")
|
|
@@ -44,3 +70,246 @@ def read_polymesh(path: Path) -> Polymesh:
|
|
|
44
70
|
print(points_file)
|
|
45
71
|
# print(faces_file)
|
|
46
72
|
return Polymesh((), (), ())
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _write_points(vertices: tuple[Vertex, ...]) -> str:
|
|
76
|
+
|
|
77
|
+
# Write file header
|
|
78
|
+
header = FoamFile(
|
|
79
|
+
location="constant/polyMesh", foam_object="points", foam_class="vectorField"
|
|
80
|
+
)
|
|
81
|
+
ret = write_header(header)
|
|
82
|
+
|
|
83
|
+
ret += f"{len(vertices)}\n(\n"
|
|
84
|
+
for v in vertices:
|
|
85
|
+
ret += f"({v.x} {v.y} {v.z})\n"
|
|
86
|
+
ret += ")\n"
|
|
87
|
+
return ret
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _write_faces(internal_faces: tuple[Face, ...], patches: list[PolymeshPatch]) -> str:
|
|
91
|
+
header = FoamFile(
|
|
92
|
+
location="constant/polyMesh", foam_object="faces", foam_class="faceList"
|
|
93
|
+
)
|
|
94
|
+
ret = write_header(header)
|
|
95
|
+
|
|
96
|
+
num_patch_faces = sum(len(p.faces) for p in patches)
|
|
97
|
+
num_faces = len(internal_faces) + num_patch_faces
|
|
98
|
+
|
|
99
|
+
ret += f"{num_faces}\n(\n"
|
|
100
|
+
for f in internal_faces:
|
|
101
|
+
verts = f.vertices
|
|
102
|
+
ret += f"{len(verts)}({verts[0]} {verts[1]} {verts[2]} {verts[3]})\n"
|
|
103
|
+
|
|
104
|
+
for p in patches:
|
|
105
|
+
for f in p.faces:
|
|
106
|
+
verts = f.vertices
|
|
107
|
+
ret += f"{len(verts)}({verts[0]} {verts[1]} {verts[2]} {verts[3]})\n"
|
|
108
|
+
ret += ")\n"
|
|
109
|
+
return ret
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _write_owners(
|
|
113
|
+
internal_faces: tuple[Face, ...], patches: list[PolymeshPatch]
|
|
114
|
+
) -> str:
|
|
115
|
+
header = FoamFile(
|
|
116
|
+
location="constant/polyMesh", foam_object="owner", foam_class="labelList"
|
|
117
|
+
)
|
|
118
|
+
ret = write_header(header)
|
|
119
|
+
|
|
120
|
+
num_patch_faces = sum(len(p.faces) for p in patches)
|
|
121
|
+
num_faces = len(internal_faces) + num_patch_faces
|
|
122
|
+
|
|
123
|
+
ret += f"{num_faces}\n(\n"
|
|
124
|
+
for f in internal_faces:
|
|
125
|
+
ret += f"{f.owner}\n"
|
|
126
|
+
for p in patches:
|
|
127
|
+
for f in p.faces:
|
|
128
|
+
ret += f"{f.owner}\n"
|
|
129
|
+
ret += ")\n"
|
|
130
|
+
return ret
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _write_neighbours(
|
|
134
|
+
internal_faces: tuple[Face, ...], patches: list[PolymeshPatch]
|
|
135
|
+
) -> str:
|
|
136
|
+
header = FoamFile(
|
|
137
|
+
location="constant/polyMesh", foam_object="neighbour", foam_class="labelList"
|
|
138
|
+
)
|
|
139
|
+
ret = write_header(header)
|
|
140
|
+
|
|
141
|
+
num_patch_faces = sum(len(p.faces) for p in patches)
|
|
142
|
+
num_faces = len(internal_faces) + num_patch_faces
|
|
143
|
+
|
|
144
|
+
ret += f"{num_faces}\n(\n"
|
|
145
|
+
for f in internal_faces:
|
|
146
|
+
ret += f"{f.neighbour}\n"
|
|
147
|
+
for p in patches:
|
|
148
|
+
for f in p.faces:
|
|
149
|
+
ret += f"{f.neighbour}\n"
|
|
150
|
+
ret += ")\n"
|
|
151
|
+
return ret
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
"""
|
|
155
|
+
def _write_face_zones(zones: list[FaceZone]) -> str:
|
|
156
|
+
|
|
157
|
+
header = FoamFile(
|
|
158
|
+
location="constant/polyMesh",
|
|
159
|
+
foam_object="faceZones",
|
|
160
|
+
foam_class="regIOobject",
|
|
161
|
+
meta={"names": tuple(zone.name for zone in zones)},
|
|
162
|
+
)
|
|
163
|
+
ret = write_header(header)
|
|
164
|
+
|
|
165
|
+
ret += f"{len(zones)}\n( "
|
|
166
|
+
for zone in zones:
|
|
167
|
+
ret += f"{zone.name}\n{{"
|
|
168
|
+
ret += "\ttype\tfaceZone;\n\tfaceLabels\tList<label>\n"
|
|
169
|
+
ret += f"{len(zone.faces)}\n("
|
|
170
|
+
for face in zone.faces:
|
|
171
|
+
ret += f"{face}\n"
|
|
172
|
+
ret += ");\n"
|
|
173
|
+
ret += "\tflipMap\tList<bool>\n"
|
|
174
|
+
ret += f"{len(zone.faces)}\n("
|
|
175
|
+
for face in zone.faces:
|
|
176
|
+
ret += "0\n"
|
|
177
|
+
ret += ");\n"
|
|
178
|
+
ret += "}\n\n"
|
|
179
|
+
ret += ")"
|
|
180
|
+
return ret
|
|
181
|
+
"""
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def _write_boundaries(patches: list[PolymeshPatch]):
|
|
185
|
+
|
|
186
|
+
header = FoamFile(
|
|
187
|
+
location="constant/polyMesh",
|
|
188
|
+
foam_object="boundary",
|
|
189
|
+
foam_class="polyBoundaryMesh",
|
|
190
|
+
)
|
|
191
|
+
ret = write_header(header)
|
|
192
|
+
|
|
193
|
+
ret += f"{len(patches)}(\n"
|
|
194
|
+
for p in patches:
|
|
195
|
+
ret += f"{p.name}\n{{"
|
|
196
|
+
ret += f"\ttype\t{p.type};\n"
|
|
197
|
+
ret += f"\tnFaces\t{len(p.faces)};\n"
|
|
198
|
+
ret += f"\tstartFace\t{p.startFace};\n"
|
|
199
|
+
ret += "}\n\n"
|
|
200
|
+
ret += ")"
|
|
201
|
+
return ret
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def _faces_equal(f0, f1):
|
|
205
|
+
return set(f0) == set(f1)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def _compare_faces(f0: Face, f1: Face):
|
|
209
|
+
if f0.owner == f1.owner:
|
|
210
|
+
if f0.neighbour == f1.neighbour:
|
|
211
|
+
return 0
|
|
212
|
+
elif f0.neighbour > f1.neighbour:
|
|
213
|
+
return 1
|
|
214
|
+
else:
|
|
215
|
+
return -1
|
|
216
|
+
else:
|
|
217
|
+
if f0.owner > f1.owner:
|
|
218
|
+
return 1
|
|
219
|
+
else:
|
|
220
|
+
return -1
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def _build_faces(mesh: Mesh) -> list[Face]:
|
|
224
|
+
faces: list[Face] = []
|
|
225
|
+
|
|
226
|
+
count = 0
|
|
227
|
+
for idx, cell in enumerate(mesh.cells):
|
|
228
|
+
hex_faces = get_hex_faces(cell)
|
|
229
|
+
for hex_face in hex_faces:
|
|
230
|
+
found = False
|
|
231
|
+
for face in faces:
|
|
232
|
+
if _faces_equal(hex_face, face.vertices):
|
|
233
|
+
if idx < face.owner:
|
|
234
|
+
faces[face.id] = Face(
|
|
235
|
+
vertices=tuple(list(reversed(face.vertices))),
|
|
236
|
+
owner=idx,
|
|
237
|
+
id=face.id,
|
|
238
|
+
neighbour=face.owner,
|
|
239
|
+
)
|
|
240
|
+
else:
|
|
241
|
+
faces[face.id] = Face(
|
|
242
|
+
vertices=face.vertices,
|
|
243
|
+
owner=face.owner,
|
|
244
|
+
id=face.id,
|
|
245
|
+
neighbour=idx,
|
|
246
|
+
)
|
|
247
|
+
found = True
|
|
248
|
+
break
|
|
249
|
+
if not found:
|
|
250
|
+
faces.append(Face(id=count, vertices=hex_face, owner=idx, neighbour=-1))
|
|
251
|
+
count += 1
|
|
252
|
+
|
|
253
|
+
faces.sort(key=cmp_to_key(_compare_faces))
|
|
254
|
+
return faces
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def _get_external_faces(faces: tuple[Face, ...]) -> tuple[Face, ...]:
|
|
258
|
+
return tuple(f for f in faces if f.neighbour == -1)
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
def _get_internal_faces(faces: tuple[Face, ...]) -> tuple[Face, ...]:
|
|
262
|
+
return tuple(f for f in faces if f.neighbour != -1)
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
def write_polymesh(path: Path, mesh: Mesh, patch_funcs: dict):
|
|
266
|
+
|
|
267
|
+
# Write points
|
|
268
|
+
with open(path / "points", "w", encoding="utf-8") as f:
|
|
269
|
+
f.write(_write_points(mesh.vertices))
|
|
270
|
+
|
|
271
|
+
# Prepare faces, owners and neighbours
|
|
272
|
+
faces = _build_faces(mesh)
|
|
273
|
+
|
|
274
|
+
internal_faces = _get_internal_faces(tuple(faces))
|
|
275
|
+
external_faces = _get_external_faces(tuple(faces))
|
|
276
|
+
|
|
277
|
+
# Get patches
|
|
278
|
+
count = len(internal_faces)
|
|
279
|
+
patches = []
|
|
280
|
+
for name, func in patch_funcs.items():
|
|
281
|
+
patch_faces = tuple(f for f in external_faces if func(f.get_centre(mesh)))
|
|
282
|
+
patches.append(PolymeshPatch(name=name, faces=patch_faces, startFace=count))
|
|
283
|
+
count += len(patch_faces)
|
|
284
|
+
|
|
285
|
+
# Add a default wall patch
|
|
286
|
+
wall_faces = []
|
|
287
|
+
for face in external_faces:
|
|
288
|
+
found = False
|
|
289
|
+
for patch in patches:
|
|
290
|
+
if patch.has_face(face):
|
|
291
|
+
found = True
|
|
292
|
+
break
|
|
293
|
+
if not found:
|
|
294
|
+
wall_faces.append(face)
|
|
295
|
+
patches.append(
|
|
296
|
+
PolymeshPatch(
|
|
297
|
+
name="wall",
|
|
298
|
+
type="wall",
|
|
299
|
+
faces=tuple(f for f in wall_faces),
|
|
300
|
+
startFace=count,
|
|
301
|
+
)
|
|
302
|
+
)
|
|
303
|
+
|
|
304
|
+
with open(path / "faces", "w", encoding="utf-8") as f:
|
|
305
|
+
f.write(_write_faces(internal_faces, patches))
|
|
306
|
+
|
|
307
|
+
with open(path / "owner", "w", encoding="utf-8") as f:
|
|
308
|
+
f.write(_write_owners(internal_faces, patches))
|
|
309
|
+
|
|
310
|
+
with open(path / "neighbour", "w", encoding="utf-8") as f:
|
|
311
|
+
f.write(_write_neighbours(internal_faces, patches))
|
|
312
|
+
|
|
313
|
+
# Write boundaries
|
|
314
|
+
with open(path / "boundary", "w", encoding="utf-8") as f:
|
|
315
|
+
f.write(_write_boundaries(patches))
|
icplot/mesh/shapes.py
CHANGED
|
@@ -15,7 +15,7 @@ from .mesh import Mesh
|
|
|
15
15
|
from .vertex import Vertex, find_closest
|
|
16
16
|
from .cell import Cell, HexCell
|
|
17
17
|
|
|
18
|
-
from .operations import map_radial, close_mesh, merge_meshes
|
|
18
|
+
from .operations import map_radial, close_mesh, merge_meshes, mesh_extrude
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
def mesh_rectangle(rect: Quad, num_width: int = 10, num_height: int = 10) -> Mesh:
|
|
@@ -64,13 +64,80 @@ def mesh_annulus(
|
|
|
64
64
|
num_width=num_circumferential,
|
|
65
65
|
num_height=num_radial,
|
|
66
66
|
)
|
|
67
|
-
radial_mesh = map_radial(rect_mesh, annulus.angle)
|
|
67
|
+
radial_mesh = map_radial(rect_mesh, annulus.angle).flip_normals()
|
|
68
68
|
|
|
69
69
|
if annulus.angle == 360:
|
|
70
70
|
return close_mesh(radial_mesh)
|
|
71
71
|
return radial_mesh
|
|
72
72
|
|
|
73
73
|
|
|
74
|
+
def _rotate_list(lst, n):
|
|
75
|
+
return lst[n:] + lst[:n]
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _close_circle(inner_mesh: Mesh, outer_mesh: Mesh, num_circumferential: int) -> Mesh:
|
|
79
|
+
|
|
80
|
+
num_side = int(num_circumferential / 4)
|
|
81
|
+
inner_verts = []
|
|
82
|
+
|
|
83
|
+
# Base
|
|
84
|
+
for idx in range(num_side + 1):
|
|
85
|
+
inner_verts.append(idx)
|
|
86
|
+
|
|
87
|
+
# RHS
|
|
88
|
+
for idx in range(1, num_side + 1):
|
|
89
|
+
inner_verts.append((idx + 1) * (num_side + 1) - 1)
|
|
90
|
+
|
|
91
|
+
# Top
|
|
92
|
+
for idx in range(2, num_side + 2):
|
|
93
|
+
inner_verts.append((num_side + 1) * (num_side + 1) - idx)
|
|
94
|
+
|
|
95
|
+
# Left
|
|
96
|
+
for idx in range(2, num_side + 1):
|
|
97
|
+
inner_verts.append((num_side + 1) * (num_side + 1 - idx))
|
|
98
|
+
|
|
99
|
+
inner_verts = _rotate_list(inner_verts, num_side + 1 + int((num_side + 1) / 2) - 1)
|
|
100
|
+
|
|
101
|
+
new_nodes = []
|
|
102
|
+
new_cells = []
|
|
103
|
+
count = 0
|
|
104
|
+
for idx in range(num_circumferential):
|
|
105
|
+
|
|
106
|
+
next_id = idx + 1
|
|
107
|
+
if next_id == num_circumferential:
|
|
108
|
+
next_id = 0
|
|
109
|
+
|
|
110
|
+
outer_next = outer_mesh.vertices[next_id]
|
|
111
|
+
nearest_next = inner_mesh.vertices[inner_verts[next_id]]
|
|
112
|
+
|
|
113
|
+
if idx == 0:
|
|
114
|
+
outer = outer_mesh.vertices[idx]
|
|
115
|
+
nearest = inner_mesh.vertices[inner_verts[idx]]
|
|
116
|
+
|
|
117
|
+
new_nodes.append(Vertex(x=nearest.x, y=nearest.y, z=nearest.z, id=count))
|
|
118
|
+
new_nodes.append(Vertex(x=outer.x, y=outer.y, z=outer.z, id=count + 1))
|
|
119
|
+
count += 2
|
|
120
|
+
|
|
121
|
+
new_nodes.append(
|
|
122
|
+
Vertex(x=nearest_next.x, y=nearest_next.y, z=nearest_next.z, id=count)
|
|
123
|
+
)
|
|
124
|
+
new_nodes.append(
|
|
125
|
+
Vertex(x=outer_next.x, y=outer_next.y, z=outer_next.z, id=count + 1)
|
|
126
|
+
)
|
|
127
|
+
count += 2
|
|
128
|
+
new_cells.append(
|
|
129
|
+
Cell(type="quad", vertices=(count - 2, count - 4, count - 3, count - 1))
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
# Create mesh interface layer
|
|
133
|
+
mesh_interface = Mesh(cells=tuple(new_cells), vertices=tuple(new_nodes))
|
|
134
|
+
mesh_interface = close_mesh(mesh_interface)
|
|
135
|
+
|
|
136
|
+
# Merge mesh interface layer
|
|
137
|
+
inner_merged = merge_meshes(inner_mesh, mesh_interface)
|
|
138
|
+
return merge_meshes(inner_merged, outer_mesh)
|
|
139
|
+
|
|
140
|
+
|
|
74
141
|
def mesh_circle(
|
|
75
142
|
circle: Circle,
|
|
76
143
|
boundary_frac: float = 0.5,
|
|
@@ -97,8 +164,59 @@ def mesh_circle(
|
|
|
97
164
|
num_height=int(num_circumferential / 4),
|
|
98
165
|
)
|
|
99
166
|
|
|
100
|
-
|
|
101
|
-
|
|
167
|
+
return _close_circle(inner_mesh, annulus_mesh, num_circumferential)
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def mesh_cylinder_basic(
|
|
171
|
+
cylinder: Cylinder,
|
|
172
|
+
boundary_frac: float = 0.5,
|
|
173
|
+
num_radial: int = 2,
|
|
174
|
+
num_circumferential: int = 8,
|
|
175
|
+
num_height=5,
|
|
176
|
+
) -> Mesh:
|
|
177
|
+
|
|
178
|
+
return mesh_extrude(
|
|
179
|
+
mesh_circle(
|
|
180
|
+
Circle(radius=cylinder.diameter / 2),
|
|
181
|
+
boundary_frac,
|
|
182
|
+
num_radial,
|
|
183
|
+
num_circumferential,
|
|
184
|
+
),
|
|
185
|
+
cylinder.length,
|
|
186
|
+
num_height,
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def mesh_compound_cylinder(
|
|
191
|
+
inlet_radius,
|
|
192
|
+
inlet_height,
|
|
193
|
+
radius,
|
|
194
|
+
height,
|
|
195
|
+
boundary_fraction,
|
|
196
|
+
num_circumferential,
|
|
197
|
+
num_radial,
|
|
198
|
+
num_height,
|
|
199
|
+
) -> Mesh:
|
|
200
|
+
|
|
201
|
+
inner = mesh_cylinder_basic(
|
|
202
|
+
Cylinder(diameter=inlet_radius * 2, length=2 * inlet_height + height),
|
|
203
|
+
boundary_fraction,
|
|
204
|
+
num_radial,
|
|
205
|
+
num_circumferential,
|
|
206
|
+
num_height * int(height / inlet_height) + 2 * num_height,
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
main_body = mesh_annulus(
|
|
210
|
+
Annulus(outer_radius=radius, inner_radius=inlet_radius),
|
|
211
|
+
num_radial=num_radial,
|
|
212
|
+
num_circumferential=num_circumferential,
|
|
213
|
+
)
|
|
214
|
+
main_body = mesh_extrude(
|
|
215
|
+
main_body, height, num_cells=num_height * int(height / inlet_height)
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
main_body = main_body.move_by(0.0, 0.0, inlet_height)
|
|
219
|
+
return merge_meshes(main_body, inner)
|
|
102
220
|
|
|
103
221
|
|
|
104
222
|
def mesh_cuboid(cuboid: Cuboid, elements_per_dim: int = 5) -> Mesh:
|
icplot/mesh/vertex.py
CHANGED
|
@@ -55,3 +55,26 @@ def find_closest(verts: list[Vertex], point: Point) -> int:
|
|
|
55
55
|
min_distance = distance
|
|
56
56
|
|
|
57
57
|
return min_id
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def find_closest_vertex(verts: tuple[Vertex, ...], v: Vertex) -> Vertex:
|
|
61
|
+
|
|
62
|
+
if not verts:
|
|
63
|
+
raise RuntimeError("Can't find nearest vert in empty list")
|
|
64
|
+
|
|
65
|
+
min_id = -1
|
|
66
|
+
min_distance = 0.0
|
|
67
|
+
for idx, vert in enumerate(verts):
|
|
68
|
+
|
|
69
|
+
distance = vert.get_vertex_distance(v)
|
|
70
|
+
|
|
71
|
+
if idx == 0:
|
|
72
|
+
min_id = idx
|
|
73
|
+
min_distance = distance
|
|
74
|
+
continue
|
|
75
|
+
|
|
76
|
+
if distance < min_distance:
|
|
77
|
+
min_id = idx
|
|
78
|
+
min_distance = distance
|
|
79
|
+
|
|
80
|
+
return verts[min_id]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: icplot
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
4
4
|
Summary: Utilities for generating plots and graphics for technical reports.
|
|
5
5
|
Author-email: "James Grogan, Irish Centre for High End Computing" <james.grogan@ichec.ie>
|
|
6
6
|
Project-URL: Repository, https://git.ichec.ie/performance/toolshed/icplot
|
|
@@ -29,22 +29,22 @@ icplot/graph/series.py,sha256=ppzQeFPY9w6Tx8RPPjEt98YXbyhNRv9QfvCJVglmtm4,3164
|
|
|
29
29
|
icplot/graph/video.py,sha256=NxE6WanX3pS9t8XTQyaNwdkiaZL85qlJn1TwPZ-81-I,748
|
|
30
30
|
icplot/graph/vtk.py,sha256=om-zujuxDKqT8IUfPkiNpanoTWwaYuXOpL2WjaLX7Xs,1918
|
|
31
31
|
icplot/mesh/__init__.py,sha256=H0TKi_J8mPhd-9kRIm_9IrJh_dtx-77tAXKPFCEGptA,178
|
|
32
|
-
icplot/mesh/cell.py,sha256=
|
|
32
|
+
icplot/mesh/cell.py,sha256=kNlo5xWKAFQkqFZxWA4FHMG5sgFQ1m68uV8xGlcdJK0,2297
|
|
33
33
|
icplot/mesh/edge.py,sha256=C33Trp9JKhUhEp28Bflwh6T7occ--Mh-qOWWenZq7qw,784
|
|
34
|
-
icplot/mesh/mesh.py,sha256=
|
|
34
|
+
icplot/mesh/mesh.py,sha256=iw24box7maKpFNbkCaCJYTedV3eVV0pjqaxepP3PjIw,3372
|
|
35
35
|
icplot/mesh/operations.py,sha256=KI8Viup-qRAzPXytKYIMJko2Vko-I2VJKGXs1I6N_RA,3672
|
|
36
|
-
icplot/mesh/shapes.py,sha256=
|
|
37
|
-
icplot/mesh/vertex.py,sha256=
|
|
36
|
+
icplot/mesh/shapes.py,sha256=WvrDwTgz-PAjRRrWfFtsXAzW9b8GVUY9v7Uqk7zkUik,9321
|
|
37
|
+
icplot/mesh/vertex.py,sha256=Nh2pTaXJuOANAp8rb03D4OpMG3nk_i_JWQHQWnynXpQ,1851
|
|
38
38
|
icplot/mesh/vtk.py,sha256=BIBi4i6j7veGqcGamzS9RJA3D6C5JRiV-lyOCL0Z3vM,1148
|
|
39
39
|
icplot/mesh/openfoam/__init__.py,sha256=oTBDlpRpOUHlzyyAZvnkvO5ZAOVk1LMc3kZhHTwXL-I,97
|
|
40
40
|
icplot/mesh/openfoam/blockmesh.py,sha256=0Y-n_tARdeLxcVmLScjvnNDB-wnigMiZQFrUh9OlXm8,3417
|
|
41
|
-
icplot/mesh/openfoam/foamfile.py,sha256=
|
|
42
|
-
icplot/mesh/openfoam/polymesh.py,sha256=
|
|
41
|
+
icplot/mesh/openfoam/foamfile.py,sha256=WQVdE0bNsPB5gOFvNdwVcVxfPbN2gVjtxtD2PlxIHAk,3349
|
|
42
|
+
icplot/mesh/openfoam/polymesh.py,sha256=32QEJM6MtWvCeMV0bVcuXjCwkZp-qobo9sjx2vyZUkM,8547
|
|
43
43
|
icplot/trace/__init__.py,sha256=JL9a1GQa-Ty4nujQ3dLv2dETX8J1iGDm8PlGL2Ug1dQ,29
|
|
44
44
|
icplot/trace/trace.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
45
|
-
icplot-0.2.
|
|
46
|
-
icplot-0.2.
|
|
47
|
-
icplot-0.2.
|
|
48
|
-
icplot-0.2.
|
|
49
|
-
icplot-0.2.
|
|
50
|
-
icplot-0.2.
|
|
45
|
+
icplot-0.2.4.dist-info/licenses/LICENSE,sha256=JedcPd23DfREo3CH5_Sc8He0jmmbOWIm1_sQaisXZ9E,34592
|
|
46
|
+
icplot-0.2.4.dist-info/METADATA,sha256=deb2q2lchW9ZfJ68OeBKQK00kX6ccgVd2ILpPY1cob0,2791
|
|
47
|
+
icplot-0.2.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
48
|
+
icplot-0.2.4.dist-info/entry_points.txt,sha256=6CdEGO5Z4NTQoOeRITTKGtzT3xNX47CGHZuWNWxZuZs,52
|
|
49
|
+
icplot-0.2.4.dist-info/top_level.txt,sha256=T_ecIGmXlOO4_xP86S-OFL8nnoxmDQFXjcDoIwpiHQk,7
|
|
50
|
+
icplot-0.2.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|