LCOV - code coverage report
Current view: top level - projectors - SubsetSampler.cpp (source / functions) Hit Total Coverage
Test: test_coverage.info.cleaned Lines: 0 96 0.0 %
Date: 2022-08-04 03:43:28 Functions: 0 36 0.0 %

          Line data    Source code
       1             : #include <set>
       2             : #include <numeric>
       3             : #include "SubsetSampler.h"
       4             : #include "PartitionDescriptor.h"
       5             : #include "SiddonsMethod.h"
       6             : 
       7             : namespace elsa
       8             : {
       9             :     template <typename DetectorDescriptor_t, typename data_t>
      10           0 :     SubsetSampler<DetectorDescriptor_t, data_t>::SubsetSampler(
      11             :         const VolumeDescriptor& volumeDescriptor, const DetectorDescriptor_t& detectorDescriptor,
      12             :         index_t nSubsets, SamplingStrategy samplingStrategy)
      13           0 :         : _indexMapping(static_cast<std::size_t>(nSubsets)),
      14           0 :           _volumeDescriptor(volumeDescriptor),
      15           0 :           _fullDetectorDescriptor(detectorDescriptor),
      16           0 :           _nSubsets{nSubsets}
      17             :     {
      18           0 :         if (nSubsets <= 1) {
      19           0 :             throw std::invalid_argument("SubsetSampler: nSubsets must be >= 2");
      20             :         }
      21             : 
      22             :         // the mapping of data indices to subsets
      23             : 
      24           0 :         const auto numCoeffsPerDim = detectorDescriptor.getNumberOfCoefficientsPerDimension();
      25           0 :         const index_t nDimensions = detectorDescriptor.getNumberOfDimensions();
      26           0 :         const auto numElements = numCoeffsPerDim[nDimensions - 1];
      27           0 :         if (samplingStrategy == SamplingStrategy::ROUND_ROBIN) {
      28           0 :             std::vector<index_t> indices(static_cast<std::size_t>(numElements));
      29           0 :             std::iota(indices.begin(), indices.end(), 0);
      30           0 :             _indexMapping = splitRoundRobin(indices, _nSubsets);
      31           0 :         } else if (samplingStrategy == SamplingStrategy::ROTATIONAL_CLUSTERING) {
      32           0 :             _indexMapping = splitRotationalClustering(detectorDescriptor, _nSubsets);
      33             :         } else {
      34           0 :             throw std::invalid_argument("SubsetSampler: unsupported sampling strategy");
      35             :         }
      36             : 
      37             :         // create the detector descriptors that correspond to each subset
      38           0 :         for (const auto& blockIndices : _indexMapping) {
      39           0 :             std::vector<Geometry> geometry;
      40           0 :             for (auto index : blockIndices) {
      41           0 :                 auto geo = detectorDescriptor.getGeometryAt(index);
      42           0 :                 if (geo.has_value()) {
      43           0 :                     geometry.emplace_back(*geo);
      44             :                 }
      45             :             }
      46           0 :             IndexVector_t numOfCoeffsPerDim =
      47             :                 detectorDescriptor.getNumberOfCoefficientsPerDimension();
      48           0 :             numOfCoeffsPerDim[numOfCoeffsPerDim.size() - 1] =
      49           0 :                 static_cast<index_t>(blockIndices.size());
      50             : 
      51           0 :             _detectorDescriptors.emplace_back(DetectorDescriptor_t(numOfCoeffsPerDim, geometry));
      52             :         }
      53           0 :     }
      54             : 
      55             :     template <typename DetectorDescriptor_t, typename data_t>
      56           0 :     std::vector<std::vector<index_t>> SubsetSampler<DetectorDescriptor_t, data_t>::splitRoundRobin(
      57             :         const std::vector<index_t>& indices, index_t nSubsets)
      58             :     {
      59           0 :         std::vector<std::vector<index_t>> subsetIndices(static_cast<std::size_t>(nSubsets));
      60             : 
      61             :         // determine the mapping of indices to subsets
      62           0 :         for (std::size_t i = 0; i < indices.size(); ++i) {
      63           0 :             const auto subset = i % static_cast<std::size_t>(nSubsets);
      64           0 :             subsetIndices[subset].template emplace_back(indices[i]);
      65             :         }
      66             : 
      67           0 :         return subsetIndices;
      68           0 :     }
      69             : 
      70             :     template <typename DetectorDescriptor_t, typename data_t>
      71             :     std::vector<std::vector<index_t>>
      72           0 :         SubsetSampler<DetectorDescriptor_t, data_t>::splitRotationalClustering(
      73             :             const DetectorDescriptor_t& detectorDescriptor, index_t nSubsets)
      74             :     {
      75             : 
      76           0 :         const auto numCoeffsPerDim = detectorDescriptor.getNumberOfCoefficientsPerDimension();
      77           0 :         const index_t nDimensions = detectorDescriptor.getNumberOfDimensions();
      78           0 :         const auto numElements = numCoeffsPerDim[nDimensions - 1];
      79           0 :         std::vector<index_t> indices(static_cast<std::size_t>(numElements));
      80           0 :         std::iota(indices.begin(), indices.end(), 0);
      81           0 :         const auto geometry = detectorDescriptor.getGeometry();
      82             : 
      83             :         // angle between two rotation matrices used as a distance measure
      84           0 :         auto dist = [nDimensions](auto& g1, auto& g2) {
      85           0 :             const auto& r1 = g1.getRotationMatrix();
      86           0 :             const auto& r2 = g2.getRotationMatrix();
      87           0 :             auto product = r1 * r2.transpose();
      88           0 :             if (nDimensions == 2) { // the 2D case
      89           0 :                 return static_cast<double>(std::atan2(product(1, 0), product(0, 0)));
      90             :             } else { // the 3D case
      91           0 :                 return std::acos((product.trace() - 1.0) / 2.0);
      92             :             }
      93             :         };
      94             : 
      95           0 :         const auto first = geometry.front();
      96           0 :         std::sort(std::begin(indices), std::end(indices),
      97           0 :                   [dist, first, &geometry](auto lhs, auto rhs) {
      98           0 :                       return dist(first, geometry[static_cast<std::size_t>(lhs)])
      99           0 :                              < dist(first, geometry[static_cast<std::size_t>(rhs)]);
     100             :                   });
     101             : 
     102           0 :         return splitRoundRobin(indices, nSubsets);
     103           0 :     }
     104             : 
     105             :     template <typename DetectorDescriptor_t, typename data_t>
     106           0 :     SubsetSampler<DetectorDescriptor_t, data_t>::SubsetSampler(
     107             :         const SubsetSampler<DetectorDescriptor_t, data_t>& other)
     108           0 :         : _indexMapping{other._indexMapping},
     109           0 :           _volumeDescriptor(other._volumeDescriptor),
     110           0 :           _fullDetectorDescriptor(other._fullDetectorDescriptor),
     111           0 :           _nSubsets{other._nSubsets}
     112             :     {
     113           0 :         for (const auto& detectorDescriptor : other._detectorDescriptors) {
     114           0 :             _detectorDescriptors.emplace_back(detectorDescriptor);
     115             :         }
     116           0 :     }
     117             : 
     118             :     template <typename DetectorDescriptor_t, typename data_t>
     119           0 :     DataContainer<data_t> SubsetSampler<DetectorDescriptor_t, data_t>::getPartitionedData(
     120             :         const DataContainer<data_t>& sinogram)
     121             :     {
     122             :         // save the number of entries per subset
     123           0 :         IndexVector_t slicesInBlock(_indexMapping.size());
     124           0 :         for (unsigned long i = 0; i < _indexMapping.size(); i++) {
     125           0 :             slicesInBlock[static_cast<index_t>(i)] = static_cast<index_t>(_indexMapping[i].size());
     126             :         }
     127           0 :         PartitionDescriptor dataDescriptor(sinogram.getDataDescriptor(), slicesInBlock);
     128             : 
     129           0 :         const auto numCoeffsPerDim =
     130           0 :             sinogram.getDataDescriptor().getNumberOfCoefficientsPerDimension();
     131           0 :         auto partitionedData = DataContainer<data_t>(dataDescriptor, sinogram.getDataHandlerType());
     132             : 
     133             :         // resort the actual measurement partitionedData
     134           0 :         index_t coeffsPerRow = numCoeffsPerDim.head(numCoeffsPerDim.size() - 1).prod();
     135           0 :         for (index_t i = 0; i < _nSubsets; i++) {
     136             :             // the indices of the partitionedData rows belonging to this subset
     137           0 :             std::vector<index_t> indices = _indexMapping[static_cast<std::size_t>(i)];
     138             : 
     139           0 :             auto block = partitionedData.getBlock(i);
     140             : 
     141           0 :             for (std::size_t j = 0; j < indices.size(); j++) {
     142           0 :                 for (int k = 0; k < coeffsPerRow; k++) {
     143           0 :                     block[static_cast<index_t>(j) * coeffsPerRow + k] =
     144           0 :                         sinogram[indices[j] * coeffsPerRow + k];
     145             :                 }
     146             :             }
     147             :         }
     148           0 :         return partitionedData;
     149           0 :     }
     150             : 
     151             :     template <typename DetectorDescriptor_t, typename data_t>
     152             :     SubsetSampler<DetectorDescriptor_t, data_t>*
     153           0 :         SubsetSampler<DetectorDescriptor_t, data_t>::cloneImpl() const
     154             :     {
     155           0 :         return new SubsetSampler<DetectorDescriptor_t, data_t>(*this);
     156             :     }
     157             : 
     158             :     template <typename DetectorDescriptor_t, typename data_t>
     159           0 :     bool SubsetSampler<DetectorDescriptor_t, data_t>::isEqual(
     160             :         const SubsetSampler<DetectorDescriptor_t, data_t>& other) const
     161             :     {
     162           0 :         if (typeid(*this) != typeid(other))
     163           0 :             return false;
     164             : 
     165           0 :         if (_indexMapping != other._indexMapping)
     166           0 :             return false;
     167             : 
     168           0 :         if (_volumeDescriptor != other._volumeDescriptor)
     169           0 :             return false;
     170             : 
     171           0 :         if (_fullDetectorDescriptor != other._fullDetectorDescriptor)
     172           0 :             return false;
     173             : 
     174           0 :         if (_nSubsets != other._nSubsets)
     175           0 :             return false;
     176             : 
     177             :         // we do not need to check if the vector of detector descriptors is equal as this is
     178             :         // implied by the equality of _data in combination with the full detector descriptor
     179             : 
     180           0 :         return true;
     181             :     }
     182             : 
     183             :     // ------------------------------------------
     184             :     // explicit template instantiation
     185             :     template class SubsetSampler<PlanarDetectorDescriptor, float>;
     186             :     template class SubsetSampler<PlanarDetectorDescriptor, double>;
     187             :     template class SubsetSampler<PlanarDetectorDescriptor, complex<float>>;
     188             :     template class SubsetSampler<PlanarDetectorDescriptor, complex<double>>;
     189             : } // namespace elsa

Generated by: LCOV version 1.14