PyHOPE 0.0.9__tar.gz → 0.1.1__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 (71) hide show
  1. pyhope-0.1.1/AUTHORS.md +24 -0
  2. {pyhope-0.0.9 → pyhope-0.1.1}/PKG-INFO +55 -15
  3. {pyhope-0.0.9 → pyhope-0.1.1}/README.md +49 -11
  4. pyhope-0.1.1/pyhope/__init__.py +163 -0
  5. pyhope-0.1.1/pyhope/basis/basis_connect.py +190 -0
  6. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/basis/basis_jacobian.py +13 -8
  7. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/basis/basis_watertight.py +1 -5
  8. pyhope-0.1.1/pyhope/check/check.py +79 -0
  9. pyhope-0.1.1/pyhope/check/check_health.py +314 -0
  10. pyhope-0.1.1/pyhope/check/check_install.py +463 -0
  11. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/common/common.py +50 -40
  12. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/common/common_parallel.py +24 -9
  13. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/common/common_progress.py +16 -8
  14. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/common/common_tools.py +1 -1
  15. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/common/common_vars.py +40 -8
  16. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/gmsh/gmsh_install.py +8 -9
  17. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/io/formats/meshio.py +2 -3
  18. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/io/io.py +110 -77
  19. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/io/io_vars.py +3 -3
  20. pyhope-0.1.1/pyhope/io/io_xdmf.py +190 -0
  21. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/mesh/connect/connect.py +93 -63
  22. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/mesh/connect/connect_mortar.py +11 -16
  23. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/mesh/connect/connect_rbtree.py +9 -8
  24. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/mesh/fem/fem.py +8 -12
  25. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/mesh/mesh.py +6 -12
  26. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/mesh/mesh_builtin.py +29 -9
  27. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/mesh/mesh_common.py +168 -26
  28. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/mesh/mesh_duplicates.py +104 -67
  29. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/mesh/mesh_external.py +12 -10
  30. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/mesh/mesh_sides.py +26 -0
  31. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/mesh/mesh_sort.py +74 -58
  32. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/mesh/mesh_vars.py +2 -1
  33. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/mesh/reader/reader_gambit.py +111 -50
  34. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/mesh/reader/reader_gmsh.py +47 -40
  35. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/mesh/reader/reader_hopr.py +66 -144
  36. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/mesh/topology/mesh_splittohex.py +6 -13
  37. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/mesh/topology/mesh_topology.py +36 -45
  38. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/mesh/transform/mesh_transform.py +3 -9
  39. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/meshio/meshio_convert.py +1 -1
  40. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/meshio/meshio_ordering.py +1 -1
  41. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/output/output.py +91 -45
  42. pyhope-0.1.1/pyhope/readintools/__init__.py +0 -0
  43. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/readintools/commandline.py +32 -8
  44. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/readintools/readintools.py +71 -65
  45. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/script/pyhope_cli.py +16 -13
  46. pyhope-0.1.1/pyproject.toml +155 -0
  47. pyhope-0.0.9/pyproject.toml +0 -89
  48. {pyhope-0.0.9 → pyhope-0.1.1}/LICENSE.md +0 -0
  49. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/__main__.py +0 -0
  50. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/basis/__init__.py +0 -0
  51. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/basis/basis_basis.py +0 -0
  52. {pyhope-0.0.9/pyhope/common → pyhope-0.1.1/pyhope/check}/__init__.py +0 -0
  53. {pyhope-0.0.9/pyhope/config → pyhope-0.1.1/pyhope/common}/__init__.py +0 -0
  54. {pyhope-0.0.9/pyhope/io → pyhope-0.1.1/pyhope/config}/__init__.py +0 -0
  55. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/config/config.py +0 -0
  56. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/gmsh/gmsh_override.py +0 -0
  57. {pyhope-0.0.9/pyhope/mesh → pyhope-0.1.1/pyhope/io}/__init__.py +0 -0
  58. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/io/formats/cgns.py +0 -0
  59. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/io/formats/gmsh.py +0 -0
  60. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/io/formats/vtk.py +0 -0
  61. {pyhope-0.0.9/pyhope/output → pyhope-0.1.1/pyhope/mesh}/__init__.py +0 -0
  62. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/mesh/elements/elements_ordering.py +0 -0
  63. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/mesh/elements/elements_shapefunctions.py +0 -0
  64. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/mesh/mesh_orient.py +0 -0
  65. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/mesh/topology/mesh_serendipity.py +0 -0
  66. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/mesh/transform/templates/convtest.py +0 -0
  67. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/mesh/transform/templates/cylinder.py +0 -0
  68. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/mesh/transform/templates/default.py +0 -0
  69. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/mesh/transform/templates/phill.py +0 -0
  70. {pyhope-0.0.9 → pyhope-0.1.1}/pyhope/mesh/transform/templates/sphere.py +0 -0
  71. {pyhope-0.0.9/pyhope/readintools → pyhope-0.1.1/pyhope/output}/__init__.py +0 -0
