Skip to content

Commit 3153988

Browse files
Merge pull request #103 from isteinbrecher/allow_custom_ids
Allow custom node set and blocks IDs
2 parents 2e41a1a + f2f6362 commit 3153988

File tree

4 files changed

+182
-65
lines changed

4 files changed

+182
-65
lines changed

src/cubitpy/cubit_to_fourc_input.py

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -30,22 +30,30 @@
3030
from cubitpy.conf import cupy
3131

3232

33-
def add_node_sets(cubit, exo, input_file, write_topology_information=True):
33+
def add_node_sets(
34+
cubit, exo, input_file, write_topology_information=True, use_exo_ids=False
35+
):
3436
"""Add the node sets contained in the cubit session/exo file to the yaml
3537
file."""
3638

3739
# If there are no node sets we can return immediately
3840
if len(cubit.node_sets) == 0:
3941
return
4042

41-
# Get names of the node sets
42-
names = []
43-
for string_list in exo.variables["ns_names"]:
44-
string = ""
45-
for char in string_list:
43+
# Get a mapping between the node set IDs and the node set names and keys in the exo file.
44+
node_set_id_to_exo_name = {}
45+
node_set_keys = [key for key in exo.variables.keys() if "node_ns" in key]
46+
for i in range(len(exo.variables["ns_prop1"])):
47+
node_set_id = int(exo.variables["ns_prop1"][i])
48+
node_set_key = node_set_keys[i]
49+
node_set_name = ""
50+
for char in exo.variables["ns_names"][i]:
4651
if isinstance(char, np.bytes_):
47-
string += char.decode("UTF-8")
48-
names.append(string)
52+
node_set_name += char.decode("UTF-8")
53+
node_set_id_to_exo_name[node_set_id] = {
54+
"key": node_set_key,
55+
"name": node_set_name,
56+
}
4957

5058
# Sort the sets into their geometry type
5159
node_sets = {
@@ -54,20 +62,18 @@ def add_node_sets(cubit, exo, input_file, write_topology_information=True):
5462
cupy.geometry.surface: [],
5563
cupy.geometry.volume: [],
5664
}
57-
boundary_condition_map = {}
58-
node_set_keys = [key for key in exo.variables.keys() if "node_ns" in key]
59-
for i_set, key in enumerate(node_set_keys):
60-
bc_section, bc_description, geometry_type = cubit.node_sets[i_set]
61-
node_sets[geometry_type].append(exo.variables[key][:])
62-
bc_key = (bc_section, geometry_type)
63-
if bc_key not in boundary_condition_map.keys():
64-
boundary_condition_map[bc_key] = []
65-
boundary_condition_map[bc_key].append(
66-
[len(node_sets[geometry_type]), bc_description, names[i_set]]
67-
)
65+
for node_set_id, node_set_data in cubit.node_sets.items():
66+
bc_section, bc_description, geometry_type = node_set_data
67+
node_set_key = node_set_id_to_exo_name[node_set_id]["key"]
68+
node_sets[geometry_type].append(exo.variables[node_set_key][:])
69+
70+
if use_exo_ids:
71+
bc_description["E"] = node_set_id
72+
else:
73+
bc_description["E"] = len(node_sets[geometry_type])
74+
6875
if bc_section not in input_file.inlined.keys():
6976
input_file[bc_section] = []
70-
bc_description["E"] = len(node_sets[geometry_type])
7177

