From 4df1c4f0765daccdb26d25b8bbce7d121f8ae074 Mon Sep 17 00:00:00 2001
From: wfg <wfg@pc0098504.ornl.gov>
Date: Mon, 13 Mar 2017 17:58:16 -0400
Subject: [PATCH] Dynamic libadios.so version in Makefile and Python bindings

Started implementation of bindings/python using boost::python
Modified Makefile to allow for dynamic library compilation

To do:
Work on time aggregation
---
 Makefile                                   |  24 ++-
 bindings/python/Makefile                   |  41 +++++
 bindings/python/include/ADIOSPy.h          |  65 ++++++++
 bindings/python/include/adiosPyFunctions.h |  27 ++++
 bindings/python/src/ADIOSPy.cpp            | 169 +++++++++++++++++++++
 bindings/python/src/adiosPyFunctions.cpp   |  45 ++++++
 bindings/python/src/glue.cpp               |  48 ++++++
 bindings/python/test_hello.py              |  38 +++++
 examples/hello/bpWriter/helloBPWriter.cpp  |   2 +-
 include/ADIOS.h                            |   4 +-
 include/core/VariableBase.h                |   1 -
 src/engine/bp/BPFileWriter.cpp             |   4 +-
 12 files changed, 455 insertions(+), 13 deletions(-)
 create mode 100644 bindings/python/Makefile
 create mode 100644 bindings/python/include/ADIOSPy.h
 create mode 100644 bindings/python/include/adiosPyFunctions.h
 create mode 100644 bindings/python/src/ADIOSPy.cpp
 create mode 100644 bindings/python/src/adiosPyFunctions.cpp
 create mode 100644 bindings/python/src/glue.cpp
 create mode 100644 bindings/python/test_hello.py

diff --git a/Makefile b/Makefile
index 33d285130..706583463 100644
--- a/Makefile
+++ b/Makefile
@@ -4,12 +4,24 @@
      
 #DEFAULT COMPILERS IN PATH, LIBS will be modified in Makefile.libs
 CC:=g++
-AR:=ar
 MPICC:=mpic++
 LIBS:=
 
+SHARED:=no
 CFLAGS:=-c -Wall -Wpedantic -std=c++11 -O0 -g
-ARFLAGS:=rcs
+LINKERMPI:=ar
+LINKERNoMPI:=ar
+LINKERFLAGS:= rcs
+LIBEXT:=a
+
+ifeq ($(SHARED),yes)
+	CFLAGS+= -fPIC
+	LINKERMPI=$(MPICC) 
+	LINKERNoMPI=$(CC)
+	LINKERFLAGS= -shared -o
+	LIBEXT=so
+endif
+
 
 #ADIOS 
 HFiles:=$(shell find ./include -type f -name "*.h")
@@ -38,8 +50,8 @@ all: mpi nompi
 
 mpi: $(HFiles) $(OBJMPI)
 	@( mkdir -p ./lib );
-	$(AR) $(ARFLAGS) ./lib/libadios.a $(OBJMPI)
-	@echo "Finished building MPI library lib/libadios.a";
+	$(LINKERMPI) $(LINKERFLAGS) ./lib/libadios.$(LIBEXT) $(OBJMPI)
+	@echo "Finished building MPI library ./lib/libadios.$(LIBEXT)";
 	@echo
     
 ./bin/mpi/%.o: %.cpp $(HFiles)
@@ -48,8 +60,8 @@ mpi: $(HFiles) $(OBJMPI)
 
 nompi: $(HFiles) $(OBJNoMPI)
 	@( mkdir -p ./lib );
-	$(AR) $(ARFLAGS) ./lib/libadios_nompi.a $(OBJNoMPI)
-	@echo "Finished building noMPI library lib/libadios_nompi.a";
+	$(LINKERNoMPI) $(LINKERFLAGS) ./lib/libadios_nompi.$(LIBEXT) $(OBJNoMPI)
+	@echo "Finished building noMPI library ./lib/libadios.$(LIBEXT)";
 	@echo
 
 ./bin/nompi/%.o: %.cpp $(HFiles)
