From 2a75f1b4d9fc2325be5029f80aa9e4856b348a1f Mon Sep 17 00:00:00 2001 From: ageay Date: Thu, 18 Apr 2013 08:24:46 +0000 Subject: [PATCH] Numpy bindings --- src/MEDCoupling/MEDCouplingMemArray.hxx | 10 ++- src/MEDCoupling_Swig/MEDCouplingMemArray.i | 18 +++++- src/MEDCoupling_Swig/MEDCouplingNumpyTest.py | 51 ++++++++++++++- src/MEDCoupling_Swig/MEDCouplingTypemaps.i | 65 ++++++++++++++++++-- 4 files changed, 133 insertions(+), 11 deletions(-) diff --git a/src/MEDCoupling/MEDCouplingMemArray.hxx b/src/MEDCoupling/MEDCouplingMemArray.hxx index d65bfe40b..f42d1a32d 100644 --- a/src/MEDCoupling/MEDCouplingMemArray.hxx +++ b/src/MEDCoupling/MEDCouplingMemArray.hxx @@ -87,15 +87,18 @@ namespace ParaMEDMEM void pushBack(T elem) throw(INTERP_KERNEL::Exception); T popBack() throw(INTERP_KERNEL::Exception); void pack() const; + bool isDeallocatorCalled() const { return _ownership; } + Deallocator getDeallocator() const { return _dealloc; } void setSpecificDeallocator(Deallocator dealloc) { _dealloc=dealloc; } void setParameterForDeallocator(void *param) { _param_for_deallocator=param; } void destroy(); ~MemArray() { destroy(); } + public: + static void CPPDeallocator(void *pt, void *param); + static void CDeallocator(void *pt, void *param); private: static void destroyPointer(T *pt, Deallocator dealloc, void *param); static Deallocator BuildFromType(DeallocType type) throw(INTERP_KERNEL::Exception); - static void CPPDeallocator(void *pt, void *param); - static void CDeallocator(void *pt, void *param); private: std::size_t _nb_of_elem; std::size_t _nb_of_elem_alloc; @@ -330,6 +333,7 @@ namespace ParaMEDMEM MEDCOUPLING_EXPORT void powEqual(const DataArrayDouble *other) throw(INTERP_KERNEL::Exception); MEDCOUPLING_EXPORT void updateTime() const { } MEDCOUPLING_EXPORT MemArray& accessToMemArray() { return _mem; } + MEDCOUPLING_EXPORT const MemArray& accessToMemArray() const { return _mem; } public: MEDCOUPLING_EXPORT void getTinySerializationIntInformation(std::vector& tinyInfo) const; MEDCOUPLING_EXPORT void getTinySerializationStrInformation(std::vector& tinyInfo) const; @@ -558,6 +562,7 @@ namespace ParaMEDMEM MEDCOUPLING_EXPORT void powEqual(const DataArrayInt *other) throw(INTERP_KERNEL::Exception); MEDCOUPLING_EXPORT void updateTime() const { } MEDCOUPLING_EXPORT MemArray& accessToMemArray() { return _mem; } + MEDCOUPLING_EXPORT const MemArray& accessToMemArray() const { return _mem; } public: MEDCOUPLING_EXPORT static int *CheckAndPreparePermutation(const int *start, const int *end); MEDCOUPLING_EXPORT static DataArrayInt *Range(int begin, int end, int step) throw(INTERP_KERNEL::Exception); @@ -689,6 +694,7 @@ namespace ParaMEDMEM MEDCOUPLING_EXPORT void useExternalArrayWithRWAccess(const char *array, int nbOfTuple, int nbOfCompo) throw(INTERP_KERNEL::Exception); MEDCOUPLING_EXPORT void updateTime() const { } MEDCOUPLING_EXPORT MemArray& accessToMemArray() { return _mem; } + MEDCOUPLING_EXPORT const MemArray& accessToMemArray() const { return _mem; } public: //MEDCOUPLING_EXPORT void getTinySerializationIntInformation(std::vector& tinyInfo) const; //MEDCOUPLING_EXPORT void getTinySerializationStrInformation(std::vector& tinyInfo) const; diff --git a/src/MEDCoupling_Swig/MEDCouplingMemArray.i b/src/MEDCoupling_Swig/MEDCouplingMemArray.i index 1e6619b5c..9b916b298 100644 --- a/src/MEDCoupling_Swig/MEDCouplingMemArray.i +++ b/src/MEDCoupling_Swig/MEDCouplingMemArray.i @@ -287,7 +287,7 @@ namespace ParaMEDMEM #ifdef WITH_NUMPY else if(PyArray_Check(elt0)) {//DataArrayDouble.New(numpyArray) - return BuildNewInstance(elt0,NPY_DOUBLE,&PyCallBackDataArrayDouble_RefType); + return BuildNewInstance(elt0,NPY_DOUBLE,&PyCallBackDataArrayDouble_RefType,"FLOAT64"); } #endif else @@ -395,6 +395,13 @@ namespace ParaMEDMEM return convertDblArrToPyList(vals,self->getNbOfElems()); } +#ifdef WITH_NUMPY + PyObject *toNumPyArray() throw(INTERP_KERNEL::Exception) // not const. It is not a bug ! + { + return ToNumPyArray(self,NPY_DOUBLE,"DataArrayDouble"); + } +#endif + PyObject *isEqualIfNotWhy(const DataArrayDouble& other, double prec) const throw(INTERP_KERNEL::Exception) { std::string ret1; @@ -2362,7 +2369,7 @@ namespace ParaMEDMEM #ifdef WITH_NUMPY else if(PyArray_Check(elt0)) {//DataArrayInt.New(numpyArray) - return BuildNewInstance(elt0,NPY_INT,&PyCallBackDataArrayInt_RefType); + return BuildNewInstance(elt0,NPY_INT,&PyCallBackDataArrayInt_RefType,"INT32"); } #endif else @@ -2475,6 +2482,13 @@ namespace ParaMEDMEM return convertIntArrToPyList(vals,self->getNbOfElems()); } +#ifdef WITH_NUMPY + PyObject *toNumPyArray() throw(INTERP_KERNEL::Exception) // not const. It is not a bug ! + { + return ToNumPyArray(self,NPY_INT,"DataArrayInt"); + } +#endif + PyObject *isEqualIfNotWhy(const DataArrayInt& other) const throw(INTERP_KERNEL::Exception) { std::string ret1; diff --git a/src/MEDCoupling_Swig/MEDCouplingNumpyTest.py b/src/MEDCoupling_Swig/MEDCouplingNumpyTest.py index d224a9f53..b6f54f119 100644 --- a/src/MEDCoupling_Swig/MEDCouplingNumpyTest.py +++ b/src/MEDCoupling_Swig/MEDCouplingNumpyTest.py @@ -297,7 +297,56 @@ class MEDCouplingNumpyTest(unittest.TestCase): self.assertTrue(a.flags["OWNDATA"]) self.assertTrue(d.isEqual(DataArrayDouble([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]),1e-14)) self.assertEqual(a.tolist(),[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19]) - pass + pass + + @unittest.skipUnless(MEDCouplingHasNumpyBindings(),"requires numpy") + def test17(self): + d=DataArrayInt.Range(0,20,1) + d.rearrange(10) + self.assertRaises(InterpKernelException,d.toNumPyArray)# forbidden one or two components of d is accepted + d.rearrange(1) + a=d.toNumPyArray() + self.assertTrue(not a.flags["OWNDATA"]) + a[-2:]=100 + self.assertTrue(d.isEqual(DataArrayInt([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,100,100]))) + self.assertEqual(a.tolist(),[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,100,100]) + del a + self.assertTrue(d.isEqual(DataArrayInt([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,100,100]))) + # + d.rearrange(2) + a=d.toNumPyArray() + self.assertTrue(not a.flags["OWNDATA"]) + a[-2:]=200 + self.assertTrue(d.isEqual(DataArrayInt([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,200,200,200,200],10,2))) + self.assertEqual(a.tolist(),[[0,1],[2,3],[4,5],[6,7],[8,9],[10,11],[12,13],[14,15],[200,200],[200,200]]) + del a + self.assertTrue(d.isEqual(DataArrayInt([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,200,200,200,200],10,2))) + pass + + @unittest.skipUnless(MEDCouplingHasNumpyBindings(),"requires numpy") + def test18(self): + d=DataArrayInt.Range(0,20,1) + d=d.convertToDblArr() + d.rearrange(10) + self.assertRaises(InterpKernelException,d.toNumPyArray)# forbidden one or two components of d is accepted + d.rearrange(1) + a=d.toNumPyArray() + self.assertTrue(not a.flags["OWNDATA"]) + a[-2:]=100 + self.assertTrue(d.isEqual(DataArrayDouble([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,100,100]),1e-14)) + self.assertEqual(a.tolist(),[0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,100,100]) + del a + self.assertTrue(d.isEqual(DataArrayDouble([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,100,100]),1e-14)) + # + d.rearrange(2) + a=d.toNumPyArray() + self.assertTrue(not a.flags["OWNDATA"]) + a[-2:]=200 + self.assertTrue(d.isEqual(DataArrayDouble([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,200,200,200,200],10,2),1e-14)) + self.assertEqual(a.tolist(),[[0,1],[2,3],[4,5],[6,7],[8,9],[10,11],[12,13],[14,15],[200,200],[200,200]]) + del a + self.assertTrue(d.isEqual(DataArrayDouble([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,200,200,200,200],10,2),1e-14)) + pass def setUp(self): pass diff --git a/src/MEDCoupling_Swig/MEDCouplingTypemaps.i b/src/MEDCoupling_Swig/MEDCouplingTypemaps.i index d3eb7d67d..fe655d9aa 100644 --- a/src/MEDCoupling_Swig/MEDCouplingTypemaps.i +++ b/src/MEDCoupling_Swig/MEDCouplingTypemaps.i @@ -24,7 +24,8 @@ void numarrdeal(void *pt, void *wron) { - PyObject *weakRefOnOwner=reinterpret_cast(wron); + void **wronc=(void **)wron; + PyObject *weakRefOnOwner=reinterpret_cast(wronc[0]); PyObject *obj=PyWeakref_GetObject(weakRefOnOwner); if(obj!=Py_None) { @@ -35,7 +36,12 @@ void numarrdeal(void *pt, void *wron) Py_XDECREF(obj); } else - free(pt); + { + typedef void (*MyDeallocator)(void *,void *); + MyDeallocator deall=(MyDeallocator)wronc[1]; + deall(pt,NULL); + } + delete [] wronc; } template @@ -189,19 +195,25 @@ void numarrdeal2(void *pt, void *obj) } template -MCData *BuildNewInstance(PyObject *elt0, int npyObjectType, PyTypeObject *pytype) +MCData *BuildNewInstance(PyObject *elt0, int npyObjectType, PyTypeObject *pytype, const char *msg) { int ndim=PyArray_NDIM(elt0); if(ndim!=1) throw INTERP_KERNEL::Exception("Input numpy array has not 1 dimension !");//to do 1 or 2. if(PyArray_ObjectType(elt0,0)!=npyObjectType) - throw INTERP_KERNEL::Exception("Input numpy array has not of type INT32 !");//to do 1 or 2. + { + std::ostringstream oss; oss << "Input numpy array has not of type " << msg << " !"; + throw INTERP_KERNEL::Exception(oss.str().c_str());//to do 1 or 2. + } npy_intp stride=PyArray_STRIDE(elt0,0); int itemSize=PyArray_ITEMSIZE(elt0); if(itemSize ret=MCData::New(); @@ -243,7 +255,8 @@ MCData *BuildNewInstance(PyObject *elt0, int npyObjectType, PyTypeObject *pytype { ret->useArray(reinterpret_cast(data),true,ParaMEDMEM::C_DEALLOC,sz,1); PyObject *ref=PyWeakref_NewRef(reinterpret_cast(eltOwning),NULL); - mma.setParameterForDeallocator(ref); + void **objs=new void *[2]; objs[0]=ref; objs[1]=(void*) ParaMEDMEM::MemArray::CDeallocator; + mma.setParameterForDeallocator(objs); mma.setSpecificDeallocator(numarrdeal); } } @@ -252,6 +265,46 @@ MCData *BuildNewInstance(PyObject *elt0, int npyObjectType, PyTypeObject *pytype return ret.retn(); } +template +PyObject *ToNumPyArray(MCData *self, int npyObjectType, const char *MCDataStr) +{ + if(!self->isAllocated()) + { + std::ostringstream oss; oss << MCDataStr << "::toNumPyArray : this is not allocated !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + ParaMEDMEM::MemArray& mem=self->accessToMemArray(); + int nbComp=self->getNumberOfComponents(); + if(nbComp!=1 && nbComp!=2) + { + std::ostringstream oss; oss << MCDataStr << "::toNumPyArray : number of components of this is " << nbComp << " ! Should 1 or 2 !"; + throw INTERP_KERNEL::Exception(oss.str().c_str()); + } + std::size_t sz=self->getNbOfElems(); + npy_intp dim[2]; + dim[0]=(npy_intp)self->getNumberOfTuples(); dim[1]=2; + const T *bg=self->getConstPointer(); + PyObject *ret=PyArray_SimpleNewFromData(nbComp,dim,npyObjectType,const_cast(bg)); + if(mem.isDeallocatorCalled()) + { + if(mem.getDeallocator()!=ParaMEDMEM::MemArray::CDeallocator) + { + int mask=NPY_OWNDATA; mask=~mask; + (reinterpret_cast(ret))->flags&=mask; + return ret; + } + else + { + PyObject *ref=PyWeakref_NewRef(ret,NULL); + void **objs=new void *[2]; objs[0]=ref; objs[1]=(void*) ParaMEDMEM::MemArray::CDeallocator; + mem.setParameterForDeallocator(objs); + mem.setSpecificDeallocator(numarrdeal); + return ret; + } + } + return ret; +} + #endif static PyObject *convertMesh(ParaMEDMEM::MEDCouplingMesh *mesh, int owner) throw(INTERP_KERNEL::Exception) -- 2.39.2