PyHOPE 0.0.9__tar.gz → 0.1.0__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.
Files changed (64) hide show
  1. {pyhope-0.0.9 → pyhope-0.1.0}/PKG-INFO +9 -5
  2. {pyhope-0.0.9 → pyhope-0.1.0}/README.md +8 -4
  3. pyhope-0.1.0/pyhope/__init__.py +163 -0
  4. pyhope-0.1.0/pyhope/basis/basis_connect.py +190 -0
  5. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/basis/basis_watertight.py +1 -5
  6. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/common/common.py +12 -2
  7. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/common/common_parallel.py +5 -1
  8. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/common/common_progress.py +9 -4
  9. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/gmsh/gmsh_install.py +5 -6
  10. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/io/formats/meshio.py +2 -3
  11. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/io/io.py +3 -4
  12. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/io/io_vars.py +2 -3
  13. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/mesh/connect/connect.py +72 -42
  14. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/mesh/connect/connect_mortar.py +6 -14
  15. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/mesh/fem/fem.py +5 -9
  16. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/mesh/mesh.py +6 -12
  17. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/mesh/mesh_builtin.py +4 -8
  18. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/mesh/mesh_common.py +168 -21
  19. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/mesh/mesh_duplicates.py +9 -6
  20. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/mesh/mesh_external.py +12 -10
  21. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/mesh/reader/reader_gambit.py +17 -14
  22. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/mesh/reader/reader_gmsh.py +28 -40
  23. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/mesh/reader/reader_hopr.py +9 -100
  24. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/mesh/topology/mesh_splittohex.py +6 -13
  25. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/mesh/topology/mesh_topology.py +24 -33
  26. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/mesh/transform/mesh_transform.py +3 -9
  27. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/meshio/meshio_convert.py +1 -1
  28. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/meshio/meshio_ordering.py +1 -1
  29. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/output/output.py +48 -28
  30. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/readintools/readintools.py +20 -49
  31. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/script/pyhope_cli.py +2 -0
  32. {pyhope-0.0.9 → pyhope-0.1.0}/pyproject.toml +1 -1
  33. {pyhope-0.0.9 → pyhope-0.1.0}/LICENSE.md +0 -0
  34. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/__main__.py +0 -0
  35. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/basis/__init__.py +0 -0
  36. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/basis/basis_basis.py +0 -0
  37. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/basis/basis_jacobian.py +0 -0
  38. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/common/__init__.py +0 -0
  39. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/common/common_tools.py +0 -0
  40. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/common/common_vars.py +0 -0
  41. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/config/__init__.py +0 -0
  42. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/config/config.py +0 -0
  43. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/gmsh/gmsh_override.py +0 -0
  44. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/io/__init__.py +0 -0
  45. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/io/formats/cgns.py +0 -0
  46. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/io/formats/gmsh.py +0 -0
  47. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/io/formats/vtk.py +0 -0
  48. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/mesh/__init__.py +0 -0
  49. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/mesh/connect/connect_rbtree.py +0 -0
  50. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/mesh/elements/elements_ordering.py +0 -0
  51. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/mesh/elements/elements_shapefunctions.py +0 -0
  52. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/mesh/mesh_orient.py +0 -0
  53. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/mesh/mesh_sides.py +0 -0
  54. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/mesh/mesh_sort.py +0 -0
  55. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/mesh/mesh_vars.py +0 -0
  56. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/mesh/topology/mesh_serendipity.py +0 -0
  57. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/mesh/transform/templates/convtest.py +0 -0
  58. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/mesh/transform/templates/cylinder.py +0 -0
  59. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/mesh/transform/templates/default.py +0 -0
  60. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/mesh/transform/templates/phill.py +0 -0
  61. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/mesh/transform/templates/sphere.py +0 -0
  62. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/output/__init__.py +0 -0
  63. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/readintools/__init__.py +0 -0
  64. {pyhope-0.0.9 → pyhope-0.1.0}/pyhope/readintools/commandline.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: PyHOPE
3
- Version: 0.0.9
3
+ Version: 0.1.0
4
4
  Summary: Python High-Order Preprocessing Environment
5
5
  License: GPL-3.0-only
6
6
  Keywords: PyHOPE,mesh generator
@@ -81,7 +81,7 @@ $ pyhope tutorials/1-01-cartbox/parameter.ini
81
81
  ├─────────────────────────────────────────────
82
82
  │ INIT MESH...
83
83
  │ Mode │ 1 [Internal] │ *CUSTOM │
84
- │ NGeo │ 4 │ *CUSTOM │
84
+ │ NGeo │ 9 │ *CUSTOM │
85
85
  ├─────────────────────────────────────────────
