simnexus 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.
- simnexus-0.1.0/LICENSE.md +22 -0
- simnexus-0.1.0/PKG-INFO +112 -0
- simnexus-0.1.0/README.md +72 -0
- simnexus-0.1.0/pyproject.toml +35 -0
- simnexus-0.1.0/setup.cfg +4 -0
- simnexus-0.1.0/simnexus/VTK/read_vtk.py +329 -0
- simnexus-0.1.0/simnexus/__init__.py +5 -0
- simnexus-0.1.0/simnexus/actions.py +250 -0
- simnexus-0.1.0/simnexus/args.py +56 -0
- simnexus-0.1.0/simnexus/d3plot_actions.py +317 -0
- simnexus-0.1.0/simnexus/dyna_actions.py +149 -0
- simnexus-0.1.0/simnexus/graph_actions.py +656 -0
- simnexus-0.1.0/simnexus/jinja_actions.py +207 -0
- simnexus-0.1.0/simnexus/openfoam_actions.py +211 -0
- simnexus-0.1.0/simnexus/protos/__init__.py +0 -0
- simnexus-0.1.0/simnexus/protos/remote_actions_pb2.py +48 -0
- simnexus-0.1.0/simnexus/protos/remote_actions_pb2_grpc.py +140 -0
- simnexus-0.1.0/simnexus/radioss_actions.py +465 -0
- simnexus-0.1.0/simnexus/rare.py +51 -0
- simnexus-0.1.0/simnexus/remote_actions.py +250 -0
- simnexus-0.1.0/simnexus/util/observer.py +34 -0
- simnexus-0.1.0/simnexus/util/openfoam_reader.py +1768 -0
- simnexus-0.1.0/simnexus/util/openradios_reader.py +258 -0
- simnexus-0.1.0/simnexus/variables.py +129 -0
- simnexus-0.1.0/simnexus.egg-info/PKG-INFO +112 -0
- simnexus-0.1.0/simnexus.egg-info/SOURCES.txt +36 -0
- simnexus-0.1.0/simnexus.egg-info/dependency_links.txt +1 -0
- simnexus-0.1.0/simnexus.egg-info/requires.txt +3 -0
- simnexus-0.1.0/simnexus.egg-info/top_level.txt +1 -0
- simnexus-0.1.0/tests/test_core.py +4 -0
- simnexus-0.1.0/tests/test_dyna.py +41 -0
- simnexus-0.1.0/tests/test_graph.py +218 -0
- simnexus-0.1.0/tests/test_openfoam_job.py +118 -0
- simnexus-0.1.0/tests/test_openradios_reader.py +417 -0
- simnexus-0.1.0/tests/test_remote_patterns.py +66 -0
- simnexus-0.1.0/tests/test_simulation_iterator.py +64 -0
- simnexus-0.1.0/tests/test_solve.py +184 -0
- simnexus-0.1.0/tests/test_vars.py +69 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
|
|
2
|
+
MIT License
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2026 Willem Roux
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
SOFTWARE.
|
simnexus-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: simnexus
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A Python module for modelling complex simulation workflows.
|
|
5
|
+
Author-email: Willem <willem4540@gmail.com>
|
|
6
|
+
License:
|
|
7
|
+
MIT License
|
|
8
|
+
|
|
9
|
+
Copyright (c) 2026 Willem Roux
|
|
10
|
+
|
|
11
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
12
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
13
|
+
in the Software without restriction, including without limitation the rights
|
|
14
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
15
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
16
|
+
furnished to do so, subject to the following conditions:
|
|
17
|
+
|
|
18
|
+
The above copyright notice and this permission notice shall be included in all
|
|
19
|
+
copies or substantial portions of the Software.
|
|
20
|
+
|
|
21
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
22
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
23
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
24
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
25
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
26
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
27
|
+
SOFTWARE.
|
|
28
|
+
|
|
29
|
+
Project-URL: Homepage, https://github.com/WillemJR/simnexus
|
|
30
|
+
Classifier: Development Status :: 3 - Alpha
|
|
31
|
+
Classifier: Programming Language :: Python :: 3
|
|
32
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
33
|
+
Classifier: Operating System :: OS Independent
|
|
34
|
+
Requires-Python: >=3.7
|
|
35
|
+
Description-Content-Type: text/markdown
|
|
36
|
+
License-File: LICENSE.md
|
|
37
|
+
Provides-Extra: dev
|
|
38
|
+
Requires-Dist: pytest; extra == "dev"
|
|
39
|
+
Dynamic: license-file
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
# SimNexus
|
|
43
|
+
|
|
44
|
+
A Python module for orchestrating complex simulations
|
|
45
|
+
with native support for LS-DYNA, OpenRadioss, and OpenFOAM.
|
|
46
|
+
|
|
47
|
+
## Overview
|
|
48
|
+
|
|
49
|
+
SimNexus enables the automation and coordination of
|
|
50
|
+
multi-physics simulation workflows.
|
|
51
|
+
The module is particularly suited for simulations that span multiple domains, such as combined structural and fluid dynamics analyses.
|
|
52
|
+
|
|
53
|
+
It supports tasks from from input preparation and
|
|
54
|
+
remote execution to results extraction and post-processing.
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
SimNexus has a native support for
|
|
58
|
+
solvers like LS-DYNA, OpenRadioss, and OpenFOAM.
|
|
59
|
+
|
|
60
|
+
## Key Features
|
|
61
|
+
|
|
62
|
+
- **Workflow Management**: Define simulation workflows as directed acyclic graphs (DAGs) where actions are executed based on dependency relationships and completion status of prerequisite tasks
|
|
63
|
+
- **Native Solver Support**: Specify input parameter values and the results to extract for a supported solver. Currently implemented are LS-DYNA and OpenRadioss for structural analysis, and OpenFOAM for computational fluid dynamics
|
|
64
|
+
- **Remote Execution**: Submit computational subgraphs to remote computing resources while maintaining local workflow coordination
|
|
65
|
+
- **Dependency Resolution**: Automatically manages execution order based on inter-action dependencies, ensuring downstream actions wait for required upstream results
|
|
66
|
+
- **Discoverability**: Query any graph for its inputs (`variables()`) and outputs (`outputs()`) without running it — solver actions read their parameterised input files to report variable names, types, and default values
|
|
67
|
+
- **Scalability using ML**: Designed to scale through integration with the Gemini CLI for the extension and use of the module.
|
|
68
|
+
|
|
69
|
+
## Typical Workflow
|
|
70
|
+
|
|
71
|
+
1. Configure input files for target solvers
|
|
72
|
+
2. Define analysis actions and their dependencies
|
|
73
|
+
3. Execute simulations on designated compute resources (local or remote)
|
|
74
|
+
4. Extract relevant results from solver outputs
|
|
75
|
+
5. Aggregate and summarize findings
|
|
76
|
+
|
|
77
|
+
SimNexus streamlines the complexity of managing heterogeneous simulation environments, enabling researchers and engineers to focus on analysis rather than workflow orchestration.
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
## Documentation
|
|
81
|
+
(Path to be added. One provided is not yet active)
|
|
82
|
+
|
|
83
|
+
[Online documentation is available here](https://willemjr.github.io/simnexus/)
|
|
84
|
+
|
|
85
|
+
See also the docs directory.
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
## Installation
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
pip install simnexus
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Usage
|
|
95
|
+
See the documentation and the examples directory for examples.
|
|
96
|
+
|
|
97
|
+
(Coming soon)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
# Example problems
|
|
102
|
+
The example problems demonstrate:
|
|
103
|
+
|
|
104
|
+
- An LS-DYNA workflow consisting of editing parameter values, job submission, and results extraction.
|
|
105
|
+
- An OpenRadioss workflow consisting of editing parameter values, job submission, and results extraction.
|
|
106
|
+
- An OpenFOAM. workflow consisting of editing parameter values, job submission, and results extraction.
|
|
107
|
+
- Remote execution examples.
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
## License
|
|
111
|
+
This project is licensed under the MIT License.
|
|
112
|
+
|
simnexus-0.1.0/README.md
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
|
|
2
|
+
# SimNexus
|
|
3
|
+
|
|
4
|
+
A Python module for orchestrating complex simulations
|
|
5
|
+
with native support for LS-DYNA, OpenRadioss, and OpenFOAM.
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
SimNexus enables the automation and coordination of
|
|
10
|
+
multi-physics simulation workflows.
|
|
11
|
+
The module is particularly suited for simulations that span multiple domains, such as combined structural and fluid dynamics analyses.
|
|
12
|
+
|
|
13
|
+
It supports tasks from from input preparation and
|
|
14
|
+
remote execution to results extraction and post-processing.
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
SimNexus has a native support for
|
|
18
|
+
solvers like LS-DYNA, OpenRadioss, and OpenFOAM.
|
|
19
|
+
|
|
20
|
+
## Key Features
|
|
21
|
+
|
|
22
|
+
- **Workflow Management**: Define simulation workflows as directed acyclic graphs (DAGs) where actions are executed based on dependency relationships and completion status of prerequisite tasks
|
|
23
|
+
- **Native Solver Support**: Specify input parameter values and the results to extract for a supported solver. Currently implemented are LS-DYNA and OpenRadioss for structural analysis, and OpenFOAM for computational fluid dynamics
|
|
24
|
+
- **Remote Execution**: Submit computational subgraphs to remote computing resources while maintaining local workflow coordination
|
|
25
|
+
- **Dependency Resolution**: Automatically manages execution order based on inter-action dependencies, ensuring downstream actions wait for required upstream results
|
|
26
|
+
- **Discoverability**: Query any graph for its inputs (`variables()`) and outputs (`outputs()`) without running it — solver actions read their parameterised input files to report variable names, types, and default values
|
|
27
|
+
- **Scalability using ML**: Designed to scale through integration with the Gemini CLI for the extension and use of the module.
|
|
28
|
+
|
|
29
|
+
## Typical Workflow
|
|
30
|
+
|
|
31
|
+
1. Configure input files for target solvers
|
|
32
|
+
2. Define analysis actions and their dependencies
|
|
33
|
+
3. Execute simulations on designated compute resources (local or remote)
|
|
34
|
+
4. Extract relevant results from solver outputs
|
|
35
|
+
5. Aggregate and summarize findings
|
|
36
|
+
|
|
37
|
+
SimNexus streamlines the complexity of managing heterogeneous simulation environments, enabling researchers and engineers to focus on analysis rather than workflow orchestration.
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
## Documentation
|
|
41
|
+
(Path to be added. One provided is not yet active)
|
|
42
|
+
|
|
43
|
+
[Online documentation is available here](https://willemjr.github.io/simnexus/)
|
|
44
|
+
|
|
45
|
+
See also the docs directory.
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install simnexus
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Usage
|
|
55
|
+
See the documentation and the examples directory for examples.
|
|
56
|
+
|
|
57
|
+
(Coming soon)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
# Example problems
|
|
62
|
+
The example problems demonstrate:
|
|
63
|
+
|
|
64
|
+
- An LS-DYNA workflow consisting of editing parameter values, job submission, and results extraction.
|
|
65
|
+
- An OpenRadioss workflow consisting of editing parameter values, job submission, and results extraction.
|
|
66
|
+
- An OpenFOAM. workflow consisting of editing parameter values, job submission, and results extraction.
|
|
67
|
+
- Remote execution examples.
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
## License
|
|
71
|
+
This project is licensed under the MIT License.
|
|
72
|
+
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "simnexus"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "A Python module for modelling complex simulation workflows."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = {file = "LICENSE.md"}
|
|
11
|
+
authors = [
|
|
12
|
+
{ name = "Willem", email = "willem4540@gmail.com" },
|
|
13
|
+
]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 3 - Alpha",
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"License :: OSI Approved :: MIT License",
|
|
18
|
+
"Operating System :: OS Independent",
|
|
19
|
+
]
|
|
20
|
+
requires-python = ">=3.7"
|
|
21
|
+
dependencies = []
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
[project.urls]
|
|
25
|
+
Homepage = "https://github.com/WillemJR/simnexus"
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
[project.optional-dependencies]
|
|
29
|
+
dev = [
|
|
30
|
+
"pytest",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[tool.setuptools.packages.find]
|
|
34
|
+
where = ["."]
|
|
35
|
+
include = ["simnexus*"]
|
simnexus-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
|
|
2
|
+
import pyvista as pv
|
|
3
|
+
from vtk.util.numpy_support import vtk_to_numpy
|
|
4
|
+
import numpy as np
|
|
5
|
+
|
|
6
|
+
from collections import namedtuple
|
|
7
|
+
|
|
8
|
+
from vtk import VTK_EMPTY_CELL, VTK_TRIANGLE, VTK_QUAD
|
|
9
|
+
from vtk import VTK_HEXAHEDRON, VTK_WEDGE, VTK_TETRA
|
|
10
|
+
|
|
11
|
+
########################
|
|
12
|
+
# // Linear cells
|
|
13
|
+
# VTK_EMPTY_CELL = 0,
|
|
14
|
+
# VTK_VERTEX = 1,
|
|
15
|
+
# VTK_POLY_VERTEX = 2,
|
|
16
|
+
# VTK_LINE = 3, <<<<<<<<<<
|
|
17
|
+
# VTK_POLY_LINE = 4,
|
|
18
|
+
# VTK_TRIANGLE = 5, <<<<<<<<<<
|
|
19
|
+
# VTK_TRIANGLE_STRIP = 6,
|
|
20
|
+
# VTK_POLYGON = 7,
|
|
21
|
+
# VTK_PIXEL = 8,
|
|
22
|
+
# VTK_QUAD = 9,
|
|
23
|
+
# VTK_TETRA = 10, <<<<<<<<<<
|
|
24
|
+
# VTK_VOXEL = 11,
|
|
25
|
+
# VTK_HEXAHEDRON = 12, <<<<<<<<<<
|
|
26
|
+
# VTK_WEDGE = 13,
|
|
27
|
+
# VTK_PYRAMID = 14, # 5 nodes, rectangular base
|
|
28
|
+
# VTK_PENTAGONAL_PRISM = 15,
|
|
29
|
+
# VTK_HEXAGONAL_PRISM = 16,
|
|
30
|
+
|
|
31
|
+
ElProp = namedtuple( 'ElProp', ['vtk_type', 'num_node'], defaults=[0] )
|
|
32
|
+
|
|
33
|
+
el_props = {
|
|
34
|
+
0: ElProp(VTK_EMPTY_CELL, 0),
|
|
35
|
+
5: ElProp(VTK_TRIANGLE, 3),
|
|
36
|
+
9: ElProp(VTK_QUAD, 4),
|
|
37
|
+
10: ElProp(VTK_TETRA, 4),
|
|
38
|
+
12: ElProp(VTK_HEXAHEDRON, 8),
|
|
39
|
+
13: ElProp(VTK_WEDGE, 6),
|
|
40
|
+
}
|
|
41
|
+
#MAX_CONN = 8 # increase if needed
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def print_mesh_data( vtk_file_name ):
|
|
45
|
+
|
|
46
|
+
print( '==========================================================' )
|
|
47
|
+
print( '== MESH DATA for', vtk_file_name )
|
|
48
|
+
print( '==========================================================' )
|
|
49
|
+
|
|
50
|
+
mesh = pv.read( vtk_file_name )
|
|
51
|
+
|
|
52
|
+
print( 'num_points', mesh.n_points ) # nodes for all parts
|
|
53
|
+
print( 'num_cells', mesh.n_cells ) # for all parts
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
print( '\n\ndata at nodes:\n', mesh.point_data )
|
|
57
|
+
print( '\n\ndata at els:\n', mesh.cell_data )
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
print( '\n\nSOME ARRAY DATA\n' )
|
|
61
|
+
print( 'points', mesh.points ) # nodes for all parts
|
|
62
|
+
|
|
63
|
+
print( 'cells', mesh.cells ) # nodes for all parts
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
#node_ids = mesh.point_data['NODE_ID']
|
|
67
|
+
#print( 'node_ids', node_ids )
|
|
68
|
+
#print( mesh.point_data['Contact_Forces'] ) # nodes for all parts
|
|
69
|
+
|
|
70
|
+
#part_ids = mesh.cell_data['PART_ID']
|
|
71
|
+
#print( part_ids )
|
|
72
|
+
#el_ids = mesh.cell_data['ELEMENT_ID']
|
|
73
|
+
#print( el_ids )
|
|
74
|
+
#print( mesh.cell_data['3DELEM_Von_Mises'] ) # nodes for all parts
|
|
75
|
+
|
|
76
|
+
cells = mesh.GetCells()
|
|
77
|
+
num_cell = cells.GetNumberOfCells()
|
|
78
|
+
cellConns = vtk_to_numpy( cells.GetConnectivityArray() )
|
|
79
|
+
cellOffsets = vtk_to_numpy( cells.GetOffsetsArray() )
|
|
80
|
+
cellTypes = vtk_to_numpy( mesh.GetCellTypesArray() )
|
|
81
|
+
coords = vtk_to_numpy( mesh.GetPoints().GetData() )
|
|
82
|
+
|
|
83
|
+
#print( 'part_ids', part_ids )
|
|
84
|
+
print( 'cellConns', cellConns.shape, cellConns.shape[0]+num_cell, cellConns )
|
|
85
|
+
print( 'cellTypes', cellTypes.shape, cellTypes )
|
|
86
|
+
print( 'coords', coords.shape, coords )
|
|
87
|
+
print( 'cellOffsets', cellOffsets )
|
|
88
|
+
print( 'cellOffsets', cellOffsets[0] )
|
|
89
|
+
|
|
90
|
+
print( '==========================================================' )
|
|
91
|
+
print( '== END MESH DATA for', vtk_file_name )
|
|
92
|
+
print( '==========================================================\n\n' )
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def read_mesh_conns( vtk_file_name, required_part_id,
|
|
97
|
+
node_data_names=None, el_data_names=None, el_nodal_data_names=None ):
|
|
98
|
+
|
|
99
|
+
mesh = pv.read( vtk_file_name )
|
|
100
|
+
|
|
101
|
+
node_ids = mesh.point_data['NODE_ID']
|
|
102
|
+
|
|
103
|
+
part_ids = mesh.cell_data['PART_ID']
|
|
104
|
+
el_ids = mesh.cell_data['ELEMENT_ID']
|
|
105
|
+
|
|
106
|
+
cells = mesh.GetCells()
|
|
107
|
+
num_cell = cells.GetNumberOfCells()
|
|
108
|
+
cellConns = vtk_to_numpy( cells.GetConnectivityArray() )
|
|
109
|
+
cellOffsets = vtk_to_numpy( cells.GetOffsetsArray() )
|
|
110
|
+
cellTypes = vtk_to_numpy( mesh.GetCellTypesArray() )
|
|
111
|
+
coords = vtk_to_numpy( mesh.GetPoints().GetData() )
|
|
112
|
+
|
|
113
|
+
if el_data_names :
|
|
114
|
+
el_data = {}
|
|
115
|
+
for d_name in el_data_names:
|
|
116
|
+
el_data[d_name] = mesh.cell_data[ d_name ]
|
|
117
|
+
else: el_data = None
|
|
118
|
+
node_data = {'node_ids':node_ids}
|
|
119
|
+
if node_data_names :
|
|
120
|
+
for d_name in node_data_names:
|
|
121
|
+
node_data[d_name] = mesh.point_data[ d_name ]
|
|
122
|
+
#else: node_data = None
|
|
123
|
+
|
|
124
|
+
if el_nodal_data_names:
|
|
125
|
+
el_nodal_mesh = mesh.cell_data_to_point_data()
|
|
126
|
+
#if node_data is None : node_data = {}
|
|
127
|
+
for d_name in el_nodal_data_names:
|
|
128
|
+
node_data[d_name] = el_nodal_mesh.point_data[ d_name ]
|
|
129
|
+
|
|
130
|
+
#
|
|
131
|
+
# Build connectivity matrix for required part
|
|
132
|
+
#
|
|
133
|
+
|
|
134
|
+
subset_el_types = []
|
|
135
|
+
|
|
136
|
+
if el_data_names:
|
|
137
|
+
subset_el_data = {}
|
|
138
|
+
for d_name in el_data_names:
|
|
139
|
+
subset_el_data[d_name] = []
|
|
140
|
+
else: subset_el_data = None
|
|
141
|
+
|
|
142
|
+
new_conn_offset = 0
|
|
143
|
+
new_cellCons = np.array( [], dtype=np.int64 )
|
|
144
|
+
new_cellOffsets = []
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
for i, e_type in enumerate( cellTypes ):
|
|
148
|
+
if el_ids[i] == 0:
|
|
149
|
+
pass # internal elements
|
|
150
|
+
elif part_ids[i] == required_part_id:
|
|
151
|
+
if e_type in( VTK_TRIANGLE, VTK_QUAD,VTK_HEXAHEDRON, VTK_WEDGE):
|
|
152
|
+
num_node = el_props[ e_type ].num_node
|
|
153
|
+
#assert( num_node <= MAX_CONN )
|
|
154
|
+
offset = cellOffsets[i]
|
|
155
|
+
conn = cellConns[ offset: offset+num_node]
|
|
156
|
+
if e_type == VTK_QUAD and conn[3] == conn[2]:
|
|
157
|
+
conn = conn[:-1]
|
|
158
|
+
e_type = VTK_TRIANGLE
|
|
159
|
+
|
|
160
|
+
subset_el_types.append( e_type )
|
|
161
|
+
|
|
162
|
+
new_cellCons = np.append( new_cellCons, conn )
|
|
163
|
+
new_cellOffsets.append( new_conn_offset )
|
|
164
|
+
new_conn_offset = new_conn_offset + len(conn)
|
|
165
|
+
|
|
166
|
+
if el_data_names:
|
|
167
|
+
for d_name in el_data_names:
|
|
168
|
+
subset_el_data[d_name].append( el_data[d_name][i] )
|
|
169
|
+
|
|
170
|
+
else:
|
|
171
|
+
pass
|
|
172
|
+
|
|
173
|
+
return coords, node_data, \
|
|
174
|
+
{ 'subset_el_data':subset_el_data,
|
|
175
|
+
'cell_conns':new_cellCons,
|
|
176
|
+
'cell_offsets': np.array(new_cellOffsets),
|
|
177
|
+
'el_types': np.array(subset_el_types) }
|
|
178
|
+
|
|
179
|
+
def compact_nodes( coords, node_data, el_dict ):
|
|
180
|
+
"""
|
|
181
|
+
Remove nodes not connected to elements (of the part)
|
|
182
|
+
"""
|
|
183
|
+
|
|
184
|
+
num_node_all = coords.shape[0]
|
|
185
|
+
|
|
186
|
+
used = np.zeros( num_node_all ).astype( bool )
|
|
187
|
+
new_node_idx = np.zeros( num_node_all )
|
|
188
|
+
|
|
189
|
+
cell_con = el_dict['cell_conns']
|
|
190
|
+
for idx in cell_con:
|
|
191
|
+
used[idx]=True
|
|
192
|
+
|
|
193
|
+
num_node_new = 0
|
|
194
|
+
for old_idx in range( num_node_all ):
|
|
195
|
+
if used[old_idx]:
|
|
196
|
+
new_node_idx[old_idx] = num_node_new
|
|
197
|
+
num_node_new += 1
|
|
198
|
+
else:
|
|
199
|
+
pass
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
# data at nodes
|
|
203
|
+
if node_data is not None:
|
|
204
|
+
node_data_subset = {}
|
|
205
|
+
for k in node_data.keys():
|
|
206
|
+
shape = list( node_data[k].shape )
|
|
207
|
+
shape[0] = num_node_new
|
|
208
|
+
node_data_subset[k] = np.zeros( shape, dtype=node_data[k].dtype )
|
|
209
|
+
|
|
210
|
+
nidx = 0
|
|
211
|
+
for old_idx in range( num_node_all ):
|
|
212
|
+
if used[old_idx]:
|
|
213
|
+
for k in node_data.keys():
|
|
214
|
+
node_data_subset[k] [ nidx ] = node_data[k][ old_idx ]
|
|
215
|
+
nidx += 1
|
|
216
|
+
else:
|
|
217
|
+
pass
|
|
218
|
+
else:
|
|
219
|
+
node_data_subset = None
|
|
220
|
+
|
|
221
|
+
# reset coords
|
|
222
|
+
coords_subset = np.zeros( (num_node_new,3), dtype=float ) # NYI 2D
|
|
223
|
+
nidx = 0
|
|
224
|
+
for old_idx in range( num_node_all ):
|
|
225
|
+
if used[old_idx]:
|
|
226
|
+
coords_subset[nidx] = coords[old_idx]
|
|
227
|
+
nidx += 1
|
|
228
|
+
else:
|
|
229
|
+
#print( 'idx', old_idx, 'not used' )
|
|
230
|
+
pass
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
# reset connectivity
|
|
235
|
+
cell_con = el_dict['cell_conns']
|
|
236
|
+
cell_off = el_dict['cell_offsets']
|
|
237
|
+
new_cell_con = np.zeros_like( cell_con)
|
|
238
|
+
#new_cell_off = np.zeros_like( cell_off )
|
|
239
|
+
for i,n_idx in enumerate( cell_con ):
|
|
240
|
+
new_cell_con[i] = new_node_idx[n_idx]
|
|
241
|
+
el_dict['cell_conns'] = new_cell_con
|
|
242
|
+
|
|
243
|
+
return coords_subset, node_data_subset
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def to_cells( el_types, cell_conns, cell_offsets ):
|
|
247
|
+
|
|
248
|
+
cells = {}
|
|
249
|
+
for etype,ep in el_props.items() :
|
|
250
|
+
numn = ep.num_node
|
|
251
|
+
mask = np.where( el_types == etype )
|
|
252
|
+
oo = cell_offsets[mask]
|
|
253
|
+
cells[etype] = [cell_conns[k:k+numn] for k in oo]
|
|
254
|
+
cells = { k:np.array(v) for k,v in cells.items() }
|
|
255
|
+
return cells
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def read_part_mesh( vtk_file_name, required_part_id,
|
|
259
|
+
node_data_names=None, el_data_names=None, el_nodal_data_names=None ):
|
|
260
|
+
|
|
261
|
+
coords, node_data, el_dict = read_mesh_conns( vtk_file_name,
|
|
262
|
+
required_part_id,
|
|
263
|
+
node_data_names, el_data_names, el_nodal_data_names )
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
coords_subset, node_data_subset = compact_nodes( coords, node_data, el_dict )
|
|
267
|
+
|
|
268
|
+
cells = to_cells( el_dict['el_types'], el_dict['cell_conns'], el_dict['cell_offsets'] )
|
|
269
|
+
|
|
270
|
+
return { 'coords' : coords_subset,
|
|
271
|
+
'data' : node_data_subset,
|
|
272
|
+
}, \
|
|
273
|
+
{ #'conns' : new_subset_el_conns,
|
|
274
|
+
#'types' : el_dict['el_types'],
|
|
275
|
+
#'cell_conns' : el_dict['cell_conns'],
|
|
276
|
+
#'cell_conn_offset' : el_dict['cell_offsets'],
|
|
277
|
+
'cells' : cells,
|
|
278
|
+
'data' : el_dict['subset_el_data'],
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def to_lcl_id( trgt_ids, srcs_ids, srcs_vals):
|
|
283
|
+
""" remap data to follow id sorting in trgt_ids instead of srcs_ids"""
|
|
284
|
+
idx_for_node_id = np.full( int(trgt_ids.max())+1, -1, dtype=int )
|
|
285
|
+
for idx,nid in enumerate(srcs_ids):
|
|
286
|
+
idx_for_node_id [int(nid)] = np.where( trgt_ids==nid )[0][0]
|
|
287
|
+
|
|
288
|
+
lcl_vals = np.zeros_like( srcs_vals )
|
|
289
|
+
#lcl_i = np.zeros_like( trgt_ids )
|
|
290
|
+
for i,nid in enumerate( srcs_ids ):
|
|
291
|
+
lcl_vals[ idx_for_node_id[nid] ] = srcs_vals[i]
|
|
292
|
+
#lcl_i[ idx_for_node_id[nid] ] = nid
|
|
293
|
+
|
|
294
|
+
return lcl_vals
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
if __name__ == '__main__':
|
|
300
|
+
#fname = 'RUBBER_SEAL_IMPDISP_GEOM_001.vtk'
|
|
301
|
+
fname = 'test.vtk'
|
|
302
|
+
#fname = 'test2.vtk'
|
|
303
|
+
#fname = 'test2_us.vtk'
|
|
304
|
+
|
|
305
|
+
required_part_id = 3
|
|
306
|
+
node_data_names = [ 'NODE_ID' ]
|
|
307
|
+
el_data_names = [ 'ELEMENT_ID' ]
|
|
308
|
+
|
|
309
|
+
print_mesh_data( fname )
|
|
310
|
+
|
|
311
|
+
node_data, el_data = \
|
|
312
|
+
read_part_mesh( fname, required_part_id,
|
|
313
|
+
node_data_names = node_data_names,
|
|
314
|
+
el_data_names = el_data_names )
|
|
315
|
+
|
|
316
|
+
print( '****** NODAL' )
|
|
317
|
+
print( 'coords:\n', node_data['coords'] )
|
|
318
|
+
print( 'node_data:\n', node_data['data'])
|
|
319
|
+
|
|
320
|
+
print( '****** ELEMENTS' )
|
|
321
|
+
#print( 'conns:\n', el_data['conns'] )
|
|
322
|
+
#print( 'cell_conns:\n', el_data['cell_conns'] )
|
|
323
|
+
for i,e_type in enumerate( el_data['types'] ):
|
|
324
|
+
co = el_data['cell_conn_offset']
|
|
325
|
+
num_node = el_props[ e_type ].num_node
|
|
326
|
+
#print( e_type, co[i], el_data['cell_conns'][ co[i]:co[i]+num_node ] )
|
|
327
|
+
print( e_type, el_data['cell_conns'][ co[i]:co[i]+num_node ] )
|
|
328
|
+
print( 'data:\n', el_data['data'] )
|
|
329
|
+
|