diff --git a/bindings/python/Makefile b/bindings/python/Makefile
new file mode 100644
index 000000000..68eca071f
--- /dev/null
+++ b/bindings/python/Makefile
@@ -0,0 +1,41 @@
+#Makefile
+# Created on: Mar 13, 2017
+#     Author: wfg
+
+# location of the Python header files
+PYTHON_VERSION:= 2.7
+PYTHON_INC:= /usr/include/python$(PYTHON_VERSION)
+PYTHON_LIBLOC:= /usr/lib/python2.7/config-x86_64-linux-gnu/
+ 
+# location of the Boost Python include files and library 
+BOOST_INC:= /usr/include/boost
+BOOST_LIBLOC:= /lib/x86_64-linux-gnu/
+
+# location of ADIOS include and lib
+ADIOS_INC:= /home/wfg/workspace/ADIOSPP/include
+ADIOS_LIB:= /home/wfg/workspace/ADIOSPP/lib
+ADIOSPy_INC:=./include
+
+CFLAGS:=-c -Wall -fPIC -O0 -g -std=c++11
+
+CPPFiles:=$(shell find ./src -type f -name "*.cpp")
+OBJS:=$(patsubst %.cpp, ./bin/%.o, $(notdir $(CPPFiles)) )
+
+INC:= -I$(PYTHON_INC) -I$(BOOST_INC) -I$(ADIOS_INC) -I$(ADIOSPy_INC)
+LIBS:= -L$(ADIOS_LIB) -ladios -L$(BOOST_LIBLOC) -lboost_python-py27 -L$(PYTHON_LIBLOC) -lpython$(PYTHON_VERSION)
+
+ 
+# compile mesh classes
+TARGET = ADIOSPy
+
+all: $(TARGET).so
+ 
+$(TARGET).so: $(OBJS)
+	mpic++ -shared -o $(TARGET).so -Wl,--export-dynamic $(OBJS) $(LIBS) 
+ 
+./bin/%.o: ./src/%.cpp
+	@( mkdir -p ./bin );
+	mpic++ $(INC) $(CFLAGS) -o $@ $<
+	
+clean:
+	rm ./bin/*.o *.so
\ No newline at end of file
diff --git a/bindings/python/include/ADIOSPy.h b/bindings/python/include/ADIOSPy.h
new file mode 100644
index 000000000..ad802f4ff
--- /dev/null
+++ b/bindings/python/include/ADIOSPy.h
@@ -0,0 +1,65 @@
+/*
+ * ADIOSPy.h
+ *
+ *  Created on: Mar 13, 2017
+ *      Author: wfg
+ */
+
+#ifndef ADIOSPY_H_
+#define ADIOSPY_H_
+
+#include <string>
+
+#include <boost/python.hpp>
+
+#include "ADIOS.h"
+#include "adiosPyFunctions.h" //ListToVector, VectorToList
+
+
+namespace adios
+{
+
+
+class ADIOSPy : public ADIOS
+{
+
+public:
+
+    ADIOSPy( MPI_Comm mpiComm, const bool debug );
+    ~ADIOSPy( );
+
+    void HelloMPI( ); ///< says hello from rank/size for testing
+
+    std::string DefineVariableDouble( const std::string name,
+                                      const boost::python::list localDimensionsPy = boost::python::list(),
+                                      const boost::python::list globalDimensionsPy = boost::python::list(),
+                                      const boost::python::list globalOffsetsPy = boost::python::list() );
+
+    std::string DefineVariableFloat( const std::string name,
+                                     const boost::python::list localDimensionsPy = boost::python::list(),
+                                     const boost::python::list globalDimensionsPy = boost::python::list(),
+                                     const boost::python::list globalOffsetsPy = boost::python::list() );
+
+    void SetVariableLocalDimensions( const std::string name, const boost::python::list list );
+
+    boost::python::list GetVariableLocalDimensions( const std::string name );
+
+
+private:
+    template< class T >
+    std::string DefineVariablePy( const std::string name, const boost::python::list& localDimensionsPy,
+                                  const boost::python::list& globalDimensionsPy, const boost::python::list& globalOffsetsPy )
+    {
+        DefineVariable<T>( name, ListToVector( localDimensionsPy ), ListToVector( globalDimensionsPy ), ListToVector( globalOffsetsPy ) );
+        return name;
+    }
+
+
+};
+
+
+
+} //end namespace
+
+
+#endif /* ADIOSPY_H_ */
diff --git a/bindings/python/include/adiosPyFunctions.h b/bindings/python/include/adiosPyFunctions.h
new file mode 100644
index 000000000..99935b2a6
--- /dev/null
+++ b/bindings/python/include/adiosPyFunctions.h
@@ -0,0 +1,27 @@
+/*
+ * adiosPyFunctions.h
+ *
+ *  Created on: Mar 13, 2017
+ *      Author: wfg
+ */
+
+#ifndef ADIOSPYFUNCTIONS_H_
+#define ADIOSPYFUNCTIONS_H_
+
+#include <vector>
+#include <string>
+#include <boost/python.hpp>
+
+
+namespace adios
+{
+
+std::vector<std::size_t> ListToVector( const boost::python::list& list );
+
+boost::python::list VectorToList( const std::vector<std::size_t>& list );
+
+}
+
+
+
+#endif /* ADIOSPYFUNCTIONS_H_ */
diff --git a/bindings/python/src/ADIOSPy.cpp b/bindings/python/src/ADIOSPy.cpp
new file mode 100644
index 000000000..9b3845f21
--- /dev/null
+++ b/bindings/python/src/ADIOSPy.cpp
@@ -0,0 +1,169 @@
+/*
+ * ADIOSPy.cpp
+ *
+ *  Created on: Mar 13, 2017
+ *      Author: wfg
+ */
+
+#include <iostream>
+
+#include "ADIOSPy.h"
+
+namespace adios
+{
+
+
+ADIOSPy::ADIOSPy( MPI_Comm mpiComm, const bool debug ):
+    ADIOS( mpiComm, debug )
+{ }
+
+
+ADIOSPy::~ADIOSPy( )
+{ }
+
+
+void ADIOSPy::HelloMPI( )
+{
+    std::cout << "Hello ADIOSPy from rank " << m_RankMPI << "/" << m_SizeMPI << "\n";
+}
+
+
+std::string ADIOSPy::DefineVariableFloat( const std::string name, const boost::python::list localDimensionsPy,
+                                          const boost::python::list globalDimensionsPy, const boost::python::list globalOffsetsPy )
+{
+    return DefineVariablePy<float>( name, localDimensionsPy, globalDimensionsPy, globalOffsetsPy );
+}
+
+
+std::string ADIOSPy::DefineVariableDouble( const std::string name, const boost::python::list localDimensionsPy,
+                                           const boost::python::list globalDimensionsPy, const boost::python::list globalOffsetsPy )
+{
+    return DefineVariablePy<double>( name, localDimensionsPy, globalDimensionsPy, globalOffsetsPy );
+}
+
+
+void ADIOSPy::SetVariableLocalDimensions( const std::string name, const boost::python::list list )
+{
+
+    auto itVar = m_Variables.find( name );
+    CheckVariableName( itVar, name, " in SetVariableLocalDimensions\n" );
+
+    const std::string type = itVar->second.first;
+
+    if( type == GetType<char>() )
+        GetVariable<char>( name ).m_Dimensions = ListToVector( list );
+
+    else if( type == GetType<unsigned char>() )
+        GetVariable<unsigned char>( name ).m_Dimensions = ListToVector( list );
+
+    else if( type == GetType<short>() )
+        GetVariable<short>( name ).m_Dimensions = ListToVector( list );
+
+    else if( type == GetType<unsigned short>() )
+        GetVariable<unsigned short>( name ).m_Dimensions = ListToVector( list );
+
+    else if( type == GetType<int>() )
+        GetVariable<int>( name ).m_Dimensions = ListToVector( list );
+
+    else if( type == GetType<unsigned int>() )
+        GetVariable<unsigned int>( name ).m_Dimensions = ListToVector( list );
+
+    else if( type == GetType<long int>() )
+        GetVariable<long int>( name ).m_Dimensions = ListToVector( list );
+
+    else if( type == GetType<unsigned long int>() )
+        GetVariable<unsigned long int>( name ).m_Dimensions = ListToVector( list );
+
+    else if( type == GetType<long long int>() )
+        GetVariable<long long int>( name ).m_Dimensions = ListToVector( list );
+
+    else if( type == GetType<unsigned long long int>() )
+        GetVariable<unsigned long long int>( name ).m_Dimensions = ListToVector( list );
+
+    else if( type == GetType<float>() )
+        GetVariable<float>( name ).m_Dimensions = ListToVector( list );
+
+    else if( type == GetType<double>() )
+        GetVariable<double>( name ).m_Dimensions = ListToVector( list );
+
+    else if( type == GetType<long double>() )
+        GetVariable<long double>( name ).m_Dimensions = ListToVector( list );
+
+    else if( type == GetType<std::complex<float>>() )
+        GetVariable<std::complex<float>>( name ).m_Dimensions = ListToVector( list );
+
+    else if( type == GetType<std::complex<double>>() )
+        GetVariable<std::complex<double>>( name ).m_Dimensions = ListToVector( list );
+
+    else if( type == GetType<std::complex<long double>>() )
+        GetVariable<std::complex<long double>>( name ).m_Dimensions = ListToVector( list );
+}
+
+
+boost::python::list ADIOSPy::GetVariableLocalDimensions( const std::string name )
+{
+    auto itVar = m_Variables.find( name );
+    CheckVariableName( itVar, name, " in SetVariableLocalDimensions\n" );
+
+    const std::string type = itVar->second.first;
+
+    std::vector<std::size_t> dims;
+
+    if( type == GetType<char>() )
+        dims = GetVariable<char>( name ).m_Dimensions;
+
+    else if( type == GetType<unsigned char>() )
+        dims = GetVariable<unsigned char>( name ).m_Dimensions;
+
+    else if( type == GetType<short>() )
+        dims = GetVariable<short>( name ).m_Dimensions;
+
+    else if( type == GetType<unsigned short>() )
+        dims = GetVariable<unsigned short>( name ).m_Dimensions;
+
+    else if( type == GetType<int>() )
+        dims = GetVariable<int>( name ).m_Dimensions;
+
+    else if( type == GetType<unsigned int>() )
+        dims = GetVariable<unsigned int>( name ).m_Dimensions;
+
+    else if( type == GetType<long int>() )
+        dims = GetVariable<long int>( name ).m_Dimensions;
+
+    else if( type == GetType<unsigned long int>() )
+        dims = GetVariable<unsigned long int>( name ).m_Dimensions;
+
+    else if( type == GetType<long long int>() )
+        dims = GetVariable<long long int>( name ).m_Dimensions;
+
+    else if( type == GetType<unsigned long long int>() )
+        dims = GetVariable<unsigned long long int>( name ).m_Dimensions;
+
+    else if( type == GetType<float>() )
+        dims = GetVariable<float>( name ).m_Dimensions;
+
+    else if( type == GetType<double>() )
+        dims = GetVariable<double>( name ).m_Dimensions;
+
+    else if( type == GetType<long double>() )
+        dims = GetVariable<long double>( name ).m_Dimensions;
+
+    else if( type == GetType<std::complex<float>>() )
+        dims = GetVariable<std::complex<float>>( name ).m_Dimensions;
+
+    else if( type == GetType<std::complex<double>>() )
+        dims = GetVariable<std::complex<double>>( name ).m_Dimensions;
+
+    else if( type == GetType<std::complex<long double>>() )
+        dims = GetVariable<std::complex<long double>>( name ).m_Dimensions;
+
+    //return dims;
+    return VectorToList( dims );
+}
+
+
+
+
+} //end namespace
+
+
diff --git a/bindings/python/src/adiosPyFunctions.cpp b/bindings/python/src/adiosPyFunctions.cpp
new file mode 100644
index 000000000..df8b41439
--- /dev/null
+++ b/bindings/python/src/adiosPyFunctions.cpp
@@ -0,0 +1,45 @@
+/*
+ * adiosPyFunctions.cpp
+ *
+ *  Created on: Mar 13, 2017
+ *      Author: wfg
+ */
+#include <iostream>
+
+#include "adiosPyFunctions.h"
+
+
+namespace adios
+{
+
+std::vector<std::size_t> ListToVector( const boost::python::list& list )
+{
+    const boost::python::ssize_t length = boost::python::len( list );
+    std::vector<std::size_t> vec;
+    vec.reserve( length );
+
+    for( unsigned int i=0; i<length;i++ )
+        vec.push_back( boost::python::extract<std::size_t>( list[i]) );
+
+    return vec;
+}
+
+
+boost::python::list VectorToList( const std::vector<std::size_t>& vec )
+{
+    boost::python::list list;
+
+    for( auto vecElement : vec )
+    {
+        list.append( vecElement );
+    }
+
+    return list;
+}
+
+
+
+
+
+}
+
diff --git a/bindings/python/src/glue.cpp b/bindings/python/src/glue.cpp
new file mode 100644
index 000000000..93ebb9434
--- /dev/null
+++ b/bindings/python/src/glue.cpp
@@ -0,0 +1,48 @@
+/*
+ * glue.cpp
+ *
+ *  Created on: Mar 13, 2017
+ *      Author: wfg
+ */
+
+#include <mpi4py/mpi4py.h>
+#include <boost/python.hpp>
+#include <boost/python/suite/indexing/vector_indexing_suite.hpp>
+
+#include "ADIOSPy.h"
+#include "adiosPyFunctions.h"
+
+
+adios::ADIOSPy ADIOSPy( boost::python::object py_comm, const bool debug )
+{
+    MPI_Comm* comm_p = PyMPIComm_Get( py_comm.ptr() );
+    if (comm_p == NULL) boost::python::throw_error_already_set();
+    return adios::ADIOSPy( *comm_p, debug );
+}
+
+
+BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS( d_overloads, DefineVariableDouble, 1, 4 )
+BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS( f_overloads, DefineVariableFloat, 1, 4 )
+
+
+BOOST_PYTHON_MODULE( ADIOSPy )
+{
+    if (import_mpi4py() < 0) return; /* Python 2.X */
+
+
+    boost::python::class_<std::vector<std::size_t> >("Dims")
+        .def(boost::python::vector_indexing_suite< std::vector<std::size_t> >() );
+    //functions
+    boost::python::def("ADIOSPy", ADIOSPy );
+
+    //classes
+    boost::python::class_<adios::ADIOSPy>("ADIOS", boost::python::no_init )
+        .def("HelloMPI", &adios::ADIOSPy::HelloMPI )
+        .def("DefineVariableDouble", &adios::ADIOSPy::DefineVariableDouble, d_overloads() )
+        .def("DefineVariableFloat", &adios::ADIOSPy::DefineVariableFloat, f_overloads() )
+        .def("SetVariableLocalDimensions", &adios::ADIOSPy::SetVariableLocalDimensions )
+        .def("GetVariableLocalDimensions", &adios::ADIOSPy::GetVariableLocalDimensions )
+    ;
+
+
+}
diff --git a/bindings/python/test_hello.py b/bindings/python/test_hello.py
new file mode 100644
index 000000000..0b9cd13ce
--- /dev/null
+++ b/bindings/python/test_hello.py
@@ -0,0 +1,38 @@
+# test_hello.py
+#  Created on: Feb 2, 2017
+#      Author: wfg
+
+from mpi4py import MPI
+from ADIOSPy import *
+
+adios = ADIOSPy( MPI.COMM_WORLD, True)
+adios.HelloMPI( )
+
+lDims = [10, 11, 12]
+Nx = 1
+
+print lDims
+print lDims[0]
+ioMyDoubles = adios.DefineVariableDouble( "ioMyDoubles", lDims )
+ioMyFloats = adios.DefineVariableFloat( "ioMyFloats", [Nx] )
+
+print "My ADIOS Variable Double " + ioMyDoubles
+print "My ADIOS Variable Float " + ioMyFloats
+
+dims = adios.GetVariableLocalDimensions( ioMyDoubles )
+print "Old Dimensions " 
+print dims
+
+lDims = [20,20,20]
+adios.SetVariableLocalDimensions( ioMyDoubles, lDims )
+
+dims = adios.GetVariableLocalDimensions( ioMyDoubles )
+print "New Dimensions " 
+print dims
+
+
+# bpWriter = adios.Open( )
+# ADIOS.SetEngineComm( bpWriter, comm ) 
+# bpWriter.Hello( )
+
+# challenge is to pass comm to C++
diff --git a/examples/hello/bpWriter/helloBPWriter.cpp b/examples/hello/bpWriter/helloBPWriter.cpp
index 2251ecdf3..496bdeb3f 100644
--- a/examples/hello/bpWriter/helloBPWriter.cpp
+++ b/examples/hello/bpWriter/helloBPWriter.cpp
@@ -54,7 +54,7 @@ int main( int argc, char* argv [] )
 
         //Define method for engine creation, it is basically straight-forward parameters
         adios::Method& bpWriterSettings = adios.DeclareMethod( "SingleFile" ); //default method type is BPWriter
