From 776fb15760850f827069e71a78ded67db3cd8e9c Mon Sep 17 00:00:00 2001
From: wfg <wfg@pc0098504.ornl.gov>
Date: Mon, 20 Mar 2017 17:01:54 -0400
Subject: [PATCH] Working on BPFileWriter Advance function for time aggregation

Python bindings now working with PyBind11
---
 bindings/python/include/ADIOSPy.h          |   1 +
 bindings/python/include/EnginePy.h         |   3 +-
 bindings/python/include/MethodPy.h         |  15 ++-
 bindings/python/include/adiosPyFunctions.h |  35 ++++--
 bindings/python/src/ADIOSPy.cpp            |  10 +-
 bindings/python/src/EnginePy.cpp           |  69 +++++------
 bindings/python/src/MethodPy.cpp           |  42 ++++---
 bindings/python/src/adiosPyFunctions.cpp   |  42 ++++---
 bindings/python/src/glueBoostPython.cpp    | 136 +--------------------
 bindings/python/src/gluePyBind11.cpp       |  24 +++-
 bindings/python/test_hello.py              |  29 +++--
 include/ADIOS.h                            |  17 ---
 include/engine/bp/BPFileWriter.h           |   2 -
 include/format/BP1Writer.h                 |   3 +
 src/engine/bp/BPFileWriter.cpp             |   2 +-
 src/format/BP1Writer.cpp                   |   7 ++
 16 files changed, 181 insertions(+), 256 deletions(-)

diff --git a/bindings/python/include/ADIOSPy.h b/bindings/python/include/ADIOSPy.h
index e2e7b6095..65cf2cfcf 100644
--- a/bindings/python/include/ADIOSPy.h
+++ b/bindings/python/include/ADIOSPy.h
@@ -31,6 +31,7 @@ namespace adios
 #ifdef HAVE_BOOSTPYTHON
 using pyList = boost::python::list;
 using pyObject = boost::python::object;
+using pyNone = pyObject();
 #endif
 
 #ifdef HAVE_PYBIND11
diff --git a/bindings/python/include/EnginePy.h b/bindings/python/include/EnginePy.h
index 3d0d033ed..23bf36c3f 100644
--- a/bindings/python/include/EnginePy.h
+++ b/bindings/python/include/EnginePy.h
@@ -27,7 +27,6 @@ namespace adios
 {
 
 #ifdef HAVE_BOOSTPYTHON
-//using pyArray = boost::python::numpy::ndarray;
 using dtype = boost::python::numpy::dtype;
 #endif
 
@@ -52,7 +51,7 @@ public:
 
 	void Close( );
 
-	void GetType( ) const;
+	void GetEngineType( ) const;
 
 private:
 
diff --git a/bindings/python/include/MethodPy.h b/bindings/python/include/MethodPy.h
index edd85d7f2..77ca9471b 100644
--- a/bindings/python/include/MethodPy.h
+++ b/bindings/python/include/MethodPy.h
@@ -45,14 +45,17 @@ public:
 
     ~MethodPy( );
 
-    /**
-     * static needed to support raw function
-     * @param dictionary
-     * @return
-     */
-    static pyObject SetParametersPy( pyTuple args, pyDict kwargs );
 
+    #ifdef HAVE_BOOSTPYTHON
+    static pyObject SetParametersPy( pyTuple args, pyDict kwargs );
     static pyObject AddTransportPy( pyTuple args, pyDict kwargs );
+    #endif
+
+
+    #ifdef HAVE_PYBIND11
+    void SetParametersPyBind11( pybind11::kwargs kwargs );
+    void AddTransportPyBind11( const std::string type, pybind11::kwargs kwargs );
+    #endif
 
     void PrintAll( ) const;
 
diff --git a/bindings/python/include/adiosPyFunctions.h b/bindings/python/include/adiosPyFunctions.h
index a25834736..1f3167929 100644
--- a/bindings/python/include/adiosPyFunctions.h
+++ b/bindings/python/include/adiosPyFunctions.h
@@ -33,6 +33,8 @@ using pyList = boost::python::list;
 using pyDict = boost::python::dict;
 using pyArray = boost::python::numpy::ndarray;
 using dtype = boost::python::numpy::dtype;
+using pyKwargs = boost::python::dict;
+using pyObject = boost::python::object;
 #endif
 
 #ifdef HAVE_PYBIND11
@@ -40,6 +42,8 @@ using pyList = pybind11::list;
 using pyDict = pybind11::dict;
 using pyArray = pybind11::array;
 using dtype = pybind11::dtype;
+using pyKwargs = pybind11::kwargs;
+using pyObject = pybind11::object;
 #endif
 
 /**
@@ -49,7 +53,14 @@ using dtype = pybind11::dtype;
  */
 Dims ListToVector( const pyList& list );
 
+#ifdef HAVE_BOOSTPYTHON
 std::map<std::string, std::string> DictToMap( const pyDict& dictionary );
+#endif
+
+#ifdef HAVE_PYBIND11
+std::map<std::string, std::string> KwargsToMap( const pybind11::kwargs& dictionary );
+#endif
+
 
 template< class T >
 const T* PyArrayToPointer( const pyArray& array )
@@ -63,27 +74,35 @@ const T* PyArrayToPointer( const pyArray& array )
     #endif
 }
 
-
 template< class T >
