icplot 0.2.3__tar.gz → 0.2.4__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.
- {icplot-0.2.3/src/icplot.egg-info → icplot-0.2.4}/PKG-INFO +1 -1
- {icplot-0.2.3 → icplot-0.2.4}/pyproject.toml +1 -1
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/mesh/cell.py +21 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/mesh/mesh.py +22 -2
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/mesh/openfoam/foamfile.py +10 -2
- icplot-0.2.4/src/icplot/mesh/openfoam/polymesh.py +315 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/mesh/shapes.py +122 -4
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/mesh/vertex.py +23 -0
- {icplot-0.2.3 → icplot-0.2.4/src/icplot.egg-info}/PKG-INFO +1 -1
- icplot-0.2.4/test/test_meshing.py +94 -0
- icplot-0.2.4/test/test_polymesh.py +124 -0
- icplot-0.2.3/src/icplot/mesh/openfoam/polymesh.py +0 -46
- icplot-0.2.3/test/test_meshing.py +0 -49
- icplot-0.2.3/test/test_polymesh.py +0 -10
- {icplot-0.2.3 → icplot-0.2.4}/LICENSE +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/README.md +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/setup.cfg +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/__init__.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/cairo_interface.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/color.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/convert.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/gantt/__init__.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/gantt/gantt.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/gantt/gantt_renderer.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/gantt/pgfgantt.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/geometry/__init__.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/geometry/base.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/geometry/operations.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/geometry/shapes.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/geometry/transform.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/graph/__init__.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/graph/axis.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/graph/generator.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/graph/matplotlib.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/graph/mpl.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/graph/plot.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/graph/plot_group.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/graph/series.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/graph/video.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/graph/vtk.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/image_utils.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/main_cli.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/mermaid.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/mesh/__init__.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/mesh/edge.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/mesh/openfoam/__init__.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/mesh/openfoam/blockmesh.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/mesh/operations.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/mesh/vtk.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/py.typed +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/scene.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/tex.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/trace/__init__.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/trace/trace.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot/tree.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot.egg-info/SOURCES.txt +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot.egg-info/dependency_links.txt +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot.egg-info/entry_points.txt +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot.egg-info/requires.txt +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/src/icplot.egg-info/top_level.txt +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/test/test_cairo_interface.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/test/test_gantt_chart.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/test/test_geometry.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/test/test_image_utils.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/test/test_line_plots.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/test/test_mermaid.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/test/test_openfoam.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/test/test_plot_group.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/test/test_tex.py +0 -0
- {icplot-0.2.3 → icplot-0.2.4}/test/test_tree.py +0 -0
|
@@ -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
|
|
@@ -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
|
"""
|
|
@@ -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
|
+
)
|
|
@@ -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
|
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from functools import cmp_to_key
|
|
4
|
+
|
|
5
|
+
from icplot.geometry import Point
|
|
6
|
+
from icplot.mesh import Vertex, Mesh, get_hex_faces
|
|
7
|
+
|
|
8
|
+
from .foamfile import read_foamfile, FoamFile, write_header
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass(frozen=True)
|
|
12
|
+
class Face:
|
|
13
|
+
"""
|
|
14
|
+
A mesh face, which is a sequence of vertices
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
vertices: tuple[int, ...]
|
|
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
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@dataclass(frozen=True)
|
|
32
|
+
class Cell:
|
|
33
|
+
"""
|
|
34
|
+
A mesh cell, which is a squence of faces
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
faces: tuple[int, ...]
|
|
38
|
+
id: int = -1
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclass(frozen=True)
|
|
42
|
+
class Polymesh:
|
|
43
|
+
"""
|
|
44
|
+
The polymesh
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
vertices: tuple[Vertex, ...]
|
|
48
|
+
faces: tuple[Face, ...]
|
|
49
|
+
cells: tuple[Cell, ...]
|
|
50
|
+
|
|
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
|
+
|
|
66
|
+
def read_polymesh(path: Path) -> Polymesh:
|
|
67
|
+
|
|
68
|
+
points_file = read_foamfile(path / "points")
|
|
69
|
+
# faces_file = read_foamfile(path / "faces")
|
|
70
|
+
print(points_file)
|
|
71
|
+
# print(faces_file)
|
|
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))
|
|
@@ -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:
|
|
@@ -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
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
from iccore.test_utils import get_test_output_dir
|
|
2
|
+
|
|
3
|
+
from icplot.geometry import Quad, Annulus, Circle, Cylinder
|
|
4
|
+
from icplot.mesh import (
|
|
5
|
+
vtk,
|
|
6
|
+
mesh_rectangle,
|
|
7
|
+
mesh_annulus,
|
|
8
|
+
mesh_circle,
|
|
9
|
+
mesh_extrude,
|
|
10
|
+
mesh_cylinder_basic,
|
|
11
|
+
mesh_compound_cylinder,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def test_mesh_rectangle():
|
|
16
|
+
|
|
17
|
+
output_dir = get_test_output_dir()
|
|
18
|
+
|
|
19
|
+
rect = Quad(width=5.0, height=5.0)
|
|
20
|
+
mesh = mesh_rectangle(rect, 5, 5)
|
|
21
|
+
|
|
22
|
+
vtk.write_unstructured_grid(mesh, output_dir / "rectangle.vtk")
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def test_annulus():
|
|
26
|
+
|
|
27
|
+
output_dir = get_test_output_dir()
|
|
28
|
+
|
|
29
|
+
shape = Annulus(outer_radius=1.0, inner_radius=0.5, angle=360)
|
|
30
|
+
mesh = mesh_annulus(shape, 2, 8)
|
|
31
|
+
|
|
32
|
+
vtk.write_unstructured_grid(mesh, output_dir / "annulus.vtk")
|
|
33
|
+
vtk.write_unstructured_grid(
|
|
34
|
+
mesh_extrude(mesh, 5, 5), output_dir / "annulus_extruded.vtk"
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def test_circle():
|
|
39
|
+
|
|
40
|
+
output_dir = get_test_output_dir()
|
|
41
|
+
|
|
42
|
+
shape = Circle(radius=1.0)
|
|
43
|
+
mesh = mesh_circle(shape, 0.7, 4, 24)
|
|
44
|
+
|
|
45
|
+
vtk.write_unstructured_grid(mesh, output_dir / "circle.vtk")
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def test_extrude():
|
|
49
|
+
|
|
50
|
+
output_dir = get_test_output_dir()
|
|
51
|
+
|
|
52
|
+
rect = Quad(width=5.0, height=5.0)
|
|
53
|
+
mesh = mesh_rectangle(rect, 5, 5)
|
|
54
|
+
|
|
55
|
+
extruded_mesh = mesh_extrude(mesh, 5, 5)
|
|
56
|
+
|
|
57
|
+
vtk.write_unstructured_grid(extruded_mesh, output_dir / "extrude.vtk")
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def test_cylinder():
|
|
61
|
+
|
|
62
|
+
output_dir = get_test_output_dir()
|
|
63
|
+
|
|
64
|
+
shape = Cylinder(diameter=2.0, length=5.0)
|
|
65
|
+
mesh = mesh_cylinder_basic(shape, 0.5, 2, 16, 5)
|
|
66
|
+
|
|
67
|
+
vtk.write_unstructured_grid(mesh, output_dir / "cylinder.vtk")
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def xtest_compound_cylinder():
|
|
71
|
+
|
|
72
|
+
output_dir = get_test_output_dir()
|
|
73
|
+
|
|
74
|
+
inlet_radius = 0.5
|
|
75
|
+
inlet_height = 1.0
|
|
76
|
+
radius = 2.0
|
|
77
|
+
height = 5.0
|
|
78
|
+
boundary_fraction = 0.5
|
|
79
|
+
num_circumferential = 16
|
|
80
|
+
num_radial = 4
|
|
81
|
+
num_height = 4
|
|
82
|
+
|
|
83
|
+
mesh = mesh_compound_cylinder(
|
|
84
|
+
inlet_radius,
|
|
85
|
+
inlet_height,
|
|
86
|
+
radius,
|
|
87
|
+
height,
|
|
88
|
+
boundary_fraction,
|
|
89
|
+
num_circumferential,
|
|
90
|
+
num_radial,
|
|
91
|
+
num_height,
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
vtk.write_unstructured_grid(mesh, output_dir / "compound_cylinder.vtk")
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
from pathlib import Path
|
|
2
|
+
import shutil
|
|
3
|
+
|
|
4
|
+
from icplot.mesh.openfoam import polymesh
|
|
5
|
+
from icplot.mesh import (
|
|
6
|
+
mesh_cylinder_basic,
|
|
7
|
+
mesh_compound_cylinder,
|
|
8
|
+
mesh_rectangle,
|
|
9
|
+
mesh_extrude,
|
|
10
|
+
vtk,
|
|
11
|
+
)
|
|
12
|
+
from icplot.geometry import Cylinder, Point, Quad
|
|
13
|
+
|
|
14
|
+
from iccore.test_utils import get_test_data_dir, get_test_output_dir
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def xtest_read_polymesh():
|
|
18
|
+
|
|
19
|
+
data_dir = get_test_data_dir()
|
|
20
|
+
|
|
21
|
+
mesh = polymesh.read_polymesh(data_dir / "openfoam/polymesh/basic")
|
|
22
|
+
print(mesh)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def inlet_func(face_centre: Point):
|
|
26
|
+
return face_centre.z == 0.0
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def outlet_func(face_centre: Point):
|
|
30
|
+
return face_centre.z == 5.0
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def test_polymesh_cube():
|
|
34
|
+
|
|
35
|
+
output_dir = get_test_output_dir()
|
|
36
|
+
polymesh_dir = output_dir / "constant/polyMesh"
|
|
37
|
+
polymesh_dir.mkdir(parents=True, exist_ok=True)
|
|
38
|
+
|
|
39
|
+
system_dir = output_dir / "system"
|
|
40
|
+
system_dir.mkdir(parents=True, exist_ok=True)
|
|
41
|
+
|
|
42
|
+
control_path = Path(__file__).parent.parent / "src/icplot/mesh/openfoam/controlDict"
|
|
43
|
+
shutil.copy(control_path, system_dir)
|
|
44
|
+
|
|
45
|
+
shape = Quad(width=1.0, height=1.0)
|
|
46
|
+
mesh = mesh_rectangle(shape, 2, 2)
|
|
47
|
+
mesh = mesh_extrude(mesh, 5.0, 2)
|
|
48
|
+
|
|
49
|
+
vtk.write_unstructured_grid(mesh, output_dir / "cube.vtk")
|
|
50
|
+
|
|
51
|
+
polymesh.write_polymesh(
|
|
52
|
+
polymesh_dir, mesh, {"inlet": inlet_func, "outlet": outlet_func}
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def test_polymesh_cylinder():
|
|
57
|
+
|
|
58
|
+
output_dir = get_test_output_dir()
|
|
59
|
+
polymesh_dir = output_dir / "constant/polyMesh"
|
|
60
|
+
polymesh_dir.mkdir(parents=True, exist_ok=True)
|
|
61
|
+
|
|
62
|
+
system_dir = output_dir / "system"
|
|
63
|
+
system_dir.mkdir(parents=True, exist_ok=True)
|
|
64
|
+
|
|
65
|
+
control_path = Path(__file__).parent.parent / "src/icplot/mesh/openfoam/controlDict"
|
|
66
|
+
shutil.copy(control_path, system_dir)
|
|
67
|
+
|
|
68
|
+
shape = Cylinder(diameter=2.0, length=5.0)
|
|
69
|
+
mesh = mesh_cylinder_basic(shape, 0.5, 2, 8, 2)
|
|
70
|
+
|
|
71
|
+
vtk.write_unstructured_grid(mesh, output_dir / "cylinder.vtk")
|
|
72
|
+
|
|
73
|
+
polymesh.write_polymesh(
|
|
74
|
+
polymesh_dir, mesh, {"inlet": inlet_func, "outlet": outlet_func}
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def compound_inlet_func(face_centre: Point):
|
|
79
|
+
return face_centre.z == 0.0
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def compound_outlet_func(face_centre: Point):
|
|
83
|
+
return face_centre.z == 7.0
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def xtest_polymesh_compound_cylinder():
|
|
87
|
+
|
|
88
|
+
output_dir = get_test_output_dir()
|
|
89
|
+
polymesh_dir = output_dir / "constant/polyMesh"
|
|
90
|
+
polymesh_dir.mkdir(parents=True, exist_ok=True)
|
|
91
|
+
|
|
92
|
+
system_dir = output_dir / "system"
|
|
93
|
+
system_dir.mkdir(parents=True, exist_ok=True)
|
|
94
|
+
|
|
95
|
+
control_path = Path(__file__).parent.parent / "src/icplot/mesh/openfoam/controlDict"
|
|
96
|
+
shutil.copy(control_path, system_dir)
|
|
97
|
+
|
|
98
|
+
inlet_radius = 0.5
|
|
99
|
+
inlet_height = 1.0
|
|
100
|
+
radius = 2.0
|
|
101
|
+
height = 5.0
|
|
102
|
+
boundary_fraction = 0.5
|
|
103
|
+
num_circumferential = 16
|
|
104
|
+
num_radial = 4
|
|
105
|
+
num_height = 4
|
|
106
|
+
|
|
107
|
+
mesh = mesh_compound_cylinder(
|
|
108
|
+
inlet_radius,
|
|
109
|
+
inlet_height,
|
|
110
|
+
radius,
|
|
111
|
+
height,
|
|
112
|
+
boundary_fraction,
|
|
113
|
+
num_circumferential,
|
|
114
|
+
num_radial,
|
|
115
|
+
num_height,
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
vtk.write_unstructured_grid(mesh, output_dir / "compound_cylinder.vtk")
|
|
119
|
+
|
|
120
|
+
polymesh.write_polymesh(
|
|
121
|
+
polymesh_dir,
|
|
122
|
+
mesh,
|
|
123
|
+
{"inlet": compound_inlet_func, "outlet": compound_outlet_func},
|
|
124
|
+
)
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
from dataclasses import dataclass
|
|
2
|
-
from pathlib import Path
|
|
3
|
-
|
|
4
|
-
from icplot.mesh import Vertex
|
|
5
|
-
|
|
6
|
-
from .foamfile import read_foamfile
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
@dataclass(frozen=True)
|
|
10
|
-
class Face:
|
|
11
|
-
"""
|
|
12
|
-
A mesh face, which is a sequence of points
|
|
13
|
-
"""
|
|
14
|
-
|
|
15
|
-
points: tuple[int, ...]
|
|
16
|
-
id: int = -1
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
@dataclass(frozen=True)
|
|
20
|
-
class Cell:
|
|
21
|
-
"""
|
|
22
|
-
A mesh cell, which is a squence of faces
|
|
23
|
-
"""
|
|
24
|
-
|
|
25
|
-
faces: tuple[int, ...]
|
|
26
|
-
id: int = -1
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
@dataclass(frozen=True)
|
|
30
|
-
class Polymesh:
|
|
31
|
-
"""
|
|
32
|
-
The polymesh
|
|
33
|
-
"""
|
|
34
|
-
|
|
35
|
-
points: tuple[Vertex, ...]
|
|
36
|
-
faces: tuple[Face, ...]
|
|
37
|
-
cells: tuple[Cell, ...]
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def read_polymesh(path: Path) -> Polymesh:
|
|
41
|
-
|
|
42
|
-
points_file = read_foamfile(path / "points")
|
|
43
|
-
# faces_file = read_foamfile(path / "faces")
|
|
44
|
-
print(points_file)
|
|
45
|
-
# print(faces_file)
|
|
46
|
-
return Polymesh((), (), ())
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
from iccore.test_utils import get_test_output_dir
|
|
2
|
-
|
|
3
|
-
from icplot.geometry import Quad, Annulus, Circle
|
|
4
|
-
from icplot.mesh import vtk, mesh_rectangle, mesh_annulus, mesh_circle, mesh_extrude
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def test_mesh_rectangle():
|
|
8
|
-
|
|
9
|
-
output_dir = get_test_output_dir()
|
|
10
|
-
|
|
11
|
-
rect = Quad(width=5.0, height=5.0)
|
|
12
|
-
mesh = mesh_rectangle(rect, 5, 5)
|
|
13
|
-
|
|
14
|
-
vtk.write_unstructured_grid(mesh, output_dir / "rectangle.vtk")
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def test_annulus():
|
|
18
|
-
|
|
19
|
-
output_dir = get_test_output_dir()
|
|
20
|
-
|
|
21
|
-
shape = Annulus(outer_radius=1.0, inner_radius=0.5, angle=360)
|
|
22
|
-
mesh = mesh_annulus(shape, 2, 8)
|
|
23
|
-
|
|
24
|
-
vtk.write_unstructured_grid(mesh, output_dir / "annulus.vtk")
|
|
25
|
-
vtk.write_unstructured_grid(
|
|
26
|
-
mesh_extrude(mesh, 5, 5), output_dir / "annulus_extruded.vtk"
|
|
27
|
-
)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
def test_circle():
|
|
31
|
-
|
|
32
|
-
output_dir = get_test_output_dir()
|
|
33
|
-
|
|
34
|
-
shape = Circle(radius=1.0)
|
|
35
|
-
mesh = mesh_circle(shape, 0.5, 2, 8)
|
|
36
|
-
|
|
37
|
-
vtk.write_unstructured_grid(mesh, output_dir / "circle.vtk")
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
def test_extrude():
|
|
41
|
-
|
|
42
|
-
output_dir = get_test_output_dir()
|
|
43
|
-
|
|
44
|
-
rect = Quad(width=5.0, height=5.0)
|
|
45
|
-
mesh = mesh_rectangle(rect, 5, 5)
|
|
46
|
-
|
|
47
|
-
extruded_mesh = mesh_extrude(mesh, 5, 5)
|
|
48
|
-
|
|
49
|
-
vtk.write_unstructured_grid(extruded_mesh, output_dir / "extrude.vtk")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|