exovista 1.0.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 (54) hide show
  1. exovista-1.0.0/.flake8 +31 -0
  2. exovista-1.0.0/.github/workflows/publish.yml +28 -0
  3. exovista-1.0.0/.gitignore +13 -0
  4. exovista-1.0.0/LICENSE +27 -0
  5. exovista-1.0.0/PKG-INFO +10 -0
  6. exovista-1.0.0/README.md +77 -0
  7. exovista-1.0.0/exovista/__init__.py +44 -0
  8. exovista-1.0.0/exovista/allclose.py +217 -0
  9. exovista-1.0.0/exovista/config.py +21 -0
  10. exovista-1.0.0/exovista/copy.py +197 -0
  11. exovista-1.0.0/exovista/element.py +918 -0
  12. exovista-1.0.0/exovista/ex_params.py +87 -0
  13. exovista-1.0.0/exovista/exodus_h.py +540 -0
  14. exovista-1.0.0/exovista/exoread.py +158 -0
  15. exovista-1.0.0/exovista/extension.py +307 -0
  16. exovista-1.0.0/exovista/file.py +4728 -0
  17. exovista-1.0.0/exovista/find_in_region.py +247 -0
  18. exovista-1.0.0/exovista/lineout.py +230 -0
  19. exovista-1.0.0/exovista/nc.py +131 -0
  20. exovista-1.0.0/exovista/netcdf.py +1036 -0
  21. exovista-1.0.0/exovista/parallel_file.py +1727 -0
  22. exovista-1.0.0/exovista/put_solution.py +54 -0
  23. exovista-1.0.0/exovista/region.py +370 -0
  24. exovista-1.0.0/exovista/similar.py +90 -0
  25. exovista-1.0.0/exovista/util.py +185 -0
  26. exovista-1.0.0/exovista/write_pyvista.py +116 -0
  27. exovista-1.0.0/exovista.egg-info/PKG-INFO +10 -0
  28. exovista-1.0.0/exovista.egg-info/SOURCES.txt +52 -0
  29. exovista-1.0.0/exovista.egg-info/dependency_links.txt +1 -0
  30. exovista-1.0.0/exovista.egg-info/entry_points.txt +2 -0
  31. exovista-1.0.0/exovista.egg-info/requires.txt +4 -0
  32. exovista-1.0.0/exovista.egg-info/top_level.txt +1 -0
  33. exovista-1.0.0/pyproject.toml +12 -0
  34. exovista-1.0.0/setup.cfg +4 -0
  35. exovista-1.0.0/test/conftest.py +8 -0
  36. exovista-1.0.0/test/data/edges.base.exo +0 -0
  37. exovista-1.0.0/test/data/edges.exo.4.0 +0 -0
  38. exovista-1.0.0/test/data/edges.exo.4.1 +0 -0
  39. exovista-1.0.0/test/data/edges.exo.4.2 +0 -0
  40. exovista-1.0.0/test/data/edges.exo.4.3 +0 -0
  41. exovista-1.0.0/test/data/mkmesh.gen +0 -0
  42. exovista-1.0.0/test/data/mkmesh.par.2.0 +0 -0
  43. exovista-1.0.0/test/data/mkmesh.par.2.1 +0 -0
  44. exovista-1.0.0/test/data/noh.exo +0 -0
  45. exovista-1.0.0/test/data/noh.exo.3.0 +0 -0
  46. exovista-1.0.0/test/data/noh.exo.3.1 +0 -0
  47. exovista-1.0.0/test/data/noh.exo.3.2 +0 -0
  48. exovista-1.0.0/test/parallel_read.py +559 -0
  49. exovista-1.0.0/test/parallel_write.py +18 -0
  50. exovista-1.0.0/test/pytest.ini +7 -0
  51. exovista-1.0.0/test/region.py +116 -0
  52. exovista-1.0.0/test/serial_read.py +558 -0
  53. exovista-1.0.0/test/serial_write.py +140 -0
  54. exovista-1.0.0/test/test.sh +2 -0
exovista-1.0.0/.flake8 ADDED
@@ -0,0 +1,31 @@
1
+ # -*- conf -*-
2
+ # flake8 settings for Nevada core files.
3
+ #
4
+ # E1: Indentation
5
+ # - E129: visually indented line with same indent as next logical line
6
+ #
7
+ # E2: Whitespace
8
+ # - E203: space before :
9
+ # - E221: multiple spaces before operator
10
+ # - E241: multiple spaces after ','
11
+ # - E272: multiple spaces before keyword
12
+ #
13
+ # E7: Statement
14
+ # - E731: do not assign a lambda expression, use a def
15
+ #
16
+ # W5: Line break warning
17
+ # - W503: line break before binary operator
18
+ # - W504: line break after binary operator
19
+ #
20
+ # These are required to get the package.py files to test clean:
21
+ # - F999: syntax error in doctest
22
+ #
23
+ # N8: PEP8-naming
24
+ # - N801: class names should use CapWords convention
25
+ # - N813: camelcase imported as lowercase
26
+ # - N814: camelcase imported as constant
27
+ #
28
+ [flake8]
29
+ ignore = E129,E221,E241,E272,E731,W503,W504,F999,N801,N813,N814,E203,W605
30
+ max-line-length = 88
31
+ exclude = lib/nevada/external,test,__init__.py,.cache,.git,opt,third_party,lib/nevada/snl,var/nevada/py-packages,var/nevada/spack/repo/packages,docs/nevada,bin/hisread.py,bin/exoread.py,var/nevada/ci,var/nevada/distro,var/nevada/tmp,var/nevada/sandboxes,var/nevada/spack/experimental-repo,TestResults.*
@@ -0,0 +1,28 @@
1
+ name: Upload Python Package to PyPI when a Release is Created
2
+ on:
3
+ release:
4
+ types: [created]
5
+ jobs:
6
+ pypi-publish:
7
+ name: Publish release to PyPI
8
+ runs-on: ubuntu-latest
9
+ environment:
10
+ name: pypi
11
+ url: https://pypi.org/p/exovista
12
+ permissions:
13
+ id-token: write
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ - name: Set up Python
17
+ uses: actions/setup-python@v4
18
+ with:
19
+ python-version: "3.x"
20
+ - name: Install dependencies
21
+ run: |
22
+ python -m pip install --upgrade pip
23
+ pip install build
24
+ - name: Build package
25
+ run: |
26
+ python -m build
27
+ - name: Publish package distributions to PyPI
28
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,13 @@
1
+ *.pyc
2
+ __pycache__
3
+ .cache
4
+ .coverage
5
+ htmlcov
6
+ *.bak
7
+
8
+ # Ignore personal settings
9
+ .vscode
10
+ .vscode/settings.json
11
+ /exovista.egg-info
12
+ /.idea
13
+ .DS_Store
exovista-1.0.0/LICENSE ADDED
@@ -0,0 +1,27 @@
1
+ Copyright 2022 National Technology & Engineering Solutions of Sandia, LLC
2
+ (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S.
3
+ Government retains certain rights in this software.
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ 1. Redistributions of source code must retain the above copyright notice, this
9
+ list of conditions and the following disclaimer.
10
+ 2. Redistributions in binary form must reproduce the above copyright notice,
11
+ this list of conditions and the following disclaimer in the documentation
12
+ and/or other materials provided with the distribution.
13
+
14
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
18
+ ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24
+
25
+ The views and conclusions contained in the software and documentation are those
26
+ of the authors and should not be interpreted as representing official policies,
27
+ either expressed or implied, of Sandia Corporation.
@@ -0,0 +1,10 @@
1
+ Metadata-Version: 2.4
2
+ Name: exovista
3
+ Version: 1.0.0
4
+ Summary: Python wrappers to the ExodusII finite element database model
5
+ License-File: LICENSE
6
+ Requires-Dist: netcdf4
7
+ Requires-Dist: pyvista
8
+ Requires-Dist: numpy
9
+ Requires-Dist: scipy
10
+ Dynamic: license-file
@@ -0,0 +1,77 @@
1
+ # ExoVista
2
+
3
+ An extension of the Sandia exodusii library for exporting PyVista meshes to Exodus format with user-defined element blocks and side sets. This project focuses on a simpler interface for PyVista users (e.g., meshes created via meshio or PyVista’s geometric utilities).
4
+
5
+ # Why ExoVista?
6
+
7
+ While PyVista can read and write Exodus files via meshio, this support is limited. For example, in the SIERRA toolset, element blocks are essential for defining material zones, and side sets are commonly used to assign boundary conditions. Currently, meshio cannot save side sets or user-defined element blocks.
8
+
9
+ ExoVista makes it easy to define side sets and element blocks by assigning a "region" cell array to the surface and volume meshes. Internally, the library automatically splits element blocks by cell type before exporting to an Exodus file.
10
+
11
+ ## Usage
12
+ basic imports
13
+ ```python
14
+ import exovista
15
+ import numpy as np
16
+ import pyvista as pv
17
+ ```
18
+
19
+ Load the letter_a PyVista example (a tetrahedral volume mesh).
20
+ After centering the mesh, extract the surface and assign cell-wise region arrays that define element blocks and side sets in the exported Exodus file.
21
+ ```python
22
+ def export_tetra_mesh():
23
+ volume = pv.examples.download_letter_a()
24
+ volume.points -= volume.center
25
+ surface = volume.extract_surface()
26
+
27
+ volume["region"] = 1 * (volume.cell_centers().points[:, 0] > 0)
28
+ volume.plot(show_edges=True, categories=True, parallel_projection=True, text="element blocks")
29
+
30
+ surface["region"] = 1 * (surface.cell_centers().points[:, 2] > 0)
31
+ surface.plot(show_edges=True, categories=True, parallel_projection=True, text="side sets")
32
+
33
+ exovista.write_exo("test.exo", volume, surface)
34
+ return None
35
+ ```
36
+ <div style="display: flex; gap: 10px;">
37
+ <img src="https://github.com/user-attachments/assets/38b84cb6-7b45-43fa-82a4-1ae72bd81b14" width="48%">
38
+ <img src="https://github.com/user-attachments/assets/1140ffbf-c8b3-4e88-8db6-47c421d3fccc" width="48%">
39
+ </div>
40
+
41
+ This example constructs a structured cylindrical volume made of hexahedral cells.
42
+ As before, extract the surface and assign region arrays before exporting.
43
+ ```python
44
+ def export_hex_mesh():
45
+ volume = pv.CylinderStructured(radius=np.linspace(1, 2, 5)).cast_to_unstructured_grid()
46
+ surface = volume.extract_surface()
47
+
48
+ volume["region"] = 1*(volume.cell_centers().points[:, 1] > 0) + 2*(volume.cell_centers().points[:, 2] > 0)
49
+ volume.plot(show_edges=True, categories=True, parallel_projection=True, text="element blocks")
50
+
51
+ surface["region"] = 1*(surface.cell_centers().points[:, 0] > 0)
52
+ surface.plot(show_edges=True, categories=True, parallel_projection=True, text="side sets")
53
+
54
+ exovista.write_exo("test.exo", volume, surface)
55
+ return None
56
+ ```
57
+ <div style="display: flex; gap: 10px;">
58
+ <img src="https://github.com/user-attachments/assets/2cdf9a4a-fdc6-491b-9e3b-724d2d817c92" width="48%">
59
+ <img src="https://github.com/user-attachments/assets/7400879b-49a3-45d6-8d4f-3f4297fbf166" width="48%">
60
+ </div>
61
+
62
+ ## Install
63
+
64
+ ```
65
+ python -m pip install .
66
+ ```
67
+
68
+ ## Copyright
69
+ This repo is a fork of https://github.com/sandialabs/exodusii and therefore inherits the below copyright:
70
+
71
+ ```
72
+ Copyright 2022 National Technology & Engineering Solutions of Sandia, LLC
73
+ (NTESS). Under the terms of Contract DE-NA0003525 with NTESS, the U.S.
74
+ Government retains certain rights in this software.
75
+
76
+ SCR# 2748
77
+ ```
@@ -0,0 +1,44 @@
1
+ from .file import exodusii_file, ExodusIIFile, write_globals
2
+ from .parallel_file import parallel_exodusii_file, MFExodusIIFile
3
+ from .allclose import allclose
4
+ from .similar import similar
5
+ from .extension import * # noqa: F403
6
+ from .lineout import lineout
7
+ from .find_in_region import find_element_data_in_region, find_node_data_in_region
8
+ from .exoread import main as exoread
9
+ from .write_pyvista import write_exo
10
+
11
+ def File(filename, *files, mode="r"):
12
+
13
+ if mode not in "rw":
14
+ raise ValueError(f"Invalid Exodus file mode {mode!r}")
15
+
16
+ if mode == "r":
17
+ files = _find_files(filename, *files)
18
+ if len(files) > 1:
19
+ f = parallel_exodusii_file(*files)
20
+ elif len(files) == 1:
21
+ f = exodusii_file(files[0], mode="r")
22
+ else:
23
+ raise ValueError("No files to open")
24
+ elif mode == "w":
25
+ if files:
26
+ raise TypeError(f"Exodus writer takes 1 file but {len(files)+1} were given")
27
+ f = exodusii_file(filename, mode="w")
28
+
29
+ return f
30
+
31
+
32
+ exo_file = File
33
+
34
+
35
+ def _find_files(*files):
36
+ import glob
37
+
38
+ found = []
39
+ for file in files:
40
+ globbed_files = glob.glob(file)
41
+ if not globbed_files:
42
+ raise FileNotFoundError(file)
43
+ found.extend(globbed_files)
44
+ return found
@@ -0,0 +1,217 @@
1
+ import sys
2
+ import numpy as np
3
+ from io import StringIO
4
+ from .util import string_kinds
5
+
6
+
7
+ def allclose(
8
+ file1,
9
+ file2,
10
+ atol=1.0e-12,
11
+ rtol=1.0e-12,
12
+ dimensions=True,
13
+ variables=True,
14
+ verbose=False,
15
+ ):
16
+ """Returns True if two files are data-wise equal within a tolerance."""
17
+
18
+ from .file import ExodusIIFile
19
+
20
+ if not isinstance(file1, ExodusIIFile):
21
+ file1 = ExodusIIFile(file1)
22
+ if not isinstance(file2, ExodusIIFile):
23
+ file2 = ExodusIIFile(file2)
24
+
25
+ ach = allclose_helper(file1, file2, atol, rtol, verbose=verbose)
26
+
27
+ ach.set_dimensions(dimensions)
28
+ ach.set_variables(variables)
29
+
30
+ ach.compare_dimensions()
31
+ ach.compare_variables()
32
+
33
+ return True if not ach.errors else False
34
+
35
+
36
+ def _allclose(a, b, atol=1.0e-08, rtol=1.0e-05):
37
+ """Returns True if two arrays are element - wise equal within a tolerance."""
38
+
39
+ def compatible_dtypes(x, y):
40
+ if x.dtype.kind in string_kinds and y.dtype.kind not in string_kinds:
41
+ return False
42
+ if y.dtype.kind in string_kinds and x.dtype.kind not in string_kinds:
43
+ return False
44
+ return True
45
+
46
+ def compatible_shape(x, y):
47
+ return x.shape == y.shape
48
+
49
+ if a is None or b is None:
50
+ if a != b:
51
+ raise ValueError(
52
+ f"cannot compare type {type(a).__name__} to type {type(b).__name__}"
53
+ )
54
+ return True
55
+
56
+ x = np.asanyarray(a)
57
+ y = np.asanyarray(b)
58
+
59
+ if not compatible_dtypes(x, y):
60
+ raise TypeError(
61
+ f"adiff not supported for input dtypes {x.dtype.kind} and {y.dtype.kind}"
62
+ )
63
+ elif not compatible_shape(x, y):
64
+ raise ValueError("input arguments must have same shape")
65
+
66
+ if x.dtype.kind in string_kinds:
67
+ x = sorted(x.flatten())
68
+ y = sorted(y.flatten())
69
+ return all([x[i] == y[i] for i in range(len(x))])
70
+
71
+ return np.allclose(x, y, atol=atol, rtol=rtol)
72
+
73
+
74
+ class allclose_helper:
75
+ def __init__(self, file1, file2, atol, rtol, print_threshold=10, verbose=False):
76
+ self.file1 = file1
77
+ self.file2 = file2
78
+ self.atol = atol
79
+ self.rtol = rtol
80
+ self.print_threshold = print_threshold
81
+ self.verbose = verbose
82
+
83
+ self._dims_to_compare = None
84
+ self._vars_to_compare = None
85
+
86
+ self.errors = 0
87
+
88
+ def log_error(self, message, end="\n"):
89
+ if self.verbose:
90
+ sys.stderr.write(f"==> Error: {message}{end}")
91
+ self.errors += 1
92
+
93
+ def all_dimensions(self):
94
+ dims1 = self.file1.dimension_names()
95
+ dims2 = self.file2.dimension_names()
96
+ return sorted(set(dims1 + dims2))
97
+
98
+ def all_variables(self):
99
+ vars1 = self.file1.variable_names()
100
+ vars2 = self.file2.variable_names()
101
+ return sorted(set(vars1 + vars2))
102
+
103
+ def set_dimensions(self, dimensions):
104
+ if dimensions is True:
105
+ dimensions = self.all_dimensions()
106
+ elif dimensions is None or dimensions is False:
107
+ dimensions = []
108
+ elif isinstance(dimensions, str):
109
+ dimensions = [dimensions]
110
+ if dimensions[0].startswith("~"):
111
+ # Compare all - except those being negated
112
+ skip = dimensions[0][1:].split("|")
113
+ dimensions = [_ for _ in self.all_dimensions() if _ not in skip]
114
+ if not isinstance(dimensions, (list, tuple)):
115
+ raise ValueError("Expected list of dimensions to compare")
116
+ self.validate_dimensions(dimensions)
117
+ self._dims_to_compare = tuple(dimensions)
118
+
119
+ def set_variables(self, variables):
120
+ if variables is True:
121
+ variables = self.all_variables()
122
+ elif variables is None or variables is False:
123
+ variables = []
124
+ elif isinstance(variables, str):
125
+ variables = [variables]
126
+ if variables[0].startswith("~"):
127
+ # Compare all - except those being negated
128
+ skip = variables[0][1:].split("|")
129
+ variables = [_ for _ in self.all_variables() if _ not in skip]
130
+ if not isinstance(variables, (list, tuple)):
131
+ raise ValueError("Expected list of variables to compare")
132
+ self.validate_variables(variables)
133
+ self._vars_to_compare = tuple(variables)
134
+
135
+ def validate_dimensions(self, dimensions):
136
+ invalid = 0
137
+ valid_dimensions = self.all_dimensions()
138
+ for dimension in dimensions:
139
+ if dimension not in valid_dimensions:
140
+ self.log_error(f"{dimension} is not a valid dimension")
141
+ invalid += 1
142
+ if invalid:
143
+ raise ValueError("One or more invalid dimensions")
144
+
145
+ def validate_variables(self, variables):
146
+ invalid = 0
147
+ valid_variables = self.all_variables()
148
+ for variable in variables:
149
+ if variable not in valid_variables:
150
+ self.log_error(f"{variable} is not a valid variable")
151
+ invalid += 1
152
+ if invalid:
153
+ raise ValueError("One or more invalid variables")
154
+
155
+ def compare_dimensions(self):
156
+ if self._dims_to_compare is None:
157
+ raise ValueError("Dimensions to compare must first be set")
158
+ for dimension in self._dims_to_compare:
159
+ self.compare_dimension(dimension)
160
+ self._dims_to_compare = None
161
+
162
+ def compare_dimension(self, dim):
163
+ if dim not in self.file1.fh.dimensions:
164
+ self.log_error(f"dimension {dim} not found in {self.file1.filename}")
165
+ return
166
+ elif dim not in self.file2.fh.dimensions:
167
+ self.log_error(f"dimension {dim} not found in {self.file2.filename}")
168
+ return
169
+ elif dim in ("time_step",):
170
+ return
171
+
172
+ dim1 = self.file1.get_dimension(dim)
173
+ dim2 = self.file1.get_dimension(dim)
174
+ if not _allclose(dim1, dim2, atol=self.atol, rtol=self.rtol):
175
+ err = StringIO()
176
+ err.write(
177
+ f"{self.file1.filename}::{dim} != "
178
+ f"{self.file2.filename}::{dim} ({dim1} != {dim2})"
179
+ )
180
+ self.log_error(err.getvalue())
181
+
182
+ def compare_variables(self):
183
+ if self._vars_to_compare is None:
184
+ raise ValueError("Variables to compare must first be set")
185
+ for variable in self._vars_to_compare:
186
+ self.compare_variable(variable)
187
+ self._vars_to_compare = None
188
+
189
+ def compare_variable(self, var):
190
+ if var not in self.file1.fh.variables:
191
+ self.log_error(f"variable {var} not found in {self.file1.filename}")
192
+ return
193
+ elif var not in self.file2.fh.variables:
194
+ self.log_error(f"variable {var} not found in {self.file2.filename}")
195
+ return
196
+
197
+ var1 = self.file1.get_variable(var)
198
+ var2 = self.file2.get_variable(var)
199
+ if var1.shape != var2.shape:
200
+ err = StringIO()
201
+ err.write(
202
+ f"{self.file1.filename}::{var}.shape != "
203
+ f"{self.file2.filename}::{var}.shape "
204
+ f"({var1.shape} != {var2.shape})"
205
+ )
206
+ self.log_error(err.getvalue())
207
+ return
208
+
209
+ if not _allclose(var1, var2, atol=self.atol, rtol=self.rtol):
210
+ err = StringIO()
211
+ s1 = np.array2string(var1, threshold=self.print_threshold)
212
+ s2 = np.array2string(var2, threshold=self.print_threshold)
213
+ err.write(
214
+ f"{self.file1.filename}::{var} != "
215
+ f"{self.file2.filename}::{var} ({s1} != {s2})"
216
+ )
217
+ self.log_error(err.getvalue())
@@ -0,0 +1,21 @@
1
+ import os
2
+ from types import SimpleNamespace
3
+
4
+
5
+ def env_boolean(var, default=None):
6
+ value = os.getenv(var, default)
7
+ if value is None:
8
+ return default
9
+ if value.lower() in ("false", "0", "off", ""):
10
+ return False
11
+ return True
12
+
13
+
14
+ def initialize_config():
15
+ cfg = SimpleNamespace()
16
+ cfg.use_netcdf4_if_possible = env_boolean("EXODUSII_USE_NETCDF4", default="on")
17
+ cfg.debug = env_boolean("EXODUSII_DEBUG", default="off")
18
+ return cfg
19
+
20
+
21
+ config = initialize_config()
@@ -0,0 +1,197 @@
1
+ from .exodus_h import types
2
+
3
+
4
+ copy_extra_set_info = False
5
+
6
+
7
+ def copy(source, target):
8
+ """Copy the source ExodusII file to the target"""
9
+ target.put_init(
10
+ source.title(),
11
+ source.num_dimensions(),
12
+ source.num_nodes(),
13
+ source.num_elems(),
14
+ source.num_blks(),
15
+ source.num_node_sets(),
16
+ source.num_side_sets(),
17
+ num_edge=source.num_edges(),
18
+ num_edge_blk=source.num_edge_blk(),
19
+ num_face=source.num_faces(),
20
+ num_face_blk=source.num_face_blk(),
21
+ )
22
+ copy_mesh(source, target)
23
+ copy_variable_params(source, target)
24
+ copy_variable_histories(source, target)
25
+
26
+
27
+ def copy_mesh(source, target):
28
+ """Copies ExodusII mesh information from source to target"""
29
+
30
+ target.put_coord_names(source.get_coord_names())
31
+ target.put_coords(source.get_coords())
32
+
33
+ for block in source.elem_blocks():
34
+ target.put_element_block(
35
+ block.id,
36
+ block.elem_type,
37
+ block.num_block_elems,
38
+ block.num_elem_nodes,
39
+ num_faces_per_elem=block.num_elem_faces,
40
+ num_edges_per_elem=block.num_elem_edges,
41
+ num_attr=block.num_elem_attrs,
42
+ )
43
+ for type in (types.node, types.edge, types.face):
44
+ conn = source.get_element_conn(block.id, type=type)
45
+ if conn is not None:
46
+ target.put_element_conn(block.id, conn, type=type)
47
+
48
+ if target.num_faces():
49
+ for block in source.face_blocks():
50
+ target.put_face_block(
51
+ block.id,
52
+ block.elem_type,
53
+ block.num_block_faces,
54
+ block.num_face_nodes,
55
+ block.num_face_attrs,
56
+ )
57
+ conn = source.get_face_block_conn(block.id)
58
+ target.put_face_conn(block.id, conn)
59
+
60
+ if target.num_edges():
61
+ for block in source.edge_blocks():
62
+ target.put_edge_block(
63
+ block.id,
64
+ block.elem_type,
65
+ block.num_block_edges,
66
+ block.num_edge_nodes,
67
+ block.num_edge_attrs,
68
+ )
69
+ conn = source.get_edge_block_conn(block.id)
70
+ target.put_edge_conn(block.id, conn)
71
+
72
+ for ns in source.node_sets():
73
+ target.put_node_set_param(ns.id, ns.num_nodes, ns.num_dist_facts)
74
+ target.put_node_set_name(ns.id, ns.name)
75
+ target.put_node_set_nodes(ns.id, ns.nodes)
76
+ if ns.num_dist_facts:
77
+ target.put_node_set_dist_fact(ns.id, ns.dist_facts)
78
+
79
+ for es in source.edge_sets():
80
+ target.put_edge_set_param(
81
+ es.id, es.num_edges, es.num_nodes_per_edge, es.num_dist_facts
82
+ )
83
+
84
+ for fs in source.face_sets():
85
+ target.put_face_set_param(
86
+ fs.id, fs.num_faces, fs.num_nodes_per_face, fs.num_dist_facts
87
+ )
88
+
89
+ for es in source.elem_sets():
90
+ target.put_element_set_param(es.id, es.num_elems, es.num_dist_facts)
91
+
92
+ for ss in source.side_sets():
93
+ target.put_side_set_param(ss.id, ss.num_sides, ss.num_dist_facts)
94
+ target.put_side_set_name(ss.id, ss.name)
95
+ target.put_side_set_sides(ss.id, ss.elems, ss.sides)
96
+ if ss.num_dist_facts:
97
+ target.put_side_set_dist_fact(ss.id, ss.dist_facts)
98
+
99
+ node_id_map = source.get_node_id_map()
100
+ target.put_node_id_map(node_id_map)
101
+
102
+ elem_id_map = source.get_element_id_map()
103
+ target.put_element_id_map(elem_id_map)
104
+
105
+ if source.num_edges():
106
+ edge_id_map = source.get_edge_id_map()
107
+ target.put_edge_id_map(edge_id_map)
108
+
109
+ if source.num_faces():
110
+ face_id_map = source.get_face_id_map()
111
+ target.put_face_id_map(face_id_map)
112
+
113
+
114
+ def copy_variable_params(source, target):
115
+
116
+ target.put_global_variable_params(source.get_global_variable_number())
117
+ target.put_global_variable_names(source.get_global_variable_names())
118
+
119
+ target.put_node_variable_params(source.get_node_variable_number())
120
+ target.put_node_variable_names(source.get_node_variable_names())
121
+
122
+ if source.get_element_variable_number() is not None:
123
+ target.put_element_variable_params(source.get_element_variable_number())
124
+ target.put_element_variable_names(source.get_element_variable_names())
125
+ table = source.get_element_variable_truth_table()
126
+ if table is not None:
127
+ target.put_element_variable_truth_table(table)
128
+
129
+ if source.get_face_variable_number() is not None:
130
+ target.put_face_variable_params(source.get_face_variable_number())
131
+ target.put_face_variable_names(source.get_face_variable_names())
132
+ table = source.get_face_variable_truth_table()
133
+ if table is not None:
134
+ target.put_face_variable_truth_table(table)
135
+
136
+ if source.get_edge_variable_number() is not None:
137
+ target.put_edge_variable_params(source.get_edge_variable_number())
138
+ target.put_edge_variable_names(source.get_edge_variable_names())
139
+ table = source.get_edge_variable_truth_table()
140
+ if table is not None:
141
+ target.put_edge_variable_truth_table(table)
142
+
143
+ target.put_node_set_variable_params(source.get_node_set_variable_number())
144
+ target.put_node_set_variable_names(source.get_node_set_variable_names())
145
+
146
+ if copy_extra_set_info:
147
+
148
+ target.put_edge_set_variable_params(source.get_edge_set_variable_number())
149
+ target.put_edge_set_variable_names(source.get_edge_set_variable_names())
150
+
151
+ target.put_face_set_variable_params(source.get_face_set_variable_number())
152
+ target.put_face_set_variable_names(source.get_face_set_variable_names())
153
+
154
+ target.put_element_set_variable_params(source.get_element_set_variable_number())
155
+ target.put_element_set_variable_names(source.get_element_set_variable_names())
156
+
157
+ target.put_side_set_variable_params(source.get_side_set_variable_number())
158
+ target.put_side_set_variable_names(source.get_side_set_variable_names())
159
+
160
+
161
+ def copy_variable_histories(source, target):
162
+
163
+ for (time_step, time) in enumerate(source.get_times(), start=1):
164
+ target.put_time(time_step, time)
165
+
166
+ values = source.get_all_global_variable_values()
167
+ target.put_global_variable_values(None, values)
168
+
169
+ for name in source.get_node_variable_names():
170
+ values = source.get_node_variable_values(name)
171
+ target.put_node_variable_values(None, name, values)
172
+
173
+ for block_id in source.get_element_block_ids():
174
+ for name in source.get_element_variable_names():
175
+ values = source.get_element_variable_values(block_id, name)
176
+ target.put_element_variable_values(None, block_id, name, values)
177
+
178
+ for block_id in source.get_edge_block_ids():
179
+ for name in source.get_edge_variable_names():
180
+ values = source.get_edge_variable_values(block_id, name)
181
+ target.put_edge_variable_values(None, block_id, name, values)
182
+
183
+ for block_id in source.get_face_block_ids():
184
+ for name in source.get_face_variable_names():
185
+ values = source.get_face_variable_values(block_id, name)
186
+ target.put_face_variable_values(None, block_id, name, values)
187
+
188
+ if copy_extra_set_info:
189
+ for set_id in source.get_node_set_ids():
190
+ for name in source.get_node_set_variable_names():
191
+ values = source.get_node_set_variable_values(block_id, name)
192
+ target.put_node_set_variable_values(None, block_id, name, values)
193
+
194
+ for set_id in source.get_side_set_ids():
195
+ for name in source.get_side_set_variable_names():
196
+ values = source.get_side_set_variable_values(block_id, name)
197
+ target.put_side_set_variable_values(None, block_id, name, values)