-dtype GetDType( )
+bool IsType( const pyArray& array )
 {
     #ifdef HAVE_BOOSTPYTHON
-    return dtype::get_builtin<T>();
+    if( array.get_dtype() == dtype::get_builtin<T>() ) return true;
     #endif
 
     #ifdef HAVE_PYBIND11
-    return dtype::of<T>();
+    if( pybind11::isinstance<pybind11::array_t<T>>( array ) ) return true;
     #endif
-}
-
-dtype DType( const pyArray& array );
-
 
+    return false;
+}
 
 
+template< class T, class U>
+T PyCast( U object )
+{
+    #ifdef HAVE_BOOSTPYTHON
+    return boost::python::extract<T>( object );
+    #endif
 
+    #ifdef HAVE_PYBIND11
+    return pybind11::cast<T>( object );
+    #endif
+}
 
 
+bool IsEmpty( pyObject object );
 
 
 } //end namespace
diff --git a/bindings/python/src/ADIOSPy.cpp b/bindings/python/src/ADIOSPy.cpp
index ab5ef1542..609b7e632 100644
--- a/bindings/python/src/ADIOSPy.cpp
+++ b/bindings/python/src/ADIOSPy.cpp
@@ -10,8 +10,7 @@
 #include <mpi4py/mpi4py.h>
 
 #include "ADIOSPy.h"
