]> SALOME platform Git repositories - tools/medcoupling.git/commitdiff
Salome HOME
Bug correction in the medcoupling <-> numpy layer agy/mc_npy_error
authorAnthony Geay <anthony.geay@edf.fr>
Thu, 6 Dec 2018 15:06:36 +0000 (16:06 +0100)
committerAnthony Geay <anthony.geay@edf.fr>
Thu, 6 Dec 2018 15:06:36 +0000 (16:06 +0100)
src/MEDCoupling/MEDCouplingMemArray.hxx
src/MEDCoupling/MEDCouplingMemArray.txx
src/MEDCoupling/MEDCouplingRefCountObject.hxx
src/MEDCoupling_Swig/MEDCouplingDataArrayTraits.hxx
src/MEDCoupling_Swig/MEDCouplingDataArrayTypemaps.i
src/MEDCoupling_Swig/MEDCouplingNumPyTest.py

index de2101fead09ccca98726081be66f26000708629..3887de6298f60ba3ef6aa4de752194f2f5357edb 100644 (file)
@@ -112,6 +112,7 @@ namespace MEDCoupling
   public:
     static void CPPDeallocator(void *pt, void *param);
     static void CDeallocator(void *pt, void *param);
+    static void COffsetDeallocator(void *pt, void *param);
   private:
     static void DestroyPointer(T *pt, Deallocator dealloc, void *param);
     static Deallocator BuildFromType(DeallocType type);
index e43325aa3f85fc300d228f016bbf5a137bc6b355..f2c2f4690fdd8500e4fa65f6b3ce44b8c98d19bb 100644 (file)
@@ -437,6 +437,14 @@ namespace MEDCoupling
     free(pt);
   }
 
+  template<class T>
+  void MemArray<T>::COffsetDeallocator(void *pt, void *param)
+  {
+    int64_t *offset(reinterpret_cast<int64_t *>(param));
+    char *ptcast(reinterpret_cast<char *>(pt));
+    free(ptcast+*offset);
+  }
+
   template<class T>
   typename MemArray<T>::Deallocator MemArray<T>::BuildFromType(DeallocType type)
   {
@@ -446,6 +454,8 @@ namespace MEDCoupling
         return CPPDeallocator;
       case DeallocType::C_DEALLOC:
         return CDeallocator;
+      case DeallocType::C_DEALLOC_WITH_OFFSET:
+        return COffsetDeallocator;
       default:
         throw INTERP_KERNEL::Exception("Invalid deallocation requested ! Unrecognized enum DeallocType !");
     }
index dcece7d5b802fd20be18516cc84ff2e1789ed2f5..5473a9a0467df7fabeaa9aa483bc20171f2ffbbf 100644 (file)
@@ -34,7 +34,8 @@ namespace MEDCoupling
   enum class DeallocType
   {
     C_DEALLOC = 2,
-    CPP_DEALLOC = 3
+    CPP_DEALLOC = 3,
+    C_DEALLOC_WITH_OFFSET = 4
   };
 
   //! The various spatial discretization of a field
index 359bc7ecd8decb0c579c4d4b4e4f592545f0ead2..50b0f9b41a500464c61bfa2f157cd7fee15b11fc 100644 (file)
@@ -55,7 +55,9 @@ void numarrdeal(void *pt, void *wron)
     {
       typedef void (*MyDeallocator)(void *,void *);
       MyDeallocator deall=(MyDeallocator)wronc[1];
-      deall(pt,NULL);
+      int64_t *offset=reinterpret_cast<int64_t*>(wronc[2]);
+      deall(pt,offset);
+      delete offset;
       Py_XDECREF(weakRefOnOwner);
     }
   delete [] wronc;
