Skip to content

Commit

Permalink
Catalyst: Add support for Exodus IOSS Properties in Conduit Represent…
Browse files Browse the repository at this point in the history
…ation (#458)

* Made conduit mimic exodus prop changes in Cat Database on read

* Added field_data equality checks btwn Exodus and Catalyst DBs in exo prop tests
  • Loading branch information
ajpelle authored May 31, 2024
1 parent dad473d commit 93707f4
Show file tree
Hide file tree
Showing 4 changed files with 177 additions and 5 deletions.
104 changes: 103 additions & 1 deletion packages/seacas/libraries/ioss/src/catalyst/Iocatalyst_DatabaseIO.C
Original file line number Diff line number Diff line change
Expand Up @@ -816,8 +816,104 @@ namespace Iocatalyst {
return true;
}

std::vector<std::string> getScalarNamesFromNonScalarField(const Ioss::Field &field) const
{
int ncomp = field.get_component_count(Ioss::Field::InOut::INPUT);
std::vector<std::string> fnames;
for(int i=1; i<=ncomp; i++){
fnames.push_back(field.get_component_name(i, Ioss::Field::InOut::INPUT));
}
return fnames;
}

template <typename T>
std::vector<T> getInterweavedScalarDataFromConduitNode(const std::vector<std::string> fnames, conduit_cpp::Node &node) const
{
int ncomp = fnames.size();
auto &&t_node = node[fnames[0] + detail::FS + detail::VALUE];
int num_get = t_node.number_of_elements();
std::vector<T> vals(ncomp*num_get);

for(int i=0; i<num_get; i++) {
for(int j=0; j<ncomp; j++){
std::string path_to_value = fnames[j] + detail::FS + detail::VALUE;
auto &&child_value = node[path_to_value];
vals[i*ncomp + j] =
reinterpret_cast<const T *>(child_value.element_ptr(0))[i];
}
}
return vals;
}

template <typename T>
void addFieldNodeAndDataToConduitNode(const Ioss::Field &field, void *data, conduit_cpp::Node &node) const
{
int ncomp = field.get_component_count(Ioss::Field::InOut::INPUT);
int num_get = field.raw_count();
node[field.get_name()] = conduit_cpp::Node();
auto &&f_node = node[field.get_name()];
f_node[detail::ROLE].set(static_cast<std::int8_t>(field.get_role()));
f_node[detail::TYPE].set(static_cast<std::int8_t>(field.get_type()));
f_node[detail::COUNT].set(static_cast<std::int64_t>(field.raw_count()));
f_node[detail::INDEX].set(static_cast<std::int64_t>(field.get_index()));
f_node[detail::COMPONENTCOUNT].set(static_cast<std::int64_t>(ncomp));
f_node[detail::STORAGE].set(field.raw_storage()->name());
f_node[detail::VALUE].set(static_cast< T *>(data), ncomp * num_get);
}

void combineScalarFieldsInConduitNodeToNonScalarField(
const Ioss::Field &field, conduit_cpp::Node &node) const
{
std::vector<std::string> fnames =
this->getScalarNamesFromNonScalarField(field);

switch (field.get_type()) {
case Ioss::Field::BasicType::DOUBLE:
this->addFieldNodeAndDataToConduitNode<double>(
field,
this->getInterweavedScalarDataFromConduitNode<double>(fnames, node).data(),
node
);
break;

case Ioss::Field::BasicType::INT32:
this->addFieldNodeAndDataToConduitNode<std::int32_t>(
field,
this->getInterweavedScalarDataFromConduitNode<std::int32_t>(fnames, node).data(),
node
);
break;

case Ioss::Field::BasicType::INT64:
this->addFieldNodeAndDataToConduitNode<std::int64_t>(
field,
this->getInterweavedScalarDataFromConduitNode<std::int64_t>(fnames, node).data(),
node
);
break;

case Ioss::Field::BasicType::CHARACTER:
this->addFieldNodeAndDataToConduitNode<std::int8_t>(
field,
this->getInterweavedScalarDataFromConduitNode<char>(fnames, node).data(),
node
);
break;
default:
std::ostringstream errmsg;
fmt::print(errmsg, "ERROR in {} on read: {}, unsupported field type: {}\n", __func__,
field.get_name(), field.type_string());
IOSS_ERROR(errmsg);
}

//Remove Related Scalars from Conduit Node
for(int i=0; i<fnames.size(); i++) {
node.remove(fnames[i]);
}
}

template <typename GroupingEntityT>
bool readFields(const conduit_cpp::Node &&parent, GroupingEntityT *block) const
bool readFields(conduit_cpp::Node &&parent, GroupingEntityT *block) const
{
// Assumption: count = entity_count (in block)
Ioss::DatabaseIO *dbase = block->get_database();
Expand Down Expand Up @@ -878,6 +974,12 @@ namespace Iocatalyst {
for (const auto &field : fields) {
block->field_add(field.set_zero_copy_enabled());
}

for (const auto &field : fields) {
if(field.raw_storage()->name() != IOSS_SCALAR()) {
this->combineScalarFieldsInConduitNodeToNonScalarField(field, parent);
}
}
}

return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,7 @@ namespace Iocatalyst {
values.push_back(itr->second + j*0.1);
}
elemBlock->put_field_data(itr->first, values);
values.clear();
}
}

Expand All @@ -449,6 +450,7 @@ namespace Iocatalyst {
values.push_back(itr->second + j*0.1);
}
nodeBlock->put_field_data(itr->first, values);
values.clear();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ class IOCATALYST_EXPORT Iocatalyst_DatabaseIOTest : public ::testing::Test
void *data;
size_t dataSize;
g->get_field_data(name, &data, &dataSize);
ASSERT_GT(dataSize, 0) << "DataSize is not greater than 0 for field "<<name<<std::endl;
std::byte *b = static_cast<std::byte *>(data);
std::vector<std::byte> zcBuffer(b, b + field.get_size());
EXPECT_EQ(dcBuffer, zcBuffer);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,18 @@
//
// See packages/seacas/LICENSE for details

#include <catalyst_tests/Iocatalyst_DatabaseIOTest.h>
#include <Ioss_Compare.h>
#include <Ioss_CopyDatabase.h>
#include <Ioss_DatabaseIO.h>
#include <Ioss_ElementBlock.h>
#include <Ioss_IOFactory.h>
#include <Ioss_MeshCopyOptions.h>
#include <Ioss_NodeBlock.h>
#include <Ioss_StructuredBlock.h>
#include <catalyst/Iocatalyst_DatabaseIO.h>
#include <catalyst_tests/Iocatalyst_DatabaseIOTest.h>
#include <catalyst/Iocatalyst_CatalystManager.h>

#include <Ioss_ElementBlock.h>


TEST_F(Iocatalyst_DatabaseIOTest, WriteThreeElementBlocksWith24Cells)
Expand Down Expand Up @@ -92,13 +100,26 @@ TEST_F(Iocatalyst_DatabaseIOTest, Exodus_Prop_ENABLE_FIELD_RECOGNITION_ON)
auto cat_elemBlock = cat_reg.get_element_block(bmSet.getUnstructuredBlockName(bm.getID()));
auto exo_elemBlock = exo_reg.get_element_block(bmSet.getUnstructuredBlockName(bm.getID()));

checkEntityContainerZeroCopyFields(cat_reg.get_element_blocks());

bool exo_foo_exists = exo_elemBlock->field_exists("foo");
bool cat_foo_exists = cat_elemBlock->field_exists("foo");
EXPECT_TRUE(exo_foo_exists);
EXPECT_TRUE(cat_foo_exists);
if(exo_foo_exists && cat_foo_exists)
EXPECT_TRUE(exo_elemBlock->get_field("foo") == cat_elemBlock->get_field("foo"));

//Check field data for equality
auto cat_field = cat_elemBlock->get_fieldref("foo");
std::vector<std::byte> dcBuffer(cat_field.get_size());
cat_elemBlock->get_field_data("foo", Data(dcBuffer), dcBuffer.size());

