Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Variable-Based iteration layout #855

Merged
merged 11 commits into from
Apr 23, 2021
Next Next commit
Step-based iteration layout
  • Loading branch information
franzpoeschel committed Apr 22, 2021
commit 75f436faa85edaa2f86ec0528a810967f80bca35
6 changes: 4 additions & 2 deletions include/openPMD/IO/ADIOS/ADIOS2IOHandler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
#include "openPMD/auxiliary/Option.hpp"
#include "openPMD/backend/Writable.hpp"
#include "openPMD/config.hpp"
#include "openPMD/IterationEncoding.hpp"

#if openPMD_HAVE_ADIOS2
# include <adios2.h>
Expand Down Expand Up @@ -224,6 +225,7 @@ class ADIOS2IOHandlerImpl

private:
adios2::ADIOS m_ADIOS;
IterationEncoding m_iterationEncoding = IterationEncoding::groupBased;
/**
* The ADIOS2 engine type, to be passed to adios2::IO::SetEngine
*/
Expand Down Expand Up @@ -1367,7 +1369,7 @@ class ADIOS2IOHandler : public AbstractIOHandler
{
#if openPMD_HAVE_ADIOS2

friend class ADIOS2IOHandlerImpl;
friend class ADIOS2IOHandlerImpl;

private:
ADIOS2IOHandlerImpl m_impl;
Expand All @@ -1386,7 +1388,7 @@ friend class ADIOS2IOHandlerImpl;
}
catch( ... )
{
std::cerr << "[~ADIOS2IOHandler] An error occurred." << std::endl;
std::cerr << "[~ADIOS2IOHandler] An error occurred." << std::endl;
}
}

Expand Down
1 change: 1 addition & 0 deletions include/openPMD/IO/AbstractIOHandlerImpl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ class AbstractIOHandlerImpl
*
* The operation should overwrite existing file positions, even when the Writable was already marked written.
* The path parameters.path may contain multiple levels (e.g. first/second/third/). This path should be relative (i.e. it should not start with a slash "/").
* The number of levels may be zero, i.e. parameters.path may be an empty string.
* The Writables file position should correspond to the complete opened path (i.e. first/second/third/ should be assigned to the Writables file position).
* The Writable should be marked written when the operation completes successfully.
*/
Expand Down
9 changes: 7 additions & 2 deletions include/openPMD/IO/IOTask.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "openPMD/backend/Attribute.hpp"
#include "openPMD/ChunkInfo.hpp"
#include "openPMD/Dataset.hpp"
#include "openPMD/IterationEncoding.hpp"

#include <memory>
#include <map>
Expand Down Expand Up @@ -108,7 +109,8 @@ template<>
struct OPENPMDAPI_EXPORT Parameter< Operation::CREATE_FILE > : public AbstractParameter
{
Parameter() = default;
Parameter(Parameter const & p) : AbstractParameter(), name(p.name) {}
Parameter(Parameter const & p) :
AbstractParameter(), name(p.name), encoding(p.encoding) {}

std::unique_ptr< AbstractParameter >
clone() const override
Expand All @@ -118,13 +120,15 @@ struct OPENPMDAPI_EXPORT Parameter< Operation::CREATE_FILE > : public AbstractPa
}

std::string name = "";
IterationEncoding encoding = IterationEncoding::groupBased;
};

template<>
struct OPENPMDAPI_EXPORT Parameter< Operation::OPEN_FILE > : public AbstractParameter
{
Parameter() = default;
Parameter(Parameter const & p) : AbstractParameter(), name(p.name) {}
Parameter(Parameter const & p) :
AbstractParameter(), name(p.name), encoding(p.encoding) {}

std::unique_ptr< AbstractParameter >
clone() const override
Expand All @@ -134,6 +138,7 @@ struct OPENPMDAPI_EXPORT Parameter< Operation::OPEN_FILE > : public AbstractPara
}

std::string name = "";
IterationEncoding encoding = IterationEncoding::groupBased;
};

template<>
Expand Down
4 changes: 3 additions & 1 deletion include/openPMD/Iteration.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,13 +156,15 @@ class Iteration : public LegacyAttributable

struct DeferredParseAccess
{
std::string index;
std::string path;
uint64_t iteration = 0;
bool fileBased = false;
std::string filename;
};

void flushFileBased(std::string const&, uint64_t);
void flushGroupBased(uint64_t);
void flushVariableBased(uint64_t);
void flush();
void deferParseAccess( DeferredParseAccess );
/*
Expand Down
2 changes: 1 addition & 1 deletion include/openPMD/IterationEncoding.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ namespace openPMD
*/
enum class IterationEncoding
{
fileBased, groupBased
fileBased, groupBased, variableBased
};

std::ostream&
Expand Down
13 changes: 10 additions & 3 deletions include/openPMD/Series.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -342,13 +342,20 @@ class SeriesImpl : public AttributableImpl

