cubitpy 0.2.0__tar.gz → 0.2.2__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 (87) hide show
  1. {cubitpy-0.2.0/src/cubitpy.egg-info → cubitpy-0.2.2}/PKG-INFO +2 -2
  2. {cubitpy-0.2.0 → cubitpy-0.2.2}/README.md +1 -1
  3. {cubitpy-0.2.0 → cubitpy-0.2.2}/src/cubitpy/conf.py +2 -1
  4. {cubitpy-0.2.0 → cubitpy-0.2.2}/src/cubitpy/cubit_to_fourc_input.py +1 -35
  5. {cubitpy-0.2.0 → cubitpy-0.2.2}/src/cubitpy/cubit_wrapper/cubit_wrapper_client.py +63 -44
  6. {cubitpy-0.2.0 → cubitpy-0.2.2}/src/cubitpy/cubit_wrapper/cubit_wrapper_host.py +11 -61
  7. cubitpy-0.2.2/src/cubitpy/exodus_utility.py +97 -0
  8. {cubitpy-0.2.0 → cubitpy-0.2.2}/src/cubitpy/version.py +3 -3
  9. {cubitpy-0.2.0 → cubitpy-0.2.2/src/cubitpy.egg-info}/PKG-INFO +2 -2
  10. {cubitpy-0.2.0 → cubitpy-0.2.2}/src/cubitpy.egg-info/SOURCES.txt +7 -1
  11. cubitpy-0.2.2/tests/input-files-ref/test_create_block_unaltered_element_dict_exo.exo +0 -0
  12. cubitpy-0.2.2/tests/input-files-ref/test_element_types_tet_single_element_with_exo.exo +0 -0
  13. cubitpy-0.2.2/tests/input-files-ref/test_node_sets_without_boundary_condition_with_exo.exo +0 -0
  14. cubitpy-0.2.2/tests/input-files-ref/test_user_defined_node_set_and_block_ids_with_exo.exo +0 -0
  15. cubitpy-0.2.2/tests/input-files-ref/test_yaml_with_exo_export_fsi.exo +0 -0
  16. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/test_cubitpy.py +68 -10
  17. {cubitpy-0.2.0 → cubitpy-0.2.2}/.coveragerc +0 -0
  18. {cubitpy-0.2.0 → cubitpy-0.2.2}/.github/workflows/code_checks.yml +0 -0
  19. {cubitpy-0.2.0 → cubitpy-0.2.2}/.github/workflows/cubitpy_test_suite_with_secrets.yml +0 -0
  20. {cubitpy-0.2.0 → cubitpy-0.2.2}/.gitignore +0 -0
  21. {cubitpy-0.2.0 → cubitpy-0.2.2}/.pre-commit-config.yaml +0 -0
  22. {cubitpy-0.2.0 → cubitpy-0.2.2}/CONTRIBUTORS +0 -0
  23. {cubitpy-0.2.0 → cubitpy-0.2.2}/LICENSE +0 -0
  24. {cubitpy-0.2.0 → cubitpy-0.2.2}/pyproject.toml +0 -0
  25. {cubitpy-0.2.0 → cubitpy-0.2.2}/setup.cfg +0 -0
  26. {cubitpy-0.2.0 → cubitpy-0.2.2}/src/cubitpy/__init__.py +0 -0
  27. {cubitpy-0.2.0 → cubitpy-0.2.2}/src/cubitpy/cubit_group.py +0 -0
  28. {cubitpy-0.2.0 → cubitpy-0.2.2}/src/cubitpy/cubit_utility.py +0 -0
  29. {cubitpy-0.2.0 → cubitpy-0.2.2}/src/cubitpy/cubit_wrapper/__init__.py +0 -0
  30. {cubitpy-0.2.0 → cubitpy-0.2.2}/src/cubitpy/cubit_wrapper/cubit_wrapper_file_transfer.py +0 -0
  31. {cubitpy-0.2.0 → cubitpy-0.2.2}/src/cubitpy/cubit_wrapper/cubit_wrapper_utility.py +0 -0
  32. {cubitpy-0.2.0 → cubitpy-0.2.2}/src/cubitpy/cubitpy.py +0 -0
  33. {cubitpy-0.2.0 → cubitpy-0.2.2}/src/cubitpy/cubitpy_types.py +0 -0
  34. {cubitpy-0.2.0 → cubitpy-0.2.2}/src/cubitpy/geometry_creation_functions.py +0 -0
  35. {cubitpy-0.2.0 → cubitpy-0.2.2}/src/cubitpy/mesh_creation_functions.py +0 -0
  36. {cubitpy-0.2.0 → cubitpy-0.2.2}/src/cubitpy.egg-info/dependency_links.txt +0 -0
  37. {cubitpy-0.2.0 → cubitpy-0.2.2}/src/cubitpy.egg-info/requires.txt +0 -0
  38. {cubitpy-0.2.0 → cubitpy-0.2.2}/src/cubitpy.egg-info/top_level.txt +0 -0
  39. {cubitpy-0.2.0 → cubitpy-0.2.2}/src/tutorial/__init__.py +0 -0
  40. {cubitpy-0.2.0 → cubitpy-0.2.2}/src/tutorial/tutorial.py +0 -0
  41. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/coverage.config +0 -0
  42. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/external-geometry/fluent_aneurysm.msh +0 -0
  43. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_block_function.4C.yaml +0 -0
  44. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_contact_condition_beam_to_surface.4C.yaml +0 -0
  45. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_contact_condition_curve_to_curve.4C.yaml +0 -0
  46. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_contact_condition_surface_to_surface.4C.yaml +0 -0
  47. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_create_block.4C.yaml +0 -0
  48. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_create_block_unaltered_element_dict.4C.yaml +0 -0
  49. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_create_block_unaltered_element_dict_exo.4C.yaml +0 -0
  50. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_create_brick_by_corner_points.4C.yaml +0 -0
  51. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_create_wedge6.4C.yaml +0 -0
  52. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_cubit_tutorial_coreform.4C.yaml +0 -0
  53. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_cubit_tutorial_cubit15.4C.yaml +0 -0
  54. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_dump_numpy_array.4C.yaml +0 -0
  55. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_element_types_hex.4C.yaml +0 -0
  56. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_element_types_quad_yplane.4C.yaml +0 -0
  57. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_element_types_quad_zplane.4C.yaml +0 -0
  58. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_element_types_tet_coreform.4C.yaml +0 -0
  59. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_element_types_tet_cubit15.4C.yaml +0 -0
  60. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_element_types_tet_single_element_with_exo.4C.yaml +0 -0
  61. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_element_types_tet_single_element_without_exo.4C.yaml +0 -0
  62. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_extrude_mesh_function.4C.yaml +0 -0
  63. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_extrude_mesh_function_average_normals_block.4C.yaml +0 -0
  64. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_extrude_mesh_function_average_normals_for_cylinder_and_sphere.4C.yaml +0 -0
  65. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_fluid_functionality_coreform.4C.yaml +0 -0
  66. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_fluid_functionality_cubit15.4C.yaml +0 -0
  67. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_fsi_functionality.4C.yaml +0 -0
  68. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_group_of_surfaces.4C.yaml +0 -0
  69. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_groups.4C.yaml +0 -0
  70. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_groups_multiple_sets.4C.yaml +0 -0
  71. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_mesh_import.4C.yaml +0 -0
  72. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_node_set_geometry_type.4C.yaml +0 -0
  73. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_node_sets_without_boundary_condition_with_exo.4C.yaml +0 -0
  74. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_node_sets_without_boundary_condition_without_exo.4C.yaml +0 -0
  75. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_point_coupling.4C.yaml +0 -0
  76. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_reset_block_1.4C.yaml +0 -0
  77. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_reset_block_2.4C.yaml +0 -0
  78. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_scatra_functionality.4C.yaml +0 -0
  79. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_serialize_nested_lists.4C.yaml +0 -0
  80. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_thermo_functionality.4C.yaml +0 -0
  81. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_user_defined_node_set_and_block_ids_with_exo.4C.yaml +0 -0
  82. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_user_defined_node_set_and_block_ids_without_exo.4C.yaml +0 -0
  83. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/input-files-ref/test_yaml_with_exo_export_fsi.4C.yaml +0 -0
  84. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/run_delete_test.py +0 -0
  85. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/test_configurations.sh +0 -0
  86. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/test_cubitpy_performance.py +0 -0
  87. {cubitpy-0.2.0 → cubitpy-0.2.2}/tests/test_tutorial.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cubitpy
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: CubitPy: Utility functions and 4C related functionality for the Cubit and Coreform python interface
5
5
  Author-email: Ivo Steinbrecher <ivo.steinbrecher@unibw.de>