-
-#include "core/Engine.h"
+#include "EnginePy.h"
 
 namespace adios
 {
@@ -62,8 +61,11 @@ void ADIOSPy::DefineVariableType( VariablePy& variablePy )
 EnginePy ADIOSPy::OpenPy( const std::string name, const std::string accessMode,
     		              const MethodPy& method, pyObject py_comm )
 {
-	EnginePy enginePy;
-	if( py_comm == pyObject() ) //None
+	EnginePy enginePy( *this );
+
+	bool isEmpty = IsEmpty( py_comm );
+
+	if( isEmpty == true   ) //None
 	{
 		enginePy.m_Engine = Open( name, accessMode, method );
 	}
diff --git a/bindings/python/src/EnginePy.cpp b/bindings/python/src/EnginePy.cpp
index c21454f76..e29b37f6c 100644
--- a/bindings/python/src/EnginePy.cpp
+++ b/bindings/python/src/EnginePy.cpp
@@ -5,6 +5,7 @@
  *      Author: wgodoy
  */
 
+#include <string>
 
 
 #include "EnginePy.h"
@@ -25,49 +26,49 @@ EnginePy::~EnginePy( )
 
 void EnginePy::WritePy( VariablePy& variable, const pyArray& array )
 {
-    const dtype arrayDType = DType( array );
 
     if( variable.m_IsVariableDefined == false ) //here define variable
     {
-             if( arrayDType == GetDType<char>() ) DefineVariableInADIOS<char>( variable );
-        else if( arrayDType == GetDType<unsigned char>() ) DefineVariableInADIOS<unsigned char>( variable );
-        else if( arrayDType == GetDType<short>() ) DefineVariableInADIOS<short>( variable );
-        else if( arrayDType == GetDType<unsigned short>() ) DefineVariableInADIOS<unsigned short>( variable );
-        else if( arrayDType == GetDType<int>() ) DefineVariableInADIOS<int>( variable );
-        else if( arrayDType == GetDType<unsigned int>() ) DefineVariableInADIOS<unsigned int>( variable );
-        else if( arrayDType == GetDType<long int>() ) DefineVariableInADIOS<long int>( variable );
-        else if( arrayDType == GetDType<unsigned long int>() ) DefineVariableInADIOS<unsigned long int>( variable );
-        else if( arrayDType == GetDType<long long int>() ) DefineVariableInADIOS<long long int>( variable );
-        else if( arrayDType == GetDType<unsigned long long int>() ) DefineVariableInADIOS<unsigned long long int>( variable );
-        else if( arrayDType == GetDType<float>() ) DefineVariableInADIOS<float>( variable );
-        else if( arrayDType == GetDType<double>() ) DefineVariableInADIOS<double>( variable );
-        else if( arrayDType == GetDType<long double>() ) DefineVariableInADIOS<long double>( variable );
-        else if( arrayDType == GetDType<std::complex<float>>() ) DefineVariableInADIOS<std::complex<float>>( variable );
-        else if( arrayDType == GetDType<std::complex<double>>() ) DefineVariableInADIOS<std::complex<double>>( variable );
-        else if( arrayDType == GetDType<std::complex<long double>>() ) DefineVariableInADIOS<std::complex<long double>>( variable );
+             if( IsType<char>( array ) ) DefineVariableInADIOS<char>( variable );
+        else if( IsType<unsigned char>( array ) ) DefineVariableInADIOS<unsigned char>( variable );
+        else if( IsType<short>( array ) ) DefineVariableInADIOS<short>( variable );
+        else if( IsType<unsigned short>( array ) ) DefineVariableInADIOS<unsigned short>( variable );
+        else if( IsType<int>( array ) ) DefineVariableInADIOS<int>( variable );
+        else if( IsType<unsigned int>( array ) ) DefineVariableInADIOS<unsigned int>( variable );
+        else if( IsType<long int>( array ) ) DefineVariableInADIOS<long int>( variable );
+        else if( IsType<unsigned long int>( array ) ) DefineVariableInADIOS<unsigned long int>( variable );
+        else if( IsType<long long int>( array ) ) DefineVariableInADIOS<long long int>( variable );
+        else if( IsType<unsigned long long int>( array ) ) DefineVariableInADIOS<unsigned long long int>( variable );
+        else if( IsType<float>( array ) ) DefineVariableInADIOS<float>( variable );
+        else if( IsType<double>( array ) ) DefineVariableInADIOS<double>( variable );
+        else if( IsType<long double>( array ) ) DefineVariableInADIOS<long double>( variable );
+        else if( IsType<std::complex<float>>( array ) ) DefineVariableInADIOS<std::complex<float>>( variable );
+        else if( IsType<std::complex<double>>( array ) ) DefineVariableInADIOS<std::complex<double>>( variable );
+        else if( IsType<std::complex<long double>>( array ) ) DefineVariableInADIOS<std::complex<long double>>( variable );
     }
 
-         if( arrayDType == GetDType<char>() ) WriteVariableInADIOS<char>( variable, array );
-    else if( arrayDType == GetDType<unsigned char>() ) WriteVariableInADIOS<unsigned char>( variable, array );
-    else if( arrayDType == GetDType<short>() ) WriteVariableInADIOS<short>( variable, array );
-    else if( arrayDType == GetDType<unsigned short>() ) WriteVariableInADIOS<unsigned short>( variable, array );
-    else if( arrayDType == GetDType<int>() ) WriteVariableInADIOS<int>( variable, array );
-    else if( arrayDType == GetDType<unsigned int>() ) WriteVariableInADIOS<unsigned int>( variable, array );
-    else if( arrayDType == GetDType<long int>() ) WriteVariableInADIOS<long int>( variable, array );
-    else if( arrayDType == GetDType<unsigned long int>() ) WriteVariableInADIOS<unsigned long int>( variable, array );
-    else if( arrayDType == GetDType<long long int>() ) WriteVariableInADIOS<long long int>( variable, array );
-    else if( arrayDType == GetDType<unsigned long long int>() ) WriteVariableInADIOS<unsigned long long int>( variable, array );
-    else if( arrayDType == GetDType<float>() ) WriteVariableInADIOS<float>( variable, array );
-    else if( arrayDType == GetDType<double>() ) WriteVariableInADIOS<double>( variable, array );
-    else if( arrayDType == GetDType<long double>() ) WriteVariableInADIOS<long double>( variable, array );
-    else if( arrayDType == GetDType<std::complex<float>>() ) WriteVariableInADIOS<std::complex<float>>( variable, array );
-    else if( arrayDType == GetDType<std::complex<double>>() ) WriteVariableInADIOS<std::complex<double>>( variable, array );
-    else if( arrayDType == GetDType<std::complex<long double>>() ) WriteVariableInADIOS<std::complex<long double>>( variable, array );
+         if( IsType<char>( array ) ) WriteVariableInADIOS<char>( variable, array );
+    else if( IsType<unsigned char>( array ) ) WriteVariableInADIOS<unsigned char>( variable, array );
+    else if( IsType<short>( array ) ) WriteVariableInADIOS<short>( variable, array );
+    else if( IsType<unsigned short>( array ) ) WriteVariableInADIOS<unsigned short>( variable, array );
+    else if( IsType<int>( array ) ) WriteVariableInADIOS<int>( variable, array );
+    else if( IsType<unsigned int>( array ) ) WriteVariableInADIOS<unsigned int>( variable, array );
+    else if( IsType<long int>( array ) ) WriteVariableInADIOS<long int>( variable, array );
+    else if( IsType<unsigned long int>( array ) ) WriteVariableInADIOS<unsigned long int>( variable, array );
+    else if( IsType<long long int>( array ) ) WriteVariableInADIOS<long long int>( variable, array );
+    else if( IsType<unsigned long long int>( array ) ) WriteVariableInADIOS<unsigned long long int>( variable, array );
+    else if( IsType<float>( array ) ) WriteVariableInADIOS<float>( variable, array );
+    else if( IsType<double>( array ) ) WriteVariableInADIOS<double>( variable, array );
+    else if( IsType<long double>( array ) ) WriteVariableInADIOS<long double>( variable, array );
+    else if( IsType<std::complex<float>>( array ) ) WriteVariableInADIOS<std::complex<float>>( variable, array );
+    else if( IsType<std::complex<double>>( array ) ) WriteVariableInADIOS<std::complex<double>>( variable, array );
+    else if( IsType<std::complex<long double>>( array ) ) WriteVariableInADIOS<std::complex<long double>>( variable, array );
+
 }
 
 
 
-void EnginePy::GetType( ) const
+void EnginePy::GetEngineType( ) const
 {
 	std::cout << "Engine type " << m_Engine->m_EngineType << "\n";
 }
diff --git a/bindings/python/src/MethodPy.cpp b/bindings/python/src/MethodPy.cpp
index ffcd05290..88babe0b4 100644
--- a/bindings/python/src/MethodPy.cpp
+++ b/bindings/python/src/MethodPy.cpp
@@ -6,6 +6,8 @@
  */
 
 
+#include <iostream>
+
 #include "MethodPy.h"
 #include "adiosPyFunctions.h"
 
@@ -29,20 +31,13 @@ MethodPy::MethodPy( const std::string type, const bool debugMode ):
 MethodPy::~MethodPy( )
 { }
 
-
+#ifdef HAVE_BOOSTPYTHON
 pyObject MethodPy::SetParametersPy( pyTuple args, pyDict kwargs )
 {
     if( py::len( args ) > 1  )
         throw std::invalid_argument( "ERROR: syntax of Method SetParameters function is incorrect, only use dictionary\n" );
 
-    #ifdef HAVE_BOOSTPYTHON
-    MethodPy& self = boost::python::extract<MethodPy&>( args[0] );
-    #endif
-
-    #ifdef HAVE_PYBIND11
-    MethodPy& self = (*this)( &args[0] );
-    #endif
-
+    MethodPy& self = PyCast<MethodPy&>( args[0] );
     self.m_Parameters = DictToMap( kwargs );
     return args[0];
 }
@@ -53,21 +48,32 @@ pyObject MethodPy::AddTransportPy( pyTuple args, pyDict kwargs )
     if( py::len( args ) != 2  )
         throw std::invalid_argument( "ERROR: syntax of Method AddTransport function is incorrect, only use one string for transport followed by a dictionary for parameters\n" );
 
-    #ifdef HAVE_BOOSTPYTHON
-    MethodPy& self = boost::python::extract<MethodPy&>( args[0] );
-    const std::string type = boost::python::extract<std::string>( args[1] );
-    #endif
-
-    #ifdef HAVE_PYBIND11
-    MethodPy& self = (*this)( &args[0] );
-    const std::string type = reinterpret_cast<std::string>( args[1] );
-    #endif
+    MethodPy& self = PyCast<MethodPy&>( args[0] );
+    const std::string type = PyCast<std::string>( args[1] );
 
     auto parameters = DictToMap( kwargs );
     parameters.insert( std::make_pair( "transport", type ) );
     self.m_TransportParameters.push_back( parameters );
     return args[0];
 }
+#endif
+
+
+#ifdef HAVE_PYBIND11
+void MethodPy::SetParametersPyBind11( pybind11::kwargs kwargs )
+{
+    this->m_Parameters = KwargsToMap( kwargs );
+}
+
+
+void MethodPy::AddTransportPyBind11( const std::string type, pybind11::kwargs kwargs )
+{
+    auto parameters = KwargsToMap( kwargs );
+    parameters.insert( std::make_pair( "transport", type ) );
+    this->m_TransportParameters.push_back( parameters );
+}
+#endif
+
 
 
 void MethodPy::PrintAll( ) const
diff --git a/bindings/python/src/adiosPyFunctions.cpp b/bindings/python/src/adiosPyFunctions.cpp
index e3155c037..80cef254d 100644
--- a/bindings/python/src/adiosPyFunctions.cpp
+++ b/bindings/python/src/adiosPyFunctions.cpp
@@ -14,15 +14,10 @@ namespace adios
 
 #ifdef HAVE_BOOSTPYTHON
 namespace py = boost::python;
-using pyCastString = py::extract<std::string>;
-using pyCastSize_t = py::extract<std::size_t>;
-
 #endif
 
 #ifdef HAVE_PYBIND11
 namespace py = pybind11;
-using pyCastString = pybind11::cast<std::string>;
-using pyCastSize_t = pybind11::cast<std::size_t>;
 #endif
 
 
@@ -34,41 +29,58 @@ Dims ListToVector( const pyList& list )
     vec.reserve( length );
 
     for( unsigned int i=0; i<length;i++ )
-        vec.push_back( pyCastSize_t( list[i]) );
+        vec.push_back( PyCast<std::size_t>( list[i]) );
 
     return vec;
 }
 
