diff --git a/bindings/python/Makefile b/bindings/python/Makefile index 2f9f607d7e79927b4a817b53da7ccf47eeee99de..53d9d5e9b2813973b0eaa077b229a3bdf9bd5904 100644 --- a/bindings/python/Makefile +++ b/bindings/python/Makefile @@ -8,11 +8,16 @@ MPICC:=mpic++ CPPFiles:=$(shell find ./source -type f -name "*.cpp") OBJS:=$(patsubst %.cpp, ./bin/%.o, $(notdir $(CPPFiles)) ) -# Python +# Python 2.7 PYTHON_VERSION:= 2.7 PYTHON_INC:= /usr/include/python$(PYTHON_VERSION) PYTHON_LIBLOC:= /usr/lib/python$(PYTHON_VERSION)/config-x86_64-linux-gnu/ - + +# Python 3.5 ...doesn't work ImportError: dynamic module does not define init function (initadios2py) +#PYTHON_VERSION:= 3.5 +#PYTHON_INC:= /usr/include/python$(PYTHON_VERSION) +#PYTHON_LIBLOC:= /usr/lib/python$(PYTHON_VERSION)/config-3.5m-x86_64-linux-gnu/ +# # ADIOS2 ADIOS2_INC:= /usr/local/include diff --git a/bindings/python/README.md b/bindings/python/README.md index 5f363d7b2b153b4afa72926b734cb5b52a28394d..e2e686715368a393bf43aac3be9882fbc03c0904 100644 --- a/bindings/python/README.md +++ b/bindings/python/README.md @@ -2,7 +2,11 @@ Python bindings for ADIOS 2.0 using PyBind11 Dependencies: - Python 2.7.x and above + Python 2.7.x and above (still testing 3.5) Numpy and MPI4PY ADIOS2 shared library (libadios2.so) - \ No newline at end of file + +Examples; + + helloBPWriter.py from adios2/examples/hello/bpWriter + helloBPTimeWriter.py from adios2/examples/hello/bpTimeWriter \ No newline at end of file diff --git a/bindings/python/helloBPTimeWriter.py b/bindings/python/helloBPTimeWriter.py new file mode 100644 index 0000000000000000000000000000000000000000..1a02fa7062465f02930540c9a98ecce87d35d7c5 --- /dev/null +++ b/bindings/python/helloBPTimeWriter.py @@ -0,0 +1,47 @@ +# clang-format off +# +# Distributed under the OSI-approved Apache License, Version 2.0. See +# accompanying file Copyright.txt for details. +# +# test_hello.py +# Created on: Feb 2, 2017 +# Author: wfg + +from mpi4py import MPI +from adios2py import * +import numpy as np + + +# MPI +comm = MPI.COMM_WORLD +rank = comm.Get_rank() +size = comm.Get_size() + +# User data +myArray = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) +nx = myArray.size + +# ADIOS +adios = ADIOS(comm, adiosDebugON) + +# IO +bpIO = adios.DeclareIO("BPN2N") + +# Variables +bpArray = bpIO.DefineVariable("bpArray", [size * nx], [rank * nx], [nx], + adiosConstantDims) +bpTimeStep = bpIO.DefineVariable("bpTimeStep") + +# Engine +bpFileWriter = bpIO.Open("myArray.bp", adiosOpenModeWrite) +# Doesn't work: bpFileWriter = bpIO.Open("myArray.bp", adiosOpenModeWrite, +# MPI.COMM_WORLD) + +for t in range(0, 10): + if(rank == 0): + bpFileWriter.Write(bpTimeStep, np.array([t])) + + bpFileWriter.Write(bpArray, myArray) + bpFileWriter.Advance() + +bpFileWriter.Close() diff --git a/bindings/python/helloBPWriter.py b/bindings/python/helloBPWriter.py index fb39e326cba510343378045965080a411c1755d8..75eb6ce596e435ee0bb65d8dd5a7363357189a60 100644 --- a/bindings/python/helloBPWriter.py +++ b/bindings/python/helloBPWriter.py @@ -1,3 +1,4 @@ +# clang-format off # # Distributed under the OSI-approved Apache License, Version 2.0. See # accompanying file Copyright.txt for details. @@ -10,17 +11,22 @@ from mpi4py import MPI from adios2py import * import numpy as np - # User data -myArray = np.array([1., 2., 3., 4., 5.]) - -print "Read " + str(adiosRead) +myArray = np.array([1., 2., 3., 4., 5., 6.]) -adios = ADIOS(MPI.COMM_WORLD, True) +# ADIOS +adios = ADIOS(MPI.COMM_WORLD, adiosDebugON) +# IO bpIO = adios.DeclareIO("BPN2N") -ioArray = bpIO.DefineVariable("bpArray", [myArray.size], [0], [myArray.size], True) - -bpFileWriter = bpIO.Open("myArray.bp", adiosWrite) + +# Variable +ioArray = bpIO.DefineVariable( + "bpArray", [myArray.size], [0], [myArray.size], adiosConstantDims) + +# Engine +bpFileWriter = bpIO.Open("myArray.bp", adiosOpenModeWrite) +# bpFileWriter = bpIO.Open("myArray.bp", adiosOpenModeWrite, +# MPI.COMM_WORLD) //doesn't work bpFileWriter.Write(ioArray, myArray) bpFileWriter.Close() diff --git a/bindings/python/source/ADIOSPy.cpp b/bindings/python/source/ADIOSPy.cpp index c613882bb935ee3ab1397a99dca5dec03f0a2249..f258de2bff7035e1a6005002613ca700be96a0cd 100644 --- a/bindings/python/source/ADIOSPy.cpp +++ b/bindings/python/source/ADIOSPy.cpp @@ -12,8 +12,6 @@ #include "adiosPyTypes.h" -#include <iostream> - namespace adios { @@ -24,8 +22,6 @@ ADIOSPy::ADIOSPy(MPI_Comm mpiComm, const bool debug) IOPy ADIOSPy::DeclareIO(const std::string name) { - std::cout << "Declaring IO " << name << "\n"; - return IOPy(m_ADIOS.DeclareIO(name), m_DebugMode); } diff --git a/bindings/python/source/EnginePy.cpp b/bindings/python/source/EnginePy.cpp index b60efe9712288c6bd1e441ab64711fd17511b466..e703f61d15c52a569f5710bab83471f79d2acbe5 100644 --- a/bindings/python/source/EnginePy.cpp +++ b/bindings/python/source/EnginePy.cpp @@ -63,6 +63,9 @@ void EnginePy::Advance(const float timeoutSeconds) m_Engine->Advance(timeoutSeconds); } -void EnginePy::Close() { m_Engine->Close(); } +void EnginePy::Close(const int transportIndex) +{ + m_Engine->Close(transportIndex); +} } // end namespace adios diff --git a/bindings/python/source/EnginePy.h b/bindings/python/source/EnginePy.h index 19f6e1dea69d28ac0041e366dd9ffac40399961c..68130704b2936469d608b8a12cb14f54fa8fee1b 100644 --- a/bindings/python/source/EnginePy.h +++ b/bindings/python/source/EnginePy.h @@ -37,7 +37,7 @@ public: void Advance(const float timeoutSeconds = 0.); - void Close(); + void Close(const int transportIndex = -1); private: IO &m_IO; diff --git a/bindings/python/source/IOPy.cpp b/bindings/python/source/IOPy.cpp index 692b2b018005f261f1500cbb0573565ba76cfc06..e1bfc599d81b2008ef9f42e67924469ae353f5dd 100644 --- a/bindings/python/source/IOPy.cpp +++ b/bindings/python/source/IOPy.cpp @@ -12,6 +12,8 @@ #include <mpi4py/mpi4py.h> +#include "adiosPyFunctions.h" //PyObjectToMPIComm + namespace adios { @@ -20,44 +22,81 @@ IOPy::IOPy(IO &io, const bool debugMode) : m_IO(io), m_DebugMode(debugMode) m_IO.m_HostLanguage = "Python"; } -void IOPy::SetParameters(const pyKwargs &kwargs) +void IOPy::SetEngine(const std::string engine) { m_IO.SetEngine(engine); } + +void IOPy::SetParameters(const pyKwargs &kwargs) noexcept { m_IO.SetParameters(KwargsToParams(kwargs)); } -unsigned int IOPy::AddTransport(const std::string type, const pyKwargs &kwargs) +unsigned int IOPy::AddTransport(const std::string type, + const pyKwargs &kwargs) noexcept { return m_IO.AddTransport(type, KwargsToParams(kwargs)); } -VariablePy IOPy::DefineVariable(const std::string &name, const pyList shape, - const pyList start, const pyList count, - const bool isConstantDims) +VariablePy &IOPy::DefineVariable(const std::string &name, const pyList shape, + const pyList start, const pyList count, + const bool isConstantDims) +{ + if (m_DebugMode) + { + if (m_Variables.count(name) == 1) + { + throw std::invalid_argument("ERROR: variable " + name + + " already exists, use GetVariable, in " + "call to DefineVariable\n"); + } + } + + auto itVariableEmplace = + m_Variables.emplace(name, VariablePy(name, shape, start, count, + isConstantDims, m_DebugMode)); + return itVariableEmplace.first->second; +} + +VariablePy &IOPy::GetVariable(const std::string &name) { - return VariablePy(name, shape, start, count, isConstantDims, m_DebugMode); + auto itVariable = m_Variables.find(name); + + if (m_DebugMode) + { + if (itVariable == m_Variables.end()) + { + throw std::invalid_argument("ERROR: variable " + name + + " doesn't exist, in " + "call to GetVariable\n"); + } + } + return itVariable->second; +} + +EnginePy IOPy::Open(const std::string &name, const int openMode, + adios::pyObject &object) +{ + MPI_Comm *mpiCommPtr = PyMPIComm_Get(object.ptr()); + + if (import_mpi4py() < 0) + { + throw std::logic_error("ERROR: could not import mpi4py " + "communicator, in call to ADIOS " + "constructor\n"); + } + + if (mpiCommPtr == nullptr) + { + throw std::runtime_error("ERROR: mpi4py communicator is null, in call " + "to ADIOS constructor\n"); + } + + return EnginePy(m_IO, name, static_cast<adios::OpenMode>(openMode), + *mpiCommPtr); } EnginePy IOPy::Open(const std::string &name, const int openMode) { - // MPI_Comm *mpiCommPtr = PyMPIComm_Get(pyMPIComm.ptr()); - // - // if (m_DebugMode) - // { - // if (mpiCommPtr == NULL) - // { - // throw std::runtime_error("ERROR: mpi4py communicator for - // engine " + - // name + " is null, in call to IO - // Open\n"); - // } - // } return EnginePy(m_IO, name, static_cast<adios::OpenMode>(openMode), m_IO.m_MPIComm); } -// EnginePy IOPy::Open(const std::string &name, const OpenMode openMode) -//{ -// return EnginePy(m_IO, name, openMode, m_IO.m_MPIComm); -//} - -} // end namespace +} // end namespace adios diff --git a/bindings/python/source/IOPy.h b/bindings/python/source/IOPy.h index 6bacc3a4183f443d6acfd16f24c6f207a661cf5f..8838d6a63532fac7fa88c5460cb940f0d12f38fd 100644 --- a/bindings/python/source/IOPy.h +++ b/bindings/python/source/IOPy.h @@ -32,16 +32,25 @@ public: ~IOPy() = default; - void SetParameters(const pyKwargs &kwargs); - unsigned int AddTransport(const std::string type, const pyKwargs &kwargs); + void SetEngine(const std::string engineType); - VariablePy DefineVariable(const std::string &name, const pyList shape, - const pyList start, const pyList count, - const bool isConstantDims); + void SetParameters(const pyKwargs &kwargs) noexcept; + unsigned int AddTransport(const std::string type, + const pyKwargs &kwargs) noexcept; + + VariablePy &DefineVariable(const std::string &name, const pyList shape, + const pyList start, const pyList count, + const bool isConstantDims); + + VariablePy &GetVariable(const std::string &name); + + EnginePy Open(const std::string &name, const int openMode, + adios::pyObject &object); EnginePy Open(const std::string &name, const int openMode); - // EnginePy Open(const std::string &name, const OpenMode openMode); +private: + std::map<std::string, VariablePy> m_Variables; }; } // end namespace adios diff --git a/bindings/python/source/adiosPyFunctions.cpp b/bindings/python/source/adiosPyFunctions.cpp index 806fd31817e60e2318c2f00ffccca598968ebdf7..92d41807a2b94695d6a0bd04ce4330439a959a92 100644 --- a/bindings/python/source/adiosPyFunctions.cpp +++ b/bindings/python/source/adiosPyFunctions.cpp @@ -5,16 +5,15 @@ * adiosPyFunctions.cpp * * Created on: Mar 13, 2017 - * Author: wfg + * Author: William F Godoy godoywf@ornl.gov */ -#include <iostream> #include "adiosPyFunctions.h" namespace adios { -Dims PyListToDims(const pyList list) +Dims PyListToDims(const pyList list) noexcept { const unsigned int length = pybind11::len(list); Dims dimensions; @@ -28,7 +27,7 @@ Dims PyListToDims(const pyList list) return dimensions; } -Params KwargsToParams(const pyKwargs &kwargs) +Params KwargsToParams(const pyKwargs &kwargs) noexcept { Params parameters; diff --git a/bindings/python/source/adiosPyFunctions.h b/bindings/python/source/adiosPyFunctions.h index ed97bbaf4f2622249316067e140edeffc38adb84..cf8bc412e2e7cf9d4fc9485e176ccb71c4def357 100644 --- a/bindings/python/source/adiosPyFunctions.h +++ b/bindings/python/source/adiosPyFunctions.h @@ -26,7 +26,7 @@ namespace adios * @param list python list of numbers * @return adios::Dims */ -Dims PyListToDims(const pyList list); +Dims PyListToDims(const pyList list) noexcept; /** * Python dictionary kwargs to adios::Params (std::map<std::string, @@ -34,7 +34,7 @@ Dims PyListToDims(const pyList list); * @param kwargs dictionary * @return adios::Params */ -Params KwargsToParams(const pyKwargs &kwargs); +Params KwargsToParams(const pyKwargs &kwargs) noexcept; } // end namespace adios diff --git a/bindings/python/source/gluePyBind11.cpp b/bindings/python/source/gluePyBind11.cpp index 0c4aa097f026b5b815b4bc4088983dbac1e41782..861557aef0e3b2ac6dd5bcb12529702b14b594f5 100644 --- a/bindings/python/source/gluePyBind11.cpp +++ b/bindings/python/source/gluePyBind11.cpp @@ -18,20 +18,24 @@ #include "EnginePy.h" #include "IOPy.h" #include "VariablePy.h" +#include "adiosPyFunctions.h" #include "adiosPyTypes.h" -adios::ADIOSPy ADIOSPyInit(adios::pyObject py_comm, const bool debugMode) +adios::ADIOSPy ADIOSPyInit(adios::pyObject &object, const bool debugMode) { - MPI_Comm *mpiCommPtr = PyMPIComm_Get(py_comm.ptr()); + MPI_Comm *mpiCommPtr = PyMPIComm_Get(object.ptr()); - if (debugMode) + if (import_mpi4py() < 0) { - if (mpiCommPtr == NULL) - { - throw std::runtime_error( - "ERROR: mpi4py communicator is null, in call " - "to ADIOS constructor\n"); - } + throw std::runtime_error("ERROR: could not import mpi4py " + "communicator, in call to ADIOS " + "constructor\n"); + } + + if (mpiCommPtr == nullptr) + { + throw std::runtime_error("ERROR: mpi4py communicator is null, in call " + "to ADIOS constructor\n"); } return adios::ADIOSPy(*mpiCommPtr, debugMode); } @@ -47,39 +51,46 @@ PYBIND11_PLUGIN(adios2py) pybind11::module m("adios2py", "ADIOS2 Python bindings using pybind11"); m.attr("adiosDebugON") = true; m.attr("adiosDebugOFF") = false; - m.attr("adiosWrite") = static_cast<int>(adios::OpenMode::Write); - m.attr("adiosRead") = static_cast<int>(adios::OpenMode::Read); - m.attr("adiosAppend") = static_cast<int>(adios::OpenMode::Append); - m.attr("adiosReadWrite") = static_cast<int>(adios::OpenMode::ReadWrite); + m.attr("adiosConstantDims") = true; + m.attr("adiosOpenModeWrite") = static_cast<int>(adios::OpenMode::Write); + m.attr("adiosOpenModeRead") = static_cast<int>(adios::OpenMode::Read); + m.attr("adiosOpenModeAppend") = static_cast<int>(adios::OpenMode::Append); + m.attr("adiosOpenModeReadWrite") = + static_cast<int>(adios::OpenMode::ReadWrite); m.def("ADIOS", &ADIOSPyInit, "Function that creates an ADIOS class object"); pybind11::class_<adios::ADIOSPy>(m, "ADIOSPy") .def("DeclareIO", &adios::ADIOSPy::DeclareIO); pybind11::class_<adios::IOPy>(m, "IOPy") + .def("SetEngine", &adios::IOPy::SetEngine) .def("SetParameters", &adios::IOPy::SetParameters) .def("AddTransport", &adios::IOPy::AddTransport) - .def("DefineVariable", &adios::IOPy::DefineVariable) - .def("Open", &adios::IOPy::Open); + .def("DefineVariable", &adios::IOPy::DefineVariable, + pybind11::return_value_policy::reference_internal, + pybind11::arg("name"), pybind11::arg("shape") = adios::pyList(), + pybind11::arg("start") = adios::pyList(), + pybind11::arg("count") = adios::pyList(), + pybind11::arg("isConstantDims") = false) + .def("GetVariable", &adios::IOPy::GetVariable, + pybind11::return_value_policy::reference_internal) + // .def("Open", (adios::EnginePy (adios::IOPy::*)( + // const std::string &, const int, + // adios::pyObject &)) & + // adios::IOPy::Open) doesn't work + .def("Open", (adios::EnginePy (adios::IOPy::*)(const std::string &, + const int)) & + adios::IOPy::Open); pybind11::class_<adios::VariablePy>(m, "VariablePy") .def("SetDimensions", &adios::VariablePy::SetDimensions); pybind11::class_<adios::EnginePy>(m, "EnginePy") .def("Write", &adios::EnginePy::Write) - .def("Advance", &adios::EnginePy::Advance) - .def("Close", &adios::EnginePy::Close); - - // Trying overloaded function - // (adios::EnginePy (adios::IOPy::*)( - // const std::string &, const adios::OpenMode, - // adios::pyObject)) & - // &adios::IOPy::Open) - // .def("Open", (adios::EnginePy (adios::IOPy::*)(const std::string - // &, - // const - // adios::OpenMode)) & - // &adios::IOPy::Open); + .def("Advance", &adios::EnginePy::Advance, + pybind11::arg("timeoutSeconds") = 0.) + .def("Close", &adios::EnginePy::Close, + pybind11::arg("transportIndex") = -1); return m.ptr(); }