From b8bf069f375424fd303ad6e594412583633c1110 Mon Sep 17 00:00:00 2001
From: Willem Jan Palenstijn <Willem.Jan.Palenstijn@cwi.nl>
Date: Tue, 23 Jun 2020 11:40:26 +0200
Subject: Refactor cython data3d object creation to prepare

---
 python/astra/PyIncludes.pxd | 16 +++++++++---
 python/astra/data3d_c.pyx   | 38 ++++-----------------------
 python/astra/utils.pxd      |  3 +++
 python/astra/utils.pyx      | 62 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 82 insertions(+), 37 deletions(-)

(limited to 'python')

diff --git a/python/astra/PyIncludes.pxd b/python/astra/PyIncludes.pxd
index b9a61a9..f964118 100644
--- a/python/astra/PyIncludes.pxd
+++ b/python/astra/PyIncludes.pxd
@@ -236,9 +236,17 @@ cdef extern from "astra/ProjectionGeometry3D.h" namespace "astra":
         int getDetectorColCount()
         int getDetectorRowCount()
 
+cdef extern from "astra/Float32VolumeData3D.h" namespace "astra":
+    cdef cppclass CFloat32VolumeData3D(CFloat32Data3D):
+        pass
+
+cdef extern from "astra/Float32ProjectionData3D.h" namespace "astra":
+    cdef cppclass CFloat32ProjectionData3D(CFloat32Data3D):
+        pass
+
 
 cdef extern from "astra/Float32VolumeData3DMemory.h" namespace "astra":
-    cdef cppclass CFloat32VolumeData3DMemory:
+    cdef cppclass CFloat32VolumeData3DMemory(CFloat32VolumeData3D):
         CFloat32VolumeData3DMemory(CVolumeGeometry3D*)
         CFloat32VolumeData3DMemory(CVolumeGeometry3D*, CFloat32CustomMemory*)
         CVolumeGeometry3D* getGeometry()
@@ -266,7 +274,7 @@ cdef extern from "astra/ConeVecProjectionGeometry3D.h" namespace "astra":
         CConeVecProjectionGeometry3D()
 
 cdef extern from "astra/Float32ProjectionData3DMemory.h" namespace "astra":
-    cdef cppclass CFloat32ProjectionData3DMemory:
+    cdef cppclass CFloat32ProjectionData3DMemory(CFloat32ProjectionData3D):
         CFloat32ProjectionData3DMemory(CProjectionGeometry3D*)
         CFloat32ProjectionData3DMemory(CConeProjectionGeometry3D*)
         CFloat32ProjectionData3DMemory(CProjectionGeometry3D*, CFloat32CustomMemory*)
@@ -280,7 +288,7 @@ cdef extern from "astra/Float32ProjectionData3DMemory.h" namespace "astra":
 
 IF HAVE_CUDA==True:
     cdef extern from "astra/Float32VolumeData3DGPU.h" namespace "astra":
-        cdef cppclass CFloat32VolumeData3DGPU:
+        cdef cppclass CFloat32VolumeData3DGPU(CFloat32VolumeData3D):
             CFloat32VolumeData3DGPU(CVolumeGeometry3D*, MemHandle3D)
             CVolumeGeometry3D* getGeometry()
             void changeGeometry(CVolumeGeometry3D*)
@@ -290,7 +298,7 @@ IF HAVE_CUDA==True:
             bool isInitialized()
 
     cdef extern from "astra/Float32ProjectionData3DGPU.h" namespace "astra":
-        cdef cppclass CFloat32ProjectionData3DGPU:
+        cdef cppclass CFloat32ProjectionData3DGPU(CFloat32ProjectionData3D):
             CFloat32ProjectionData3DGPU(CProjectionGeometry3D*, MemHandle3D)
             CProjectionGeometry3D* getGeometry()
             void changeGeometry(CProjectionGeometry3D*)
diff --git a/python/astra/data3d_c.pyx b/python/astra/data3d_c.pyx
index 4c8aa62..a1b9138 100644
--- a/python/astra/data3d_c.pyx
+++ b/python/astra/data3d_c.pyx
@@ -44,6 +44,7 @@ from .PyXMLDocument cimport XMLDocument
 
 cimport utils
 from .utils import wrap_from_bytes
+from .utils cimport linkVolFromGeometry, linkProjFromGeometry
 
 from .pythonutils import geom_size, GPULink
 