std::unique_ptr< ParsedInput > parseInput(std::string);
void init(std::shared_ptr< AbstractIOHandler >, std::unique_ptr< ParsedInput >);
void initDefaults();
void initDefaults( IterationEncoding );
std::future< void > flush_impl(
iterations_iterator begin,
iterations_iterator end,
FlushLevel );
void flushFileBased( iterations_iterator begin, iterations_iterator end );
void flushGroupBased( iterations_iterator begin, iterations_iterator end );
/*
* Group-based and variable-based iteration layouts share a lot of logic
* (realistically, the variable-based iteration layout only throws out
* one layer in the hierarchy).
* As a convention, methods that deal with both layouts are called
* .*GorVBased, short for .*GroupOrVariableBased
*/
void flushGorVBased( iterations_iterator begin, iterations_iterator end );
void flushMeshesPath();
void flushParticlesPath();
void readFileBased( );
Expand All @@ -361,7 +368,7 @@ class SeriesImpl : public AttributableImpl
* as of yet. Such a facility will be required upon implementing things such
* as resizable datasets.
*/
void readGroupBased( bool init = true );
void readGorVBased( bool init = true );
void readBase();
std::string iterationFilename( uint64_t i );
void openIteration( uint64_t index, Iteration iteration );
Expand Down
2 changes: 1 addition & 1 deletion include/openPMD/backend/Attributable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ class AttributableImpl
std::vector< std::string > myPath() const;

void flushAttributes();
void readAttributes();
void readAttributes( bool reread = false );

