TomographicImaging / CIL

A versatile python framework for tomographic imaging
https://tomographicimaging.github.io/CIL/
Apache License 2.0
98 stars 45 forks source link

CGLS/ProjectionOperator Stack Trace Doesn't Point To Correct Issue #1990

Open M-A-Demir opened 1 week ago

M-A-Demir commented 1 week ago

Description

When running the following code:

A = ProjectionOperator(ig, ag, device="GPU")
initial = ig.allocate(0)

cgls_simple = CGLS(initial=initial, operator=A, data=centred_data)

The stack trace shows:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[32], line 9
      5 print(A, initial, data_reord)
      8 # lsqr_simple = LSQR(initial=initial, operator=A, data=data_reord)
----> 9 cgls_simple = CGLS(initial=initial, operator=A, data=data_reord)

File ~/.conda/envs/cil/lib/python3.10/site-packages/cil/optimisation/algorithms/CGLS.py:72, in CGLS.__init__(self, initial, operator, data, **kwargs)
     70     initial = operator.domain_geometry().allocate(0)
     71 if initial is not None and operator is not None and data is not None:
---> 72     self.set_up(initial=initial, operator=operator, data=data)

File ~/.conda/envs/cil/lib/python3.10/site-packages/cil/optimisation/algorithms/CGLS.py:91, in CGLS.set_up(self, initial, operator, data)
     88 self.x = initial.copy()
     89 self.operator = operator
---> 91 self.r = data - self.operator.direct(self.x)
     92 self.s = self.operator.adjoint(self.r)
     94 self.p = self.s.copy()

File ~/.conda/envs/cil/lib/python3.10/site-packages/cil/plugins/astra/operators/ProjectionOperator.py:161, in ProjectionOperator_ag.direct(self, IM, out)
    144 def direct(self, IM, out=None):
    145     '''Applies the direct of the operator i.e. the forward projection.
    146 
    147     Parameters
   (...)
    158         The processed data. Suppressed if `out` is passed
    159     '''
--> 161     return self.operator.direct(IM, out=out)

File ~/.conda/envs/cil/lib/python3.10/site-packages/cil/plugins/astra/operators/AstraProjector2D.py:82, in AstraProjector2D.direct(self, x, out)
     66 '''Applies the direct of the operator i.e. the forward projection.
     67 
     68 Parameters
   (...)
     79     The processed data. Suppressed if `out` is passed
     80 '''
     81 self.fp.set_input(x)
---> 82 return self.fp.get_output(out = out)

File ~/.conda/envs/cil/lib/python3.10/site-packages/cil/framework/processors.py:119, in Processor.get_output(self, out)
    116     raise ValueError('Output data not compatible with processor')
    118 if self.output is None or self.shouldRun:
--> 119     out = self.process(out=out)
    120     if self.store_output:
    121         self.output = out.copy()

File ~/.conda/envs/cil/lib/python3.10/site-packages/cil/plugins/astra/processors/AstraForwardProjector2D.py:115, in AstraForwardProjector2D.process(self, out)
    111 new_shape_ig = [x if x>0 else 1 for x in new_shape_ig]
    113 IM_data_temp = IM.as_array().reshape(new_shape_ig)
--> 115 sinogram_id, arr_out = astra.create_sino(IM_data_temp, self.proj_id)
    116 astra.data2d.delete(sinogram_id)
    118 arr_out = np.squeeze(arr_out)

File ~/.conda/envs/cil/lib/python3.10/site-packages/astra/creators.py:385, in create_sino(data, proj_id, returnData, gpuIndex)
    367 def create_sino(data, proj_id, returnData=True, gpuIndex=None):
    368     """Create a forward projection of an image (2D).
    369 
    370     :param data: Image data or ID.
   (...)
    383     order.
    384 """
--> 385     proj_geom = projector.projection_geometry(proj_id)
    386     vol_geom = projector.volume_geometry(proj_id)
    388     if isinstance(data, np.ndarray):

File ~/.conda/envs/cil/lib/python3.10/site-packages/astra/projector.py:66, in projection_geometry(i)
     58 def projection_geometry(i):
     59     """Get projection geometry of a projector.
     60 
     61     :param i: ID of projector.
   (...)
     64 
     65     """
---> 66     return p.projection_geometry(i)

File astra/projector_c.pyx:97, in astra.projector_c.projection_geometry()

File astra/projector_c.pyx:88, in astra.projector_c.getObject()

TypeError: an integer is required

However, the actual reason the code fails is because of capitalising "GPU" when calling ProjectionOperator. The line should be A = ProjectionOperator(ig, ag, device="gpu"), but this is not clear from the stack trace.

Environment

import cil, sys
print(cil.version.version, cil.version.commit_hash, sys.version, sys.platform)

Output: 24.2.1.dev1+g83894302 g83894302 3.10.15 | packaged by conda-forge | (main, Sep 30 2024, 17:51:04) [GCC 13.3.0] linux

MargaretDuff commented 1 week ago

Thanks Mariam! Perhaps when we set up the Projection operator, it should check if the string passed to the device argument is one of a set of allowed strings and then print a suitable error message if not.