@@ -0,0 +1,24 @@
1
+ <div class="no-extra-css"></div>
2
+ # Authors
3
+
4
+ PyHOPE's development is coordinated by the Numerics Research Group (NRG) at
5
+ University of Stuttgart. The primary contact is Patrick Kopper, who is the *principal developer*
6
+ and main contributor. In addition, there are *contributors* who have
7
+ provided substantial additions or modifications. Together, these two groups form
8
+ authors as mentioned in the [LICENSE.md](LICENSE.md) file.
9
+
10
+ ## Principal Developers
11
+ * [Patrick Kopper](https://www.iag.uni-stuttgart.de/en/institute/team/Kopper-00001/),
12
+ University of Stuttgart, Germany
13
+
14
+ ## Contributors
15
+ The following people contributed major additions or modifications to PyHOPE and
16
+ are listed in alphabetical order:
17
+
18
+ * Daniel Appel
19
+ * Marcel Blind
20
+ * Stephen Copplestone
21
+ * Patrick Kopper
22
+ * Marius Kurz
23
+ * Felix Rodach
24
+ * Anna Schwarz
@@ -1,8 +1,10 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: PyHOPE
3
- Version: 0.0.9
3
+ Version: 0.1.1
4
4
  Summary: Python High-Order Preprocessing Environment
5
5
  License: GPL-3.0-only
6
+ License-File: AUTHORS.md
7
+ License-File: LICENSE.md
6
8
  Keywords: PyHOPE,mesh generator
7
9
  Author: Numerics Research Group (NRG)
8
10
  Author-email: numerics@iag.uni-stuttgart.de
@@ -24,10 +26,10 @@ Requires-Dist: numpy (>=2.0.0)
24
26
  Requires-Dist: packaging
25
27
  Requires-Dist: plotext
26
28
  Requires-Dist: scipy
27
- Requires-Dist: sortedcontainers
28
29
  Requires-Dist: typing-extensions
30
+ Project-URL: Documentation, https://hopr-framework.github.io/PyHOPE
29
31
  Project-URL: Homepage, https://numericsresearchgroup.org
30
- Project-URL: Repository, https://gitlab.iag.uni-stuttgart.de/flexi/codes/pyhope
32
+ Project-URL: Repository, https://github.com/hopr-framework/pyhope
31
33
  Description-Content-Type: text/markdown
32
34
 
33
35
  PyHOPE (Python High-Order Preprocessing Environment) is an open-source Python framework for the generation of three-dimensional unstructured high-order meshes. These meshes are needed by high-order numerical methods like Discontinuous Galerkin, Spectral Element Methods, or pFEM, in order to retain their accuracy if the computational domain includes curved boundaries.
@@ -49,22 +51,44 @@ PyHOPE is built using standard Python packages. You can install PyHOPE by follow
49
51
  ```
50
52
  If you choose not to use a virtual environment, skip this step and proceed directly to the installation of PyHOPE.
51
53
 
54
+ > [!IMPORTANT]
55
+ > For new shell sessions, the virtual environment must be re-sourced using `source venv/bin/activate` before using `pyhope` commands.
56
+
52
57
  2. **Install PyHOPE**
53
58
  PyHOPE is installed using `pip`, the Python package installer. This command fetches the PyHOPE package and its dependencies from PyPI (Python Package Index) and installs them.
54
59
  ```bash
55
60
  python -m pip install pyhope
56
61
  ```
57
62
 
58
- 3. **Run PyHOPE**
59
- PyHOPE is available as a command-line tool. After installation, its functionalities can be accessed directly from the terminal.
60
- ```bash
61
- pyhope --help
62
- ```
63
+ # Testing
64
+ PyHOPE features internal health checks to verify that everything works as expected. The checks can be invoked directly from the terminal.
65
+ ```bash
66
+ pyhope --verify [tutorials] # Run all health checks
67
+ pyhope --verify-health # Run Python health checks
68
+ pyhope --verify-install [tutorials] # Run PyHOPE mesh generation checks
69
+ ```
63
70
 
64
- > 🛈 Remark: For new shell sessions, the virtual environment must be re-sourced using `source venv/bin/activate` before using `pyhope` commands.
71
+ > [!NOTE]
72
+ > By default, PyHOPE looks for the `tutorials` directory relative to the current working directory or the git root. If neither exists, PyHOPE downloads the tests from GitHub while using available authentication methods.
73
+
74
+ # Getting Help
75
+ PyHOPE help output is formatted to serve as self-hosting INI format. A list of all options and the default values can be accessed by running the following command.
76
+ ```bash
77
+ pyhope --help
78
+ ```
79
+
80
+ # Documentation
81
+ PyHOPE is heavily inspired by [HOPR (High Order Preprocessor)](https://github.com/hopr-framework/hopr) and shares the same input/output format. For more information and tutorials, please visit the [HOPR documentation](https://hopr.readthedocs.io).
65
82
 
66
83
  # Usage
67
- PyHOPE is invoked from the command line. Run parameters are read from a configuration file. The following output is obtained when running the example configuration file `tutorials/1-01-cartbox/parameter.ini`.
84
+ PyHOPE can either be invoked directly from the command line or used as a Python library.
85
+
86
+ ## Command Line Usage
87
+ PyHOPE can be invoked from the command line. After installation, its functionalities can be accessed directly from the terminal by passing a valid configuration file.
88
+ ```bash
89
+ pyhope [parameter.ini]
90
+ ```
91
+ The following output is obtained when running the example configuration file `tutorials/1-01-cartbox/parameter.ini`.
68
92
  ```
69
93
  $ pyhope tutorials/1-01-cartbox/parameter.ini
70
94
  ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
@@ -81,7 +105,7 @@ $ pyhope tutorials/1-01-cartbox/parameter.ini
81
105
  ├─────────────────────────────────────────────
82
106
  │ INIT MESH...
83
107
  │ Mode │ 1 [Internal] │ *CUSTOM │
84
- │ NGeo │ 4 │ *CUSTOM │
108
+ │ NGeo │ 9 │ *CUSTOM │
85
109
  ├─────────────────────────────────────────────
86
110
  │ GENERATE MESH...
87
111
  ├────
@@ -89,6 +113,7 @@ $ pyhope tutorials/1-01-cartbox/parameter.ini
89
113
  ├── Generating zone 1
90
114
  │ Corner │ (/0.,0.,0. ,,1.,0.,0. ,,1.,1... │ *CUSTOM │
91
115
  │ nElems │ (/8,8,8/) │ *CUSTOM │
116
+ │ ElemType │ 108 [hexahedron] │ *CUSTOM │
92
117
  │ StretchType │ (/0,0,0/) │ DEFAULT │
93
118
  │ BCIndex │ (/1,2,3,4,5,6/) │ *CUSTOM │
94
119
  ├────
@@ -111,8 +136,6 @@ $ pyhope tutorials/1-01-cartbox/parameter.ini
111
136
  │ vv │ (/0., 1., 0./) │ *CUSTOM │
112
137
  │ vv │ (/0., 0., 1./) │ *CUSTOM │
113
138
  ├────
114
- │ ElemType │ 108 [hexahedron] │ *CUSTOM │
115
- ├────
116
139
  ├── Generated mesh with 512 cells
117
140
  ├─────────────────────────────────────────────
118
141
  ├── BUILD DATA STRUCTURE...
@@ -133,7 +156,7 @@ $ pyhope tutorials/1-01-cartbox/parameter.ini
133
156
  ├─────────────────────────────────────────────
134
157
  │ CONNECT MESH...
135
158
  ├────
136
- │ doPeriodicCorrect │ True │ DEFAULT │
159
+ │ doPeriodicCorrect │ False │ DEFAULT │
137
160
  │ doMortars │ True │ DEFAULT │
138
161
  ├────
139
162
  │ Number of sides : 3072
@@ -143,6 +166,11 @@ $ pyhope tutorials/1-01-cartbox/parameter.ini
143
166
  │ Number of boundary sides : 384
144
167
  │ Number of periodic sides : 0
145
168
  ├─────────────────────────────────────────────
169
+ │ CHECK CONNECTIVITY...
170
+ ├────
171
+ │ CheckConnectivity │ True │ DEFAULT │
172
+ │ Processing Elements |█████████████████████████████████| 512/512 [100%] in 0.0s (24000.00/s)
173
+ ├─────────────────────────────────────────────
146
174
  │ CHECK WATERTIGHTNESS...
147
175
  ├────
148
176
  │ CheckWatertightness │ True │ DEFAULT │
@@ -178,3 +206,15 @@ $ pyhope tutorials/1-01-cartbox/parameter.ini
178
206
  ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
179
207
  ```
180
208
 
209
+ ## Python Library Usage
210
+ PyHOPE can be included in other Python libraries. PyHOPE exposes its functionally via runtime contexts defined by [Context Managers](https://docs.python.org/3/library/stdtypes.html#typecontextmanager). The following Python code loads a HOPR HDF5 mesh and derived quantities. For a complete list of currently implemented functions, see the [source code](pyhope/__init__.py).
211
+ ```python
212
+ from pyhope import Basis, Mesh
213
+ with Mesh('1-01-cartbox_mesh.h5') as m:
214
+ elems = m.elems
215
+ lobatto_nodes = Basis.legendre_gauss_lobatto_nodes(order=m.nGeo)
216
+ ```
217
+
218
+ # Licence
219
+ PyHOPE is licensed under the GPL-3.0 license (see [LICENSE.md](LICENSE.md)).
220
+
@@ -17,22 +17,44 @@ PyHOPE is built using standard Python packages. You can install PyHOPE by follow
17
17
  ```
18
18
  If you choose not to use a virtual environment, skip this step and proceed directly to the installation of PyHOPE.
19
19
 
20
+ > [!IMPORTANT]
21
+ > For new shell sessions, the virtual environment must be re-sourced using `source venv/bin/activate` before using `pyhope` commands.
22
+
20
23
  2. **Install PyHOPE**
21
24
  PyHOPE is installed using `pip`, the Python package installer. This command fetches the PyHOPE package and its dependencies from PyPI (Python Package Index) and installs them.
22
25
  ```bash
23
26
  python -m pip install pyhope
24
27
  ```
25
28
 
26
- 3. **Run PyHOPE**
27
- PyHOPE is available as a command-line tool. After installation, its functionalities can be accessed directly from the terminal.
28
- ```bash
29
- pyhope --help
30
- ```
29
+ # Testing
30
+ PyHOPE features internal health checks to verify that everything works as expected. The checks can be invoked directly from the terminal.
31
+ ```bash
32
+ pyhope --verify [tutorials] # Run all health checks
33
+ pyhope --verify-health # Run Python health checks
34
+ pyhope --verify-install [tutorials] # Run PyHOPE mesh generation checks
35
+ ```
31
36
 
32
- > 🛈 Remark: For new shell sessions, the virtual environment must be re-sourced using `source venv/bin/activate` before using `pyhope` commands.
37
+ > [!NOTE]
38
+ > By default, PyHOPE looks for the `tutorials` directory relative to the current working directory or the git root. If neither exists, PyHOPE downloads the tests from GitHub while using available authentication methods.
39
+
40
+ # Getting Help
41
+ PyHOPE help output is formatted to serve as self-hosting INI format. A list of all options and the default values can be accessed by running the following command.
42
+ ```bash
43
+ pyhope --help
44
+ ```
45
+
46
+ # Documentation
47
+ PyHOPE is heavily inspired by [HOPR (High Order Preprocessor)](https://github.com/hopr-framework/hopr) and shares the same input/output format. For more information and tutorials, please visit the [HOPR documentation](https://hopr.readthedocs.io).
33
48
 
34
49
  # Usage
35
- PyHOPE is invoked from the command line. Run parameters are read from a configuration file. The following output is obtained when running the example configuration file `tutorials/1-01-cartbox/parameter.ini`.
50
+ PyHOPE can either be invoked directly from the command line or used as a Python library.
51
+
52
+ ## Command Line Usage
53
+ PyHOPE can be invoked from the command line. After installation, its functionalities can be accessed directly from the terminal by passing a valid configuration file.
54
+ ```bash
55
+ pyhope [parameter.ini]
56
+ ```
57
+ The following output is obtained when running the example configuration file `tutorials/1-01-cartbox/parameter.ini`.
36
58
  ```
37
59
  $ pyhope tutorials/1-01-cartbox/parameter.ini
38
60
  ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
@@ -49,7 +71,7 @@ $ pyhope tutorials/1-01-cartbox/parameter.ini
49
71
  ├─────────────────────────────────────────────
50
72
  │ INIT MESH...
51
73
  │ Mode │ 1 [Internal] │ *CUSTOM │
52
- │ NGeo │ 4 │ *CUSTOM │
74
+ │ NGeo │ 9 │ *CUSTOM │
53
75
  ├─────────────────────────────────────────────
54
76
  │ GENERATE MESH...
55
77
  ├────
@@ -57,6 +79,7 @@ $ pyhope tutorials/1-01-cartbox/parameter.ini
57
79
  ├── Generating zone 1
58
80
  │ Corner │ (/0.,0.,0. ,,1.,0.,0. ,,1.,1... │ *CUSTOM │
59
81
  │ nElems │ (/8,8,8/) │ *CUSTOM │
82
+ │ ElemType │ 108 [hexahedron] │ *CUSTOM │
60
83
  │ StretchType │ (/0,0,0/) │ DEFAULT │
61
84
  │ BCIndex │ (/1,2,3,4,5,6/) │ *CUSTOM │
62
85
  ├────
@@ -79,8 +102,6 @@ $ pyhope tutorials/1-01-cartbox/parameter.ini
79
102
  │ vv │ (/0., 1., 0./) │ *CUSTOM │
80
103
  │ vv │ (/0., 0., 1./) │ *CUSTOM │
81
104
  ├────
82
- │ ElemType │ 108 [hexahedron] │ *CUSTOM │
83
- ├────
84
105
  ├── Generated mesh with 512 cells
85
106
  ├─────────────────────────────────────────────
86
107
  ├── BUILD DATA STRUCTURE...
@@ -101,7 +122,7 @@ $ pyhope tutorials/1-01-cartbox/parameter.ini
101
122
  ├─────────────────────────────────────────────
102
123
  │ CONNECT MESH...
103
124
  ├────
104
- │ doPeriodicCorrect │ True │ DEFAULT │
125
+ │ doPeriodicCorrect │ False │ DEFAULT │
105
126
  │ doMortars │ True │ DEFAULT │
106
127
  ├────
107
128
  │ Number of sides : 3072
@@ -111,6 +132,11 @@ $ pyhope tutorials/1-01-cartbox/parameter.ini
111
132
  │ Number of boundary sides : 384
112
133
  │ Number of periodic sides : 0
113
134
  ├─────────────────────────────────────────────
135
+ │ CHECK CONNECTIVITY...
136
+ ├────
137
+ │ CheckConnectivity │ True │ DEFAULT │
138
+ │ Processing Elements |█████████████████████████████████| 512/512 [100%] in 0.0s (24000.00/s)
139
+ ├─────────────────────────────────────────────
114
140
  │ CHECK WATERTIGHTNESS...
115
141
  ├────
116
142
  │ CheckWatertightness │ True │ DEFAULT │
@@ -145,3 +171,15 @@ $ pyhope tutorials/1-01-cartbox/parameter.ini
145
171
  ┃ PyHOPE completed in [0.25 sec]
146
172
  ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
147
173
  ```
174
+
175
+ ## Python Library Usage
176
+ PyHOPE can be included in other Python libraries. PyHOPE exposes its functionally via runtime contexts defined by [Context Managers](https://docs.python.org/3/library/stdtypes.html#typecontextmanager). The following Python code loads a HOPR HDF5 mesh and derived quantities. For a complete list of currently implemented functions, see the [source code](pyhope/__init__.py).
177
+ ```python
178
+ from pyhope import Basis, Mesh
179
+ with Mesh('1-01-cartbox_mesh.h5') as m:
180
+ elems = m.elems
181
+ lobatto_nodes = Basis.legendre_gauss_lobatto_nodes(order=m.nGeo)
182
+ ```
183
+
184
+ # Licence
185
+ PyHOPE is licensed under the GPL-3.0 license (see [LICENSE.md](LICENSE.md)).
@@ -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 # pragma: no cover
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)
@@ -142,8 +142,18 @@ def CheckJacobians() -> None:
142
142
  # Prepare elements for parallel processing
143
143
  tasks = []
144
144
 
145
- # Cache the mapping
146
- linCache = {}
145
+ # Pre-compute LINTEN mappings for all element types
146
+ linCache = {}
147
+ elemOrder = 100 if mesh_vars.nGeo == 1 else 200
148
+ elemTypes = tuple([s + elemOrder for s in (4, 5, 6, 8)])
149
+ for elemType in elemTypes:
150
+ try:
151
+ _, mapLin = LINTEN(elemType, order=mesh_vars.nGeo)
152
+ mapLin = np.array(tuple(mapLin[np.int64(i)] for i in range(len(mapLin))))
153
+ linCache[elemType] = mapLin
154
+ # Only hexahedrons supported for specific nGeo
155
+ except ValueError:
156
+ pass
147
157
 
148
158
  for elem in elems:
149
159
  elemType = elem.type
@@ -153,12 +163,7 @@ def CheckJacobians() -> None:
153
163
  continue
154
164
 
155
165
  # Get the mapping
156
- if elemType in linCache:
157
- mapLin = linCache[elemType]
158
- else:
159
- _, mapLin = LINTEN(elemType, order=mesh_vars.nGeo)
160
- mapLin = np.array(tuple(mapLin[np.int64(i)] for i in range(len(mapLin))))
161
- linCache[elemType] = mapLin
166
+ mapLin = linCache[elemType]
162
167
 
163
168
  # Fill the NodeCoords
164
169
  nodeCoords = np.empty((nGeo ** 3, 3), dtype=np.float64)