Skip to content

Commit

Permalink
Added CombineH5 Pybindings and related test
Browse files Browse the repository at this point in the history
  • Loading branch information
Aastha Bagree committed Aug 22, 2023
1 parent c73a443 commit 1ea6c6a
Show file tree
Hide file tree
Showing 8 changed files with 213 additions and 1 deletion.
2 changes: 1 addition & 1 deletion src/IO/H5/CombineH5.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ size_t get_number_of_elements(const std::vector<std::string>& input_filenames,
}
return total_elements;
}
} // namespace
}
namespace h5 {

void combine_h5(const std::string& file_prefix, const std::string& subfile_name,
Expand Down
2 changes: 2 additions & 0 deletions src/IO/H5/CombineH5.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#include "Utilities/StdHelpers.hpp"

namespace h5 {

void combine_h5(const std::string& file_prefix, const std::string& subfile_name,
const std::string& output);

} // namespace h5
2 changes: 2 additions & 0 deletions src/IO/H5/Python/Bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <pybind11/pybind11.h>

#include "IO/H5/Python/CombineH5.hpp"
#include "IO/H5/Python/Dat.hpp"
#include "IO/H5/Python/File.hpp"
#include "IO/H5/Python/TensorData.hpp"
Expand All @@ -19,4 +20,5 @@ PYBIND11_MODULE(_Pybindings, m) { // NOLINT
py_bindings::bind_h5dat(m);
py_bindings::bind_h5vol(m);
py_bindings::bind_tensordata(m);
py_bindings::bind_h5combine(m);
}
1 change: 1 addition & 0 deletions src/IO/H5/Python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ spectre_python_add_module(
VolumeData.cpp
PYTHON_FILES
__init__.py
CombineH5.py
DeleteSubfiles.py
ExtendConnectivityData.py
ExtractDatFromH5.py
Expand Down
20 changes: 20 additions & 0 deletions src/IO/H5/Python/CombineH5.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Distributed under the MIT License.
// See LICENSE.txt for details.

#include "IO/H5/Python/CombineH5.hpp"

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <string>

#include "IO/H5/CombineH5.hpp"

namespace py = pybind11;

namespace py_bindings {
void bind_h5combine(py::module& m) {
// Wrapper for combining h5 files
m.def("combine_h5", &h5::combine_h5, py::arg("file_prefix"),
py::arg("subfile_name"), py::arg("output"));
}
} // namespace py_bindings
11 changes: 11 additions & 0 deletions src/IO/H5/Python/CombineH5.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Distributed under the MIT License.
// See LICENSE.txt for details.

#pragma once

#include <pybind11/pybind11.h>

namespace py_bindings {
// NOLINTNEXTLINE(google-runtime-references)
void bind_h5combine(pybind11::module& m);
} // namespace py_bindings
17 changes: 17 additions & 0 deletions tests/Unit/IO/H5/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,23 @@ target_link_libraries(
Utilities
)

spectre_add_python_bindings_test(
"Unit.IO.H5.CombineH5.Python"
"Test_CombineH5.py"
"unit;IO;H5;Python"
PyH5
)

if(${BUILD_PYTHON_BINDINGS})
# Test is a bit slow because it writes a bunch of plot files to verify
# the argument handling works.
set_tests_properties(
"Unit.IO.H5.CombineH5.Python"
PROPERTIES
TIMEOUT 80
)
endif()

spectre_add_python_bindings_test(
"Unit.IO.H5.Python"
"Test_H5.py"
Expand Down
159 changes: 159 additions & 0 deletions tests/Unit/IO/H5/Test_CombineH5.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
# Distributed under the MIT License.
# See LICENSE.txt for details.

import os
import unittest

import numpy as np

import spectre.IO.H5 as spectre_h5
from spectre import Informer
from spectre.DataStructures import DataVector
from spectre.IO.H5 import ElementVolumeData, TensorComponent, combine_h5
from spectre.Spectral import Basis, Quadrature


class TestCombineH5(unittest.TestCase):
# Test Fixtures
def setUp(self):
# The tests in this class combine 2 HDF5 files to generate one,
# using the Combine_H5 functionality.
self.file_name1 = os.path.join(
Informer.unit_test_build_path(), "IO/TestVolumeData0.h5"
)
self.file_name2 = os.path.join(
Informer.unit_test_build_path(), "IO/TestVolumeData1.h5"
)

self.output_file = os.path.join(
Informer.unit_test_build_path(), "IO/TestOutput"
)

if os.path.isfile(self.file_name1):
os.remove(self.file_name1)
if os.path.isfile(self.file_name2):
os.remove(self.file_name2)
if os.path.isfile(self.output_file + "0.h5"):
os.remove(self.output_file + "0.h5")

# Initializing attributes
grid_names1 = ["[B0(L0I0,L0I0,L1I0)]"]
grid_names2 = ["[B0(L1I0,L0I0,L0I0)]"]
observation_values = {0: 7.0, 1: 1.3}
basis = Basis.Legendre
quad = Quadrature.Gauss
self.observation_ids = [0, 1]

# Writing ElementVolume data and TensorComponent Data to first file
self.h5_file1 = spectre_h5.H5File(file_name=self.file_name1, mode="a")
self.tensor_component_data1 = np.array([[0.0], [0.3], [0.6]])
self.h5_file1.insert_vol("/element_data", version=0)
self.h5_file1.close_current_object()
self.vol_file1 = self.h5_file1.get_vol(path="/element_data")

self.element_vol_data_file_1 = [
ElementVolumeData(
element_name=grid_names1[0],
components=[
TensorComponent(
"field_1", DataVector(self.tensor_component_data1[i])
),
TensorComponent(
"field_2",
DataVector(self.tensor_component_data1[i + 1]),
),
],
extents=3 * [2],
basis=3 * [basis],
quadrature=3 * [quad],
)
for i, observation_id in enumerate(self.observation_ids)
]

# Write extents and tensor volume data to the volfile
for i, observation_id in enumerate(self.observation_ids):
self.vol_file1.write_volume_data(
observation_id,
observation_values[observation_id],
[
self.element_vol_data_file_1[i],
],
)

# Store initial connectivity data
self.initial_h5_connectivity = self.vol_file1.get_tensor_component(
self.observation_ids[0], "connectivity"
).data

self.h5_file1.close()

# Writing ElementVolume data and TensorComponent Data to second file
self.h5_file2 = spectre_h5.H5File(file_name=self.file_name2, mode="a")
self.tensor_component_data2 = np.array([[1.0], [0.13], [0.16]])
self.h5_file2.insert_vol("/element_data", version=0)
self.h5_file2.close_current_object()
self.vol_file2 = self.h5_file2.get_vol(path="/element_data")

self.element_vol_data_file_2 = [
ElementVolumeData(
element_name=grid_names2[0],
components=[
TensorComponent(
"field_1", DataVector(self.tensor_component_data2[i])
),
TensorComponent(
"field_2",
DataVector(self.tensor_component_data2[i + 1]),
),
],
extents=3 * [2],
basis=3 * [basis],
quadrature=3 * [quad],
)
for i, observation_id in enumerate(self.observation_ids)
]

# Write extents and tensor volume data to the volfile
for i, observation_id in enumerate(self.observation_ids):
self.vol_file2.write_volume_data(
observation_id,
observation_values[observation_id],
[
self.element_vol_data_file_2[i],
],
)
self.h5_file2.close()

def tearDown(self):
self.h5_file1.close()
self.h5_file2.close()
if os.path.isfile(self.file_name1):
os.remove(self.file_name1)
if os.path.isfile(self.file_name2):
os.remove(self.file_name2)
if os.path.isfile(self.output_file + "0.h5"):
os.remove(self.output_file + "0.h5")

def test_combine_h5(self):
# Run the combine_h5 command and check if any feature (for eg.
# connectivity length has increased due to combining two files)

combine_h5(self.file_name1[:-4], "element_data", self.output_file)
h5_output = spectre_h5.H5File(
file_name=self.output_file + "0.h5", mode="a"
)
output_vol = h5_output.get_vol(path="/element_data")

# Extracts the connectivity data from the volume file
# If length of final connectivity is more, combine_h5
# has successfully merged the two HDF5 files.

final_h5_connectivity = output_vol.get_tensor_component(
self.observation_ids[0], "connectivity"
).data

assert len(self.initial_h5_connectivity) < len(final_h5_connectivity)


if __name__ == "__main__":
unittest.main(verbosity=2)

0 comments on commit 1ea6c6a

Please sign in to comment.