-        bpWriterSettings.AddTransport( "File", "have_metadata_file=yes" ); //uses default POSIX library
+        bpWriterSettings.AddTransport( "File", "have_metadata_file=no" ); //uses default POSIX library
 
         //Create engine smart pointer due to polymorphism,
         //Open returns a smart pointer to Engine containing the Derived class Writer
diff --git a/include/ADIOS.h b/include/ADIOS.h
index 8c3ba6216..00c58e52a 100644
--- a/include/ADIOS.h
+++ b/include/ADIOS.h
@@ -84,10 +84,8 @@ public: // PUBLIC Constructors and Functions define the User Interface with ADIO
 
     ~ADIOS( ); ///< empty, using STL containers for memory management
 
-
     void InitMPI( ); ///< sets rank and size in m_rank and m_Size, respectively.
 
-
     /**
      * Look for template specialization
      * @param name
@@ -192,7 +190,7 @@ public: // PUBLIC Constructors and Functions define the User Interface with ADIO
 
 
 
-private: //no const to allow default empty and copy constructors
+protected: //no const to allow default empty and copy constructors
 
     std::map<unsigned int, Variable<char> > m_Char;
     std::map<unsigned int, Variable<unsigned char> > m_UChar;
diff --git a/include/core/VariableBase.h b/include/core/VariableBase.h
index 07d6602f7..4bf492354 100644
--- a/include/core/VariableBase.h
+++ b/include/core/VariableBase.h
@@ -22,7 +22,6 @@ namespace adios
 
 using Dims = std::vector<std::size_t>;
 
-
 class VariableBase
 {
 
diff --git a/src/engine/bp/BPFileWriter.cpp b/src/engine/bp/BPFileWriter.cpp
index 8be5a0249..a22d286c0 100644
--- a/src/engine/bp/BPFileWriter.cpp
+++ b/src/engine/bp/BPFileWriter.cpp
@@ -246,7 +246,7 @@ void BPFileWriter::InitTransports( )
     for( const auto& parameters : m_Method.m_TransportParameters )
     {
         auto itProfile = parameters.find( "profile_units" );
-        Support::Resolutions resolution;
+        Support::Resolutions resolution = Support::Resolutions::s; //default is seconds
         if( itProfile != parameters.end() )
         {
             if( itProfile->second == "mus" || itProfile->second == "microseconds" )
@@ -362,7 +362,7 @@ void BPFileWriter::WriteProcessGroupIndex( )
 bool BPFileWriter::CheckBuffersAllocation( const std::size_t indexSize, const std::size_t payloadSize )
 {
     //Check if data in buffer needs to be reallocated
-    const std::size_t neededSize = m_Buffer.m_DataPosition + payloadSize + indexSize + 500; //adding some bytes tolerance
+    const std::size_t neededSize = m_Buffer.m_DataPosition + payloadSize + indexSize + 100; //adding some bytes tolerance
     // might need to write payload in batches
     bool doTransportsFlush = ( neededSize > m_MaxBufferSize )? true : false;
 
-- 
GitLab