-
+#ifdef HAVE_BOOSTPYTHON
 std::map<std::string, std::string> DictToMap( const pyDict& dictionary )
 {
+    std::map<std::string, std::string> parameters;
+
     pyList keys = dictionary.keys();
     const unsigned int length = py::len( keys );
 
-    std::map<std::string, std::string> parameters;
-
     for( unsigned int k = 0; k < length; ++k )
     {
-        const std::string key( pyCastString( keys[k] ) );
-        const std::string value( pyCastString( dictionary[ keys[k] ] ) );
+        const std::string key( PyCast<std::string>( keys[k] ) );
+        const std::string value( PyCast<std::string>( dictionary[ keys[k] ] ) );
         parameters.insert( std::make_pair( key, value ) );
     }
 
     return parameters;
 }
+#endif
+
+#ifdef HAVE_PYBIND11
+std::map<std::string, std::string> KwargsToMap( const pybind11::kwargs& kwargs )
+{
+    std::map<std::string, std::string> parameters;
+
+    for( const auto& pair : kwargs )
+    {
+        const std::string key( PyCast<std::string>( pair.first ) );
+        const std::string value( PyCast<std::string>( pair.second ) );
+        parameters.insert( std::make_pair( key, value ) );
+    }
+    return parameters;
+}
+#endif
 
 
-dtype DType( const pyArray& array )
+bool IsEmpty( pyObject object )
 {
+    bool isEmpty = false;
 
 #ifdef HAVE_BOOSTPYTHON
-    return array.get_dtype();
+    if( object == boost::python::object() ) isEmpty = true;
 #endif
 
 #ifdef HAVE_PYBIND11
-    return array.dtype();
+    if( object == pybind11::none() ) isEmpty = true;
 #endif
-
+    return isEmpty;
 }
 
 
diff --git a/bindings/python/src/glueBoostPython.cpp b/bindings/python/src/glueBoostPython.cpp
index b0114261e..4a94464aa 100644
--- a/bindings/python/src/glueBoostPython.cpp
+++ b/bindings/python/src/glueBoostPython.cpp
@@ -14,6 +14,7 @@
 
 
 #include "ADIOSPy.h"