index 3a6bbcdca484447d0230cdf7e937e6a909218557..c56510f7afc1ffa6d2cbb6f224b124dfe581a5d3 100644 (file)
@@ -199,11 +199,17 @@ MCData *BuildNewInstance(PyObject *elt0, int npyObjectType, PyTypeObject *pytype
         }
       else
         {
-          ret->useArray(reinterpret_cast<const T *>(data),true,MEDCoupling::DeallocType::C_DEALLOC,sz0,sz1);
+          ret->useArray(reinterpret_cast<const T *>(data),true,MEDCoupling::DeallocType::C_DEALLOC_WITH_OFFSET,sz0,sz1);
           PyObject *ref=PyWeakref_NewRef(reinterpret_cast<PyObject *>(eltOwning),NULL);
-          typename MEDCoupling::MemArray<T>::Deallocator tmp(MEDCoupling::MemArray<T>::CDeallocator);
+          typename MEDCoupling::MemArray<T>::Deallocator tmp(MEDCoupling::MemArray<T>::COffsetDeallocator);
           void **tmp2 = reinterpret_cast<void**>(&tmp); // MSVC2010 does not support constructor()
-          void **objs=new void *[2]; objs[0]=ref; objs[1]=*tmp2;
+          const char *dataEltOwning(PyArray_BYTES(eltOwning));//In case of input array is a sub array of a 2D,3D... array there is an offset
+          int64_t offset(0);
+          if(data!=dataEltOwning)
+            {
+              offset=data>dataEltOwning?-((int64_t)(std::distance(dataEltOwning,data))):(int64_t)std::distance(data,dataEltOwning);
+            }
+          void **objs=new void *[3]; objs[0]=ref; objs[1]=*tmp2; objs[2]=new int64_t(offset);
           mma.setParameterForDeallocator(objs);
           mma.setSpecificDeallocator(numarrdeal);
         }
@@ -308,7 +314,7 @@ PyObject *ToNumPyArrayUnderground(MCData *self, int npyObjectType, const char *M
           PyObject *ref(PyWeakref_NewRef(ret,NULL));
           typename MEDCoupling::MemArray<T>::Deallocator tmp(mem.getDeallocator());
           void **tmp2 = reinterpret_cast<void**>(&tmp); // MSVC2010 does not support constructor()
-          void **objs=new void *[2]; objs[0]=reinterpret_cast<void*>(ref); objs[1]=*tmp2;
+          void **objs=new void *[3]; objs[0]=reinterpret_cast<void*>(ref); objs[1]=*tmp2; objs[2]=new int64_t(0);
           mem.setParameterForDeallocator(objs);
           mem.setSpecificDeallocator(numarrdeal);
           return ret;
index 0cfc225e363278a3e5f6323a0eafca90d5bfb6f3..6ce7868ef7015b7d442c381f9388f148ba1b9190 100644 (file)
@@ -23,7 +23,7 @@ import sys
 if sys.platform == "win32":
     from MEDCouplingCompat import *
 else:
-    from MEDCoupling import *
+    from medcoupling import *
 
 if MEDCouplingHasNumPyBindings():
     from numpy import *
@@ -1062,6 +1062,22 @@ class MEDCouplingNumPyTest(unittest.TestCase):
         self.assertTrue(not b.flags["OWNDATA"])
         pass
 
+    @unittest.skipUnless(MEDCouplingHasNumPyBindings(),"requires numpy")
+    def test41(self):
+        """ This non regression test is focused on a numpy subarray of a bigger numpy array. Typically a 1D array coming from a 2D array. When medcoupling takes the ownership, medcoupling must store an offset to deallocate correctly the pointer. The pointer of medcoupling array is NOT the pointer to be transmited to free. The offset is typically the distance between the start of the main 2D array and the start of 1D array medcouplingized."""
+        import numpy as np
+        array = np.array([[1,2,3,10],[4,5,6,20],[7,8,9,30]],dtype=np.float64) # create a 2D array 
+        b = array[2] # b data pointer starts at array+2*4*sizeof(float64) so offset is expected to be equal to -2*4*sizeof(float64)=-64
+        self.assertTrue(array.flags["OWNDATA"])
+        self.assertTrue(not b.flags["OWNDATA"])
+        d=DataArrayDouble(b)
+        self.assertTrue(not array.flags["OWNDATA"])
+        self.assertTrue(not b.flags["OWNDATA"])
+        del b ; gc.collect()
+        del array ; gc.collect()
+        del d ; gc.collect() # important : destroy d after b and array to be sure to let the ownership to d.
+        pass
+
     def setUp(self):
         pass
     pass