diff --git a/CMakeLists.txt b/CMakeLists.txt index 4b517fd8..dff351ba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -350,6 +350,9 @@ set(TRIQS_LINK_LIBS # General include header # remove this dep to C++ include_directories(${TRIQS_SOURCE_DIR}) +# for the generated headers for python convertions +include_directories(${CMAKE_BINARY_DIR}/include/) +# Add it to triqs definitions #-------------------------------- # General C++ compilation flags diff --git a/cmake/FindPythonWrapperMacro.cmake b/cmake/FindPythonWrapperMacro.cmake index 4418e93b..bac2164a 100644 --- a/cmake/FindPythonWrapperMacro.cmake +++ b/cmake/FindPythonWrapperMacro.cmake @@ -6,21 +6,20 @@ include_directories(${PYTHON_INCLUDE_DIRS} ${PYTHON_NUMPY_INCLUDE_DIR}) # ModuleName = the python name of the module # ModuleDest = path in the pytriqs tree [ FOR INSTALLATION ONLY] IMPROVE MAKE THIS OPTIONAL (for test) -#EXECUTE_PROCESS(COMMAND mkdir -p ${CMAKE_BINARY_DIR}/pytriqs/converters/) +EXECUTE_PROCESS(COMMAND mkdir -p ${CMAKE_BINARY_DIR}/include/pytriqs/converters/) include_directories( ${CMAKE_BINARY_DIR}) macro (triqs_python_extension ModuleName) message(STATUS "Preparing extension module ${ModuleName}") SET(wrap_name ${CMAKE_CURRENT_BINARY_DIR}/${ModuleName}_wrap.cpp) - SET(converter_name ${CMAKE_CURRENT_BINARY_DIR}/${ModuleName}_converter.cpp) + SET(converter_name ${CMAKE_BINARY_DIR}/include/pytriqs/converters/${ModuleName}.hpp) # Adjust pythonpath so that pytriqs is visible and the wrap_generator too... # pytriqs needed since we import modules with pure python method to extract the doc.. add_custom_command(OUTPUT ${wrap_name} ${converter_name} DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${ModuleName}_desc.py COMMAND PYTHONPATH=${CMAKE_BINARY_DIR}/pytriqs/wrap_generator:${CMAKE_BINARY_DIR}/ ${PYTHON_INTERPRETER} ${CMAKE_CURRENT_BINARY_DIR}/${ModuleName}_desc.py ${CMAKE_SOURCE_DIR}/pytriqs/wrap_generator/wrapper.mako.cpp ${wrap_name} ${CMAKE_SOURCE_DIR}/pytriqs/wrap_generator/py_converter_wrapper.mako.hpp ${converter_name} ) - set_property (GLOBAL APPEND PROPERTY TRIQS_PY_CONVERTERS_CPP_LIST "${CMAKE_CURRENT_BINARY_DIR}/${ModuleName}_converter.cpp") set_property (GLOBAL APPEND PROPERTY TRIQS_PY_CONVERTERS_TARGETS "python_wrap_${ModuleName}") add_custom_target(python_wrap_${ModuleName} ALL DEPENDS ${wrap_name} ${converter_name}) @@ -33,6 +32,7 @@ macro (triqs_python_extension ModuleName) target_link_libraries(${ModuleName} ${TRIQS_LINK_LIBS} triqs) if (${ARGN} MATCHES "") + install (FILES ${converter_name} DESTINATION "include/pytriqs/converters") install (TARGETS ${ModuleName} DESTINATION ${TRIQS_PYTHON_LIB_DEST}/${ARGN} ) endif (${ARGN} MATCHES "") #set_property (GLOBAL APPEND PROPERTY DEPENDANCE_TO_ADD triqs_${NickName} ) diff --git a/pytriqs/CMakeLists.txt b/pytriqs/CMakeLists.txt index 8c003394..5e264846 100644 --- a/pytriqs/CMakeLists.txt +++ b/pytriqs/CMakeLists.txt @@ -1,4 +1,4 @@ -option(Python_use_mpi4py "Use mpi4py instead of boost.mpi" OFF) +option(Python_use_mpi4py "Use mpi4py (if OFF, use boost.mpi)" OFF) if (Python_use_mpi4py) SET (TRIQS_PYTHON_MPI_USE_MPI4PY 1) else() diff --git a/pytriqs/gf/local/CMakeLists.txt b/pytriqs/gf/local/CMakeLists.txt index 250b1052..f1589735 100644 --- a/pytriqs/gf/local/CMakeLists.txt +++ b/pytriqs/gf/local/CMakeLists.txt @@ -2,15 +2,15 @@ SET(PYTHON_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/__init__.py ${CMAKE_CURRENT_SOURCE_DIR}/block_gf.py + ${CMAKE_CURRENT_SOURCE_DIR}/descriptor_base.py ${CMAKE_CURRENT_SOURCE_DIR}/descriptors.py - ${CMAKE_CURRENT_SOURCE_DIR}/gf_generic.py - ${CMAKE_CURRENT_SOURCE_DIR}/gf_imfreq.py - ${CMAKE_CURRENT_SOURCE_DIR}/gf_imtime.py - ${CMAKE_CURRENT_SOURCE_DIR}/gf_legendre.py - ${CMAKE_CURRENT_SOURCE_DIR}/gf_refreq.py - ${CMAKE_CURRENT_SOURCE_DIR}/gf_retime.py - ${CMAKE_CURRENT_SOURCE_DIR}/gf_two_real_times.py - ${CMAKE_CURRENT_SOURCE_DIR}/impl_plot.py + ${CMAKE_CURRENT_SOURCE_DIR}/_gf_imfreq.py + ${CMAKE_CURRENT_SOURCE_DIR}/_gf_imtime.py + #${CMAKE_CURRENT_SOURCE_DIR}/_gf_legendre.py + ${CMAKE_CURRENT_SOURCE_DIR}/_gf_refreq.py + ${CMAKE_CURRENT_SOURCE_DIR}/_gf_retime.py + #${CMAKE_CURRENT_SOURCE_DIR}/gf_two_real_times.py + ${CMAKE_CURRENT_SOURCE_DIR}/_gf_plot.py ${CMAKE_CURRENT_SOURCE_DIR}/inverse.py ${CMAKE_CURRENT_SOURCE_DIR}/lazy_expressions.py ${CMAKE_CURRENT_SOURCE_DIR}/tools.py diff --git a/pytriqs/gf/local/gf_desc.py b/pytriqs/gf/local/gf_desc.py index 98f68729..3990a2e5 100644 --- a/pytriqs/gf/local/gf_desc.py +++ b/pytriqs/gf/local/gf_desc.py @@ -1,7 +1,6 @@ from wrap_generator import * module = module_(full_name = "pytriqs.gf.local.gf", doc = "Local Green functions ...") -module.add_include("") module.add_include("") module.add_include("") module.add_include("") @@ -16,6 +15,7 @@ module.add_using("triqs::utility::mini_vector") t = class_( py_type = "TailGf", c_type = "local::tail_view", + c_type_absolute = "triqs::gfs::local::tail_view", serializable= "tuple", is_printable= True, arithmetic = ("algebra","double") @@ -85,9 +85,11 @@ module.add_class(t) ######################## module.add_enum(c_name = "statistic_enum", + c_name_absolute = "triqs::gfs::statistic_enum", values = ["Fermion","Boson"]) module.add_enum(c_name = "mesh_kind", + c_name_absolute = "triqs::gfs::mesh_kind", values = ["half_bins","full_bins","without_last"]) ######################## @@ -97,6 +99,7 @@ module.add_enum(c_name = "mesh_kind", def make_mesh( py_type, c_tag, has_kind=True, is_im=False) : m = class_( py_type = py_type, c_type = "gf_mesh<%s>"%c_tag, + c_type_absolute = "triqs::gfs::gf_mesh"%c_tag, serializable= "tuple", is_printable= True, ) @@ -196,6 +199,7 @@ def make_gf( py_type, c_tag, is_complex_data = True, is_im = False) : g = class_( py_type = py_type, c_type = "gf_view<%s>"%c_tag, + c_type_absolute = "triqs::gfs::gf_view"%c_tag, #serializable= "boost", serializable= "tuple", is_printable= True, @@ -306,10 +310,6 @@ def make_gf( py_type, c_tag, is_complex_data = True, is_im = False) : # Pure python methods g.add_pure_python_method("pytriqs.gf.local._gf_%s.plot"%c_tag, py_name = "_plot_") - g.add_method(py_name = "_as_C_pointer", - calling_pattern = 'auto result = PyCapsule_New(new std::pair(&self_c,typeid(self_c)),NULL,NULL)', - signature = "PyObject*()") - return g ######################## diff --git a/pytriqs/parameters/parameters_desc.py b/pytriqs/parameters/parameters_desc.py index 1c6cc470..dfd26120 100644 --- a/pytriqs/parameters/parameters_desc.py +++ b/pytriqs/parameters/parameters_desc.py @@ -1,7 +1,7 @@ from wrap_generator import * # The module -module = module_(full_name = "pytriqs.parameters.parameters.my_module", doc = " Doc of my_module ") +module = module_(full_name = "pytriqs.parameters.parameters", doc = "TO BE WRITTEN") module.add_include("") module.add_include("") module.add_using("namespace triqs::params") @@ -9,7 +9,7 @@ module.add_using("namespace triqs::params") # one class g = class_( py_type = "Parameters", - c_type = "parameters", + c_type = "triqs::params::parameters", #serializable= "tuple", is_printable= True, hdf5 = True, diff --git a/pytriqs/wrap_generator/py_converter_wrapper.mako.hpp b/pytriqs/wrap_generator/py_converter_wrapper.mako.hpp index 429fc170..b55ea440 100644 --- a/pytriqs/wrap_generator/py_converter_wrapper.mako.hpp +++ b/pytriqs/wrap_generator/py_converter_wrapper.mako.hpp @@ -1,5 +1,8 @@ // Specialization of py_converter to types wrapped by the wrap_generator. // DO NOT EDIT. Generated automatically by wrap_generator +#pragma once +// in case it is included in the module ${module.full_name}.so, we do not want this specialization +#ifndef TRIQS_PYTHON_WRAPPER_MODULE_${module.name} %for file in module.include_list : %if file.startswith('<'): @@ -9,39 +12,34 @@ %endif %endfor -using dcomplex = std::complex; - -%for ns in module.using: -using ${ns}; -%endfor - -//#include #include namespace triqs { namespace py_tools { -%for n,t in enumerate(module.wrapped_types_by_me) : +%for n,c in enumerate(module.classes.values()) : - template<> void ** py_converter<${t}>::init() { +template<> struct py_converter<${c.c_type_absolute}> { + + static void ** init() { PyObject * mod = PyImport_ImportModule("${module.full_name}"); if (mod ==NULL) return NULL; void ** table = (void **)PyCapsule_Import("${module.full_name}._exported_wrapper_convert_fnt", 0); return table; } - template<> PyObject * py_converter<${t}>::c2py(${t} const & x){ + static PyObject * c2py(${c.c_type_absolute} const & x){ static void **wrapped_convert_fnt = init(); if (wrapped_convert_fnt == NULL) return NULL; - return ((PyObject * (*)(${t} const &)) wrapped_convert_fnt[3*${n}])(x); + return ((PyObject * (*)(${c.c_type_absolute} const &)) wrapped_convert_fnt[3*${n}])(x); } - template<> ${t}& py_converter<${t}>::py2c(PyObject * ob){ + static ${c.c_type_absolute}& py2c(PyObject * ob){ static void **wrapped_convert_fnt = init(); if (wrapped_convert_fnt == NULL) std::terminate(); // It should never happen since py2c is called only is is_convertible is true (py_converter specs) - return ((${t}& (*)(PyObject *)) wrapped_convert_fnt[3*${n}+1])(ob); + return ((${c.c_type_absolute}& (*)(PyObject *)) wrapped_convert_fnt[3*${n}+1])(ob); } - template<> bool py_converter<${t}>::is_convertible(PyObject *ob, bool raise_exception) { + static bool is_convertible(PyObject *ob, bool raise_exception) { static void **wrapped_convert_fnt = init(); if (wrapped_convert_fnt == NULL) { if (!raise_exception && PyErr_Occurred()) {PyErr_Print();PyErr_Clear();} @@ -49,6 +47,65 @@ namespace triqs { namespace py_tools { } return ((bool (*)(PyObject *,bool)) wrapped_convert_fnt[3*${n}+2])(ob,raise_exception); } -%endfor -}} +}; +%endfor + +//--------------------- Converters of regular types -------------------------- + +%for c in module.classes.values() : + + %if c.implement_regular_type_converter : + // ${c.py_type} is wrapping a view, we are also implementing the converter of the associated regular type + template<> struct py_converter<${c.regular_type_absolute}> { + using regular_type = ${c.regular_type_absolute}; + using conv = py_converter<${c.c_type_absolute}>; + static PyObject *c2py(regular_type &g) { return conv::c2py(g); } + static PyObject *c2py(regular_type &&g) { return conv::c2py(g); } + static bool is_convertible(PyObject * ob, bool raise_exception) { return conv::is_convertible(ob, raise_exception); } + static regular_type py2c(PyObject *ob) { return conv::py2c(ob); } +}; +%endif +%endfor +//--------------------- Converters of enums -------------------------- + +%for en in module.enums : + +namespace triqs { namespace py_tools { + +template <> struct py_converter<${en.c_name_absolute}> { + static PyObject * c2py(${en.c_name_absolute} x) { + %for n,val in enumerate(en.values[:-1]) : + if (x == ${val}) return PyString_FromString("${val}"); + %endfor + return PyString_FromString("${en.values[-1]}"); // last case separate to avoid no return warning of compiler + } + static ${en.c_name_absolute} py2c(PyObject * ob){ + std::string s=PyString_AsString(ob); + %for n,val in enumerate(en.values[:-1]) : + if (s == "${val}") return ${val}; + %endfor + return ${en.values[-1]}; + } + static bool is_convertible(PyObject *ob, bool raise_exception) { + if (!PyString_Check(ob)) { + if (raise_exception) PyErr_SetString(PyExc_ValueError, "Convertion of C++ enum ${en.c_name_absolute} : the object is not a string"); + return false; + } + std::string s=PyString_AsString(ob); + %for n,val in enumerate(en.values) : + if (s == "${val}") return true; + %endfor + if (raise_exception) { + auto err = "Convertion of C++ enum ${en.c_name_absolute} : \nThe string \"" + s +"\" is not in [${','.join([str(x) for x in en.values])}]"; + PyErr_SetString(PyExc_ValueError, err.c_str()); + } + return false; + } +}; + +}} +%endfor + +}} +#endif diff --git a/pytriqs/wrap_generator/wrap_generator.py b/pytriqs/wrap_generator/wrap_generator.py index b06d34e1..af73a883 100644 --- a/pytriqs/wrap_generator/wrap_generator.py +++ b/pytriqs/wrap_generator/wrap_generator.py @@ -235,6 +235,8 @@ class class_ : Representation of a wrapped type Data : - c_type : C++ type to be wrapped. + - c_type_absolute : full path of c_type, no using, no alias (need for + the py_converter hpp file) - py_type : Name given in Python - doc : the doc string. - c_type_is_view : boolean @@ -244,11 +246,14 @@ class class_ : - members : a dict : string -> member_ """ hidden_python_function = {} # global dict of the python function to add to the module, hidden for the user, for precompute and so on - def __init__(self, c_type, py_type, hdf5 = False, arithmetic = None, serializable = None, is_printable = False, doc = '' ) : + def __init__(self, c_type, py_type, c_type_absolute = None, hdf5 = False, arithmetic = None, serializable = None, is_printable = False, doc = '' ) : self.c_type = c_type + self.c_type_absolute = c_type_absolute or c_type self.c_type_is_view = is_type_a_view(c_type) self.implement_regular_type_converter = self.c_type_is_view # by default, it will also make the converter of the associated regular type - if self.c_type_is_view : self.regular_type = 'typename ' + self.c_type + '::regular_type' + if self.c_type_is_view : + self.regular_type = 'typename ' + self.c_type + '::regular_type' + self.regular_type_absolute = 'typename ' + self.c_type_absolute + '::regular_type' self.py_type = py_type c_to_py_type[self.c_type] = self.py_type # register the name translation for the doc generation self.hdf5 = hdf5 @@ -420,8 +425,8 @@ class enum_ : - values : list of string representing the enumerated - doc : the doc string. """ - def __init__(self, c_name, values, doc = '') : - self.c_name, self.values, self.doc = c_name, values, doc + def __init__(self, c_name, values, c_name_absolute = None, doc = '') : + self.c_name, self.c_name_absolute, self.values, self.doc = c_name, c_name_absolute or c_name, values, doc class module_ : """ @@ -443,7 +448,6 @@ class module_ : self.classes = {} self.functions = {} self.include_list = [] - self.wrapped_types_by_me = {} self.enums = [] self.using =[] self.python_functions = {} @@ -452,8 +456,8 @@ class module_ : def add_class(self, cls): if cls.py_type in self.classes : raise IndexError, "The class %s already exists"%cls.py_type self.classes[cls.py_type] = cls - self.wrapped_types[cls.c_type] = cls.py_type - self.wrapped_types_by_me[cls.c_type] = cls.py_type + self.wrapped_types[cls.c_type] = cls + self.wrapped_types[cls.c_type_absolute] = cls # we can call is by its name or its absolute name def add_function(self, **kw): if "name" in kw : diff --git a/pytriqs/wrap_generator/wrapper.mako.cpp b/pytriqs/wrap_generator/wrapper.mako.cpp index c68b9431..b8952a4d 100644 --- a/pytriqs/wrap_generator/wrapper.mako.cpp +++ b/pytriqs/wrap_generator/wrapper.mako.cpp @@ -1,4 +1,5 @@ //--------------------- includes and using ------------------------------------- +#define TRIQS_PYTHON_WRAPPER_MODULE_${module.name} %for file in module.include_list : %if file.startswith('<'): @@ -966,15 +967,15 @@ init${module.name}(void) register_h5_reader_for_${c.py_type}(); %endfor -%if len(module.wrapped_types_by_me) >0 : +%if len(module.classes) >0 : // declare the exported wrapper functions - static void * _exported_wrapped_convert_fnt[3*${len(module.wrapped_types_by_me)}]; + static void * _exported_wrapped_convert_fnt[3*${len(module.classes)}]; // init the array with the function pointers - %for n,t in enumerate(module.wrapped_types_by_me) : - _exported_wrapped_convert_fnt[3*${n}] = (void *)convert_to_python<${t}>; - _exported_wrapped_convert_fnt[3*${n}+1] = (void *)convert_from_python<${t}>; - _exported_wrapped_convert_fnt[3*${n}+2] = (void *)convertible_from_python<${t}>; + %for n,c in enumerate(module.classes.values()) : + _exported_wrapped_convert_fnt[3*${n}] = (void *)convert_to_python<${c.c_type_absolute}>; + _exported_wrapped_convert_fnt[3*${n}+1] = (void *)convert_from_python<${c.c_type_absolute}>; + _exported_wrapped_convert_fnt[3*${n}+2] = (void *)convertible_from_python<${c.c_type_absolute}>; %endfor /* Create a Capsule containing the API pointer array's address */ diff --git a/pytriqs/wrap_test/a.hpp b/pytriqs/wrap_test/a.hpp index 221bb0eb..3a88c2ef 100644 --- a/pytriqs/wrap_test/a.hpp +++ b/pytriqs/wrap_test/a.hpp @@ -1,3 +1,4 @@ +#pragma once #include #include #include diff --git a/pytriqs/wrap_test/b.hpp b/pytriqs/wrap_test/b.hpp index 7be6003c..b80ed867 100644 --- a/pytriqs/wrap_test/b.hpp +++ b/pytriqs/wrap_test/b.hpp @@ -1,3 +1,4 @@ +#pragma once #include "./a.hpp" /// some function using A diff --git a/pytriqs/wrap_test/my_moduleB_desc.py b/pytriqs/wrap_test/my_moduleB_desc.py index ff115353..88473050 100644 --- a/pytriqs/wrap_test/my_moduleB_desc.py +++ b/pytriqs/wrap_test/my_moduleB_desc.py @@ -3,6 +3,7 @@ from wrap_generator import * # The module mod = module_(full_name = "pytriqs.wrap_test.my_moduleB", doc = " Doc of my_module ") mod.add_include("") +mod.add_include("") mod.add_function (name = "print_a2", signature = "void(A a)", doc = "DOC of print_a") diff --git a/triqs/CMakeLists.txt b/triqs/CMakeLists.txt index 1f2de960..f6f408be 100644 --- a/triqs/CMakeLists.txt +++ b/triqs/CMakeLists.txt @@ -5,18 +5,6 @@ FOREACH(CPP ${ALLSOURCES}) ENDFOREACH(CPP ${ALLSOURCES}) get_property(ALLSOURCES GLOBAL PROPERTY TRIQS_LIB_CPP_SOURCES_LIST) -## The library also contains all the converters python <-> C++ -## automatically generated for all wrapped modules. -## The lists are defined in subdirectory, in each module -## NB : pytriqs subdir is and must be called BEFORE triqs, or these lists are empty -get_property(all_py_converters_sources GLOBAL PROPERTY TRIQS_PY_CONVERTERS_CPP_LIST) -get_property(all_py_converters_targets GLOBAL PROPERTY TRIQS_PY_CONVERTERS_TARGETS) - -# All files are generated, cmake should not worry not to see them at configuration time -foreach(CPP ${all_py_converters_sources}) - set_source_files_properties(${CPP} PROPERTIES GENERATED TRUE) -endforeach() - # compile every subdirectory add_all_subdirectories_with_cmakelist() @@ -30,7 +18,8 @@ add_library(triqs ${ALLSOURCES} ${all_py_converters_sources}) target_link_libraries (triqs ${LINK_RT} ${TRIQS_LINK_LIBS} ) # The TRIQS library depends on the generation of the .cpp wrapper and converters files -# which must be produced first. +# which are produced first. +get_property(all_py_converters_targets GLOBAL PROPERTY TRIQS_PY_CONVERTERS_TARGETS) foreach(T ${all_py_converters_targets}) add_dependencies(triqs ${T}) endforeach() diff --git a/triqs/mc_tools/mc_generic.hpp b/triqs/mc_tools/mc_generic.hpp index 22a8e80f..3f5806a1 100644 --- a/triqs/mc_tools/mc_generic.hpp +++ b/triqs/mc_tools/mc_generic.hpp @@ -60,7 +60,7 @@ namespace triqs { namespace mc_tools { * \param[in] P dictionary parameters * \param[in] AfterCycleDuty a function bool() to be called after each QMC cycle */ - mc_generic(utility::parameters const & P, std::function AfterCycleDuty = std::function() ) : + mc_generic(params::parameters const & P, std::function AfterCycleDuty = std::function() ) : RandomGenerator(std::string(P["random_name"]), long(P["random_seed"])), report(&std::cout,int(P["verbosity"])), AllMoves(RandomGenerator), diff --git a/triqs/parameters/parameters.hpp b/triqs/parameters/parameters.hpp index 152aadd6..8344132b 100644 --- a/triqs/parameters/parameters.hpp +++ b/triqs/parameters/parameters.hpp @@ -20,6 +20,7 @@ ******************************************************************************/ #pragma once #include "./_field.hpp" + namespace triqs { namespace params { @@ -100,7 +101,6 @@ namespace params { p1.update(p2); return p1; } - // can only be implemented after complete declaration of parameters template _field& _field::add_field(T&&... x) { auto* pp = dynamic_cast<_data_impl*>(p.get()); @@ -108,7 +108,6 @@ namespace params { pp->x.add_field(std::forward(x)...); return *this; } - - } } +#include diff --git a/triqs/python_tools/wrapper_tools.hpp b/triqs/python_tools/wrapper_tools.hpp index 0bfdb3c8..ed331dfe 100644 --- a/triqs/python_tools/wrapper_tools.hpp +++ b/triqs/python_tools/wrapper_tools.hpp @@ -57,12 +57,11 @@ class pyref { //--------------------- py_converters ----------------------------- // default version for a wrapped type. To be specialized later. -template struct py_converter { - static void ** init(); - static PyObject * c2py(T const & x); - static T & py2c(PyObject * ob); - static bool is_convertible(PyObject * ob, bool raise_exception); -}; +template struct py_converter; + //static PyObject * c2py(T const & x); + //static T & py2c(PyObject * ob); + //static bool is_convertible(PyObject * ob, bool raise_exception); + // // We only use these functions in the code, not converter // TODO : Does c2py return NULL in failure ? Or is it undefined...