+#include "EnginePy.h"
 #include "adiosPyFunctions.h"
 
 
@@ -32,9 +33,6 @@ adios::ADIOSPy ADIOSPy( py::object py_comm, const bool debug )
 using ReturnInternalReference = py::return_internal_reference<>;
 BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS( open_overloads, adios::ADIOSPy::OpenPy, 3, 4 )
 
-BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS( write_overload, adios::EnginePy::WritePy, 2, 2 )
-
-
 
 BOOST_PYTHON_MODULE( ADIOSPy )
 {
@@ -51,104 +49,14 @@ BOOST_PYTHON_MODULE( ADIOSPy )
     //classes
     py::class_<adios::ADIOSPy>("ADIOS", py::no_init )
         .def("HelloMPI", &adios::ADIOSPy::HelloMPI )
-        .def("DefineVariableChar", &adios::ADIOSPy::DefineVariablePy<char>, ReturnInternalReference() )
-        .def("DefineVariableUChar", &adios::ADIOSPy::DefineVariablePy<unsigned char>, ReturnInternalReference() )
-        .def("DefineVariableShort", &adios::ADIOSPy::DefineVariablePy<short>, ReturnInternalReference() )
-        .def("DefineVariableUShort", &adios::ADIOSPy::DefineVariablePy<unsigned short>, ReturnInternalReference() )
-        .def("DefineVariableInt", &adios::ADIOSPy::DefineVariablePy<int>, ReturnInternalReference() )
-        .def("DefineVariableUInt", &adios::ADIOSPy::DefineVariablePy<unsigned int>, ReturnInternalReference() )
-        .def("DefineVariableLInt", &adios::ADIOSPy::DefineVariablePy<long int>, ReturnInternalReference() )
-        .def("DefineVariableULInt", &adios::ADIOSPy::DefineVariablePy<unsigned long int>, ReturnInternalReference() )
-        .def("DefineVariableLLInt", &adios::ADIOSPy::DefineVariablePy<long long int>, ReturnInternalReference() )
-        .def("DefineVariableULLInt", &adios::ADIOSPy::DefineVariablePy<unsigned long long int>, ReturnInternalReference() )
-        .def("DefineVariableFloat", &adios::ADIOSPy::DefineVariablePy<float>, ReturnInternalReference() )
-        .def("DefineVariableDouble", &adios::ADIOSPy::DefineVariablePy<double>, ReturnInternalReference() )
-        .def("DefineVariableLDouble", &adios::ADIOSPy::DefineVariablePy<long double>, ReturnInternalReference() )
-        .def("DefineVariableCFloat", &adios::ADIOSPy::DefineVariablePy<std::complex<float>>, ReturnInternalReference() )
-        .def("DefineVariableCDouble", &adios::ADIOSPy::DefineVariablePy<std::complex<double>>, ReturnInternalReference() )
-        .def("DefineVariableCLDouble", &adios::ADIOSPy::DefineVariablePy<std::complex<long double>>, ReturnInternalReference() )
+        .def("DefineVariable", &adios::ADIOSPy::DefineVariablePy )
         .def("DeclareMethod", &adios::ADIOSPy::DeclareMethodPy, ReturnInternalReference() )
 		.def("Open", &adios::ADIOSPy::OpenPy, open_overloads() )
     ;
 
-    py::class_<adios::VariablePy<char>>("VariableChar", py::no_init )
-        .def("SetLocalDimensions", &adios::VariablePy<char>::SetLocalDimensions )
-        .def("GetLocalDimensions", &adios::VariablePy<char>::GetLocalDimensions )
-    ;
-
-    py::class_<adios::VariablePy<unsigned char>>("VariableUChar", py::no_init )
-        .def("SetLocalDimensions", &adios::VariablePy<unsigned char>::SetLocalDimensions )
-        .def("GetLocalDimensions", &adios::VariablePy<unsigned char>::GetLocalDimensions )
-    ;
-
-    py::class_<adios::VariablePy<short>>("VariableShort", py::no_init )
-        .def("SetLocalDimensions", &adios::VariablePy<short>::SetLocalDimensions )
-        .def("GetLocalDimensions", &adios::VariablePy<short>::GetLocalDimensions )
-    ;
-
-    py::class_<adios::VariablePy<unsigned short>>("VariableUShort", py::no_init )
-        .def("SetLocalDimensions", &adios::VariablePy<unsigned short>::SetLocalDimensions )
-        .def("GetLocalDimensions", &adios::VariablePy<unsigned short>::GetLocalDimensions )
-    ;
-
-    py::class_<adios::VariablePy<int>>("VariableInt", py::no_init )
-        .def("SetLocalDimensions", &adios::VariablePy<int>::SetLocalDimensions )
-        .def("GetLocalDimensions", &adios::VariablePy<int>::GetLocalDimensions )
-    ;
-
-    py::class_<adios::VariablePy<unsigned int>>("VariableUInt", py::no_init )
-        .def("SetLocalDimensions", &adios::VariablePy<unsigned int>::SetLocalDimensions )
-        .def("GetLocalDimensions", &adios::VariablePy<unsigned int>::GetLocalDimensions )
-    ;
-
-    py::class_<adios::VariablePy<long int>>("VariableLInt", py::no_init )
-        .def("SetLocalDimensions", &adios::VariablePy<long int>::SetLocalDimensions )
-        .def("GetLocalDimensions", &adios::VariablePy<long int>::GetLocalDimensions )
-    ;
-
-    py::class_<adios::VariablePy<unsigned long int>>("VariableULInt", py::no_init )
-        .def("SetLocalDimensions", &adios::VariablePy<unsigned long int>::SetLocalDimensions )
-        .def("GetLocalDimensions", &adios::VariablePy<unsigned long int>::GetLocalDimensions )
-    ;
-
-    py::class_<adios::VariablePy<long long int>>("VariableLLInt", py::no_init )
-        .def("SetLocalDimensions", &adios::VariablePy<long long int>::SetLocalDimensions )
-        .def("GetLocalDimensions", &adios::VariablePy<long long int>::GetLocalDimensions )
-    ;
-
-    py::class_<adios::VariablePy<unsigned long long int>>("VariableULLInt", py::no_init )
-        .def("SetLocalDimensions", &adios::VariablePy<unsigned long long int>::SetLocalDimensions )
-        .def("GetLocalDimensions", &adios::VariablePy<unsigned long long int>::GetLocalDimensions )
-    ;
-
-    py::class_<adios::VariablePy<float>>("VariableFloat", py::no_init )
-        .def("SetLocalDimensions", &adios::VariablePy<float>::SetLocalDimensions )
-        .def("GetLocalDimensions", &adios::VariablePy<float>::GetLocalDimensions )
-    ;
-
-    py::class_<adios::VariablePy<double>>("VariableDouble", py::no_init )
-        .def("SetLocalDimensions", &adios::VariablePy<double>::SetLocalDimensions )
-        .def("GetLocalDimensions", &adios::VariablePy<double>::GetLocalDimensions )
-    ;
-
-    py::class_<adios::VariablePy<long double>>("VariableLDouble", py::no_init )
-        .def("SetLocalDimensions", &adios::VariablePy<long double>::SetLocalDimensions )
-        .def("GetLocalDimensions", &adios::VariablePy<long double>::GetLocalDimensions )
-    ;
-
-    py::class_<adios::VariablePy<std::complex<float>>>("VariableCFloat", py::no_init )
-        .def("SetLocalDimensions", &adios::VariablePy<std::complex<float>>::SetLocalDimensions )
-        .def("GetLocalDimensions", &adios::VariablePy<std::complex<float>>::GetLocalDimensions )
-    ;
-
-    py::class_<adios::VariablePy<std::complex<double>>>("VariableCDouble", py::no_init )
-        .def("SetLocalDimensions", &adios::VariablePy<std::complex<double>>::SetLocalDimensions )
-        .def("GetLocalDimensions", &adios::VariablePy<std::complex<double>>::GetLocalDimensions )
-    ;
-
-    py::class_<adios::VariablePy<std::complex<long double>>>("VariableCLDouble", py::no_init )
-        .def("SetLocalDimensions", &adios::VariablePy<std::complex<long double>>::SetLocalDimensions )
-        .def("GetLocalDimensions", &adios::VariablePy<std::complex<long double>>::GetLocalDimensions )
+    py::class_<adios::VariablePy>("Variable", py::no_init )
+        .def("SetLocalDimensions", &adios::VariablePy::SetLocalDimensions )
+        .def("GetLocalDimensions", &adios::VariablePy::GetLocalDimensions )
     ;
 
     py::class_<adios::MethodPy>("Method", py::no_init )
@@ -159,39 +67,7 @@ BOOST_PYTHON_MODULE( ADIOSPy )
 
     //Engine
     py::class_<adios::EnginePy>("EnginePy", py::no_init )
-        .def("Write", static_cast< void( adios::EnginePy::*)
-            (adios::VariablePy<char>&, const np::ndarray& )>( &adios::EnginePy::WritePy ), write_overload() )
-        .def("Write", static_cast< void( adios::EnginePy::*)
-            (adios::VariablePy<unsigned char>&, const np::ndarray& )>( &adios::EnginePy::WritePy ), write_overload() )
-        .def("Write", static_cast< void( adios::EnginePy::*)
-            (adios::VariablePy<short>&, const np::ndarray& )>( &adios::EnginePy::WritePy ), write_overload() )
-        .def("Write", static_cast< void( adios::EnginePy::*)
-            (adios::VariablePy<unsigned short>&, const np::ndarray& )>( &adios::EnginePy::WritePy ), write_overload() )
-        .def("Write", static_cast< void( adios::EnginePy::*)
-            (adios::VariablePy<int>&, const np::ndarray& )>( &adios::EnginePy::WritePy ), write_overload() )
-        .def("Write", static_cast< void( adios::EnginePy::*)
-            (adios::VariablePy<unsigned int>&, const np::ndarray& )>( &adios::EnginePy::WritePy ), write_overload() )
-        .def("Write", static_cast< void( adios::EnginePy::*)
-            (adios::VariablePy<long int>&, const np::ndarray& )>( &adios::EnginePy::WritePy ), write_overload() )
-        .def("Write", static_cast< void( adios::EnginePy::*)
-            (adios::VariablePy<unsigned long int>&, const np::ndarray& )>( &adios::EnginePy::WritePy ), write_overload() )
-        .def("Write", static_cast< void( adios::EnginePy::*)
-            (adios::VariablePy<long long int>&, const np::ndarray& )>( &adios::EnginePy::WritePy ), write_overload() )
-        .def("Write", static_cast< void( adios::EnginePy::*)
-            (adios::VariablePy<unsigned long long int>&, const np::ndarray& )>( &adios::EnginePy::WritePy ), write_overload() )
-        .def("Write", static_cast< void( adios::EnginePy::*)
-            (adios::VariablePy<float>&, const np::ndarray& )>( &adios::EnginePy::WritePy ), write_overload() )
-        .def("Write", static_cast< void( adios::EnginePy::*)
-            (adios::VariablePy<double>&, const np::ndarray& )>( &adios::EnginePy::WritePy ), write_overload() )
-        .def("Write", static_cast< void( adios::EnginePy::*)
-            (adios::VariablePy<long double>&, const np::ndarray& )>( &adios::EnginePy::WritePy ), write_overload() )
-        .def("Write", static_cast< void( adios::EnginePy::*)
-            (adios::VariablePy<std::complex<float>>&, const np::ndarray& )>( &adios::EnginePy::WritePy ), write_overload() )
-        .def("Write", static_cast< void( adios::EnginePy::*)
-            (adios::VariablePy<std::complex<double>>&, const np::ndarray& )>( &adios::EnginePy::WritePy ), write_overload() )
-        .def("Write", static_cast< void( adios::EnginePy::*)
-            (adios::VariablePy<std::complex<long double>>&, const np::ndarray& )>( &adios::EnginePy::WritePy ), write_overload() )
-
+        .def("Write", &adios::EnginePy::WritePy )
 		.def( "Close", &adios::EnginePy::Close )
     ;
 }
