Skip to content

Commit 76442f8

Browse files
Ejoin combine sets blocks (#662)
* IOSS: Add a reset_entity_count() function * EJOIN: Nodeset mesh data now works for combining same-name nodesets * EJOIN: Transient nodeset data seems to work.. * EJOIN: Clean up patching process * Committing clang-format changes * CONJOIN: Fix copyright date range [ci skip] * IOSS: Fix copyright date range [ci skip] * EJOIN: Initial impl of element block combining * Committing clang-format changes * EJOIN: Initial implementation of sset combine Signed-off-by: Greg Sjaardema <gsjaardema@gmail.com> * EJOIN: Minor cleanup of recent changes Signed-off-by: Greg Sjaardema <gsjaardema@gmail.com> * EJOIN: Add missing name_in_output property * EJOIN: Fix output of nodal_nodeset fields * Committing clang-format changes * EJOIN: Fix nodal nodeset nodelist node output * Committing clang-format changes * EJOIN: Minor tweaks Signed-off-by: Greg Sjaardema <gsjaardema@gmail.com> * EJOIN: Refactor build_local_element_map * EJOIN: Refactor output_input_map access Signed-off-by: Greg Sjaardema <gsjaardema@gmail.com> * EJOIN: Add testing of ns merge and combine options * Committing clang-format changes * EJOIN: Add input test files * EJOIN: assert -> SMART_ASSERT * EJOIN: Handle combined nodesets with conslidated nodes * EJOIN: handle duplicate nodes in nodesets due to combine and match * Committing clang-format changes * EJOIN: Handle multi-component output fields * Committing clang-format changes * EJOIN: Update gold files * EJOIN: Refactor nset dup node handling * Committing clang-format changes * EJOIN: Show all diffs in exodiff; minor change in gold files * EJOIN: Add debug output (to see why tests diffing) * Committing clang-format changes * EJOIN: More deterministic sort; update gold * Committing clang-format changes * EJOIN: Remove debug output; minor refacrotings * EJOIN: Tests need exodiff. Make sure it is available * EJOIN: nset->nodeset, sset->sideset * EJOIN: Remove beta from version; ready for merge --------- Signed-off-by: Greg Sjaardema <gsjaardema@gmail.com> Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
1 parent 55fe9ae commit 76442f8

File tree

16 files changed

+701
-461
lines changed

16 files changed

+701
-461
lines changed

packages/seacas/applications/conjoin/CJ_Internals.C

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright(C) 1999-, 20242024, , , , National Technology & Engineering Solutions
2+
* Copyright(C) 1999-2025 National Technology & Engineering Solutions
33
* of Sandia, LLC (NTESS). Under the terms of Contract DE-NA0003525 with
44
* NTESS, the U.S. Government retains certain rights in this software.
55
*

packages/seacas/applications/ejoin/CMakeLists.txt

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,45 @@ TRIBITS_ADD_EXECUTABLE(
1717
)
1818

1919
TRIBITS_SUBPACKAGE_POSTPROCESS()
20+
21+
if (${CMAKE_PROJECT_NAME}_ENABLE_SEACASExodiff)
22+
TRIBITS_ADD_ADVANCED_TEST(ejoin_combine_nes_nodeset_merge
23+
TEST_0 EXEC ejoin ARGS --output combine_nes.g --match_nodeset_nodes p1:2,p2:1 --omit_nodeset p1:2,p2:1 --combine_element --combine_sideset --combine_nodeset ${CMAKE_CURRENT_SOURCE_DIR}/test/2block1.g ${CMAKE_CURRENT_SOURCE_DIR}/test/2block2.g
24+
NOEXEPREFIX NOEXESUFFIX
25+
TEST_1 EXEC exodiff ARGS -show_all_diffs -pedantic ${CMAKE_CURRENT_SOURCE_DIR}/test/2block-nes-gold.g combine_nes.g
26+
DIRECTORY ../exodiff
27+
NOEXEPREFIX NOEXESUFFIX
28+
COMM serial
29+
XHOSTTYPE Windows
30+
)
31+
32+
TRIBITS_ADD_ADVANCED_TEST(ejoin_nodeset_merge
33+
TEST_0 EXEC ejoin ARGS --output ns-merge.g --match_nodeset_nodes p1:2,p2:1 --omit_nodeset p1:2,p2:1 ${CMAKE_CURRENT_SOURCE_DIR}/test/2block1.g ${CMAKE_CURRENT_SOURCE_DIR}/test/2block2.g
34+
NOEXEPREFIX NOEXESUFFIX
35+
TEST_1 EXEC exodiff ARGS -show_all_diffs -pedantic ${CMAKE_CURRENT_SOURCE_DIR}/test/2block-gold.g ns-merge.g
36+
DIRECTORY ../exodiff
37+
NOEXEPREFIX NOEXESUFFIX
38+
COMM serial
39+
XHOSTTYPE Windows
40+
)
41+
42+
TRIBITS_ADD_ADVANCED_TEST(ejoin_combine_ne_nodeset_merge
43+
TEST_0 EXEC ejoin ARGS --output combine_ne.g --match_nodeset_nodes p1:2,p2:1 --omit_nodeset p1:2,p2:1 --combine_element --combine_nodeset ${CMAKE_CURRENT_SOURCE_DIR}/test/2block1.g ${CMAKE_CURRENT_SOURCE_DIR}/test/2block2.g
44+
NOEXEPREFIX NOEXESUFFIX
45+
TEST_1 EXEC exodiff ARGS -show_all_diffs -pedantic ${CMAKE_CURRENT_SOURCE_DIR}/test/2block-ne-gold.g combine_ne.g
46+
DIRECTORY ../exodiff
47+
NOEXEPREFIX NOEXESUFFIX
48+
COMM serial
49+
XHOSTTYPE Windows
50+
)
51+
52+
TRIBITS_ADD_ADVANCED_TEST(ejoin_combine_ns_nodeset_merge
53+
TEST_0 EXEC ejoin ARGS -output combine_ns.g --match_nodeset_nodes p1:2,p2:1 --omit_nodeset p1:2,p2:1 --combine_sideset --combine_nodeset ${CMAKE_CURRENT_SOURCE_DIR}/test/2block1.g ${CMAKE_CURRENT_SOURCE_DIR}/test/2block2.g
54+
NOEXEPREFIX NOEXESUFFIX
55+
TEST_1 EXEC exodiff ARGS -show_all_diffs -pedantic ${CMAKE_CURRENT_SOURCE_DIR}/test/2block-ns-gold.g combine_ns.g
56+
DIRECTORY ../exodiff
57+
NOEXEPREFIX NOEXESUFFIX
58+
COMM serial
59+
XHOSTTYPE Windows
60+
)
61+
endif()

packages/seacas/applications/ejoin/EJ_SystemInterface.C

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -113,15 +113,29 @@ void SystemInterface::enroll_options()
113113
"Combine nodes if they are within tolerance distance of each other.", nullptr);
114114

