Using your own source/detector coordinates or list-mode data ============================================================ This page gives some tips on how to reconstruct data that cannot be reconstructed through built-in methods. This can be a different modality, non-cylindrical PET scanner, list-mode PET data or something else. There are no restrictions on the geometry, but the reconstruction process is not optimized. This means that speed will most likely be impacted and the quality may not be the best possible. However, it should be possible to reconstruct data from any geometry and even any modality as long as it can be reconstructed through ray-tracing means. In this case ray-tracing refers to the computation of the intersection length of a ray in a single voxel/pixel. One thing to note is that by default OMEGA computes everything in emission tomography way. What this means, is that the intersection length is converted into probability. To avoid this, use ``options.CT = true`` (or ``options.CT = True`` in Python). This should be put before any reconstructions or before constructing the class object to compute your own algorithms. The origin is always assumed to be in the center. You can move it with the variables ``options.oOffsetX``, ``options.oOffsetY`` and ``options.oOffsetZ``. Normally OMEGA loads all measurement and coordinate variables to the device (e.g. GPU). However, with list-mode data or custom coordinates, this can take a lot of device memory and lead to out-of-memory errors. To circumvent this, set ``options.loadTOF = false`` and use subsets. This sends only the data needed for the current subset to the device. This will lead to slower reconstruction though, but can prevent out-of-memory errors. There are two ways to perform reconstructions with custom hardware or list-mode data: index-based reconstruction and coordinate-based reconstruction. For the choice of algorithm, PDHG is recommended. Index-based reconstruction -------------------------- Index-based reconstruction is suitable for symmetric systems. It requires two index-vectors ``options.trIndex`` and ``options.axIndex``, as well as coordinate vectors ``options.x`` and ``options.z``. trIndex contains the transaxial, in this case x and y, indices that correspond to the coordinates in ``options.x``. The indices have to be in pairs, i.e. two indices are required for source-detector or detector-detector pairs. axIndex is the same, but for axial, i.e. z, coordinates. The indices also have to be zero-based! Each index pair must correspond to a measurement in ``options.SinM``. An example: You have 5 measurements, and two unique coordinates. In such case, for example, ``options.trIndex = [0 2 0 3 1 2 1 3 1 3]`` would point to the coordinates in the corresponding index. If ``options.x = [1.5 3 1 2]`` and the first two elements are x-coordinates and the next y-coordinates, Thus 0 in trIndex would point to 1.5 in x, 2 to 1, and so on. Note that the order in ``options.x`` doesn't matter, but ``options.trIndex`` has to both the x and y indices next to each other in memory. OMEGA also uses column-major ordering and thus in Python you should use Fortran-ordered arrays or simply vectors. ``Inveon_PET_main_listmode_example`` contains a list-mode example of index-based reconstruction, but it is suitable for other types of data as well. Since index-based reconstruction has both the index vectors and coordinate vectors, it is suitable only when the coordinate vectors are small. The index-vectors are 16-bit unsigned integers and thus can have a value of 65535 at most, but use less memory than the pure coordinate-based reconstruction showcased below. Note that ``options.trIndex`` and ``options.axIndex`` should have twice the number of elements than in ``options.SinM``, due to the pair nature of indices. In general, the indices are used to point to specific coordinates at each measurement. The order of the measurements and indices has to be the same. For example the indices 0 and 2, should refer to the coordinates of the first measurement, 0 and 3 to the second measurement and so on. Here is also the same text as in the list-mode example: If true, requires ``options.trIndex`` and ``options.axIndex`` variables. These should include the transaxial and axial, respectively, detector coordinate indices. Two indices are required per measurement, i.e. source-detector or detector-detector pairs. The indexing has to be zero-based! The transaxial coordinates should be stored in ``options.x`` and axial coordinates in ``options.z``. The indices should correspond to the coordinates in each. Note that ``options.x`` should have both the x- and y-coordinates while ``options.z`` should have only the z-coordinates. You can also include randoms by inputting them as negative measurements. The indices are used in the same order as measurements. Coordinate-based reconstruction ------------------------------- This method is simpler than the index-based one, but can consume more memory. Coordinate-based method also works with any type of geometry. You need to put the x-, y- and z-coordinates into ``options.x``, first for source or detector 1 and then for detector or detector 2, i.e. a total of six coordinates for one measurement. The order should be x, y and z or y, x, and z. The number of elements in ``options.x`` has to be six times that of ``options.SinM``, which has to contain the measurements. The order in ``options.x`` should thus be: [source1X, source1Y, source1Z, detector1X, detector1Y, detector1Z, source2X, source2Y, source2Z, detector2X, detector2Y, detector2Z, source3X, ...], where the number refers to the index in ``options.SinM``, i.e. the measurement number. Source can also be another detector in PET cases. Since OMEGA is column-major, in Python you should use Fortran-ordering, or for simplicity simply use vectors. Same example as above, ``Inveon_PET_main_listmode_example``, showcases the coordinate-based reconstruction. Alternatively there is also ``custom_detector_exampleSimple`` and ``custom_coordinates_custom_algorithm_example``. Latter shows how to compute your own custom algorithms. Using list-mode data -------------------- While the above two can be used for the coordinates of list-mode data, there are few special things to take into account when using list-mode data. First ``options.SinM`` should preferably contain only ones or minus ones. Negative values should be used for randoms. If you add randoms manually, you don't actually need to set ``options.randoms_correction`` to true. While the measurements are not really needed for list-mode reconstruction, OMEGA requires their inclusion at the moment. TOF is not yet supported with list-mode data. Another thing to note is the computation of the sensitivity image, such as the one required by MLEM/OSEM. If the sensitivity image is computed with the same coordinates as the list-mode data, the reconstructions will fail. There are two alternatives, one is to compute the sensitivity image using all applicable LORs by using the built-in feature. This is, however, only applicable to cylindrical scanners and scanners where the reconstruction can be performed in normal, sinogram, mode. This feature can be enabled with ``options.compute_sensitivity_image``. Note that the scanner properties have to be correctly set to use this feature. Alternatively, simply use an algorithm that doesn't require a sensitivity image, such as PDHG.