diff --git a/bindings/python/src/gluePyBind11.cpp b/bindings/python/src/gluePyBind11.cpp
index 0e83fd352..ccd727ce6 100644
--- a/bindings/python/src/gluePyBind11.cpp
+++ b/bindings/python/src/gluePyBind11.cpp
@@ -12,6 +12,7 @@
 #include "pybind11/pybind11.h"
 
 #include "ADIOSPy.h"
+#include "EnginePy.h"
 
 
 namespace py = pybind11;
@@ -35,13 +36,28 @@ PYBIND11_PLUGIN( ADIOSPy )
 
     py::class_<adios::ADIOSPy>( m, "ADIOS" )
         .def("HelloMPI", &adios::ADIOSPy::HelloMPI )
-        .def("DefineVariableDouble", &adios::ADIOSPy::DefineVariablePy<double>, py::return_value_policy::reference_internal )
-        .def("DefineVariableFloat", &adios::ADIOSPy::DefineVariablePy<float>, py::return_value_policy::reference_internal )
-//                py::arg("localDimensionsPy") = py::list(),
-//                py::arg("globalDimensionsPy") = py::list(), py::arg("globalOffsetsPy") = py::list()   )
+        .def("DefineVariable", &adios::ADIOSPy::DefineVariablePy )
         .def("DeclareMethod", &adios::ADIOSPy::DeclareMethodPy, py::return_value_policy::reference_internal )
         .def("Open", &adios::ADIOSPy::OpenPy )
     ;
 
