From 6f094f37fd2503e104a0477ac01d7a5b825d351a Mon Sep 17 00:00:00 2001
From: "Jakob Jorgensen, WS at HMXIF" <jakob.jorgensen@manchester.ac.uk>
Date: Fri, 26 Apr 2019 15:53:10 +0100
Subject: Reorganise ops, processors and utils as directories

---
 .../ccpi/astra/operators/AstraProjector3DSimple.py |  75 +++++
 .../ccpi/astra/operators/AstraProjectorMC.py       | 112 +++++++
 .../ccpi/astra/operators/AstraProjectorSimple.py   |  71 ++++
 Wrappers/Python/ccpi/astra/operators/__init__.py   |   4 +
 Wrappers/Python/ccpi/astra/ops.py                  | 249 --------------
 Wrappers/Python/ccpi/astra/processors.py           | 363 ---------------------
 .../ccpi/astra/processors/AstraBackProjector.py    |  80 +++++
 .../ccpi/astra/processors/AstraBackProjector3D.py  |  67 ++++
 .../ccpi/astra/processors/AstraBackProjectorMC.py  |  40 +++
 .../ccpi/astra/processors/AstraForwardProjector.py |  85 +++++
 .../astra/processors/AstraForwardProjector3D.py    |  72 ++++
 .../astra/processors/AstraForwardProjectorMC.py    |  42 +++
 Wrappers/Python/ccpi/astra/processors/__init__.py  |   7 +
 Wrappers/Python/ccpi/astra/utils.py                |  62 ----
 Wrappers/Python/ccpi/astra/utils/__init__.py       |   2 +
 .../ccpi/astra/utils/convert_geometry_to_astra.py  |  62 ++++
 Wrappers/Python/setup.py                           |   6 +-
 Wrappers/Python/wip/demo_astra_mc.py               |   2 +-
 Wrappers/Python/wip/demo_astra_nexus.py            |   2 +-
 Wrappers/Python/wip/demo_astra_simple.py           |   2 +-
 Wrappers/Python/wip/demo_astra_sophiabeads.py      |   2 +-
 Wrappers/Python/wip/demo_astra_sophiabeads3D.py    |   2 +-
 Wrappers/Python/wip/work_out_adjoint.py            |   2 +-
 Wrappers/Python/wip/work_out_adjoint3D.py          |   2 +-
 .../Python/wip/work_out_adjoint_sophiabeads.py     |   2 +-
 25 files changed, 732 insertions(+), 683 deletions(-)
 create mode 100644 Wrappers/Python/ccpi/astra/operators/AstraProjector3DSimple.py
 create mode 100644 Wrappers/Python/ccpi/astra/operators/AstraProjectorMC.py
 create mode 100644 Wrappers/Python/ccpi/astra/operators/AstraProjectorSimple.py
 create mode 100644 Wrappers/Python/ccpi/astra/operators/__init__.py
 delete mode 100755 Wrappers/Python/ccpi/astra/ops.py
 delete mode 100644 Wrappers/Python/ccpi/astra/processors.py
 create mode 100644 Wrappers/Python/ccpi/astra/processors/AstraBackProjector.py
 create mode 100644 Wrappers/Python/ccpi/astra/processors/AstraBackProjector3D.py
 create mode 100644 Wrappers/Python/ccpi/astra/processors/AstraBackProjectorMC.py
 create mode 100644 Wrappers/Python/ccpi/astra/processors/AstraForwardProjector.py
 create mode 100644 Wrappers/Python/ccpi/astra/processors/AstraForwardProjector3D.py
 create mode 100644 Wrappers/Python/ccpi/astra/processors/AstraForwardProjectorMC.py
 create mode 100644 Wrappers/Python/ccpi/astra/processors/__init__.py
 delete mode 100755 Wrappers/Python/ccpi/astra/utils.py
 create mode 100644 Wrappers/Python/ccpi/astra/utils/__init__.py
 create mode 100644 Wrappers/Python/ccpi/astra/utils/convert_geometry_to_astra.py

(limited to 'Wrappers/Python')