@@ -53,9 +54,6 @@ from six.moves import reduce
 
 include "config.pxi"
 
-cdef extern from "Python.h":
-    void* PyLong_AsVoidPtr(object)
-
 
 cdef CData3DManager * man3d = <CData3DManager * >PyData3DManager.getSingletonPtr()
 
@@ -68,16 +66,12 @@ cdef CFloat32Data3DMemory * dynamic_cast_mem_safe(CFloat32Data3D *obj) except NU
         raise RuntimeError("Not a memory 3D data object")
     return ret
 
-cdef extern from "CFloat32CustomPython.h":
-    cdef cppclass CFloat32CustomPython:
-        CFloat32CustomPython(arrIn)
 
 def create(datatype,geometry,data=None, link=False):
     cdef Config *cfg
     cdef CVolumeGeometry3D * pGeometry
     cdef CProjectionGeometry3D * ppGeometry
     cdef CFloat32Data3D * pDataObject3D
-    cdef CConeProjectionGeometry3D* pppGeometry
     cdef CFloat32CustomMemory * pCustom = NULL
     IF HAVE_CUDA==True:
         cdef MemHandle3D hnd
@@ -101,20 +95,9 @@ def create(datatype,geometry,data=None, link=False):
             del pGeometry
             raise RuntimeError('Geometry class not initialized.')
         if link:
-            if isinstance(data, np.ndarray):
-                pCustom = <CFloat32CustomMemory*> new CFloat32CustomPython(data)
-                pDataObject3D = <CFloat32Data3D * > new CFloat32VolumeData3DMemory(pGeometry, pCustom)
-            elif isinstance(data, GPULink):
-                IF HAVE_CUDA==True:
-                    s = geom_size(geometry)
-                    hnd = wrapHandle(<float*>PyLong_AsVoidPtr(data.ptr), data.x, data.y, data.z, data.pitch/4)
-                    pDataObject3D = <CFloat32Data3D * > new CFloat32VolumeData3DGPU(pGeometry, hnd)
-                ELSE:
-                    raise NotImplementedError("CUDA support is not enabled in ASTRA")
-            else:
-                raise TypeError("data should be a numpy.ndarray or a GPULink object")
+            pDataObject3D = linkVolFromGeometry(pGeometry, data)
         else:
-            pDataObject3D = <CFloat32Data3D * > new CFloat32VolumeData3DMemory(pGeometry)
+            pDataObject3D = new CFloat32VolumeData3DMemory(pGeometry)
         del cfg
         del pGeometry
     elif datatype == '-sino' or datatype == '-proj3d' or datatype == '-sinocone':
@@ -136,20 +119,9 @@ def create(datatype,geometry,data=None, link=False):
             del ppGeometry
             raise RuntimeError('Geometry class not initialized.')
         if link:
-            if isinstance(data, np.ndarray):
-                pCustom = <CFloat32CustomMemory*> new CFloat32CustomPython(data)
-                pDataObject3D = <CFloat32Data3D * > new CFloat32ProjectionData3DMemory(ppGeometry, pCustom)
-            elif isinstance(data, GPULink):
-                IF HAVE_CUDA==True:
-                    s = geom_size(geometry)
-                    hnd = wrapHandle(<float*>PyLong_AsVoidPtr(data.ptr), data.x, data.y, data.z, data.pitch/4)
-                    pDataObject3D = <CFloat32Data3D * > new CFloat32ProjectionData3DGPU(ppGeometry, hnd)
-                ELSE:
-                    raise NotImplementedError("CUDA support is not enabled in ASTRA")
-            else:
-                raise TypeError("data should be a numpy.ndarray or a GPULink object")
+            pDataObject3D = linkProjFromGeometry(ppGeometry, data)
         else:
-            pDataObject3D = <CFloat32Data3DMemory * > new CFloat32ProjectionData3DMemory(ppGeometry)
+            pDataObject3D = new CFloat32ProjectionData3DMemory(ppGeometry)
         del ppGeometry
         del cfg
     else:
diff --git a/python/astra/utils.pxd b/python/astra/utils.pxd
index ea3da86..69f4e96 100644
--- a/python/astra/utils.pxd
+++ b/python/astra/utils.pxd
@@ -33,3 +33,6 @@ from .PyIncludes cimport *
 
 cdef configToDict(Config *)
 cdef Config * dictToConfig(string rootname, dc) except NULL
