From fc9ce1b8b67542287110eae5ba66ce78386d7da4 Mon Sep 17 00:00:00 2001 From: Junmin Gu Date: Mon, 23 Oct 2023 12:59:21 -0700 Subject: [PATCH 1/3] new attempt to commit query support of local array. removed unused code sections added support for Local Arrays added test for local arrays in python result can be returned as vector of start/count (global array only), or vector of block ids --- bindings/CXX11/adios2/cxx11/Query.cpp | 8 +- bindings/CXX11/adios2/cxx11/Query.h | 1 + bindings/Python/py11Query.cpp | 7 + bindings/Python/py11Query.h | 1 + bindings/Python/py11glue.cpp | 3 +- examples/basics/queryWorker/queryWorker.cpp | 54 ++++-- source/adios2/toolkit/query/BlockIndex.h | 134 ++++++++------ source/adios2/toolkit/query/Query.cpp | 165 ++++++++++-------- source/adios2/toolkit/query/Query.h | 59 ++++++- source/adios2/toolkit/query/Worker.cpp | 20 ++- source/adios2/toolkit/query/Worker.h | 1 + testing/adios2/bindings/python/CMakeLists.txt | 3 +- .../bindings/python/TestQueryLocalArray.py | 140 +++++++++++++++ 13 files changed, 446 insertions(+), 150 deletions(-) create mode 100644 testing/adios2/bindings/python/TestQueryLocalArray.py 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..52bcca5983 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,10 @@ 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; + 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 +162,9 @@ class QueryVar : public QueryBase std::string &GetVarName() { return m_VarName; } void BlockIndexEvaluate(adios2::core::IO &, adios2::core::Engine &, - std::vector> &touchedBlocks); + std::vector &touchedBlocks); + // std::vector> &touchedBlocks); + void BroadcastOutputRegion(const adios2::Box ®ion) { m_OutputRegion = region; } void Print() { m_RangeTree.Print(); } @@ -183,6 +207,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 +262,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() From ebd862fd8b8ab05268562a0fb4421b0fbf4e6a25 Mon Sep 17 00:00:00 2001 From: Junmin Gu Date: Mon, 23 Oct 2023 13:54:21 -0700 Subject: [PATCH 2/3] removed commented code --- source/adios2/toolkit/query/Query.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/source/adios2/toolkit/query/Query.h b/source/adios2/toolkit/query/Query.h index 52bcca5983..9d3107b91d 100644 --- a/source/adios2/toolkit/query/Query.h +++ b/source/adios2/toolkit/query/Query.h @@ -121,7 +121,6 @@ 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; static Box GetIntersection(const Box &box1, const Box &box2) noexcept @@ -163,7 +162,6 @@ 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; } From ce817fb139162bd553cbd2046c739863cb5e9252 Mon Sep 17 00:00:00 2001 From: Junmin Gu Date: Mon, 23 Oct 2023 14:19:22 -0700 Subject: [PATCH 3/3] missed file TestBPQuery when copied from the previous repo --- testing/adios2/performance/query/TestBPQuery.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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)