]> SALOME platform Git repositories - tools/medcoupling.git/commitdiff
Salome HOME
Numpy bindings MrgToV7main1804
authorageay <ageay>
Thu, 18 Apr 2013 08:24:46 +0000 (08:24 +0000)
committerageay <ageay>
Thu, 18 Apr 2013 08:24:46 +0000 (08:24 +0000)
src/MEDCoupling/MEDCouplingMemArray.hxx
src/MEDCoupling_Swig/MEDCouplingMemArray.i
src/MEDCoupling_Swig/MEDCouplingNumpyTest.py
src/MEDCoupling_Swig/MEDCouplingTypemaps.i

index d65bfe40b96a3be4ff01299f745078ca1b4f999b..f42d1a32deb0640d883ea30e67f8cca1d14ea610 100644 (file)
@@ -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<double>& accessToMemArray() { return _mem; }
+    MEDCOUPLING_EXPORT const MemArray<double>& accessToMemArray() const { return _mem; }
   public:
     MEDCOUPLING_EXPORT void getTinySerializationIntInformation(std::vector<int>& tinyInfo) const;
     MEDCOUPLING_EXPORT void getTinySerializationStrInformation(std::vector<std::string>& 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<int>& accessToMemArray() { return _mem; }
+    MEDCOUPLING_EXPORT const MemArray<int>& 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<char>& accessToMemArray() { return _mem; }
+    MEDCOUPLING_EXPORT const MemArray<char>& accessToMemArray() const { return _mem; }
   public:
     //MEDCOUPLING_EXPORT void getTinySerializationIntInformation(std::vector<int>& tinyInfo) const;
     //MEDCOUPLING_EXPORT void getTinySerializationStrInformation(std::vector<std::string>& tinyInfo) const;
index 1e6619b5ca576ccedcf5a8ab4779dca150a608d9..9b916b2986ee301ada6e0c34b883729a49d538a3 100644 (file)
@@ -287,7 +287,7 @@ namespace ParaMEDMEM
 #ifdef WITH_NUMPY
         else if(PyArray_Check(elt0))
           {//DataArrayDouble.New(numpyArray)
-            return BuildNewInstance<DataArrayDouble,double>(elt0,NPY_DOUBLE,&PyCallBackDataArrayDouble_RefType);
+            return BuildNewInstance<DataArrayDouble,double>(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<DataArrayDouble,double>(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<DataArrayInt,int>(elt0,NPY_INT,&PyCallBackDataArrayInt_RefType);
+            return BuildNewInstance<DataArrayInt,int>(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<DataArrayInt,int>(self,NPY_INT,"DataArrayInt");
+      }
+#endif
+
       PyObject *isEqualIfNotWhy(const DataArrayInt& other) const throw(INTERP_KERNEL::Exception)
       {
         std::string ret1;
index d224a9f53da466c7ee2641ae8bfde08067f18e5a..b6f54f119cbe3fce14e65d022a027cc7ba8f07cb 100644 (file)
@@ -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
index d3eb7d67df21d513822a6fbb75f88208641bf4d5..fe655d9aae65c5fe65e7f513239ed797a5590625 100644 (file)
@@ -24,7 +24,8 @@
 
 void numarrdeal(void *pt, void *wron)
 {
-  PyObject *weakRefOnOwner=reinterpret_cast<PyObject *>(wron);
+  void **wronc=(void **)wron;
+  PyObject *weakRefOnOwner=reinterpret_cast<PyObject *>(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<class MCData>
@@ -189,19 +195,25 @@ void numarrdeal2(void *pt, void *obj)
 }
 
 template<class MCData, class T>
-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<stride)
     throw INTERP_KERNEL::Exception("Input numpy array has item size < stride !");
   if(stride!=sizeof(T))
-    throw INTERP_KERNEL::Exception("Input numpy array has not stride set to 4 !");//to do
+    {
+      std::ostringstream oss; oss << "Input numpy array has not stride set to " << sizeof(T) << " !";
+      throw INTERP_KERNEL::Exception(oss.str().c_str());
+    }
   npy_intp sz=PyArray_DIM(elt0,0);
   const char *data=PyArray_BYTES(elt0);
   typename ParaMEDMEM::MEDCouplingAutoRefCountObjectPtr<MCData> ret=MCData::New();
@@ -243,7 +255,8 @@ MCData *BuildNewInstance(PyObject *elt0, int npyObjectType, PyTypeObject *pytype
         {
           ret->useArray(reinterpret_cast<const T *>(data),true,ParaMEDMEM::C_DEALLOC,sz,1);
           PyObject *ref=PyWeakref_NewRef(reinterpret_cast<PyObject *>(eltOwning),NULL);
-          mma.setParameterForDeallocator(ref);
+          void **objs=new void *[2]; objs[0]=ref; objs[1]=(void*) ParaMEDMEM::MemArray<T>::CDeallocator;
+          mma.setParameterForDeallocator(objs);
           mma.setSpecificDeallocator(numarrdeal);
         }
     }
@@ -252,6 +265,46 @@ MCData *BuildNewInstance(PyObject *elt0, int npyObjectType, PyTypeObject *pytype
   return ret.retn();
 }
 
+template<class MCData, class T>
+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<T>& 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<T *>(bg));
+  if(mem.isDeallocatorCalled())
+    {
+      if(mem.getDeallocator()!=ParaMEDMEM::MemArray<T>::CDeallocator)
+        {
+          int mask=NPY_OWNDATA; mask=~mask;
+          (reinterpret_cast<PyArrayObject *>(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<T>::CDeallocator;
+          mem.setParameterForDeallocator(objs);
+          mem.setSpecificDeallocator(numarrdeal);
+          return ret;
+        }
+    }
+  return ret;
+}
+
 #endif
 
 static PyObject *convertMesh(ParaMEDMEM::MEDCouplingMesh *mesh, int owner) throw(INTERP_KERNEL::Exception)