diff --git a/include/openPMD/Series.hpp b/include/openPMD/Series.hpp index 2000920c6e..a81fc0eda5 100644 --- a/include/openPMD/Series.hpp +++ b/include/openPMD/Series.hpp @@ -127,6 +127,33 @@ class Series : public Attributable */ Series& setMeshesPath(std::string const& meshesPath); + /** + * @throw no_such_attribute_error If optional attribute is not present. + * @return Vector with a String per (writing) MPI rank, indicating user- + * defined meta information per rank. Example: host name. + */ + chunk_assignment::RankMeta + mpiRanksMetaInfo() const; + + /** + * @brief Set the Mpi Ranks Meta Info attribute, i.e. a Vector with + * a String per (writing) MPI rank, indicating user- + * defined meta information per rank. Example: host name. + * + * @return Reference to modified series. + */ + Series & setMpiRanksMetaInfo( chunk_assignment::RankMeta ); + + /** + * @brief Set the Mpi Ranks Meta Info attribute, i.e. a Vector with + * a String per (writing) MPI rank, indicating user- + * defined meta information per rank. Example: host name. + * + * @return Reference to modified series. + */ + Series & + setMpiRanksMetaInfo( std::string const & myRankInfo ); + /** * @throw no_such_attribute_error If optional attribute is not present. * @return String representing the path to particle species, relative(!) to basePath. @@ -376,6 +403,9 @@ class Series : public Attributable std::shared_ptr< auxiliary::Option< WriteIterations > > m_writeIterations = std::make_shared< auxiliary::Option< WriteIterations > >(); +#if openPMD_HAVE_MPI + MPI_Comm m_communicator; +#endif }; // Series /** diff --git a/include/openPMD/auxiliary/Filesystem.hpp b/include/openPMD/auxiliary/Filesystem.hpp index 686cbf1384..a5d20250d7 100644 --- a/include/openPMD/auxiliary/Filesystem.hpp +++ b/include/openPMD/auxiliary/Filesystem.hpp @@ -100,5 +100,20 @@ std::string collective_file_read( std::string const & path, MPI_Comm ); #endif -} // namespace auxiliary -} // namespace openPMD + +struct no_such_file_error +{ +}; + +/** + * @brief Read a file line by line. + * + * @param path Path to the file. + * @return Lines of the read file, excluding newline characters. + * + * @throws no_such_file_error + */ +std::vector< std::string > +read_file_by_lines( std::string const & path ); +} // auxiliary +} // openPMD diff --git a/include/openPMD/auxiliary/MPI.hpp b/include/openPMD/auxiliary/MPI.hpp index 9527907e0f..04504d42af 100644 --- a/include/openPMD/auxiliary/MPI.hpp +++ b/include/openPMD/auxiliary/MPI.hpp @@ -1,5 +1,7 @@ #pragma once +#include "openPMD/config.hpp" + #if openPMD_HAVE_MPI # include diff --git a/src/Series.cpp b/src/Series.cpp index 6b9af1b9ef..7fb33431c3 100644 --- a/src/Series.cpp +++ b/src/Series.cpp @@ -20,6 +20,7 @@ */ #include "openPMD/auxiliary/Date.hpp" #include "openPMD/auxiliary/Filesystem.hpp" +#include "openPMD/auxiliary/MPI.hpp" #include "openPMD/auxiliary/StringManip.hpp" #include "openPMD/IO/AbstractIOHandler.hpp" #include "openPMD/IO/AbstractIOHandlerHelper.hpp" @@ -81,6 +82,7 @@ Series::Series( std::string const & options ) : iterations{ Container< Iteration, uint64_t >() } , m_iterationEncoding{ std::make_shared< IterationEncoding >() } + , m_communicator{ comm } { auto input = parseInput( filepath ); auto handler = @@ -182,6 +184,90 @@ Series::setMeshesPath(std::string const& mp) return *this; } +chunk_assignment::RankMeta +Series::mpiRanksMetaInfo() const +{ + std::vector< std::string > asContiguousVector; + try + { + asContiguousVector = + getAttribute( "rankMetaInfo" ).get< std::vector< std::string > >(); + } + catch( std::runtime_error const & ) + { + // workaround: if vector has length 1, some backends may report a + // single value instead of a vector + asContiguousVector = { + getAttribute( "rankMetaInfo" ).get< std::string >() + }; + } + chunk_assignment::RankMeta res; + for( size_t i = 0; i < asContiguousVector.size(); ++i ) + { + res[ i ] = std::move( asContiguousVector[ i ] ); + } + return res; +} + +Series & +Series::setMpiRanksMetaInfo( chunk_assignment::RankMeta rankMeta ) +{ + std::vector< std::string > asContiguousVector; + asContiguousVector.reserve( rankMeta.size() ); + try + { + for( size_t i = 0; i < rankMeta.size(); ++i ) + { + asContiguousVector.emplace_back( std::move( rankMeta.at( i ) ) ); + } + } + catch( std::out_of_range ) + { + throw std::runtime_error( "[setMpiRanksMetaInfo] Can only set meta " + "info for contiguous ranks 0 to n." ); + } + + setAttribute( "rankMetaInfo", std::move( asContiguousVector ) ); + return *this; +} + +Series & +Series::setMpiRanksMetaInfo( std::string const & myRankInfo ) +{ + if( auxiliary::starts_with( myRankInfo, '@' ) ) + { + // read from file + std::string fileName = auxiliary::replace_first( myRankInfo, "@", "" ); + std::vector< std::string > rankMeta; + try + { + rankMeta = auxiliary::read_file_by_lines( fileName ); + } + catch( auxiliary::no_such_file_error const & ) + { + std::cerr << "Not setting rank meta information, because file has " + "not been found: " + << fileName << std::endl; + return *this; + } + setAttribute( "rankMetaInfo", rankMeta ); + return *this; + } +#if openPMD_HAVE_MPI + int rank; + MPI_Comm_rank( m_communicator, &rank ); + std::vector< std::string > rankMeta = + auxiliary::collectStringsTo( m_communicator, 0, myRankInfo ); + if( rank == 0 ) + { + setAttribute( "rankMetaInfo", std::move( rankMeta ) ); + } + return *this; +#else + setAttribute( "rankMetaInfo", std::vector< std::string >{ myRankInfo } ); +#endif +} + std::string Series::particlesPath() const { diff --git a/src/auxiliary/Filesystem.cpp b/src/auxiliary/Filesystem.cpp index 4bd7765a4d..59fa0534c1 100644 --- a/src/auxiliary/Filesystem.cpp +++ b/src/auxiliary/Filesystem.cpp @@ -35,6 +35,8 @@ #include #include #include +#include +#include namespace openPMD @@ -258,5 +260,22 @@ collective_file_read( std::string const & path, MPI_Comm comm ) #endif -} // namespace auxiliary -} // namespace openPMD +std::vector< std::string > +read_file_by_lines( std::string const & path ) +{ + std::vector< std::string > res; + std::ifstream file( path, std::ios_base::in ); + if ( file.fail( ) ) + { + throw no_such_file_error( ); + } + std::string line; + while( std::getline( file, line ) ) + { + res.push_back( std::move( line ) ); + line = std::string( ); + } + return res; +} +} // auxiliary +} // openPMD diff --git a/test/CoreTest.cpp b/test/CoreTest.cpp index 0565a2fd0a..c09d7a0556 100644 --- a/test/CoreTest.cpp +++ b/test/CoreTest.cpp @@ -4,7 +4,7 @@ # define OPENPMD_protected public #endif -#include "openPMD/Chunk.hpp" +#include "openPMD/ChunkInfo.hpp" #include "openPMD/openPMD.hpp" #include @@ -56,7 +56,7 @@ print( ChunkTable const & table ) { for( auto const & chunk : table ) { - std::cout << "[Rank: " << chunk.mpi_rank << ",\tOffset: "; + std::cout << "[Rank: " << chunk.sourceID << ",\tOffset: "; for( auto offset : chunk.offset ) { std::cout << offset << ", ";