exo_reg.begin_state(1);
auto exo_field = exo_elemBlock->get_fieldref("foo");
std::vector<std::byte> deBuffer(exo_field.get_size());
exo_elemBlock->get_field_data("foo", Data(deBuffer), deBuffer.size());
EXPECT_EQ(dcBuffer, deBuffer);

//Check foo_x doesn't exist
bool exo_foo_x_exists = exo_elemBlock->field_exists("foo_x");
bool cat_foo_x_exists = cat_elemBlock->field_exists("foo_x");
Expand Down Expand Up @@ -135,6 +156,8 @@ TEST_F(Iocatalyst_DatabaseIOTest, Exodus_Prop_ENABLE_FIELD_RECOGNITION_OFF)
auto cat_elemBlock = cat_reg.get_element_block(bmSet.getUnstructuredBlockName(bm.getID()));
auto exo_elemBlock = exo_reg.get_element_block(bmSet.getUnstructuredBlockName(bm.getID()));

checkEntityContainerZeroCopyFields(cat_reg.get_element_blocks());

bool exo_foo_x_exists = exo_elemBlock->field_exists("foo_x");
bool cat_foo_x_exists = cat_elemBlock->field_exists("foo_x");
EXPECT_TRUE(exo_foo_x_exists);
Expand Down Expand Up @@ -173,21 +196,24 @@ TEST_F(Iocatalyst_DatabaseIOTest, Exodus_Prop_IGNORE_REALN_FIELDS_ON)
auto cat_elemBlock = cat_reg.get_element_block(bmSet.getUnstructuredBlockName(bm.getID()));
auto exo_elemBlock = exo_reg.get_element_block(bmSet.getUnstructuredBlockName(bm.getID()));

checkEntityContainerZeroCopyFields(cat_reg.get_element_blocks());

bool exo_foo_1_exists = exo_elemBlock->field_exists("foo_1");
bool cat_foo_1_exists = cat_elemBlock->field_exists("foo_1");
EXPECT_TRUE(exo_foo_1_exists);
EXPECT_TRUE(cat_foo_1_exists);
if(exo_foo_1_exists && cat_foo_1_exists)
EXPECT_TRUE(exo_elemBlock->get_field("foo_1") == cat_elemBlock->get_field("foo_1"));

}

TEST_F(Iocatalyst_DatabaseIOTest, Exodus_Prop_IGNORE_REALN_FIELDS_OFF)
{
Iocatalyst::BlockMesh bm;
setBlockMeshSize(2, 2, 2);

bm.addTransientCellField("foo_1", 2);
bm.addTransientCellField("foo_2", 3);
bm.addTransientCellField("foo_1", 3);
bm.addTransientCellField("foo_2", 2);
bm.addTransientCellField("foo_3", 4);


Expand All @@ -209,12 +235,26 @@ TEST_F(Iocatalyst_DatabaseIOTest, Exodus_Prop_IGNORE_REALN_FIELDS_OFF)
auto cat_elemBlock = cat_reg.get_element_block(bmSet.getUnstructuredBlockName(bm.getID()));
auto exo_elemBlock = exo_reg.get_element_block(bmSet.getUnstructuredBlockName(bm.getID()));

checkEntityContainerZeroCopyFields(cat_reg.get_element_blocks());

bool exo_foo_exists = exo_elemBlock->field_exists("foo");
bool cat_foo_exists = cat_elemBlock->field_exists("foo");
EXPECT_TRUE(exo_foo_exists);
EXPECT_TRUE(cat_foo_exists);
if(exo_foo_exists && cat_foo_exists)
EXPECT_TRUE(exo_elemBlock->get_field("foo") == cat_elemBlock->get_field("foo"));

//Check field data for equality
auto cat_field = cat_elemBlock->get_fieldref("foo");
std::vector<std::byte> dcBuffer(cat_field.get_size());
cat_elemBlock->get_field_data("foo", Data(dcBuffer), dcBuffer.size());

exo_reg.begin_state(1);
auto exo_field = exo_elemBlock->get_fieldref("foo");
std::vector<std::byte> deBuffer(exo_field.get_size());
exo_elemBlock->get_field_data("foo", Data(deBuffer), deBuffer.size());
EXPECT_EQ(dcBuffer, deBuffer);

}

TEST_F(Iocatalyst_DatabaseIOTest, Exodus_Prop_FIELD_SUFFIX_SEPARATOR)
Expand Down Expand Up @@ -249,6 +289,8 @@ TEST_F(Iocatalyst_DatabaseIOTest, Exodus_Prop_FIELD_SUFFIX_SEPARATOR)
auto cat_elemBlock = cat_reg.get_element_block(bmSet.getUnstructuredBlockName(bm.getID()));
auto exo_elemBlock = exo_reg.get_element_block(bmSet.getUnstructuredBlockName(bm.getID()));

checkEntityContainerZeroCopyFields(cat_reg.get_element_blocks());

bool exo_foo_x_exists = exo_elemBlock->field_exists("foo_x");
bool cat_foo_x_exists = cat_elemBlock->field_exists("foo_x");
EXPECT_TRUE(exo_foo_x_exists);
Expand All @@ -262,6 +304,17 @@ TEST_F(Iocatalyst_DatabaseIOTest, Exodus_Prop_FIELD_SUFFIX_SEPARATOR)
EXPECT_TRUE(cat_bar_exists);
if(exo_bar_exists && cat_bar_exists)
EXPECT_TRUE(exo_elemBlock->get_field("bar") == cat_elemBlock->get_field("bar"));

//Check bar field data for equality
auto cat_field = cat_elemBlock->get_fieldref("bar");
std::vector<std::byte> dcBuffer(cat_field.get_size());
cat_elemBlock->get_field_data("bar", Data(dcBuffer), dcBuffer.size());

exo_reg.begin_state(1);
auto exo_field = exo_elemBlock->get_fieldref("bar");
std::vector<std::byte> deBuffer(exo_field.get_size());
exo_elemBlock->get_field_data("bar", Data(deBuffer), deBuffer.size());
EXPECT_EQ(dcBuffer, deBuffer);

}

Expand Down Expand Up @@ -294,12 +347,25 @@ TEST_F(Iocatalyst_DatabaseIOTest, Exodus_Prop_FIELD_STRIP_TRAILING_UNDERSCORE)
auto cat_elemBlock = cat_reg.get_element_block(bmSet.getUnstructuredBlockName(bm.getID()));
auto exo_elemBlock = exo_reg.get_element_block(bmSet.getUnstructuredBlockName(bm.getID()));

checkEntityContainerZeroCopyFields(cat_reg.get_element_blocks());

bool exo_foo_exists = exo_elemBlock->field_exists("foo");
bool cat_foo_exists = cat_elemBlock->field_exists("foo");
EXPECT_TRUE(exo_foo_exists);
EXPECT_TRUE(cat_foo_exists);
if(exo_foo_exists && cat_foo_exists)
EXPECT_TRUE(exo_elemBlock->get_field("foo") == cat_elemBlock->get_field("foo"));

//Check field data for equality
auto cat_field = cat_elemBlock->get_fieldref("foo");
std::vector<std::byte> dcBuffer(cat_field.get_size());
cat_elemBlock->get_field_data("foo", Data(dcBuffer), dcBuffer.size());

exo_reg.begin_state(1);
auto exo_field = exo_elemBlock->get_fieldref("foo");
std::vector<std::byte> deBuffer(exo_field.get_size());
exo_elemBlock->get_field_data("foo", Data(deBuffer), deBuffer.size());
EXPECT_EQ(dcBuffer, deBuffer);

}

Expand All @@ -325,6 +391,7 @@ TEST_F(Iocatalyst_DatabaseIOTest, Exodus_Prop_SURFACE_SPLIT_TYPE)
Ioss::Region cat_reg(cat_d);

Ioss::SideSetContainer cat_sideSets = cat_reg.get_sidesets();
checkEntityContainerZeroCopyFields(cat_sideSets);

EXPECT_TRUE(cat_sideSets.empty())<<"Cat sidesets not empty when different SURFACE_SPLIT_TYPE";

Expand Down

0 comments on commit 93707f4

Please sign in to comment.