diff --git a/Wrappers/Python/ccpi/astra/operators/AstraProjector3DSimple.py b/Wrappers/Python/ccpi/astra/operators/AstraProjector3DSimple.py
new file mode 100644
index 0000000..3240ee4
--- /dev/null
+++ b/Wrappers/Python/ccpi/astra/operators/AstraProjector3DSimple.py
@@ -0,0 +1,75 @@
+# -*- coding: utf-8 -*-
+#    This work is independent part of the Core Imaging Library developed by
+#    Visual Analytics and Imaging System Group of the Science Technology
+#    Facilities Council, STFC
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+from ccpi.optimisation.operators import Operator, LinearOperator
+import numpy
+from ccpi.framework import AcquisitionData, ImageData, DataContainer
+from ccpi.optimisation.ops import PowerMethodNonsquare
+from ccpi.astra.processors import AstraForwardProjector, AstraBackProjector, \
+     AstraForwardProjector3D, AstraBackProjector3D
+
+class AstraProjector3DSimple(LinearOperator):
+    """ASTRA projector modified to use DataSet and geometry."""
+    def __init__(self, geomv, geomp):
+        super(AstraProjector3DSimple, self).__init__()
+        
+        # Store volume and sinogram geometries.
+        self.sinogram_geometry = geomp
+        self.volume_geometry = geomv
+        
+        self.fp = AstraForwardProjector3D(volume_geometry=geomv,
+                                        sinogram_geometry=geomp,
+                                        output_axes_order=['vertical','angle','horizontal'])
+        
+        self.bp = AstraBackProjector3D(volume_geometry=geomv,
+                                        sinogram_geometry=geomp,
+                                        output_axes_order=['vertical','horizontal_y','horizontal_x'])
+                
+        # Initialise empty for singular value.
+        self.s1 = None
+    
+    def direct(self, IM):
+        self.fp.set_input(IM)
+        out = self.fp.get_output()
+        return out
+    
+    def adjoint(self, DATA):
+        self.bp.set_input(DATA)
+        out = self.bp.get_output()
+        return out
+    
+    #def delete(self):
+    #    astra.data2d.delete(self.proj_id)
+    
+    def get_max_sing_val(self):
+        self.s1, sall, svec = PowerMethodNonsquare(self,10)
+        return self.s1
+    
+    def size(self):
+        # Only implemented for 2D
+        return ( (self.sinogram_geometry.angles.size, \
+                  self.sinogram_geometry.pixel_num_h, \
+                  self.sinogram_geometry.pixel_num_v,), \
+                 (self.volume_geometry.voxel_num_x, \
+                  self.volume_geometry.voxel_num_y, \
+                  self.volume_geometry.voxel_num_z) )
+    
+    def create_image_data(self):
+        inputsize = self.size()[1]
+        return DataContainer(numpy.random.randn(inputsize[2],
+                                                inputsize[1],
+                                                inputsize[0]))
\ No newline at end of file
diff --git a/Wrappers/Python/ccpi/astra/operators/AstraProjectorMC.py b/Wrappers/Python/ccpi/astra/operators/AstraProjectorMC.py
new file mode 100644
index 0000000..51f51ca
--- /dev/null
+++ b/Wrappers/Python/ccpi/astra/operators/AstraProjectorMC.py
@@ -0,0 +1,112 @@
+# -*- coding: utf-8 -*-
+#    This work is independent part of the Core Imaging Library developed by
+#    Visual Analytics and Imaging System Group of the Science Technology
+#    Facilities Council, STFC
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+from ccpi.optimisation.operators import Operator, LinearOperator
+from ccpi.framework import AcquisitionData, ImageData, DataContainer
+from ccpi.optimisation.ops import PowerMethodNonsquare
+from ccpi.astra.processors import AstraForwardProjector, AstraBackProjector, \
+     AstraForwardProjectorMC, AstraBackProjectorMC, AstraForwardProjector3D, \
+     AstraBackProjector3D
+
+class AstraProjectorMC(LinearOperator):
+    """ASTRA Multichannel projector"""
+    def __init__(self, geomv, geomp, device):
+        super(AstraProjectorMC, self).__init__()
+        
+        # Store volume and sinogram geometries.
+        self.sinogram_geometry = geomp
+        self.volume_geometry = geomv
+        
+        self.fp = AstraForwardProjectorMC(volume_geometry=geomv,
+                                        sinogram_geometry=geomp,
+                                        proj_id=None,
+                                        device=device)
+        
+        self.bp = AstraBackProjectorMC(volume_geometry=geomv,
+                                        sinogram_geometry=geomp,
+                                        proj_id=None,
+                                        device=device)
+                
+        # Initialise empty for singular value.
+        self.s1 = None
+    
+#    def direct(self, IM):
+#        self.fp.set_input(IM)
+#        out = self.fp.get_output()
+#        return out
+#    
+#    def adjoint(self, DATA):
+#        self.bp.set_input(DATA)
+#        out = self.bp.get_output()
+#        return out
+    
+    
+    def direct(self, IM, out=None):
+        self.fp.set_input(IM)
+        
+        if out is None:
+            return self.fp.get_output()
+        else:
+            out.fill(self.fp.get_output())
+    
+    def adjoint(self, DATA, out=None):
+        self.bp.set_input(DATA)
+        
+        if out is None:
+            return self.bp.get_output()
+        else:
+            out.fill(self.bp.get_output())    
+    
+    #def delete(self):
+    #    astra.data2d.delete(self.proj_id)
+    
+#    def get_max_sing_val(self):
+#        if self.s1 is None:
+#            self.s1, sall, svec = PowerMethodNonsquare(self,10)
+#            return self.s1
+#        else:
+#            return self.s1
+#    
+#    def size(self):
+#        # Only implemented for 2D
+#        return ( (self.sinogram_geometry.angles.size, \
+#                  self.sinogram_geometry.pixel_num_h), \
+#                 (self.volume_geometry.voxel_num_x, \
+#                  self.volume_geometry.voxel_num_y) )
+#    
+#    def create_image_data(self):
+#        inputsize = self.size()[1]
+#        return DataContainer(numpy.random.randn(self.volume_geometry.channels,
+#                                                inputsize[0],
+#                                                inputsize[1]))
+        
+#    def allocate_direct(self):
+#        return self.create_image_data()def domain_geometry(self):
+#        return self.volume_geometry
+    
+    def domain_geometry(self):
+        return self.volume_geometry
+    
+    def range_geometry(self):
+        return self.sinogram_geometry    
+    
+    def norm(self):
+
+        x0 = self.volume_geometry.allocate('random')
+        self.s1, sall, svec = PowerMethodNonsquare(self, 50, x0)
+        return self.s1
+    
\ No newline at end of file
diff --git a/Wrappers/Python/ccpi/astra/operators/AstraProjectorSimple.py b/Wrappers/Python/ccpi/astra/operators/AstraProjectorSimple.py
new file mode 100644
index 0000000..b459e82
--- /dev/null
+++ b/Wrappers/Python/ccpi/astra/operators/AstraProjectorSimple.py
@@ -0,0 +1,71 @@
+# -*- coding: utf-8 -*-
+#    This work is independent part of the Core Imaging Library developed by
+#    Visual Analytics and Imaging System Group of the Science Technology
+#    Facilities Council, STFC
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License as published by
+#    the Free Software Foundation, either version 3 of the License, or
+#    (at your option) any later version.
+#
+#    This program is distributed in the hope that it will be useful,
+#    but WITHOUT ANY WARRANTY; without even the implied warranty of
+#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#    GNU General Public License for more details.
+#
+#    You should have received a copy of the GNU General Public License
+#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+from ccpi.optimisation.operators import Operator, LinearOperator
+from ccpi.framework import AcquisitionData, ImageData, DataContainer
+from ccpi.optimisation.ops import PowerMethodNonsquare
+from ccpi.astra.processors import AstraForwardProjector, AstraBackProjector
+
+class AstraProjectorSimple(LinearOperator):
+    """ASTRA projector modified to use DataSet and geometry."""
+    def __init__(self, geomv, geomp, device):
+        super(AstraProjectorSimple, self).__init__()
+        
+        # Store volume and sinogram geometries.
+        self.sinogram_geometry = geomp
+        self.volume_geometry = geomv
+        
+        self.fp = AstraForwardProjector(volume_geometry=geomv,
+                                        sinogram_geometry=geomp,
+                                        proj_id=None,
+                                        device=device)
+        
+        self.bp = AstraBackProjector(volume_geometry=geomv,
+                                        sinogram_geometry=geomp,
+                                        proj_id=None,
+                                        device=device)
+                
+        # Initialise empty for singular value.
+        self.s1 = None
+        
+    def direct(self, IM, out=None):
+        self.fp.set_input(IM)
+        
+        if out is None:
+            return self.fp.get_output()
+        else:
+            out.fill(self.fp.get_output())
+    
+    def adjoint(self, DATA, out=None):
+        self.bp.set_input(DATA)
+        
+        if out is None:
+            return self.bp.get_output()
+        else:
+            out.fill(self.bp.get_output())
+
+    def domain_geometry(self):
+        return self.volume_geometry
+    
+    def range_geometry(self):
+        return self.sinogram_geometry    
+    
+    def norm(self):
+
+        x0 = self.volume_geometry.allocate('random')
+        self.s1, sall, svec = PowerMethodNonsquare(self, 50, x0)
+        return self.s1
\ No newline at end of file
diff --git a/Wrappers/Python/ccpi/astra/operators/__init__.py b/Wrappers/Python/ccpi/astra/operators/__init__.py
new file mode 100644
index 0000000..6848776
--- /dev/null
+++ b/Wrappers/Python/ccpi/astra/operators/__init__.py
@@ -0,0 +1,4 @@
+
+from .AstraProjectorSimple import AstraProjectorSimple
+from .AstraProjector3DSimple import AstraProjector3DSimple
+from .AstraProjectorMC import AstraProjectorMC
\ No newline at end of file
diff --git a/Wrappers/Python/ccpi/astra/ops.py b/Wrappers/Python/ccpi/astra/ops.py
deleted file mode 100755
index 3cc8453..0000000
--- a/Wrappers/Python/ccpi/astra/ops.py
+++ /dev/null
@@ -1,249 +0,0 @@
-# -*- coding: utf-8 -*-
-#    This work is independent part of the Core Imaging Library developed by
-#    Visual Analytics and Imaging System Group of the Science Technology
-#    Facilities Council, STFC
-#    This program is free software: you can redistribute it and/or modify
-#    it under the terms of the GNU General Public License as published by
-#    the Free Software Foundation, either version 3 of the License, or
-#    (at your option) any later version.
-#
-#    This program is distributed in the hope that it will be useful,
-#    but WITHOUT ANY WARRANTY; without even the implied warranty of
-#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-#    GNU General Public License for more details.
-#
-#    You should have received a copy of the GNU General Public License
-#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
-
-from ccpi.optimisation.operators import Operator, LinearOperator
-import numpy
-from ccpi.framework import AcquisitionData, ImageData, DataContainer
-from ccpi.optimisation.ops import PowerMethodNonsquare
-from ccpi.astra.processors import AstraForwardProjector, AstraBackProjector, \
-     AstraForwardProjectorMC, AstraBackProjectorMC, AstraForwardProjector3D, \
-     AstraBackProjector3D
-
-class AstraProjectorSimple(LinearOperator):
-    """ASTRA projector modified to use DataSet and geometry."""
-    def __init__(self, geomv, geomp, device):
-        super(AstraProjectorSimple, self).__init__()
-        
-        # Store volume and sinogram geometries.
-        self.sinogram_geometry = geomp
-        self.volume_geometry = geomv
-        
-        self.fp = AstraForwardProjector(volume_geometry=geomv,
-                                        sinogram_geometry=geomp,
-                                        proj_id=None,
-                                        device=device)
-        
-        self.bp = AstraBackProjector(volume_geometry=geomv,
-                                        sinogram_geometry=geomp,
-                                        proj_id=None,
-                                        device=device)
-                
-        # Initialise empty for singular value.
-        self.s1 = None
-        
-    def direct(self, IM, out=None):
-        self.fp.set_input(IM)
-        
-        if out is None:
-            return self.fp.get_output()
-        else:
-            out.fill(self.fp.get_output())
-    
-    def adjoint(self, DATA, out=None):
-        self.bp.set_input(DATA)
-        
-        if out is None:
-            return self.bp.get_output()
-        else:
-            out.fill(self.bp.get_output())
-               
-        
-    
-#    def direct(self, IM):
-#        self.fp.set_input(IM)
-#        out = self.fp.get_output()
-#        return out
-#    
-#    def adjoint(self, DATA):
-#        self.bp.set_input(DATA)
-#        out = self.bp.get_output()
-#        return out
-    
-    #def delete(self):
-    #    astra.data2d.delete(self.proj_id)
-    
-    #def get_max_sing_val(self):
-    #    self.s1, sall, svec = PowerMethodNonsquare(self,10)
-    #    return self.s1
-
-    def domain_geometry(self):
-        return self.volume_geometry
-    
-    def range_geometry(self):
-        return self.sinogram_geometry    
-    
-    def norm(self):
-
-        x0 = self.volume_geometry.allocate('random')
-        self.s1, sall, svec = PowerMethodNonsquare(self, 50, x0)
-        return self.s1
-    
-    def size(self):
-        # Only implemented for 2D
-        return ( (self.sinogram_geometry.angles.size, \
-                  self.sinogram_geometry.pixel_num_h), \
-                 (self.volume_geometry.voxel_num_x, \
-                  self.volume_geometry.voxel_num_y) )
-    
-    #def create_image_data(self):
-    #    inputsize = self.size()[1]
-    #    return DataContainer(numpy.random.randn(inputsize[0],
-    #                                            inputsize[1]))
-
-class AstraProjector3DSimple(Operator):
-    """ASTRA projector modified to use DataSet and geometry."""
-    def __init__(self, geomv, geomp):
-        super(AstraProjector3DSimple, self).__init__()
-        
-        # Store volume and sinogram geometries.
-        self.sinogram_geometry = geomp
-        self.volume_geometry = geomv
-        
-        self.fp = AstraForwardProjector3D(volume_geometry=geomv,
-                                        sinogram_geometry=geomp,
-                                        output_axes_order=['vertical','angle','horizontal'])
-        
-        self.bp = AstraBackProjector3D(volume_geometry=geomv,
-                                        sinogram_geometry=geomp,
-                                        output_axes_order=['vertical','horizontal_y','horizontal_x'])
-                
-        # Initialise empty for singular value.
-        self.s1 = None
-    
-    def direct(self, IM):
-        self.fp.set_input(IM)
-        out = self.fp.get_output()
-        return out
-    
-    def adjoint(self, DATA):
-        self.bp.set_input(DATA)
-        out = self.bp.get_output()
-        return out
-    
-    #def delete(self):
-    #    astra.data2d.delete(self.proj_id)
-    
-    def get_max_sing_val(self):
-        self.s1, sall, svec = PowerMethodNonsquare(self,10)
-        return self.s1
-    
-    def size(self):
-        # Only implemented for 2D
-        return ( (self.sinogram_geometry.angles.size, \
-                  self.sinogram_geometry.pixel_num_h, \
-                  self.sinogram_geometry.pixel_num_v,), \
-                 (self.volume_geometry.voxel_num_x, \
-                  self.volume_geometry.voxel_num_y, \
-                  self.volume_geometry.voxel_num_z) )
-    
-    def create_image_data(self):
-        inputsize = self.size()[1]
-        return DataContainer(numpy.random.randn(inputsize[2],
-                                                inputsize[1],
-                                                inputsize[0]))
-
-
-class AstraProjectorMC(LinearOperator):
-    """ASTRA Multichannel projector"""
-    def __init__(self, geomv, geomp, device):
-        super(AstraProjectorMC, self).__init__()
-        
-        # Store volume and sinogram geometries.
-        self.sinogram_geometry = geomp
-        self.volume_geometry = geomv
-        
-        self.fp = AstraForwardProjectorMC(volume_geometry=geomv,
-                                        sinogram_geometry=geomp,
-                                        proj_id=None,
-                                        device=device)
-        
-        self.bp = AstraBackProjectorMC(volume_geometry=geomv,
-                                        sinogram_geometry=geomp,
-                                        proj_id=None,
-                                        device=device)
-                
-        # Initialise empty for singular value.
-        self.s1 = None
-    
-#    def direct(self, IM):
-#        self.fp.set_input(IM)
-#        out = self.fp.get_output()
-#        return out
-#    
-#    def adjoint(self, DATA):
-#        self.bp.set_input(DATA)
-#        out = self.bp.get_output()
-#        return out
-    
-    
-    def direct(self, IM, out=None):
-        self.fp.set_input(IM)
-        
-        if out is None:
-            return self.fp.get_output()
-        else:
-            out.fill(self.fp.get_output())
-    
-    def adjoint(self, DATA, out=None):
-        self.bp.set_input(DATA)
-        
-        if out is None:
-            return self.bp.get_output()
-        else:
-            out.fill(self.bp.get_output())    
-    
-    #def delete(self):
-    #    astra.data2d.delete(self.proj_id)
-    
-#    def get_max_sing_val(self):
-#        if self.s1 is None:
-#            self.s1, sall, svec = PowerMethodNonsquare(self,10)
-#            return self.s1
-#        else:
-#            return self.s1
-#    
-#    def size(self):
-#        # Only implemented for 2D
-#        return ( (self.sinogram_geometry.angles.size, \
-#                  self.sinogram_geometry.pixel_num_h), \
-#                 (self.volume_geometry.voxel_num_x, \
-#                  self.volume_geometry.voxel_num_y) )
-#    
-#    def create_image_data(self):
-#        inputsize = self.size()[1]
-#        return DataContainer(numpy.random.randn(self.volume_geometry.channels,
-#                                                inputsize[0],
-#                                                inputsize[1]))
-        
-#    def allocate_direct(self):
-#        return self.create_image_data()def domain_geometry(self):
-#        return self.volume_geometry
-    
-    def domain_geometry(self):
-        return self.volume_geometry
-    
-    def range_geometry(self):
-        return self.sinogram_geometry    
-    
-    def norm(self):
-
-        x0 = self.volume_geometry.allocate('random')
-        self.s1, sall, svec = PowerMethodNonsquare(self, 50, x0)
-        return self.s1
-    
-
-
diff --git a/Wrappers/Python/ccpi/astra/processors.py b/Wrappers/Python/ccpi/astra/processors.py
deleted file mode 100644
index 855f890..0000000
--- a/Wrappers/Python/ccpi/astra/processors.py
+++ /dev/null
@@ -1,363 +0,0 @@
-from ccpi.framework import DataProcessor, ImageData, AcquisitionData
-from ccpi.astra.utils import convert_geometry_to_astra
-import astra
-
-
-class AstraForwardProjector(DataProcessor):
-    '''AstraForwardProjector
-    
-    Forward project ImageData to AcquisitionData using ASTRA proj_id.
-    
-    Input: ImageData
-    Parameter: proj_id
-    Output: AcquisitionData
-    '''
-    
-    def __init__(self,
-                 volume_geometry=None,
-                 sinogram_geometry=None,
-                 proj_id=None,
-                 device='cpu'):
-        kwargs = {
-                  'volume_geometry'  : volume_geometry,
-                  'sinogram_geometry'  : sinogram_geometry,
-                  'proj_id'  : proj_id,
-                  'device'  : device
-                  }
-        
-        #DataProcessor.__init__(self, **kwargs)
-        super(AstraForwardProjector, self).__init__(**kwargs)
-        
-        self.set_ImageGeometry(volume_geometry)
-        self.set_AcquisitionGeometry(sinogram_geometry)
-        
-        # Set up ASTRA Volume and projection geometry, not to be stored in self
-        vol_geom, proj_geom = convert_geometry_to_astra(self.volume_geometry,
-                                                        self.sinogram_geometry)
-        
-        # ASTRA projector, to be stored
-        if device == 'cpu':
-            # Note that 'line' only one option
-            if self.sinogram_geometry.geom_type == 'parallel':
-                self.set_projector(astra.create_projector('line', proj_geom, vol_geom) )
-            elif self.sinogram_geometry.geom_type == 'cone':
-                self.set_projector(astra.create_projector('line_fanflat', proj_geom, vol_geom) )
-            else:
-                NotImplemented    
-        elif device == 'gpu':
-            self.set_projector(astra.create_projector('cuda', proj_geom, vol_geom) )
-        else:
-            NotImplemented
-    
-    def check_input(self, dataset):
-        if dataset.number_of_dimensions == 3 or\
-           dataset.number_of_dimensions == 2:
-               return True
-        else:
-            raise ValueError("Expected input dimensions is 2 or 3, got {0}"\
-                             .format(dataset.number_of_dimensions))
-    
-    def set_projector(self, proj_id):
-        self.proj_id = proj_id
-    
-    def set_ImageGeometry(self, volume_geometry):
-        self.volume_geometry = volume_geometry
-    
-    def set_AcquisitionGeometry(self, sinogram_geometry):
-        self.sinogram_geometry = sinogram_geometry
-    
-    def process(self):
-        IM = self.get_input()
-        DATA = AcquisitionData(geometry=self.sinogram_geometry)
-        #sinogram_id, DATA = astra.create_sino( IM.as_array(), 
-        #                           self.proj_id)
-        sinogram_id, DATA.array = astra.create_sino(IM.as_array(), 
-                                                           self.proj_id)
-        astra.data2d.delete(sinogram_id)
-        
-        if self.device == 'cpu':
-            return DATA
-        else:
-            if self.sinogram_geometry.geom_type == 'cone':
-                return DATA
-            else:
-                 scaling = 1.0/self.volume_geometry.voxel_size_x
-                 return scaling*DATA
-
-class AstraBackProjector(DataProcessor):
-    '''AstraBackProjector
-    
-    Back project AcquisitionData to ImageData using ASTRA proj_id.
-    
-    Input: AcquisitionData
-    Parameter: proj_id
-    Output: ImageData
-    '''
-    
-    def __init__(self,
-                 volume_geometry=None,
-                 sinogram_geometry=None,
-                 proj_id=None,
-                 device='cpu'):
-        kwargs = {
-                  'volume_geometry'  : volume_geometry,
-                  'sinogram_geometry'  : sinogram_geometry,
-                  'proj_id'  : proj_id,
-                  'device'  : device
-                  }
-        
-        #DataProcessor.__init__(self, **kwargs)
-        super(AstraBackProjector, self).__init__(**kwargs)
-        
-        self.set_ImageGeometry(volume_geometry)
-        self.set_AcquisitionGeometry(sinogram_geometry)
-        
-                # Set up ASTRA Volume and projection geometry, not to be stored in self
-        vol_geom, proj_geom = convert_geometry_to_astra(self.volume_geometry,
-                                                        self.sinogram_geometry)
-        
-        # ASTRA projector, to be stored
-        if device == 'cpu':
-            # Note that 'line' only one option
-            if self.sinogram_geometry.geom_type == 'parallel':
-                self.set_projector(astra.create_projector('line', proj_geom, vol_geom) )
-            elif self.sinogram_geometry.geom_type == 'cone':
-                self.set_projector(astra.create_projector('line_fanflat', proj_geom, vol_geom) )
-            else:
-                NotImplemented 
-        elif device == 'gpu':
-            self.set_projector(astra.create_projector('cuda', proj_geom, vol_geom) )
-        else:
-            NotImplemented
-    
-    def check_input(self, dataset):
-        if dataset.number_of_dimensions == 3 or dataset.number_of_dimensions == 2:
-               return True
-        else:
-            raise ValueError("Expected input dimensions is 2 or 3, got {0}"\
-                             .format(dataset.number_of_dimensions))
-    
-    def set_projector(self, proj_id):
-        self.proj_id = proj_id
-        
-    def set_ImageGeometry(self, volume_geometry):
-        self.volume_geometry = volume_geometry
-        
-    def set_AcquisitionGeometry(self, sinogram_geometry):
-        self.sinogram_geometry = sinogram_geometry
-    
-    def process(self):
-        DATA = self.get_input()
-        IM = ImageData(geometry=self.volume_geometry)
-        rec_id, IM.array = astra.create_backprojection(DATA.as_array(),
-                            self.proj_id)
-        astra.data2d.delete(rec_id)
-        
-        if self.device == 'cpu':
-            return IM
-        else:
-            scaling = self.volume_geometry.voxel_size_x**3  
-            return scaling*IM
-
-class AstraForwardProjectorMC(AstraForwardProjector):
-    '''AstraForwardProjector Multi channel
-    
-    Forward project ImageData to AcquisitionDataSet using ASTRA proj_id.
-    
-    Input: ImageDataSet
-    Parameter: proj_id
-    Output: AcquisitionData
-    '''
-    def check_input(self, dataset):
-        if dataset.number_of_dimensions == 2 or \
-           dataset.number_of_dimensions == 3 or \
-           dataset.number_of_dimensions == 4:
-               return True
-        else:
-            raise ValueError("Expected input dimensions is 2 or 3, got {0}"\
-                             .format(dataset.number_of_dimensions))
-    def process(self):
-        IM = self.get_input()
-        #create the output AcquisitionData
-        DATA = AcquisitionData(geometry=self.sinogram_geometry)
-        
-        for k in range(DATA.geometry.channels):
-            sinogram_id, DATA.as_array()[k] = astra.create_sino(IM.as_array()[k], 
-                                                           self.proj_id)
-            astra.data2d.delete(sinogram_id)
-        
-        if self.device == 'cpu':
-            return DATA
-        else:
-            if self.sinogram_geometry.geom_type == 'cone':
-                return DATA
-            else:
-                 scaling = (1.0/self.volume_geometry.voxel_size_x) 
-                 return scaling*DATA
-
-class AstraBackProjectorMC(AstraBackProjector):
-    '''AstraBackProjector Multi channel
-    
-    Back project AcquisitionData to ImageData using ASTRA proj_id.
-    
-    Input: AcquisitionData
-    Parameter: proj_id
-    Output: ImageData
-    '''
-    def check_input(self, dataset):
-        if dataset.number_of_dimensions == 2 or \
-           dataset.number_of_dimensions == 3 or \
-           dataset.number_of_dimensions == 4:
-               return True
-        else:
-            raise ValueError("Expected input dimensions is 2 or 3, got {0}"\
-                             .format(dataset.number_of_dimensions))
-    def process(self):
-        DATA = self.get_input()
-        
-        IM = ImageData(geometry=self.volume_geometry)
-        
-        for k in range(IM.geometry.channels):
-            rec_id, IM.as_array()[k] = astra.create_backprojection(
-                    DATA.as_array()[k], 
-                    self.proj_id)
-            astra.data2d.delete(rec_id)
-        
-        if self.device == 'cpu':
-            return IM
-        else:
-            scaling = self.volume_geometry.voxel_size_x**3  
-            return scaling*IM
-
-class AstraForwardProjector3D(DataProcessor):
-    '''AstraForwardProjector3D
-    
-    Forward project ImageData to AcquisitionData using ASTRA proj_geom and 
-    vol_geom.
-    
-    Input: ImageData
-    Parameter: proj_geom, vol_geom
-    Output: AcquisitionData
-    '''
-    
-    def __init__(self,
-                 volume_geometry=None,
-                 sinogram_geometry=None,
-                 proj_geom=None,
-                 vol_geom=None,
-                 output_axes_order=None):
-        kwargs = {
-                  'volume_geometry'  : volume_geometry,
-                  'sinogram_geometry'  : sinogram_geometry,
-                  'proj_geom'  : proj_geom,
-                  'vol_geom'  : vol_geom,
-                  'output_axes_order'  : output_axes_order
-                  }
-        
-        #DataProcessor.__init__(self, **kwargs)
-        super(AstraForwardProjector3D, self).__init__(**kwargs)
-        
-        self.set_ImageGeometry(volume_geometry)
-        self.set_AcquisitionGeometry(sinogram_geometry)
-        
-        # Set up ASTRA Volume and projection geometry, not to be stored in self
-        vol_geom, proj_geom = convert_geometry_to_astra(self.volume_geometry,
-                                                        self.sinogram_geometry)
-        
-        # Also store ASTRA geometries
-        self.vol_geom = vol_geom
-        self.proj_geom = proj_geom
-    
-    def check_input(self, dataset):
-        if dataset.number_of_dimensions == 3:
-               return True
-        else:
-            raise ValueError("Expected input dimensions 3, got {0}"\
-                             .format(dataset.number_of_dimensions))
-    
-    def set_ImageGeometry(self, volume_geometry):
-        self.volume_geometry = volume_geometry
-    
-    def set_AcquisitionGeometry(self, sinogram_geometry):
-        self.sinogram_geometry = sinogram_geometry
-    
-    def set_vol_geom(self, vol_geom):
-        self.vol_geom = vol_geom
-    
-    def set_AcquisitionGeometry(self, sinogram_geometry):
-        self.sinogram_geometry = sinogram_geometry
-    
-    def process(self):
-        IM = self.get_input()
-        DATA = AcquisitionData(geometry=self.sinogram_geometry,
-                               dimension_labels=self.output_axes_order)
-        sinogram_id, DATA.array = astra.create_sino3d_gpu(IM.as_array(), 
-                                                           self.proj_geom,
-                                                           self.vol_geom)
-        astra.data3d.delete(sinogram_id)
-        # 3D CUDA FP does not need scaling
-        return DATA
-
-class AstraBackProjector3D(DataProcessor):
-    '''AstraBackProjector3D
-    
-    Back project AcquisitionData to ImageData using ASTRA proj_geom, vol_geom.
-    
-    Input: AcquisitionData
-    Parameter: proj_geom, vol_geom
-    Output: ImageData
-    '''
-    
-    def __init__(self,
-                 volume_geometry=None,
-                 sinogram_geometry=None,
-                 proj_geom=None,
-                 vol_geom=None,
-                 output_axes_order=None):
-        kwargs = {
-                  'volume_geometry'  : volume_geometry,
-                  'sinogram_geometry'  : sinogram_geometry,
-                  'proj_geom'  : proj_geom,
-                  'vol_geom'  : vol_geom,
-                  'output_axes_order'  : output_axes_order
-                  }
-        
-        #DataProcessor.__init__(self, **kwargs)
-        super(AstraBackProjector3D, self).__init__(**kwargs)
-        
-        self.set_ImageGeometry(volume_geometry)
-        self.set_AcquisitionGeometry(sinogram_geometry)
-        
-                # Set up ASTRA Volume and projection geometry, not to be stored in self
-        vol_geom, proj_geom = convert_geometry_to_astra(self.volume_geometry,
-                                                        self.sinogram_geometry)
-        
-        # Also store ASTRA geometries
-        self.vol_geom = vol_geom
-        self.proj_geom = proj_geom
-    
-    def check_input(self, dataset):
-        if dataset.number_of_dimensions == 3:
-               return True
-        else:
-            raise ValueError("Expected input dimensions is 3, got {0}"\
-                             .format(dataset.number_of_dimensions))
-        
-    def set_ImageGeometry(self, volume_geometry):
-        self.volume_geometry = volume_geometry
-        
-    def set_AcquisitionGeometry(self, sinogram_geometry):
-        self.sinogram_geometry = sinogram_geometry
-    
-    def process(self):
-        DATA = self.get_input()
-        IM = ImageData(geometry=self.volume_geometry,
-                       dimension_labels=self.output_axes_order)
-        rec_id, IM.array = astra.create_backprojection3d_gpu(DATA.as_array(),
-                            self.proj_geom,
-                            self.vol_geom)
-        astra.data3d.delete(rec_id)
-        
-        # Scaling of 3D ASTRA backprojector, works both parallel and cone.
-        scaling = 1/self.volume_geometry.voxel_size_x**2  
-        return scaling*IM
diff --git a/Wrappers/Python/ccpi/astra/processors/AstraBackProjector.py b/Wrappers/Python/ccpi/astra/processors/AstraBackProjector.py
new file mode 100644
index 0000000..476523a
--- /dev/null
+++ b/Wrappers/Python/ccpi/astra/processors/AstraBackProjector.py
@@ -0,0 +1,80 @@
+from ccpi.framework import DataProcessor, ImageData, AcquisitionData
+from ccpi.astra.utils import convert_geometry_to_astra
+import astra
+
+
+class AstraBackProjector(DataProcessor):
+    '''AstraBackProjector
+    
+    Back project AcquisitionData to ImageData using ASTRA proj_id.
+    
+    Input: AcquisitionData
+    Parameter: proj_id
+    Output: ImageData
+    '''
+    
+    def __init__(self,
+                 volume_geometry=None,
+                 sinogram_geometry=None,
+                 proj_id=None,
+                 device='cpu'):
+        kwargs = {
+                  'volume_geometry'  : volume_geometry,
+                  'sinogram_geometry'  : sinogram_geometry,
+                  'proj_id'  : proj_id,
+                  'device'  : device
+                  }
+        
+        #DataProcessor.__init__(self, **kwargs)
+        super(AstraBackProjector, self).__init__(**kwargs)
+        
+        self.set_ImageGeometry(volume_geometry)
+        self.set_AcquisitionGeometry(sinogram_geometry)
+        
+                # Set up ASTRA Volume and projection geometry, not to be stored in self
+        vol_geom, proj_geom = convert_geometry_to_astra(self.volume_geometry,
+                                                        self.sinogram_geometry)
+        
+        # ASTRA projector, to be stored
+        if device == 'cpu':
+            # Note that 'line' only one option
+            if self.sinogram_geometry.geom_type == 'parallel':
+                self.set_projector(astra.create_projector('line', proj_geom, vol_geom) )
+            elif self.sinogram_geometry.geom_type == 'cone':
+                self.set_projector(astra.create_projector('line_fanflat', proj_geom, vol_geom) )
+            else:
+                NotImplemented 
+        elif device == 'gpu':
+            self.set_projector(astra.create_projector('cuda', proj_geom, vol_geom) )
+        else:
+            NotImplemented
+    
+    def check_input(self, dataset):
+        if dataset.number_of_dimensions == 3 or dataset.number_of_dimensions == 2:
+               return True
+        else:
+            raise ValueError("Expected input dimensions is 2 or 3, got {0}"\
+                             .format(dataset.number_of_dimensions))
+    
+    def set_projector(self, proj_id):
+        self.proj_id = proj_id
+        
+    def set_ImageGeometry(self, volume_geometry):
+        self.volume_geometry = volume_geometry
+        
+    def set_AcquisitionGeometry(self, sinogram_geometry):
+        self.sinogram_geometry = sinogram_geometry
+    
+    def process(self):
+        DATA = self.get_input()
+        IM = ImageData(geometry=self.volume_geometry)
+        rec_id, IM.array = astra.create_backprojection(DATA.as_array(),
+                            self.proj_id)
+        astra.data2d.delete(rec_id)
+        
+        if self.device == 'cpu':
+            return IM
+        else:
+            scaling = self.volume_geometry.voxel_size_x**3  
+            return scaling*IM
+        
\ No newline at end of file
diff --git a/Wrappers/Python/ccpi/astra/processors/AstraBackProjector3D.py b/Wrappers/Python/ccpi/astra/processors/AstraBackProjector3D.py
new file mode 100644
index 0000000..b1d139e
--- /dev/null
+++ b/Wrappers/Python/ccpi/astra/processors/AstraBackProjector3D.py
@@ -0,0 +1,67 @@
+from ccpi.framework import DataProcessor, ImageData, AcquisitionData
+from ccpi.astra.utils import convert_geometry_to_astra
+import astra
+
+class AstraBackProjector3D(DataProcessor):
+    '''AstraBackProjector3D
+    
+    Back project AcquisitionData to ImageData using ASTRA proj_geom, vol_geom.
+    
+    Input: AcquisitionData
+    Parameter: proj_geom, vol_geom
+    Output: ImageData
+    '''
+    
+    def __init__(self,
+                 volume_geometry=None,
+                 sinogram_geometry=None,
+                 proj_geom=None,
+                 vol_geom=None,
+                 output_axes_order=None):
+        kwargs = {
+                  'volume_geometry'  : volume_geometry,
+                  'sinogram_geometry'  : sinogram_geometry,
+                  'proj_geom'  : proj_geom,
+                  'vol_geom'  : vol_geom,
+                  'output_axes_order'  : output_axes_order
+                  }
+        
+        #DataProcessor.__init__(self, **kwargs)
+        super(AstraBackProjector3D, self).__init__(**kwargs)
+        
+        self.set_ImageGeometry(volume_geometry)
+        self.set_AcquisitionGeometry(sinogram_geometry)
+        
+                # Set up ASTRA Volume and projection geometry, not to be stored in self
+        vol_geom, proj_geom = convert_geometry_to_astra(self.volume_geometry,
+                                                        self.sinogram_geometry)
+        
+        # Also store ASTRA geometries
+        self.vol_geom = vol_geom
+        self.proj_geom = proj_geom
+    
+    def check_input(self, dataset):
+        if dataset.number_of_dimensions == 3:
+               return True
+        else:
+            raise ValueError("Expected input dimensions is 3, got {0}"\
+                             .format(dataset.number_of_dimensions))
+        
+    def set_ImageGeometry(self, volume_geometry):
+        self.volume_geometry = volume_geometry
+        
+    def set_AcquisitionGeometry(self, sinogram_geometry):
+        self.sinogram_geometry = sinogram_geometry
+    
+    def process(self):
+        DATA = self.get_input()
+        IM = ImageData(geometry=self.volume_geometry,
+                       dimension_labels=self.output_axes_order)
+        rec_id, IM.array = astra.create_backprojection3d_gpu(DATA.as_array(),
+                            self.proj_geom,
+                            self.vol_geom)
+        astra.data3d.delete(rec_id)
+        
+        # Scaling of 3D ASTRA backprojector, works both parallel and cone.
+        scaling = 1/self.volume_geometry.voxel_size_x**2  
+        return scaling*IM
diff --git a/Wrappers/Python/ccpi/astra/processors/AstraBackProjectorMC.py b/Wrappers/Python/ccpi/astra/processors/AstraBackProjectorMC.py
new file mode 100644
index 0000000..d48fb80
--- /dev/null
+++ b/Wrappers/Python/ccpi/astra/processors/AstraBackProjectorMC.py
@@ -0,0 +1,40 @@
+from ccpi.framework import DataProcessor, ImageData, AcquisitionData
+from ccpi.astra.utils import convert_geometry_to_astra
+
+from ccpi.astra.processors import AstraBackProjector
+
+import astra
+
+class AstraBackProjectorMC(AstraBackProjector):
+    '''AstraBackProjector Multi channel
+    
+    Back project AcquisitionData to ImageData using ASTRA proj_id.
+    
+    Input: AcquisitionData
+    Parameter: proj_id
+    Output: ImageData
+    '''
+    def check_input(self, dataset):
+        if dataset.number_of_dimensions == 2 or \
+           dataset.number_of_dimensions == 3 or \
+           dataset.number_of_dimensions == 4:
+               return True
+        else:
+            raise ValueError("Expected input dimensions is 2 or 3, got {0}"\
+                             .format(dataset.number_of_dimensions))
+    def process(self):
+        DATA = self.get_input()
+        
+        IM = ImageData(geometry=self.volume_geometry)
+        
+        for k in range(IM.geometry.channels):
+            rec_id, IM.as_array()[k] = astra.create_backprojection(
+                    DATA.as_array()[k], 
+                    self.proj_id)
+            astra.data2d.delete(rec_id)
+        
+        if self.device == 'cpu':
+            return IM
+        else:
+            scaling = self.volume_geometry.voxel_size_x**3  
+            return scaling*IM
\ No newline at end of file
diff --git a/Wrappers/Python/ccpi/astra/processors/AstraForwardProjector.py b/Wrappers/Python/ccpi/astra/processors/AstraForwardProjector.py
new file mode 100644
index 0000000..dd5bab4
--- /dev/null
+++ b/Wrappers/Python/ccpi/astra/processors/AstraForwardProjector.py
@@ -0,0 +1,85 @@
+from ccpi.framework import DataProcessor, ImageData, AcquisitionData
+from ccpi.astra.utils import convert_geometry_to_astra
+import astra
+
+
+class AstraForwardProjector(DataProcessor):
+    '''AstraForwardProjector
+    
+    Forward project ImageData to AcquisitionData using ASTRA proj_id.
+    
+    Input: ImageData
+    Parameter: proj_id
+    Output: AcquisitionData
+    '''
+    
+    def __init__(self,
+                 volume_geometry=None,
+                 sinogram_geometry=None,
+                 proj_id=None,
+                 device='cpu'):
+        kwargs = {
+                  'volume_geometry'  : volume_geometry,
+                  'sinogram_geometry'  : sinogram_geometry,
+                  'proj_id'  : proj_id,
+                  'device'  : device
+                  }
+        
+        #DataProcessor.__init__(self, **kwargs)
+        super(AstraForwardProjector, self).__init__(**kwargs)
+        
+        self.set_ImageGeometry(volume_geometry)
+        self.set_AcquisitionGeometry(sinogram_geometry)
+        
+        # Set up ASTRA Volume and projection geometry, not to be stored in self
+        vol_geom, proj_geom = convert_geometry_to_astra(self.volume_geometry,
+                                                        self.sinogram_geometry)
+        
+        # ASTRA projector, to be stored
+        if device == 'cpu':
+            # Note that 'line' only one option
+            if self.sinogram_geometry.geom_type == 'parallel':
+                self.set_projector(astra.create_projector('line', proj_geom, vol_geom) )
+            elif self.sinogram_geometry.geom_type == 'cone':
+                self.set_projector(astra.create_projector('line_fanflat', proj_geom, vol_geom) )
+            else:
+                NotImplemented    
+        elif device == 'gpu':
+            self.set_projector(astra.create_projector('cuda', proj_geom, vol_geom) )
+        else:
+            NotImplemented
+    
+    def check_input(self, dataset):
+        if dataset.number_of_dimensions == 3 or\
+           dataset.number_of_dimensions == 2:
+               return True
+        else:
+            raise ValueError("Expected input dimensions is 2 or 3, got {0}"\
+                             .format(dataset.number_of_dimensions))
+    
+    def set_projector(self, proj_id):
+        self.proj_id = proj_id
+    
+    def set_ImageGeometry(self, volume_geometry):
+        self.volume_geometry = volume_geometry
+    
+    def set_AcquisitionGeometry(self, sinogram_geometry):
+        self.sinogram_geometry = sinogram_geometry
+    
+    def process(self):
+        IM = self.get_input()
+        DATA = AcquisitionData(geometry=self.sinogram_geometry)
+        #sinogram_id, DATA = astra.create_sino( IM.as_array(), 
+        #                           self.proj_id)
+        sinogram_id, DATA.array = astra.create_sino(IM.as_array(), 
+                                                           self.proj_id)
+        astra.data2d.delete(sinogram_id)
+        
+        if self.device == 'cpu':
+            return DATA
+        else:
+            if self.sinogram_geometry.geom_type == 'cone':
+                return DATA
+            else:
+                 scaling = 1.0/self.volume_geometry.voxel_size_x
+                 return scaling*DATA
\ No newline at end of file
diff --git a/Wrappers/Python/ccpi/astra/processors/AstraForwardProjector3D.py b/Wrappers/Python/ccpi/astra/processors/AstraForwardProjector3D.py
new file mode 100644
index 0000000..d18b43e
--- /dev/null
+++ b/Wrappers/Python/ccpi/astra/processors/AstraForwardProjector3D.py
@@ -0,0 +1,72 @@
+from ccpi.framework import DataProcessor, ImageData, AcquisitionData
+from ccpi.astra.utils import convert_geometry_to_astra
+import astra
+
+class AstraForwardProjector3D(DataProcessor):
+    '''AstraForwardProjector3D
+    
+    Forward project ImageData to AcquisitionData using ASTRA proj_geom and 
+    vol_geom.
+    
+    Input: ImageData
+    Parameter: proj_geom, vol_geom
+    Output: AcquisitionData
+    '''
+    
+    def __init__(self,
+                 volume_geometry=None,
+                 sinogram_geometry=None,
+                 proj_geom=None,
+                 vol_geom=None,
+                 output_axes_order=None):
+        kwargs = {
+                  'volume_geometry'  : volume_geometry,
+                  'sinogram_geometry'  : sinogram_geometry,
+                  'proj_geom'  : proj_geom,
+                  'vol_geom'  : vol_geom,
+                  'output_axes_order'  : output_axes_order
+                  }
+        
+        #DataProcessor.__init__(self, **kwargs)
+        super(AstraForwardProjector3D, self).__init__(**kwargs)
+        
+        self.set_ImageGeometry(volume_geometry)
+        self.set_AcquisitionGeometry(sinogram_geometry)
+        
+        # Set up ASTRA Volume and projection geometry, not to be stored in self
+        vol_geom, proj_geom = convert_geometry_to_astra(self.volume_geometry,
+                                                        self.sinogram_geometry)
+        
+        # Also store ASTRA geometries
+        self.vol_geom = vol_geom
+        self.proj_geom = proj_geom
+    
+    def check_input(self, dataset):
+        if dataset.number_of_dimensions == 3:
+               return True
+        else:
+            raise ValueError("Expected input dimensions 3, got {0}"\
+                             .format(dataset.number_of_dimensions))
+    
+    def set_ImageGeometry(self, volume_geometry):
+        self.volume_geometry = volume_geometry
+    
+    def set_AcquisitionGeometry(self, sinogram_geometry):
+        self.sinogram_geometry = sinogram_geometry
+    
+    def set_vol_geom(self, vol_geom):
+        self.vol_geom = vol_geom
+    
+    def set_AcquisitionGeometry(self, sinogram_geometry):
+        self.sinogram_geometry = sinogram_geometry
+    
+    def process(self):
+        IM = self.get_input()
+        DATA = AcquisitionData(geometry=self.sinogram_geometry,
+                               dimension_labels=self.output_axes_order)
+        sinogram_id, DATA.array = astra.create_sino3d_gpu(IM.as_array(), 
+                                                           self.proj_geom,
+                                                           self.vol_geom)
+        astra.data3d.delete(sinogram_id)
+        # 3D CUDA FP does not need scaling
+        return DATA
\ No newline at end of file
diff --git a/Wrappers/Python/ccpi/astra/processors/AstraForwardProjectorMC.py b/Wrappers/Python/ccpi/astra/processors/AstraForwardProjectorMC.py
new file mode 100644
index 0000000..5a697ca
--- /dev/null
+++ b/Wrappers/Python/ccpi/astra/processors/AstraForwardProjectorMC.py
@@ -0,0 +1,42 @@
+from ccpi.framework import DataProcessor, ImageData, AcquisitionData
+from ccpi.astra.utils import convert_geometry_to_astra
+
+from ccpi.astra.processors import AstraForwardProjector
+
+import astra
+
+class AstraForwardProjectorMC(AstraForwardProjector):
+    '''AstraForwardProjector Multi channel
+    
+    Forward project ImageData to AcquisitionDataSet using ASTRA proj_id.
+    
+    Input: ImageDataSet
+    Parameter: proj_id
+    Output: AcquisitionData
+    '''
+    def check_input(self, dataset):
+        if dataset.number_of_dimensions == 2 or \
+           dataset.number_of_dimensions == 3 or \
+           dataset.number_of_dimensions == 4:
+               return True
+        else:
+            raise ValueError("Expected input dimensions is 2 or 3, got {0}"\
+                             .format(dataset.number_of_dimensions))
+    def process(self):
+        IM = self.get_input()
+        #create the output AcquisitionData
+        DATA = AcquisitionData(geometry=self.sinogram_geometry)
+        
+        for k in range(DATA.geometry.channels):
+            sinogram_id, DATA.as_array()[k] = astra.create_sino(IM.as_array()[k], 
+                                                           self.proj_id)
+            astra.data2d.delete(sinogram_id)
+        
+        if self.device == 'cpu':
+            return DATA
+        else:
+            if self.sinogram_geometry.geom_type == 'cone':
+                return DATA
+            else:
+                 scaling = (1.0/self.volume_geometry.voxel_size_x) 
+                 return scaling*DATA
\ No newline at end of file
diff --git a/Wrappers/Python/ccpi/astra/processors/__init__.py b/Wrappers/Python/ccpi/astra/processors/__init__.py
new file mode 100644
index 0000000..6bfd7f5
--- /dev/null
+++ b/Wrappers/Python/ccpi/astra/processors/__init__.py
@@ -0,0 +1,7 @@
+
+from .AstraForwardProjector import AstraForwardProjector
+from .AstraBackProjector import AstraBackProjector
+from .AstraForwardProjectorMC import AstraForwardProjectorMC
+from .AstraBackProjectorMC import AstraBackProjectorMC
+from .AstraForwardProjector3D import AstraForwardProjector3D
+from .AstraBackProjector3D import AstraBackProjector3D
diff --git a/Wrappers/Python/ccpi/astra/utils.py b/Wrappers/Python/ccpi/astra/utils.py
deleted file mode 100755
index 2b19305..0000000
--- a/Wrappers/Python/ccpi/astra/utils.py
+++ /dev/null
@@ -1,62 +0,0 @@
-import astra
-import numpy as np
-
-def convert_geometry_to_astra(volume_geometry, sinogram_geometry):
-    # Set up ASTRA Volume and projection geometry, not stored
-    if sinogram_geometry.dimension == '2D':
-        vol_geom = astra.create_vol_geom(volume_geometry.voxel_num_x, 
-                                         volume_geometry.voxel_num_y, 
-                                         volume_geometry.get_min_x(), 
-                                         volume_geometry.get_max_x(), 
-                                         volume_geometry.get_min_y(), 
-                                         volume_geometry.get_max_y())
-        
-        if sinogram_geometry.geom_type == 'parallel':
-            proj_geom = astra.create_proj_geom('parallel',
-                                               sinogram_geometry.pixel_size_h,
-                                               sinogram_geometry.pixel_num_h,
-                                               sinogram_geometry.angles)
-        elif sinogram_geometry.geom_type == 'cone':
-            proj_geom = astra.create_proj_geom('fanflat',
-                                               sinogram_geometry.pixel_size_h,
-                                               sinogram_geometry.pixel_num_h,
-                                               sinogram_geometry.angles,
-                                               np.abs(sinogram_geometry.dist_source_center),
-                                               np.abs(sinogram_geometry.dist_center_detector))
-        else:
-            NotImplemented
-            
-    elif sinogram_geometry.dimension == '3D':
-        vol_geom = astra.create_vol_geom(volume_geometry.voxel_num_x, 
-                                         volume_geometry.voxel_num_y, 
-                                         volume_geometry.voxel_num_z, 
-                                         volume_geometry.get_min_x(), 
-                                         volume_geometry.get_max_x(), 
-                                         volume_geometry.get_min_y(), 
-                                         volume_geometry.get_max_y(), 
-                                         volume_geometry.get_min_z(), 
-                                         volume_geometry.get_max_z())
-        
-        if sinogram_geometry.geom_type == 'parallel':
-            proj_geom = astra.create_proj_geom('parallel3d',
-                                               sinogram_geometry.pixel_size_h,
-                                               sinogram_geometry.pixel_size_v,
-                                               sinogram_geometry.pixel_num_v,
-                                               sinogram_geometry.pixel_num_h,
-                                               sinogram_geometry.angles)
-        elif sinogram_geometry.geom_type == 'cone':
-            proj_geom = astra.create_proj_geom('cone',
-                                               sinogram_geometry.pixel_size_h,
-                                               sinogram_geometry.pixel_size_v,
-                                               sinogram_geometry.pixel_num_v,
-                                               sinogram_geometry.pixel_num_h,
-                                               sinogram_geometry.angles,
-                                               np.abs(sinogram_geometry.dist_source_center),
-                                               np.abs(sinogram_geometry.dist_center_detector))
-        else:
-            NotImplemented
-            
-    else:
-        NotImplemented
-    
-    return vol_geom, proj_geom
\ No newline at end of file
diff --git a/Wrappers/Python/ccpi/astra/utils/__init__.py b/Wrappers/Python/ccpi/astra/utils/__init__.py
new file mode 100644
index 0000000..c740fba
--- /dev/null
+++ b/Wrappers/Python/ccpi/astra/utils/__init__.py
@@ -0,0 +1,2 @@
+
+from .convert_geometry_to_astra import convert_geometry_to_astra
\ No newline at end of file
diff --git a/Wrappers/Python/ccpi/astra/utils/convert_geometry_to_astra.py b/Wrappers/Python/ccpi/astra/utils/convert_geometry_to_astra.py
new file mode 100644
index 0000000..2b19305
--- /dev/null
+++ b/Wrappers/Python/ccpi/astra/utils/convert_geometry_to_astra.py
@@ -0,0 +1,62 @@
+import astra
+import numpy as np
+
+def convert_geometry_to_astra(volume_geometry, sinogram_geometry):
+    # Set up ASTRA Volume and projection geometry, not stored
+    if sinogram_geometry.dimension == '2D':
+        vol_geom = astra.create_vol_geom(volume_geometry.voxel_num_x, 
+                                         volume_geometry.voxel_num_y, 
+                                         volume_geometry.get_min_x(), 
+                                         volume_geometry.get_max_x(), 
+                                         volume_geometry.get_min_y(), 
+                                         volume_geometry.get_max_y())
+        
+        if sinogram_geometry.geom_type == 'parallel':
+            proj_geom = astra.create_proj_geom('parallel',
+                                               sinogram_geometry.pixel_size_h,
+                                               sinogram_geometry.pixel_num_h,
+                                               sinogram_geometry.angles)
+        elif sinogram_geometry.geom_type == 'cone':
+            proj_geom = astra.create_proj_geom('fanflat',
+                                               sinogram_geometry.pixel_size_h,
+                                               sinogram_geometry.pixel_num_h,
+                                               sinogram_geometry.angles,
+                                               np.abs(sinogram_geometry.dist_source_center),
+                                               np.abs(sinogram_geometry.dist_center_detector))
+        else:
+            NotImplemented
+            
+    elif sinogram_geometry.dimension == '3D':
+        vol_geom = astra.create_vol_geom(volume_geometry.voxel_num_x, 
+                                         volume_geometry.voxel_num_y, 
+                                         volume_geometry.voxel_num_z, 
+                                         volume_geometry.get_min_x(), 
+                                         volume_geometry.get_max_x(), 
+                                         volume_geometry.get_min_y(), 
+                                         volume_geometry.get_max_y(), 
+                                         volume_geometry.get_min_z(), 
+                                         volume_geometry.get_max_z())
+        
+        if sinogram_geometry.geom_type == 'parallel':
+            proj_geom = astra.create_proj_geom('parallel3d',
+                                               sinogram_geometry.pixel_size_h,
+                                               sinogram_geometry.pixel_size_v,
+                                               sinogram_geometry.pixel_num_v,
+                                               sinogram_geometry.pixel_num_h,
+                                               sinogram_geometry.angles)
+        elif sinogram_geometry.geom_type == 'cone':
+            proj_geom = astra.create_proj_geom('cone',
+                                               sinogram_geometry.pixel_size_h,
+                                               sinogram_geometry.pixel_size_v,
+                                               sinogram_geometry.pixel_num_v,
+                                               sinogram_geometry.pixel_num_h,
+                                               sinogram_geometry.angles,
+                                               np.abs(sinogram_geometry.dist_source_center),
+                                               np.abs(sinogram_geometry.dist_center_detector))
+        else:
+            NotImplemented
+            
+    else:
+        NotImplemented
+    
+    return vol_geom, proj_geom
\ No newline at end of file
diff --git a/Wrappers/Python/setup.py b/Wrappers/Python/setup.py
index 85dde19..e854dee 100755
--- a/Wrappers/Python/setup.py
+++ b/Wrappers/Python/setup.py
@@ -32,7 +32,11 @@ cil_version='0.12.0'
 setup(
     name="ccpi-astra",
     version=cil_version,
-    packages=['ccpi' , 'ccpi.astra'],
+    packages=['ccpi' , 
+              'ccpi.astra',
+              'ccpi.astra.operators',
+              'ccpi.astra.processors',
+              'ccpi.astra.utils'],
 
     # Project uses reStructuredText, so ensure that the docutils get
     # installed or upgraded on the target machine
diff --git a/Wrappers/Python/wip/demo_astra_mc.py b/Wrappers/Python/wip/demo_astra_mc.py
index f09dcb8..e5999de 100755
--- a/Wrappers/Python/wip/demo_astra_mc.py
+++ b/Wrappers/Python/wip/demo_astra_mc.py
@@ -8,7 +8,7 @@
 from ccpi.framework import ImageData, AcquisitionData, ImageGeometry, AcquisitionGeometry
 from ccpi.optimisation.algs import FISTA
 from ccpi.optimisation.funcs import Norm2sq, Norm1
-from ccpi.astra.ops import AstraProjectorMC
+from ccpi.astra.operators import AstraProjectorMC
 
 import numpy
 import matplotlib.pyplot as plt
diff --git a/Wrappers/Python/wip/demo_astra_nexus.py b/Wrappers/Python/wip/demo_astra_nexus.py
index 1db44c0..7892d24 100644
--- a/Wrappers/Python/wip/demo_astra_nexus.py
+++ b/Wrappers/Python/wip/demo_astra_nexus.py
@@ -15,7 +15,7 @@ from ccpi.plugins.ops import CCPiProjectorSimple
 from ccpi.processors import Normalizer, CenterOfRotationFinder 
 from ccpi.plugins.processors import AcquisitionDataPadder
 from ccpi.io.reader import NexusReader
-from ccpi.astra.ops import AstraProjector3DSimple
+from ccpi.astra.operators import AstraProjector3DSimple
 
 # All external imports
 import numpy
diff --git a/Wrappers/Python/wip/demo_astra_simple.py b/Wrappers/Python/wip/demo_astra_simple.py
index c1dd877..57caaee 100755
--- a/Wrappers/Python/wip/demo_astra_simple.py
+++ b/Wrappers/Python/wip/demo_astra_simple.py
@@ -8,7 +8,7 @@
 from ccpi.framework import ImageData , ImageGeometry, AcquisitionGeometry
 from ccpi.optimisation.algs import FISTA, FBPD, CGLS
 from ccpi.optimisation.funcs import Norm2sq, Norm1, TV2D
-from ccpi.astra.ops import AstraProjectorSimple
+from ccpi.astra.operators import AstraProjectorSimple
 
 import numpy as np
 import matplotlib.pyplot as plt
diff --git a/Wrappers/Python/wip/demo_astra_sophiabeads.py b/Wrappers/Python/wip/demo_astra_sophiabeads.py
index bcc775e..b72a5f9 100755
--- a/Wrappers/Python/wip/demo_astra_sophiabeads.py
+++ b/Wrappers/Python/wip/demo_astra_sophiabeads.py
@@ -11,7 +11,7 @@ from ccpi.io.reader import XTEKReader
 import numpy as np
 import matplotlib.pyplot as plt
 from ccpi.framework import ImageGeometry, AcquisitionGeometry, AcquisitionData, ImageData
-from ccpi.astra.ops import AstraProjectorSimple
+from ccpi.astra.operators import AstraProjectorSimple
 from ccpi.optimisation.algs import CGLS
 
 # Set up reader object and read the data
diff --git a/Wrappers/Python/wip/demo_astra_sophiabeads3D.py b/Wrappers/Python/wip/demo_astra_sophiabeads3D.py
index edfe1b9..8c43657 100644
--- a/Wrappers/Python/wip/demo_astra_sophiabeads3D.py
+++ b/Wrappers/Python/wip/demo_astra_sophiabeads3D.py
@@ -11,7 +11,7 @@ from ccpi.io.reader import XTEKReader
 import numpy as np
 import matplotlib.pyplot as plt
 from ccpi.framework import ImageGeometry, AcquisitionData, ImageData
-from ccpi.astra.ops import AstraProjector3DSimple
+from ccpi.astra.operators import AstraProjector3DSimple
 from ccpi.optimisation.algs import CGLS
 
 import numpy
diff --git a/Wrappers/Python/wip/work_out_adjoint.py b/Wrappers/Python/wip/work_out_adjoint.py
index 34d58ff..276fb76 100644
--- a/Wrappers/Python/wip/work_out_adjoint.py
+++ b/Wrappers/Python/wip/work_out_adjoint.py
@@ -8,7 +8,7 @@
 from ccpi.framework import ImageData , ImageGeometry, AcquisitionGeometry, AcquisitionData
 from ccpi.optimisation.algs import FISTA, FBPD, CGLS
 from ccpi.optimisation.funcs import Norm2sq, Norm1, TV2D
-from ccpi.astra.ops import AstraProjectorSimple
+from ccpi.astra.operators import AstraProjectorSimple
 
 import numpy as np
 import matplotlib.pyplot as plt
diff --git a/Wrappers/Python/wip/work_out_adjoint3D.py b/Wrappers/Python/wip/work_out_adjoint3D.py
index 162e55a..0e4f847 100644
--- a/Wrappers/Python/wip/work_out_adjoint3D.py
+++ b/Wrappers/Python/wip/work_out_adjoint3D.py
@@ -8,7 +8,7 @@
 from ccpi.framework import ImageData , ImageGeometry, AcquisitionGeometry, AcquisitionData
 from ccpi.optimisation.algs import FISTA, FBPD, CGLS
 from ccpi.optimisation.funcs import Norm2sq, Norm1, TV2D
-from ccpi.astra.ops import AstraProjector3DSimple
+from ccpi.astra.operators import AstraProjector3DSimple
 
 import numpy as np
 import matplotlib.pyplot as plt
diff --git a/Wrappers/Python/wip/work_out_adjoint_sophiabeads.py b/Wrappers/Python/wip/work_out_adjoint_sophiabeads.py
index 2492826..7f35a16 100644
--- a/Wrappers/Python/wip/work_out_adjoint_sophiabeads.py
+++ b/Wrappers/Python/wip/work_out_adjoint_sophiabeads.py
@@ -8,7 +8,7 @@
 from ccpi.framework import ImageData , ImageGeometry, AcquisitionGeometry, AcquisitionData
 from ccpi.optimisation.algs import FISTA, FBPD, CGLS
 from ccpi.optimisation.funcs import Norm2sq, Norm1, TV2D
-from ccpi.astra.ops import AstraProjectorSimple
+from ccpi.astra.operators import AstraProjectorSimple
 
 import numpy as np
 import matplotlib.pyplot as plt
-- 
cgit v1.2.3


From 493d4fe58d74c8027213ec1f409bc853d90a3282 Mon Sep 17 00:00:00 2001
From: "Jakob Jorgensen, WS at HMXIF" <jakob.jorgensen@manchester.ac.uk>
Date: Fri, 26 Apr 2019 16:50:39 +0100
Subject: Add/remove new/old methods in operators

---
 .../ccpi/astra/operators/AstraProjector3DSimple.py | 26 +++++---------
 .../ccpi/astra/operators/AstraProjectorMC.py       | 41 +---------------------
 .../ccpi/astra/operators/AstraProjectorSimple.py   |  1 -
 3 files changed, 10 insertions(+), 58 deletions(-)

(limited to 'Wrappers/Python')

diff --git a/Wrappers/Python/ccpi/astra/operators/AstraProjector3DSimple.py b/Wrappers/Python/ccpi/astra/operators/AstraProjector3DSimple.py
index 3240ee4..606bce6 100644
--- a/Wrappers/Python/ccpi/astra/operators/AstraProjector3DSimple.py
+++ b/Wrappers/Python/ccpi/astra/operators/AstraProjector3DSimple.py
@@ -16,7 +16,6 @@
 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 from ccpi.optimisation.operators import Operator, LinearOperator
-import numpy
 from ccpi.framework import AcquisitionData, ImageData, DataContainer
 from ccpi.optimisation.ops import PowerMethodNonsquare
 from ccpi.astra.processors import AstraForwardProjector, AstraBackProjector, \
@@ -52,24 +51,17 @@ class AstraProjector3DSimple(LinearOperator):
         out = self.bp.get_output()
         return out
     
-    #def delete(self):
-    #    astra.data2d.delete(self.proj_id)
-    
     def get_max_sing_val(self):
         self.s1, sall, svec = PowerMethodNonsquare(self,10)
         return self.s1
     
-    def size(self):
-        # Only implemented for 2D
-        return ( (self.sinogram_geometry.angles.size, \
-                  self.sinogram_geometry.pixel_num_h, \
-                  self.sinogram_geometry.pixel_num_v,), \
-                 (self.volume_geometry.voxel_num_x, \
-                  self.volume_geometry.voxel_num_y, \
-                  self.volume_geometry.voxel_num_z) )
+    def domain_geometry(self):
+        return self.volume_geometry
+    
+    def range_geometry(self):
+        return self.sinogram_geometry  
     
-    def create_image_data(self):
-        inputsize = self.size()[1]
-        return DataContainer(numpy.random.randn(inputsize[2],
-                                                inputsize[1],
-                                                inputsize[0]))
\ No newline at end of file
+    def norm(self):
+        x0 = self.volume_geometry.allocate('random')
+        self.s1, sall, svec = PowerMethodNonsquare(self, 50, x0)
+        return self.s1
\ No newline at end of file
diff --git a/Wrappers/Python/ccpi/astra/operators/AstraProjectorMC.py b/Wrappers/Python/ccpi/astra/operators/AstraProjectorMC.py
index 51f51ca..a6993ba 100644
--- a/Wrappers/Python/ccpi/astra/operators/AstraProjectorMC.py
+++ b/Wrappers/Python/ccpi/astra/operators/AstraProjectorMC.py
@@ -42,18 +42,7 @@ class AstraProjectorMC(LinearOperator):
                                         device=device)
                 
         # Initialise empty for singular value.
