PyHOPE 0.9.0__tar.gz → 0.10.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 (86) hide show
  1. {pyhope-0.9.0 → pyhope-0.10.0}/AUTHORS.md +1 -0
  2. {pyhope-0.9.0 → pyhope-0.10.0}/PKG-INFO +12 -5
  3. {pyhope-0.9.0 → pyhope-0.10.0}/README.md +9 -1
  4. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/__init__.py +59 -16
  5. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/basis/basis_basis.py +114 -58
  6. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/basis/basis_connect.py +6 -4
  7. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/basis/basis_jacobian.py +19 -10
  8. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/basis/basis_watertight.py +30 -15
  9. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/check/check.py +22 -3
  10. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/check/check_health.py +128 -44
  11. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/check/check_install.py +9 -2
  12. pyhope-0.10.0/pyhope/check/check_unittest.py +329 -0
  13. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/common/common.py +11 -4
  14. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/common/common_numba.py +1 -1
  15. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/common/common_parallel.py +4 -2
  16. pyhope-0.10.0/pyhope/common/common_template.py +91 -0
  17. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/common/common_tools.py +19 -0
  18. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/common/common_unique.py +0 -1
  19. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/common/common_vars.py +24 -10
  20. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/config/config.py +7 -1
  21. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/gmsh/gmsh_install.py +17 -8
  22. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/io/formats/meshio.py +21 -14
  23. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/io/formats/vtk.py +9 -2
  24. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/io/io.py +36 -60
  25. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/io/io_debug.py +7 -9
  26. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/io/io_gmsh.py +0 -2
  27. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/io/io_xdmf.py +1 -1
  28. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/mesh/connect/connect.py +65 -45
  29. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/mesh/connect/connect_mortar.py +168 -43
  30. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/mesh/connect/connect_rbtree.py +47 -48
  31. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/mesh/elements/elements_shapefunctions.py +8 -1
  32. pyhope-0.10.0/pyhope/mesh/extrude/mesh_extrude.py +490 -0
  33. pyhope-0.10.0/pyhope/mesh/extrude/templates/linear.py +65 -0
  34. pyhope-0.10.0/pyhope/mesh/fem/fem.py +508 -0
  35. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/mesh/mesh.py +34 -16
  36. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/mesh/mesh_builtin.py +27 -24
  37. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/mesh/mesh_common.py +185 -140
  38. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/mesh/mesh_duplicates.py +23 -16
  39. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/mesh/mesh_external.py +16 -10
  40. pyhope-0.10.0/pyhope/mesh/mesh_mortar.py +218 -0
  41. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/mesh/mesh_orient.py +12 -4
  42. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/mesh/mesh_sort.py +7 -4
  43. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/mesh/mesh_vars.py +21 -12
  44. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/mesh/reader/reader_gambit.py +1 -21
  45. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/mesh/reader/reader_gmsh.py +150 -35
  46. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/mesh/reader/reader_hopr.py +4 -23
  47. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/mesh/sort/sort_hilbert.py +4 -4
  48. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/mesh/topology/mesh_serendipity.py +4 -0
  49. pyhope-0.10.0/pyhope/mesh/topology/mesh_splittohex.py +654 -0
  50. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/mesh/topology/mesh_topology.py +113 -57
  51. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/mesh/transform/mesh_transform.py +47 -68
  52. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/mesh/transform/templates/convtest.py +8 -1
  53. pyhope-0.10.0/pyhope/mesh/transform/templates/cylinder.py +151 -0
  54. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/mesh/transform/templates/default.py +8 -2
  55. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/mesh/transform/templates/phill.py +17 -10
  56. pyhope-0.10.0/pyhope/mesh/transform/templates/sine.py +105 -0
  57. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/mesh/transform/templates/sphere.py +62 -22
  58. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/mesh/transform/templates/sphere_box.py +24 -16
  59. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/meshio/meshio_convert.py +13 -6
  60. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/meshio/meshio_ordering.py +15 -5
  61. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/output/output.py +4 -2
  62. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/readintools/commandline.py +7 -4
  63. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/readintools/readintools.py +26 -6
  64. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/script/pyhope_cli.py +12 -10
  65. {pyhope-0.9.0 → pyhope-0.10.0}/pyproject.toml +32 -13
  66. pyhope-0.9.0/pyhope/basis/__init__.py +0 -0
  67. pyhope-0.9.0/pyhope/check/__init__.py +0 -0
  68. pyhope-0.9.0/pyhope/common/__init__.py +0 -0
  69. pyhope-0.9.0/pyhope/config/__init__.py +0 -0
  70. pyhope-0.9.0/pyhope/io/__init__.py +0 -0
  71. pyhope-0.9.0/pyhope/mesh/__init__.py +0 -0
  72. pyhope-0.9.0/pyhope/mesh/fem/fem.py +0 -450
  73. pyhope-0.9.0/pyhope/mesh/topology/mesh_splittohex.py +0 -412
  74. pyhope-0.9.0/pyhope/mesh/transform/templates/cylinder.py +0 -115
  75. pyhope-0.9.0/pyhope/output/__init__.py +0 -0
  76. pyhope-0.9.0/pyhope/readintools/__init__.py +0 -0
  77. {pyhope-0.9.0 → pyhope-0.10.0}/LICENSE.md +0 -0
  78. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/__main__.py +0 -0
  79. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/common/common_progress.py +0 -0
  80. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/gmsh/gmsh_override.py +0 -0
  81. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/io/formats/cgns.py +0 -0
  82. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/io/formats/gmsh.py +1 -1
  83. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/io/io_vars.py +0 -0
  84. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/mesh/elements/elements_ordering.py +0 -0
  85. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/mesh/mesh_sides.py +0 -0
  86. {pyhope-0.9.0 → pyhope-0.10.0}/pyhope/meshio/meshio_nodes.py +0 -0