115115
options_.enroll("match_nodeset_nodes", GetLongOption::MandatoryValue,
116-
"Combine nodes in the specified nodeset(s) if they are within `tolerance` "
117-
"distance of each other.\n"
116+
"Combine nodes in the specified nodeset(s) if they are within\n"
117+
"\t\t`tolerance` distance of each other.\n"
118118
"\t\tSpecify nodesets in each part as p#:id1:id2,p#:id2,id4...",
119119
nullptr);
120120

121121
options_.enroll("tolerance", GetLongOption::MandatoryValue,
122122
"Maximum distance between two nodes to be considered colocated.", nullptr,
123123
nullptr, true);
124124

125+
options_.enroll(
126+
"combine_nodesets", GetLongOption::NoValue,
127+
"Input nodesets with the same name will be combined into a single nodeset on output.",
128+
nullptr);
129+
options_.enroll("combine_sidesets", GetLongOption::NoValue,
130+
"Input sidesets with the same name will be combined into a "
131+
"single sideset on output.",
132+
nullptr);
133+
options_.enroll("combine_element_blocks", GetLongOption::NoValue,
134+
"Element blocks with the same name and topology will be "
135+
"combined into a\n"
136+
"\t\tsingle element block on output.",
137+
nullptr, nullptr, true);
138+
125139
#if 0
126140
options_.enroll("match_elem_ids", GetLongOption::NoValue,
127141
"Combine elements if their global ids match and they are compatible.\n"
@@ -220,7 +234,8 @@ void SystemInterface::enroll_options()
220234
nullptr);
221235

222236
options_.enroll("quantize_nsd", GetLongOption::MandatoryValue,
223-
"Use the lossy quantize compression method. Value specifies number of digits to "
237+
"Use the lossy quantize compression method.\n"
238+
"\t\tValue specifies number of digits to "
224239
"retain (1..15) [exodus only]",
225240
nullptr, nullptr, true);
226241

@@ -276,10 +291,10 @@ bool SystemInterface::parse_options(int argc, char **argv)
276291
size_t part_count = inputFiles_.size();
277292
blockOmissions_.resize(part_count);
278293
blockInclusions_.resize(part_count);
279-
nsetOmissions_.resize(part_count);
280-
ssetOmissions_.resize(part_count);
294+
nodesetOmissions_.resize(part_count);
295+
sidesetOmissions_.resize(part_count);
281296
assemblyOmissions_.resize(part_count);
282-
nsetMatch_.resize(part_count);
297+
nodesetMatch_.resize(part_count);
283298

284299
// Get options from environment variable also...
285300
char *options = getenv("EJOIN_OPTIONS");
@@ -349,10 +364,6 @@ bool SystemInterface::parse_options(int argc, char **argv)
349364
}
350365
}
351366

352-
if (options_.retrieve("omit_part_assemblies") != nullptr) {
353-
createAssemblies_ = false;
354-
}
355-
356367
{
357368
const char *temp = options_.retrieve("extract_blocks");
358369
if (temp != nullptr) {
@@ -363,7 +374,7 @@ bool SystemInterface::parse_options(int argc, char **argv)
363374
{
364375
const char *temp = options_.retrieve("match_nodeset_nodes");
365376
if (temp != nullptr) {
366-
parse_omissions(temp, &nsetMatch_, "nodelist", true);
377+
parse_omissions(temp, &nodesetMatch_, "nodelist", true);
367378
}
368379
}
369380

@@ -374,7 +385,7 @@ bool SystemInterface::parse_options(int argc, char **argv)
374385
omitNodesets_ = true;
375386
}
376387
else {
377-
parse_omissions(temp, &nsetOmissions_, "nodelist", false);
388+
parse_omissions(temp, &nodesetOmissions_, "nodelist", false);
378389
}
379390
}
380391
else {
@@ -389,7 +400,7 @@ bool SystemInterface::parse_options(int argc, char **argv)
389400
omitSidesets_ = true;
390401
}
391402
else {
392-
parse_omissions(temp, &ssetOmissions_, "surface", false);
403+
parse_omissions(temp, &sidesetOmissions_, "surface", false);
393404
}
394405
}
395406
else {
@@ -421,24 +432,25 @@ bool SystemInterface::parse_options(int argc, char **argv)
421432
{
422433
const char *temp = options_.retrieve("nsetvar");
423434
if (temp != nullptr) {
424-
parse_variable_names(temp, &nsetVarNames_);
435+
parse_variable_names(temp, &nodesetVarNames_);
425436
}
426437
}
427438

428439
{
429440
const char *temp = options_.retrieve("ssetvar");
430441
if (temp != nullptr) {
431-
parse_variable_names(temp, &ssetVarNames_);
442+
parse_variable_names(temp, &sidesetVarNames_);
432443
}
433444
}
434445

446+
createAssemblies_ = options_.retrieve("omit_part_assemblies") != nullptr;
435447
disableFieldRecognition_ = options_.retrieve("disable_field_recognition") != nullptr;
436448
useNetcdf4_ = options_.retrieve("netcdf4") != nullptr;
437449
ignoreElementIds_ = options_.retrieve("ignore_element_ids") != nullptr;
438-
439-
if (options_.retrieve("64-bit") != nullptr) {
440-
ints64bit_ = true;
441-
}
450+
combineNodesets_ = options_.retrieve("combine_nodesets") != nullptr;
451+
combineSidesets_ = options_.retrieve("combine_sidesets") != nullptr;
452+
combineElementBlocks_ = options_.retrieve("combine_element_blocks") != nullptr;
453+
ints64bit_ = options_.retrieve("64-bit") != nullptr;
442454

443455
zlib_ = (options_.retrieve("zlib") != nullptr);
444456
szip_ = (options_.retrieve("szip") != nullptr);

packages/seacas/applications/ejoin/EJ_SystemInterface.h

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ class SystemInterface
2424
double tolerance() const { return tolerance_; }
2525
bool match_node_ids() const { return matchNodeIds_; }
2626
bool match_node_xyz() const { return matchNodeXYZ_; }
27-
bool match_nodeset_nodes() const { return !nsetMatch_.empty(); }
27+
bool match_nodeset_nodes() const { return !nodesetMatch_.empty(); }
2828
bool match_elem_ids() const { return matchElemIds_; }
2929
bool omit_nodesets() const { return omitNodesets_; }
3030
bool omit_sidesets() const { return omitSidesets_; }
@@ -49,20 +49,23 @@ class SystemInterface
4949
int step_max() const { return stepMax_; }
5050
int step_interval() const { return stepInterval_; }
5151

52+
bool combine_nodesets() const { return combineNodesets_; }
53+
bool combine_sidesets() const { return combineSidesets_; }
54+
bool combine_element_blocks() const { return combineElementBlocks_; }
5255
vector3d offset() const { return offset_; }
5356
const std::vector<int> &information_record_parts() const { return infoRecordParts_; }
5457
const StringIdVector &global_var_names() const { return globalVarNames_; }
5558
const StringIdVector &node_var_names() const { return nodeVarNames_; }
5659
const StringIdVector &elem_var_names() const { return elemVarNames_; }
57-
const StringIdVector &nset_var_names() const { return nsetVarNames_; }
58-
const StringIdVector &sset_var_names() const { return ssetVarNames_; }
60+
const StringIdVector &nodeset_var_names() const { return nodesetVarNames_; }
61+
const StringIdVector &sideset_var_names() const { return sidesetVarNames_; }
5962

6063
const Omissions &block_inclusions() const { return blockInclusions_; }
6164
const Omissions &block_omissions() const { return blockOmissions_; }
62-
const Omissions &nset_omissions() const { return nsetOmissions_; }
63-
const Omissions &sset_omissions() const { return ssetOmissions_; }
65+
const Omissions &nodeset_omissions() const { return nodesetOmissions_; }
66+
const Omissions &sideset_omissions() const { return sidesetOmissions_; }
6467
const Omissions &assembly_omissions() const { return assemblyOmissions_; }
65-
const Omissions &nset_match() const { return nsetMatch_; }
68+
const Omissions &nodeset_match() const { return nodesetMatch_; }
6669

6770
const std::string &block_prefix() const { return blockPrefix_; }
6871

@@ -112,6 +115,10 @@ class SystemInterface
112115
bool useNetcdf4_{false};
113116
bool ignoreElementIds_{false};
114117

118+
bool combineElementBlocks_{false};
119+
bool combineNodesets_{false};
120+
bool combineSidesets_{false};
121+
115122
bool createAssemblies_{true};
116123

117124
std::string blockPrefix_{"p"};
@@ -122,17 +129,17 @@ class SystemInterface
122129
Omissions blockInclusions_;
123130
Omissions blockOmissions_;
124131
Omissions assemblyOmissions_;
125-
Omissions nsetOmissions_;
126-
Omissions ssetOmissions_;
132+
Omissions nodesetOmissions_;
133+
Omissions sidesetOmissions_;
127134

128-
Omissions nsetMatch_;
135+
Omissions nodesetMatch_;
129136

130137
std::vector<int> nodesetConvertParts_;
131138
std::vector<int> infoRecordParts_;
132139

133140
StringIdVector globalVarNames_;
134141
StringIdVector nodeVarNames_;
135142
StringIdVector elemVarNames_;
136-
StringIdVector nsetVarNames_;
137-
StringIdVector ssetVarNames_;
143+
StringIdVector nodesetVarNames_;
144+
StringIdVector sidesetVarNames_;
138145
};

packages/seacas/applications/ejoin/EJ_Version.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,6 @@
99

1010
static const std::array<std::string, 3> qainfo{
1111
"ejoin",
12-
"2025/05/14",
13-
"1.7.0",
12+
"2025/06/04",
13+
"1.8.1",
1414
};

packages/seacas/applications/ejoin/EJ_mapping.C

Lines changed: 38 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -256,37 +256,52 @@ template void build_reverse_node_map(Ioss::Region &global, RegionVector &part_me
256256
std::vector<int64_t> &local_node_map);
257257

258258
template <typename INT>
259-
void build_local_element_map(RegionVector &part_mesh, std::vector<INT> &local_element_map)
259+
std::vector<INT> build_local_element_map(RegionVector &part_mesh, Ioss::Region &output_region,
260+
const IO_map &output_input_map)
260261
{
261-
size_t global = 0;
262-
size_t offset = 0;
263-
for (auto &p : part_mesh) {
262+
INT element_offset = 0;
263+
for (auto &pm : part_mesh) {
264+
pm->property_add(Ioss::Property("element_offset", element_offset));
265+
INT local_elem_count = pm->get_property("element_count").get_int();
266+
element_offset += local_elem_count;
267+
}
264268

265-
const auto &ebs = p->get_element_blocks();
266-
auto i = ebs.begin();
267-
268-
while (i != ebs.end()) {
269-
const auto *eb = *i++;
270-
size_t num_elem = eb->entity_count();
271-
if (entity_is_omitted(eb)) {
272-
// Fill local_element_map with -1 for the omitted elements.
273-
for (size_t j = 0; j < num_elem; j++) {
274-
local_element_map[offset + j] = -1;
275-
}
276-
}
277-
else {
278-
for (size_t j = 0; j < num_elem; j++) {
279-
local_element_map[offset + j] = global++;
269+
std::vector<INT> local_element_map(element_offset, -1);
270+
const Ioss::ElementBlockContainer &ebs = output_region.get_element_blocks();
271+
272+
size_t global = 0;
273+
for (const auto &oeb : ebs) {
274+
const auto &itr = output_input_map.find(oeb);
275+
assert(itr != output_input_map.end());
276+
const auto &[key, oeb_inputs] = *itr;
277+
for (const auto &[ieb, offset] : oeb_inputs) {
278+
if (ieb != nullptr) {
279+
int64_t ieb_count = ieb->entity_count();
280+
281+
auto *input_region = dynamic_cast<const Ioss::Region *>(ieb->contained_in());
282+
size_t ireg_offset = input_region->get_property("element_offset").get_int();
283+
size_t ieb_offset = dynamic_cast<Ioss::EntityBlock *>(ieb)->get_offset();
284+
285+
// Element block `ieb` has `ieb_count` elements that run
286+
// from `ieb_offset` to `ieb_offset + ieb_count` in
287+
// `input_region` In `local_element_map, they run from
288+
// `ireg_offset + ieb_offset` to `ireg_offset +
289+
// ieb_offset + ieb_count`.
290+
for (int64_t i = 0; i < ieb_count; i++) {
291+
local_element_map[ireg_offset + ieb_offset + i] = global++;
280292
}
281293
}
282-
offset += num_elem;
283294
}
284295
}
296+
return local_element_map;
285297
}
286298

287-
template void build_local_element_map(RegionVector &part_mesh, std::vector<int> &local_element_map);
288-
template void build_local_element_map(RegionVector &part_mesh,
289-
std::vector<int64_t> &local_element_map);
299+
template std::vector<int> build_local_element_map(RegionVector &part_mesh,
300+
Ioss::Region &output_region,
301+
const IO_map &output_input_map);
302+
template std::vector<int64_t> build_local_element_map(RegionVector &part_mesh,
303+
Ioss::Region &output_region,
304+
const IO_map &output_input_map);
290305

291306
template <typename INT>
292307
void generate_element_ids(RegionVector &part_mesh, const std::vector<INT> &local_element_map,

packages/seacas/applications/ejoin/EJ_mapping.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@
77

88
#include "EJ_CodeTypes.h"
99

10+
using IO_map =
11+
std::map<Ioss::GroupingEntity *, std::vector<std::pair<Ioss::GroupingEntity *, size_t>>>;
12+
1013
template <typename INT>
1114
void eliminate_omitted_nodes(RegionVector &part_mesh, std::vector<INT> &global_node_map,
1215
std::vector<INT> &local_node_map, bool fill_global);
@@ -16,7 +19,8 @@ void build_reverse_node_map(Ioss::Region &output_region, RegionVector &part_mesh
1619
std::vector<INT> &global_node_map, std::vector<INT> &local_node_map);
1720

1821
template <typename INT>
19-
void build_local_element_map(RegionVector &part_mesh, std::vector<INT> &local_element_map);
22+
std::vector<INT> build_local_element_map(RegionVector &part_mesh, Ioss::Region &output_region,
23+
const IO_map &output_input_map);
2024

2125
template <typename INT>
2226
void generate_element_ids(RegionVector &part_mesh, const std::vector<INT> &local_element_map,

packages/seacas/applications/ejoin/EJ_match.C

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ void match_nodeset_nodes(RegionVector &part_mesh, double tolerance,
223223
// Select all nodes that are in the listed nodeset(s)...
224224
// On return, `local_node_map` will have >=0 entries for all nodeset nodes.
225225
// entries = -1 for active, but non-nodeset, and -2 for omitted nodes.
226-
select_nodeset_nodes(part_mesh, local_node_map, interFace.nset_match());
226+
select_nodeset_nodes(part_mesh, local_node_map, interFace.nodeset_match());
227227

228228
match_nodes(part_mesh, tolerance, global_node_map, local_node_map);
229229
}

0 commit comments

Comments
 (0)