-        self.s1 = None
-    
-#    def direct(self, IM):
-#        self.fp.set_input(IM)
-#        out = self.fp.get_output()
-#        return out
-#    
-#    def adjoint(self, DATA):
-#        self.bp.set_input(DATA)
-#        out = self.bp.get_output()
-#        return out
-    
+        self.s1 = None    
     
     def direct(self, IM, out=None):
         self.fp.set_input(IM)
@@ -71,33 +60,6 @@ class AstraProjectorMC(LinearOperator):
         else:
             out.fill(self.bp.get_output())    
     
-    #def delete(self):
-    #    astra.data2d.delete(self.proj_id)
-    
-#    def get_max_sing_val(self):
-#        if self.s1 is None:
-#            self.s1, sall, svec = PowerMethodNonsquare(self,10)
-#            return self.s1
-#        else:
-#            return self.s1
-#    
-#    def size(self):
-#        # Only implemented for 2D
-#        return ( (self.sinogram_geometry.angles.size, \
-#                  self.sinogram_geometry.pixel_num_h), \
-#                 (self.volume_geometry.voxel_num_x, \
-#                  self.volume_geometry.voxel_num_y) )
-#    
-#    def create_image_data(self):
-#        inputsize = self.size()[1]
-#        return DataContainer(numpy.random.randn(self.volume_geometry.channels,
-#                                                inputsize[0],
-#                                                inputsize[1]))
-        
-#    def allocate_direct(self):
-#        return self.create_image_data()def domain_geometry(self):
-#        return self.volume_geometry
-    
     def domain_geometry(self):
         return self.volume_geometry
     
