Skip to content

Commit

Permalink
Merge pull request #1473 from LLNL/task/white238/quadrature_data_sidre
Browse files Browse the repository at this point in the history
Fix `MFEMSidreDataCollection::LoadExternalData` and add test cases for various `LoadExternalData` functions
  • Loading branch information
white238 authored Jan 13, 2025
2 parents 8f678a9 + 3066766 commit b811391
Show file tree
Hide file tree
Showing 7 changed files with 981 additions and 13 deletions.
3 changes: 3 additions & 0 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ to use Open Cascade's file I/O capabilities in support of Quest applications.
- ItemCollection and its child classes MapCollection, ListCollection, and IndexedCollection were moved from Sidre
to core. The namespace prefix for these classes is now `axom::` instead of `axom::sidre`. The internal usage of
these types within Sidre Datastore and Group is unchanged.
- `MFEMSidreDataCollection::LoadExternalData` now takes two optional string parameters, one that is a
filename (defaults to the `name` member variable) and the other is a `Group` path relative to the base of
the Data Collection itself (defaults to the root of the `DataStore`).

### Deprecated

Expand Down
39 changes: 36 additions & 3 deletions src/axom/sidre/core/MFEMSidreDataCollection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -953,18 +953,51 @@ void MFEMSidreDataCollection::Load(const std::string& path,
}
}

void MFEMSidreDataCollection::LoadExternalData(const std::string& path)
void MFEMSidreDataCollection::LoadExternalData(const std::string& filename,
const std::string& group_name)
{
// Use the user-provided group name or the DataCollection's base group
Group* grp = m_bp_grp->getDataStore()->getRoot();
if(!group_name.empty())
{
#if defined(AXOM_USE_MPI) && defined(MFEM_USE_MPI)
if(m_comm != MPI_COMM_NULL)
{
SLIC_ERROR(
"Loading external data with a group name is not supported in "
"parallel.");
}
#endif

SLIC_ERROR_IF(!m_bp_grp->hasGroup(group_name),
axom::fmt::format(
"MFEMSidreDataCollection does not have a Sidre Group '{}'",
group_name));
grp = m_bp_grp->getGroup(group_name);
}

// Use the user-provided file name or the DataCollection's file name
std::string path = name;
if(!filename.empty())
{
path = filename;
}
path = get_file_path(path);

#if defined(AXOM_USE_MPI) && defined(MFEM_USE_MPI)
if(m_comm != MPI_COMM_NULL)
{
// The conduit abstraction appears to automatically handle the ".root"
// suffix, but the IOManager does not, so it gets added here
using axom::utilities::string::endsWith;
std::string suffixedPath = endsWith(path, ".root") ? path : path + ".root";
IOManager reader(m_comm);
reader.loadExternalData(m_bp_grp->getDataStore()->getRoot(), path);
reader.loadExternalData(grp, suffixedPath);
}
else
#endif
{
m_bp_grp->loadExternalData(path);
grp->loadExternalData(path);
}
}

Expand Down
10 changes: 8 additions & 2 deletions src/axom/sidre/core/MFEMSidreDataCollection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -476,8 +476,14 @@ class MFEMSidreDataCollection : public mfem::DataCollection
Load(get_file_path(name), "sidre_hdf5");
}

/// Load external data after registering externally owned fields.
void LoadExternalData(const std::string& path);
/** @brief Load external data for the whole MFEMSidreDataCollection unless a specific group name is given.
* @note This must happen after registering externally owned fields.
*
* @param filename Optional base filename to be loaded, function will add prefix path and cycle
* @param group_name Optional group name to load external data, relative to base of MFEMSidreDataCollection
**/
void LoadExternalData(const std::string& filename = "",
const std::string& group_name = "");

/** @brief Updates the DataCollection's cycle, time, and time-step variables
with the values from the data store. */
Expand Down
1 change: 1 addition & 0 deletions src/axom/sidre/tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ set(gtest_sidre_tests
sidre_native_layout.cpp
sidre_attribute.cpp
sidre_mcarray.cpp
sidre_read_write_userdefined_data.cpp
)

set(gtest_sidre_C_tests
Expand Down
53 changes: 53 additions & 0 deletions src/axom/sidre/tests/sidre_mfem_datacollection.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,59 @@ TEST(sidre_datacollection, dc_reload_gf_vdim)
EXPECT_TRUE(sdc_reader.verifyMeshBlueprint());
}

TEST(sidre_datacollection, dc_reload_externaldata)
{
const std::string view_name = "external_data";

// Create DC
auto mesh = mfem::Mesh::MakeCartesian1D(10);
const bool owns_mesh_data = true;
MFEMSidreDataCollection sdc_writer(testName(), &mesh, owns_mesh_data);
// After creation set owning to false so data doesn't get double free'd by reader and writer
sdc_writer.SetOwnData(false);
#if defined(AXOM_USE_MPI) && defined(MFEM_USE_MPI)
sdc_writer.SetComm(MPI_COMM_WORLD);
#endif
sdc_writer.SetCycle(0);

// Create external buffer and add it to DC
axom::Array<int64_t> writer_data {1, 2, 3, 4};
axom::sidre::Group* writer_bp_group = sdc_writer.GetBPGroup();
axom::sidre::View* writer_external_view =
writer_bp_group->createView(view_name);
writer_external_view->setExternalDataPtr(axom::sidre::INT64_ID,
writer_data.size(),
writer_data.data());
EXPECT_TRUE(writer_bp_group->hasView(view_name));

sdc_writer.Save();

// Load DC from file
MFEMSidreDataCollection sdc_reader(testName());
#if defined(AXOM_USE_MPI) && defined(MFEM_USE_MPI)
sdc_reader.SetComm(MPI_COMM_WORLD);
#endif
// Note: this will recreate the external view but not load the external data yet
sdc_reader.Load();
axom::sidre::Group* reader_bp_group = sdc_reader.GetBPGroup();
EXPECT_TRUE(reader_bp_group->hasView(view_name));
axom::sidre::View* reader_external_view = reader_bp_group->getView(view_name);

// Create external buffer with wrong data and load previously saved data into it
axom::Array<int64_t> reader_data {5, 6, 7, 8};
reader_external_view->setExternalDataPtr(reader_data.data());
sdc_reader.LoadExternalData();

EXPECT_TRUE(writer_data.size() == reader_data.size());
SLIC_INFO(axom::fmt::format("~~~~ {}", writer_data.size()));
for(int i = 0; i < reader_data.size(); ++i)
{
SLIC_INFO(axom::fmt::format("~~~~ {} == {}", reader_data[i], writer_data[i]));
EXPECT_TRUE(reader_data[i] == writer_data[i]);
}
SLIC_INFO("~~~ END");
}

TEST(sidre_datacollection, dc_reload_mesh)
{
const std::string field_name = "test_field";
Expand Down
Loading

0 comments on commit b811391

Please sign in to comment.