+cdef CFloat32VolumeData3D* linkVolFromGeometry(CVolumeGeometry3D *pGeometry, data) except NULL
+cdef CFloat32ProjectionData3D* linkProjFromGeometry(CProjectionGeometry3D *pGeometry, data) except NULL
+
diff --git a/python/astra/utils.pyx b/python/astra/utils.pyx
index b534d72..3b6e3ff 100644
--- a/python/astra/utils.pyx
+++ b/python/astra/utils.pyx
@@ -45,6 +45,18 @@ from .PyXMLDocument cimport XMLDocument
 from .PyXMLDocument cimport XMLNode
 from .PyIncludes cimport *
 
+from .pythonutils import GPULink
+
+cdef extern from "CFloat32CustomPython.h":
+    cdef cppclass CFloat32CustomPython:
+        CFloat32CustomPython(arrIn)
+
+cdef extern from "Python.h":
+    void* PyLong_AsVoidPtr(object)
+
+
+include "config.pxi"
+
 
 cdef Config * dictToConfig(string rootname, dc) except NULL:
     cdef Config * cfg = new Config()
@@ -230,3 +242,53 @@ cdef XMLNode2dict(XMLNode node):
         inc(it)
     if len(opts)>0: dct['options'] = opts
     return dct
+
+cdef CFloat32VolumeData3D* linkVolFromGeometry(CVolumeGeometry3D *pGeometry, data) except NULL:
+    cdef CFloat32VolumeData3D * pDataObject3D = NULL
+    geom_shape = (pGeometry.getGridSliceCount(), pGeometry.getGridRowCount(), pGeometry.getGridColCount())
+    if isinstance(data, np.ndarray):
+        data_shape = data.shape
+    elif isinstance(data, GPULink):
+        data_shape = (data.z, data.y, data.x)
+    if geom_shape != data_shape:
+        raise ValueError(
+            "The dimensions of the data do not match those specified in the geometry.".format(data_shape, geom_shape))
+
+    if isinstance(data, np.ndarray):
+        pCustom = <CFloat32CustomMemory*> new CFloat32CustomPython(data)
+        pDataObject3D = new CFloat32VolumeData3DMemory(pGeometry, pCustom)
+    elif isinstance(data, GPULink):
+        IF HAVE_CUDA==True:
+            hnd = wrapHandle(<float*>PyLong_AsVoidPtr(data.ptr), data.x, data.y, data.z, data.pitch/4)
+            pDataObject3D = new CFloat32VolumeData3DGPU(pGeometry, hnd)
+        ELSE:
+            raise NotImplementedError("CUDA support is not enabled in ASTRA")
+    else:
+        raise TypeError("data should be a numpy.ndarray or a GPULink object")
+    return pDataObject3D
+
+cdef CFloat32ProjectionData3D* linkProjFromGeometry(CProjectionGeometry3D *pGeometry, data) except NULL:
+    cdef CFloat32ProjectionData3D * pDataObject3D = NULL
+    geom_shape = (pGeometry.getDetectorRowCount(), pGeometry.getProjectionCount(), pGeometry.getDetectorColCount())
+    if isinstance(data, np.ndarray):
+        data_shape = data.shape
+    elif isinstance(data, GPULink):
+        data_shape = (data.z, data.y, data.x)
+    if geom_shape != data_shape:
+        raise ValueError(
+            "The dimensions of the data do not match those specified in the geometry.".format(data_shape, geom_shape))
+
+    if isinstance(data, np.ndarray):
+        pCustom = <CFloat32CustomMemory*> new CFloat32CustomPython(data)
+        pDataObject3D = new CFloat32ProjectionData3DMemory(pGeometry, pCustom)
+    elif isinstance(data, GPULink):
+        IF HAVE_CUDA==True:
+            hnd = wrapHandle(<float*>PyLong_AsVoidPtr(data.ptr), data.x, data.y, data.z, data.pitch/4)
+            pDataObject3D = new CFloat32ProjectionData3DGPU(pGeometry, hnd)
+        ELSE:
+            raise NotImplementedError("CUDA support is not enabled in ASTRA")
+    else:
+        raise TypeError("data should be a numpy.ndarray or a GPULink object")
+    return pDataObject3D
+
+
-- 
cgit v1.2.3