@@ -105,7 +67,6 @@ class AstraProjectorMC(LinearOperator):
         return self.sinogram_geometry    
     
     def norm(self):
-
         x0 = self.volume_geometry.allocate('random')
         self.s1, sall, svec = PowerMethodNonsquare(self, 50, x0)
         return self.s1
diff --git a/Wrappers/Python/ccpi/astra/operators/AstraProjectorSimple.py b/Wrappers/Python/ccpi/astra/operators/AstraProjectorSimple.py
index b459e82..71bc3c6 100644
--- a/Wrappers/Python/ccpi/astra/operators/AstraProjectorSimple.py
+++ b/Wrappers/Python/ccpi/astra/operators/AstraProjectorSimple.py
@@ -65,7 +65,6 @@ class AstraProjectorSimple(LinearOperator):
         return self.sinogram_geometry    
     
     def norm(self):
-
         x0 = self.volume_geometry.allocate('random')
         self.s1, sall, svec = PowerMethodNonsquare(self, 50, x0)
         return self.s1
\ No newline at end of file
-- 
cgit v1.2.3


From 3dd7810b24962999c1a80c72e1dfa411543e4c52 Mon Sep 17 00:00:00 2001
From: "Jakob Jorgensen, WS at HMXIF" <jakob.jorgensen@manchester.ac.uk>
Date: Fri, 26 Apr 2019 17:06:35 +0100
Subject: Add out argument in dataprocessor process method