+    py::class_<adios::VariablePy>( m, "Variable")
+        .def("SetLocalDimensions", &adios::VariablePy::SetLocalDimensions )
+        .def("GetLocalDimensions", &adios::VariablePy::GetLocalDimensions )
+    ;
+
+    py::class_<adios::MethodPy>( m, "Method")
+        .def("SetParameters", &adios::MethodPy::SetParametersPyBind11 )
+        .def("AddTransport", &adios::MethodPy::AddTransportPyBind11 )
+        .def("PrintAll", &adios::MethodPy::PrintAll )
+    ;
+
+    //Engine
+    py::class_<adios::EnginePy>( m, "Engine")
+        .def("Write", &adios::EnginePy::WritePy )
+        .def("Close", &adios::EnginePy::Close )
+    ;
+
+
     return m.ptr();
 }
diff --git a/bindings/python/test_hello.py b/bindings/python/test_hello.py
index f167ab0db..cb28d2f1e 100644
--- a/bindings/python/test_hello.py
+++ b/bindings/python/test_hello.py
@@ -9,37 +9,36 @@ import numpy as np
 # Create ADIOS and verify MPI Comm is passed correctly
 adios = ADIOSPy( MPI.COMM_WORLD, True ) #Pass communicator and debug flag is True
 rank = MPI.COMM_WORLD.Get_rank()
-size = MPI.COMM_WORLD.Get_size()
+size = MPI.COMM_WORLD.Get_size() 
 
 # User data
 myArray = np.array( [1,2,3,4])
 
-# if( rank % 2 == 1 ):  # odd ranks only
-oddRankArray = np.array( [11.,12.,13.,14.])
+if( rank % 2 == 1 ):  # odd ranks only
+    oddRankArray = np.array( [11.,12.,13.,14.] )
+    
 
 # ADIOS Define Variables    
-# ioMyDoubles = adios.DefineVariableDouble( "ioMyDoubles", [myArray.size], [], [] )
+ioArray = adios.DefineVariable( "ioArray", [myArray.size], [], [] )
 
-# if( rank % 2 == 1 ): # odd ranks only
-ioMyFloats = adios.DefineVariable( "ioMyFloats", [oddRankArray.size], [], [] )
-print oddRankArray.dtype
-print myArray.dtype
+if( rank % 2 == 1 ): # odd ranks only
+    ioOddRankArray = adios.DefineVariable( "ioMyFloats", [oddRankArray.size], [], [] )
+    
 
 #Setup method and print summary
 ioSettings = adios.DeclareMethod("adiosSettings", "BPFileWriter")
 ioSettings.SetParameters( max_buffer_size = '10000000' )