/** Retrieve the value of a floating point Attribute of user-defined precision with ensured type-safety.
*
Expand Down
7 changes: 4 additions & 3 deletions src/IO/ADIOS/ADIOS1IOHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ ADIOS1IOHandlerImpl::flush()
case O::CREATE_PATH:
createPath(i.writable, deref_dynamic_cast< Parameter< O::CREATE_PATH > >(i.parameter.get()));
break;
case O::OPEN_PATH:
openPath(i.writable, deref_dynamic_cast< Parameter< O::OPEN_PATH > >(i.parameter.get()));
break;
case O::CREATE_DATASET:
createDataset(i.writable, deref_dynamic_cast< Parameter< O::CREATE_DATASET > >(i.parameter.get()));
break;
Expand Down Expand Up @@ -129,9 +132,6 @@ ADIOS1IOHandlerImpl::flush()
case O::EXTEND_DATASET:
extendDataset(i.writable, deref_dynamic_cast< Parameter< O::EXTEND_DATASET > >(i.parameter.get()));
break;
case O::OPEN_PATH:
openPath(i.writable, deref_dynamic_cast< Parameter< O::OPEN_PATH > >(i.parameter.get()));
break;
case O::CLOSE_PATH:
closePath(i.writable, deref_dynamic_cast< Parameter< O::CLOSE_PATH > >(i.parameter.get()));
break;
Expand Down Expand Up @@ -243,6 +243,7 @@ ADIOS1IOHandler::enqueue(IOTask const& i)
{
case Operation::CREATE_FILE:
case Operation::CREATE_PATH:
case Operation::OPEN_PATH:
case Operation::CREATE_DATASET:
case Operation::OPEN_FILE:
case Operation::WRITE_ATT:
Expand Down
36 changes: 32 additions & 4 deletions src/IO/ADIOS/ADIOS2IOHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ void ADIOS2IOHandlerImpl::createFile(
VERIFY( success, "[ADIOS2] Could not create directory." );
}

m_iterationEncoding = parameters.encoding;
associateWithFile( writable, shared_name );
this->m_dirty.emplace( shared_name );
getFileData( shared_name ).m_mode = adios2::Mode::Write; // WORKAROUND
Expand Down Expand Up @@ -470,6 +471,7 @@ ADIOS2IOHandlerImpl::openFile(
writable->written = true;
writable->abstractFilePosition = std::make_shared< ADIOS2FilePosition >( );

m_iterationEncoding = parameters.encoding;
// enforce opening the file
// lazy opening is deathly in parallel situations
getFileData( file );
Expand Down Expand Up @@ -512,7 +514,9 @@ void ADIOS2IOHandlerImpl::openPath(
std::string prefix =
filePositionToString( setAndGetFilePosition( writable->parent ) );
std::string suffix = auxiliary::removeSlashes( parameters.path );
std::string infix = auxiliary::ends_with( prefix, '/' ) ? "" : "/";
std::string infix = suffix.empty() || auxiliary::ends_with( prefix, '/' )
? ""
: "/";

/* ADIOS has no concept for explicitly creating paths.
* They are implicitly created with the paths of variables/attributes. */
Expand Down Expand Up @@ -1525,9 +1529,27 @@ namespace detail
adios2::Dims const & count,
bool const constantDims )
{
adios2::Variable< T > var =
IO.DefineVariable< T >( name, shape, start, count, constantDims );
if ( !var )
/*
* Step/Variable-based iteration layout:
* The variable may already be defined from a previous step,
* so check if it's already here.
*/
adios2::Variable< T > var = IO.InquireVariable< T >( name );
if( !var )
{
var = IO.DefineVariable< T >(
name, shape, start, count, constantDims );
}
else
{
var.SetShape( shape );
if( count.size() > 0 )
{
var.SetSelection( { start, count } );
}
}

if( !var )
{
throw std::runtime_error(
"[ADIOS2] Internal error: Could not create Variable '" + name + "'." );
Expand Down Expand Up @@ -2206,6 +2228,12 @@ namespace detail
"bp4", "bp3", "hdf5", "file"
};

// step/variable-based iteration encoding requires the new schema
if( m_impl->m_iterationEncoding == IterationEncoding::variableBased )
{
m_impl->m_schema = ADIOS2Schema::schema_2021_02_09;
}

// set engine type
bool isStreaming = false;
{
Expand Down
11 changes: 7 additions & 4 deletions src/IO/ADIOS/CommonADIOS1IOHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -677,10 +677,13 @@ CommonADIOS1IOHandlerImpl::openPath(
{
/* Sanitize path */
std::string path = parameters.path;
if( auxiliary::starts_with(path, '/') )
path = auxiliary::replace_first(path, "/", "");
if( !auxiliary::ends_with(path, '/') )
path += '/';
if( !path.empty() )
{
if( auxiliary::starts_with(path, '/') )
path = auxiliary::replace_first(path, "/", "");
if( !auxiliary::ends_with(path, '/') )
path += '/';
}

writable->written = true;
writable->abstractFilePosition = std::make_shared< ADIOS1FilePosition >(path);
Expand Down
7 changes: 4 additions & 3 deletions src/IO/ADIOS/ParallelADIOS1IOHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,9 @@ ParallelADIOS1IOHandlerImpl::flush()
case O::CREATE_PATH:
createPath(i.writable, deref_dynamic_cast< Parameter< O::CREATE_PATH > >(i.parameter.get()));
break;
case O::OPEN_PATH:
openPath(i.writable, deref_dynamic_cast< Parameter< O::OPEN_PATH > >(i.parameter.get()));
break;
case O::CREATE_DATASET:
createDataset(i.writable, deref_dynamic_cast< Parameter< O::CREATE_DATASET > >(i.parameter.get()));
break;
Expand Down Expand Up @@ -151,9 +154,6 @@ ParallelADIOS1IOHandlerImpl::flush()
case O::EXTEND_DATASET:
extendDataset(i.writable, deref_dynamic_cast< Parameter< O::EXTEND_DATASET > >(i.parameter.get()));
break;
case O::OPEN_PATH:
openPath(i.writable, deref_dynamic_cast< Parameter< O::OPEN_PATH > >(i.parameter.get()));
break;
case O::CLOSE_PATH:
closePath(i.writable, deref_dynamic_cast< Parameter< O::CLOSE_PATH > >(i.parameter.get()));
break;
Expand Down Expand Up @@ -265,6 +265,7 @@ ParallelADIOS1IOHandler::enqueue(IOTask const& i)
{
case Operation::CREATE_FILE:
case Operation::CREATE_PATH:
case Operation::OPEN_PATH:
case Operation::CREATE_DATASET:
case Operation::OPEN_FILE:
case Operation::WRITE_ATT:
Expand Down
24 changes: 14 additions & 10 deletions src/IO/HDF5/HDF5IOHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -528,19 +528,23 @@ HDF5IOHandlerImpl::openPath(

/* Sanitize path */
std::string path = parameters.path;
if( auxiliary::starts_with(path, '/') )
path = auxiliary::replace_first(path, "/", "");
if( !auxiliary::ends_with(path, '/') )
path += '/';
if( !path.empty() )
{
if( auxiliary::starts_with(path, '/') )
path = auxiliary::replace_first(path, "/", "");
if( !auxiliary::ends_with(path, '/') )
path += '/';
path_id = H5Gopen(node_id,
path.c_str(),
H5P_DEFAULT);
VERIFY(path_id >= 0, "[HDF5] Internal error: Failed to open HDF5 group during path opening");

path_id = H5Gopen(node_id,
path.c_str(),
H5P_DEFAULT);
VERIFY(path_id >= 0, "[HDF5] Internal error: Failed to open HDF5 group during path opening");
herr_t status;
status = H5Gclose(path_id);
VERIFY(status == 0, "[HDF5] Internal error: Failed to close HDF5 group during path opening");
}

herr_t status;
status = H5Gclose(path_id);
VERIFY(status == 0, "[HDF5] Internal error: Failed to close HDF5 group during path opening");
status = H5Gclose(node_id);
VERIFY(status == 0, "[HDF5] Internal error: Failed to close HDF5 group during path opening");

Expand Down
Loading