---
 .../Python/ccpi/astra/processors/AstraBackProjector.py  | 12 ++++++++----
 .../ccpi/astra/processors/AstraBackProjector3D.py       |  9 +++++++--
 .../ccpi/astra/processors/AstraBackProjectorMC.py       | 12 +++++++++---
 .../ccpi/astra/processors/AstraForwardProjector.py      | 17 ++++++++++-------
 .../ccpi/astra/processors/AstraForwardProjector3D.py    | 11 ++++++-----
 .../ccpi/astra/processors/AstraForwardProjectorMC.py    | 14 ++++++++++----
 6 files changed, 50 insertions(+), 25 deletions(-)

(limited to 'Wrappers/Python')

diff --git a/Wrappers/Python/ccpi/astra/processors/AstraBackProjector.py b/Wrappers/Python/ccpi/astra/processors/AstraBackProjector.py
index 476523a..d094e79 100644
--- a/Wrappers/Python/ccpi/astra/processors/AstraBackProjector.py
+++ b/Wrappers/Python/ccpi/astra/processors/AstraBackProjector.py
@@ -65,7 +65,7 @@ class AstraBackProjector(DataProcessor):
     def set_AcquisitionGeometry(self, sinogram_geometry):
         self.sinogram_geometry = sinogram_geometry
     
