From 2b5dd322ce6d2b5f7b8a9c525189271095ba73c6 Mon Sep 17 00:00:00 2001 From: Olivier Parcollet Date: Thu, 29 May 2014 21:34:46 +0200 Subject: [PATCH] lattice : python wrapper --- pytriqs/gf/local/CMakeLists.txt | 2 +- pytriqs/lattice/CMakeLists.txt | 10 +- pytriqs/lattice/lattice_tools.pyx | 116 ----------------------- pytriqs/lattice/lattice_tools_desc.py | 105 ++++++++++++++++++++ pytriqs/wrap_generator/CMakeLists.txt | 8 ++ pytriqs/wrap_generator/wrap_generator.py | 14 ++- pytriqs/wrap_generator/wrapper.mako.cpp | 7 ++ test/pytriqs/base/dos.py | 2 +- triqs/lattice/bravais_lattice.hpp | 2 +- triqs/lattice/tight_binding.hpp | 2 + triqs/python_tools/wrapper_tools.hpp | 36 +++++++ 11 files changed, 175 insertions(+), 129 deletions(-) delete mode 100644 pytriqs/lattice/lattice_tools.pyx create mode 100644 pytriqs/lattice/lattice_tools_desc.py create mode 100644 pytriqs/wrap_generator/CMakeLists.txt diff --git a/pytriqs/gf/local/CMakeLists.txt b/pytriqs/gf/local/CMakeLists.txt index f1589735..09f00616 100644 --- a/pytriqs/gf/local/CMakeLists.txt +++ b/pytriqs/gf/local/CMakeLists.txt @@ -6,7 +6,7 @@ SET(PYTHON_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/descriptors.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_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 diff --git a/pytriqs/lattice/CMakeLists.txt b/pytriqs/lattice/CMakeLists.txt index 6224933e..92371ad5 100644 --- a/pytriqs/lattice/CMakeLists.txt +++ b/pytriqs/lattice/CMakeLists.txt @@ -5,12 +5,10 @@ SET(PYTHON_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/tight_binding.py ) +install (FILES ${CMAKE_SOURCE_DIR}/pytriqs/__init__.py.template DESTINATION "include/pytriqs/gf/local" RENAME __init__.py) + install (FILES ${PYTHON_SOURCES} DESTINATION ${TRIQS_PYTHON_LIB_DEST}/lattice) -# THE C++ code -#SET(CPP_DIR ${CMAKE_CURRENT_SOURCE_DIR}/C++) -cython_module(LatticeTools lattice_tools lattice ) - -# ??? -#target_link_libraries(_pytriqs_LatticeTools triqs ${TRIQS_LINK_LIBS}) +# Build C extension module +triqs_python_extension(lattice_tools lattice) diff --git a/pytriqs/lattice/lattice_tools.pyx b/pytriqs/lattice/lattice_tools.pyx deleted file mode 100644 index 62e6a31c..00000000 --- a/pytriqs/lattice/lattice_tools.pyx +++ /dev/null @@ -1,116 +0,0 @@ -from dcomplex cimport * -from shared_ptr cimport * -from arrays cimport * -from libcpp.pair cimport pair -from libcpp.vector cimport vector -from libcpp.string cimport string as std_string -#from extractor cimport * -#from h5 cimport * -from cython.operator cimport dereference as deref, preincrement as inc #dereference and increment operator - -import numpy - -cdef extern from "triqs/lattice/brillouin_zone.hpp" : - cdef cppclass bravais_lattice_c " triqs::lattice::bravais_lattice" : - bravais_lattice_c(matrix[double] & units, vector[tqa_vector[double]] &, vector[std_string] &) except + - int n_orbitals() - matrix[double] units() - int dim() - tqa_vector[double] lattice_to_real_coordinates (tqa_vector_view[double] &) - -cdef extern from "triqs/lattice/tight_binding.hpp" namespace "triqs::gf" : - cdef cppclass tight_binding " triqs::lattice::tight_binding" : - tight_binding(bravais_lattice_c & units, vector[vector[long]] &, vector[matrix[dcomplex]] &) except + - - #Fix the name conflict pv wiht a pxd, cf doc....? - array_view[complex,THREE] hopping_stack_c "hopping_stack" (tight_binding & TB, array_view[double,TWO] & k_stack) - pair [array[double,ONE],array[double,TWO]] dos_c "dos" (tight_binding & TB, size_t nkpts, size_t neps) - pair [array[double,ONE],array[double,ONE]] dos_patch_c "dos_patch" (tight_binding & TB, array_view[double,TWO] & triangles, size_t neps, size_t ndiv) - array_view[double,TWO] energies_on_bz_path_c "energies_on_bz_path" (tight_binding & TB, tqa_vector[double] & K1, tqa_vector[double] & K2, size_t n_pts) - array_view[complex,THREE] energy_matrix_on_bz_path_c "energy_matrix_on_bz_path" (tight_binding & TB, tqa_vector[double] & K1, tqa_vector[double] & K2, size_t n_pts) - array_view[double,TWO] energies_on_bz_grid_c "energies_on_bz_grid" (tight_binding & TB, size_t n_pts) - -cdef class BravaisLattice : - """ - """ - cdef bravais_lattice_c * _c - def __init__(self, units, orbital_positions = None ) : - """ """ - cdef vector[std_string] names - cdef vector[tqa_vector[double]] atom_pos - orbital_positions = orbital_positions if orbital_positions else dict ("", (0,0,0) ) - for name, pos in orbital_positions.items(): - names.push_back(name) - atom_pos.push_back(tqa_vector[double](pos)) - self._c = new bravais_lattice_c( matrix[double](units),atom_pos, names) - - def __dealloc__(self): - del self._c - - def lattice_to_real_coordinates(self, R) : - """ - Transform into real coordinates. - :param x_in: coordinates in the basis of the unit vectors - :rtype: Output coordinates in R^3 (real coordinates) as an array - """ - return self._c.lattice_to_real_coordinates ( tqa_vector_view[double] (R)).to_python() - - property dim : - """Dimension of the lattice""" - def __get__(self) : - """Dimension of the lattice""" - return self._c.dim() - - def n_orbitals(self) : - """Number of orbitals""" - return self._c.n_orbitals() - -cdef class TightBinding: - """ - """ - cdef tight_binding * _c - def __init__(self, BravaisLattice bravais_lattice, hopping ) : - """ """ - #self._c = new tight_binding(deref(bravais_lattice._c)) - #cdef vector[long] d - cdef vector[matrix[dcomplex]] mats - cdef vector[vector[long]] displs - for displ, mat in hopping.items() : - displs.push_back(displ) - #d = displ - mats.push_back(matrix[dcomplex] (numpy.array(mat, dtype =float))) - #self._c.push_back( d, matrix[double] (numpy.array(mat, dtype =float))) - self._c = new tight_binding(deref(bravais_lattice._c), displs, mats) - - def __dealloc__(self): - del self._c - -# ------------------------------------------- - -def hopping_stack (TightBinding TB, k_stack) : - """ """ - return hopping_stack_c(deref(TB._c), array_view[double,TWO](k_stack)).to_python() - -def dos ( TightBinding TB, int nkpts, int neps): - """ """ - a = dos_c(deref(TB._c), nkpts, neps) - return (a.first.to_python(), a.second.to_python()) - -def dos_patch ( TightBinding TB, triangles, int neps, int ndiv): - """ """ - a = dos_patch_c(deref(TB._c), array_view[double,TWO] (triangles), neps, ndiv) - return (a.first.to_python(), a.second.to_python()) - -def energies_on_bz_path ( TightBinding TB, K1, K2, n_pts) : - """ """ - return energies_on_bz_path_c (deref(TB._c), tqa_vector[double](K1), tqa_vector[double] (K2), n_pts).to_python() - -def energy_matrix_on_bz_path ( TightBinding TB, K1, K2, n_pts) : - """ """ - return energy_matrix_on_bz_path_c (deref(TB._c), tqa_vector[double](K1), tqa_vector[double] (K2), n_pts).to_python() - -def energies_on_bz_grid ( TightBinding TB, n_pts) : - """ """ - return energies_on_bz_grid_c (deref(TB._c), n_pts).to_python() - - diff --git a/pytriqs/lattice/lattice_tools_desc.py b/pytriqs/lattice/lattice_tools_desc.py new file mode 100644 index 00000000..62863f41 --- /dev/null +++ b/pytriqs/lattice/lattice_tools_desc.py @@ -0,0 +1,105 @@ +from wrap_generator import * + +module = module_(full_name = "pytriqs.lattice_tools", doc = "Lattice tools (to be improved)") +module.add_include("") +module.add_include("") +module.add_using("namespace triqs::lattice") +module.add_using("namespace triqs::arrays") +module.add_using("namespace triqs") +module.add_using("r_t = arrays::vector") +module.add_using("k_t = arrays::vector") + +# --------- Bravais lattice ---------------------------------- + +bl = class_( py_type = "BravaisLattice", + c_type = "bravais_lattice", + c_type_absolute = "triqs::lattice::bravais_lattice", + serializable= "tuple", + ) + +bl.add_constructor(signature = "(matrix units, std::vector orbital_positions, std::vector atom_orb_name)", + doc = "") +bl.add_constructor(signature = "(matrix units, std::vector orbital_positions)", + doc = "") +bl.add_constructor(signature = "(matrix units)", + doc = "") +bl.add_constructor(signature = "()", + doc = "") + +bl.add_property(getter = cfunction(c_name="dim", signature = "int()"), + doc = "Dimension of the lattice") + +bl.add_property(getter = cfunction(c_name="n_orbitals", signature = "int()"), + doc = "Number of orbitals") + +bl.add_property(getter = cfunction(c_name="units", signature = "matrix_const_view()"), + doc = "Base vectors of the lattice") + +bl.add_method(py_name = "lattice_to_real_coordinates", + c_name = "lattice_to_real_coordinates", + signature = "r_t(r_t x)", + doc = "Transform into real coordinates.") + +module.add_class(bl) + +# --------- TightBinding ---------------------------------- +tb = class_( py_type = "TightBinding", + c_type = "tight_binding", + c_type_absolute = "triqs::lattice::tight_binding", + #serializable= "tuple", + ) + +tb.add_constructor(signature = "(bravais_lattice latt, PyObject* hopping)", + calling_pattern = + """ + // We need to rewrite manually the call to the constructor : + // hopping is a dict : displacement -> matrix + // we flatten it into 2 vector of vector and matrix resp. + // for the tight_binding constructor + // First of all, if it is not a dict, error + if (!PyDict_Check(hopping)) {PyErr_SetString(PyExc_TypeError, "hopping must be a mapping type (dict)"); return 0;} + // The arguments for the C++ constructor + std::vector> displs; + std::vector> mats; + // we loop on the dict // Cf python doc for PyDict_Next + PyObject *key, *value; + Py_ssize_t pos = 0; + while (PyDict_Next(hopping, &pos, &key, &value)) { + displs.push_back(convert_from_python>(key)); + mats.push_back(convert_from_python>(value)); + } + auto result = tight_binding(*latt, displs, mats); + """, + doc = " ") + +module.add_class(tb) + +# --------- Module functions ---------------------------------- + +module.add_function(name = "hopping_stack", + signature = "array (tight_binding TB, array_const_view k_stack)", + doc = """ """) +module.add_function(name = "dos", + signature = "std::pair, array> (tight_binding TB, int nkpts, int neps)", + doc = """ """) +module.add_function(name = "dos_patch", + signature = "std::pair, array> (tight_binding TB, array triangles, int neps, int ndiv)", + doc = """ """) +module.add_function(name = "energies_on_bz_path", + signature = "array (tight_binding TB, k_t K1, k_t K2, int n_pts)", + doc = """ """) +module.add_function(name = "energy_matrix_on_bz_path", + signature = "array (tight_binding TB, k_t K1, k_t K2, int n_pts)", + doc = """ """) +module.add_function(name = "energies_on_bz_grid", + signature = "array (tight_binding TB, int n_pts)", + doc = """ """) + +######################## +## Code generation +######################## + +if __name__ == '__main__' : + module.generate_code(mako_template = sys.argv[1], wrap_file = sys.argv[2]) + module.generate_py_converter_header(mako_template = sys.argv[3], wrap_file = sys.argv[4]) + diff --git a/pytriqs/wrap_generator/CMakeLists.txt b/pytriqs/wrap_generator/CMakeLists.txt new file mode 100644 index 00000000..8868b4ac --- /dev/null +++ b/pytriqs/wrap_generator/CMakeLists.txt @@ -0,0 +1,8 @@ +SET(PYTHON_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/wrap_generator.py + ${CMAKE_CURRENT_SOURCE_DIR}/py_converter_wrapper.mako.hpp + ${CMAKE_CURRENT_SOURCE_DIR}/wrapper.mako.cpp + ) + +install (FILES ${PYTHON_SOURCES} DESTINATION ${CMAKE_INSTALL_PREFIX}/share/triqs/wrap_generator) + diff --git a/pytriqs/wrap_generator/wrap_generator.py b/pytriqs/wrap_generator/wrap_generator.py index af73a883..0ecf7a63 100644 --- a/pytriqs/wrap_generator/wrap_generator.py +++ b/pytriqs/wrap_generator/wrap_generator.py @@ -57,10 +57,11 @@ class cfunction : def f(): # analyse the argument, be careful that , can also be in type, like A, so we count the < > acc = '' for s in args.split(',') : - acc += (',' if acc else '') + s + acc += (',' if acc else '') + s.strip() if acc.count('<') == acc.count('>') : r, acc = acc,'' yield r + args = [ re.sub('=',' ',x).split() for x in f() if x] # list of (type, name, default) or (type, name) else: self.rtype = kw.pop("rtype", None) @@ -351,12 +352,17 @@ class class_ : All arguments passed by keywords to function_ construction """ assert 'c_name' not in kw, "No c_name here" - assert 'calling_pattern' not in kw, "No calling_pattern here" - f = cfunction(c_name = "__init__", is_constructor = True, **kw) + #assert 'calling_pattern' not in kw, "No calling_pattern here" + if 'calling_pattern' not in kw : kw['c_name'] = "__init__" + f = cfunction(is_constructor = True, **kw) build_type = regular_type_if_view_else_type(self.c_type) if self.c_type_is_view and build_from_regular_type else self.c_type all_args = ",".join([ ('*' if t in module_.wrapped_types else '') + n for t,n,d in f.args]) #all_args = ",".join([ ('*' if t in module_.wrapped_types else '') + n + (' = ' + d if d else '') for t,n,d in f.args]) - f._calling_pattern = "((%s *)self)->_c ->"%self.py_type + ('operator =' if not self.c_type_is_view else 'rebind') + " (%s (%s));"%(build_type,all_args) + if 'calling_pattern' not in kw : + f._calling_pattern = "((%s *)self)->_c ->"%self.py_type + ('operator =' if not self.c_type_is_view else 'rebind') + " (%s (%s));"%(build_type,all_args) + else : + f._calling_pattern = kw['calling_pattern'] + "\n ((%s *)self)->_c ->"%self.py_type + ('operator =' if not self.c_type_is_view else 'rebind') + " (std::move(result));" + if not self.constructor : self.constructor = pyfunction(py_name = "__init__", **kw) self.constructor.is_constructor = True diff --git a/pytriqs/wrap_generator/wrapper.mako.cpp b/pytriqs/wrap_generator/wrapper.mako.cpp index a67c9023..177596b2 100644 --- a/pytriqs/wrap_generator/wrapper.mako.cpp +++ b/pytriqs/wrap_generator/wrapper.mako.cpp @@ -150,11 +150,18 @@ static PyObject* ${c.py_type}_new(PyTypeObject *type, PyObject *args, PyObject * ${c.py_type} *self; self = (${c.py_type} *)type->tp_alloc(type, 0); if (self != NULL) { + try { %if not c.c_type_is_view : self->_c = new ${c.c_type}{}; %else : self->_c = new ${c.c_type}{typename ${c.c_type}::regular_type{}}; // no default constructor for views %endif + } + catch (std::exception const & e) { + std::cout << e.what()< const& units, std::vector atom_orb_pos) : bravais_lattice(units, atom_orb_pos, std::vector(atom_orb_pos.size(), "")) {} bravais_lattice(matrix const& units) : bravais_lattice(units, std::vector{{0, 0, 0}}) {} - bravais_lattice() : bravais_lattice(arrays::make_unit_matrix(3)) {} + bravais_lattice() : bravais_lattice(arrays::make_unit_matrix(2)) {} int n_orbitals() const { return atom_orb_name.size(); } arrays::matrix_const_view units() const { return units_; } diff --git a/triqs/lattice/tight_binding.hpp b/triqs/lattice/tight_binding.hpp index f200da24..6c608755 100644 --- a/triqs/lattice/tight_binding.hpp +++ b/triqs/lattice/tight_binding.hpp @@ -38,6 +38,8 @@ namespace lattice { public: /// tight_binding(bravais_lattice const& bl, std::vector> all_disp, std::vector> all_matrices); + + tight_binding() = default; /// Underlying lattice bravais_lattice const& lattice() const { return bl_; } diff --git a/triqs/python_tools/wrapper_tools.hpp b/triqs/python_tools/wrapper_tools.hpp index 4934b358..4a71a186 100644 --- a/triqs/python_tools/wrapper_tools.hpp +++ b/triqs/python_tools/wrapper_tools.hpp @@ -301,6 +301,38 @@ template struct py_converter> { } }; +// --- pair --- + +template struct py_converter> { + static PyObject * c2py(std::pair const &p) { + PyObject * list = PyList_New(0); + if (PyList_Append(list, py_converter::c2py(std::get<0>(p))) == -1) { Py_DECREF(list); return NULL;} // error + if (PyList_Append(list, py_converter::c2py(std::get<1>(p))) == -1) { Py_DECREF(list); return NULL;} // error + return list; + } + + static bool is_convertible(PyObject *ob, bool raise_exception) { + if (!PySequence_Check(ob)) goto _false; + { + pyref seq = PySequence_Fast(ob, "expected a sequence"); + if (!py_converter::is_convertible(PySequence_Fast_GET_ITEM((PyObject*)seq, 0),raise_exception)) goto _false; //borrowed ref + if (!py_converter::is_convertible(PySequence_Fast_GET_ITEM((PyObject*)seq, 1),raise_exception)) goto _false; //borrowed ref + return true; + } + _false: + if (raise_exception) { PyErr_SetString(PyExc_TypeError, "Can not convert to std::pair");} + return false; + } + + static std::pair py2c(PyObject * ob) { + pyref seq = PySequence_Fast(ob, "expected a sequence"); + return std::make_pair( + py_converter::py2c(PySequence_Fast_GET_ITEM((PyObject*)seq, 0)), + py_converter::py2c(PySequence_Fast_GET_ITEM((PyObject*)seq, 1)) + ); + } +}; + // --- mini_vector--- // via std::vector template struct py_converter> { @@ -339,6 +371,10 @@ template struct py_converter template struct py_converter> : py_converter_array> {}; template struct py_converter> : py_converter_array> {}; +template struct py_converter> : py_converter_array> {}; +template struct py_converter> : py_converter_array> {}; +template struct py_converter> : py_converter_array> {}; + template struct py_converter> : py_converter_array> {}; template struct py_converter> : py_converter_array> {}; template struct py_converter> : py_converter_array> {};