diff --git a/examples/heatTransfer/read/CMakeLists.txt b/examples/heatTransfer/read/CMakeLists.txt index 7f3e9c4589874abe0d85fc6b7a065ad2fbc7ed4e..8527738fb7c8a25bbd19a2488d6c06ec8bbb5fa9 100644 --- a/examples/heatTransfer/read/CMakeLists.txt +++ b/examples/heatTransfer/read/CMakeLists.txt @@ -4,9 +4,18 @@ #------------------------------------------------------------------------------# if(ADIOS_USE_MPI) + + find_package(MPI COMPONENTS C REQUIRED) + add_executable(heatTransfer_read_adios2 heatRead_adios2.cpp PrintData.cpp) + target_include_directories(heatTransfer_read_adios2 + PRIVATE ${MPI_C_INCLUDE_PATH} + ) + target_link_libraries(heatTransfer_read_adios2 + adios2 ${MPI_C_LIBRARIES} + ) + if(ADIOS_USE_ADIOS1) find_package(ADIOS1 REQUIRED) - find_package(MPI COMPONENTS C REQUIRED) add_executable(heatTransfer_read_adios1 heatRead_adios1.cpp PrintData.cpp) target_include_directories(heatTransfer_read_adios1 @@ -16,5 +25,6 @@ if(ADIOS_USE_MPI) adios1::adios ${MPI_C_LIBRARIES} ) endif() + endif() diff --git a/examples/heatTransfer/read/heatRead_adios2.cpp b/examples/heatTransfer/read/heatRead_adios2.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9d19ad85244b5c2d17404b6f1b66c58de85c8936 --- /dev/null +++ b/examples/heatTransfer/read/heatRead_adios2.cpp @@ -0,0 +1,111 @@ + +#include <mpi.h> + +#include "adios2.h" + +#include <cstdint> +#include <iomanip> +#include <iostream> +#include <math.h> +#include <memory> +#include <stdexcept> +#include <string> +#include <vector> + +#include "PrintData.h" + +int main(int argc, char *argv[]) +{ + MPI_Init(&argc, &argv); + + if (argc < 2) + { + std::cout << "Not enough arguments: need an input file\n"; + return 1; + } + const char *inputfile = argv[1]; + + /* World comm spans all applications started with the same aprun command + on a Cray XK6. So we have to split and create the local + 'world' communicator for the reader only. + In normal start-up, the communicator will just equal the MPI_COMM_WORLD. + */ + + int wrank, wnproc; + MPI_Comm_rank(MPI_COMM_WORLD, &wrank); + MPI_Comm_size(MPI_COMM_WORLD, &wnproc); + MPI_Barrier(MPI_COMM_WORLD); + + const unsigned int color = 2; + MPI_Comm mpiReaderComm; + MPI_Comm_split(MPI_COMM_WORLD, color, wrank, &mpiReaderComm); + + int rank, nproc; + MPI_Comm_rank(mpiReaderComm, &rank); + MPI_Comm_size(mpiReaderComm, &nproc); + + adios::ADIOS ad("adios2.xml", mpiReaderComm, adios::Verbose::INFO); + + // Define method for engine creation + // 1. Get method def from config file or define new one + + adios::Method &bpReaderSettings = ad.DeclareMethod("input"); + if (!bpReaderSettings.IsUserDefined()) + { + // if not defined by user, we can change the default settings + // BPFileWriter is the default engine + bpReaderSettings.SetEngine("ADIOS1Reader"); + // Allow an extra thread for data processing + bpReaderSettings.AllowThreads(1); + // ISO-POSIX file is the default transport + // Passing parameters to the transport + bpReaderSettings.AddTransport("File", "verbose=4"); + } + + auto bpReader = ad.Open(inputfile, "r", mpiReaderComm, bpReaderSettings); + + if (bpReader == nullptr) + throw std::ios_base::failure("ERROR: failed to open ADIOS bpReader\n"); + + unsigned int gndx; + unsigned int gndy; + bpReader->Read<unsigned int>("gndx", &gndx); + bpReader->Read<unsigned int>("gndy", &gndy); + + if (rank == 0) + { + std::cout << "gndx = " << gndx << std::endl; + std::cout << "gndy = " << gndy << std::endl; + } + + // 1D decomposition of the columns, which is inefficient for reading! + std::vector<uint64_t> readsize({gndx, gndy / nproc}); + std::vector<uint64_t> offset({0LL, rank * readsize[1]}); + if (rank == nproc - 1) + { + // last process should read all the rest of columns + readsize[1] = gndy - readsize[1] * (nproc - 1); + } + + std::cout << "rank " << rank << " reads " << readsize[1] + << " columns from offset " << offset[1] << std::endl; + + adios::Variable<double> *vT = bpReader->InquireVariableDouble("T"); + + double *T = new double[vT->GetNSteps() * readsize[0] * readsize[1]]; + + // Create a 2D selection for the subset + adios::SelectionBoundingBox sel(offset, readsize); + vT->SetSelection(sel); + + // Arrays are read by scheduling one or more of them + // and performing the reads at once + bpReader->ScheduleRead(*vT, T); + bpReader->PerformReads(adios::PerformReadMode::BLOCKINGREAD); + + printData(T, readsize.data(), offset.data(), rank, vT->GetNSteps()); + bpReader->Close(); + delete[] T; + MPI_Finalize(); + return 0; +} diff --git a/source/adios2/core/Engine.cpp b/source/adios2/core/Engine.cpp index 76ded52fae6704f798c76c4692a3efa314c0f8bd..d8bcbd1eb5679d61ae02d86054cf8c37c0884a6f 100644 --- a/source/adios2/core/Engine.cpp +++ b/source/adios2/core/Engine.cpp @@ -280,11 +280,15 @@ VariableCompound *Engine::InquireVariableCompound(const std::string & /*name*/, } void Engine::Read(Variable<double> & /*variable*/, const double * /*values*/) {} -void Engine::ScheduleRead(Variable<double> & /*variable*/, - const double * /*values*/) +void Engine::ScheduleRead(Variable<double> & /*variable*/, double * /*values*/) +{ +} +void Engine::ScheduleRead(const std::string /*variableName*/, + double * /*values*/) { } void Engine::Release() {} +void Engine::PerformReads(PerformReadMode /*mode*/){}; // PROTECTED void Engine::Init() {} diff --git a/source/adios2/core/Engine.h b/source/adios2/core/Engine.h index cea4802d4a9caf53a85fb1a24496eeb757a118b4..dec2565ddb5e3064d50842b88c88a58d1eb640fb 100644 --- a/source/adios2/core/Engine.h +++ b/source/adios2/core/Engine.h @@ -311,7 +311,7 @@ public: * @param values pointer passed from the application */ template <class T> - void ScheduleRead(Variable<T> &variable, const T *values) + void ScheduleRead(Variable<T> &variable, T *values) { ScheduleRead(variable, values); } @@ -322,7 +322,7 @@ public: * @param values */ template <class T> - void ScheduleRead(const std::string variableName, const T *values) + void ScheduleRead(const std::string variableName, T *values) { ScheduleRead(variableName, values); } @@ -333,7 +333,7 @@ public: * @param values */ template <class T> - void ScheduleRead(Variable<T> &variable, const T &values) + void ScheduleRead(Variable<T> &variable, T &values) { ScheduleRead(variable, &values); } @@ -344,7 +344,7 @@ public: * @param values */ template <class T> - void ScheduleRead(const std::string variableName, const T &values) + void ScheduleRead(const std::string variableName, T &values) { ScheduleRead(variableName, &values); } @@ -364,7 +364,8 @@ public: */ void ScheduleRead() { ScheduleRead(nullptr, nullptr); } - virtual void ScheduleRead(Variable<double> &variable, const double *values); + virtual void ScheduleRead(Variable<double> &variable, double *values); + virtual void ScheduleRead(const std::string variableName, double *values); /** * Perform all scheduled reads, either blocking until all reads completed, @@ -372,7 +373,7 @@ public: * return immediately. * @param mode Blocking or non-blocking modes */ - void PerformReads(PerformReadMode mode); + virtual void PerformReads(PerformReadMode mode); /** * Reader application indicates that no more data will be read from the diff --git a/source/adios2/core/Variable.h b/source/adios2/core/Variable.h index 5b0fdbb5b81b94743e2860d7c15efb68fbfa3841..9493878377380304c8f6734b4239e9e51477ee47 100644 --- a/source/adios2/core/Variable.h +++ b/source/adios2/core/Variable.h @@ -76,11 +76,6 @@ public: */ std::vector<std::size_t> GetGlobalDimensions(); - /** Return the number of steps available for the variable - * @return Number of steps - */ - int GetSteps(); - void Monitor(std::ostream &logInfo) const noexcept { logInfo << "Variable: " << m_Name << "\n"; diff --git a/source/adios2/core/VariableBase.h b/source/adios2/core/VariableBase.h index aef3af0d3ab2b96817ec18b91b417a82155865f7..0061c8ec5a2abddb98f4255fad84966d02710a8b 100644 --- a/source/adios2/core/VariableBase.h +++ b/source/adios2/core/VariableBase.h @@ -133,6 +133,16 @@ public: ConvertUint64VectorToSizetVector(sel.m_Count, m_MemoryDimensions); ConvertUint64VectorToSizetVector(sel.m_Start, m_MemoryOffsets); } + + /** Return the number of steps available for the variable + * @return Number of steps + */ + int GetNSteps() { return m_nsteps; } + +private: + /* Values filled by InquireVariable() */ + int m_nsteps = + 1; ///< number of steps available in a file (or 1 in staging), }; } // end namespace diff --git a/source/adios2/engine/adios1/ADIOS1Reader.cpp b/source/adios2/engine/adios1/ADIOS1Reader.cpp index 7ec1ac27934ac73522c8d769e7fe4afe7f626ca0..b1ad2750dbc00e4072331460909a6ad18cb3fe54 100644 --- a/source/adios2/engine/adios1/ADIOS1Reader.cpp +++ b/source/adios2/engine/adios1/ADIOS1Reader.cpp @@ -27,9 +27,16 @@ ADIOS1Reader::ADIOS1Reader(ADIOS &adios, const std::string &name, { Init(); adios_read_init_method(m_ReadMethod, mpiComm, ""); + m_fh = adios_read_open(name.c_str(), m_ReadMethod, mpiComm, + ADIOS_LOCKMODE_CURRENT, 0.0); } -ADIOS1Reader::~ADIOS1Reader() { adios_read_finalize_method(m_ReadMethod); } +ADIOS1Reader::~ADIOS1Reader() +{ + if (m_fh != nullptr) + adios_read_close(m_fh); + adios_read_finalize_method(m_ReadMethod); +} Variable<void> * ADIOS1Reader::InquireVariable(const std::string &variableName, @@ -157,7 +164,40 @@ ADIOS1Reader::InquireVariableCompound(const std::string &variableName, return nullptr; } -void ADIOS1Reader::Close(const int transportIndex) {} +void ADIOS1Reader::ScheduleReadCommon(const std::string &name, + const Dims &ldims, const Dims &offs, + void *data) +{ + + uint64_t start[32], count[32]; + for (int i = 0; i < ldims.size(); i++) + { + start[i] = (uint64_t)offs[i]; + count[i] = (uint64_t)ldims[i]; + } + ADIOS_SELECTION *sel = + adios_selection_boundingbox(ldims.size(), start, count); + adios_schedule_read(m_fh, sel, name.c_str(), 1, 0, data); + adios_selection_delete(sel); +} + +void ADIOS1Reader::ScheduleRead(Variable<double> &variable, double *values) +{ + ScheduleReadCommon(variable.m_Name, variable.m_LocalDimensions, + variable.m_Offsets, (void *)values); +} + +void ADIOS1Reader::ScheduleRead(const std::string variableName, double *values) +{ + ScheduleRead(m_ADIOS.GetVariable<double>(variableName), values); +} + +void ADIOS1Reader::PerformReads(PerformReadMode mode) +{ + adios_perform_reads(m_fh, (int)mode); +} + +void ADIOS1Reader::Close(const int transportIndex) { adios_read_close(m_fh); } // PRIVATE void ADIOS1Reader::Init() diff --git a/source/adios2/engine/adios1/ADIOS1Reader.h b/source/adios2/engine/adios1/ADIOS1Reader.h index 51b9e044335625cdc6fd8274d408db3340ef24b0..720acbad605dd5ac6fb6802816f859cdad44ed5d 100644 --- a/source/adios2/engine/adios1/ADIOS1Reader.h +++ b/source/adios2/engine/adios1/ADIOS1Reader.h @@ -88,9 +88,14 @@ public: VariableCompound *InquireVariableCompound(const std::string &name, const bool readIn = true); + void ScheduleRead(Variable<double> &variable, double *values); + void ScheduleRead(const std::string variableName, double *values); + + void PerformReads(PerformReadMode mode); void Close(const int transportIndex = -1); private: + ADIOS_FILE *m_fh = nullptr; ///< ADIOS1 file handler void Init(); ///< called from constructor, gets the selected ADIOS1 /// transport method from settings void InitParameters(); @@ -110,6 +115,9 @@ private: return nullptr; // on failure } + void ScheduleReadCommon(const std::string &name, const Dims &ldims, + const Dims &offs, void *data); + enum ADIOS_READ_METHOD m_ReadMethod = ADIOS_READ_METHOD_BP; };