-    def process(self):
+    def process(self, out=None):
         DATA = self.get_input()
         IM = ImageData(geometry=self.volume_geometry)
         rec_id, IM.array = astra.create_backprojection(DATA.as_array(),
@@ -73,8 +73,12 @@ class AstraBackProjector(DataProcessor):
         astra.data2d.delete(rec_id)
         
         if self.device == 'cpu':
-            return IM
+            ret = IM
         else:
             scaling = self.volume_geometry.voxel_size_x**3  
-            return scaling*IM
-        
\ No newline at end of file
+            ret = scaling*IM
+        
+        if out is None:
+            return ret
+        else:
+            out.fill(ret)
\ No newline at end of file
diff --git a/Wrappers/Python/ccpi/astra/processors/AstraBackProjector3D.py b/Wrappers/Python/ccpi/astra/processors/AstraBackProjector3D.py
index b1d139e..26a549a 100644
--- a/Wrappers/Python/ccpi/astra/processors/AstraBackProjector3D.py
+++ b/Wrappers/Python/ccpi/astra/processors/AstraBackProjector3D.py
@@ -53,7 +53,7 @@ class AstraBackProjector3D(DataProcessor):
     def set_AcquisitionGeometry(self, sinogram_geometry):
         self.sinogram_geometry = sinogram_geometry
     
-    def process(self):
+    def process(self, out=None):
         DATA = self.get_input()
         IM = ImageData(geometry=self.volume_geometry,
                        dimension_labels=self.output_axes_order)
@@ -64,4 +64,9 @@ class AstraBackProjector3D(DataProcessor):
         
         # Scaling of 3D ASTRA backprojector, works both parallel and cone.
         scaling = 1/self.volume_geometry.voxel_size_x**2  
-        return scaling*IM
+        ret = scaling*IM
+        
+        if out is None:
+            return ret
+        else:
+            out.fill(ret)
diff --git a/Wrappers/Python/ccpi/astra/processors/AstraBackProjectorMC.py b/Wrappers/Python/ccpi/astra/processors/AstraBackProjectorMC.py
index d48fb80..84932b6 100644
--- a/Wrappers/Python/ccpi/astra/processors/AstraBackProjectorMC.py
+++ b/Wrappers/Python/ccpi/astra/processors/AstraBackProjectorMC.py
@@ -22,7 +22,8 @@ class AstraBackProjectorMC(AstraBackProjector):
         else:
             raise ValueError("Expected input dimensions is 2 or 3, got {0}"\
                              .format(dataset.number_of_dimensions))
-    def process(self):
+    
+    def process(self, out):
         DATA = self.get_input()
         
         IM = ImageData(geometry=self.volume_geometry)
@@ -34,7 +35,12 @@ class AstraBackProjectorMC(AstraBackProjector):
             astra.data2d.delete(rec_id)
         
         if self.device == 'cpu':
-            return IM
+            ret = IM
         else:
             scaling = self.volume_geometry.voxel_size_x**3  
-            return scaling*IM
\ No newline at end of file
+            ret = scaling*IM
+        
+        if out is None:
+            return ret
+        else:
+            out.fill(ret)
\ No newline at end of file
diff --git a/Wrappers/Python/ccpi/astra/processors/AstraForwardProjector.py b/Wrappers/Python/ccpi/astra/processors/AstraForwardProjector.py
index dd5bab4..2cf5716 100644
--- a/Wrappers/Python/ccpi/astra/processors/AstraForwardProjector.py
+++ b/Wrappers/Python/ccpi/astra/processors/AstraForwardProjector.py
@@ -65,21 +65,24 @@ class AstraForwardProjector(DataProcessor):
     
     def set_AcquisitionGeometry(self, sinogram_geometry):
         self.sinogram_geometry = sinogram_geometry
-    
-    def process(self):
+        
+    def process(self, out=None):
         IM = self.get_input()
         DATA = AcquisitionData(geometry=self.sinogram_geometry)
-        #sinogram_id, DATA = astra.create_sino( IM.as_array(), 
-        #                           self.proj_id)
         sinogram_id, DATA.array = astra.create_sino(IM.as_array(), 
                                                            self.proj_id)
         astra.data2d.delete(sinogram_id)
         
         if self.device == 'cpu':
-            return DATA
+            ret = DATA
         else:
             if self.sinogram_geometry.geom_type == 'cone':
-                return DATA
+                ret = DATA
             else:
                  scaling = 1.0/self.volume_geometry.voxel_size_x
-                 return scaling*DATA
\ No newline at end of file
+                 ret = scaling*DATA
+        
+        if out is None:
+            return ret
+        else:
+            out.fill(ret)
\ No newline at end of file
diff --git a/Wrappers/Python/ccpi/astra/processors/AstraForwardProjector3D.py b/Wrappers/Python/ccpi/astra/processors/AstraForwardProjector3D.py
index d18b43e..18b4078 100644
--- a/Wrappers/Python/ccpi/astra/processors/AstraForwardProjector3D.py
+++ b/Wrappers/Python/ccpi/astra/processors/AstraForwardProjector3D.py
@@ -57,10 +57,7 @@ class AstraForwardProjector3D(DataProcessor):
     def set_vol_geom(self, vol_geom):
         self.vol_geom = vol_geom
     
-    def set_AcquisitionGeometry(self, sinogram_geometry):
-        self.sinogram_geometry = sinogram_geometry
-    
-    def process(self):
+    def process(self, out=None):
         IM = self.get_input()
         DATA = AcquisitionData(geometry=self.sinogram_geometry,
                                dimension_labels=self.output_axes_order)
@@ -69,4 +66,8 @@ class AstraForwardProjector3D(DataProcessor):
                                                            self.vol_geom)
         astra.data3d.delete(sinogram_id)
         # 3D CUDA FP does not need scaling
