Skip to content
Snippets Groups Projects
Commit ad527fdd authored by williamfgc's avatar williamfgc Committed by GitHub
Browse files

Merge pull request #224 from pnorbert/fix-variable-definitions

Fix the variable definition initialization rules and add test for Def…
parents c9254edf c68ed079
No related branches found
No related tags found
No related merge requests found
......@@ -70,6 +70,8 @@ int main(int argc, char *argv[])
// Get io settings from the config file or
// create one with default settings here
adios2::IO &io = adios.DeclareIO("Output");
// io.SetEngine("ADIOS1Writer");
// io.AddTransport("File", {{"library", "MPI"}});
/*
* Define joinable local array: type, name, global and local size
......
......@@ -29,7 +29,7 @@ void Engine::Write(Variable<T> &variable, const T *values)
{
if (m_DebugMode)
{
variable.CheckDims("in call to Write");
variable.CheckDimsBeforeWrite("Write(" + variable.m_Name + ")");
}
DoWrite(variable, values);
......
......@@ -60,8 +60,7 @@ void VariableBase::SetSelection(const Dims start, const Dims count)
}
if (m_ShapeID == ShapeID::GlobalArray &&
(m_Shape.size() != m_Count.size() ||
m_Shape.size() != m_Start.size()))
(m_Shape.size() != count.size() || m_Shape.size() != start.size()))
{
throw std::invalid_argument("ERROR: count and start must be the "
"same size as shape for variable " +
......@@ -154,89 +153,147 @@ void VariableBase::ClearTransforms() noexcept { m_TransformsInfo.clear(); }
// PRIVATE
void VariableBase::InitShapeType()
{
if (!m_Shape.empty() && m_Start.empty() && m_Count.empty())
if (!m_Shape.empty())
{
if (m_DebugMode)
if (std::count(m_Shape.begin(), m_Shape.end(), JoinedDim) == 1)
{
if (m_ConstantDims)
if (!m_Start.empty() &&
std::count(m_Start.begin(), m_Start.end(), 0) != m_Start.size())
{
throw std::invalid_argument(
"ERROR: isConstantShape (true) argument is invalid "
"with empty start and count "
"arguments\n");
throw std::invalid_argument("ERROR: The Start array must be "
"empty or full-zero when defining "
"a Joined Array in call to "
"DefineVariable " +
m_Name + "\n");
}
m_ShapeID = ShapeID::JoinedArray;
}
m_ShapeID = ShapeID::GlobalArray;
}
else if (!m_Shape.empty() && m_Shape.size() == m_Start.size() &&
m_Shape.size() == m_Count.size())
{
if (m_DebugMode)
else if (m_Start.empty() && m_Count.empty())
{
auto lf_LargerThanError = [&](const unsigned int i,
const std::string dims1,
const std::string dims2) {
const std::string iString(std::to_string(i));
throw std::invalid_argument(
"ERROR: " + dims1 + "[" + iString + "] > " + dims2 + "[" +
iString + "], in DefineVariable " + m_Name + "\n");
};
for (unsigned int i = 0; i < m_Shape.size(); ++i)
if (m_Shape.size() == 1 && m_Shape.front() == LocalValueDim)
{
if (m_Count[i] > m_Shape[i])
m_ShapeID = ShapeID::LocalValue;
m_SingleValue = true;
}
else
{
if (m_DebugMode)
{
lf_LargerThanError(i, "count", "shape");
if (m_ConstantDims)
{
throw std::invalid_argument(
"ERROR: isConstantShape (true) argument is invalid "
"with empty start and count "
"arguments in call to "
"DefineVariable " +
m_Name + "\n");
}
}
if (m_Start[i] > m_Shape[i])
m_ShapeID = ShapeID::GlobalArray;
}
}
else if (m_Shape.size() == m_Start.size() &&
m_Shape.size() == m_Count.size())
{
if (m_DebugMode)
{
auto lf_LargerThanError = [&](const unsigned int i,
const std::string dims1,
const std::string dims2) {
const std::string iString(std::to_string(i));
throw std::invalid_argument(
"ERROR: " + dims1 + "[" + iString + "] > " + dims2 +
"[" + iString + "], in DefineVariable " + m_Name +
"\n");
};
for (unsigned int i = 0; i < m_Shape.size(); ++i)
{
lf_LargerThanError(i, "start", "shape");
if (m_Count[i] > m_Shape[i])
{
lf_LargerThanError(i, "count", "shape");
}
if (m_Start[i] > m_Shape[i])
{
lf_LargerThanError(i, "start", "shape");
}
}
}
m_ShapeID = ShapeID::GlobalArray;
}
else
{
throw std::invalid_argument("ERROR: the "
"combination of shape, start and count "
"arguments is inconsistent, in call to "
"DefineVariable " +
m_Name + "\n");
}
m_ShapeID = ShapeID::GlobalArray;
}
else if (m_Shape.empty() && m_Start.empty() && m_Count.empty())
{
m_ShapeID = ShapeID::GlobalValue;
m_SingleValue = true;
}
else if (m_Shape.empty() && m_Start.empty() && !m_Count.empty())
{
m_ShapeID = ShapeID::LocalArray;
}
else if (m_Shape.size() == 1 && m_Shape.front() == LocalValueDim)
{
m_ShapeID = ShapeID::LocalValue;
m_SingleValue = true;
}
else if (!m_Shape.empty() &&
std::count(m_Shape.begin(), m_Shape.end(), JoinedDim) == 1)
else //(m_Shape.empty())
{
m_ShapeID = ShapeID::JoinedArray;
if (m_Start.empty())
{
if (m_Count.empty())
{
m_ShapeID = ShapeID::GlobalValue;
m_SingleValue = true;
}
else if (m_Start.empty() && !m_Count.empty())
{
m_ShapeID = ShapeID::LocalArray;
}
}
else
{
throw std::invalid_argument(
"ERROR: if the "
"shape is empty, start must be empty as well, in call to "
"DefineVariable " +
m_Name + "\n");
}
}
else if (!m_Shape.empty() &&
std::count(m_Shape.begin(), m_Shape.end(), JoinedDim) > 1)
/* Extra checks for invalid settings */
if (m_DebugMode)
CheckDimsCommon("DefineVariable(" + m_Name + ")");
}
void VariableBase::CheckDimsCommon(const std::string hint) const
{
if (m_ShapeID != ShapeID::LocalValue)
{
throw std::invalid_argument("ERROR: variable can't have more than one "
"JoinedDim in shape argument, in call to "
"DefineVariable " +
m_Name + "\n");
if ((!m_Shape.empty() &&
std::count(m_Shape.begin(), m_Shape.end(), LocalValueDim) > 0) ||
(!m_Start.empty() &&
std::count(m_Start.begin(), m_Start.end(), LocalValueDim) > 0) ||
(!m_Count.empty() &&
std::count(m_Count.begin(), m_Count.end(), LocalValueDim) > 0))
{
throw std::invalid_argument("ERROR: LocalValueDim is only "
"allowed in a {LocalValueDim} "
"shape in call to " +
hint + "\n");
}
}
else
if ((!m_Shape.empty() &&
std::count(m_Shape.begin(), m_Shape.end(), JoinedDim) > 1) ||
(!m_Start.empty() &&
std::count(m_Start.begin(), m_Start.end(), JoinedDim) > 0) ||
(!m_Count.empty() &&
std::count(m_Count.begin(), m_Count.end(), JoinedDim) > 0))
{
throw std::invalid_argument("ERROR: the "
"combination of shape, start and count "
"arguments is inconsistent, in call to "
"DefineVariable " +
m_Name + "\n");
throw std::invalid_argument("ERROR: JoinedDim is only allowed once in "
"Shape and cannot appear in Start/Count in "
"call to " +
hint + "\n");
}
}
void VariableBase::CheckDims(const std::string hint) const
void VariableBase::CheckDimsBeforeWrite(const std::string hint) const
{
if (m_ShapeID == ShapeID::GlobalArray)
{
......@@ -245,10 +302,12 @@ void VariableBase::CheckDims(const std::string hint) const
throw std::invalid_argument(
"ERROR: GlobalArray variable " + m_Name +
" start and count dimensions must be defined by either "
"DefineVariable or a Selection " +
"DefineVariable or a Selection in call to " +
hint + "\n");
}
}
CheckDimsCommon(hint);
// TODO need to think more exceptions here
}
......
......@@ -137,9 +137,14 @@ public:
/** Registered transforms */
std::vector<TransformInfo> m_TransformsInfo;
/** Self-check dims according to type, called right after DefineVariable and
* SetSelection.
* @param hint extra debugging info for the exception */
void CheckDimsCommon(const std::string hint) const;
/** Self-check dims according to type, called from Engine before Write
* @param hint extra debugging info for the exception */
void CheckDims(const std::string hint) const;
void CheckDimsBeforeWrite(const std::string hint) const;
private:
const bool m_DebugMode = false;
......
......@@ -6,4 +6,8 @@
add_executable(TestADIOSInterfaceWrite TestADIOSInterfaceWrite.cpp)
target_link_libraries(TestADIOSInterfaceWrite adios2 gtest gtest_main)
add_executable(TestADIOSDefineVariable TestADIOSDefineVariable.cpp)
target_link_libraries(TestADIOSDefineVariable adios2 gtest gtest_main)
gtest_add_tests(TARGET TestADIOSInterfaceWrite)
gtest_add_tests(TARGET TestADIOSDefineVariable)
\ No newline at end of file
#include <cstdint>
#include <iostream>
#include <stdexcept>
#include <adios2.h>
#include <gtest/gtest.h>
class ADIOSDefineVariableTest : public ::testing::Test
{
public:
ADIOSDefineVariableTest() : adios(true), io(adios.DeclareIO("TestIO")) {}
protected:
// virtual void SetUp() { }
// virtual void TearDown() { }
adios2::ADIOS adios;
adios2::IO &io;
};
TEST_F(ADIOSDefineVariableTest, DefineGlobalValue)
{
// Define ADIOS global value
auto &globalvalue = io.DefineVariable<int>("globalvalue");
// Verify the return type is as expected
::testing::StaticAssertTypeEq<decltype(globalvalue),
adios2::Variable<int> &>();
// Verify the dimensions, name, and type are correct
ASSERT_EQ(globalvalue.m_Shape.size(), 0);
EXPECT_EQ(globalvalue.m_Start.size(), 0);
EXPECT_EQ(globalvalue.m_Count.size(), 0);
EXPECT_EQ(globalvalue.m_Name, "globalvalue");
EXPECT_EQ(globalvalue.m_Type, "int");
}
TEST_F(ADIOSDefineVariableTest, DefineLocalValue)
{
// Define ADIOS local value (a value changing across processes)
auto &localvalue =
io.DefineVariable<int>("localvalue", {adios2::LocalValueDim});
// Verify the return type is as expected
::testing::StaticAssertTypeEq<decltype(localvalue),
adios2::Variable<int> &>();
// Verify the dimensions, name, and type are correct
ASSERT_EQ(localvalue.m_Shape.size(), 1);
EXPECT_EQ(localvalue.m_Shape[0], adios2::LocalValueDim);
EXPECT_EQ(localvalue.m_Start.size(), 0);
EXPECT_EQ(localvalue.m_Count.size(), 0);
EXPECT_EQ(localvalue.m_Name, "localvalue");
EXPECT_EQ(localvalue.m_Type, "int");
}
TEST_F(ADIOSDefineVariableTest, DefineGlobalArray)
{
// Define ADIOS global array
std::size_t n = 50;
auto &globalarray = io.DefineVariable<int>("globalarray", {100, n, 30},
{50, n / 2, 0}, {10, n / 2, 30});
// Verify the return type is as expected
::testing::StaticAssertTypeEq<decltype(globalarray),
adios2::Variable<int> &>();
// Verify the dimensions, name, and type are correct
ASSERT_EQ(globalarray.m_Shape.size(), 3);
EXPECT_EQ(globalarray.m_Shape[0], 100);
EXPECT_EQ(globalarray.m_Shape[1], n);
EXPECT_EQ(globalarray.m_Shape[2], 30);
EXPECT_EQ(globalarray.m_Start.size(), 3);
EXPECT_EQ(globalarray.m_Start[0], 50);
EXPECT_EQ(globalarray.m_Start[1], n / 2);
EXPECT_EQ(globalarray.m_Start[2], 0);
EXPECT_EQ(globalarray.m_Count.size(), 3);
EXPECT_EQ(globalarray.m_Count[0], 10);
EXPECT_EQ(globalarray.m_Count[1], n / 2);
EXPECT_EQ(globalarray.m_Count[2], 30);
EXPECT_EQ(globalarray.m_Name, "globalarray");
EXPECT_EQ(globalarray.m_Type, "int");
}
TEST_F(ADIOSDefineVariableTest, DefineGlobalArrayWithSelections)
{
// Define ADIOS global array with postponed size definition in SetSelection
std::size_t n = 50;
auto &globalarray = io.DefineVariable<int>("globalarray", {100, n, 30});
// Verify the return type is as expected
::testing::StaticAssertTypeEq<decltype(globalarray),
adios2::Variable<int> &>();
// Make a 3D selection to describe the local dimensions of the
// variable we write and its offsets in the global spaces
adios2::SelectionBoundingBox sel({50, n / 2, 0}, {10, n / 2, 30});
globalarray.SetSelection(sel);
// Verify the dimensions, name, and type are correct
ASSERT_EQ(globalarray.m_Shape.size(), 3);
EXPECT_EQ(globalarray.m_Shape[0], 100);
EXPECT_EQ(globalarray.m_Shape[1], n);
EXPECT_EQ(globalarray.m_Shape[2], 30);
EXPECT_EQ(globalarray.m_Start.size(), 3);
EXPECT_EQ(globalarray.m_Start[0], 50);
EXPECT_EQ(globalarray.m_Start[1], n / 2);
EXPECT_EQ(globalarray.m_Start[2], 0);
EXPECT_EQ(globalarray.m_Count.size(), 3);
EXPECT_EQ(globalarray.m_Count[0], 10);
EXPECT_EQ(globalarray.m_Count[1], n / 2);
EXPECT_EQ(globalarray.m_Count[2], 30);
EXPECT_EQ(globalarray.m_Name, "globalarray");
EXPECT_EQ(globalarray.m_Type, "int");
}
TEST_F(ADIOSDefineVariableTest, DefineGlobalArrayConstantDims)
{
// Define ADIOS global array with locked-down dimensions
std::size_t n = 50;
auto &globalarray = io.DefineVariable<int>(
"globalarray", {100, n, 30}, {50, n / 2, 0}, {10, n / 2, 30}, true);
// Verify the return type is as expected
::testing::StaticAssertTypeEq<decltype(globalarray),
adios2::Variable<int> &>();
adios2::SelectionBoundingBox sel({50, n / 2, 0}, {10, n / 2, 30});
EXPECT_THROW(globalarray.SetSelection(sel), std::invalid_argument);
// Verify the dimensions, name, and type are correct
ASSERT_EQ(globalarray.m_Shape.size(), 3);
EXPECT_EQ(globalarray.m_Shape[0], 100);
EXPECT_EQ(globalarray.m_Shape[1], n);
EXPECT_EQ(globalarray.m_Shape[2], 30);
EXPECT_EQ(globalarray.m_Start.size(), 3);
EXPECT_EQ(globalarray.m_Start[0], 50);
EXPECT_EQ(globalarray.m_Start[1], n / 2);
EXPECT_EQ(globalarray.m_Start[2], 0);
EXPECT_EQ(globalarray.m_Count.size(), 3);
EXPECT_EQ(globalarray.m_Count[0], 10);
EXPECT_EQ(globalarray.m_Count[1], n / 2);
EXPECT_EQ(globalarray.m_Count[2], 30);
EXPECT_EQ(globalarray.m_Name, "globalarray");
EXPECT_EQ(globalarray.m_Type, "int");
}
TEST_F(ADIOSDefineVariableTest, DefineGlobalArrayInvalidLocalValueDim)
{
// Define ADIOS global array
std::size_t n = 50;
adios2::Variable<int> *globalarray;
EXPECT_THROW(globalarray = &io.DefineVariable<int>(
"globalarray", {100, adios2::LocalValueDim, 30},
{50, n / 2, 0}, {10, n / 2, 30}),
std::invalid_argument);
}
TEST_F(ADIOSDefineVariableTest, DefineLocalArray)
{
// Define ADIOS local array (no global dimensions, no offsets)
std::size_t n = 50;
auto &localarray =
io.DefineVariable<int>("localarray", {}, {}, {10, n / 2, 30});
// Verify the return type is as expected
::testing::StaticAssertTypeEq<decltype(localarray),
adios2::Variable<int> &>();
// Verify the dimensions, name, and type are correct
ASSERT_EQ(localarray.m_Shape.size(), 0);
EXPECT_EQ(localarray.m_Start.size(), 0);
EXPECT_EQ(localarray.m_Count.size(), 3);
EXPECT_EQ(localarray.m_Count[0], 10);
EXPECT_EQ(localarray.m_Count[1], n / 2);
EXPECT_EQ(localarray.m_Count[2], 30);
EXPECT_EQ(localarray.m_Name, "localarray");
EXPECT_EQ(localarray.m_Type, "int");
EXPECT_EQ(localarray.m_ShapeID, adios2::ShapeID::LocalArray);
}
TEST_F(ADIOSDefineVariableTest, DefineLocalArrayWithSelection)
{
// Define ADIOS local array with postponed size definition in SetSelection
std::size_t n = 50;
auto &localarray = io.DefineVariable<int>(
"localarray", {}, {},
{adios2::UnknownDim, adios2::UnknownDim, adios2::UnknownDim});
// Verify the return type is as expected
::testing::StaticAssertTypeEq<decltype(localarray),
adios2::Variable<int> &>();
ASSERT_EQ(localarray.m_Shape.size(), 0);
EXPECT_EQ(localarray.m_Start.size(), 0);
EXPECT_EQ(localarray.m_Count.size(), 3);
EXPECT_EQ(localarray.m_Count[0], 0);
EXPECT_EQ(localarray.m_Count[1], 0);
EXPECT_EQ(localarray.m_Count[2], 0);
EXPECT_EQ(localarray.m_Name, "localarray");
EXPECT_EQ(localarray.m_Type, "int");
EXPECT_EQ(localarray.m_ShapeID, adios2::ShapeID::LocalArray);
// Make a 3D selection to describe the local dimensions of the
// variable we write
adios2::SelectionBoundingBox sel({}, {10, n / 2, 30});
localarray.SetSelection(sel);
adios2::SelectionBoundingBox selbad({50, n / 2, 0}, {10, n / 2, 30});
EXPECT_THROW(localarray.SetSelection(selbad), std::invalid_argument);
// Verify the dimensions, name, and type are correct
ASSERT_EQ(localarray.m_Shape.size(), 0);
EXPECT_EQ(localarray.m_Start.size(), 0);
EXPECT_EQ(localarray.m_Count.size(), 3);
EXPECT_EQ(localarray.m_Count[0], 10);
EXPECT_EQ(localarray.m_Count[1], n / 2);
EXPECT_EQ(localarray.m_Count[2], 30);
EXPECT_EQ(localarray.m_Name, "localarray");
EXPECT_EQ(localarray.m_Type, "int");
EXPECT_EQ(localarray.m_ShapeID, adios2::ShapeID::LocalArray);
}
TEST_F(ADIOSDefineVariableTest, DefineLocalArrayConstantDims)
{
// Define ADIOS local array with locked down dimensions
std::size_t n = 50;
auto &localarray =
io.DefineVariable<int>("localarray", {}, {}, {10, n / 2, 30}, true);
// Verify the return type is as expected
::testing::StaticAssertTypeEq<decltype(localarray),
adios2::Variable<int> &>();
adios2::SelectionBoundingBox sel({}, {10, n / 2, 30});
EXPECT_THROW(localarray.SetSelection(sel), std::invalid_argument);
// Verify the dimensions, name, and type are correct
ASSERT_EQ(localarray.m_Shape.size(), 0);
EXPECT_EQ(localarray.m_Start.size(), 0);
EXPECT_EQ(localarray.m_Count.size(), 3);
EXPECT_EQ(localarray.m_Count[0], 10);
EXPECT_EQ(localarray.m_Count[1], n / 2);
EXPECT_EQ(localarray.m_Count[2], 30);
EXPECT_EQ(localarray.m_Name, "localarray");
EXPECT_EQ(localarray.m_Type, "int");
EXPECT_EQ(localarray.m_ShapeID, adios2::ShapeID::LocalArray);
}
TEST_F(ADIOSDefineVariableTest, DefineLocalArrayInvalidOffsets)
{
// Define ADIOS local array but try to add offsets
std::size_t n = 50;
adios2::Variable<int> *localarray;
EXPECT_THROW(localarray = &io.DefineVariable<int>(
"localarray", {}, {50, n / 2, 0}, {10, n / 2, 30}),
std::invalid_argument);
}
TEST_F(ADIOSDefineVariableTest, DefineJoinedArrayFirstDim)
{
// Define ADIOS joined array
std::size_t n = 50;
auto &joinedarray = io.DefineVariable<int>(
"joinedarray", {adios2::JoinedDim, n, 30}, {}, {10, n, 30});
// Verify the return type is as expected
::testing::StaticAssertTypeEq<decltype(joinedarray),
adios2::Variable<int> &>();
// Verify the dimensions, name, and type are correct
ASSERT_EQ(joinedarray.m_Shape.size(), 3);
EXPECT_EQ(joinedarray.m_Shape[0], adios2::JoinedDim);
EXPECT_EQ(joinedarray.m_Shape[1], n);
EXPECT_EQ(joinedarray.m_Shape[2], 30);
EXPECT_EQ(joinedarray.m_Start.size(), 0);
EXPECT_EQ(joinedarray.m_Count.size(), 3);
EXPECT_EQ(joinedarray.m_Count[0], 10);
EXPECT_EQ(joinedarray.m_Count[1], n);
EXPECT_EQ(joinedarray.m_Count[2], 30);
EXPECT_EQ(joinedarray.m_Name, "joinedarray");
EXPECT_EQ(joinedarray.m_Type, "int");
}
TEST_F(ADIOSDefineVariableTest, DefineJoinedArraySecondDim)
{
// Define ADIOS joined array
std::size_t n = 50;
auto &joinedarray = io.DefineVariable<int>(
"joinedarray", {n, adios2::JoinedDim, 30}, {0, 0, 0}, {n, 10, 30});
// Verify the return type is as expected
::testing::StaticAssertTypeEq<decltype(joinedarray),
adios2::Variable<int> &>();
// Verify the dimensions, name, and type are correct
ASSERT_EQ(joinedarray.m_Shape.size(), 3);
EXPECT_EQ(joinedarray.m_Shape[0], n);
EXPECT_EQ(joinedarray.m_Shape[1], adios2::JoinedDim);
EXPECT_EQ(joinedarray.m_Shape[2], 30);
EXPECT_EQ(joinedarray.m_Start.size(), 3);
EXPECT_EQ(joinedarray.m_Start[0], 0);
EXPECT_EQ(joinedarray.m_Start[1], 0);
EXPECT_EQ(joinedarray.m_Start[2], 0);
EXPECT_EQ(joinedarray.m_Count.size(), 3);
EXPECT_EQ(joinedarray.m_Count[0], n);
EXPECT_EQ(joinedarray.m_Count[1], 10);
EXPECT_EQ(joinedarray.m_Count[2], 30);
EXPECT_EQ(joinedarray.m_Name, "joinedarray");
EXPECT_EQ(joinedarray.m_Type, "int");
}
TEST_F(ADIOSDefineVariableTest, DefineJoinedArrayTooManyJoinedDims)
{
// Define ADIOS joined array
std::size_t n = 50;
adios2::Variable<int> *joinedarray;
EXPECT_THROW(joinedarray = &io.DefineVariable<int>(
"joinedarray", {n, adios2::JoinedDim, adios2::JoinedDim},
{}, {n, 50, 30}),
std::invalid_argument);
}
TEST_F(ADIOSDefineVariableTest, DefineJoinedArrayInvalidStart)
{
// Define ADIOS joined array
std::size_t n = 10;
std::size_t WrongValue = 1;
adios2::Variable<int> *joinedarray;
// Start must be empty or full zero array
EXPECT_THROW(
joinedarray = &io.DefineVariable<int>(
"joinedarray", {adios2::JoinedDim, 50}, {0, WrongValue}, {n, 50}),
std::invalid_argument);
}
int main(int argc, char **argv)
{
#ifdef ADIOS2_HAVE_MPI
MPI_Init(nullptr, nullptr);
#endif
::testing::InitGoogleTest(&argc, argv);
int result = RUN_ALL_TESTS();
#ifdef ADIOS2_HAVE_MPI
MPI_Finalize();
#endif
return result;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment