diff --git a/bindings/CXX11/adios2/cxx11/Query.cpp b/bindings/CXX11/adios2/cxx11/Query.cpp index 140d1485c6..099b68a818 100644 --- a/bindings/CXX11/adios2/cxx11/Query.cpp +++ b/bindings/CXX11/adios2/cxx11/Query.cpp @@ -14,6 +14,11 @@ QueryWorker::QueryWorker(const std::string &configFile, adios2::Engine &reader) delete m; } +void QueryWorker::GetResultCoverage(std::vector &touched_blockIDs) +{ + m_Worker->GetResultCoverage(touched_blockIDs); +} + void QueryWorker::GetResultCoverage(std::vector> &touched_blocks) { adios2::Box empty; @@ -26,4 +31,5 @@ void QueryWorker::GetResultCoverage(const adios2::Box &outputSelec if (m_Worker) return m_Worker->GetResultCoverage(outputSelection, touched_blocks); } -} + +} // namespace diff --git a/bindings/CXX11/adios2/cxx11/Query.h b/bindings/CXX11/adios2/cxx11/Query.h index 1b26ab62d6..0cd5750bbf 100644 --- a/bindings/CXX11/adios2/cxx11/Query.h +++ b/bindings/CXX11/adios2/cxx11/Query.h @@ -29,6 +29,7 @@ class QueryWorker // configFile has query, can be either xml or json QueryWorker(const std::string &configFile, adios2::Engine &engine); + void GetResultCoverage(std::vector &touched_block_ids); // touched_blocks is a list of regions specified by (start, count), // that contains data that satisfies the query file void GetResultCoverage(std::vector> &touched_blocks); diff --git a/bindings/Python/py11Query.cpp b/bindings/Python/py11Query.cpp index 0e82cae6bb..01c8cdb050 100644 --- a/bindings/Python/py11Query.cpp +++ b/bindings/Python/py11Query.cpp @@ -36,5 +36,12 @@ std::vector> Query::GetResult() return touched_blocks; } +std::vector Query::GetBlockIDs() +{ + std::vector touched_block_ids; + m_QueryWorker->GetResultCoverage(touched_block_ids); + return touched_block_ids; +} + } // py11 } // adios2 diff --git a/bindings/Python/py11Query.h b/bindings/Python/py11Query.h index b8cd29018b..64768f0b7d 100644 --- a/bindings/Python/py11Query.h +++ b/bindings/Python/py11Query.h @@ -34,6 +34,7 @@ class Query explicit operator bool() const noexcept; std::vector> GetResult(); + std::vector GetBlockIDs(); private: Query(adios2::query::Worker *qw); diff --git a/bindings/Python/py11glue.cpp b/bindings/Python/py11glue.cpp index b9f239b603..128c52d941 100644 --- a/bindings/Python/py11glue.cpp +++ b/bindings/Python/py11glue.cpp @@ -357,7 +357,8 @@ PYBIND11_MODULE(ADIOS2_PYTHON_MODULE_NAME, m) "adios2 query construction, a xml query File and a read engine", pybind11::arg("queryFile"), pybind11::arg("reader") = true) - .def("GetResult", &adios2::py11::Query::GetResult); + .def("GetResult", &adios2::py11::Query::GetResult) + .def("GetBlockIDs", &adios2::py11::Query::GetBlockIDs); pybind11::class_(m, "Variable") // Python 2 diff --git a/examples/basics/queryWorker/queryWorker.cpp b/examples/basics/queryWorker/queryWorker.cpp index 9d878714b7..c6cd4e32b9 100644 --- a/examples/basics/queryWorker/queryWorker.cpp +++ b/examples/basics/queryWorker/queryWorker.cpp @@ -1,16 +1,39 @@ -/* - * Distributed under the OSI-approved Apache License, Version 2.0. See - * accompanying file Copyright.txt for details. - */ - #include "adios2.h" #include #include +#include #include +#include +#include +#include #include #include +// touched block ids are printed. +void queryIDs(adios2::IO &queryIO, std::string &dataFileName, std::string &queryFile) +{ + adios2::Engine reader = queryIO.Open(dataFileName, adios2::Mode::Read, MPI_COMM_WORLD); + // adios2::QueryWorker* worker = NULL; + queryIO.SetParameter("StreamReader", "true"); + std::vector touched_blockIDs; + + while (reader.BeginStep() == adios2::StepStatus::OK) + { + adios2::QueryWorker w = adios2::QueryWorker(queryFile, reader); + w.GetResultCoverage(touched_blockIDs); + + std::cout << " Num touched blocks =" << touched_blockIDs.size() << std::endl; + for (auto n : touched_blockIDs) + { + std::cout << "\t[" << n << "] " << std::endl; + } + + reader.EndStep(); + } + reader.Close(); +} + void queryWithStreaming(adios2::IO &queryIO, std::string &dataFileName, std::string &queryFile) { adios2::Engine reader = queryIO.Open(dataFileName, adios2::Mode::Read, MPI_COMM_WORLD); @@ -23,7 +46,10 @@ void queryWithStreaming(adios2::IO &queryIO, std::string &dataFileName, std::str adios2::QueryWorker w = adios2::QueryWorker(queryFile, reader); w.GetResultCoverage(touched_blocks); - std::cout << " ... now can read out touched blocks ... size=" << touched_blocks.size() + std::cout << " Num touched regions =" + << touched_blocks.size() + // std::cout << " ... now can read out touched blocks ... size=" << + // touched_blocks.size() << std::endl; for (auto n : touched_blocks) { @@ -67,12 +93,6 @@ int main(int argc, char *argv[]) configFileName = argv[1]; dataFileName = argv[2]; - if (rank == 0) - { - std::cout << " using config file = " << configFileName << std::endl; - std::cout << " data file = " << dataFileName << std::endl; - } - adios2::ADIOS ad = adios2::ADIOS(configFileName, MPI_COMM_WORLD); adios2::IO queryIO = ad.DeclareIO("query"); @@ -82,8 +102,16 @@ int main(int argc, char *argv[]) { queryFile = argv[3]; } - std::cout << "Testing query file ..." << queryFile << std::endl; + if (rank == 0) + { + std::cout << " using config file = " << configFileName << std::endl; + std::cout << " data file = " << dataFileName << std::endl; + std::cout << " queryfile = " << queryFile << std::endl; + } + + queryIDs(queryIO, dataFileName, queryFile); + std::cout << "\n" << std::endl; queryWithStreaming(queryIO, dataFileName, queryFile); return 0; diff --git a/source/adios2/toolkit/query/BlockIndex.h b/source/adios2/toolkit/query/BlockIndex.h index 94890de269..b3a52afcb0 100644 --- a/source/adios2/toolkit/query/BlockIndex.h +++ b/source/adios2/toolkit/query/BlockIndex.h @@ -12,15 +12,6 @@ namespace query template class BlockIndex { - struct Tree - { - // - // ** no need to keep the original block. might be smaller than - // blockIndex typename Variable::BPInfo& m_BlockInfo; - // - std::vector::BPInfo> m_SubBlockInfo; - }; - public: BlockIndex(adios2::core::Variable *var, adios2::core::IO &io, adios2::core::Engine &reader) @@ -30,15 +21,20 @@ class BlockIndex void Generate(std::string &fromBPFile, const adios2::Params &inputs) {} - void Evaluate(const QueryVar &query, std::vector> &resultSubBlocks) + void Evaluate(const QueryVar &query, std::vector &resultBlockIDs) { + if (nullptr == m_VarPtr) + { + throw std::runtime_error("Unable to evaluate query! Invalid Variable detected"); + } + if (m_IdxReader.m_EngineType.find("5") != std::string::npos) // a bp5 reader - RunBP5Stat(query, resultSubBlocks); + RunBP5Stat(query, resultBlockIDs); else - RunBP4Stat(query, resultSubBlocks); + RunBP4Stat(query, resultBlockIDs); } - void RunBP5Stat(const QueryVar &query, std::vector> &hitBlocks) + void RunBP5Stat(const QueryVar &query, std::vector &hitBlocks) { size_t currStep = m_IdxReader.CurrentStep(); adios2::Dims currShape = m_VarPtr->Shape(); @@ -52,29 +48,40 @@ class BlockIndex } for (auto &blockInfo : MinBlocksInfo->BlocksInfo) { - Dims ss(MinBlocksInfo->Dims); - Dims cc(MinBlocksInfo->Dims); - for (std::vector::size_type i = 0; i < ss.size(); i++) - { - ss[i] = blockInfo.Start[i]; - cc[i] = blockInfo.Count[i]; - } - if (!query.TouchSelection(ss, cc)) - continue; - T bmin = *(T *)&blockInfo.MinMax.MinUnion; T bmax = *(T *)&blockInfo.MinMax.MaxUnion; bool isHit = query.m_RangeTree.CheckInterval(bmin, bmax); - if (isHit) + + if (!isHit) + continue; + + if (m_VarPtr->m_ShapeID != adios2::ShapeID::LocalArray) { - adios2::Box box = {ss, cc}; - hitBlocks.push_back(box); + Dims ss(MinBlocksInfo->Dims); + Dims cc(MinBlocksInfo->Dims); + for (std::vector::size_type i = 0; i < ss.size(); i++) + { + ss[i] = blockInfo.Start[i]; + cc[i] = blockInfo.Count[i]; + } + if (!query.TouchSelection(ss, cc)) + continue; + + if (isHit) + { + adios2::Box box = {ss, cc}; + hitBlocks.push_back(BlockHit(blockInfo.BlockID, box)); + } + } + else + { // local array + hitBlocks.push_back(BlockHit(blockInfo.BlockID)); } } delete MinBlocksInfo; } - void RunBP4Stat(const QueryVar &query, std::vector> &hitBlocks) + void RunBP4Stat(const QueryVar &query, std::vector &hitBlocks) { size_t currStep = m_IdxReader.CurrentStep(); adios2::Dims currShape = m_VarPtr->Shape(); @@ -86,45 +93,66 @@ class BlockIndex for (auto &blockInfo : varBlocksInfo) { - if (!query.TouchSelection(blockInfo.Start, blockInfo.Count)) + bool isHit = query.m_RangeTree.CheckInterval(blockInfo.Min, blockInfo.Max); + if (!isHit) continue; - if (blockInfo.MinMaxs.size() > 0) + if (m_VarPtr->m_ShapeID == adios2::ShapeID::LocalArray) { - adios2::helper::CalculateSubblockInfo(blockInfo.Count, blockInfo.SubBlockInfo); - unsigned int numSubBlocks = static_cast(blockInfo.MinMaxs.size() / 2); - for (unsigned int i = 0; i < numSubBlocks; i++) + if (isHit) + hitBlocks.push_back(BlockHit(blockInfo.BlockID)); + } + else + { + // global array + if (!query.TouchSelection(blockInfo.Start, blockInfo.Count)) + continue; + + BlockHit tmp(blockInfo.BlockID); + if (blockInfo.MinMaxs.size() > 0) { - bool isHit = query.m_RangeTree.CheckInterval(blockInfo.MinMaxs[2 * i], - blockInfo.MinMaxs[2 * i + 1]); - if (isHit) + // Consolidate to whole block If all subblocks are hits, then return the whole + // block + bool allCovered = true; + + adios2::helper::CalculateSubblockInfo(blockInfo.Count, blockInfo.SubBlockInfo); + unsigned int numSubBlocks = + static_cast(blockInfo.MinMaxs.size() / 2); + for (unsigned int i = 0; i < numSubBlocks; i++) { - adios2::Box currSubBlock = - adios2::helper::GetSubBlock(blockInfo.Count, blockInfo.SubBlockInfo, i); - for (size_t d = 0; d < blockInfo.Count.size(); ++d) + bool isSubblockHit = query.m_RangeTree.CheckInterval( + blockInfo.MinMaxs[2 * i], blockInfo.MinMaxs[2 * i + 1]); + if (isSubblockHit) + { + adios2::Box currSubBlock = adios2::helper::GetSubBlock( + blockInfo.Count, blockInfo.SubBlockInfo, i); + for (size_t d = 0; d < blockInfo.Count.size(); ++d) + currSubBlock.first[d] += blockInfo.Start[d]; + + if (!query.TouchSelection(currSubBlock.first, currSubBlock.second)) + continue; + tmp.m_Regions.push_back(currSubBlock); + } + else { - currSubBlock.first[d] += blockInfo.Start[d]; + allCovered = false; } - if (!query.TouchSelection(currSubBlock.first, currSubBlock.second)) - continue; - hitBlocks.push_back(currSubBlock); + } // for num subblocks + + if (!allCovered) + { + hitBlocks.push_back(tmp); + continue; } } - } - else - { // default - bool isHit = query.m_RangeTree.CheckInterval(blockInfo.Min, blockInfo.Max); - if (isHit) - { - adios2::Box box = {blockInfo.Start, blockInfo.Count}; - hitBlocks.push_back(box); - } + + // no subblock info or (allCovered = true) + adios2::Box box = {blockInfo.Start, blockInfo.Count}; + hitBlocks.push_back(BlockHit(blockInfo.BlockID, box)); } } } - Tree m_Content; - // can not be unique_ptr as it changes with bp5 through steps // as BP5Deserializer::SetupForStep calls io.RemoveVariables() // must use ptr as bp5 associates ptrs with blockinfo, see MinBlocksInfo() in bp5 diff --git a/source/adios2/toolkit/query/Query.cpp b/source/adios2/toolkit/query/Query.cpp index 6dc85b94c5..cca5c68481 100644 --- a/source/adios2/toolkit/query/Query.cpp +++ b/source/adios2/toolkit/query/Query.cpp @@ -53,6 +53,77 @@ adios2::Dims split(const std::string &s, char delim) return dim; } +BlockHit::BlockHit(size_t id) : m_ID(id) {} + +BlockHit::BlockHit(size_t id, Box &box) : m_ID(id) { m_Regions.push_back(box); } + +BlockHit::BlockHit(const BlockHit &cpy) +{ + m_ID = cpy.m_ID; + m_Regions = cpy.m_Regions; +} + +// +// return false if no intersection to apply +// e.g. different blockID, no overlapped subblocks +// return true if has intersection +// +// note that BlockHit comparison should match +// e.g. both are local/global arrays blocks +// +bool BlockHit::applyIntersection(const BlockHit &tmp) +{ + if (m_ID != tmp.m_ID) + return false; + + // local array, no subblock info + if (isLocalArrayBlock() || tmp.isLocalArrayBlock()) + return true; + + // check subblocks: + bool overlapped = false; + for (auto b : tmp.m_Regions) + { + for (auto it = m_Regions.begin(); it != m_Regions.end(); it++) + { + adios2::Box curr = QueryBase::GetIntersection(*it, b); + if (curr.first.size() != 0) // has intersection + { + overlapped = true; + *it = curr; + } + } + } + + return overlapped; +} + +// return true if can extended with tmp +// e.g. at least same blockID with tmp +bool BlockHit::applyExtension(const BlockHit &tmp) +{ + if (m_ID != tmp.m_ID) + return false; + + // check subblocks: + for (auto b : tmp.m_Regions) + { + bool duplicated = false; + for (auto box : m_Regions) + { + if (adios2::helper::IdenticalBoxes(box, b)) + { + duplicated = true; + continue; + } + } + if (!duplicated) + m_Regions.push_back(b); + } + + return true; +} + void QueryBase::ApplyOutputRegion(std::vector> &touchedBlocks, const adios2::Box &referenceRegion) { @@ -97,10 +168,11 @@ bool QueryComposite::AddNode(QueryBase *var) } void QueryComposite::BlockIndexEvaluate(adios2::core::IO &io, adios2::core::Engine &reader, - std::vector> &touchedBlocks) + // std::vector> &touchedBlocks) + std::vector &touchedBlocks) { - auto lf_ApplyAND = [&](std::vector> &touched, - const std::vector> &curr) -> void { + auto lf_ApplyAND = [&](std::vector &touched, + const std::vector &curr) -> void { if (curr.size() == 0) { touched.clear(); @@ -112,35 +184,19 @@ void QueryComposite::BlockIndexEvaluate(adios2::core::IO &io, adios2::core::Engi bool intersects = false; for (auto b : curr) { - adios2::Box curr = GetIntersection(touched[i - 1], b); - if (curr.first.size() != 0) // has intersection + if (touched[i].applyIntersection(b)) { intersects = true; break; } } if (!intersects) - // it = touched.erase(it); touched.erase(touched.begin() + i - 1); - // if (touched.end() == it) - // break; - } - - for (auto b : curr) - { - for (auto it = touched.begin(); it != touched.end(); it++) - { - adios2::Box curr = GetIntersection(*it, b); - if (curr.first.size() != 0) // has intersection - { - *it = curr; - } - } } }; // lf_ApplyAND - auto lf_ApplyOR = [&](std::vector> &touched, - const std::vector> &curr) -> void { + auto lf_ApplyOR = [&](std::vector &touched, + const std::vector &curr) -> void { if (curr.size() == 0) return; @@ -149,7 +205,7 @@ void QueryComposite::BlockIndexEvaluate(adios2::core::IO &io, adios2::core::Engi bool duplicated = false; for (auto box : touched) { - if (adios2::helper::IdenticalBoxes(box, b)) + if (box.applyExtension(b)) { duplicated = true; continue; @@ -160,42 +216,6 @@ void QueryComposite::BlockIndexEvaluate(adios2::core::IO &io, adios2::core::Engi } }; // lf_ApplyOR - /* - auto lf_ApplyRelation = [&](std::vector> &collection, - const Box &block) -> void { - if (adios2::query::Relation::AND == m_Relation) - { - for (auto it = touchedBlocks.begin(); it != touchedBlocks.end(); - it++) - { - adios2::Box curr = GetIntersection(*it, block); - // adios2::helper::IntersectionBox(*it, block); - if (curr.first.size() == 0) // no intersection - { - it = touchedBlocks.erase(it); - if (touchedBlocks.end() == it) - return; - } - else - *it = curr; - } - - return; - } - - if (adios2::query::Relation::OR == m_Relation) - { - for (auto box : touchedBlocks) - { - if (adios2::helper::IdenticalBoxes(box, block)) - return; - } - touchedBlocks.push_back(block); - return; - } - }; // local - */ - if (m_Nodes.size() == 0) return; @@ -203,7 +223,7 @@ void QueryComposite::BlockIndexEvaluate(adios2::core::IO &io, adios2::core::Engi for (auto node : m_Nodes) { counter++; - std::vector> currBlocks; + std::vector currBlocks; node->BlockIndexEvaluate(io, reader, currBlocks); if (counter == 1) { @@ -227,9 +247,6 @@ void QueryComposite::BlockIndexEvaluate(adios2::core::IO &io, adios2::core::Engi else if (adios2::query::Relation::OR == m_Relation) lf_ApplyOR(touchedBlocks, currBlocks); } - // plan to shift all var results to regions start at 0, and find out the - // overlapped regions boxes can be different size especially if they are - // from BP3 } bool QueryVar::IsSelectionValid(adios2::Dims &shape) const @@ -245,14 +262,6 @@ bool QueryVar::IsSelectionValid(adios2::Dims &shape) const return false; // different dimension } - /* - for (size_t i = 0; i < shape.size(); i++) - { - if ((m_Selection.first[i] > shape[i]) || - (m_Selection.second[i] > shape[i])) - return false; - } - */ return true; } @@ -298,13 +307,10 @@ bool QueryVar::TouchSelection(adios2::Dims &start, adios2::Dims &count) const } void QueryVar::BlockIndexEvaluate(adios2::core::IO &io, adios2::core::Engine &reader, - std::vector> &touchedBlocks) + std::vector &touchedBlocks) { const DataType varType = io.InquireVariableType(m_VarName); - // Variable var = io.InquireVariable(m_VarName); - // BlockIndex idx(io, reader); - // var already exists when loading query. skipping validity checking #define declare_type(T) \ if (varType == adios2::helper::GetDataType()) \ @@ -320,7 +326,14 @@ void QueryVar::BlockIndexEvaluate(adios2::core::IO &io, adios2::core::Engine &re if (touchedBlocks.size() > 0) { LimitToSelection(touchedBlocks); - ApplyOutputRegion(touchedBlocks, m_Selection); + + for (auto blk : touchedBlocks) + { + if (!blk.isLocalArrayBlock()) + { + ApplyOutputRegion(blk.m_Regions, m_Selection); + } + } } } } // namespace query diff --git a/source/adios2/toolkit/query/Query.h b/source/adios2/toolkit/query/Query.h index f3bef1c34b..9d3107b91d 100644 --- a/source/adios2/toolkit/query/Query.h +++ b/source/adios2/toolkit/query/Query.h @@ -93,6 +93,27 @@ class RangeTree std::vector m_SubNodes; }; // class RangeTree +struct BlockHit +{ + BlockHit(size_t id); + BlockHit(size_t id, Box &box); + BlockHit(const BlockHit &cpy); + + size_t m_ID; + + // if no sublocks, m_Regions is start/count of block (if global array). size=1 + // with subblocks, + // if global array, m_Regions has all the touched sub blocks with (abs) start count + // if local array, because client needs to read whole block, subblocks is ignored + // size=0 + // items in this vector are assumed to have no intersection. + std::vector> m_Regions; + + bool isLocalArrayBlock() const { return (0 == m_Regions.size()); } + bool applyIntersection(const BlockHit &tmp); + bool applyExtension(const BlockHit &tmp); +}; + class QueryBase { public: @@ -100,9 +121,9 @@ class QueryBase virtual bool IsCompatible(const adios2::Box &box) = 0; virtual void Print() = 0; virtual void BlockIndexEvaluate(adios2::core::IO &, adios2::core::Engine &, - std::vector> &touchedBlocks) = 0; + std::vector &touchedBlocks) = 0; - Box GetIntersection(const Box &box1, const Box &box2) noexcept + static Box GetIntersection(const Box &box1, const Box &box2) noexcept { Box b1 = adios2::helper::StartEndBox(box1.first, box1.second); Box b2 = adios2::helper::StartEndBox(box2.first, box2.second); @@ -140,7 +161,8 @@ class QueryVar : public QueryBase std::string &GetVarName() { return m_VarName; } void BlockIndexEvaluate(adios2::core::IO &, adios2::core::Engine &, - std::vector> &touchedBlocks); + std::vector &touchedBlocks); + void BroadcastOutputRegion(const adios2::Box ®ion) { m_OutputRegion = region; } void Print() { m_RangeTree.Print(); } @@ -183,6 +205,32 @@ class QueryVar : public QueryBase } } + // only applies to global arrays + void LimitToSelection(std::vector &blockHits) + { + for (auto i = blockHits.size(); i >= 1; i--) + { + if (blockHits[i - 1].isLocalArrayBlock()) + return; + + bool keepBlk = false; + for (auto it = blockHits[i - 1].m_Regions.begin(); + it != blockHits[i - 1].m_Regions.end(); it++) + { + Box overlap = GetIntersection(m_Selection, *it); + if (overlap.first.size() != 0) + { + keepBlk = true; + it->first = overlap.first; + it->second = overlap.second; + } + } + + if (!keepBlk) + blockHits.erase(blockHits.begin() + i - 1); + } + } + RangeTree m_RangeTree; adios2::Box m_Selection; @@ -212,7 +260,8 @@ class QueryComposite : public QueryBase } void BlockIndexEvaluate(adios2::core::IO &, adios2::core::Engine &, - std::vector> &touchedBlocks); + std::vector &touchedBlocks); + // std::vector> &touchedBlocks); bool AddNode(QueryBase *v); diff --git a/source/adios2/toolkit/query/Worker.cpp b/source/adios2/toolkit/query/Worker.cpp index 9609e8277a..e1a8ab02c2 100644 --- a/source/adios2/toolkit/query/Worker.cpp +++ b/source/adios2/toolkit/query/Worker.cpp @@ -82,6 +82,20 @@ QueryVar *Worker::GetBasicVarQuery(adios2::core::IO ¤tIO, const std::strin return nullptr; } +void Worker::GetResultCoverage(std::vector &touchedBlockIDs) +{ + touchedBlockIDs.clear(); + + std::vector blockHits; + if (m_Query && m_SourceReader) + { + m_Query->BlockIndexEvaluate(m_SourceReader->m_IO, *m_SourceReader, blockHits); + } + + for (auto blk : blockHits) + touchedBlockIDs.push_back(blk.m_ID); +} + void Worker::GetResultCoverage(const adios2::Box &outputRegion, std::vector> &touchedBlocks) { @@ -95,7 +109,11 @@ void Worker::GetResultCoverage(const adios2::Box &outputRegion, if (m_Query && m_SourceReader) { - m_Query->BlockIndexEvaluate(m_SourceReader->m_IO, *m_SourceReader, touchedBlocks); + std::vector blockHits; + m_Query->BlockIndexEvaluate(m_SourceReader->m_IO, *m_SourceReader, blockHits); + + for (auto blk : blockHits) + touchedBlocks.insert(touchedBlocks.end(), blk.m_Regions.begin(), blk.m_Regions.end()); } } } // namespace query diff --git a/source/adios2/toolkit/query/Worker.h b/source/adios2/toolkit/query/Worker.h index d95042a356..09cee08f7b 100644 --- a/source/adios2/toolkit/query/Worker.h +++ b/source/adios2/toolkit/query/Worker.h @@ -42,6 +42,7 @@ class Worker adios2::core::Engine *GetSourceReader() { return m_SourceReader; } + void GetResultCoverage(std::vector &); void GetResultCoverage(const adios2::Box &, std::vector> &); protected: diff --git a/testing/adios2/bindings/python/CMakeLists.txt b/testing/adios2/bindings/python/CMakeLists.txt index dd3c292a75..7d4b8d4104 100644 --- a/testing/adios2/bindings/python/CMakeLists.txt +++ b/testing/adios2/bindings/python/CMakeLists.txt @@ -25,7 +25,8 @@ if(ADIOS2_HAVE_MPI) add_python_mpi_test(BPBlocksInfo) add_python_mpi_test(BPChangingShapeHighLevelAPI) add_python_mpi_test(NullEngine) - add_python_mpi_test(Query) + add_python_mpi_test(Query) + add_python_mpi_test(QueryLocalArray) # Currently hangs in H5Fclose for unknown reasons #if(ADIOS2_HAVE_HDF5) # add_python_mpi_test(BPWriteTypesHighLevelAPI_HDF5) diff --git a/testing/adios2/bindings/python/TestQueryLocalArray.py b/testing/adios2/bindings/python/TestQueryLocalArray.py new file mode 100644 index 0000000000..8025d540d7 --- /dev/null +++ b/testing/adios2/bindings/python/TestQueryLocalArray.py @@ -0,0 +1,140 @@ +# +from mpi4py import MPI +import numpy as np +import adios2 +import sys + +# MPI +comm = MPI.COMM_WORLD +rank = comm.Get_rank() +size = comm.Get_size() + +# ####################################### +# # usage: [bp4 | bp5=default] ## +# ####################################### +numSteps = 5 +queryFile = 'query.xml' +targetVarName = 'var0' + +# User data +myArray = np.array([0, 1., 2., 3., 4., 5., 6., 7., 8., 9.]) +Nx = myArray.size + +# ADIOS MPI Communicator +adios = adios2.ADIOS(comm) + +supportedEngines = ['bp5', 'bp4'] +engineType = 'bp5' +if (len(sys.argv) > 1): + engineType = sys.argv[1].lower() + +if (engineType in supportedEngines): + if (rank == 0): + print('Using engine type:', engineType) +else: + sys.exit('specified engine does not exist') + + +dataFileName = 'test_' + engineType + '.bp' + + +def writeDataFile(): + bpIO = adios.DeclareIO("Writer") + bpIO.SetEngine(engineType) + + ioArray = bpIO.DefineVariable(targetVarName, myArray, [], [], [Nx], False) + + bpIO.SetParameter("statsblocksize", "3") + + bpFileWriter = bpIO.Open(dataFileName, adios2.Mode.Write) + + for i in range(numSteps): + bpFileWriter.BeginStep() + bpFileWriter.Put(ioArray, i * 10.0 + myArray / (rank + 1), + adios2.Mode.Sync) + bpFileWriter.EndStep() + + bpFileWriter.Close() + + +def createQueryFile(): + print(".. Writing query file to: ", queryFile) + + file1 = open(queryFile, 'w') + queryContent = [ + "\n", "\n", + " \n" + " \n", + " \n", + " \n", + " \n", " \n", + " \n", " \n", "\n" + ] + file1.writelines(queryContent) + file1.close() + + +def doAnalysis(reader, touched_blocks, varList): + print(" Step: ", reader.CurrentStep(), + " num touched blocks: ", len(touched_blocks)) + + values = [] + data = {} + + for var in varList: + data[var] = [] + + if (len(touched_blocks) > 0): + for n in touched_blocks: + for var in varList: + values = np.zeros(10, dtype=np.double) + var.SetBlockSelection(n) + reader.Get(var, values, adios2.Mode.Sync) + data[var].extend(values) + + +def queryDataFile(): + # # use no mpi + adios_nompi = adios2.ADIOS() + queryIO = adios_nompi.DeclareIO("query") + + reader = queryIO.Open(dataFileName, adios2.Mode.Read) + print("dataFile=", dataFileName, "queryFile=", queryFile) + touched_blocks = [] + + print("Num steps: ", reader.Steps()) + + while (reader.BeginStep() == adios2.StepStatus.OK): + # bp5 loads metadata after beginstep(), + # therefore query has to be called per step + w = adios2.Query(queryFile, reader) + # assume only rank 0 wants to process result + var = [queryIO.InquireVariable(targetVarName)] + + if (rank == 0): + touched_blocks = w.GetBlockIDs() + doAnalysis(reader, touched_blocks, var) + + reader.EndStep() + reader.Close() + + +def cleanUp(): + import os + import shutil + os.remove(queryFile) + shutil.rmtree(dataFileName) + print(" Cleanup generated files: ", queryFile, dataFileName) + +# +# actual setup: +# + + +writeDataFile() + + +if (0 == rank): + createQueryFile() + queryDataFile() + cleanUp() diff --git a/testing/adios2/performance/query/TestBPQuery.cpp b/testing/adios2/performance/query/TestBPQuery.cpp index a3ff5ae4a2..6e0e918a10 100644 --- a/testing/adios2/performance/query/TestBPQuery.cpp +++ b/testing/adios2/performance/query/TestBPQuery.cpp @@ -31,10 +31,10 @@ void WriteXmlQuery1D(const std::string &queryFile, const std::string &ioName, file << " " << std::endl; file << " " << std::endl; file << " " << std::endl; - file << " " << std::endl; + file << " " << std::endl; file << " " << std::endl; file << " " << std::endl; - file << " " << std::endl; + file << " " << std::endl; file << " " << std::endl; file << " " << std::endl; file << " " << std::endl; @@ -99,7 +99,7 @@ void BPQueryTest::QueryIntVar(const std::string &fname, adios2::ADIOS &adios, std::vector rr; if (engineName.compare("BP4") == 0) - rr = {9, 9, 9}; + rr = {2, 1, 1}; else rr = {1, 1, 1}; @@ -135,7 +135,7 @@ void BPQueryTest::QueryDoubleVar(const std::string &fname, adios2::ADIOS &adios, std::vector rr; //= {0,9,9}; if (engineName.compare("BP4") == 0) - rr = {0, 9, 9}; + rr = {0, 3, 1}; else rr = {0, 1, 1}; while (bpReader.BeginStep() == adios2::StepStatus::OK)