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

Added python query API #2832

Merged
merged 9 commits into from
Sep 9, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bindings/Python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Python_add_library(adios2_py MODULE
py11Attribute.cpp
py11Engine.cpp
py11Operator.cpp
py11Query.cpp
py11File.cpp py11File.tcc
py11glue.cpp
)
Expand Down
1 change: 1 addition & 0 deletions bindings/Python/py11Engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class IO; // friend
class Engine
{
friend class IO;
friend class Query;

public:
struct Info
Expand Down
45 changes: 45 additions & 0 deletions bindings/Python/py11Query.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/*
* Distributed under the OSI-approved Apache License, Version 2.0. See
* accompanying file Copyright.txt for details.
*
* py11Query.h :
*
* Created on: August 5, 2021
* Author: Junmin Gu (jgu@lbl.gov)
*/

#include "py11Query.h"

namespace adios2
{
namespace py11
{

Query::Query(adios2::query::Worker *qw) : m_QueryWorker(qw) {}

Query::Query(std::string queryFile, Engine reader)
{
adios2::query::Worker *m =
adios2::query::GetWorker(queryFile, reader.m_Engine);
if (m == nullptr)
throw std::invalid_argument("ERROR: unable to construct query. ");
m_QueryWorker = std::make_shared<adios2::query::Worker>(std::move(*m));
delete m;
}

Query::operator bool() const noexcept
{
return (m_QueryWorker == nullptr) ? false : true;
}

std::vector<Box<Dims>> Query::GetResult()
{
// std::cout<<"Do something"<<std::endl;
adios2::Box<adios2::Dims> empty; // look into all data
std::vector<Box<Dims>> touched_blocks;
m_QueryWorker->GetResultCoverage(empty, touched_blocks);
return touched_blocks;
}

} // py11
} // adios2
48 changes: 48 additions & 0 deletions bindings/Python/py11Query.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Distributed under the OSI-approved Apache License, Version 2.0. See
* accompanying file Copyright.txt for details.
*
* py11Query.h :
*
* Created on: August 5, 2021
* Author: Junmin Gu (jgu@lbl.gov)
*/

#ifndef ADIOS2_BINDINGS_PYTHON_QUERY_H_
#define ADIOS2_BINDINGS_PYTHON_QUERY_H_

#include <pybind11/numpy.h>

//#include "adios2/toolkit/query/Query.h"
#include "adios2/toolkit/query/Worker.h"
#include "py11Engine.h"

namespace adios2
{
namespace py11
{

class Engine;

class Query
{

public:
Query(std::string queryFile, Engine reader);
~Query() = default;

explicit operator bool() const noexcept;

std::vector<Box<Dims>> GetResult();
// const Box< Dims > & refinedSelectionIfAny,
// std::vector< Box< Dims > > &touched_blocks

private:
Query(adios2::query::Worker *qw);
std::shared_ptr<adios2::query::Worker> m_QueryWorker;
};

} // end namespace py11
} // end namespace adios2

#endif /* BINDINGS_PYTHON_PYQUERY_H_ */
21 changes: 20 additions & 1 deletion bindings/Python/py11glue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "py11File.h"
#include "py11IO.h"
#include "py11Operator.h"
#include "py11Query.h"
#include "py11Variable.h"

#if ADIOS2_USE_MPI
Expand Down Expand Up @@ -364,6 +365,25 @@ PYBIND11_MODULE(ADIOS2_PYTHON_MODULE_NAME, m)
.def("RemoveAttribute", &adios2::py11::IO::RemoveAttribute)
.def("RemoveAllAttributes", &adios2::py11::IO::RemoveAllAttributes);

pybind11::class_<adios2::py11::Query>(m, "Query")
.def("__nonzero__",
[](const adios2::py11::Query &query) {
const bool opBool = query ? true : false;
return opBool;
})
// Python 3
.def("__bool__",
[](const adios2::py11::Query &query) {
const bool opBool = query ? true : false;
return opBool;
})
.def(
pybind11::init<const std::string &, const adios2::py11::Engine &>(),
"adios2 query construction, a xml query File and a read engine",
pybind11::arg("queryFile"), pybind11::arg("reader") = true)

.def("GetResult", &adios2::py11::Query::GetResult);

pybind11::class_<adios2::py11::Variable>(m, "Variable")
// Python 2
.def("__nonzero__",
Expand Down Expand Up @@ -522,7 +542,6 @@ PYBIND11_MODULE(ADIOS2_PYTHON_MODULE_NAME, m)
[](const adios2::py11::File &stream) { return stream; })
.def("__exit__",
[](adios2::py11::File &stream, pybind11::args) { stream.Close(); })

.def("__iter__", [](adios2::py11::File &stream) { return stream; },
pybind11::keep_alive<0, 1>())
.def("__next__",
Expand Down
2 changes: 2 additions & 0 deletions source/adios2/toolkit/query/Query.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -247,12 +247,14 @@ 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;
}

Expand Down
2 changes: 0 additions & 2 deletions source/adios2/toolkit/query/XmlWorker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,6 @@ void XmlWorker::ConstructQuery(QueryVar &simpleQ, const pugi::xml_node &node)

if (bbNode)
{
adios2::Box<adios2::Dims> box =
adios2::Box<adios2::Dims>({100, 100}, {200, 200});
std::string startStr =
adios2::helper::XMLAttribute("start", bbNode, "in query")->value();
std::string countStr =
Expand Down
106 changes: 106 additions & 0 deletions testing/adios2/bindings/python/TestQuery.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
from mpi4py import MPI
import numpy as np
import adios2
import sys
import os
import math
import matplotlib.pyplot as plt

# MPI
comm = MPI.COMM_WORLD
rank = comm.Get_rank()
size = comm.Get_size()

configFile = './defaultConfig.xml'
queryFile = './sampleQuery.xml'
dataPath = './heat.bp'

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(n[1], dtype=np.double)
var.SetSelection(n)
reader.Get(var, values, adios2.Mode.Sync)
data[var].extend(values)
# do analysis with data here

def runQuery():
adios = adios2.ADIOS(configFile, comm, True)
queryIO = adios.DeclareIO("query")
reader = queryIO.Open(dataPath, adios2.Mode.Read, comm)
w = adios2.Query(queryFile, reader)

touched_blocks = []

var = [queryIO.InquireVariable("T")]

print("Num steps: ", reader.Steps())

while (reader.BeginStep() == adios2.StepStatus.OK):
# say only rank 0 wants to process result
if (rank == 0):
touched_blocks = w.GetResult()
doAnalysis(reader, touched_blocks, var)

reader.EndStep()
reader.Close()

def createConfigFile():
print(".. Writing config file to: ", configFile)
file1 = open(configFile, 'w')

xmlContent = ["<?xml version=\"1.0\"?>\n",
"<adios-config>\n",
"<io name=\"query\">\n",
" <engine type=\"BPFile\">\n",
" </engine>\n",
" <transport type=\"File\">\n",
" <parameter key=\"Library\" value=\"POSIX\"/>\n",
" </transport>\n",
"</io>\n", "</adios-config>\n"]

file1.writelines(xmlContent)
file1.close()

def createQueryFile():
print(".. Writing query file to: ", queryFile)

file1 = open(queryFile, 'w')
queryContent = [
"<?xml version=\"1.0\"?>\n", "<adios-query>\n",
" <io name=\"query\">\n"
" <var name=\"T\">\n",
" <op value=\"AND\">\n",
" <range compare=\"LT\" value=\"2.7\"/>\n",
" <range compare=\"GT\" value=\"2.66\"/>\n", " </op>\n",
" </var>\n", " </io>\n", "</adios-query>\n"
]
file1.writelines(queryContent)
file1.close()


if (os.path.exists(dataPath) is False):
print("Please generate data file:", dataPath,
" from heat transfer example first.")
else:
# configFile created
createConfigFile()

# queryFile Generated
createQueryFile()

print(".. Running query against: ", dataPath)
runQuery()

print("Now clean up.")
os.remove(queryFile)
os.remove(configFile)
Binary file added testing/adios2/bindings/python/heat.bp/data.0
Binary file not shown.
Binary file added testing/adios2/bindings/python/heat.bp/md.0
Binary file not shown.
Binary file added testing/adios2/bindings/python/heat.bp/md.idx
Binary file not shown.
6 changes: 6 additions & 0 deletions testing/adios2/bindings/python/heat.bp/profiling.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[
{ "rank": 0, "start": "Thu_Aug_19_14:58:09_2021", "threads": 1, "bytes": 3964, "mkdir_mus": 186, "memcpy_mus": 0, "aggregation_mus": 0, "meta_sort_merge_mus": 542, "minmax_mus": 48, "buffering_mus": 1136, "transport_0": { "type": "File_stdio", "close_mus": 142, "write_mus": 182, "open_mus": 0 },"transport_1": { "type": "File_stdio", "close_mus": 0, "write_mus": 48, "open_mus": 0 } },
{ "rank": 1, "start": "Thu_Aug_19_14:58:09_2021", "threads": 1, "bytes": 3888, "mkdir_mus": 193, "memcpy_mus": 0, "aggregation_mus": 0, "meta_sort_merge_mus": 65, "minmax_mus": 61, "buffering_mus": 774, },
{ "rank": 2, "start": "Thu_Aug_19_14:58:09_2021", "threads": 1, "bytes": 3888, "mkdir_mus": 196, "memcpy_mus": 0, "aggregation_mus": 0, "meta_sort_merge_mus": 110, "minmax_mus": 47, "buffering_mus": 768, },
{ "rank": 3, "start": "Thu_Aug_19_14:58:09_2021", "threads": 1, "bytes": 3888, "mkdir_mus": 197, "memcpy_mus": 0, "aggregation_mus": 0, "meta_sort_merge_mus": 100, "minmax_mus": 47, "buffering_mus": 671, }
]