86
86
  │ GENERATE MESH...
87
87
  ├────
@@ -89,6 +89,7 @@ $ pyhope tutorials/1-01-cartbox/parameter.ini
89
89
  ├── Generating zone 1
90
90
  │ Corner │ (/0.,0.,0. ,,1.,0.,0. ,,1.,1... │ *CUSTOM │
91
91
  │ nElems │ (/8,8,8/) │ *CUSTOM │
92
+ │ ElemType │ 108 [hexahedron] │ *CUSTOM │
92
93
  │ StretchType │ (/0,0,0/) │ DEFAULT │
93
94
  │ BCIndex │ (/1,2,3,4,5,6/) │ *CUSTOM │
94
95
  ├────
@@ -111,8 +112,6 @@ $ pyhope tutorials/1-01-cartbox/parameter.ini
111
112
  │ vv │ (/0., 1., 0./) │ *CUSTOM │
112
113
  │ vv │ (/0., 0., 1./) │ *CUSTOM │
113
114
  ├────
114
- │ ElemType │ 108 [hexahedron] │ *CUSTOM │
115
- ├────
116
115
  ├── Generated mesh with 512 cells
117
116
  ├─────────────────────────────────────────────
118
117
  ├── BUILD DATA STRUCTURE...
@@ -133,7 +132,7 @@ $ pyhope tutorials/1-01-cartbox/parameter.ini
133
132
  ├─────────────────────────────────────────────
134
133
  │ CONNECT MESH...
135
134
  ├────
136
- │ doPeriodicCorrect │ True │ DEFAULT │
135
+ │ doPeriodicCorrect │ False │ DEFAULT │
137
136
  │ doMortars │ True │ DEFAULT │
138
137
  ├────
139
138
  │ Number of sides : 3072
@@ -143,6 +142,11 @@ $ pyhope tutorials/1-01-cartbox/parameter.ini
143
142
  │ Number of boundary sides : 384
144
143
  │ Number of periodic sides : 0
145
144
  ├─────────────────────────────────────────────
145
+ │ CHECK CONNECTIVITY...
146
+ ├────
147
+ │ CheckConnectivity │ True │ DEFAULT │
148
+ │ Processing Elements |█████████████████████████████████| 512/512 [100%] in 0.0s (24000.00/s)
149
+ ├─────────────────────────────────────────────
146
150
  │ CHECK WATERTIGHTNESS...
147
151
  ├────
148
152
  │ CheckWatertightness │ True │ DEFAULT │
@@ -49,7 +49,7 @@ $ pyhope tutorials/1-01-cartbox/parameter.ini
49
49
  ├─────────────────────────────────────────────
50
50
  │ INIT MESH...
51
51
  │ Mode │ 1 [Internal] │ *CUSTOM │
52
- │ NGeo │ 4 │ *CUSTOM │
52
+ │ NGeo │ 9 │ *CUSTOM │
53
53
  ├─────────────────────────────────────────────
54
54
  │ GENERATE MESH...
55
55
  ├────
@@ -57,6 +57,7 @@ $ pyhope tutorials/1-01-cartbox/parameter.ini
57
57
  ├── Generating zone 1
58
58
  │ Corner │ (/0.,0.,0. ,,1.,0.,0. ,,1.,1... │ *CUSTOM │
59
59
  │ nElems │ (/8,8,8/) │ *CUSTOM │
60
+ │ ElemType │ 108 [hexahedron] │ *CUSTOM │
60
61
  │ StretchType │ (/0,0,0/) │ DEFAULT │
61
62
  │ BCIndex │ (/1,2,3,4,5,6/) │ *CUSTOM │
62
63
  ├────
@@ -79,8 +80,6 @@ $ pyhope tutorials/1-01-cartbox/parameter.ini
79
80
  │ vv │ (/0., 1., 0./) │ *CUSTOM │
80
81
  │ vv │ (/0., 0., 1./) │ *CUSTOM │
81
82
  ├────
82
- │ ElemType │ 108 [hexahedron] │ *CUSTOM │
83
- ├────
84
83
  ├── Generated mesh with 512 cells
85
84
  ├─────────────────────────────────────────────
86
85
  ├── BUILD DATA STRUCTURE...
@@ -101,7 +100,7 @@ $ pyhope tutorials/1-01-cartbox/parameter.ini
101
100
  ├─────────────────────────────────────────────
102
101
  │ CONNECT MESH...
103
102
  ├────
104
- │ doPeriodicCorrect │ True │ DEFAULT │
103
+ │ doPeriodicCorrect │ False │ DEFAULT │
105
104
  │ doMortars │ True │ DEFAULT │
106
105
  ├────
107
106
  │ Number of sides : 3072
@@ -111,6 +110,11 @@ $ pyhope tutorials/1-01-cartbox/parameter.ini
111
110
  │ Number of boundary sides : 384
112
111
  │ Number of periodic sides : 0
113
112
  ├─────────────────────────────────────────────
113
+ │ CHECK CONNECTIVITY...
114
+ ├────
115
+ │ CheckConnectivity │ True │ DEFAULT │
116
+ │ Processing Elements |█████████████████████████████████| 512/512 [100%] in 0.0s (24000.00/s)
117
+ ├─────────────────────────────────────────────
114
118
  │ CHECK WATERTIGHTNESS...
115
119
  ├────
116
120
  │ CheckWatertightness │ True │ DEFAULT │
@@ -0,0 +1,163 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ #
4
+ # SPDX-License-Identifier: GPL-3.0-or-later
5
+ #
6
+ # This file is part of PyHOPE
7
+ #
8
+ # Copyright (c) 2024 Numerics Research Group, University of Stuttgart, Prof. Andrea Beck
9
+ #
10
+ # PyHOPE is free software: you can redistribute it and/or modify it under the
11
+ # terms of the GNU General Public License as published by the Free Software
12
+ # Foundation, either version 3 of the License, or (at your option) any later
13
+ # version.
14
+ #
15
+ # PyHOPE is distributed in the hope that it will be useful, but WITHOUT ANY
16
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
17
+ # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18
+ #
19
+ # You should have received a copy of the GNU General Public License along with
20
+ # PyHOPE. If not, see <http://www.gnu.org/licenses/>.
21
+
22
+
23
+ # ==================================================================================================================================
24
+ # Mesh generation library
25
+ # ==================================================================================================================================
26
+ # ----------------------------------------------------------------------------------------------------------------------------------
27
+ # Standard libraries
28
+ # ----------------------------------------------------------------------------------------------------------------------------------
29
+ from collections import namedtuple
30
+ from contextlib import contextmanager
31
+ # ----------------------------------------------------------------------------------------------------------------------------------
32
+ # Third-party libraries
33
+ # ----------------------------------------------------------------------------------------------------------------------------------
34
+ # ----------------------------------------------------------------------------------------------------------------------------------
35
+ # Local imports
36
+ # ----------------------------------------------------------------------------------------------------------------------------------
37
+ from pyhope.basis.basis_basis import legendre_gauss_nodes, legendre_gauss_lobatto_nodes
38
+ from pyhope.basis.basis_basis import barycentric_weights, polynomial_derivative_matrix
39
+ from pyhope.basis.basis_basis import lagrange_interpolation_polys, calc_vandermonde
40
+ from pyhope.basis.basis_basis import change_basis_3D, change_basis_2D
41
+ from pyhope.basis.basis_basis import evaluate_jacobian
42
+ # ==================================================================================================================================
43
+
44
+
45
+ class Basis:
46
+ """ Basis class to hold all basis related functions and variables
47
+ """
48
+ legendre_gauss_nodes = staticmethod(legendre_gauss_nodes)
49
+ legendre_gauss_lobatto_nodes = staticmethod(legendre_gauss_lobatto_nodes)
50
+ barycentric_weights = staticmethod(barycentric_weights)
51
+ polynomial_derivative_matrix = staticmethod(polynomial_derivative_matrix)
52
+ lagrange_interpolation_polys = staticmethod(lagrange_interpolation_polys)
53
+ calc_vandermonde = staticmethod(calc_vandermonde)
54
+ change_basis_3D = staticmethod(change_basis_3D)
55
+ change_basis_2D = staticmethod(change_basis_2D)
56
+ evaluate_jacobian = staticmethod(evaluate_jacobian)
57
+
58
+
59
+ # Define a named tuple to hold the mesh data
60
+ MeshContainer = namedtuple('Mesh',
61
+ ['mesh', # The generated mesh object
62
+ 'nGeo', # Polynomial order
63
+ 'bcs', # Boundary conditions
64
+ 'elems', # Elements
65
+ 'sides' # Sides
66
+ ])
67
+
68
+
69
+ @contextmanager
70
+ def Mesh(*args, stdout=False, stderr=True):
71
+ """ Mesh context manager to generate a mesh from a given file
72
+
73
+ Args:
74
+ *args: The mesh file path(s) to be processed
75
+ stdout (bool): If False, standard output is suppressed
76
+ stderr (bool): If False, standard error is suppressed
77
+
78
+ Yields:
79
+ Mesh: An object containing the generated mesh and its properties
80
+ """
81
+ # Standard libraries -----------------------------------
82
+ import os
83
+ # Third-party libraries --------------------------------
84
+ import h5py
85
+ from contextlib import redirect_stdout, redirect_stderr, ExitStack
86
+ # Local imports ----------------------------------------
87
+ import pyhope.config.config as config
88
+ import pyhope.mesh.mesh_vars as mesh_vars
89
+ from pyhope.common.common import DefineCommon, InitCommon
90
+ from pyhope.io.io import DefineIO, InitIO
91
+ from pyhope.mesh.connect.connect import ConnectMesh
92
+ from pyhope.mesh.mesh import DefineMesh, InitMesh, GenerateMesh
93
+ from pyhope.mesh.mesh_sides import GenerateSides
94
+ from pyhope.readintools.readintools import DefineConfig, ReadConfig
95
+ # ------------------------------------------------------
96
+
97
+ try:
98
+ # Check if the arguments provided are valid mesh files
99
+ if not args:
100
+ raise ValueError('No mesh file provided.')
101
+
102
+ for arg in args:
103
+ # Check if the argument is a valid file path
104
+ if not os.path.isfile(arg):
105
+ raise FileNotFoundError(f'Mesh file not found: {arg}')
106
+
107
+ # Check if the argument is a valid HDF5 file
108
+ if not h5py.is_hdf5(arg):
109
+ raise ValueError(f'Mesh file not a valid HDF5 file: {arg}')
110
+
111
+ # Suppress output to standard output
112
+ with ExitStack() as stack:
113
+ with open(os.devnull, 'w') as null:
114
+ if not stdout:
115
+ stack.enter_context(redirect_stdout(null))
116
+ if not stderr:
117
+ stack.enter_context(redirect_stderr(null))
118
+
119
+ # Perform the reduced PyHOPE initialization
120
+ with DefineConfig() as dc:
121
+ config.prms = dc
122
+ DefineCommon()
123
+ DefineIO()
124
+ DefineMesh()
125
+
126
+ with ReadConfig(args[0]) as rc:
127
+ config.params = rc
128
+
129
+ # Read-in required parameters
130
+ InitCommon()
131
+ InitIO()
132
+ InitMesh()
133
+
134
+ # Generate the actual mesh
135
+ GenerateMesh()
136
+
137
+ # Build our data structures
138
+ GenerateSides()
139
+ ConnectMesh()
140
+
141
+ # Export mesh variables
142
+ mesh = mesh_vars.mesh
143
+
144
+ nGeo = mesh_vars.nGeo
145
+ bcs = mesh_vars.bcs
146
+
147
+ elems = mesh_vars.elems
148
+ sides = mesh_vars.sides
149
+
150
+ yield MeshContainer(mesh = mesh, # noqa: E251
151
+ nGeo = nGeo, # noqa: E251
152
+ bcs = bcs, # noqa: E251
153
+ elems = elems, # noqa: E251
154
+ sides = sides # noqa: E251
155
+ )
156
+
157
+ finally:
158
+ # Cleanup resources after exiting the context
159
+ mesh_vars.mesh = None
160
+ mesh_vars.nGeo = None
161
+ mesh_vars.bcs = None
162
+ mesh_vars.elems = None
163
+ mesh_vars.sides = None
@@ -0,0 +1,190 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+ #
4
+ # SPDX-License-Identifier: GPL-3.0-or-later
5
+ #
6
+ # This file is part of PyHOPE
7
+ #
8
+ # Copyright (c) 2024 Numerics Research Group, University of Stuttgart, Prof. Andrea Beck
9
+ #
10
+ # PyHOPE is free software: you can redistribute it and/or modify it under the
11
+ # terms of the GNU General Public License as published by the Free Software
12
+ # Foundation, either version 3 of the License, or (at your option) any later
13
+ # version.
14
+ #
15
+ # PyHOPE is distributed in the hope that it will be useful, but WITHOUT ANY
16
+ # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
17
+ # A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18
+ #
19
+ # You should have received a copy of the GNU General Public License along with
20
+ # PyHOPE. If not, see <http://www.gnu.org/licenses/>.
21
+
22
+ # ==================================================================================================================================
23
+ # Mesh generation library
24
+ # ==================================================================================================================================
25
+ # ----------------------------------------------------------------------------------------------------------------------------------
26
+ # Standard libraries
27
+ # ----------------------------------------------------------------------------------------------------------------------------------
28
+ import re
29
+ import sys
30
+ from typing import Final
31
+ # ----------------------------------------------------------------------------------------------------------------------------------
32
+ # Third-party libraries
33
+ # ----------------------------------------------------------------------------------------------------------------------------------
34
+ import numpy as np
35
+ import numpy.typing as npt
36
+ # ----------------------------------------------------------------------------------------------------------------------------------
37
+ # Local imports
38
+ # ----------------------------------------------------------------------------------------------------------------------------------
39
+ import pyhope.mesh.mesh_vars as mesh_vars
40
+ from pyhope.mesh.mesh_common import sidetovol2
41
+ from pyhope.mesh.mesh_common import face_to_nodes
42
+ # ==================================================================================================================================
43
+
44
+
45
+ def check_sides(elem,
46
+ ) -> list[bool | int | np.ndarray]:
47
+ results = []
48
+ elems: Final[list] = mesh_vars.elems
49
+ sides: Final[list] = mesh_vars.sides
50
+ nGeo: Final[int] = mesh_vars.nGeo
51
+ bcs: Final[list] = mesh_vars.bcs
52
+ # Tolerance for physical comparison
53
+ tol: Final[float] = mesh_vars.tolPeriodic
54
+ vvs: Final[list] = mesh_vars.vvs
55
+ points: Final[npt.NDArray] = mesh_vars.mesh.points
56
+
57
+ for SideID in elem.sides:
58
+ master = sides[SideID]
59
+ # Only connected sides that are master sides and not small mortar sides
60
+ if master.connection is None \
61
+ or master.connection < 0 \
62
+ or master.MS != 1 \
63
+ or master.sideType < 0: # noqa: E271
64
+ continue
65
+
66
+ side = (master, sides[master.connection])
67
+
68
+ # Only actual element sides
69
+ if side[0].face is None \
70
+ or side[1].face is None: # noqa: E271
71
+ continue
72
+
73
+ # Sanity check the flip with the other nodes
74
+ elem0 = elems[side[0].elemID]
75
+ elem1 = elems[side[1].elemID]
76
+ if elem1.type % 100 != 8:
77
+ continue
78
+
79
+ # Map the meshio nodes to the tensor-product nodes
80
+ elemType = elem0.type
81
+ nodes = elem0.nodes[sidetovol2(nGeo, 0 , side[0].face, elemType)]
82
+ nbNodes = elem1.nodes[sidetovol2(nGeo, side[1].flip, side[1].face, elemType)]
83
+
84
+ # INFO: THIS CURRENTLY MIGHT NOT WORK SINCE WE POTENTIALLY ONLY HAVE THE CORNER NODES AVAILABLE
85
+ try:
86
+ # Translate to periodic nodes if required
87
+ if side[0].bcid is not None and side[1].bcid is not None and bcs[side[1].bcid].type[0] == 1:
88
+ nbNodes = np.vectorize(lambda s: mesh_vars.periNodes[(s, bcs[side[1].bcid].name)], otypes=[int])(nbNodes)
89
+ # Check if the node IDs match
90
+ success = np.array_equal(nodes, nbNodes)
91
+ # Fallback to comparison of physical coordinates
92
+ except KeyError:
93
+ # Check if periodic vector matches using vectorized np.allclose
94
+ iVV = bcs[side[0].bcid].type[3]
95
+ vv = vvs[np.abs(iVV) - 1]['Dir'] * np.sign(iVV)
96
+ success = np.allclose(points[nodes] + vv, points[nbNodes], rtol=tol, atol=tol)
97
+
98
+ results.append((success, SideID))
99
+ return results
100
+
101
+
102
+ def process_chunk(chunk) -> np.ndarray:
103
+ """Process a chunk of elements by checking surface normal orientation
104
+ """
105
+ chunk_results = np.empty(len(chunk), dtype=object)
106
+ chunk_results[:] = [check_sides(elem_data) for elem_data in chunk]
107
+ return chunk_results
108
+
109
+
110
+ def CheckConnect() -> None:
111
+ """ Check if the mesh is correctly connected
112
+ """
113
+ # Local imports ----------------------------------------
114
+ import pyhope.output.output as hopout
115
+ import pyhope.mesh.mesh_vars as mesh_vars
116
+ from pyhope.common.common_parallel import run_in_parallel
117
+ from pyhope.common.common_vars import np_mtp
118
+ from pyhope.readintools.readintools import GetLogical
119
+ # ------------------------------------------------------
120
+
121
+ hopout.separator()
122
+ hopout.info('CHECK CONNECTIVITY...')
123
+ hopout.sep()
124
+
125
+ checkConnectivity = GetLogical('CheckConnectivity')
126
+ if not checkConnectivity:
127
+ return None
128
+
129
+ # Check all sides
130
+ elems: Final[list] = mesh_vars.elems
131
+
132
+ # Only consider hexahedrons
133
+ if any(e.type % 100 != 8 for e in elems):
134
+ elemTypes = list(set([e.type for e in elems if e.type % 100 != 8]))
135
+ print(hopout.warn('Ignored element type: {}'.format(
136
+ [re.sub(r"\d+$", "", mesh_vars.ELEMTYPE.inam[e][0]) for e in elemTypes]
137
+ )))
138
+ return
139
+
140
+ # Prepare elements for parallel processing
141
+ if np_mtp > 0:
142
+ tasks = tuple((elem)
143
+ for elem in elems)
144
+ # Run in parallel with a chunk size
145
+ # > Dispatch the tasks to the workers, minimum 10 tasks per worker, maximum 1000 tasks per worker
146
+ res = run_in_parallel(process_chunk, tasks, chunk_size=max(1, min(1000, max(10, int(len(tasks)/(40.*np_mtp))))))
147
+ else:
148
+ res = np.empty(len(elems), dtype=object)
149
+ res[:] = [check_sides(elem) for elem in elems]
150
+
151
+ results = tuple(tuple(result for r in res for result in r if not bool(result[0]))
152
+ )
153
+ if len(results) > 0:
154
+ nGeo: Final[int] = mesh_vars.nGeo
155
+ sides: Final[list] = mesh_vars.sides
156
+ points: Final[np.ndarray] = mesh_vars.mesh.points
157
+
158
+ nconn = len(tuple(tuple(result for r in res for result in r)))
159
+
160
+ for result in results:
161
+ # Unpack the results
162
+ side = sides[result[1]]
163
+ elem = elems[side.elemID]
164
+ nbside = sides[side.connection]
165
+ nbelem = elems[nbside.elemID]
166
+
167
+ nodes = elem.nodes[face_to_nodes( side.face, elem.type, nGeo)]
168
+ nbnodes = nbelem.nodes[face_to_nodes(nbside.face, nbelem.type, nGeo)]
169
+
170
+ print()
171
+ # Check if side is oriented inwards
172
+ errStr = 'Side connectivity does not match the calculated neighbour side'
173
+ print(hopout.warn(errStr, length=len(errStr)+16))
174
+
175
+ # Print the information
176
+ strLen = max(len(str(side.sideID+1)), len(str(nbside.sideID+1)))
177
+ print(hopout.warn(f'> Element { elem.elemID+1:>{strLen}}, Side { side.face}, Side { side.sideID+1:>{strLen}}')) # noqa: E501
178
+ print(hopout.warn('- Coordinates : [' + ' '.join('{:12.3f}'.format(s) for s in points[ nodes[ 0, 0]]) + ']')) # noqa: E271
179
+ print(hopout.warn('- Coordinates : [' + ' '.join('{:12.3f}'.format(s) for s in points[ nodes[ 0, -1]]) + ']')) # noqa: E271
180
+ print(hopout.warn('- Coordinates : [' + ' '.join('{:12.3f}'.format(s) for s in points[ nodes[-1, 0]]) + ']')) # noqa: E271
181
+ print(hopout.warn('- Coordinates : [' + ' '.join('{:12.3f}'.format(s) for s in points[ nodes[-1, -1]]) + ']')) # noqa: E271
182
+ # print()
183
+ print(hopout.warn(f'> Element {nbelem.elemID+1:>{strLen}}, Side {nbside.face}, Side {nbside.sideID+1:>{strLen}}')) # noqa: E501
184
+ print(hopout.warn('- Coordinates : [' + ' '.join('{:12.3f}'.format(s) for s in points[nbnodes[ 0, 0]]) + ']')) # noqa: E271
185
+ print(hopout.warn('- Coordinates : [' + ' '.join('{:12.3f}'.format(s) for s in points[nbnodes[ 0, -1]]) + ']')) # noqa: E271
186
+ print(hopout.warn('- Coordinates : [' + ' '.join('{:12.3f}'.format(s) for s in points[nbnodes[-1, 0]]) + ']')) # noqa: E271
187
+ print(hopout.warn('- Coordinates : [' + ' '.join('{:12.3f}'.format(s) for s in points[nbnodes[-1, -1]]) + ']')) # noqa: E271
188
+
189
+ hopout.warning(f'Connectivity check failed for {len(results)} / {nconn} connections!')
190
+ sys.exit(1)
@@ -26,7 +26,6 @@
26
26
  # Standard libraries
27
27
  # ----------------------------------------------------------------------------------------------------------------------------------
28
28
  import re
29
- import sys
30
29
  from typing import Final
31
30
  # ----------------------------------------------------------------------------------------------------------------------------------
32
31
  # Third-party libraries
@@ -76,8 +75,6 @@ def check_sides(elem,
76
75
  weights : np.ndarray,
77
76
  # sides : list
78
77
  ) -> list[bool | int | np.ndarray]:
79
- # Local imports ----------------------------------------
80
- # ------------------------------------------------------
81
78
  results = []
82
79
  points = mesh_vars.mesh.points
83
80
  elems = mesh_vars.elems
@@ -276,5 +273,4 @@ def CheckWatertight() -> None:
276
273
  print(hopout.warn('- Coordinates : [' + ' '.join('{:12.3f}'.format(s) for s in points[nbnodes[-1, 0]]) + ']')) # noqa: E271
277
274
  print(hopout.warn('- Coordinates : [' + ' '.join('{:12.3f}'.format(s) for s in points[nbnodes[-1, -1]]) + ']')) # noqa: E271
278
275
 
279
- hopout.warning(f'Watertightness check failed for {len(results)} / {nconn} connections!')
280
- sys.exit(1)
276
+ hopout.error(f'Watertightness check failed for {len(results)} / {nconn} connections!')
@@ -26,7 +26,6 @@
26
26
  # Standard libraries
27
27
  # ----------------------------------------------------------------------------------------------------------------------------------
28
28
  import os
29
- import sys
30
29
  from io import TextIOWrapper
31
30
  from typing import cast
32
31
  # ----------------------------------------------------------------------------------------------------------------------------------
@@ -104,6 +103,9 @@ def DebugEnabled() -> bool:
104
103
  """ Check if program runs with debugger attached
105
104
  > https://stackoverflow.com/a/77627075/23851165
106
105
  """
106
+ # Standard libraries -----------------------------------
107
+ import sys
108
+ # ------------------------------------------------------
107
109
  try:
108
110
  if sys.gettrace() is not None:
109
111
  return True
@@ -120,12 +122,20 @@ def DebugEnabled() -> bool:
120
122
 
121
123
 
122
124
  def IsInteractive() -> bool:
123
- return cast(TextIOWrapper, sys.__stdin__).isatty()
125
+ """ Check if the program is running in an interactive terminal
126
+ """
127
+ # Standard libraries -----------------------------------
128
+ import sys
129
+ # ------------------------------------------------------
130
+ return cast(TextIOWrapper, sys.__stdin__).isatty() and cast(TextIOWrapper, sys.__stdout__).isatty()
124
131
 
125
132
 
126
133
  def IsDisplay() -> bool:
127
134
  """ Check if the program is running in a display environment
128
135
  """
136
+ # Standard libraries -----------------------------------
137
+ import sys
138
+ # ------------------------------------------------------
129
139
  # Check if running on Linux, otherwise assume a display
130
140
  if not sys.platform.startswith('linux'):
131
141
  return True
@@ -58,6 +58,7 @@ def run_in_parallel(process_chunk: Callable, elems: tuple, chunk_size: int = 10)
58
58
  """Run the element processing in parallel using a specified number of processes
59
59
  """
60
60
  # Local imports ----------------------------------------
61
+ from pyhope.common.common import IsInteractive
61
62
  from pyhope.common.common_vars import np_mtp
62
63
  # ------------------------------------------------------
63
64
 
@@ -65,8 +66,11 @@ def run_in_parallel(process_chunk: Callable, elems: tuple, chunk_size: int = 10)
65
66
  total_elements = len(elems)
66
67
  progress_queue = Queue()
67
68
 
69
+ # Create a progress bar target
70
+ target = update_progress if IsInteractive() else None
71
+
68
72
  # Use a separate thread for the progress bar
69
- progress_thread = threading.Thread(target=update_progress, args=(progress_queue, total_elements))
73
+ progress_thread = threading.Thread(target=target, args=(progress_queue, total_elements))
70
74
  progress_thread.start()
71
75
 
72
76
  # Use multiprocessing Pool for parallel processing
@@ -45,14 +45,19 @@ class ProgressBar:
45
45
  """ Provide a progress bar outside of the context manager
46
46
  """
47
47
  def __init__(self, title: Optional[str], value: int, length: int = 33, threshold: int = barElems) -> None:
48
+ # Local imports ----------------------------------------
49
+ from pyhope.common.common import IsInteractive
50
+ # ------------------------------------------------------
51
+ if value <= threshold or not IsInteractive():
52
+ self.bar = None
53
+ return None
54
+
48
55
  self._cm : Final = alive_bar(title=title, total=value, length=length)
49
56
  self._title: Optional[str] = title
50
57
  self._len : int = length
51
58
 
52
- if value > threshold:
53
- self.bar = self._cm.__enter__()
54
- else:
55
- self.bar = None
59
+ # Initialize the progress bar
60
+ self.bar = self._cm.__enter__()
56
61
 
57
62
  def step(self, steps: int = 1) -> None:
58
63
  if self.bar is not None:
@@ -29,7 +29,6 @@ import os
29
29
  import shutil
30
30
  import platform
31
31
  import subprocess
32
- import sys
33
32
  from importlib import metadata
34
33
  from packaging.version import Version
35
34
  from typing import Optional, cast
@@ -97,8 +96,7 @@ def PkgsCheckGmsh() -> None:
97
96
  PkgsInstallGmsh(system, arch, version='pypi')
98
97
  return None
99
98
  else:
100
- hopout.warning('Gmsh is not installed, exiting...')
101
- sys.exit(1)
99
+ hopout.error('Gmsh is not installed, exiting...')
102
100
 
103
101
  gmsh_version = cast(str, gmsh_version)
104
102
  # Assume that newer versions have updated CGNS
@@ -132,9 +130,11 @@ def PkgsCheckGmsh() -> None:
132
130
 
133
131
 
134
132
  def PkgsInstallGmsh(system: str, arch: str, version: str) -> None:
135
- # Local imports ----------------------------------------
133
+ # Standard libraries -----------------------------------
134
+ import sys
136
135
  import hashlib
137
136
  import tempfile
137
+ # Local imports ----------------------------------------
138
138
  import pyhope.output.output as hopout
139
139
  from pyhope.common.common_vars import Gitlab
140
140
  # ------------------------------------------------------
@@ -185,8 +185,7 @@ def PkgsInstallGmsh(system: str, arch: str, version: str) -> None:
185
185
  if sha256.hexdigest() == Gitlab.LIB_SUPPORT[system][arch]:
186
186
  hopout.info('Hash matches, installing Gmsh wheel...')
187
187
  else:
188
- hopout.warning('Hash mismatch, exiting...')
189
- sys.exit(1)
188
+ hopout.error('Hash mismatch, exiting...')
190
189
 
191
190
  # Remove the old version
192
191
  try:
@@ -27,7 +27,6 @@
27
27
  # ----------------------------------------------------------------------------------------------------------------------------------
28
28
  from functools import cache
29
29
  from typing import Tuple
30
- import sys
31
30
  # ----------------------------------------------------------------------------------------------------------------------------------
32
31
  # Third-party libraries
33
32
  import numpy as np
@@ -144,7 +143,7 @@ def edgePointMESHIO(start: int, end: int, edge: int, node: int) -> np.ndarray:
144
143
  case 11:
145
144
  return np.array((start , end , node ), dtype=int)
146
145
  case _:
147
- sys.exit(1)
146
+ raise ValueError(f'Invalid edge index: {edge}.')
148
147
 
149
148
 
150
149
  @cache
@@ -171,7 +170,7 @@ def facePointMESHIO(start: int, end: int, face: int, pos: int) -> np.ndarray:
171
170
  index = facePointMatrix(end-start-1, pos, orient=False)
172
171
  return np.array((start+index[0]+1 , start+index[1]+1 , end ), dtype=int)
173
172
  case _:
174
- sys.exit(1)
173
+ raise ValueError(f'Invalid face index: {face}.')
175
174
 
176
175
 
177
176
  @cache
@@ -25,13 +25,11 @@
25
25
  # ----------------------------------------------------------------------------------------------------------------------------------
26
26
  # Standard libraries
27
27
  # ----------------------------------------------------------------------------------------------------------------------------------
28
- import sys
29
28
  from collections import OrderedDict
30
29
  from typing import Final
31
30
  # ----------------------------------------------------------------------------------------------------------------------------------
32
31
  # Third-party libraries
33
32
  import h5py
34
- import heapq
35
33
  import numpy as np
36
34
  # ----------------------------------------------------------------------------------------------------------------------------------
37
35
  # ----------------------------------------------------------------------------------------------------------------------------------
@@ -197,8 +195,7 @@ def IO() -> None:
197
195
  mesh.write(fname, file_format='gmsh')
198
196
 
199
197
  case _: # Default
200
- hopout.warning('Unknown output format {}, exiting...'.format(io_vars.outputformat))
201
- sys.exit(1)
198
+ hopout.error('Unknown output format {}, exiting...'.format(io_vars.outputformat))
202
199
 
203
200
  # hopout.sep()
204
201
  # hopout.info('OUTPUT MESH DONE!')
@@ -215,6 +212,8 @@ def getMeshInfo() -> tuple[np.ndarray, # ElemInfo
215
212
  np.ndarray | None, # Optional[EdgeConnectInfo]
216
213
  dict[int, int]
217
214
  ]:
215
+ # Standard libraries -----------------------------------
216
+ import heapq
218
217
  # Local imports ----------------------------------------
219
218
  import pyhope.mesh.mesh_vars as mesh_vars
220
219
  from pyhope.mesh.fem.fem import getFEMInfo