@@ -20,5 +20,6 @@ are listed in alphabetical order:
20
20
  * Stephen Copplestone
21
21
  * Patrick Kopper
22
22
  * Marius Kurz
23
+ * Leon Teichröb
23
24
  * Felix Rodach
24
25
  * Anna Schwarz
@@ -1,17 +1,16 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyHOPE
3
- Version: 0.9.0
3
+ Version: 0.10.0
4
4
  Summary: Python High-Order Preprocessing Environment
5
- License: GPL-3.0-only
5
+ License-Expression: GPL-3.0-only
6
6
  License-File: AUTHORS.md
7
7
  License-File: LICENSE.md
8
8
  Keywords: PyHOPE,mesh generator
9
9
  Author: Numerics Research Group (NRG)
10
10
  Author-email: numerics@iag.uni-stuttgart.de
11
11
  Requires-Python: >=3.10
12
- Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Development Status :: 4 - Beta
13
13
  Classifier: Operating System :: POSIX :: Linux
14
- Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
15
14
  Classifier: Programming Language :: Python :: 3
16
15
  Classifier: Programming Language :: Python :: 3.10
17
16
  Classifier: Programming Language :: Python :: 3.11
@@ -35,6 +34,12 @@ Project-URL: Homepage, https://numericsresearchgroup.org
35
34
  Project-URL: Repository, https://github.com/hopr-framework/pyhope
36
35
  Description-Content-Type: text/markdown
37
36
 
