Pteros  2.0
Molecular modeling library for human beings!
bindings_util.h
1 /*
2  *
3  * This source code is part of
4  * ******************
5  * *** Pteros ***
6  * ******************
7  * molecular modeling library
8  *
9  * Copyright (c) 2009-2013, Semen Yesylevskyy
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of Artistic License:
13  *
14  * Please note, that Artistic License is slightly more restrictive
15  * then GPL license in terms of distributing the modified versions
16  * of this software (they should be approved first).
17  * Read http://www.opensource.org/licenses/artistic-license-2.0.php
18  * for details. Such license fits scientific software better then
19  * GPL because it prevents the distribution of bugged derivatives.
20  *
21 */
22 
23 #ifndef BINDINGS_UTIL_H
24 #define BINDINGS_UTIL_H
25 
26 #include "pteros/core/pteros_error.h"
27 #include "pteros/analysis/trajectory_processor.h"
28 
29 #include <boost/python.hpp>
30 
31 #include <numpy/noprefix.h>
32 
33 #include <boost/python/numeric.hpp>
34 
35 #include <iostream>
36 
37 namespace pteros {
38 
39 // Some helper functions and macros
40 
41 // Class for releasing resources
42 class Decrementer {
43 public:
44  Decrementer(PyObject* pyobj): m_obj(pyobj) {}
45  ~Decrementer(){ Py_XDECREF(m_obj); }
46 private:
47  PyObject* m_obj;
48 };
49 
50 template<class T, int PyT>
51 PyObject* mapper(PyObject* pyobj, size_t& dim1, size_t& dim2){
52  PyObject* aux = nullptr;
53 
54  size_t py_dim1, py_dim2;
55 
56  // Check if pyobj is a numpy array
57  if(PyArray_Check(pyobj)){
58  int ndim = PyArray_NDIM((PyArrayObject*)pyobj);
59  if(ndim>2) throw Pteros_error("Need 1D or 2D array!");
60 
61  py_dim1 = PyArray_DIM((PyArrayObject*)pyobj,0);
62  py_dim2 = PyArray_DIM((PyArrayObject*)pyobj,1);
63  dim1 = (ndim==1) ? py_dim1 : py_dim2;
64  dim2 = (ndim==1) ? 1 : py_dim1;
65 
66  // For fixed size Eigen object do a sanity check
67  if( T::RowsAtCompileTime!=Eigen::Dynamic
68  && T::ColsAtCompileTime!=Eigen::Dynamic
69  && (T::RowsAtCompileTime!=dim1 || T::ColsAtCompileTime!=dim2) )
70  {
71  throw Pteros_error()<<"Passed an array of size "<<dim1<<":"<<dim2
72  << " while expected size is "
73  << T::RowsAtCompileTime<<":"<<T::ColsAtCompileTime<<"!";
74  }
75 
76  // Check array type
77  if(PyArray_TYPE((PyArrayObject*)pyobj)==PyT){
78  // The best case! Direct mapping
79  // We need to increase reference counter of initial object
80  // since it will be decreased later by Decrementer!
81  Py_XINCREF((PyObject*)pyobj);
82  return (PyObject*)pyobj;
83  } else {
84  // Wrong type :( Need to cast.
85  aux = PyArray_Cast((PyArrayObject*)pyobj,PyT);
86  return aux;
87  }
88 
89  } else if(PySequence_Check(pyobj)) { // Check if it is a sequence
90  // Get first dimension as list size
91  py_dim1 = PySequence_Size(pyobj);
92  // Get second dimension as the size of first list element
93  PyObject* item0 = PySequence_GetItem(pyobj,0);
94  if(PySequence_Check(item0)){
95  py_dim2 = PySequence_Size(item0);
96  } else {
97  py_dim2 = 1;
98  }
99  Py_XDECREF(item0);
100 
101  dim1 = (py_dim2==1) ? py_dim1 : py_dim2;
102  dim2 = (py_dim2==1) ? 1 : py_dim1;
103 
104  // For fixed size Eigen object do a sanity check
105  if( T::RowsAtCompileTime!=Eigen::Dynamic
106  && T::ColsAtCompileTime!=Eigen::Dynamic
107  && (T::RowsAtCompileTime!=dim1 || T::ColsAtCompileTime!=dim2) )
108  {
109  throw Pteros_error()<< "Passed an object of size "<<dim1<<":"<<dim2
110  << " while expected size is "
111  << T::RowsAtCompileTime<<":"<<T::ColsAtCompileTime<<"!";
112  }
113 
114  // Convert to array and map
115  aux = PyArray_FROM_OT(pyobj,PyT);
116  if(!aux) throw Pteros_error("Can't convert sequence to array!");
117  return aux;
118  } else {
119  // Something incompatible
120  throw Pteros_error("An array or a sequence is required!");
121  }
122 }
123 
124 #define MAP_EIGEN_TO_PYTHON_F(T,matr,pyobj) \
125  size_t __dim1__for__##matr, __dim2__for__##matr; \
126  PyObject* __pyobj__for__##matr = mapper<T,NPY_FLOAT>(pyobj,__dim1__for__##matr,__dim2__for__##matr);\
127  Decrementer __dec__for__##matr(__pyobj__for__##matr);\
128  Eigen::Map<T> matr((float*)PyArray_DATA((PyArrayObject*)__pyobj__for__##matr),__dim1__for__##matr,__dim2__for__##matr);
129 
130 #define MAP_EIGEN_TO_PYTHON_I(T,matr,pyobj) \
131  size_t __dim1__for__##matr, __dim2__for__##matr; \
132  PyObject* __pyobj__for__##matr = mapper<T,NPY_INT>(pyobj,__dim1__for__##matr,__dim2__for__##matr);\
133  Decrementer __dec__for__##matr(__pyobj__for__##matr);\
134  Eigen::Map<T> matr((int*)PyArray_DATA((PyArrayObject*)__pyobj__for__##matr),__dim1__for__##matr,__dim2__for__##matr);
135 
136 
137 #define CREATE_PYARRAY_1D_AND_MAP_F(pyobj, T, matr, dim) \
138  PyObject* pyobj; \
139  { \
140  npy_intp sz[1] = {dim};\
141  pyobj = PyArray_SimpleNew(1, sz, NPY_FLOAT); \
142  } \
143  Eigen::Map<T> matr((float*)PyArray_DATA((PyArrayObject*)pyobj),dim,1);
144 
145 #define CREATE_PYARRAY_1D_AND_MAP_I(pyobj, T, matr, dim) \
146  PyObject* pyobj; \
147  { \
148  npy_intp sz[1] = {dim};\
149  pyobj = PyArray_SimpleNew(1, sz, NPY_INT); \
150  } \
151  Eigen::Map<T> matr((int*)PyArray_DATA((PyArrayObject*)pyobj),dim,1);
152 
153 
154 #define CREATE_PYARRAY_2D_AND_MAP_F(pyobj, T, matr, dim1, dim2) \
155  PyObject* pyobj; \
156  { \
157  npy_intp dims[2] = {dim2,dim1}; \
158  pyobj = PyArray_SimpleNew(2, dims, NPY_FLOAT); \
159  } \
160  Eigen::Map<T> matr((float*)PyArray_DATA((PyArrayObject*)pyobj),dim1,dim2);
161 
162 #define CREATE_PYARRAY_2D_AND_MAP_I(pyobj, T, matr, dim1, dim2) \
163  PyObject* pyobj; \
164  { \
165  npy_intp dims[2] = {dim2,dim1}; \
166  pyobj = PyArray_SimpleNew(2, dims, NPY_INT); \
167  } \
168  Eigen::Map<T> matr((int*)PyArray_DATA((PyArrayObject*)pyobj),dim1,dim2);
169 
170 #define PYOBJECT_TO_VECTOR(pyobj,T,vecname) \
171  vector<T> vecname; \
172  if( PySequence_Check(pyobj) ){ \
173  boost::python::object __list__for__##pyobj( handle<>(borrowed(pyobj)) ); \
174  int n = boost::python::len(__list__for__##pyobj); \
175  vecname.resize(n); \
176  for(int i=0;i<n;++i) vecname[i] = extract<T>(__list__for__##pyobj[i]); \
177  } else { \
178  throw Pteros_error("Provided python object is not a sequence!"); \
179  }
180 
181 
182 } // End of namespace Pteros
183 
184 #endif
Pteros namespace.
Definition: options.cpp:32