-ioSettings.AddTransport( 'File', have_metadata_file = 'yes', library = 'POSIX', blah = 'sds' )  # POSIX is default, just checking
+ioSettings.AddTransport( 'File', have_metadata_file = 'yes', library = 'POSIX' )  # POSIX is default, just checking
 
 #Start Engine
 bpFileWriter = adios.Open( "file.bp", "w", ioSettings, None )  # Open files using N-to-N method, None means no new MPI communicator
-# bpFileWriter.Write( ioMyDoubles, myArray )
-
-# if( rank % 2 == 1 ): 
-bpFileWriter.Write( ioMyFloats, oddRankArray )
+bpFileWriter.Write( ioArray, myArray )
 
+if( rank % 2 == 1 ): 
+    bpFileWriter.Write( ioOddRankArray, oddRankArray )
+    
 bpFileWriter.Close( ) 
 
 if( rank == 0 ):
     print "Done writing " + str( size ) + " bp files"
-    ioSettings.PrintAll( ) # just prints a summary of Method/Transport parameters
-    
\ No newline at end of file
+    ioSettings.PrintAll( ) # just prints a summary of Method/Transport parameters
\ No newline at end of file
diff --git a/include/ADIOS.h b/include/ADIOS.h
index 1c8f0f65e..00c58e52a 100644
--- a/include/ADIOS.h
+++ b/include/ADIOS.h
@@ -192,8 +192,6 @@ public: // PUBLIC Constructors and Functions define the User Interface with ADIO
 
 protected: //no const to allow default empty and copy constructors
 
-    std::map<unsigned int, Variable<void> > m_Unknown; ///< C style void* Variable, type is unknown at DefineVariable, used in Python
-
     std::map<unsigned int, Variable<char> > m_Char;
     std::map<unsigned int, Variable<unsigned char> > m_UChar;
     std::map<unsigned int, Variable<short> > m_Short;
@@ -268,17 +266,6 @@ protected: //no const to allow default empty and copy constructors
 };
 
 //template specializations of DefineVariable:
-template<> inline
-Variable<void>& ADIOS::DefineVariable( const std::string name, const Dims dimensions,
-                                       const Dims globalDimensions, const Dims globalOffsets )
-{
-    CheckVariableInput( name, dimensions );
-    const unsigned int size = m_Unknown.size();
-    m_Unknown.emplace( size, Variable<void>( name, dimensions, globalDimensions, globalOffsets, m_DebugMode ) );
-    m_Variables.emplace( name, std::make_pair( GetType<void>(), size ) );
-    return m_Unknown.at( size );
-}
-
 template<> inline
 Variable<char>& ADIOS::DefineVariable( const std::string name, const Dims dimensions,
                                        const Dims globalDimensions, const Dims globalOffsets )
@@ -471,10 +458,6 @@ Variable<std::complex<long double>>& ADIOS::DefineVariable( const std::string na
 
 
 //Get template specialization
-template<> inline
-Variable<void>& ADIOS::GetVariable( const std::string name )
-{ return m_Unknown.at( GetVariableIndex<void>(name) ); }
-
 template<> inline
 Variable<char>& ADIOS::GetVariable( const std::string name )
 { return m_Char.at( GetVariableIndex<char>(name) ); }
diff --git a/include/engine/bp/BPFileWriter.h b/include/engine/bp/BPFileWriter.h
index 3b48ea1e5..af45aa4b0 100644
--- a/include/engine/bp/BPFileWriter.h
+++ b/include/engine/bp/BPFileWriter.h
@@ -102,8 +102,6 @@ private:
 
     void WriteProcessGroupIndex( );
 
-
-
     /**
      * Common function for primitive (including std::complex) writes
      * @param group
diff --git a/include/format/BP1Writer.h b/include/format/BP1Writer.h
index f209bcea4..51fbd6d1d 100644
--- a/include/format/BP1Writer.h
+++ b/include/format/BP1Writer.h
@@ -324,6 +324,9 @@ public:
     }
 
 
+    void Advance( BP1MetadataSet& metadataSet, capsule::STLVector& buffer );
+
+
     /**
      * Function that sets metadata (if first close) and writes to a single transport
      * @param metadataSet current rank metadata set
diff --git a/src/engine/bp/BPFileWriter.cpp b/src/engine/bp/BPFileWriter.cpp
index 72a5066ff..e70a72e57 100644
--- a/src/engine/bp/BPFileWriter.cpp
+++ b/src/engine/bp/BPFileWriter.cpp
@@ -144,7 +144,7 @@ void BPFileWriter::Write( const std::string variableName, const void* values )
 
 void BPFileWriter::Advance( )
 {
-    //first close current pg
+
 }
 
 
diff --git a/src/format/BP1Writer.cpp b/src/format/BP1Writer.cpp
index 287d79f7e..11af2e254 100644
--- a/src/format/BP1Writer.cpp
+++ b/src/format/BP1Writer.cpp
@@ -95,6 +95,13 @@ void BP1Writer::WriteProcessGroupIndex( const bool isFortran, const std::string
 
 
 
+void BP1Writer::Advance( BP1MetadataSet& metadataSet, capsule::STLVector& buffer )
+{
+    FlattenData( metadataSet, buffer );
+
+
+}
+
 
 
 void BP1Writer::Close( BP1MetadataSet& metadataSet, capsule::STLVector& buffer, Transport& transport, bool& isFirstClose,
-- 
GitLab