37
+ [![CI](https://github.com/hopr-framework/PyHOPE/actions/workflows/ci.yml/badge.svg)](https://github.com/hopr-framework/PyHOPE/actions/workflows/ci.yml)
38
+ [![Documentation](https://github.com/hopr-framework/PyHOPE/actions/workflows/github-pages.yml/badge.svg)](https://github.com/hopr-framework/PyHOPE/actions/workflows/github-pages.yml)
39
+ [![JOSS](https://joss.theoj.org/papers/39eb3be78f37c78588fe6dc443785024/status.svg)](https://joss.theoj.org/papers/39eb3be78f37c78588fe6dc443785024)
40
+ [![OpenSSF Best Practices](https://www.bestpractices.dev/projects/12060/badge)](https://www.bestpractices.dev/projects/12060)
41
+ [![OpenSSF Baseline](https://www.bestpractices.dev/projects/12060/baseline)](https://www.bestpractices.dev/projects/12060)
42
+
38
43
  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.
39
44
 
40
45
  PyHOPE has been developed by the Numerics Research Group (NRG) lead by Prof. Andrea Beck at the Institute of Aerodynamics and Gas Dynamics at the University of Stuttgart, Germany.
@@ -73,6 +78,7 @@ PyHOPE features internal health checks to verify that everything works as expect
73
78
  pyhope --verify [tutorials] # Run all health checks
74
79
  pyhope --verify-health # Run Python health checks
75
80
  pyhope --verify-install [tutorials] # Run PyHOPE mesh generation checks
81
+ pyhope --verify-unittest # Run PyHOPE unit tests
76
82
  ```
77
83
 
78
84
  > [!NOTE]
@@ -169,6 +175,7 @@ $ pyhope tutorials/1-01-cartbox/parameter.ini
169
175
  ├────
170
176
  │ doPeriodicCorrect │ False │ DEFAULT │
171
177
  │ doMortars │ True │ DEFAULT │
178
+ │ Processing Sides |█████████████████████████████████| 3072/3072 [100%] in 0.0s (24000.00/s)
172
179
  ├────
173
180
  │ Number of sides : 3072
174
181
  │ Number of inner sides : 2688
@@ -219,7 +226,7 @@ $ pyhope tutorials/1-01-cartbox/parameter.ini
219
226
  ```
220
227
 
221
228
  ## Python Library Usage
222
- 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](https://github.com/hopr-framework/PyHOPE/blob/main/pyhope/__init__.py).
229
+ 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 [PyHOPE documentation](https://hopr-framework.github.io/PyHOPE/user-guide/library_usage).
223
230
  ```python
224
231
  from pyhope import Basis, Mesh
225
232
  with Mesh('1-01-cartbox_mesh.h5') as m:
@@ -1,3 +1,9 @@
1
+ [![CI](https://github.com/hopr-framework/PyHOPE/actions/workflows/ci.yml/badge.svg)](https://github.com/hopr-framework/PyHOPE/actions/workflows/ci.yml)
2
+ [![Documentation](https://github.com/hopr-framework/PyHOPE/actions/workflows/github-pages.yml/badge.svg)](https://github.com/hopr-framework/PyHOPE/actions/workflows/github-pages.yml)
3
+ [![JOSS](https://joss.theoj.org/papers/39eb3be78f37c78588fe6dc443785024/status.svg)](https://joss.theoj.org/papers/39eb3be78f37c78588fe6dc443785024)
4
+ [![OpenSSF Best Practices](https://www.bestpractices.dev/projects/12060/badge)](https://www.bestpractices.dev/projects/12060)
5
+ [![OpenSSF Baseline](https://www.bestpractices.dev/projects/12060/baseline)](https://www.bestpractices.dev/projects/12060)
6
+
1
7
  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.
2
8
 
3
9
  PyHOPE has been developed by the Numerics Research Group (NRG) lead by Prof. Andrea Beck at the Institute of Aerodynamics and Gas Dynamics at the University of Stuttgart, Germany.
@@ -36,6 +42,7 @@ PyHOPE features internal health checks to verify that everything works as expect
36
42
  pyhope --verify [tutorials] # Run all health checks
37
43
  pyhope --verify-health # Run Python health checks
38
44
  pyhope --verify-install [tutorials] # Run PyHOPE mesh generation checks
45
+ pyhope --verify-unittest # Run PyHOPE unit tests
39
46
  ```
40
47
 
41
48
  > [!NOTE]
@@ -132,6 +139,7 @@ $ pyhope tutorials/1-01-cartbox/parameter.ini
132
139
  ├────
133
140
  │ doPeriodicCorrect │ False │ DEFAULT │
134
141
  │ doMortars │ True │ DEFAULT │
142
+ │ Processing Sides |█████████████████████████████████| 3072/3072 [100%] in 0.0s (24000.00/s)
135
143
  ├────
136
144
  │ Number of sides : 3072
137
145
  │ Number of inner sides : 2688
@@ -182,7 +190,7 @@ $ pyhope tutorials/1-01-cartbox/parameter.ini
182
190
  ```
183
191
 
184
192
  ## Python Library Usage
185
- 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](https://github.com/hopr-framework/PyHOPE/blob/main/pyhope/__init__.py).
193
+ 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 [PyHOPE documentation](https://hopr-framework.github.io/PyHOPE/user-guide/library_usage).
186
194
  ```python
187
195
  from pyhope import Basis, Mesh
188
196
  with Mesh('1-01-cartbox_mesh.h5') as m:
@@ -28,32 +28,72 @@
28
28
  # ----------------------------------------------------------------------------------------------------------------------------------
29
29
  from collections import namedtuple
30
30
  from contextlib import contextmanager
31
+ from functools import update_wrapper
32
+ from typing import final
31
33
  # ----------------------------------------------------------------------------------------------------------------------------------
32
34
  # Third-party libraries
33
35
  # ----------------------------------------------------------------------------------------------------------------------------------
34
36
  # ----------------------------------------------------------------------------------------------------------------------------------
35
37
  # Local imports
36
38
  # ----------------------------------------------------------------------------------------------------------------------------------
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
39
  # ==================================================================================================================================
43
40
 
44
41
 
42
+ def _staticwrapper(func):
43
+ """ Custom helper to lift the (annotations, doc, etc.) to the staticmethod
44
+ """
45
+ # Create a wrapper that carries the metadata
46
+ def wrapper(*args, **kwargs):
47
+ return func(*args, **kwargs)
48
+
49
+ # Lift metadata (annotations, doc, etc.) to the wrapper
50
+ update_wrapper(wrapper, func)
51
+
52
+ # Convert the metadata-rich wrapper into a staticmethod
53
+ return staticmethod(wrapper)
54
+
55
+
56
+ @final
45
57
  class Basis:
46
58
  """ Basis class to hold all basis related functions and variables
47
59
  """
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)
60
+ # Local imports ----------------------------------------
61
+ from pyhope.basis.basis_basis import legendre_gauss_nodes, legendre_gauss_lobatto_nodes
62
+ from pyhope.basis.basis_basis import barycentric_weights
63
+ from pyhope.basis.basis_basis import polynomial_derivative_matrix, polynomial_derivative_matrix_prism
64
+ from pyhope.basis.basis_basis import polynomial_derivative_matrix_pyram, polynomial_derivative_matrix_tetra
65
+ from pyhope.basis.basis_basis import lagrange_interpolation_polys, calc_vandermonde
66
+ from pyhope.basis.basis_basis import change_basis_3D, change_basis_2D, change_basis_1D
67
+ from pyhope.basis.basis_basis import equi_nodes_prism, equi_nodes_pyram, equi_nodes_tetra
68
+ from pyhope.basis.basis_basis import evaluate_jacobian, evaluate_jacobian_simplex
69
+ # ------------------------------------------------------
70
+ legendre_gauss_nodes = _staticwrapper(legendre_gauss_nodes)
71
+ legendre_gauss_lobatto_nodes = _staticwrapper(legendre_gauss_lobatto_nodes)
72
+ barycentric_weights = _staticwrapper(barycentric_weights)
73
+ polynomial_derivative_matrix = _staticwrapper(polynomial_derivative_matrix)
74
+ polynomial_derivative_matrix_prism = _staticwrapper(polynomial_derivative_matrix_prism)
75
+ polynomial_derivative_matrix_pyram = _staticwrapper(polynomial_derivative_matrix_pyram)
76
+ polynomial_derivative_matrix_tetra = _staticwrapper(polynomial_derivative_matrix_tetra)
77
+ lagrange_interpolation_polys = _staticwrapper(lagrange_interpolation_polys)
78
+ calc_vandermonde = _staticwrapper(calc_vandermonde)
79
+ change_basis_3D = _staticwrapper(change_basis_3D)
80
+ change_basis_2D = _staticwrapper(change_basis_2D)
81
+ change_basis_1D = _staticwrapper(change_basis_1D)
82
+ equi_nodes_prism = _staticwrapper(equi_nodes_prism)
83
+ equi_nodes_pyram = _staticwrapper(equi_nodes_pyram)
84
+ equi_nodes_tetra = _staticwrapper(equi_nodes_tetra)
85
+ evaluate_jacobian = _staticwrapper(evaluate_jacobian)
86
+ evaluate_jacobian_simplex = _staticwrapper(evaluate_jacobian_simplex)
87
+
88
+
89
+ @final
90
+ class Mapping:
91
+ """ Mapping class to hold all mapping related functions and variables
92
+ """
93
+ # Local imports ----------------------------------------
94
+ from pyhope.mesh.mesh_common import LINMAP
95
+ # ------------------------------------------------------
96
+ mesh_format_to_tensor_product = _staticwrapper(LINMAP)
57
97
 
58
98
 
59
99
  # Define a named tuple to hold the mesh data
@@ -61,12 +101,13 @@ MeshContainer = namedtuple('Mesh',
61
101
  ['mesh', # The generated mesh object
62
102
  'nGeo', # Polynomial order
63
103
  'bcs', # Boundary conditions
104
+ 'vvs', # Periodic vectors
64
105
  'elems', # Elements
65
106
  'sides' # Sides
66
107
  ])
67
108
 
68
109
 
69
- @contextmanager # pragma: no cover
110
+ @contextmanager
70
111
  def Mesh(*args: str, stdout: bool = False, stderr: bool = True):
71
112
  """ Mesh context manager to generate a mesh from a given file
72
113
 
@@ -139,10 +180,11 @@ def Mesh(*args: str, stdout: bool = False, stderr: bool = True):
139
180
  ConnectMesh()
140
181
 
141
182
  # Export mesh variables
142
- mesh = mesh_vars.mesh
183
+ mesh = mesh_vars.mesh
143
184
 
144
185
  nGeo = mesh_vars.nGeo
145
186
  bcs = mesh_vars.bcs
187
+ vvs = mesh_vars.vvs
146
188
 
147
189
  elems = mesh_vars.elems
148
190
  sides = mesh_vars.sides
@@ -150,6 +192,7 @@ def Mesh(*args: str, stdout: bool = False, stderr: bool = True):
150
192
  yield MeshContainer(mesh = mesh, # noqa: E251
151
193
  nGeo = nGeo, # noqa: E251
152
194
  bcs = bcs, # noqa: E251
195
+ vvs = vvs, # noqa: E251
153
196
  elems = elems, # noqa: E251
154
197
  sides = sides # noqa: E251
155
198
  )
@@ -25,8 +25,9 @@
25
25
  # ----------------------------------------------------------------------------------------------------------------------------------
26
26
  # Standard libraries
27
27
  # ----------------------------------------------------------------------------------------------------------------------------------
28
+ from __future__ import annotations
28
29
  from functools import cache
29
- from typing import Final, Union
30
+ from typing import Any, Final
30
31
  # ----------------------------------------------------------------------------------------------------------------------------------
31
32
  # Third-party libraries
32
33
  # ----------------------------------------------------------------------------------------------------------------------------------
@@ -34,31 +35,38 @@ import numpy as np
34
35
  import scipy as sp
35
36
  # from threadpoolctl import ThreadpoolController
36
37
  # ----------------------------------------------------------------------------------------------------------------------------------
37
- # Local imports
38
+ # Typing libraries
38
39
  # ----------------------------------------------------------------------------------------------------------------------------------
40
+ import typing
39
41
  from pyhope.common.common_numba import NUMBA_AVAILABLE
42
+ if typing.TYPE_CHECKING or NUMBA_AVAILABLE:
43
+ import numpy.typing as npt
44
+ # ----------------------------------------------------------------------------------------------------------------------------------
45
+ # Local imports
46
+ # ----------------------------------------------------------------------------------------------------------------------------------
40
47
  from pyhope.common.common_numba import jit, types
41
48
  from pyhope.mesh.mesh_common import NDOFS_ELEM
42
49
  # ==================================================================================================================================
43
50
 
44
51
 
45
- def legendre_gauss_lobatto_nodes(order: int) -> tuple[np.ndarray, np.ndarray]:
52
+ @jit(types.Tuple((types.float64[:], types.float64[:]))(types.int64), nopython=True, cache=True, nogil=True)
53
+ def legendre_gauss_lobatto_nodes(order: int) -> tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]:
46
54
  """ Return Legendre-Gauss-Lobatto nodes and weights for a given order in 1D
47
55
  """
48
56
  order -= 1
49
57
  # Special cases for small N
50
58
  if order == 1:
51
- return np.array((-1, 1)), np.array((1, 1))
59
+ return np.array((-1, 1), dtype=np.float64), np.array((1, 1), dtype=np.float64)
52
60
 
53
61
  # Compute the initial guess for the LGL nodes (roots of P'_N)
54
62
  nodes = np.cos(np.pi * np.arange(order+1) / order)
55
63
 
56
64
  # Initialize the Legendre polynomial and its derivative
57
- p = np.zeros((order+1, order+1))
65
+ p = np.zeros((order+1, order+1), dtype=np.float64)
58
66
 
59
67
  # Iteratively solve for the LGL nodes using Newton's method
60
68
  xOld = 2 * np.ones_like(nodes)
61
- tol = 1e-14
69
+ tol = 1e-14
62
70
  while np.max(np.abs(nodes - xOld)) > tol:
63
71
  xOld = nodes.copy()
64
72
  p[:, 0] = 1
@@ -76,7 +84,8 @@ def legendre_gauss_lobatto_nodes(order: int) -> tuple[np.ndarray, np.ndarray]:
76
84
  return nodes, weights
77
85
 
78
86
 
79
- def legendre_gauss_nodes(order: int) -> tuple[np.ndarray, np.ndarray]:
87
+ @cache
88
+ def legendre_gauss_nodes(order: int) -> tuple[npt.NDArray[np.float64], npt.NDArray[np.float64]]:
80
89
  """ Return Legendre-Gauss nodes and weights for a given order in 1D
81
90
  """
82
91
  nodes, weights = np.polynomial.legendre.leggauss(order)
@@ -84,7 +93,7 @@ def legendre_gauss_nodes(order: int) -> tuple[np.ndarray, np.ndarray]:
84
93
 
85
94
 
86
95
  @cache
87
- def equi_nodes_prism(order: int) -> np.ndarray:
96
+ def equi_nodes_prism(order: int) -> npt.NDArray[np.float64]:
88
97
  """ Return equidistant nodes on a wedge/prism
89
98
  """
90
99
  xEq = np.linspace(-1, 1, num=order, dtype=np.float64)
@@ -94,7 +103,7 @@ def equi_nodes_prism(order: int) -> np.ndarray:
94
103
 
95
104
 
96
105
  @cache
97
- def equi_nodes_pyram(order: int) -> np.ndarray:
106
+ def equi_nodes_pyram(order: int) -> npt.NDArray[np.float64]:
98
107
  """ Return equidistant nodes on a pyramid
99
108
  """
100
109
  xEq = np.linspace(-1, 1, num=order, dtype=np.float64)
@@ -104,7 +113,7 @@ def equi_nodes_pyram(order: int) -> np.ndarray:
104
113
 
105
114
 
106
115
  @cache
107
- def equi_nodes_tetra(order: int) -> np.ndarray:
116
+ def equi_nodes_tetra(order: int) -> npt.NDArray[np.float64]:
108
117
  """ Return equidistant nodes on a tetrahedron
109
118
  """
110
119
  xEq = np.linspace(-1, 1, num=order, dtype=np.float64)
@@ -113,26 +122,49 @@ def equi_nodes_tetra(order: int) -> np.ndarray:
113
122
  return np.vstack((xEq[iXI[mask]], xEq[iETA[mask]], xEq[iZETA[mask]]))
114
123
 
115
124
 
116
- def barycentric_weights(_: int, xGP: np.ndarray) -> np.ndarray:
117
- """ Compute the barycentric weights for a given node set
118
- > Algorithm 30, Kopriva
119
- """
120
- # Create a difference matrix (x_i - x_j) for all i, j
121
- diff_matrix = xGP[:, np.newaxis] - xGP[np.newaxis, :]
125
+ if not NUMBA_AVAILABLE:
126
+ def barycentric_weights(_: int, xGP: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]:
127
+ """ Compute the barycentric weights for a given node set
128
+ > Algorithm 30, Kopriva
129
+ """
130
+ # Create a difference matrix (x_i - x_j) for all i, j
131
+ diff_matrix = xGP[:, np.newaxis] - xGP[np.newaxis, :]
122
132
 
123
- # Set the diagonal to 1 to avoid division by zero (diagonal elements will not be used)
124
- np.fill_diagonal(diff_matrix, 1.0)
133
+ # Set the diagonal to 1 to avoid division by zero (diagonal elements will not be used)
134
+ np.fill_diagonal(diff_matrix, 1.0)
125
135
 
126
- # Compute the product of all differences for each row (excluding the diagonal)
127
- wBary = np.prod(diff_matrix, axis=1)
136
+ # Compute the product of all differences for each row (excluding the diagonal)
137
+ wBary = np.prod(diff_matrix, axis=1)
128
138
 
129
- # Take the reciprocal to get the final barycentric weights
130
- # wBary = 1.0 / wBary
139
+ # Take the reciprocal to get the final barycentric weights
140
+ # wBary = 1.0 / wBary
131
141
 
132
- return 1.0 / wBary
142
+ return 1.0 / wBary
143
+ else:
144
+ @jit(types.float64[:](types.int64, types.float64[:]), nopython=True, cache=True, nogil=True)
145
+ def barycentric_weights(_, xGP):
146
+ """ Compute the barycentric weights for a given node set
147
+ > Algorithm 30, Kopriva
148
+ """
149
+ n = xGP.shape[0]
150
+ w_bary = np.ones(n, dtype=np.float64)
151
+
152
+ # Create a difference matrix (x_i - x_j) for all i, j
153
+ for i in range(n):
154
+ # Set the diagonal to 1 to avoid division by zero (diagonal elements will not be used)
155
+ p = 1.0
156
+
157
+ # Compute the product of all differences for each row (excluding the diagonal)
158
+ for j in range(n):
159
+ if i != j:
160
+ p *= (xGP[i] - xGP[j])
161
+ w_bary[i] = p
133
162
 
163
+ # Take the reciprocal to get the final barycentric weights
164
+ return 1.0 / w_bary
134
165
 
135
- def polynomial_derivative_matrix(order: int, xGP: np.ndarray) -> np.ndarray:
166
+
167
+ def polynomial_derivative_matrix(order: int, xGP: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]:
136
168
  """ Compute the polynomial derivative matrix for a given node set
137
169
  > Algorithm 37, Kopriva
138
170
  """
@@ -148,12 +180,17 @@ def polynomial_derivative_matrix(order: int, xGP: np.ndarray) -> np.ndarray:
148
180
  return D
149
181
 
150
182
 
151
- def lagrange_interpolation_polys(x: Union[float, np.ndarray], order: int, xGP: np.ndarray, wBary: np.ndarray) -> np.ndarray:
183
+ @jit(types.float64[:](types.float64, types.int64, types.float64[:], types.float64[:]),
184
+ nopython=True, cache=True, nogil=True)
185
+ def lagrange_interpolation_polys(x: float,
186
+ order: int,
187
+ xGP: npt.NDArray[np.float64],
188
+ wBary: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]:
152
189
  """ Computes all Lagrange functions evaluated at position x in [-1;1]
153
190
  > Algorithm 34, Kopriva
154
191
  """
155
192
  # Equal points need special treatment
156
- lagrange = np.zeros(order)
193
+ lagrange = np.zeros(order, dtype=np.float64)
157
194
  for iGP in range(order):
158
195
  if abs(x - xGP[iGP]) < 1.E-14:
159
196
  lagrange[iGP] = 1
@@ -170,11 +207,17 @@ def lagrange_interpolation_polys(x: Union[float, np.ndarray], order: int, xGP: n
170
207
  return lagrange/tmp
171
208
 
172
209
 
173
- def calc_vandermonde(n_In: int, n_Out: int, wBary_In: np.ndarray, xi_In: np.ndarray, xi_Out: np.ndarray) -> np.ndarray:
210
+ @jit(types.float64[:, :](types.int64, types.int64, types.float64[:], types.float64[:], types.float64[:]),
211
+ nopython=True, cache=True, nogil=True)
212
+ def calc_vandermonde(n_In: int,
213
+ n_Out: int,
214
+ wBary_In: npt.NDArray[np.float64],
215
+ xi_In: npt.NDArray[np.float64],
216
+ xi_Out: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]:
174
217
  """ Build a 1D Vandermonde matrix using the Lagrange basis functions of degree N_In,
175
218
  evaluated at the interpolation points xi_Out
176
219
  """
177
- Vdm = np.zeros((n_Out, n_In))
220
+ Vdm = np.zeros((n_Out, n_In), dtype=np.float64)
178
221
  for iXI in range(n_Out):
179
222
  Vdm[iXI, :] = lagrange_interpolation_polys(xi_Out[iXI], n_In, xi_In, wBary_In)
180
223
  return Vdm
@@ -254,7 +297,7 @@ def calc_vandermonde(n_In: int, n_Out: int, wBary_In: np.ndarray, xi_In: np.ndar
254
297
  # return Vdm
255
298
 
256
299
 
257
- def polynomial_derivative_matrix_prism(order: int, xGP: np.ndarray) -> np.ndarray:
300
+ def polynomial_derivative_matrix_prism(order: int, xGP: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]:
258
301
  """ Compute the polynomial derivative matrix for a prism
259
302
  """
260
303
  a: Final[np.ndarray] = xGP[0, :]
@@ -262,19 +305,19 @@ def polynomial_derivative_matrix_prism(order: int, xGP: np.ndarray) -> np.ndarra
262
305
  c: Final[np.ndarray] = xGP[2, :]
263
306
 
264
307
  nDOFs = NDOFS_ELEM(106, order-1)
265
- Vdm = np.zeros(( nDOFs, nDOFs))
266
- Vr = np.zeros(( nDOFs, nDOFs))
267
- Vs = np.zeros(( nDOFs, nDOFs))
268
- Vt = np.zeros(( nDOFs, nDOFs))
269
- D = np.zeros((3, nDOFs, nDOFs))
308
+ Vdm = np.zeros(( nDOFs, nDOFs), dtype=np.float64)
309
+ Vr = np.zeros(( nDOFs, nDOFs), dtype=np.float64)
310
+ Vs = np.zeros(( nDOFs, nDOFs), dtype=np.float64)
311
+ Vt = np.zeros(( nDOFs, nDOFs), dtype=np.float64)
312
+ D = np.zeros((3, nDOFs, nDOFs), dtype=np.float64)
270
313
 
271
314
  # Precompute required Jacobi polynomials and derivatives
272
315
  # fZETA(i) = P_i^(0,0)(c), dfZETA(i) = 0.5*(i+1)*P_{i-1}^{(1,1)}(c)
273
- fZETA_all = np.array([ sp.special.eval_jacobi(i , 0, 0, c) for i in range(order)])
274
- dfZETA_all = np.array([0.5*(i+1)*sp.special.eval_jacobi(i-1, 1, 1, c) for i in range(order)])
275
- # fETA(j) = P_j^(0,0)(b), dfETA(j) = 0.5*(j+1)*P_{j-1}^{(1,1)}(b)
276
- fETA_all = np.array([ sp.special.eval_jacobi(j , 0, 0, b) for j in range(order)])
277
- dfETA_all = np.array([0.5*(j+1)*sp.special.eval_jacobi(j-1, 1, 1, b) for j in range(order)])
316
+ fZETA_all = np.array(tuple( sp.special.eval_jacobi(i , 0, 0, c) for i in range(order)))
317
+ dfZETA_all = np.array(tuple(0.5*(i+1)*sp.special.eval_jacobi(i-1, 1, 1, c) for i in range(order)))
318
+ # fETA(j) = P_j^(0,0)(tuple(), dfETA(j) = 0.5*(j+1)*P_{j-1}^{(1,1)}(b)
319
+ fETA_all = np.array(tuple( sp.special.eval_jacobi(j , 0, 0, b) for j in range(order)))
320
+ dfETA_all = np.array(tuple(0.5*(j+1)*sp.special.eval_jacobi(j-1, 1, 1, b) for j in range(order)))
278
321
 
279
322
  jacobi_xi_polys = [[sp.special.jacobi(i, 2*j + 1, 0) for i in range(order - j)] for j in range(order)]
280
323
  jacobi_xi_derivs = [[p.deriv() for p in row] for row in jacobi_xi_polys]
@@ -347,7 +390,7 @@ def polynomial_derivative_matrix_prism(order: int, xGP: np.ndarray) -> np.ndarra
347
390
  return D
348
391
 
349
392
 
350
- def polynomial_derivative_matrix_pyram(order: int, xGP: np.ndarray) -> np.ndarray:
393
+ def polynomial_derivative_matrix_pyram(order: int, xGP: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]:
351
394
  """ Compute the polynomial derivative matrix for a pyramid
352
395
  """
353
396
  a = np.where((1 - xGP[2, :]) <= 1.e-12, -1.0, 2 * (1 + xGP[0, :]) / (1. - xGP[2, :] + 1.e-20) - 1.)
@@ -355,11 +398,11 @@ def polynomial_derivative_matrix_pyram(order: int, xGP: np.ndarray) -> np.ndarra
355
398
  c = xGP[2, :]
356
399
 
357
400
  nDOFs = NDOFS_ELEM(105, order-1)
358
- Vdm = np.zeros(( nDOFs, nDOFs))
359
- Vr = np.zeros(( nDOFs, nDOFs))
360
- Vs = np.zeros(( nDOFs, nDOFs))
361
- Vt = np.zeros(( nDOFs, nDOFs))
362
- D = np.zeros((3, nDOFs, nDOFs))
401
+ Vdm = np.zeros(( nDOFs, nDOFs), dtype=np.float64)
402
+ Vr = np.zeros(( nDOFs, nDOFs), dtype=np.float64)
403
+ Vs = np.zeros(( nDOFs, nDOFs), dtype=np.float64)
404
+ Vt = np.zeros(( nDOFs, nDOFs), dtype=np.float64)
405
+ D = np.zeros((3, nDOFs, nDOFs), dtype=np.float64)
363
406
 
364
407
  iX = 0
365
408
  for iZETA in range(order):
@@ -421,7 +464,7 @@ def polynomial_derivative_matrix_pyram(order: int, xGP: np.ndarray) -> np.ndarra
421
464
  return D
422
465
 
423
466
 
424
- def polynomial_derivative_matrix_tetra(order: int, xGP: np.ndarray) -> np.ndarray:
467
+ def polynomial_derivative_matrix_tetra(order: int, xGP: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]:
425
468
  """ Compute the polynomial derivative matrix for a tetra
426
469
  """
427
470
  a = np.where(np.abs(xGP[1, :] + xGP[2, :]) <= 1.e-12, -1.0, 2 * (1 + xGP[0, :]) / (- xGP[1, :] - xGP[2, :] + 1.e-20) - 1.)
@@ -429,11 +472,11 @@ def polynomial_derivative_matrix_tetra(order: int, xGP: np.ndarray) -> np.ndarra
429
472
  c = xGP[2, :]
430
473
 
431
474
  nDOFs = NDOFS_ELEM(104, order-1)
432
- Vdm = np.zeros(( nDOFs, nDOFs))
433
- Vr = np.zeros(( nDOFs, nDOFs))
434
- Vs = np.zeros(( nDOFs, nDOFs))
435
- Vt = np.zeros(( nDOFs, nDOFs))
436
- D = np.zeros((3, nDOFs, nDOFs))
475
+ Vdm = np.zeros(( nDOFs, nDOFs), dtype=np.float64)
476
+ Vr = np.zeros(( nDOFs, nDOFs), dtype=np.float64)
477
+ Vs = np.zeros(( nDOFs, nDOFs), dtype=np.float64)
478
+ Vt = np.zeros(( nDOFs, nDOFs), dtype=np.float64)
479
+ D = np.zeros((3, nDOFs, nDOFs), dtype=np.float64)
437
480
 
438
481
  # Precompute constants
439
482
  sqrt2 = np.sqrt(2.)
@@ -504,7 +547,7 @@ def polynomial_derivative_matrix_tetra(order: int, xGP: np.ndarray) -> np.ndarra
504
547
 
505
548
 
506
549
  if not NUMBA_AVAILABLE:
507
- def change_basis_3D(Vdm: np.ndarray, x3D_In: np.ndarray) -> np.ndarray:
550
+ def change_basis_3D(Vdm: npt.NDArray[np.float64], x3D_In: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]:
508
551
  """ Interpolate a 3D tensor product Lagrange basis defined by (N_in+1) 1D interpolation point positions xi_In(0:N_In)
509
552
  to another 3D tensor product node positions (number of nodes N_out+1)
510
553
  defined by (N_out+1) interpolation point positions xi_Out(0:N_Out)
@@ -533,7 +576,7 @@ if not NUMBA_AVAILABLE:
533
576
 
534
577
  else:
535
578
  @jit((types.float64[:, :, :, ::1])(types.float64[:, ::1], types.float64[:, :, :, :]), nopython=True, cache=True, nogil=True)
536
- def change_basis_3D(Vdm: np.ndarray, x3D_In: np.ndarray) -> np.ndarray:
579
+ def change_basis_3D(Vdm: npt.NDArray[np.float64], x3D_In: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]:
537
580
  """ Interpolate a 3D tensor product Lagrange basis defined by (N_in+1) 1D interpolation point positions xi_In(0:N_In)
538
581
  to another 3D tensor product node positions (number of nodes N_out+1)
539
582
  defined by (N_out+1) interpolation point positions xi_Out(0:N_Out)
@@ -561,7 +604,7 @@ else:
561
604
 
562
605
 
563
606
  if not NUMBA_AVAILABLE:
564
- def change_basis_2D(Vdm: np.ndarray, x2D_In: np.ndarray) -> np.ndarray:
607
+ def change_basis_2D(Vdm: npt.NDArray[np.float64], x2D_In: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]:
565
608
  """ Interpolate a 2D tensor product Lagrange basis defined by (N_in+1) 1D interpolation point positions xi_In(0:N_In)
566
609
  to another 2D tensor product node positions (number of nodes N_out+1)
567
610
  defined by (N_out+1) interpolation point positions xi_Out(0:N_Out)
@@ -584,7 +627,7 @@ if not NUMBA_AVAILABLE:
584
627
 
585
628
  else:
586
629
  @jit((types.float64[:, :, ::1])(types.float64[:, ::1], types.float64[:, :, :]), nopython=True, cache=True, nogil=True)
587
- def change_basis_2D(Vdm: np.ndarray, x2D_In: np.ndarray) -> np.ndarray:
630
+ def change_basis_2D(Vdm: npt.NDArray[np.float64], x2D_In: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]:
588
631
  """ Interpolate a 2D tensor product Lagrange basis defined by (N_in+1) 1D interpolation point positions xi_In(0:N_In)
589
632
  to another 2D tensor product node positions (number of nodes N_out+1)
590
633
  defined by (N_out+1) interpolation point positions xi_Out(0:N_Out)
@@ -607,7 +650,18 @@ else:
607
650
  return x2D_Out.reshape(dim1, n_Out, n_Out)
608
651
 
609
652
 
610
- def evaluate_jacobian(xGeo_In: np.ndarray, VdmGLtoAP: np.ndarray, D_EqToGL: np.ndarray) -> np.ndarray:
653
+ def change_basis_1D(Vdm: npt.NDArray[np.float64], x1D_In: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]:
654
+ """ Interpolate a 1D tensor product Lagrange basis defined by (N_in+1) 1D interpolation point positions xi_In(0:N_In)
655
+ to another 1D tensor product node positions (number of nodes N_out+1)
656
+ defined by (N_out+1) interpolation point positions xi_Out(0:N_Out)
657
+ xi is defined in the 1D reference element xi=[-1,1]
658
+ """
659
+ return Vdm @ x1D_In
660
+
661
+
662
+ def evaluate_jacobian(xGeo_In: npt.NDArray[np.float64],
663
+ VdmGLtoAP: npt.NDArray[np.float64],
664
+ D_EqToGL: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]:
611
665
  """ Calculate the Jacobian of the mapping for a given element
612
666
  """
613
667
  dim1 = xGeo_In.shape[0]
@@ -622,7 +676,7 @@ def evaluate_jacobian(xGeo_In: np.ndarray, VdmGLtoAP: np.ndarray, D_EqToGL: np.n
622
676
 
623
677
  # Perform tensor contraction for the second derivative (Eta direction)
624
678
  dXdEtaGL = np.tensordot(D_EqToGL, xGeo_In, axes=(1, 2))
625
- dXdEtaGL = np.moveaxis(dXdEtaGL , 1, 0) # Correct the shape to (3, n_Out, n_In, n_In)
679
+ dXdEtaGL = np.transpose(dXdEtaGL, (1, 2, 0, 3))
626
680
  # PERF: This is actually slower than the individual contractions
627
681
  # dXdEtaGL = np.einsum('qj,dijk->dqik', D_EqToGL, xGeo_In, optimize=True)
628
682
 
@@ -656,7 +710,9 @@ def evaluate_jacobian(xGeo_In: np.ndarray, VdmGLtoAP: np.ndarray, D_EqToGL: np.n
656
710
  return np.einsum('ijkl,ijkl->jkl', dXdXiAP, cross_eta_zeta)
657
711
 
658
712
 
659
- def evaluate_jacobian_simplex(xGeo_In: np.ndarray, _: np.ndarray, D_EqToGL: np.ndarray) -> np.ndarray:
713
+ def evaluate_jacobian_simplex(xGeo_In: npt.NDArray[np.float64],
714
+ _: Any,
715
+ D_EqToGL: npt.NDArray[np.float64]) -> npt.NDArray[np.float64]:
660
716
  # Perform tensor contraction for each derivative
661
717
  # Change basis for each direction
662
718
  dXdXiAP = xGeo_In[:, :] @ D_EqToGL[0, :, :]
@@ -25,6 +25,7 @@
25
25
  # ----------------------------------------------------------------------------------------------------------------------------------
26
26
  # Standard libraries
27
27
  # ----------------------------------------------------------------------------------------------------------------------------------
28
+ from __future__ import annotations
28
29
  import re
29
30
  import sys
30
31
  from typing import Final, Optional, cast
@@ -167,14 +168,15 @@ def CheckConnect() -> None:
167
168
  if np_mtp > 0:
168
169
  # Run in parallel with a chunk size
169
170
  # > Dispatch the tasks to the workers, minimum 10 tasks per worker, maximum 1000 tasks per worker
170
- res = run_in_parallel(process_chunk,
171
- elems,
172
- chunk_size=max(1, min(1000, max(10, int(len(elems)/(40.*np_mtp))))),
171
+ res = run_in_parallel(process_chunk, # noqa: E251
172
+ elems, # noqa: E251
173
+ chunk_size = max(1, min(1000, max(10, int(len(elems)/(40.*np_mtp))))), # noqa: E251
174
+ ordering = False, # noqa: E251
173
175
  )
174
176
  else:
175
177
  res = [elem for elem in elems if check_sides(elem, failed_only=True)]
176
178
 
177
- if len(res) > 0:
179
+ if len(res) > 0: # pragma: no cover
178
180
  # Flatten per-element results (skip None placeholders)
179
181
  results = tuple(result for elem_results in res if isinstance(elem_results, Iterable) and elem_results is not None
180
182
  for result in elem_results) # noqa: E272