6
6
  License-Expression: MIT
@@ -89,7 +89,7 @@ This file should look like:
89
89
  ```yaml
90
90
  cubitpy_mode: "local" # "local" or "remote"
91
91
  local_config:
92
- cubit_path: "/Users/ivosteinbrecher/opt/Cubit-15.2/Cubit.app"
92
+ cubit_path: "/Users/username/opt/Cubit-15.2/Cubit.app"
93
93
  remote_config:
94
94
  user: "username"
95
95
  host: "hostname"
@@ -67,7 +67,7 @@ This file should look like:
67
67
  ```yaml
68
68
  cubitpy_mode: "local" # "local" or "remote"
69
69
  local_config:
70
- cubit_path: "/Users/ivosteinbrecher/opt/Cubit-15.2/Cubit.app"
70
+ cubit_path: "/Users/username/opt/Cubit-15.2/Cubit.app"
71
71
  remote_config:
72
72
  user: "username"
73
73
  host: "hostname"
@@ -74,6 +74,8 @@ class CubitOptions(object):
74
74
  self._host_platform = "linux"
75
75
  elif self._host_platform.startswith("darwin"):
76
76
  self._host_platform = "macos"
77
+ elif self._host_platform.startswith("win32"):
78
+ self._host_platform = "windows"
77
79
  else:
78
80
  raise ValueError(
79
81
  "Got unexpected host platform: {}".format(self._host_platform)
@@ -84,7 +86,6 @@ class CubitOptions(object):
84
86
  "/tmp/cubitpy_{}".format(getpass.getuser()), # nosec
85
87
  "pid_{}".format(os.getpid()),
86
88
  )
87
- self.temp_log = os.path.join(self.temp_dir, "cubitpy.log")
88
89
 
89
90
  # Check if temp path exits, if not create it.
90
91
  os.makedirs(self.temp_dir, exist_ok=True)
@@ -33,46 +33,12 @@ import numpy as np
33
33
  from fourcipp.fourc_input import FourCInput
34
34
 
35
35
  from cubitpy.conf import GeometryType, cupy
36
+ from cubitpy.exodus_utility import get_exo_info
36
37
 
37
38
  if TYPE_CHECKING:
38
39
  from cubitpy.cubitpy import CubitPy
39
40
 
40
41
 
41
- def get_exo_info(exo, entry_type) -> tuple[dict, dict]:
42
- """Build mappings between Exodus IDs and Cubit IDs for blocks or
43
- nodesets."""
44
-
45
- if entry_type == "block":
46
- exo_identifier = "eb"
47
- elif entry_type == "nodeset":
48
- exo_identifier = "ns"
49
- else:
50
- raise ValueError(f"Invalid entry type: {entry_type}")
51
-
52
- if exo_identifier + "_names" not in exo.variables.keys():
53
- return {}, {}
54
-
55
- # List of explicitly given names
56
- names = []
57
- for line in exo.variables[exo_identifier + "_names"]:
58
- name: str | None = str(netCDF4.chartostring(line))
59
- if name == "":
60
- name = None
61
- names.append(name)
62
-
63
- # Get information of all entries of the given type
64
- cubit_id_to_info = {}
65
- exo_id_to_info = {}
66
- for exo_id, cubit_id in enumerate(
67
- exo.variables[exo_identifier + "_prop1"][:].tolist()
68
- ):
69
- info = {"cubit_id": cubit_id, "exo_id": exo_id, "name": names[exo_id]}
70
- cubit_id_to_info[cubit_id] = info.copy()
71
- exo_id_to_info[exo_id] = info.copy()
72
-
73
- return cubit_id_to_info, exo_id_to_info
74
-
75
-
76
42
  def add_node_sets_external_geometry(cubit: CubitPy, input_file: FourCInput) -> None:
77
43
  """Add a reference to the node sets contained in the cubit session/exo file
78
44
  to the yaml file."""
@@ -38,6 +38,7 @@ Note: The contents of `cubit_wrapper_utility.py` will be added to the start
38
38
 
39
39
  import os
40
40
  import sys
41
+ import tempfile
41
42
 
42
43
  # Cubit constants
43
44
  cubit_vertex = "cubitpy_vertex"
@@ -51,23 +52,6 @@ cubit_body = "cubitpy_body"
51
52
  parameters = {}
52
53
 
53
54
 
54
- def out(string):
55
- """The print version does over different interpreters, so this function
56
- prints strings to an active console.
57
-
58
- Insert the path of your console to get the
59
- right output.
60
- To get the current path of your console type: tty
61
- """
62
-
63
- if "tty" in parameters.keys():
64
- out_console = parameters["tty"]
65
- else:
66
- out_console = "/dev/pts/18"
67
- escaped_string = "{}".format(string).replace('"', '\\"')
68
- os.system('echo "{}" > {}'.format(escaped_string, out_console)) # nosec
69
-
70
-
71
55
  def is_cubit_type(obj):