7278
if not write_topology_information:
7379
# when working with external .exo meshes, we do not write the
@@ -122,12 +128,9 @@ def add_exodus_geometry_section(cubit, input_file, rel_exo_file_path):
122128
The relative path (as seen from the yaml input file) to the exodus
123129
file that contains the mesh.
124130
"""
125-
# Retrieve a list of the block IDs and the corresponding block data of the current session
126-
element_block_ids = cubit.cubit.get_block_id_list()
127-
element_blocks = cubit.blocks
128131

129132
# Iterate over all blocks and add them to the input file
130-
for cur_block_id, cur_block_data in zip(element_block_ids, element_blocks):
133+
for cur_block_id, cur_block_data in cubit.blocks.items():
131134
# retrieve the name of the geometry section that this block belongs to
132135
cur_geometry_section_key = cur_block_data[0].get_four_c_section() + " GEOMETRY"
133136
# If the geometry section for this block does not exist yet, create it
@@ -238,8 +241,9 @@ def get_input_file_with_mesh(cubit):
238241
connectivity_keys = [key for key in exo.variables.keys() if "connect" in key]
239242
connectivity_keys.sort()
240243
i_element = 0
241-
for i_block, key in enumerate(connectivity_keys):
242-
ele_type, block_dict = cubit.blocks[i_block]
244+
for key in connectivity_keys:
245+
key_id = int(key[7:])
246+
ele_type, block_dict = cubit.blocks[key_id]
243247
block_section = f"{ele_type.get_four_c_section()} ELEMENTS"
244248
if block_section not in input_file.sections.keys():
245249
input_file[block_section] = []

src/cubitpy/cubitpy.py

Lines changed: 64 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,26 @@
3939
from cubitpy.cubit_wrapper.cubit_wrapper_host import CubitConnect
4040

4141

42+
def _get_and_check_ids(name, container, id_list, given_id):
43+
"""Perform checks for the block and node set IDs used in CubitPy."""
44+
45+
# Check that the IDs stored in container are the same as created with this function.
46+
if not set(container.keys()) == set(id_list):
47+
raise ValueError(
48+
f"The existing {name} ids in CubitPy ({set(container.keys())}) don't match the ones in Cubit ({id_list})"
49+
)
50+
51+
# Get the id of the block to create.
52+
if given_id is None:
53+
if len(id_list) > 0:
54+
given_id = max(id_list) + 1
55+
else:
56+
given_id = 1
57+
elif given_id in id_list:
58+
raise ValueError(f"The provided {name} id {given_id} already exists {id_list}")
59+
return given_id
60+
61+
4262
class CubitPy(object):
4363
"""A wrapper class with additional functionality for cubit."""
4464

@@ -69,12 +89,10 @@ def __init__(self, *, cubit_exe=None, **kwargs):
6989
# Set lists and counters for blocks and sets
7090
self._default_cubit_variables()
7191

72-
self.fourc_input = FourCInput()
73-
7492
def _default_cubit_variables(self):
7593
"""Set the default values for the lists and counters used in cubit."""
76-
self.blocks = []
77-
self.node_sets = []
94+
self.blocks = {}
95+
self.node_sets = {}
7896
self.fourc_input = FourCInput()
7997

8098
def __getattr__(self, key, *args, **kwargs):
@@ -128,7 +146,14 @@ def _name_created_set(self, set_type, set_id, name, item):
128146
self.cubit.cmd('{} {} name "{}"'.format(set_type, set_id, rename_name))
129147

130148
def add_element_type(
131-
self, item, el_type, *, name=None, material=None, bc_description=None
149+
self,
150+
item,
151+
el_type,
152+
*,
153+
name=None,
154+
material=None,
155+
bc_description=None,
156+
block_id: int | None = None,
132157
):
133158
"""Add a block to cubit that contains the geometry in item. Also set
134159
the element type of block.
@@ -147,6 +172,9 @@ def add_element_type(
147172
bc_description: dict
148173
Will be written after the material string. If this is not set, the
149174
default values for the given element type will be used.
175+
block_id:
176+
Optionally the block ID can be given by the user. If this ID already exists
177+
an error will be raised.
150178
"""
151179

152180
# default values
@@ -155,19 +183,15 @@ def add_element_type(
155183
if bc_description is None:
156184
bc_description = {}
157185

158-
# Check that all blocks in cubit are created with this function.
159-
n_blocks = len(self.blocks)
160-
if not len(self.cubit.get_block_id_list()) == n_blocks:
161-
raise ValueError(
162-
"The block counter is {1}, but the number of blocks in cubit is {0}, all blocks should be created with this function!".format(
163-
len(self.cubit.get_block_id_list()), n_blocks
164-
)
165-
)
186+
# Check and get the block id for the new block.
187+
block_id = _get_and_check_ids(
188+
"block", self.blocks, self.cubit.get_block_id_list(), block_id
189+
)
166190

167191
# Get element type of item.
168192
geometry_type = item.get_geometry_type()
169193

170-
self.cubit.cmd("create block {}".format(n_blocks + 1))
194+
self.cubit.cmd("create block {}".format(block_id))
171195

172196
if not isinstance(item, CubitGroup):
173197
cubit_scheme, cubit_element_type = el_type.get_cubit_names()
@@ -181,30 +205,30 @@ def add_element_type(
181205

182206
self.cubit.cmd(
183207
"block {} {} {}".format(
184-
n_blocks + 1, geometry_type.get_cubit_string(), item.id()
208+
block_id, geometry_type.get_cubit_string(), item.id()
185209
)
186210
)
187211
self.cubit.cmd(
188-
"block {} element type {}".format(n_blocks + 1, cubit_element_type)
212+
"block {} element type {}".format(block_id, cubit_element_type)
189213
)
190214
else:
191-
item.add_to_block(n_blocks + 1, el_type)
215+
item.add_to_block(block_id, el_type)
192216

193-
self._name_created_set("block", n_blocks + 1, name, item)
217+
self._name_created_set("block", block_id, name, item)
194218

195219
# If the user does not give a bc_description, load the default one.
196220
if not bc_description:
197221
bc_description = el_type.get_default_four_c_description()
198222

199223
# Add data that will be written to bc file.
200-
self.blocks.append([el_type, material | bc_description])
224+
self.blocks[block_id] = [el_type, material | bc_description]
201225

202226
def reset_blocks(self):
203227
"""This method deletes all blocks in Cubit and resets the counter in
204228
this object."""
205229

206230
# Reset the block list of this object.
207-
self.blocks = []
231+
self.blocks = {}
208232

209233
# Delete all blocks.
210234
for block_id in self.get_block_id_list():
@@ -219,6 +243,7 @@ def add_node_set(
219243
bc_description=None,
220244
bc_section=None,
221245
geometry_type=None,
246+
node_set_id: int | None = None,
222247
):
223248
"""Add a node set to cubit. This node set can have a boundary
224249
condition.
@@ -239,34 +264,33 @@ def add_node_set(
239264
geometry_type: cupy.geometry
240265
Directly set the geometry type, instead of obtaining it from the
241266
given item.
267+
node_set_id:
268+
Optionally the node set ID can be given by the user. If this ID
269+
already exists an error will be raised.
242270
"""
243271

244-
# Check that all node sets in cubit are created with this function.
245-
n_node_sets = len(self.node_sets)
246-
if not len(self.cubit.get_nodeset_id_list()) == n_node_sets:
247-
raise ValueError(
248-
"The node set counter is {1}, but the number of node sets in cubit is {0}, all node sets should be created with this function!".format(
249-
len(self.cubit.get_nodeset_id_list()), n_node_sets
250-
)
251-
)
272+
# Check and get the node set id for the new node set.
273+
node_set_id = _get_and_check_ids(
274+
"nodeset", self.node_sets, self.cubit.get_nodeset_id_list(), node_set_id
275+
)
252276

253277
# Get element type of item if it was not explicitly given.
254278
if geometry_type is None:
255279
geometry_type = item.get_geometry_type()
256280

257-
self.cubit.cmd("create nodeset {}".format(n_node_sets + 1))
281+
self.cubit.cmd("create nodeset {}".format(node_set_id))
258282
if not isinstance(item, CubitGroup):
259283
# Add the geometries to the node set in cubit.
260284
self.cubit.cmd(
261285
"nodeset {} {} {}".format(
262-
n_node_sets + 1, geometry_type.get_cubit_string(), item.id()
286+
node_set_id, geometry_type.get_cubit_string(), item.id()
263287
)
264288
)
265289
else:
266290
# Add the group to the node set in cubit.
267-
item.add_to_nodeset(n_node_sets + 1)
291+
item.add_to_nodeset(node_set_id)
268292

269-
self._name_created_set("nodeset", n_node_sets + 1, name, item)
293+
self._name_created_set("nodeset", node_set_id, name, item)
270294

271295
# Add data that will be written to bc file.
272296
if (
@@ -282,7 +306,7 @@ def add_node_set(
282306
bc_section = bc_type.get_dat_bc_section_header(geometry_type)
283307
if bc_description is None:
284308
bc_description = {}
285-
self.node_sets.append([bc_section, bc_description, geometry_type])
309+
self.node_sets[node_set_id] = [bc_section, bc_description, geometry_type]
286310

287311
def get_ids(self, geometry_type):
288312
"""Get a list with all available ids of a certain geometry type."""
@@ -367,7 +391,13 @@ def dump(self, yaml_path, mesh_in_exo=False):
367391
# create a deep copy of the input_file
368392
input_file = self.fourc_input.copy()
369393
# Add the node sets
370-
add_node_sets(self, exo, input_file, write_topology_information=False)
394+
add_node_sets(
395+
self,
396+
exo,
397+
input_file,
398+
write_topology_information=False,
399+
use_exo_ids=True,
400+
)
371401
# Add the problem geometry section
372402
rel_exo_path = os.path.relpath(exo_path, start=yaml_dir)
373403
add_exodus_geometry_section(self, input_file, rel_exo_path)

tests/input-files-ref/test_yaml_with_exo_export.4C.yaml

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ DESIGN SURF DIRICH CONDITIONS:
2525
- null
2626
- null
2727
- null
28-
E: 3
28+
E: 17
2929
ENTITY_TYPE: "node_set_id"
3030
- NUMDOF: 3
3131
ONOFF:
@@ -40,7 +40,53 @@ DESIGN SURF DIRICH CONDITIONS:
4040
- 1
4141
- null
4242
- null
43-
E: 4
43+
E: 18
44+
ENTITY_TYPE: "node_set_id"
45+
DESIGN LINE NEUMANN CONDITIONS:
46+
- NUMDOF: 3
47+
ONOFF:
48+
- 1
49+
- 0
50+
- 0
51+
VAL:
52+
- 1.0
53+
- 0.0
54+
- 0.0
55+
FUNCT:
56+
- null
57+
- null
58+
- null
59+
E: 19
60+
ENTITY_TYPE: "node_set_id"
61+
- NUMDOF: 3
62+
ONOFF:
63+
- 1
64+
- 0
65+
- 0
66+
VAL:
67+
- 1.0
68+
- 0.0
69+
- 0.0
70+
FUNCT:
71+
- null
72+
- null
73+
- null
74+
E: 20
75+
ENTITY_TYPE: "node_set_id"
76+
- NUMDOF: 3
77+
ONOFF:
78+
- 1
79+
- 1
80+
- 0
81+
VAL:
82+
- 1.0
83+
- 0.0
84+
- 0.0
85+
FUNCT:
86+
- null
87+
- null
88+
- null
89+
E: 15
4490
ENTITY_TYPE: "node_set_id"
4591
STRUCTURE GEOMETRY:
4692
FILE: "test_yaml_with_exo_export.exo"
@@ -49,6 +95,6 @@ STRUCTURE GEOMETRY:
4995
- ID: 1
5096
ELEMENT_NAME: "SOLID"
5197
ELEMENT_DATA: "MAT 1 KINEM nonlinear"
52-
- ID: 2
98+
- ID: 27
5399
ELEMENT_NAME: "SOLID"
54100
ELEMENT_DATA: "MAT 2 KINEM nonlinear"

0 commit comments

Comments
 (0)