-        return DATA
\ No newline at end of file
+        
+        if out is None:
+            return DATA
+        else:
+            out.fill(DATA)
\ No newline at end of file
diff --git a/Wrappers/Python/ccpi/astra/processors/AstraForwardProjectorMC.py b/Wrappers/Python/ccpi/astra/processors/AstraForwardProjectorMC.py
index 5a697ca..34f4222 100644
--- a/Wrappers/Python/ccpi/astra/processors/AstraForwardProjectorMC.py
+++ b/Wrappers/Python/ccpi/astra/processors/AstraForwardProjectorMC.py
@@ -22,7 +22,8 @@ class AstraForwardProjectorMC(AstraForwardProjector):
         else:
             raise ValueError("Expected input dimensions is 2 or 3, got {0}"\
                              .format(dataset.number_of_dimensions))
-    def process(self):
+    
+    def process(self, out=None):
         IM = self.get_input()
         #create the output AcquisitionData
         DATA = AcquisitionData(geometry=self.sinogram_geometry)
@@ -33,10 +34,15 @@ class AstraForwardProjectorMC(AstraForwardProjector):
             astra.data2d.delete(sinogram_id)
         
         if self.device == 'cpu':
-            return DATA
+            ret = DATA
         else:
             if self.sinogram_geometry.geom_type == 'cone':
-                return DATA
+                ret = DATA
             else:
                  scaling = (1.0/self.volume_geometry.voxel_size_x) 
-                 return scaling*DATA
\ No newline at end of file
+                 ret = scaling*DATA
+        
+        if out is None:
+            return ret
+        else:
+            out.fill(ret)
\ No newline at end of file
-- 
cgit v1.2.3


From 590a1178f8eaef600541e9a8a6a863b07afca806 Mon Sep 17 00:00:00 2001
From: "Jakob Jorgensen, WS at HMXIF" <jakob.jorgensen@manchester.ac.uk>
Date: Fri, 26 Apr 2019 17:12:11 +0100
Subject: Add out in 3D projector

---
 .../ccpi/astra/operators/AstraProjector3DSimple.py | 22 ++++++++++++----------
 .../ccpi/astra/operators/AstraProjectorMC.py       |  3 +--
 2 files changed, 13 insertions(+), 12 deletions(-)

(limited to 'Wrappers/Python')

diff --git a/Wrappers/Python/ccpi/astra/operators/AstraProjector3DSimple.py b/Wrappers/Python/ccpi/astra/operators/AstraProjector3DSimple.py
index 606bce6..8058cdc 100644
--- a/Wrappers/Python/ccpi/astra/operators/AstraProjector3DSimple.py
+++ b/Wrappers/Python/ccpi/astra/operators/AstraProjector3DSimple.py
@@ -41,19 +41,21 @@ class AstraProjector3DSimple(LinearOperator):
         # Initialise empty for singular value.
         self.s1 = None
     
-    def direct(self, IM):
+    def direct(self, IM, out=None):
         self.fp.set_input(IM)
-        out = self.fp.get_output()
-        return out
+        
+        if out is None:
+            return self.fp.get_output()
+        else:
+            out.fill(self.fp.get_output())
     
-    def adjoint(self, DATA):
+    def adjoint(self, DATA, out=None):
         self.bp.set_input(DATA)
-        out = self.bp.get_output()
-        return out
-    
-    def get_max_sing_val(self):
-        self.s1, sall, svec = PowerMethodNonsquare(self,10)
-        return self.s1
+        
+        if out is None:
+            return self.bp.get_output()
+        else:
+            out.fill(self.bp.get_output())    
     
     def domain_geometry(self):
         return self.volume_geometry
diff --git a/Wrappers/Python/ccpi/astra/operators/AstraProjectorMC.py b/Wrappers/Python/ccpi/astra/operators/AstraProjectorMC.py
index a6993ba..f796a63 100644
--- a/Wrappers/Python/ccpi/astra/operators/AstraProjectorMC.py
+++ b/Wrappers/Python/ccpi/astra/operators/AstraProjectorMC.py
@@ -69,5 +69,4 @@ class AstraProjectorMC(LinearOperator):
     def norm(self):
         x0 = self.volume_geometry.allocate('random')
         self.s1, sall, svec = PowerMethodNonsquare(self, 50, x0)
-        return self.s1
-    
\ No newline at end of file
+        return self.s1
\ No newline at end of file
-- 
cgit v1.2.3


From d6b38d0e635db69f46b603525d746620a47f0528 Mon Sep 17 00:00:00 2001
From: Edoardo Pasca <edo.paskino@gmail.com>
Date: Tue, 30 Apr 2019 16:22:29 +0100
Subject: add default value to out

---
 Wrappers/Python/ccpi/astra/processors/AstraBackProjectorMC.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'Wrappers/Python')

diff --git a/Wrappers/Python/ccpi/astra/processors/AstraBackProjectorMC.py b/Wrappers/Python/ccpi/astra/processors/AstraBackProjectorMC.py
index 84932b6..ef8fe5d 100644
--- a/Wrappers/Python/ccpi/astra/processors/AstraBackProjectorMC.py
+++ b/Wrappers/Python/ccpi/astra/processors/AstraBackProjectorMC.py
@@ -23,7 +23,7 @@ class AstraBackProjectorMC(AstraBackProjector):
             raise ValueError("Expected input dimensions is 2 or 3, got {0}"\
                              .format(dataset.number_of_dimensions))
     
-    def process(self, out):
+    def process(self, out=None):
         DATA = self.get_input()
         
         IM = ImageData(geometry=self.volume_geometry)
@@ -43,4 +43,4 @@ class AstraBackProjectorMC(AstraBackProjector):
         if out is None:
             return ret
         else:
-            out.fill(ret)
\ No newline at end of file
+            out.fill(ret)
-- 
cgit v1.2.3