72
56
  """Check if the object is of a cubit base."""
73
57
  if (
@@ -117,9 +101,8 @@ def channel_send(argument):
117
101
  cubit_objects = {}
118
102
 
119
103
 
120
- # The first call are parameters needed in this script
104
+ # The first call are parameters needed in this script and to initialize cubit.
121
105
  parameters = channel.receive()
122
- channel_send(None)
123
106
  if not isinstance(parameters, dict):
124
107
  raise TypeError(
125
108
  "The first item should be a dictionary. Got {}!\nparameters={}".format(
@@ -132,32 +115,73 @@ for path in parameters["additional_sys_paths"]:
132
115
  if path not in sys.path:
133
116
  sys.path.append(path)
134
117
 
118
+ # Import libraries needed if this script is running on a remote system.
119
+ # Also, create a temporary directory that is accessible by Cubit.
120
+ if parameters["is_remote"]:
121
+ import platform
122
+ import subprocess # nosec B404
123
+ import time
124
+
125
+ temp_dir = tempfile.TemporaryDirectory(prefix="cubitpy_temp_dir")
126
+
127
+
128
+ if sys.version_info[0] < 3:
129
+ # On non-Coreform Cubit versions (running on python2), we check the log file to get the
130
+ # messages and errors from Cubit. This can be removed once support for python2 is
131
+ # dropped, as the message handler is the cleaner solution.
132
+ _temp_dir = "/tmp/cubitpy_temp_log" # nosec
133
+ if not os.path.exists(_temp_dir):
134
+ os.makedirs(_temp_dir)
135
+ temp_log = os.path.join(_temp_dir, "cubitpy.log")
136
+ open(temp_log, "w").close()
137
+ parameters["init_arguments"].extend(["-log", temp_log])
138
+
139
+
140
+ # Import and initialize the cubit python module
135
141
  import cubit
136
142
 
137
- # The second call is the initialization call for cubit
138
- # init = ['init', cubit_path, [args]]
139
- init = channel.receive()
140
- if not init[0] == "init":
141
- raise ValueError("The second call must be init!")
142
- if not len(init) == 2:
143
- raise ValueError("Two arguments must be given to init!")
144
- cubit.init(init[1])
143
+ cubit.init(parameters["init_arguments"])
145
144
  cubit_objects[id(cubit)] = cubit
146
145
  channel_send(object_to_id(cubit))
147
146
 
148
147
 
149
- if parameters["is_remote"]:
150
- import platform
151
- import subprocess # nosec B404
152
- import tempfile
153
- import time
148
+ # Add a custom message handler to Cubit
149
+ if sys.version_info[0] < 3:
154
150
 
155
- # On remote systems, create a temporary directory.
156
- temp_dir = tempfile.TemporaryDirectory(prefix="cubitpy_temp_dir")
151
+ class MessageHandler:
152
+ """This class intercepts messages and errors from Cubit.
153
+
154
+ This is done by checking the log file, which is not ideal but
155
+ the only option for non-Coreform Cubit versions running on
156
+ python2.
157
+ """
158
+
159
+ def __init__(self):
160
+ self.setup()
161
+
162
+ def setup(self):
163
+ """Check if the log file is empty, if it is not, empty it."""
164
+ if os.stat(temp_log).st_size != 0:
165
+ with open(temp_log, "w"):
166
+ pass
167
+
168
+ def pop(self):
169
+ """Return the stored log messages."""
170
+
171
+ with open(temp_log, "r") as log_file:
172
+ log_text = log_file.read().strip()
157
173
 
174
+ if log_text == "":
175
+ return_value = [[], []]
176
+ else:
177
+ # On old cubit versions, we send all messages as warnings, as they are
178
+ # not directly related to the messages on newer cubit versions.
179
+ return_value = [[log_text], []]
180
+ self.setup()
181
+ return return_value
158
182
 
159
- # Try to add a custom message handler to Cubit
160
- try:
183
+ message_handler = MessageHandler()
184
+ else:
161
185
 
162
186
  class MessageHandler(cubit.CubitMessageHandler):
163
187
  """This class intercepts messages and errors from Cubit."""
@@ -182,14 +206,9 @@ try:
182
206
  """Append the error to the list of errors."""
183
207
  self.errors.append(message)
184
208
 
185
- message_handler_cubit = MessageHandler()
186
- message_handler_cubit.setup()
187
- cubit.set_cubit_message_handler(message_handler_cubit)
188
-
189
- # Everything worked, so overwrite the message handler with the one linked to Cubit.
190
- message_handler = message_handler_cubit
191
- except Exception:
192
- pass # nosec B110
209
+ message_handler = MessageHandler()
210
+ message_handler.setup()
211
+ cubit.set_cubit_message_handler(message_handler)
193
212
 
194
213
 
195
214
  # Now start an endless loop (until None is sent) and perform the cubit functions
@@ -23,7 +23,6 @@
23
23
  interpreter and the main python interpreter."""
24
24
 
25
25
  import atexit
26
- import os
27
26
  import warnings
28
27
  from pathlib import Path
29
28
 
@@ -42,18 +41,9 @@ class CubitConnect(object):
42
41
  receive the output.
43
42
  """
44
43
 
45
- def __init__(self, *, cubit_args=None):
44
+ def __init__(self):
46
45
  """Initialize the connection between the client (cubit) python
47
- interpreter and this one. Also load the cubit module in the remote
48
- interpreter.
49
-
50
- Args
51
- ----
52
- cubit_args: [str]
53
- List of arguments to pass to cubit.init
54
- interpreter: str
55
- Python interpreter to be used for running cubit.
56
- """
46
+ interpreter and this one."""
57
47
 
58
48
  # Set up the gateway to the client python interpreter
59
49
  if cupy.is_remote():
@@ -80,52 +70,23 @@ class CubitConnect(object):
80
70
  self.channel = self.gw.remote_exec(client_code)
81
71
 
82
72
  # Arguments for cubit
83
- if cubit_args is None:
84
- arguments = [
85
- "cubit",
86
- # "-log", # Write the log to a file
87
- # "dev/null",
88
- "-information", # Do not output information of cubit
89
- "Off",
90
- "-nojournal", # Do write a journal file
91
- "-noecho", # Do not output commands used in cubit
92
- ]
93
- else:
94
- arguments = ["cubit"] + cubit_args
73
+ init_arguments = [
74
+ "cubit",
75
+ "-information", # Do not output information of cubit
76
+ "Off",
77
+ "-nojournal", # Do write a journal file
78
+ "-noecho", # Do not output commands used in cubit
79
+ ]
95
80
 
96
81
  # Parameters for initialization of the client interpreter.
97
82
  parameters = {
98
83
  "additional_sys_paths": [str(cubit_lib)],
99
84
  "is_remote": cupy.is_remote(),
85
+ "init_arguments": init_arguments,
100
86
  }
101
87
 
102
- # In remote mode, configure the remote Python environment and send the client code
103
- if cupy.is_remote():
104
- self.log_check = False
105
-
106
- # Local mode – run cubit on the local machine
107
- else:
108
- # Check if a log file was given in the cubit arguments
109
- for arg in arguments:
110
- if arg.startswith("-log="):
111
- log_given = True
112
- break
113
- else:
114
- log_given = False
115
-
116
- self.log_check = False
117
-
118
- if not log_given:
119
- # Write the log to a temporary file and check the contents after each call to cubit
120
- arguments.extend(["-log", cupy.temp_log])
121
- parameters["tty"] = cupy.temp_log
122
- self.log_check = True
123
-
124
- # Send the parameters to the client interpreter
125
- self.send_and_return(parameters)
126
-
127
88
  # Initialize cubit in the client and create the linking object here
128
- cubit_id = self.send_and_return(["init", arguments])
89
+ cubit_id = self.send_and_return(parameters)
129
90
  if cubit_id is None:
130
91
  raise RuntimeError(
131
92
  "Could not initialize cubit in the client! "
@@ -219,12 +180,6 @@ class CubitConnect(object):
219
180
  else:
220
181
  return item
221
182
 
222
- if self.log_check:
223
- # Check if the log file is empty. If it is not, empty it.
224
- if os.stat(cupy.temp_log).st_size != 0:
225
- with open(cupy.temp_log, "w"):
226
- pass
227
-
228
183
  # Check if there are cubit objects in the arguments
229
184
  arguments = serialize_item(args)
230
185
 
@@ -233,11 +188,6 @@ class CubitConnect(object):
233
188
  [cubit_object.cubit_id, name, arguments]
234
189
  )
235
190
 
236
- if self.log_check:
237
- # Print the content of the log file
238
- with open(cupy.temp_log, "r") as log_file:
239
- print(log_file.read(), end="")
240
-
241
191
  # Check if the return value is a cubit object
242
192
  if cubit_item_to_id(cubit_return) is not None:
243
193
  return CubitObject(self, cubit_return)
@@ -0,0 +1,97 @@
1
+ # The MIT License (MIT)
2
+ #
3
+ # Copyright (c) 2018-2026 CubitPy Authors
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+ """Utility functions interacting with the exodus file format."""
23
+
24
+ from pathlib import Path
25
+
26
+ import netCDF4
27
+ import numpy as np
28
+
29
+
30
+ def get_exo_info(exo, entry_type) -> tuple[dict, dict]:
31
+ """Build mappings between Exodus IDs and Cubit IDs for blocks or
32
+ nodesets."""
33
+
34
+ if entry_type == "block":
35
+ exo_identifier = "eb"
36
+ elif entry_type == "nodeset":
37
+ exo_identifier = "ns"
38
+ else:
39
+ raise ValueError(f"Invalid entry type: {entry_type}")
40
+
41
+ if exo_identifier + "_names" not in exo.variables.keys():
42
+ return {}, {}
43
+
44
+ # List of explicitly given names
45
+ names = []
46
+ for line in exo.variables[exo_identifier + "_names"]:
47
+ name: str | None = str(netCDF4.chartostring(line))
48
+ if name == "":
49
+ name = None
50
+ names.append(name)
51
+
52
+ # Get information of all entries of the given type
53
+ cubit_id_to_info = {}
54
+ exo_id_to_info = {}
55
+ for exo_id, cubit_id in enumerate(
56
+ exo.variables[exo_identifier + "_prop1"][:].tolist()
57
+ ):
58
+ info = {"cubit_id": cubit_id, "exo_id": exo_id, "name": names[exo_id]}
59
+ cubit_id_to_info[cubit_id] = info.copy()
60
+ exo_id_to_info[exo_id] = info.copy()
61
+
62
+ return cubit_id_to_info, exo_id_to_info
63
+
64
+
65
+ def convert_exodus_to_dict(exo_path: Path) -> dict:
66
+ """Load an exodus file from disk and convert it to a dictionary containing
67
+ all the relevant information.
68
+
69
+ This function can be used in testing to compare exodus files with
70
+ each other.
71
+ """
72
+ exo_data = {}
73
+ with netCDF4.Dataset(exo_path) as exo:
74
+ exo_data["coordinates"] = (
75
+ np.array(
76
+ [exo.variables["coord" + dim][:] for dim in ["x", "y", "z"]],
77
+ )
78
+ .transpose()
79
+ .tolist()
80
+ )
81
+
82
+ _, exo_block_id_to_info = get_exo_info(exo, "block")
83
+ exo_data["exo_block_id_to_info"] = exo_block_id_to_info
84
+ for exo_id in exo_block_id_to_info.keys():
85
+ connectivity_name = f"connect{exo_id + 1}"
86
+ connectivity = np.array(exo.variables[connectivity_name][:]).tolist()
87
+ exo_data[connectivity_name] = connectivity
88
+
89
+ _, exo_node_set_id_to_info = get_exo_info(exo, "nodeset")
90
+ exo_data["exo_node_set_id_to_info"] = exo_node_set_id_to_info
91
+ for exo_id in exo_node_set_id_to_info.keys():
92
+ node_set_name = f"node_ns{exo_id + 1}"
93
+ unique_node_set_ids = np.unique(np.array(exo.variables[node_set_name][:]))
94
+ # The correct data type here would be `set`. However, this can not be
95
+ # serialized by FourCIPP, so we return an ordered list of the unique IDs here.
96
+ exo_data[node_set_name] = unique_node_set_ids.tolist()
97
+ return exo_data
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '0.2.0'
22
- __version_tuple__ = version_tuple = (0, 2, 0)
21
+ __version__ = version = '0.2.2'
22
+ __version_tuple__ = version_tuple = (0, 2, 2)
23
23
 
24
- __commit_id__ = commit_id = 'ge9904e2c4'
24
+ __commit_id__ = commit_id = 'g4d0bd8df5'
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cubitpy
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: CubitPy: Utility functions and 4C related functionality for the Cubit and Coreform python interface
5
5
  Author-email: Ivo Steinbrecher <ivo.steinbrecher@unibw.de>
6
6
  License-Expression: MIT
@@ -89,7 +89,7 @@ This file should look like:
89
89
  ```yaml
90
90
  cubitpy_mode: "local" # "local" or "remote"
91
91
  local_config:
92
- cubit_path: "/Users/ivosteinbrecher/opt/Cubit-15.2/Cubit.app"
92
+ cubit_path: "/Users/username/opt/Cubit-15.2/Cubit.app"
93
93
  remote_config:
94
94
  user: "username"
95
95
  host: "hostname"
@@ -14,6 +14,7 @@ src/cubitpy/cubit_to_fourc_input.py
14
14
  src/cubitpy/cubit_utility.py
15
15
  src/cubitpy/cubitpy.py
16
16
  src/cubitpy/cubitpy_types.py
17
+ src/cubitpy/exodus_utility.py
17
18
  src/cubitpy/geometry_creation_functions.py
18
19
  src/cubitpy/mesh_creation_functions.py
19
20
  src/cubitpy/version.py
@@ -43,6 +44,7 @@ tests/input-files-ref/test_contact_condition_surface_to_surface.4C.yaml
43
44
  tests/input-files-ref/test_create_block.4C.yaml
44
45
  tests/input-files-ref/test_create_block_unaltered_element_dict.4C.yaml
45
46
  tests/input-files-ref/test_create_block_unaltered_element_dict_exo.4C.yaml
47
+ tests/input-files-ref/test_create_block_unaltered_element_dict_exo.exo
46
48
  tests/input-files-ref/test_create_brick_by_corner_points.4C.yaml
47
49
  tests/input-files-ref/test_create_wedge6.4C.yaml
48
50
  tests/input-files-ref/test_cubit_tutorial_coreform.4C.yaml
@@ -54,6 +56,7 @@ tests/input-files-ref/test_element_types_quad_zplane.4C.yaml
54
56
  tests/input-files-ref/test_element_types_tet_coreform.4C.yaml
55
57
  tests/input-files-ref/test_element_types_tet_cubit15.4C.yaml
56
58
  tests/input-files-ref/test_element_types_tet_single_element_with_exo.4C.yaml
59
+ tests/input-files-ref/test_element_types_tet_single_element_with_exo.exo
57
60
  tests/input-files-ref/test_element_types_tet_single_element_without_exo.4C.yaml
58
61
  tests/input-files-ref/test_extrude_mesh_function.4C.yaml
59
62
  tests/input-files-ref/test_extrude_mesh_function_average_normals_block.4C.yaml
@@ -67,6 +70,7 @@ tests/input-files-ref/test_groups_multiple_sets.4C.yaml
67
70
  tests/input-files-ref/test_mesh_import.4C.yaml
68
71
  tests/input-files-ref/test_node_set_geometry_type.4C.yaml
69
72
  tests/input-files-ref/test_node_sets_without_boundary_condition_with_exo.4C.yaml
73
+ tests/input-files-ref/test_node_sets_without_boundary_condition_with_exo.exo
70
74
  tests/input-files-ref/test_node_sets_without_boundary_condition_without_exo.4C.yaml
71
75
  tests/input-files-ref/test_point_coupling.4C.yaml
72
76
  tests/input-files-ref/test_reset_block_1.4C.yaml
@@ -75,5 +79,7 @@ tests/input-files-ref/test_scatra_functionality.4C.yaml
75
79
  tests/input-files-ref/test_serialize_nested_lists.4C.yaml
76
80
  tests/input-files-ref/test_thermo_functionality.4C.yaml
77
81
  tests/input-files-ref/test_user_defined_node_set_and_block_ids_with_exo.4C.yaml
82
+ tests/input-files-ref/test_user_defined_node_set_and_block_ids_with_exo.exo
78
83
  tests/input-files-ref/test_user_defined_node_set_and_block_ids_without_exo.4C.yaml
79
- tests/input-files-ref/test_yaml_with_exo_export_fsi.4C.yaml
84
+ tests/input-files-ref/test_yaml_with_exo_export_fsi.4C.yaml
85
+ tests/input-files-ref/test_yaml_with_exo_export_fsi.exo
@@ -42,6 +42,7 @@ from cubitpy.cubit_utility import (
42
42
  string_to_node_set_info,
43
43
  )
44
44
  from cubitpy.cubitpy import CubitPy
45
+ from cubitpy.exodus_utility import convert_exodus_to_dict
45
46
  from cubitpy.geometry_creation_functions import (
46
47
  create_brick_by_corner_points,
47
48
  create_parametric_surface,
@@ -126,17 +127,23 @@ def compare_yaml(
126
127
  ref_file = Path(testing_input) / (compare_name + ".4C.yaml")
127
128
  out_file = Path(testing_temp) / (compare_name + ".4C.yaml")
128
129
 
129
- if mesh_in_exo:
130
- # dump the input script with the mesh in exodus format
131
- cubit.dump(out_file, mesh_in_exo=True)
132
- # make sure the directory also contains the exo mesh
133
- out_file_stem = out_file.with_name(out_file.name.removesuffix(".4C.yaml"))
134
- assert out_file_stem.with_suffix(".exo").exists()
135
- else:
136
- cubit.dump(out_file)
130
+ cubit.dump(out_file, mesh_in_exo=mesh_in_exo)
131
+
132
+ def get_input_file_with_data(input_file_path):
133
+ """Load the input file into a FourCIPP object and if the mesh is given
134
+ in exodus format, add this as a data structure for comparison."""
135
+ input_file = FourCInput.from_4C_yaml(input_file_path)
136
+ if mesh_in_exo:
137
+ exo_path = input_file_path.parent / (compare_name + ".exo")
138
+ exo_data = convert_exodus_to_dict(exo_path)
139
+ section_name = "STRUCTURE GEOMETRY"
140
+ structure_section = input_file.pop(section_name)
141
+ structure_section["FILE"] = exo_data
142
+ input_file.combine_sections({section_name: structure_section})
143
+ return input_file
137
144
 
138
- ref_input_file = FourCInput.from_4C_yaml(ref_file)
139
- out_input_file = FourCInput.from_4C_yaml(out_file)
145
+ ref_input_file = get_input_file_with_data(ref_file)
146
+ out_input_file = get_input_file_with_data(out_file)
140
147
 
141
148
  try:
142
149
  files_are_equal = ref_input_file.compare(
@@ -2503,3 +2510,54 @@ def test_cubit_warnings_and_errors():
2503
2510
  match="ERROR: All dimensions must be nonzero and positive. Entered values are:",
2504
2511
  ):
2505
2512
  cubit.cmd("brick x -10")
2513
+
2514
+
2515
+ def test_exodus_to_dict():
2516
+ """Create a simple model and check the convert exodus to dict
2517
+ functionality."""
2518
+
2519
+ # Create the brick with a single solid element
2520
+ cubit = CubitPy()
2521
+ create_brick(
2522
+ cubit,
2523
+ 1,
2524
+ 2,
2525
+ 3,
2526
+ mesh_interval=[1, 1, 1],
2527
+ element_type=cupy.element_type.hex8,
2528
+ name="cube",
2529
+ )
2530
+
2531
+ # Add node sets to the top surface and to the whole volume of the brick, to make
2532
+ # the exodus file more general.
2533
+ cubit.add_node_set(cubit.group(add_value="add surface 2"), name="top")
2534
+ cubit.add_node_set(cubit.group(add_value="add volume 1"), name="all")
2535
+
2536
+ input_file_path = Path(testing_temp) / "exo_to_dict.4C.yaml"
2537
+ exo_path = Path(testing_temp) / "exo_to_dict.exo"
2538
+ cubit.dump(input_file_path, mesh_in_exo=True)
2539
+
2540
+ exo_dict = convert_exodus_to_dict(exo_path)
2541
+
2542
+ reference_exo_dict = {
2543
+ "coordinates": [
2544
+ [-0.5, -1.0, 1.5],
2545
+ [-0.5, -1.0, -1.5],
2546
+ [-0.5, 1.0, -1.5],
2547
+ [-0.5, 1.0, 1.5],
2548
+ [0.5, -1.0, 1.5],
2549
+ [0.5, -1.0, -1.5],
2550
+ [0.5, 1.0, -1.5],
2551
+ [0.5, 1.0, 1.5],
2552
+ ],
2553
+ "exo_block_id_to_info": {0: {"cubit_id": 1, "exo_id": 0, "name": "cube"}},
2554
+ "connect1": [[1, 2, 3, 4, 5, 6, 7, 8]],
2555
+ "exo_node_set_id_to_info": {
2556
+ 0: {"cubit_id": 1, "exo_id": 0, "name": "cpy_1_s_top"},
2557
+ 1: {"cubit_id": 2, "exo_id": 1, "name": "cpy_2_v_all"},
2558
+ },
2559
+ "node_ns1": [2, 3, 6, 7],
2560
+ "node_ns2": [1, 2, 3, 4, 5, 6, 7, 8],
2561
+ }
2562
+
2563
+ compare_nested_dicts_or_lists(exo_dict, reference_exo_dict)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes