├── .gitignore ├── logo ├── kct_cbct_logo.png ├── kct_cbct_logoa.png └── kct_cbct_logob.png ├── tests ├── files │ └── camera.matrices └── catch_main.cpp ├── publications ├── KulvaitKrylov2021.pdf └── KulvaitKrylov2021_posterFully3D.pdf ├── include ├── BackprojectorScalingMethod.hpp ├── NDRange │ ├── NDRangeHelper.hpp │ ├── CBCTLocalNDRangeFactory.hpp │ ├── PBCT2DLocalNDRangeFactory.hpp │ └── PBCTLocalNDRangeFactory.hpp ├── GLSQRReconstructor.hpp ├── Perfusion │ ├── CGLSPerfusionReconstructor.hpp │ ├── GLSQRPerfusionReconstructor.hpp │ └── PerfusionOperator.hpp ├── PSIRTReconstructor.hpp ├── GradientType.hpp ├── PDHGROFExecutor.hpp ├── OSSARTReconstructor.hpp ├── BasePBCTReconstructor.hpp ├── Watches.hpp ├── BasePBCT2DReconstructor.hpp ├── BaseROFOperator.hpp ├── PDHGPBCT2DReconstructor.hpp ├── ReductionParameters.hpp ├── CArmArguments.hpp ├── CGLSReconstructor.hpp ├── CGLSPBCTReconstructor.hpp ├── ParallelBeamProjector.hpp ├── CGLSPBCT2DReconstructor.hpp ├── VolumeConvolutionOperator.hpp ├── AlgorithmsBarrierBuffers.hpp ├── BasePBCTOperator.hpp ├── CuttingVoxelProjector.hpp └── PartialPBCT2DOperator.hpp ├── formatWebkit ├── .gitmodules ├── src ├── NDRange │ ├── CBCTLocalNDRangeFactory.cpp │ └── NDRangeHelper.cpp ├── Perfusion │ ├── PerfusionOperator.cpp │ ├── CGLSPerfusionReconstructor.cpp │ └── GLSQRPerfusionReconstructor.cpp ├── sortFileJ.cpp ├── mergeFiles.cpp ├── BasePBCTReconstructor.cpp ├── projectFloats.cpp ├── OSSARTReconstructor.cpp ├── projectVolume.cpp ├── BasePBCT2DReconstructor.cpp ├── createLinkStructure.cpp ├── alg │ └── ParallelBeamProjector.cpp ├── linalg-projector.cpp ├── linalg-sort.cpp └── PSIRTReconstructor.cpp ├── utils └── forwardDifferenceCoefficients.py ├── opencl ├── proximal.cl ├── centerVoxelProjector.cl └── rescaleProjections.cl ├── cmake ├── FindMKL.cmake └── FindOpenCL.cmake ├── .clang-format └── pythonScripts └── generateConvolutionKernels.py /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | exec 3 | doc 4 | info 5 | *.swp 6 | *.pdf 7 | opencl/allsources.cl 8 | -------------------------------------------------------------------------------- /logo/kct_cbct_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kulvait/KCT_cbct/HEAD/logo/kct_cbct_logo.png -------------------------------------------------------------------------------- /logo/kct_cbct_logoa.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kulvait/KCT_cbct/HEAD/logo/kct_cbct_logoa.png -------------------------------------------------------------------------------- /logo/kct_cbct_logob.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kulvait/KCT_cbct/HEAD/logo/kct_cbct_logob.png -------------------------------------------------------------------------------- /tests/files/camera.matrices: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kulvait/KCT_cbct/HEAD/tests/files/camera.matrices -------------------------------------------------------------------------------- /publications/KulvaitKrylov2021.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kulvait/KCT_cbct/HEAD/publications/KulvaitKrylov2021.pdf -------------------------------------------------------------------------------- /publications/KulvaitKrylov2021_posterFully3D.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kulvait/KCT_cbct/HEAD/publications/KulvaitKrylov2021_posterFully3D.pdf -------------------------------------------------------------------------------- /include/BackprojectorScalingMethod.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace KCT { 4 | 5 | enum BackprojectorScalingMethod { NoScaling, FBPScaling, NaturalScaling, KaczmarzScaling }; 6 | 7 | } 8 | -------------------------------------------------------------------------------- /formatWebkit: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | shopt -s globstar 3 | for f in {src,include,tests}/**/*.{c,hpp,h,cpp,tpp}; do 4 | if echo x"$f" | grep -v '*' > /dev/null; then #Process only matches that do not contain asterix 5 | echo "Formating file $f." 6 | clang-format -style=file -i "$f" 7 | fi 8 | done 9 | -------------------------------------------------------------------------------- /include/NDRange/NDRangeHelper.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Logging 4 | #include "PLOG/PlogSetup.h" 5 | 6 | // External libraries 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // Internal libraries 13 | #include "rawop.h" 14 | #include "stringFormatter.h" 15 | 16 | namespace KCT { 17 | 18 | class NDRangeHelper 19 | { 20 | public: 21 | static cl::NDRange flipNDRange(cl::NDRange& x); 22 | static std::string NDRangeToString(cl::NDRange& x, std::string name=""); 23 | }; 24 | 25 | } // namespace KCT 26 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "submodules/plog"] 2 | path = submodules/plog 3 | url = https://github.com/SergiusTheBest/plog 4 | [submodule "submodules/CLI11"] 5 | path = submodules/CLI11 6 | url = https://github.com/CLIUtils/CLI11 7 | [submodule "submodules/ctpl"] 8 | path = submodules/ctpl 9 | url = https://github.com/vit-vit/ctpl 10 | [submodule "submodules/CTIOL"] 11 | path = submodules/CTIOL 12 | url = ../kct_ctiol.git 13 | [submodule "submodules/CTMAL"] 14 | path = submodules/CTMAL 15 | url = ../kct_ctmal.git 16 | [submodule "submodules/matplotlib-cpp"] 17 | path = submodules/matplotlib-cpp 18 | url = https://github.com/lava/matplotlib-cpp 19 | [submodule "submodules/gitversion"] 20 | path = submodules/gitversion 21 | url = https://github.com/kulvait/gitversion 22 | [submodule "submodules/Catch2"] 23 | path = submodules/Catch2 24 | url = https://github.com/catchorg/Catch2.git 25 | -------------------------------------------------------------------------------- /src/NDRange/CBCTLocalNDRangeFactory.cpp: -------------------------------------------------------------------------------- 1 | #include "NDRange/CBCTLocalNDRangeFactory.hpp" 2 | 3 | namespace KCT { 4 | 5 | cl::NDRange CBCTLocalNDRangeFactory::getProjectorLocalNDRange(cl::NDRange lr, bool verbose) const {} 6 | cl::NDRange CBCTLocalNDRangeFactory::getProjectorBarrierLocalNDRange(cl::NDRange lr, 7 | bool verbose) const 8 | { 9 | } 10 | cl::NDRange CBCTLocalNDRangeFactory::getBackprojectorLocalNDRange(cl::NDRange lr, 11 | bool verbose) const 12 | { 13 | } 14 | bool CBCTLocalNDRangeFactory::isLocalRangeAdmissible(cl::NDRange& localRange) const {} 15 | void CBCTLocalNDRangeFactory::checkLocalRange(cl::NDRange& localRange, std::string name) const {} 16 | cl::NDRange CBCTLocalNDRangeFactory::guessProjectorLocalNDRange(bool barrierCalls) const {} 17 | cl::NDRange CBCTLocalNDRangeFactory::guessBackprojectorLocalNDRange() const {} 18 | 19 | } // namespace KCT 20 | -------------------------------------------------------------------------------- /tests/catch_main.cpp: -------------------------------------------------------------------------------- 1 | #define CATCH_CONFIG_RUNNER 2 | #include "PLOG/PlogSetup.h" 3 | #include "PROG/RunTimeInfo.hpp" 4 | #include "catch.hpp" 5 | 6 | using namespace KCT; 7 | 8 | int main(int argc, char* argv[]) 9 | { 10 | // global setup... 11 | bool logging = true; 12 | if(logging) 13 | { 14 | plog::Severity verbosityLevel 15 | = plog::debug; // Set to debug to see the debug messages, info messages 16 | std::string csvLogFile = "/tmp/imageRegistrationLog.csv"; // Set NULL to disable 17 | bool logToConsole = true; 18 | plog::PlogSetup plogSetup(verbosityLevel, csvLogFile, logToConsole); 19 | plogSetup.initLogging(); 20 | } 21 | int result = Catch::Session().run(argc, argv); 22 | 23 | // global clean-up... 24 | 25 | return result; 26 | } 27 | 28 | std::string basedir() 29 | { 30 | util::RunTimeInfo rti; 31 | std::string path = rti.getExecutableDirectoryPath(); // build dir 32 | return io::getParent(path); 33 | } 34 | 35 | TEST_CASE("LOGGING SETUP", "catch_main.cpp") {} 36 | -------------------------------------------------------------------------------- /src/NDRange/NDRangeHelper.cpp: -------------------------------------------------------------------------------- 1 | #include "NDRange/NDRangeHelper.hpp" 2 | 3 | namespace KCT { 4 | cl::NDRange NDRangeHelper::flipNDRange(cl::NDRange& x) 5 | { 6 | int dim = x.dimensions(); 7 | if(dim == 2) 8 | { 9 | return cl::NDRange(x[1], x[0]); 10 | } else if(dim == 3) 11 | { 12 | return cl::NDRange(x[2], x[1], x[0]); 13 | } else 14 | { // Nothing to flip 15 | return x; 16 | } 17 | } 18 | 19 | std::string NDRangeHelper::NDRangeToString(cl::NDRange& x, std::string name) 20 | { 21 | std::string str; 22 | int dim = x.dimensions(); 23 | if(dim == 0) 24 | { 25 | str = "cl::NullRange"; 26 | } else if(dim == 1) 27 | { 28 | str = io::xprintf("cl::NDRange(%d)", x[0]); 29 | } else if(dim == 2) 30 | { 31 | str = io::xprintf("cl::NDRange(%d, %d)", x[0], x[1]); 32 | } else 33 | { 34 | str = io::xprintf("cl::NDRange(%d, %d, %d)", x[0], x[1], x[2]); 35 | } 36 | if(name != "") 37 | { 38 | return io::xprintf("%s=%s", name.c_str(), str.c_str()); 39 | } else 40 | { 41 | return str; 42 | } 43 | } 44 | } // namespace KCT 45 | -------------------------------------------------------------------------------- /src/Perfusion/PerfusionOperator.cpp: -------------------------------------------------------------------------------- 1 | #include "Perfusion/PerfusionOperator.hpp" 2 | 3 | namespace KCT { 4 | 5 | int PerfusionOperator::project(bool blocking) 6 | { 7 | reportTime("PERFUSION PROJECTION", blocking, true); 8 | allocateBBuffers(1);//b_buf is not writeable as it contains only data for reconstruction 9 | std::vector> b_prj = getBBuffers(0); 10 | BasePerfusionReconstructor::project(x_buf, b_prj); 11 | for(uint32_t sweepID = 0; sweepID != BVNUM; sweepID++) 12 | { 13 | Q[0]->enqueueReadBuffer(*b_prj[sweepID], CL_TRUE, 0, sizeof(float) * BDIM, b[sweepID]); 14 | } 15 | reportTime("PERFUSION PROJECTION duration", blocking, true); 16 | return 0; 17 | } 18 | 19 | int PerfusionOperator::backproject(bool blocking) 20 | { 21 | reportTime("PERFUSION BACKPROJECTION", blocking, true); 22 | BasePerfusionReconstructor::backproject(b_buf, x_buf); 23 | for(uint32_t vectorID = 0; vectorID != XVNUM; vectorID++) 24 | { 25 | Q[0]->enqueueReadBuffer(*x_buf[vectorID], CL_TRUE, 0, sizeof(float) * XDIM, x[vectorID]); 26 | } 27 | reportTime("PERFUSION BACKPROJECTION duration", blocking, true); 28 | return 0; 29 | } 30 | 31 | } // namespace KCT 32 | -------------------------------------------------------------------------------- /include/GLSQRReconstructor.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Logging 4 | #include "PLOG/PlogSetup.h" 5 | 6 | // External libraries 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // Internal libraries 13 | #include "BaseReconstructor.hpp" 14 | #include "DEN/DenProjectionMatrixReader.hpp" 15 | #include "MATRIX/ProjectionMatrix.hpp" 16 | #include "OPENCL/OpenCLManager.hpp" 17 | #include "rawop.h" 18 | #include "stringFormatter.h" 19 | 20 | namespace KCT { 21 | 22 | class GLSQRReconstructor : public BaseReconstructor 23 | { 24 | public: 25 | GLSQRReconstructor(uint32_t pdimx, 26 | uint32_t pdimy, 27 | uint32_t pdimz, 28 | uint32_t vdimx, 29 | uint32_t vdimy, 30 | uint32_t vdimz, 31 | uint32_t workGroupSize = 256) 32 | : BaseReconstructor(pdimx, pdimy, pdimz, vdimx, vdimy, vdimz, workGroupSize) 33 | { 34 | } 35 | 36 | virtual int reconstruct(uint32_t maxIterations = 100, float errCondition = 0.01); 37 | int reconstructTikhonov(double lambda, uint32_t maxIterations = 100, float errCondition = 0.01); 38 | }; 39 | 40 | } // namespace KCT 41 | -------------------------------------------------------------------------------- /include/NDRange/CBCTLocalNDRangeFactory.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Logging 4 | #include "PLOG/PlogSetup.h" 5 | 6 | // External libraries 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // Internal libraries 13 | #include "rawop.h" 14 | #include "stringFormatter.h" 15 | #include "NDRange/NDRangeHelper.hpp" 16 | 17 | namespace KCT { 18 | 19 | class CBCTLocalNDRangeFactory 20 | { 21 | public: 22 | CBCTLocalNDRangeFactory(uint32_t vdimx, 23 | uint32_t vdimy, 24 | uint32_t vdimz, 25 | uint32_t maxWorkGroupSize) 26 | : vdimx(vdimx) 27 | , vdimy(vdimy) 28 | , vdimz(vdimz) 29 | , maxWorkGroupSize(maxWorkGroupSize) 30 | { 31 | } 32 | 33 | cl::NDRange getProjectorLocalNDRange(cl::NDRange lr = cl::NullRange, bool verbose = false) const; 34 | cl::NDRange getProjectorBarrierLocalNDRange(cl::NDRange lr = cl::NullRange, bool verbose = false) const; 35 | cl::NDRange getBackprojectorLocalNDRange(cl::NDRange lr = cl::NullRange, bool verbose = false) const; 36 | 37 | private: 38 | uint32_t vdimx, vdimy, vdimz; 39 | uint32_t maxWorkGroupSize; 40 | bool isAdmissibleRange(uint32_t n0, uint32_t n1, uint32_t n2) const; 41 | bool isLocalRangeAdmissible(cl::NDRange& localRange) const; 42 | void checkLocalRange(cl::NDRange& localRange, std::string name) const; 43 | cl::NDRange guessProjectorLocalNDRange(bool barrierCalls) const; 44 | cl::NDRange guessBackprojectorLocalNDRange() const; 45 | }; 46 | 47 | } // namespace KCT 48 | -------------------------------------------------------------------------------- /include/NDRange/PBCT2DLocalNDRangeFactory.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Logging 4 | #include "PLOG/PlogSetup.h" 5 | 6 | // External libraries 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // Internal libraries 13 | #include "NDRange/NDRangeHelper.hpp" 14 | #include "rawop.h" 15 | #include "stringFormatter.h" 16 | 17 | namespace KCT { 18 | 19 | class PBCT2DLocalNDRangeFactory 20 | { 21 | public: 22 | PBCT2DLocalNDRangeFactory(uint32_t vdimx, uint32_t vdimy, uint32_t maxWorkGroupSize) 23 | : vdimx(vdimx) 24 | , vdimy(vdimy) 25 | , maxWorkGroupSize(maxWorkGroupSize) 26 | { 27 | } 28 | 29 | cl::NDRange getProjectorLocalNDRange(cl::NDRange lr = cl::NullRange, 30 | bool verbose = false) const; 31 | cl::NDRange getProjectorBarrierLocalNDRange(cl::NDRange lr = cl::NullRange, 32 | bool verbose = false) const; 33 | cl::NDRange getBackprojectorLocalNDRange(cl::NDRange lr = cl::NullRange, 34 | bool verbose = false) const; 35 | 36 | private: 37 | uint32_t vdimx, vdimy; 38 | uint32_t maxWorkGroupSize; 39 | 40 | bool isLocalRangeAdmissible(cl::NDRange& localRange) const; 41 | bool isAdmissibleRange(uint32_t n0, uint32_t n1) const; 42 | void checkLocalRange(cl::NDRange& localRange, std::string name) const; 43 | cl::NDRange guessProjectorLocalNDRange(bool barrierCalls) const; 44 | cl::NDRange guessBackprojectorLocalNDRange() const; 45 | }; 46 | 47 | } // namespace KCT 48 | -------------------------------------------------------------------------------- /include/Perfusion/CGLSPerfusionReconstructor.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Logging 4 | #include "PLOG/PlogSetup.h" 5 | 6 | // External libraries 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // Internal libraries 13 | #include "DEN/DenProjectionMatrixReader.hpp" 14 | #include "MATRIX/ProjectionMatrix.hpp" 15 | #include "OPENCL/OpenCLManager.hpp" 16 | #include "Perfusion/BasePerfusionReconstructor.hpp" 17 | #include "rawop.h" 18 | #include "stringFormatter.h" 19 | 20 | namespace KCT { 21 | 22 | class CGLSPerfusionReconstructor : public BasePerfusionReconstructor 23 | { 24 | public: 25 | /** 26 | * Initialize Cutting Voxel Projector 27 | * 28 | * @param volume Pointer to volume file 29 | * @param vdimx Volume x dimension 30 | * @param vdimy Volume y dimension 31 | * @param vdimz Volume z dimension 32 | * @param xpath Path of cl kernel files 33 | * @param debug Should debugging be used by suppliing source and -g as options 34 | */ 35 | CGLSPerfusionReconstructor(uint32_t pdimx, 36 | uint32_t pdimy, 37 | uint32_t pdimz, 38 | uint32_t vdimx, 39 | uint32_t vdimy, 40 | uint32_t vdimz, 41 | uint32_t workGroupSize = 256) 42 | : BasePerfusionReconstructor(pdimx, pdimy, pdimz, vdimx, vdimy, vdimz, workGroupSize) 43 | { 44 | } 45 | 46 | int reconstruct(uint32_t maxIterations = 100, float errCondition = 0.01, bool blocking = false); 47 | }; 48 | 49 | } // namespace KCT 50 | -------------------------------------------------------------------------------- /include/Perfusion/GLSQRPerfusionReconstructor.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Logging 4 | #include "PLOG/PlogSetup.h" 5 | 6 | // External libraries 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // Internal libraries 13 | #include "Perfusion/BasePerfusionReconstructor.hpp" 14 | #include "DEN/DenProjectionMatrixReader.hpp" 15 | #include "MATRIX/ProjectionMatrix.hpp" 16 | #include "OPENCL/OpenCLManager.hpp" 17 | #include "rawop.h" 18 | #include "stringFormatter.h" 19 | 20 | namespace KCT { 21 | 22 | class GLSQRPerfusionReconstructor : public BasePerfusionReconstructor 23 | { 24 | public: 25 | /** 26 | * Initialize GLSQRPerfusionReconstructor 27 | * 28 | * @param volume Pointer to volume file 29 | * @param vdimx Volume x dimension 30 | * @param vdimy Volume y dimension 31 | * @param vdimz Volume z dimension 32 | * @param xpath Path of cl kernel files 33 | * @param debug Should debugging be used by suppliing source and -g as options 34 | */ 35 | GLSQRPerfusionReconstructor(uint32_t pdimx, 36 | uint32_t pdimy, 37 | uint32_t pdimz, 38 | uint32_t vdimx, 39 | uint32_t vdimy, 40 | uint32_t vdimz, 41 | uint32_t workGroupSize = 256) 42 | : BasePerfusionReconstructor(pdimx, pdimy, pdimz, vdimx, vdimy, vdimz, workGroupSize) 43 | { 44 | } 45 | 46 | int reconstruct(uint32_t maxIterations = 100, float errCondition = 0.01, bool blocking = false); 47 | }; 48 | 49 | } // namespace KCT 50 | -------------------------------------------------------------------------------- /include/PSIRTReconstructor.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Logging 4 | #include "PLOG/PlogSetup.h" 5 | 6 | // External libraries 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // Internal libraries 13 | #include "BaseReconstructor.hpp" 14 | #include "DEN/DenProjectionMatrixReader.hpp" 15 | #include "MATRIX/LightProjectionMatrix.hpp" 16 | #include "MATRIX/ProjectionMatrix.hpp" 17 | #include "OPENCL/OpenCLManager.hpp" 18 | #include "rawop.h" 19 | #include "stringFormatter.h" 20 | 21 | namespace KCT { 22 | 23 | class PSIRTReconstructor : public BaseReconstructor 24 | { 25 | public: 26 | /** 27 | * Initialize Cutting Voxel Projector 28 | * 29 | * @param volume Pointer to volume file 30 | * @param vdimx Volume x dimension 31 | * @param vdimy Volume y dimension 32 | * @param vdimz Volume z dimension 33 | * @param xpath Path of cl kernel files 34 | * @param debug Should debugging be used by suppliing source and -g as options 35 | */ 36 | PSIRTReconstructor(uint32_t pdimx, 37 | uint32_t pdimy, 38 | uint32_t pdimz, 39 | uint32_t vdimx, 40 | uint32_t vdimy, 41 | uint32_t vdimz, 42 | uint32_t workGroupSize = 256) 43 | : BaseReconstructor(pdimx, pdimy, pdimz, vdimx, vdimy, vdimz, workGroupSize) 44 | { 45 | } 46 | 47 | virtual int reconstruct(uint32_t maxIterations = 100, float errCondition = 0.01); 48 | int reconstruct_sirt(uint32_t maxIterations = 100, float errCondition = 0.01); 49 | 50 | void setup(double alpha = 1.99); 51 | 52 | private: 53 | double alpha; 54 | }; 55 | 56 | } // namespace KCT 57 | -------------------------------------------------------------------------------- /include/NDRange/PBCTLocalNDRangeFactory.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Logging 4 | #include "PLOG/PlogSetup.h" 5 | 6 | // External libraries 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // Internal libraries 13 | #include "rawop.h" 14 | #include "stringFormatter.h" 15 | #include "NDRange/NDRangeHelper.hpp" 16 | 17 | namespace KCT { 18 | 19 | class PBCTLocalNDRangeFactory 20 | { 21 | public: 22 | PBCTLocalNDRangeFactory(uint32_t vdimx, 23 | uint32_t vdimy, 24 | uint32_t vdimz, 25 | uint32_t maxWorkGroupSize) 26 | : vdimx(vdimx) 27 | , vdimy(vdimy) 28 | , vdimz(vdimz) 29 | , maxWorkGroupSize(maxWorkGroupSize) 30 | { 31 | } 32 | 33 | cl::NDRange getProjectorLocalNDRange(cl::NDRange lr = cl::NullRange, 34 | bool verbose = false) const; 35 | cl::NDRange getProjectorBarrierLocalNDRange(cl::NDRange lr = cl::NullRange, 36 | bool verbose = false) const; 37 | cl::NDRange getBackprojectorLocalNDRange(cl::NDRange lr = cl::NullRange, 38 | bool verbose = false) const; 39 | 40 | private: 41 | uint32_t vdimx, vdimy, vdimz; 42 | uint32_t maxWorkGroupSize; 43 | bool isAdmissibleRange(uint32_t n0, uint32_t n1, uint32_t n2) const; 44 | bool isLocalRangeAdmissible(cl::NDRange& localRange) const; 45 | void checkLocalRange(cl::NDRange& localRange, std::string name) const; 46 | cl::NDRange guessProjectorLocalNDRange(bool barrierCalls) const; 47 | cl::NDRange guessBackprojectorLocalNDRange() const; 48 | }; 49 | 50 | } // namespace KCT 51 | -------------------------------------------------------------------------------- /utils/forwardDifferenceCoefficients.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # Simple script to compute the coefficients of the forward difference approximation 4 | import numpy as np 5 | import sympy as sp 6 | import argparse 7 | 8 | 9 | parser = argparse.ArgumentParser(description="Compute forward difference coefficients.") 10 | parser.add_argument('order', type=int, help='Order of the forward difference approximation') 11 | ARG = parser.parse_args() 12 | 13 | def forward_difference_coefficients(n): 14 | # Define symbols 15 | f0 = sp.symbols("f0") 16 | equations = [] 17 | dsymbols = [] 18 | fsymbols = [f0] 19 | for i in range(n): 20 | dsymbols.append(sp.symbols("d%d"%(i+1))) 21 | fsymbols.append(sp.symbols("f%d"%(i+1))) 22 | for i in range(n): 23 | equation = f0 - fsymbols[i+1] 24 | #length is i+1 25 | for j in range(n): 26 | if j==0: 27 | equation = equation + (i+1) * dsymbols[0] 28 | else: 29 | equation += dsymbols[j]*(i+1)**(j+1)/sp.factorial(j+1) 30 | equations.append(equation) 31 | 32 | # print(equations) 33 | solution = sp.solve(equations, dsymbols) 34 | # print(solution) 35 | d1_coefficients = [solution[d].expand() for d in dsymbols] 36 | # print(d1_coefficients) 37 | # Collect the coefficients of f0, f1, ..., fn for d1 38 | coefficients = [] 39 | for coef in d1_coefficients: 40 | coeffs_dict = sp.collect(coef, fsymbols, evaluate=False) 41 | coefficients.append([coeffs_dict.get(f, 0) for f in fsymbols]) 42 | 43 | return coefficients[0] # Coefficients for d1 44 | 45 | # Example usage: 46 | order = ARG.order 47 | coefficients = forward_difference_coefficients(order) 48 | print(f"Coefficients for forward difference of order {order}: {coefficients}") 49 | 50 | -------------------------------------------------------------------------------- /include/Perfusion/PerfusionOperator.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Logging 4 | #include "PLOG/PlogSetup.h" 5 | 6 | // External libraries 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // Internal libraries 13 | #include "DEN/DenProjectionMatrixReader.hpp" 14 | #include "MATRIX/ProjectionMatrix.hpp" 15 | #include "OPENCL/OpenCLManager.hpp" 16 | #include "Perfusion/BasePerfusionReconstructor.hpp" 17 | #include "rawop.h" 18 | #include "stringFormatter.h" 19 | 20 | namespace KCT { 21 | 22 | class PerfusionOperator : public BasePerfusionReconstructor 23 | { 24 | public: 25 | /** 26 | * Initialize GLSQRPerfusionReconstructor 27 | * 28 | * @param volume Pointer to volume file 29 | * @param vdimx Volume x dimension 30 | * @param vdimy Volume y dimension 31 | * @param vdimz Volume z dimension 32 | * @param xpath Path of cl kernel files 33 | * @param debug Should debugging be used by suppliing source and -g as options 34 | */ 35 | PerfusionOperator(uint32_t pdimx, 36 | uint32_t pdimy, 37 | uint32_t pdimz, 38 | uint32_t vdimx, 39 | uint32_t vdimy, 40 | uint32_t vdimz, 41 | uint32_t workGroupSize = 256) 42 | : BasePerfusionReconstructor(pdimx, pdimy, pdimz, vdimx, vdimy, vdimz, workGroupSize) 43 | { 44 | } 45 | 46 | int reconstruct(uint32_t maxIterations = 100, float errCondition = 0.01, bool blocking = false) 47 | { 48 | LOGD << "This function is not implemented in PerfusionOperator class."; 49 | return 1; 50 | } 51 | int project(bool blocking = false); 52 | int backproject(bool blocking = false); 53 | }; 54 | 55 | } // namespace KCT 56 | -------------------------------------------------------------------------------- /include/GradientType.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace KCT { 6 | 7 | /** 8 | * @brief Enum for gradient types, e.g. central vs. forward difference and derivative type. 9 | */ 10 | enum class GradientType { 11 | CentralDifference3Point, 12 | CentralDifference5Point, 13 | ForwardDifference2Point, 14 | ForwardDifference3Point, 15 | ForwardDifference4Point, 16 | ForwardDifference5Point, 17 | ForwardDifference6Point, 18 | ForwardDifference7Point 19 | }; 20 | 21 | // Free function to convert GradientType to string 22 | inline std::string GradientTypeToString(GradientType type) 23 | { 24 | switch(type) 25 | { 26 | // Sigma=tau=0.7 27 | case GradientType::CentralDifference3Point: 28 | return "CentralDifference3Point convergent with sigma=tau=0.7"; 29 | // Sigma=tau=0.35 30 | case GradientType::CentralDifference5Point: 31 | return "CentralDifference5Point convergetnt with sigma=tau=0.35"; 32 | // Sigma=tau=0.5 33 | case GradientType::ForwardDifference2Point: 34 | return "ForwardDifference2Point convergent with sigma=tau=0.5"; 35 | // Sigma=tau=0.125 36 | case GradientType::ForwardDifference3Point: 37 | return "ForwardDifference3Point convergent with sigma=tau=0.125"; 38 | case GradientType::ForwardDifference4Point: 39 | return "ForwardDifference4Point convergent with sigma=tau=0.125"; 40 | case GradientType::ForwardDifference5Point: 41 | return "ForwardDifference5Point convergent with sigma=tau=0.125"; 42 | case GradientType::ForwardDifference6Point: 43 | return "ForwardDifference6Point convergent with sigma=tau=0.125"; 44 | case GradientType::ForwardDifference7Point: 45 | return "ForwardDifference7Point convergent with sigma=tau=0.125"; 46 | default: 47 | return "Unknown GradientType"; 48 | } 49 | } 50 | 51 | } // namespace KCT 52 | -------------------------------------------------------------------------------- /include/PDHGROFExecutor.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Logging 4 | #include "PLOG/PlogSetup.h" 5 | 6 | // External libraries 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // Internal libraries 13 | #include "BaseROFOperator.hpp" 14 | #include "rawop.h" 15 | #include "stringFormatter.h" 16 | 17 | namespace KCT { 18 | 19 | class PDHGROFExecutor : virtual public BaseROFOperator 20 | { 21 | public: 22 | /** 23 | * Initialize object 24 | * 25 | * @param vdimx Volume x dimension 26 | * @param vdimy Volume y dimension 27 | * @param vdimz Volume z dimension 28 | * @param xpath Path of cl kernel files 29 | * @param debug Should debugging be used by suppliing source and -g as options 30 | */ 31 | /** 32 | * @brief Construct a new PDHGROFExecutor object 33 | * 34 | * @param pdimx 35 | * @param pdimy 36 | * @param pdimz 37 | * @param vdimx 38 | * @param vdimy 39 | * @param vdimz 40 | * @param workGroupSize 41 | */ 42 | PDHGROFExecutor(uint32_t vdimx, uint32_t vdimy, uint32_t vdimz, uint32_t workGroupSize = 256) 43 | : BaseROFOperator(vdimx, vdimy, vdimz, workGroupSize) 44 | 45 | { 46 | } 47 | 48 | virtual int reconstruct(float mu, 49 | float tau, 50 | float sigma, 51 | float theta, 52 | uint32_t maxPDHGIterations = 100, 53 | float errConditionPDHG = 0.01) override; 54 | 55 | private: 56 | std::shared_ptr directionVector_xbuf, residualVector_xbuf, 57 | residualVector_xbuf_L2add, discrepancy_bbuf_xpart_L2, AdirectionVector_bbuf_xpart_L2; 58 | std::array computeSolutionNorms(std::shared_ptr x_vector, 59 | std::shared_ptr x_vector_dx, 60 | std::shared_ptr x_vector_dy, 61 | std::shared_ptr x_0); 62 | bool proximalOperatorVerbose = false; 63 | }; 64 | 65 | } // namespace KCT 66 | -------------------------------------------------------------------------------- /include/OSSARTReconstructor.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Logging 4 | #include "PLOG/PlogSetup.h" 5 | 6 | // External libraries 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // Internal libraries 13 | #include "BaseReconstructor.hpp" 14 | #include "DEN/DenProjectionMatrixReader.hpp" 15 | #include "MATRIX/LightProjectionMatrix.hpp" 16 | #include "MATRIX/ProjectionMatrix.hpp" 17 | #include "OPENCL/OpenCLManager.hpp" 18 | #include "rawop.h" 19 | #include "stringFormatter.h" 20 | 21 | namespace KCT { 22 | 23 | class OSSARTReconstructor : public BaseReconstructor 24 | { 25 | public: 26 | /** 27 | * Initialize Cutting Voxel Projector 28 | * 29 | * @param volume Pointer to volume file 30 | * @param vdimx Volume x dimension 31 | * @param vdimy Volume y dimension 32 | * @param vdimz Volume z dimension 33 | * @param xpath Path of cl kernel files 34 | * @param debug Should debugging be used by suppliing source and -g as options 35 | */ 36 | OSSARTReconstructor(uint32_t pdimx, 37 | uint32_t pdimy, 38 | uint32_t pdimz, 39 | uint32_t vdimx, 40 | uint32_t vdimy, 41 | uint32_t vdimz, 42 | uint32_t workGroupSize = 256) 43 | : BaseReconstructor(pdimx, pdimy, pdimz, vdimx, vdimy, vdimz, workGroupSize) 44 | { 45 | setup(0.9, 1); 46 | removeUpperBoxCondition(); 47 | removeLowerBoxCondition(); 48 | } 49 | 50 | void setup(float relaxationParameter, uint32_t subsetCount); 51 | 52 | void addUpperBoxCondition(float upperBound, float upperBoxSubstitution); 53 | 54 | void removeUpperBoxCondition(); 55 | 56 | void addLowerBoxCondition(float lowerBound, float lowerBoxSubstitution); 57 | 58 | void removeLowerBoxCondition(); 59 | 60 | virtual int reconstruct(uint32_t maxIterations = 100, float errCondition = 0.01); 61 | 62 | private: 63 | float relaxationParameter; 64 | uint32_t subsetCount; 65 | bool lowerBoxCondition, upperBoxCondition; 66 | float lowerBound, upperBound; 67 | float lowerBoundSubstitution, upperBoundSubstitution; 68 | }; 69 | 70 | } // namespace KCT 71 | -------------------------------------------------------------------------------- /src/sortFileJ.cpp: -------------------------------------------------------------------------------- 1 | // Logging 2 | #include "PLOG/PlogSetup.h" 3 | 4 | // External libraries 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // External libraries 13 | #include "CLI/CLI.hpp" //Command line parser 14 | #include "ctpl_stl.h" //Threadpool 15 | 16 | // Internal libraries 17 | #include "ARGPARSE/parseArgs.h" 18 | #include "SMA/BufferedSparseMatrixDoubleReader.hpp" 19 | #include "SMA/BufferedSparseMatrixFloatWritter.hpp" 20 | 21 | using namespace KCT; 22 | 23 | int main(int argc, char* argv[]) 24 | { 25 | plog::Severity verbosityLevel = plog::debug; // Set to debug to see the 26 | // debug messages, info 27 | // messages 28 | std::string csvLogFile = "/tmp/dacprojector.csv"; // Set NULL to disable 29 | bool logToConsole = true; 30 | plog::PlogSetup plogSetup(verbosityLevel, csvLogFile, logToConsole); 31 | plogSetup.initLogging(); 32 | LOGI << "sortsortsort"; 33 | // Argument parsing 34 | std::string a_unsortedDouble; 35 | std::string a_sortedFloat; 36 | CLI::App app{ "Using divide and conquer techniques to construct CT system matrix.." }; 37 | app.add_option("unsorted_double", a_unsortedDouble, "File in a sparse matrix format to output.") 38 | ->required() 39 | ->check(CLI::ExistingFile); 40 | app.add_option("sorted_float", a_sortedFloat, 41 | "Files in a DEN format to process. These files represents projection matrices.") 42 | ->required() 43 | ->check(CLI::NonexistentPath); 44 | app.parse(argc, argv); 45 | // Frames to process 46 | matrix::BufferedSparseMatrixDoubleReader input(a_unsortedDouble); 47 | uint64_t numberOfElements = input.getNumberOfElements(); 48 | std::vector elements; 49 | for(uint64_t k = 0; k != numberOfElements; k++) 50 | { 51 | elements.push_back(input.readNextElement()); 52 | } 53 | std::sort(elements.begin(), elements.end(), std::greater()); 54 | matrix::BufferedSparseMatrixFloatWritter output(a_sortedFloat); 55 | for(uint64_t k = 0; k != numberOfElements; k++) 56 | { 57 | output.insertValue(elements[k].i, elements[k].j, elements[k].v); 58 | } 59 | output.flush(); 60 | LOGI << "END"; 61 | } 62 | -------------------------------------------------------------------------------- /include/BasePBCTReconstructor.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Logging 4 | #include "PLOG/PlogSetup.h" 5 | 6 | // External libraries 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // Internal libraries 13 | #include "AlgorithmsBarrierBuffers.hpp" 14 | #include "BasePBCTOperator.hpp" 15 | #include "BufferedFrame2D.hpp" 16 | #include "DEN/DenAsyncFrame2DWritter.hpp" 17 | #include "DEN/DenProjectionMatrixReader.hpp" 18 | #include "Kniha.hpp" 19 | #include "MATRIX/utils.hpp" 20 | #include "OPENCL/OpenCLManager.hpp" 21 | #include "rawop.h" 22 | #include "stringFormatter.h" 23 | 24 | using namespace KCT::matrix; 25 | namespace KCT { 26 | 27 | class BasePBCTReconstructor : public virtual BasePBCTOperator 28 | { 29 | public: 30 | BasePBCTReconstructor(uint32_t pdimx, 31 | uint32_t pdimy, 32 | uint32_t pdimz, 33 | uint32_t vdimx, 34 | uint32_t vdimy, 35 | uint32_t vdimz, 36 | uint32_t workGroupSize = 256) 37 | : BasePBCTOperator(pdimx, 38 | pdimy, 39 | pdimz, 40 | vdimx, 41 | vdimy, 42 | vdimz, 43 | workGroupSize) 44 | { 45 | } 46 | 47 | virtual ~BasePBCTReconstructor() = default; 48 | 49 | virtual int reconstruct(uint32_t maxItterations, float minDiscrepancyError) = 0; 50 | 51 | void setReportingParameters(bool verbose, 52 | uint32_t reportKthIteration = 0, 53 | std::string intermediatePrefix = ""); 54 | int initializeVectors(float* projection, float* volume, bool volumeContainsX0); 55 | double adjointProductTest(); 56 | 57 | protected: 58 | // OpenCL buffers 59 | std::shared_ptr b_buf = nullptr; 60 | std::shared_ptr x_buf = nullptr; 61 | // tmp_b_buf for rescaling, tmp_x_buf for LSQR 62 | std::shared_ptr tmp_x_buf = nullptr, tmp_b_buf = nullptr; 63 | float* x = nullptr; // Volume data 64 | float* b = nullptr; // Projection data 65 | 66 | uint32_t reportKthIteration = 0; 67 | // Auxiliary functions 68 | void writeVolume(cl::Buffer& X, std::string path); 69 | void writeProjections(cl::Buffer& B, std::string path); 70 | }; 71 | 72 | } // namespace KCT 73 | -------------------------------------------------------------------------------- /opencl/proximal.cl: -------------------------------------------------------------------------------- 1 | //==============================proximal.cl===================================== 2 | // This file contains the OpenCL code for the proximal operators mainly used in 3 | // PDHG algorithm associated with Total Variation (TV) minimization. 4 | 5 | // This kernel implements the proximal operator of the indicator function for the dual problem 6 | // in the context of Total Variation (TV) minimization. In Chambolle-Pock or PDHG algorithms, 7 | // this operator corresponds to the "shrinkage" or "dual projection" step. It projects the 8 | // vector (G1, G2), which represents the dual variable (associated with the gradient), onto 9 | // the l2-ball of radius 'mu' in L_inf norm. 10 | // This is equivalent to applying the proximal operator of 11 | // the conjugate of the TV norm (the l1 norm of the gradient). 12 | 13 | // The goal is to ensure that the gradient norm (magnitude of the vector) does not exceed mu. 14 | // This is a critical step in the PDHG update for the dual variable. 15 | void kernel FLOATvector_infProjectionToLambda2DBall(global float* restrict G1, 16 | global float* restrict G2, 17 | float const mu) 18 | { 19 | size_t gid = get_global_id(0); 20 | float gx = G1[gid]; 21 | float gy = G2[gid]; 22 | // Compute the magnitude of the vector (gx, gy) 23 | float f = sqrt(gx * gx + gy * gy); 24 | // If the magnitude is greater than mu, project the vector onto the mu ball surface 25 | if(f > mu) 26 | { 27 | f = mu / f; 28 | G1[gid] = gx * f; 29 | G2[gid] = gy * f; 30 | } 31 | } 32 | 33 | // L1 proximal operator, soft thresholding solving min omega | u - u0 | + 1/2 | u - x_prox |_2^2 34 | void kernel FLOATvector_distL1ProxSoftThreasholding(global float* restrict U0, 35 | global float* restrict XPROX, 36 | float const omega) 37 | { 38 | size_t gid = get_global_id(0); 39 | float u_0 = U0[gid]; 40 | float x_prox = XPROX[gid]; 41 | float x_min; 42 | if(u_0 < x_prox - omega) 43 | { 44 | x_min = x_prox - omega; 45 | } else if(u_0 > x_prox + omega) 46 | { 47 | x_min = x_prox + omega; 48 | } else 49 | { 50 | 51 | x_min = u_0; 52 | // Relax proper proximal 53 | // x_min = x_prox; 54 | } 55 | XPROX[gid] = x_min; 56 | } 57 | //==============================END proximal.cl===================================== 58 | -------------------------------------------------------------------------------- /include/Watches.hpp: -------------------------------------------------------------------------------- 1 | #include "stringFormatter.h" 2 | #include 3 | 4 | namespace KCT { 5 | 6 | class Watches 7 | { 8 | public: 9 | Watches() 10 | { 11 | using namespace std::chrono; 12 | timestamp = high_resolution_clock::now(); 13 | // high_resolution 14 | } 15 | 16 | void reset() 17 | { 18 | using namespace std::chrono; 19 | timestamp = high_resolution_clock::now(); 20 | } 21 | 22 | bool pressed = false; 23 | std::chrono::time_point lastTime; 24 | std::chrono::time_point now; 25 | std::chrono::time_point timestamp; 26 | 27 | std::string textWithTimeFromLastReset(std::string txt = "") 28 | { 29 | std::chrono::milliseconds ms = millisecondsFromTimestamp(false); 30 | float milliSeconds = ms.count() / 1000.0; 31 | std::string msg = io::xprintf("%s %0.2f", txt.c_str(), milliSeconds); 32 | return msg; 33 | } 34 | 35 | std::chrono::milliseconds millisecondsFromTimestamp(bool setNewTimestamp) 36 | { 37 | std::chrono::milliseconds ms = std::chrono::duration_cast( 38 | std::chrono::high_resolution_clock::now() - timestamp); 39 | if(setNewTimestamp) 40 | { 41 | reset(); 42 | } 43 | return ms; 44 | } 45 | 46 | void press(std::string txt = "") 47 | { 48 | using namespace std::chrono; 49 | if(!pressed) 50 | { 51 | pressed = true; 52 | LOGI << io::xprintf("%s", txt.c_str()); 53 | lastTime = high_resolution_clock::now(); 54 | } else 55 | { 56 | now = high_resolution_clock::now(); 57 | duration xxx = duration_cast>(now - lastTime); 58 | LOGI << io::xprintf("%s %0.3fs", txt.c_str(), xxx.count()); 59 | lastTime = now; 60 | } 61 | }; 62 | 63 | void pressE(std::string txt = "") 64 | { 65 | using namespace std::chrono; 66 | if(!pressed) 67 | { 68 | pressed = true; 69 | LOGE << io::xprintf("%s", txt.c_str()); 70 | lastTime = high_resolution_clock::now(); 71 | } else 72 | { 73 | now = high_resolution_clock::now(); 74 | duration xxx = duration_cast>(now - lastTime); 75 | LOGE << io::xprintf("%s %0.3fs", txt.c_str(), xxx.count()); 76 | lastTime = now; 77 | } 78 | }; 79 | }; 80 | } // namespace KCT 81 | -------------------------------------------------------------------------------- /cmake/FindMKL.cmake: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # 3 | # \file cmake/FindMKL.cmake 4 | # \author J. Bakosi 5 | # \copyright 2012-2015, Jozsef Bakosi, 2016, Los Alamos National Security, LLC. 6 | # \brief Find the Math Kernel Library from Intel 7 | # \date Thu 26 Jan 2017 02:05:50 PM MST 8 | # 9 | ################################################################################ 10 | 11 | # Find the Math Kernel Library from Intel 12 | # 13 | # MKL_FOUND - System has MKL 14 | # MKL_INCLUDE_DIRS - MKL include files directories 15 | # MKL_LIBRARIES - The MKL libraries 16 | # MKL_INTERFACE_LIBRARY - MKL interface library 17 | # MKL_SEQUENTIAL_LAYER_LIBRARY - MKL sequential layer library 18 | # MKL_CORE_LIBRARY - MKL core library 19 | # 20 | # The environment variables MKLROOT and INTEL are used to find the library. 21 | # Everything else is ignored. If MKL is found "-DMKL_ILP64" is added to 22 | # CMAKE_C_FLAGS and CMAKE_CXX_FLAGS. 23 | # 24 | # Example usage: 25 | # 26 | # find_package(MKL) 27 | # if(MKL_FOUND) 28 | # target_link_libraries(TARGET ${MKL_LIBRARIES}) 29 | # endif() 30 | 31 | # If already in cache, be silent 32 | if (MKL_INCLUDE_DIRS AND MKL_LIBRARIES AND MKL_INTERFACE_LIBRARY AND 33 | MKL_SEQUENTIAL_LAYER_LIBRARY AND MKL_CORE_LIBRARY) 34 | set (MKL_FIND_QUIETLY TRUE) 35 | endif() 36 | 37 | if(NOT BUILD_SHARED_LIBS) 38 | #set(COR_LIB "libmkl_core.a") 39 | set(COR_LIB "libmkl_rt.so") 40 | else() 41 | set(COR_LIB "libmkl_rt.so") 42 | endif() 43 | 44 | find_path(MKL_INCLUDE_DIR NAMES mkl_lapacke.h HINTS /opt/intel/compilers_and_libraries_2019.4.243/linux/mkl/include /opt/intel/compilers_and_libraries_2019.0.117/linux/mkl/includei /opt/intel/mkl/include /usr/include/mkl $ENV{HOME}/opt/MKL/2022/mkl/2022.0.1/include /opt/intel/oneapi/mkl/2023.1.0/include) 45 | set(MKL_INCLUDE_DIRS ${MKL_INCLUDE_DIR}) 46 | message("Found MKL_INCLUDE_DIRS ${MKL_INCLUDE_DIR}") 47 | get_filename_component(MKL_BASE_DIR ${MKL_INCLUDE_DIR} DIRECTORY) 48 | 49 | find_library(MKL_CORE_LIBRARY 50 | NAMES ${COR_LIB} 51 | PATHS ${MKL_BASE_DIR}/lib/intel64_lin/ /lib/x86_64-linux-gnu/ ${MKL_BASE_DIR}/lib/intel64/ 52 | NO_DEFAULT_PATH) 53 | #Seems that in the oneapi version MKL routines also depend on library in oneapi/compiler/2023.1.0/linux/compiler/lib/intel64_lin/ so in troubles try ldconfig with this path 54 | #It might be necessary to create /etc/ld.so.conf.d/intel.conf with the following content 55 | ##Intel MKL 56 | #/opt/intel/oneapi/compiler/2023.1.0/linux/compiler/lib/intel64_lin/ 57 | #/opt/intel/oneapi/mkl/2023.1.0/lib/intel64/ 58 | 59 | 60 | set(MKL_LIBRARIES ${MKL_CORE_LIBRARY}) 61 | 62 | # Handle the QUIETLY and REQUIRED arguments and set MKL_FOUND to TRUE if 63 | # all listed variables are TRUE. 64 | INCLUDE(FindPackageHandleStandardArgs) 65 | FIND_PACKAGE_HANDLE_STANDARD_ARGS(MKL DEFAULT_MSG MKL_LIBRARIES MKL_INCLUDE_DIRS MKL_CORE_LIBRARY) 66 | 67 | MARK_AS_ADVANCED(MKL_INCLUDE_DIRS MKL_LIBRARIES MKL_CORE_LIBRARY) 68 | -------------------------------------------------------------------------------- /include/BasePBCT2DReconstructor.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Logging 4 | #include "PLOG/PlogSetup.h" 5 | 6 | // External libraries 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // Internal libraries 13 | #include "AlgorithmsBarrierBuffers.hpp" 14 | #include "BackprojectorScalingMethod.hpp" 15 | #include "BasePBCT2DOperator.hpp" 16 | #include "BufferedFrame2D.hpp" 17 | #include "DEN/DenAsyncFrame2DWritter.hpp" 18 | #include "DEN/DenProjectionMatrixReader.hpp" 19 | #include "Kniha.hpp" 20 | #include "MATRIX/utils.hpp" 21 | #include "OPENCL/OpenCLManager.hpp" 22 | #include "rawop.h" 23 | #include "stringFormatter.h" 24 | 25 | using namespace KCT::matrix; 26 | namespace KCT { 27 | 28 | class BasePBCT2DReconstructor : public virtual BasePBCT2DOperator 29 | { 30 | public: 31 | BasePBCT2DReconstructor(uint32_t pdimx, 32 | uint32_t pdimy, 33 | uint32_t pdimz, 34 | uint32_t vdimx, 35 | uint32_t vdimy, 36 | uint32_t vdimz, 37 | uint32_t workGroupSize = 256) 38 | : BasePBCT2DOperator(pdimx, pdimy, pdimz, vdimx, vdimy, vdimz, workGroupSize) 39 | { 40 | } 41 | 42 | virtual ~BasePBCT2DReconstructor() = default; 43 | 44 | virtual int reconstruct(uint32_t maxItterations, float minDiscrepancyError) = 0; 45 | 46 | /** 47 | * Simple method to test projector simply project x_buf containing volume array using currect 48 | * projector and writes result to projection array. 49 | */ 50 | void simpleProjection(); 51 | /** 52 | * Simple method to test backprojector simply backproject b_buf containing projection array 53 | * using currect backprojector and writes result to volume array. 54 | * 55 | * @param naturalBackprojectionScaling Multiply output by pi / (pdimx * pdimz) 56 | */ 57 | void simpleBackprojection(BackprojectorScalingMethod scalingType 58 | = BackprojectorScalingMethod::NoScaling); 59 | 60 | void setReportingParameters(bool verbose, 61 | uint32_t reportKthIteration = 0, 62 | std::string intermediatePrefix = ""); 63 | int initializeVectors(float* projection, float* volume, bool volumeContainsX0); 64 | double adjointProductTest(); 65 | 66 | protected: 67 | // OpenCL buffers 68 | std::shared_ptr b_buf = nullptr; 69 | std::shared_ptr x_buf = nullptr; 70 | // tmp_b_buf for rescaling, tmp_x_buf for LSQR 71 | std::shared_ptr tmp_x_buf = nullptr, tmp_b_buf = nullptr; 72 | float* x = nullptr; // Volume data 73 | float* b = nullptr; // Projection data 74 | 75 | uint32_t reportKthIteration = 0; 76 | // Auxiliary functions 77 | void writeVolume(cl::Buffer& X, std::string path); 78 | void writeProjections(cl::Buffer& B, std::string path); 79 | }; 80 | 81 | } // namespace KCT 82 | -------------------------------------------------------------------------------- /opencl/centerVoxelProjector.cl: -------------------------------------------------------------------------------- 1 | //==============================centerVoxelProjector.cl===================================== 2 | int volIndex(int* i, int* j, int* k, int3* vdims) 3 | { 4 | return (*i) + (*j) * vdims->x + (*k) * (vdims->x * vdims->y); 5 | } 6 | 7 | /** Project given volume using cutting voxel projector. 8 | * 9 | * 10 | * @param volume Volume to project. 11 | * @param projection Projection to construct. 12 | * @param PM Projection matrix. This projection matrix is constructed in the way that (i,j,k) = 13 | * (0,0,0,1) is projected to the center of the voxel with given coordinates. 14 | * @param sourcePosition Source position in the xyz space. 15 | * @param normalToDetector Normal to detector in the (i,j,k) space. 16 | * @param vdims Dimensions of the volume. 17 | * @param voxelSizes Lengths of the voxel edges. 18 | * @param pdims Dimensions of the projection. 19 | * @param scalingFactor Scale the results by this factor. 20 | * 21 | * @return 22 | */ 23 | void kernel FLOATcenter_voxel_project(global const float* restrict volume, 24 | global float* restrict projection, 25 | private uint projectionOffset, 26 | private double16 PM, 27 | private double3 sourcePosition, 28 | private double3 normalToDetector, 29 | private int3 vdims, 30 | private double3 voxelSizes, 31 | private double3 volumeCenter, 32 | private int2 pdims, 33 | private float scalingFactor) 34 | { 35 | int i = get_global_id(2); 36 | int j = get_global_id(1); 37 | int k = get_global_id(0); // This is more effective from the perspective of atomic colisions 38 | const double3 IND_ijk = { (double)(i), (double)(j), (double)(k), 0.0 }; 39 | const double3 zerocorner_xyz = { volumeCenter.x - 0.5 * (double)vdims.x * voxelSizes.x, 40 | volumeCenter.y - 0.5 * (double)vdims.y * voxelSizes.y, 41 | volumeCenter.z - 0.5 * (double)vdims.z * voxelSizes.z }; 42 | const double3 voxelcenter_xyz = zerocorner_xyz 43 | + ((IND_ijk + 0.5) * voxelSizes); // Using widening and vector multiplication operations 44 | int ind = projectionIndex(PM, voxelcenter_xyz, pdims); 45 | if(ind != -1) 46 | { 47 | int VINDEX = volIndex(&i, &j, &k, &vdims); 48 | float voxelValue = volume[VINDEX]; 49 | double3 sourceToVoxel_xyz = voxelcenter_xyz - sourcePosition; 50 | double sourceToVoxel_xyz_norm = length(sourceToVoxel_xyz); 51 | double cosine = dot(normalToDetector, sourceToVoxel_xyz) / sourceToVoxel_xyz_norm; 52 | double cosPowThree = cosine * cosine * cosine; 53 | float value = voxelValue * scalingFactor 54 | / (sourceToVoxel_xyz_norm * sourceToVoxel_xyz_norm * cosPowThree); 55 | AtomicAdd_g_f(&projection[projectionOffset + ind], 56 | value); // Atomic version of projection[ind] += value; 57 | } 58 | } 59 | //==============================END centerVoxelProjector.cl===================================== 60 | -------------------------------------------------------------------------------- /src/mergeFiles.cpp: -------------------------------------------------------------------------------- 1 | // Logging 2 | #include "PLOG/PlogSetup.h" 3 | 4 | // External libraries 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // External libraries 13 | #include "CLI/CLI.hpp" //Command line parser 14 | #include "ctpl_stl.h" //Threadpool 15 | 16 | // Internal libraries 17 | #include "SMA/BufferedSparseMatrixFloatReader.hpp" 18 | #include "SMA/BufferedSparseMatrixFloatWritter.hpp" 19 | 20 | using namespace KCT; 21 | 22 | int main(int argc, char* argv[]) 23 | { 24 | plog::Severity verbosityLevel = plog::debug; // Set to debug to see the 25 | // debug messages, info 26 | // messages 27 | std::string csvLogFile = "/tmp/dacprojector.csv"; // Set NULL to disable 28 | bool logToConsole = true; 29 | plog::PlogSetup plogSetup(verbosityLevel, csvLogFile, logToConsole); 30 | plogSetup.initLogging(); 31 | LOGI << "sortsortsort"; 32 | // Argument parsing 33 | std::vector a_unsortedDoubles; 34 | std::string a_sortedFloat; 35 | CLI::App app{ "Using divide and conquer techniques to construct CT system matrix.." }; 36 | app.add_option("sorted_float", a_sortedFloat, 37 | "Files in a DEN format to process. These files represents projection matrices.") 38 | ->required() 39 | ->check(CLI::NonexistentPath); 40 | app.add_option("unsorted_double", a_unsortedDoubles, 41 | "File in a sparse matrix format to output.") 42 | ->required() 43 | ->check(CLI::ExistingFile); 44 | app.parse(argc, argv); 45 | // Frames to process 46 | std::vector> readers; 47 | for(std::string const& v : a_unsortedDoubles) 48 | { 49 | std::shared_ptr r 50 | = std::make_shared(v, 16384); 51 | readers.push_back(r); 52 | } 53 | matrix::BufferedSparseMatrixFloatWritter output(a_sortedFloat, 16384); 54 | 55 | // Find the minimum value of i in a readers 56 | int mink = 0; 57 | uint32_t i, j; 58 | float v; 59 | while(true) 60 | { 61 | uint32_t mini = 256 * 256 * 199; 62 | for(std::size_t k = 0; k != a_unsortedDoubles.size(); k++) 63 | { 64 | readers[k]->getNextValue(&i, &j, &v); 65 | if(i < mini) 66 | { 67 | mini = i; 68 | mink = k; 69 | } 70 | } 71 | if(mini == 256 * 256 * 199) 72 | { 73 | for(std::size_t k = 0; k != a_unsortedDoubles.size(); k++) 74 | { 75 | if(!readers[k]->atEnd()) 76 | { 77 | LOGD << io::xprintf("Not at end in %s.", a_unsortedDoubles[k].c_str()); 78 | } 79 | } 80 | break; 81 | } 82 | while(true) 83 | { 84 | readers[mink]->getNextValue(&i, &j, &v); 85 | if(i == mini) 86 | { 87 | output.insertValue(i, j, v); 88 | readers[mink]->increaseCounter(); 89 | } else 90 | { 91 | break; 92 | } 93 | } 94 | } 95 | output.flush(); 96 | LOGI << "END"; 97 | } 98 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | # BasedOnStyle: WebKit 4 | AccessModifierOffset: -4 5 | AlignAfterOpenBracket: Align 6 | AlignConsecutiveAssignments: false 7 | AlignConsecutiveDeclarations: false 8 | AlignEscapedNewlines: Right 9 | AlignOperands: false 10 | AlignTrailingComments: false 11 | AllowAllParametersOfDeclarationOnNextLine: true 12 | AllowShortBlocksOnASingleLine: false 13 | AllowShortCaseLabelsOnASingleLine: false 14 | AllowShortFunctionsOnASingleLine: All 15 | AllowShortIfStatementsOnASingleLine: false 16 | AllowShortLoopsOnASingleLine: false 17 | AlwaysBreakAfterDefinitionReturnType: None 18 | AlwaysBreakAfterReturnType: None 19 | AlwaysBreakBeforeMultilineStrings: false 20 | AlwaysBreakTemplateDeclarations: true 21 | BinPackArguments: true 22 | BinPackParameters: false 23 | BraceWrapping: 24 | AfterClass: true 25 | AfterControlStatement: true 26 | AfterEnum: false 27 | AfterFunction: true 28 | AfterNamespace: false 29 | AfterObjCDeclaration: false 30 | AfterStruct: true 31 | AfterUnion: true 32 | BeforeCatch: false 33 | BeforeElse: false 34 | IndentBraces: false 35 | SplitEmptyFunction: true 36 | SplitEmptyRecord: true 37 | SplitEmptyNamespace: true 38 | BreakBeforeBinaryOperators: All 39 | BreakBeforeBraces: Custom 40 | BreakBeforeInheritanceComma: false 41 | BreakBeforeTernaryOperators: true 42 | BreakConstructorInitializersBeforeComma: false 43 | BreakConstructorInitializers: BeforeComma 44 | BreakAfterJavaFieldAnnotations: false 45 | BreakStringLiterals: true 46 | ColumnLimit: 150 47 | CommentPragmas: '^ IWYU pragma:' 48 | CompactNamespaces: false 49 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 50 | ConstructorInitializerIndentWidth: 4 51 | ContinuationIndentWidth: 4 52 | Cpp11BracedListStyle: false 53 | DerivePointerAlignment: false 54 | DisableFormat: false 55 | ExperimentalAutoDetectBinPacking: false 56 | FixNamespaceComments: true 57 | ForEachMacros: 58 | - foreach 59 | - Q_FOREACH 60 | - BOOST_FOREACH 61 | IncludeCategories: 62 | - Regex: '^"(llvm|llvm-c|clang|clang-c)/' 63 | Priority: 2 64 | - Regex: '^(<|"(gtest|gmock|isl|json)/)' 65 | Priority: 3 66 | - Regex: '.*' 67 | Priority: 1 68 | IncludeIsMainRegex: '(Test)?$' 69 | IndentCaseLabels: false 70 | IndentWidth: 4 71 | IndentWrappedFunctionNames: false 72 | JavaScriptQuotes: Leave 73 | JavaScriptWrapImports: true 74 | KeepEmptyLinesAtTheStartOfBlocks: true 75 | MacroBlockBegin: '' 76 | MacroBlockEnd: '' 77 | MaxEmptyLinesToKeep: 1 78 | NamespaceIndentation: Inner 79 | ObjCBlockIndentWidth: 4 80 | ObjCSpaceAfterProperty: true 81 | ObjCSpaceBeforeProtocolList: true 82 | PenaltyBreakAssignment: 2 83 | PenaltyBreakBeforeFirstCallParameter: 19 84 | PenaltyBreakComment: 300 85 | PenaltyBreakFirstLessLess: 120 86 | PenaltyBreakString: 1000 87 | PenaltyExcessCharacter: 1000000 88 | PenaltyReturnTypeOnItsOwnLine: 60 89 | PointerAlignment: Left 90 | ReflowComments: true 91 | SortIncludes: true 92 | SortUsingDeclarations: true 93 | SpaceAfterCStyleCast: false 94 | SpaceAfterTemplateKeyword: true 95 | SpaceBeforeAssignmentOperators: true 96 | SpaceBeforeParens: Never 97 | SpaceInEmptyParentheses: false 98 | SpacesBeforeTrailingComments: 1 99 | SpacesInAngles: false 100 | SpacesInContainerLiterals: true 101 | SpacesInCStyleCastParentheses: false 102 | SpacesInParentheses: false 103 | SpacesInSquareBrackets: false 104 | Standard: Cpp11 105 | TabWidth: 8 106 | UseTab: Never 107 | ... 108 | -------------------------------------------------------------------------------- /src/BasePBCTReconstructor.cpp: -------------------------------------------------------------------------------- 1 | #include "BasePBCTReconstructor.hpp" 2 | 3 | namespace KCT { 4 | 5 | /** 6 | * @brief 7 | * 8 | * @param projections The b vector to invert. 9 | * @param volume Allocated memory to store x. Might contain the initial guess. 10 | * 11 | * @return 12 | */ 13 | int BasePBCTReconstructor::initializeVectors(float* projections, 14 | float* volume, 15 | bool useVolumeAsInitialX0) 16 | { 17 | this->useVolumeAsInitialX0 = useVolumeAsInitialX0; 18 | this->b = projections; 19 | this->x = volume; 20 | cl_int err; 21 | 22 | // Initialize buffers 23 | if(useVolumeAsInitialX0) 24 | { 25 | x_buf = std::make_shared(*context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, 26 | sizeof(float) * XDIM, (void*)volume, &err); 27 | } else 28 | { 29 | x_buf = std::make_shared(*context, CL_MEM_READ_WRITE, sizeof(float) * XDIM, 30 | nullptr, &err); 31 | } 32 | if(err != CL_SUCCESS) 33 | { 34 | LOGE << io::xprintf("Unsucessful initialization of buffer with error code %d!", err); 35 | return -1; 36 | } 37 | size_t BDIM_bs = sizeof(float) * uint64_t(BDIM); 38 | b_buf = std::make_shared(*context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, BDIM_bs, 39 | (void*)projections, &err); 40 | if(err != CL_SUCCESS) 41 | { 42 | LOGE << io::xprintf("Unsucessful initialization of buffer with error code %d!", err); 43 | return -1; 44 | } 45 | tmp_b_buf = std::make_shared(*context, CL_MEM_READ_WRITE, BDIM_bs, nullptr, &err); 46 | if(err != CL_SUCCESS) 47 | { 48 | LOGE << io::xprintf("Unsucessful initialization of buffer with error code %d!", err); 49 | return -1; 50 | } 51 | return 0; 52 | } 53 | 54 | void BasePBCTReconstructor::writeVolume(cl::Buffer& X, std::string path) 55 | { 56 | bufferIntoArray(X, x, XDIM); 57 | bool arrayxmajor = true; 58 | bool outxmajor = true; 59 | io::DenFileInfo::create3DDenFileFromArray(x, arrayxmajor, path, io::DenSupportedType::FLOAT32, 60 | vdimx, vdimy, vdimz, outxmajor); 61 | } 62 | 63 | void BasePBCTReconstructor::writeProjections(cl::Buffer& B, std::string path) 64 | { 65 | bufferIntoArray(B, b, BDIM); 66 | bool arrayxmajor = false; 67 | bool outxmajor = true; 68 | io::DenFileInfo::create3DDenFileFromArray(b, arrayxmajor, path, io::DenSupportedType::FLOAT32, 69 | pdimx, pdimy, pdimz, outxmajor); 70 | } 71 | 72 | void BasePBCTReconstructor::setReportingParameters(bool verbose, 73 | uint32_t reportKthIteration, 74 | std::string intermediatePrefix) 75 | { 76 | this->verbose = verbose; 77 | this->reportKthIteration = reportKthIteration; 78 | this->intermediatePrefix = intermediatePrefix; 79 | } 80 | 81 | double BasePBCTReconstructor::adjointProductTest() 82 | { 83 | std::shared_ptr xa_buf; // X buffers 84 | allocateXBuffers(1); 85 | xa_buf = getXBuffer(0); 86 | allocateBBuffers(1); 87 | std::shared_ptr ba_buf; // B buffers 88 | ba_buf = getBBuffer(0); 89 | project(*x_buf, *ba_buf); 90 | backproject(*b_buf, *xa_buf); 91 | double bdotAx = scalarProductBBuffer_barrier_double(*b_buf, *ba_buf); 92 | double ATbdotx = scalarProductXBuffer_barrier_double(*x_buf, *xa_buf); 93 | return (bdotAx / ATbdotx); 94 | } 95 | } // namespace KCT 96 | -------------------------------------------------------------------------------- /include/BaseROFOperator.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // External libraries 4 | #include 5 | #include 6 | #include 7 | 8 | // Internal libraries 9 | #include "AlgorithmsBarrierBuffers.hpp" 10 | #include "BasePBCTOperator.hpp" // Assuming this contains useful base operator methods 11 | #include "GradientType.hpp" 12 | 13 | namespace KCT { 14 | 15 | class BaseROFOperator : public virtual Kniha, public AlgorithmsBarrierBuffers 16 | { 17 | public: 18 | BaseROFOperator(uint32_t vdimx, uint32_t vdimy, uint32_t vdimz, uint32_t workGroupSize = 256) 19 | : AlgorithmsBarrierBuffers(0, 0, 0, vdimx, vdimy, vdimz, workGroupSize) 20 | , workGroupSize(workGroupSize) 21 | , vdimx(vdimx) 22 | , vdimy(vdimy) 23 | , vdimz(vdimz) 24 | { 25 | XDIM = static_cast(vdimx) * static_cast(vdimy) 26 | * static_cast(vdimz); 27 | vdims = cl_int3({ int(vdimx), int(vdimy), int(vdimz) }); 28 | timestamp = std::chrono::steady_clock::now(); 29 | } 30 | 31 | virtual int reconstruct(float mu, 32 | float tau, 33 | float sigma, 34 | float theta, 35 | uint32_t maxPDHGIterations, 36 | float errConditionPDHG) 37 | = 0; 38 | 39 | int initializeVolume(float* volume); 40 | 41 | void initializeVolumeConvolution(); 42 | void initializeProximal(); 43 | void initializeGradient(); 44 | 45 | void setTimestamp(bool finishCommandQueue); 46 | 47 | int initializeOpenCL(uint32_t platformID, 48 | uint32_t* deviceIds, 49 | uint32_t deviceIdsLength, 50 | std::string xpath, 51 | bool debug, 52 | bool relaxed); 53 | 54 | int problemSetup(double voxelSpacingX, double voxelSpacingY, double voxelSpacingZ); 55 | 56 | int volume_gradient2D(cl::Buffer& F, cl::Buffer& GX, cl::Buffer& GY); 57 | 58 | int volume_gradient2D_adjoint(cl::Buffer& GX, cl::Buffer& GY, cl::Buffer& D); 59 | 60 | std::chrono::milliseconds millisecondsFromTimestamp(bool setNewTimestamp); 61 | 62 | std::string printTime(std::string msg, bool finishCommandQueue, bool setNewTimestamp); 63 | 64 | void reportTime(std::string msg, bool finishCommandQueue, bool setNewTimestamp); 65 | void setVerbose(bool verbose, std::string intermediatePrefix); 66 | void setReportingParameters(bool verbose, 67 | uint32_t reportKthIteration, 68 | std::string intermediatePrefix); 69 | 70 | void setGradientType(GradientType type); 71 | 72 | protected: 73 | const uint32_t workGroupSize; 74 | const uint32_t vdimx, vdimy, vdimz; 75 | float* x = nullptr; 76 | double voxelSpacingX, voxelSpacingY, voxelSpacingZ; 77 | cl_double3 voxelSizes; 78 | cl_float3 voxelSizesF; 79 | GradientType useGradientType; 80 | 81 | std::shared_ptr x_buf = nullptr; 82 | std::shared_ptr tmp_x_buf = nullptr; 83 | std::vector> x_buffers, tmp_x_buffers; 84 | 85 | void writeVolume(cl::Buffer& X, const std::string& path); 86 | 87 | uint64_t XDIM; 88 | cl_int3 vdims; 89 | std::chrono::time_point timestamp; 90 | 91 | bool verbose = false; 92 | std::string intermediatePrefix = ""; 93 | uint32_t reportKthIteration = 0; 94 | 95 | int allocateXBuffers(uint32_t xBufferCount); 96 | std::shared_ptr getXBuffer(uint32_t i); 97 | 98 | private: 99 | bool gradientInitialized = false; 100 | }; 101 | 102 | } // namespace KCT 103 | -------------------------------------------------------------------------------- /include/PDHGPBCT2DReconstructor.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Logging 4 | #include "PLOG/PlogSetup.h" 5 | 6 | // External libraries 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // Internal libraries 13 | #include "BasePBCT2DReconstructor.hpp" 14 | #include "DEN/DenProjectionMatrixReader.hpp" 15 | #include "GEOMETRY/Geometry3DParallel.hpp" 16 | #include "GEOMETRY/Geometry3DParallelI.hpp" 17 | #include "OPENCL/OpenCLManager.hpp" 18 | #include "rawop.h" 19 | #include "stringFormatter.h" 20 | 21 | namespace KCT { 22 | 23 | class PDHGPBCT2DReconstructor : virtual public BasePBCT2DReconstructor 24 | { 25 | public: 26 | /** 27 | * Initialize Cutting Voxel Projector 28 | * 29 | * @param volume Pointer to volume file 30 | * @param vdimx Volume x dimension 31 | * @param vdimy Volume y dimension 32 | * @param vdimz Volume z dimension 33 | * @param xpath Path of cl kernel files 34 | * @param debug Should debugging be used by suppliing source and -g as options 35 | */ 36 | PDHGPBCT2DReconstructor(uint32_t pdimx, 37 | uint32_t pdimy, 38 | uint32_t pdimz, 39 | uint32_t vdimx, 40 | uint32_t vdimy, 41 | uint32_t vdimz, 42 | uint32_t workGroupSize = 256) 43 | : BasePBCT2DOperator(pdimx, pdimy, pdimz, vdimx, vdimy, vdimz, workGroupSize) 44 | , BasePBCT2DReconstructor(pdimx, pdimy, pdimz, vdimx, vdimy, vdimz, workGroupSize) 45 | 46 | { 47 | } 48 | 49 | virtual int reconstruct(uint32_t maxIterations = 100, float errCondition = 0.01); 50 | 51 | int reconstruct(float lambda, 52 | float tau, 53 | float sigma, 54 | float theta, 55 | uint32_t maxPDHGIterations = 100, 56 | float errConditionPDHG = 0.01, 57 | uint32_t maxCGLSIterations = 100, 58 | float errConditionCGLS = 0.01); 59 | 60 | private: 61 | /** 62 | * CGLS proximal operator solving problem 63 | * min_x 1 / (2 * tau) ||x-x_prox||_2^2 + ||Ax - b||_2^2 by means of CGLS based approximation. 64 | * The pointers might point to the same buffer or three different buffers. It is also admissible 65 | * that xbufIN_x_prox and xbufIN_x0 are not equal and xbufOUT is one of them. The procedure will 66 | * handle these situations. 67 | * 68 | * @param xbufIN_x_prox Proximal vector 69 | * @param xbufIN_x0 Initial vector 70 | * @param xbufOUT Output vector 71 | * @param tau Regularization parameter for proximal operator 72 | * @param maxCGLSIterations Maximum number of CGLS iterations 73 | * @param errConditionCGLS Error condition for CGLS 74 | * @param outerIterationIndex Index of the outer iteration for logging purposes 75 | * 76 | * @return 77 | */ 78 | int proximalOperatorCGLS(std::shared_ptr xbufIN_x_prox, 79 | std::shared_ptr xbufIN_x0, 80 | std::shared_ptr xbufOUT, 81 | float tau, 82 | uint32_t maxCGLSIterations = 100, 83 | float errConditionCGLS = 0.01, 84 | uint32_t outerIterationIndex = 0); 85 | // Add global buffers for CGLS 86 | std::shared_ptr directionVector_xbuf, residualVector_xbuf, 87 | residualVector_xbuf_L2add, discrepancy_bbuf_xpart_L2, AdirectionVector_bbuf_xpart_L2; 88 | std::shared_ptr discrepancy_bbuf, AdirectionVector_bbuf; 89 | std::array computeSolutionNorms(std::shared_ptr x_vector, 90 | std::shared_ptr x_vector_dx, 91 | std::shared_ptr x_vector_dy, 92 | std::shared_ptr x_0 = nullptr, 93 | bool computeDiscrepancy = true); 94 | double NB0, NATB0; 95 | bool proximalOperatorVerbose = true; 96 | }; 97 | 98 | } // namespace KCT 99 | -------------------------------------------------------------------------------- /src/projectFloats.cpp: -------------------------------------------------------------------------------- 1 | // Logging 2 | #include "PLOG/PlogSetup.h" 3 | 4 | // External libraries 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // External libraries 13 | #include "CLI/CLI.hpp" //Command line parser 14 | #include "ctpl_stl.h" //Threadpool 15 | 16 | // Internal libraries 17 | #include "ARGPARSE/parseArgs.h" 18 | #include "SMA/BufferedSparseMatrixFloatReader.hpp" 19 | #include "rawop.h" 20 | 21 | using namespace KCT; 22 | 23 | int main(int argc, char* argv[]) 24 | { 25 | plog::Severity verbosityLevel = plog::debug; // Set to debug to see the 26 | // debug messages, info 27 | // messages 28 | std::string csvLogFile = "/tmp/dacprojector.csv"; // Set NULL to disable 29 | bool logToConsole = true; 30 | plog::PlogSetup plogSetup(verbosityLevel, csvLogFile, logToConsole); 31 | plogSetup.initLogging(); 32 | LOGI << "START"; 33 | // Argument parsing 34 | int a_threads = 1; 35 | // It is evaluated from -0.5, pixels are centerred at integer coordinates 36 | int projectionSizeX = 616; 37 | int projectionSizeY = 480; 38 | int projectionSizeZ = 1; 39 | // Here (0,0,0) is in the center of the volume 40 | int volumeSizeX = 256; 41 | int volumeSizeY = 256; 42 | int volumeSizeZ = 199; 43 | 44 | std::string a_inputVolume; 45 | std::string a_inputSystemMatrix; 46 | std::string a_projectionFile; 47 | 48 | CLI::App app{ "Using divide and conquer techniques to construct CT system matrix.." }; 49 | app.add_option("-j,--threads", a_threads, "Number of extra threads that application can use.") 50 | ->check(CLI::Range(1, 65535)); 51 | app.add_option("-n,--number_of_projections", projectionSizeZ, 52 | "Number of projections, defaults to 1.") 53 | ->check(CLI::Range(1, 65535)); 54 | app.add_option("input_volume", a_inputVolume, 55 | "Files in a DEN format to process. These files represents projection matrices.") 56 | ->required() 57 | ->check(CLI::ExistingFile); 58 | app.add_option("system_matrix", a_inputSystemMatrix, 59 | "Files in a DEN format to process. These files represents projection matrices.") 60 | ->required() 61 | ->check(CLI::ExistingFile); 62 | app.add_option("output_file", a_projectionFile, "File in a sparse matrix format to output.") 63 | ->required(); 64 | app.parse(argc, argv); 65 | // Frames to process 66 | int totalVolumeSize = volumeSizeX * volumeSizeY * volumeSizeZ; 67 | float* volume = new float[volumeSizeX * volumeSizeY * volumeSizeZ]; 68 | io::readBytesFrom(a_inputVolume, 6, (uint8_t*)volume, totalVolumeSize * 4); 69 | uint32_t i, j; 70 | float v; 71 | 72 | matrix::BufferedSparseMatrixFloatReader A(a_inputSystemMatrix, 16384); 73 | uint64_t elements = A.getNumberOfElements(); 74 | uint32_t totalProjectionSize = projectionSizeX * projectionSizeY * projectionSizeZ; 75 | float* projection = new float[totalProjectionSize](); // Initialized by zeros 76 | 77 | uint16_t buf[3]; 78 | buf[0] = projectionSizeY; 79 | buf[1] = projectionSizeX; 80 | buf[2] = projectionSizeZ; 81 | while(elements != 0) 82 | { 83 | A.readNextValue(&i, &j, &v); 84 | projection[j] += volume[i] * v; 85 | elements--; 86 | } /* 87 | float curvol; 88 | uint32_t previ = totalProjectionSize; 89 | while(elements != 0) 90 | { 91 | A.readNextValue(&i, &j, &v); 92 | if(i!=previ) 93 | { 94 | curvol = volume[i]; 95 | previ = i; 96 | } 97 | projection[j] += curvol * v; 98 | elements--; 99 | }*/ 100 | io::createEmptyFile(a_projectionFile, 0, true); // Try if this is faster 101 | io::appendBytes(a_projectionFile, (uint8_t*)buf, 6); 102 | io::appendBytes(a_projectionFile, (uint8_t*)projection, totalProjectionSize * 4); 103 | delete[] volume; 104 | delete[] projection; 105 | LOGI << "END"; 106 | } 107 | -------------------------------------------------------------------------------- /opencl/rescaleProjections.cl: -------------------------------------------------------------------------------- 1 | //==============================rescaleProjections.cl===================================== 2 | /** 3 | * Scale projections by dividing by the area of the pixel times cos^3(\theta) and multiplying by f^2 4 | * 5 | * @param projection Projection buffer. 6 | * @param projectionOffset Offset of projection buffer. 7 | * @param ICM Inverse camera matrix. 8 | * @param sourcePosition 9 | * @param normalToDetector 10 | * @param pdims Dimensions of projection 11 | * @param scalingFactor f^2/pixelArea 12 | * 13 | */ 14 | void kernel FLOATrescale_projections_cos(global float* projection, 15 | private uint projectionOffset, 16 | private double16 ICM, 17 | private double3 sourcePosition, 18 | private double3 normalToDetector, 19 | private uint2 pdims, 20 | private float scalingFactor) 21 | { 22 | uint px = get_global_id(0); 23 | uint py = get_global_id(1); 24 | const uint IND = projectionOffset + px * pdims.y + py; 25 | const double4 P = { (double)px, (double)py, 1.0, 0.0 }; 26 | double4 V; // Point that will be projected to P by CM 27 | 28 | V.s0 = dot(ICM.s0123, P); 29 | V.s1 = dot(ICM.s4567, P); 30 | V.s2 = dot(ICM.s89ab, P); 31 | V.s3 = dot(ICM.scdef, P); 32 | if(fabs(V.s3) < 0.001) // This is legal operation since source is projected to (0,0,0) 33 | { 34 | V.s012 = V.s012 + sourcePosition; 35 | V.s3 = V.s3 + 1.0; 36 | } 37 | V.s0 = V.s0 / V.s3; 38 | V.s1 = V.s1 / V.s3; 39 | V.s2 = V.s2 / V.s3; 40 | double3 n = normalize(V.s012 - sourcePosition); 41 | double cosine = fabs(-dot(normalToDetector, n)); 42 | double cosPowThree = cosine * cosine * cosine; 43 | float pixelValue = projection[IND]; 44 | float value = pixelValue * scalingFactor / cosPowThree; 45 | projection[IND] = value; 46 | } 47 | 48 | /** 49 | * Scaling by dividing by the area S that is the area of the unit splhere that gets projected onto 50 | * given pixel. 51 | * 52 | * @param projection Projection buffer. 53 | * @param projectionOffset Offset of projection buffer. 54 | * @param pdims Dimensions of projection 55 | * @param normalProjection Point on the detector to that normal to the detector is projected and 56 | * where z axis of the local coordinates crosses projector. 57 | * @param pixelSizes Sizes of pixels in voxel related coordinate system. 58 | * @param sourceToDetector Length from the source to detector. 59 | * 60 | * @return 61 | */ 62 | void kernel FLOATrescale_projections_exact(global float* projection, 63 | private const uint projectionOffset, 64 | private const uint2 pdims, 65 | private const double2 normalProjection, 66 | private const double2 pixelSizes, 67 | private const double sourceToDetector) 68 | { 69 | const uint px = get_global_id(0); 70 | const uint py = get_global_id(1); 71 | const uint IND = projectionOffset + px * pdims.y + py; 72 | const double2 pxD = { px, py }; 73 | const double2 v2 = (pxD - normalProjection) * pixelSizes; 74 | const double3 v = (double3)(v2, sourceToDetector); 75 | const double3 halfpiX = { 0.5 * pixelSizes.x, 0.0, 0.0 }; 76 | const double3 halfpiY = { 0.0, 0.5 * pixelSizes.y, 0.0 }; 77 | const double3 v_A = v - halfpiX + halfpiY; 78 | const double3 v_B = v - halfpiX - halfpiY; 79 | const double3 v_C = v + halfpiX - halfpiY; 80 | const double3 v_D = v + halfpiX + halfpiY; 81 | const double3 n_AB = normalize(cross(v_A, v_B)); 82 | const double3 n_BC = normalize(cross(v_B, v_C)); 83 | const double3 n_CD = normalize(cross(v_C, v_D)); 84 | const double3 n_DA = normalize(cross(v_D, v_A)); 85 | const double S = acos(-dot(n_AB, n_BC)) + acos(-dot(n_BC, n_CD)) - acos(dot(n_CD, n_DA)) 86 | - acos(dot(n_DA, n_AB)); 87 | projection[IND] = projection[IND] / S; 88 | } 89 | //==============================END rescaleProjections.cl===================================== 90 | -------------------------------------------------------------------------------- /include/ReductionParameters.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Logging 4 | #include "PLOG/PlogSetup.h" 5 | 6 | // External libraries 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // Internal libraries 13 | #include "DEN/DenProjectionMatrixReader.hpp" 14 | #include "Kniha.hpp" 15 | #include "MATRIX/LightProjectionMatrix.hpp" 16 | #include "MATRIX/ProjectionMatrix.hpp" 17 | #include "MATRIX/utils.hpp" 18 | #include "OPENCL/OpenCLManager.hpp" 19 | #include "PROG/KCTException.hpp" 20 | #include "rawop.h" 21 | #include "stringFormatter.h" 22 | 23 | namespace KCT { 24 | 25 | class ReductionParameters 26 | { 27 | public: 28 | const uint32_t UINT32_MAXXX = ((uint32_t)-1); 29 | const uint32_t pdimx, pdimy, pdimz, vdimx, vdimy, vdimz; 30 | const uint32_t workGroupSize; 31 | uint32_t pFrameSize, vFrameSize; 32 | uint64_t XDIM, BDIM, XDIM_ALIGNED, BDIM_ALIGNED, XDIM_REDUCED1, BDIM_REDUCED1, 33 | XDIM_REDUCED1_ALIGNED, BDIM_REDUCED1_ALIGNED, XDIM_REDUCED2, BDIM_REDUCED2, 34 | XDIM_REDUCED2_ALIGNED, BDIM_REDUCED2_ALIGNED; 35 | uint64_t DIM_REDUCED1_MIN, DIM_REDUCED2_MIN; 36 | uint64_t BYTESIZE_REDUCED1_MIN, BYTESIZE_REDUCED2_MIN; 37 | 38 | ReductionParameters(uint32_t pdimx, 39 | uint32_t pdimy, 40 | uint32_t pdimz, 41 | uint32_t vdimx, 42 | uint32_t vdimy, 43 | uint32_t vdimz, 44 | uint32_t workGroupSize = 256) 45 | : pdimx(pdimx) 46 | , pdimy(pdimy) 47 | , pdimz(pdimz) 48 | , vdimx(vdimx) 49 | , vdimy(vdimy) 50 | , vdimz(vdimz) 51 | , workGroupSize(workGroupSize) 52 | { 53 | XDIM = uint64_t(vdimx) * uint64_t(vdimy) * uint64_t(vdimz); 54 | BDIM = uint64_t(pdimx) * uint64_t(pdimy) * uint64_t(pdimz); 55 | vFrameSize = computeFrameSize(vdimx, vdimy); 56 | pFrameSize = computeFrameSize(pdimx, pdimy); 57 | XDIM_ALIGNED = XDIM + (workGroupSize - XDIM % workGroupSize) % workGroupSize; 58 | BDIM_ALIGNED = BDIM + (workGroupSize - BDIM % workGroupSize) % workGroupSize; 59 | XDIM_REDUCED1 = XDIM_ALIGNED / workGroupSize; // It is divisible by design 60 | BDIM_REDUCED1 = BDIM_ALIGNED / workGroupSize; 61 | XDIM_REDUCED1_ALIGNED 62 | = XDIM_REDUCED1 + (workGroupSize - XDIM_REDUCED1 % workGroupSize) % workGroupSize; 63 | BDIM_REDUCED1_ALIGNED 64 | = BDIM_REDUCED1 + (workGroupSize - BDIM_REDUCED1 % workGroupSize) % workGroupSize; 65 | XDIM_REDUCED2 = XDIM_REDUCED1_ALIGNED / workGroupSize; 66 | BDIM_REDUCED2 = BDIM_REDUCED1_ALIGNED / workGroupSize; 67 | XDIM_REDUCED2_ALIGNED 68 | = XDIM_REDUCED2 + (workGroupSize - XDIM_REDUCED2 % workGroupSize) % workGroupSize; 69 | BDIM_REDUCED2_ALIGNED 70 | = BDIM_REDUCED2 + (workGroupSize - BDIM_REDUCED2 % workGroupSize) % workGroupSize; 71 | if(XDIM > BDIM) 72 | { 73 | DIM_REDUCED1_MIN = XDIM_REDUCED1; 74 | DIM_REDUCED2_MIN = XDIM_REDUCED2; 75 | } else 76 | { 77 | DIM_REDUCED1_MIN = BDIM_REDUCED1; 78 | DIM_REDUCED2_MIN = BDIM_REDUCED2; 79 | } 80 | // For non-barier reduction algorithms to work 81 | if(DIM_REDUCED1_MIN < pdimz) 82 | { 83 | DIM_REDUCED1_MIN = pdimz; 84 | } 85 | if(DIM_REDUCED1_MIN < vdimz) 86 | { 87 | DIM_REDUCED1_MIN = vdimz; 88 | } 89 | BYTESIZE_REDUCED1_MIN = sizeof(double) * DIM_REDUCED1_MIN; 90 | BYTESIZE_REDUCED2_MIN = sizeof(double) * DIM_REDUCED2_MIN; 91 | } 92 | 93 | private: 94 | uint32_t computeFrameSize(uint32_t dx, uint32_t dy) 95 | { 96 | uint64_t fs = (uint64_t)dx * (uint64_t)dy; 97 | std::string err; 98 | if(fs > UINT32_MAXXX) 99 | { 100 | err = io::xprintf( 101 | "Algorithms for reduction are based on the assumption that frameSize=%lu fits into " 102 | "UINT32_MAXXX=%lu, but it is not the case here.", 103 | fs, UINT32_MAXXX); 104 | KCTERR(err); 105 | } 106 | return (uint32_t)fs; 107 | } 108 | }; 109 | 110 | } // namespace KCT 111 | -------------------------------------------------------------------------------- /include/CArmArguments.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | #include "OPENCL/OpenCLManager.hpp" 7 | #include "PROG/Arguments.hpp" 8 | #include "rawop.h" 9 | 10 | namespace KCT::util { 11 | 12 | class CArmArguments : public virtual Arguments 13 | { 14 | public: 15 | // Dimensions 16 | CLI::Option_group* og_geometry = nullptr; 17 | uint32_t volumeSizeX = 256; 18 | uint32_t volumeSizeY = 256; 19 | uint32_t volumeSizeZ = 199; 20 | uint32_t projectionSizeX = 616; 21 | uint32_t projectionSizeY = 480; 22 | uint32_t projectionSizeZ = 248; 23 | // Discretization 24 | double voxelSizeX = 1.0; 25 | double voxelSizeY = 1.0; 26 | double voxelSizeZ = 1.0; 27 | double volumeCenterX = 0.0; 28 | double volumeCenterY = 0.0; 29 | double volumeCenterZ = 0.0; 30 | double pixelSizeX = 0.616; 31 | double pixelSizeY = 0.616; 32 | 33 | // Basis specification 34 | bool useLegendrePolynomials = false; 35 | bool useChebyshevPolynomials = false; 36 | bool useFourierBasis = false; 37 | std::string engineerBasis = ""; 38 | // Basis and timings 39 | uint32_t basisSize = 7; 40 | float pause_size = 1171; 41 | float frame_time = 16.8; 42 | float start_offset = 0.0, end_offset = 0.0; 43 | 44 | // Settings 45 | uint32_t maxIterationCount = 40; 46 | double stoppingRelativeError = 0.00025; 47 | uint32_t maxIterationPDHG = 40; 48 | double stoppingRelativePDHG = 0.00025; 49 | uint32_t reportKthIteration = 0; 50 | 51 | // Projector settings 52 | bool useCVPProjector = false; 53 | bool useExactScaling = true; 54 | bool useCosScaling = false; 55 | bool useNoScaling = false; 56 | bool useBarrierCalls = false; 57 | bool useElevationCorrection = false; 58 | int barrierArraySize = -1; // Guess it 59 | // int barrierArraySize = 7680; ... To fit Intel 60 | bool useCenterVoxelProjector = false; 61 | bool useSiddonProjector = false; 62 | uint32_t probesPerEdge = 1; 63 | bool useTTProjector = false; 64 | 65 | // Backprojector settings 66 | bool backprojectorNoScaling = false; 67 | bool backprojectorFBPScaling = false; 68 | bool backprojectorNaturalScaling = false; 69 | bool backprojectorKaczmarzScaling = false; 70 | 71 | // OpenCL 72 | std::string CLplatformString = ""; 73 | uint32_t CLplatformID = 0; 74 | std::vector CLdeviceIDs; 75 | std::vector backprojectorLocalNDRange = { 0, 1, 1 }; 76 | std::vector projectorLocalNDRange = { 0, 1, 1 }; 77 | bool CLdebug = false; 78 | bool CLrelaxed = false; 79 | uint32_t CLitemsPerWorkgroup = 256; 80 | // Returns minimum CL_DEVICE_LOCAL_MEM_SIZE 81 | uint64_t parsePlatformString(bool verbose = false); 82 | 83 | protected: 84 | CArmArguments(int argc, char* argv[], std::string appName); 85 | 86 | // From parsePlatformString() 87 | void insertDeviceID(uint32_t deviceID, uint32_t devicesOnPlatform); 88 | void fillDevicesList(std::string commaSeparatedEntries, uint32_t CLplatformID); 89 | 90 | void addGeometryGroup(); 91 | void addVolumeSizeArgs(bool includeSizez = true); 92 | void addVoxelSizeArgs(); 93 | void addVolumeCenterArgs(); 94 | void addProjectionSizeArgs(); 95 | void addPixelSizeArgs(); 96 | 97 | void addBasisGroup(); 98 | void addBasisSpecificationArgs(bool includeBasisSize = true); 99 | 100 | void addSettingsGroup(); 101 | void addCLSettingsGroup(); 102 | void addSettingsArgs(); 103 | void addCLSettingsArgs(); 104 | void addProjectorLocalNDRangeArgs(); 105 | void addBackprojectorLocalNDRangeArgs(); 106 | void addRelaxedArg(); 107 | 108 | // Projector setup 109 | void addProjectorSettingsGroups(); 110 | void addCuttingVoxelProjectorArgs(bool includeNoScaling = false); 111 | void addTTProjectorArgs(); 112 | void addSiddonProjectorArgs(); 113 | void addCenterVoxelProjectorArgs(); 114 | void addProjectorArgs(); 115 | void addBackprojectorScalingArgs(); 116 | 117 | CLI::Option_group* og_basis = nullptr; 118 | CLI::Option_group* og_settings = nullptr; 119 | CLI::Option_group* og_projectorsettings = nullptr; 120 | CLI::Option_group* og_projectortypesettings = nullptr; 121 | CLI::Option_group* og_cl_settings = nullptr; 122 | 123 | CLI::Option* opt_cl_backprojectorlocalrange = nullptr; 124 | CLI::Option* opt_cl_projectorlocalrange = nullptr; 125 | CLI::Option* opt_cl_localarraysize = nullptr; 126 | }; 127 | } // namespace KCT::util 128 | -------------------------------------------------------------------------------- /include/CGLSReconstructor.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Logging 4 | #include "PLOG/PlogSetup.h" 5 | 6 | // External libraries 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // Internal libraries 13 | #include "BaseReconstructor.hpp" 14 | #include "DEN/DenProjectionMatrixReader.hpp" 15 | #include "MATRIX/LightProjectionMatrix.hpp" 16 | #include "MATRIX/ProjectionMatrix.hpp" 17 | #include "OPENCL/OpenCLManager.hpp" 18 | #include "rawop.h" 19 | #include "stringFormatter.h" 20 | 21 | namespace KCT { 22 | 23 | class CGLSReconstructor : public BaseReconstructor 24 | { 25 | public: 26 | /** 27 | * Initialize Cutting Voxel Projector 28 | * 29 | * @param volume Pointer to volume file 30 | * @param vdimx Volume x dimension 31 | * @param vdimy Volume y dimension 32 | * @param vdimz Volume z dimension 33 | * @param xpath Path of cl kernel files 34 | * @param debug Should debugging be used by suppliing source and -g as options 35 | */ 36 | CGLSReconstructor(uint32_t pdimx, 37 | uint32_t pdimy, 38 | uint32_t pdimz, 39 | uint32_t vdimx, 40 | uint32_t vdimy, 41 | uint32_t vdimz, 42 | uint32_t workGroupSize = 256, 43 | cl::NDRange projectorLocalNDRange = cl::NullRange, 44 | cl::NDRange backprojectorLocalNDRange = cl::NullRange) 45 | : BaseReconstructor(pdimx, 46 | pdimy, 47 | pdimz, 48 | vdimx, 49 | vdimy, 50 | vdimz, 51 | workGroupSize, 52 | projectorLocalNDRange, 53 | backprojectorLocalNDRange) 54 | { 55 | removeTikhonovRegularization(); 56 | useGradient3D(true); 57 | useLaplace3D(true); 58 | } 59 | 60 | virtual int reconstruct(uint32_t maxIterations = 100, float errCondition = 0.01); 61 | 62 | int reconstruct_experimental(uint32_t maxIterations = 100, float errCondition = 0.01); 63 | 64 | int reconstructTikhonov(uint32_t maxIterations = 100, float errCondition = 0.01); 65 | 66 | int reconstructDiagonalPreconditioner(std::shared_ptr invertedpreconditioner_xbuf, 67 | uint32_t maxIterations = 100, 68 | float errCondition = 0.01); 69 | 70 | int reconstructDiagonalPreconditioner(float* invertedpreconditioner, 71 | uint32_t maxIterations = 100, 72 | float errCondition = 0.01); 73 | 74 | int reconstructJacobi(uint32_t maxIterations = 100, float errCondition = 0.01); 75 | 76 | void precomputeJacobiPreconditioner(std::shared_ptr X); 77 | 78 | void addTikhonovRegularization(float L2, float V2, float Laplace); 79 | 80 | void useGradient3D(bool gradient3D); 81 | void useLaplace3D(bool laplace3D); 82 | 83 | void removeTikhonovRegularization(); 84 | 85 | private: 86 | void tikhonovMatrixActionToAdirectionAndScale(cl::Buffer XIN); 87 | void tikhonovMatrixActionToDiscrepancyAndScale(cl::Buffer XIN); 88 | void tikhonovMatrixActionOnDiscrepancyToUpdateResidualVector(cl::Buffer residualVector); 89 | void tikhonov_discrepancy_equals_discrepancy_minus_alphaAdirection(double alpha); 90 | void tikhonovZeroDiscrepancyBuffers(); 91 | void tikhonovSetRegularizingBuffersNull(); 92 | int weightedLeastSquares(float* weights); 93 | int preconditionnedLeastSquares(float* preconditionerXDIM); 94 | double tikhonovSumOfAdirectionNorms2(); 95 | 96 | std::shared_ptr residualVector_xbuf_L2add, residualVector_xbuf_V2xadd, 97 | residualVector_xbuf_V2yadd, residualVector_xbuf_V2zadd, 98 | residualVector_xbuf_Laplaceadd; // X buffers 99 | std::shared_ptr discrepancy_bbuf_xpart_L2, discrepancy_bbuf_xpart_V2x, 100 | discrepancy_bbuf_xpart_V2y, discrepancy_bbuf_xpart_V2z, 101 | discrepancy_bbuf_xpart_Laplace; // X buffers 102 | std::shared_ptr AdirectionVector_bbuf_xpart_L2, AdirectionVector_bbuf_xpart_V2x, 103 | AdirectionVector_bbuf_xpart_V2y, AdirectionVector_bbuf_xpart_V2z, 104 | AdirectionVector_bbuf_xpart_Laplace; // X buffers 105 | std::shared_ptr weighting_bbuf = nullptr; 106 | std::shared_ptr preconditioning_xbuf = nullptr; 107 | bool tikhonovRegularization; 108 | bool tikhonovRegularizationL2; 109 | bool tikhonovRegularizationV2; 110 | bool tikhonovRegularizationLaplace; 111 | bool laplace3D; 112 | bool gradient3D; 113 | float effectSizeL2, effectSizeV2, effectSizeLaplace; 114 | }; 115 | 116 | } // namespace KCT 117 | -------------------------------------------------------------------------------- /include/CGLSPBCTReconstructor.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Logging 4 | #include "PLOG/PlogSetup.h" 5 | 6 | // External libraries 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // Internal libraries 13 | #include "BasePBCTReconstructor.hpp" 14 | #include "DEN/DenProjectionMatrixReader.hpp" 15 | #include "OPENCL/OpenCLManager.hpp" 16 | #include "GEOMETRY/Geometry3DParallel.hpp" 17 | #include "GEOMETRY/Geometry3DParallelI.hpp" 18 | #include "rawop.h" 19 | #include "stringFormatter.h" 20 | 21 | namespace KCT { 22 | 23 | class CGLSPBCTReconstructor : virtual public BasePBCTReconstructor 24 | { 25 | public: 26 | /** 27 | * Initialize Cutting Voxel Projector 28 | * 29 | * @param volume Pointer to volume file 30 | * @param vdimx Volume x dimension 31 | * @param vdimy Volume y dimension 32 | * @param vdimz Volume z dimension 33 | * @param xpath Path of cl kernel files 34 | * @param debug Should debugging be used by suppliing source and -g as options 35 | */ 36 | CGLSPBCTReconstructor(uint32_t pdimx, 37 | uint32_t pdimy, 38 | uint32_t pdimz, 39 | uint32_t vdimx, 40 | uint32_t vdimy, 41 | uint32_t vdimz, 42 | uint32_t workGroupSize = 256) 43 | : BasePBCTOperator(pdimx, 44 | pdimy, 45 | pdimz, 46 | vdimx, 47 | vdimy, 48 | vdimz, 49 | workGroupSize) 50 | , BasePBCTReconstructor(pdimx, 51 | pdimy, 52 | pdimz, 53 | vdimx, 54 | vdimy, 55 | vdimz, 56 | workGroupSize) 57 | 58 | { 59 | removeTikhonovRegularization(); 60 | useGradient3D(true); 61 | useLaplace3D(true); 62 | } 63 | 64 | virtual int reconstruct(uint32_t maxIterations = 100, float errCondition = 0.01); 65 | 66 | int reconstruct_experimental(uint32_t maxIterations = 100, float errCondition = 0.01); 67 | 68 | int reconstructTikhonov(uint32_t maxIterations = 100, float errCondition = 0.01); 69 | 70 | int reconstructDiagonalPreconditioner(std::shared_ptr invertedpreconditioner_xbuf, 71 | uint32_t maxIterations = 100, 72 | float errCondition = 0.01); 73 | 74 | int reconstructDiagonalPreconditioner(float* invertedpreconditioner, 75 | uint32_t maxIterations = 100, 76 | float errCondition = 0.01); 77 | 78 | int reconstructJacobi(uint32_t maxIterations = 100, float errCondition = 0.01); 79 | 80 | void precomputeJacobiPreconditioner(std::shared_ptr X); 81 | 82 | void addTikhonovRegularization(float L2, float V2, float Laplace); 83 | 84 | void useGradient3D(bool gradient3D); 85 | void useLaplace3D(bool laplace3D); 86 | 87 | void removeTikhonovRegularization(); 88 | 89 | private: 90 | void tikhonovMatrixActionToAdirectionAndScale(cl::Buffer XIN); 91 | void tikhonovMatrixActionToDiscrepancyAndScale(cl::Buffer XIN); 92 | void tikhonovMatrixActionOnDiscrepancyToUpdateResidualVector(cl::Buffer residualVector); 93 | void tikhonov_discrepancy_equals_discrepancy_minus_alphaAdirection(double alpha); 94 | void tikhonovZeroDiscrepancyBuffers(); 95 | void tikhonovSetRegularizingBuffersNull(); 96 | int weightedLeastSquares(float* weights); 97 | int preconditionnedLeastSquares(float* preconditionerXDIM); 98 | double tikhonovSumOfAdirectionNorms2(); 99 | 100 | std::shared_ptr residualVector_xbuf_L2add, residualVector_xbuf_V2xadd, 101 | residualVector_xbuf_V2yadd, residualVector_xbuf_V2zadd, 102 | residualVector_xbuf_Laplaceadd; // X buffers 103 | std::shared_ptr discrepancy_bbuf_xpart_L2, discrepancy_bbuf_xpart_V2x, 104 | discrepancy_bbuf_xpart_V2y, discrepancy_bbuf_xpart_V2z, 105 | discrepancy_bbuf_xpart_Laplace; // X buffers 106 | std::shared_ptr AdirectionVector_bbuf_xpart_L2, AdirectionVector_bbuf_xpart_V2x, 107 | AdirectionVector_bbuf_xpart_V2y, AdirectionVector_bbuf_xpart_V2z, 108 | AdirectionVector_bbuf_xpart_Laplace; // X buffers 109 | std::shared_ptr weighting_bbuf = nullptr; 110 | std::shared_ptr preconditioning_xbuf = nullptr; 111 | bool tikhonovRegularization; 112 | bool tikhonovRegularizationL2; 113 | bool tikhonovRegularizationV2; 114 | bool tikhonovRegularizationLaplace; 115 | bool laplace3D; 116 | bool gradient3D; 117 | float effectSizeL2, effectSizeV2, effectSizeLaplace; 118 | }; 119 | 120 | } // namespace KCT 121 | -------------------------------------------------------------------------------- /include/ParallelBeamProjector.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Logging 4 | #include "PLOG/PlogSetup.h" 5 | 6 | // External libraries 7 | #include 8 | #include 9 | #include 10 | 11 | // Internal libraries 12 | #include "BasePBCTOperator.hpp" 13 | #include "Kniha.hpp" 14 | #include "MATRIX/LUDoolittleForm.hpp" 15 | #include "MATRIX/ProjectionMatrix.hpp" 16 | #include "MATRIX/SquareMatrix.hpp" 17 | #include "OPENCL/OpenCLManager.hpp" 18 | #include "rawop.h" 19 | #include "stringFormatter.h" 20 | 21 | namespace KCT { 22 | 23 | class ParallelBeamProjector : public virtual BasePBCTOperator 24 | { 25 | public: 26 | /** 27 | * Class that encapsulates projector and backprojector implementation of Cutting Voxel Projector 28 | * and other algorithms. 29 | * 30 | * @param pdimx Number of pixels 31 | * @param pdimy Number of pixels 32 | * @param vdimx Number of voxels 33 | * @param vdimy Number of voxels 34 | * @param vdimz Number of voxels 35 | */ 36 | ParallelBeamProjector(uint32_t pdimx, 37 | uint32_t pdimy, 38 | uint32_t pdimz, 39 | uint32_t vdimx, 40 | uint32_t vdimy, 41 | uint32_t vdimz, 42 | uint32_t workGroupSize = 256) 43 | : BasePBCTOperator(pdimx, 44 | pdimy, 45 | pdimz, 46 | vdimx, 47 | vdimy, 48 | vdimz, 49 | workGroupSize) 50 | { 51 | totalVolumeBufferSize = XDIM * sizeof(float); 52 | totalProjectionBufferSize = BDIM * sizeof(float); 53 | frameSize = pdimx * pdimy; 54 | } 55 | /** 56 | * Initialize volume buffer by given size. 57 | * 58 | * @param volumeSizeX 59 | * @param volumeSizeY 60 | * @param volumeSizeZ 61 | * @param volumeArray If its nullptr, initialize by zero. 62 | * 63 | * @return 64 | */ 65 | int initializeOrUpdateVolumeBuffer(float* volumeArray = nullptr); 66 | /** 67 | * Initialize volume buffer by given size, updates voxel size of the projector. 68 | * 69 | * @param volumeSizeX 70 | * @param volumeSizeY 71 | * @param volumeSizeZ 72 | * @param volumeArray If its nullptr, initialize by zero. 73 | * 74 | * @return 75 | */ 76 | int initializeOrUpdateVolumeBuffer(uint32_t vdimx, 77 | uint32_t vdimy, 78 | uint32_t vdimz, 79 | float* volumeArray = nullptr); 80 | 81 | int fillVolumeBufferByConstant(float constant); 82 | 83 | /** 84 | * Initialize projection buffer by given size. With or without updating dimensions 85 | * 86 | * @param projectionSizeX 87 | * @param projectionSizeY 88 | * @param projectionSizeZ 89 | * @param projectionArray If is nullptr, initialize by zero. 90 | * 91 | * @return 92 | */ 93 | int initializeOrUpdateProjectionBuffer(uint32_t pdimx, 94 | uint32_t pdimy, 95 | uint32_t pdimz, 96 | float* projectionArray = nullptr); 97 | int initializeOrUpdateProjectionBuffer(uint32_t projectionSizeZ, 98 | float* projectionArray = nullptr); 99 | int initializeOrUpdateProjectionBuffer(float* projectionArray = nullptr); 100 | 101 | int fillProjectionBufferByConstant(float constant); 102 | 103 | int project(float* volume, float* projection); 104 | int project_print_discrepancy(float* volume, float* projection, float* rhs); 105 | int backproject(float* projection, float* volume); 106 | 107 | double normSquare(float* projection, uint32_t pdimx, uint32_t pdimy); 108 | double normSquareDifference(float* projection, uint32_t pdimx, uint32_t pdimy); 109 | 110 | private: 111 | int arrayIntoBuffer(float* c_array, cl::Buffer cl_buffer, uint64_t size); 112 | int bufferIntoArray(cl::Buffer cl_buffer, float* c_array, uint64_t size); 113 | const cl_float FLOATZERO = 0.0f; 114 | const cl_double DOUBLEZERO = 0.0; 115 | float FLOATONE = 1.0f; 116 | float* volume = nullptr; 117 | uint64_t totalVolumeBufferSize; 118 | uint64_t frameSize; 119 | uint64_t totalProjectionBufferSize; 120 | cl::NDRange projectorLocalNDRange; 121 | cl::NDRange projectorLocalNDRangeBarrier; 122 | 123 | bool centerVoxelProjector = false; 124 | cl_int3 vdims; 125 | cl_int2 pdims; 126 | cl_uint2 pdims_uint; 127 | cl_double3 voxelSizes; 128 | cl_double3 volumeCenter; 129 | bool useCVPProjector = true; 130 | bool useCVPExactProjectionsScaling = true; 131 | bool useCVPElevationCorrection = false; 132 | bool useBarrierImplementation = false; 133 | uint32_t LOCALARRAYSIZE = 0; 134 | bool useSiddonProjector = false; 135 | cl_uint2 pixelGranularity = { 1, 1 }; 136 | bool useTTProjector = false; 137 | 138 | std::shared_ptr volumeBuffer = nullptr; 139 | std::shared_ptr projectionBuffer = nullptr; 140 | std::shared_ptr tmpBuffer = nullptr; 141 | size_t tmpBuffer_size = 0; 142 | std::chrono::time_point timestamp; 143 | }; 144 | 145 | } // namespace KCT 146 | -------------------------------------------------------------------------------- /src/OSSARTReconstructor.cpp: -------------------------------------------------------------------------------- 1 | #include "OSSARTReconstructor.hpp" 2 | 3 | namespace KCT { 4 | 5 | void OSSARTReconstructor::setup(float relaxationParameter, uint32_t subsetCount) 6 | { 7 | this->relaxationParameter = relaxationParameter; 8 | this->subsetCount = subsetCount; 9 | } 10 | 11 | void OSSARTReconstructor::addUpperBoxCondition(float upperBound, float upperBoundSubstitution) 12 | { 13 | this->upperBoxCondition = true; 14 | this->upperBound = upperBound; 15 | this->upperBoundSubstitution = upperBoundSubstitution; 16 | } 17 | 18 | void OSSARTReconstructor::removeUpperBoxCondition() { this->upperBoxCondition = false; } 19 | 20 | void OSSARTReconstructor::addLowerBoxCondition(float lowerBound, float lowerBoundSubstitution) 21 | { 22 | this->lowerBoxCondition = true; 23 | this->lowerBound = lowerBound; 24 | this->lowerBoundSubstitution = lowerBoundSubstitution; 25 | } 26 | 27 | void OSSARTReconstructor::removeLowerBoxCondition() { this->lowerBoxCondition = false; } 28 | 29 | int OSSARTReconstructor::reconstruct(uint32_t maxIterations, float errCondition) 30 | { 31 | std::string welcomeString 32 | = io::xprintf("WELCOME TO OS SART with %d subsets and relaxation parameter %0.2f.", 33 | subsetCount, relaxationParameter); 34 | LOGD << printTime(welcomeString, false, true); 35 | uint32_t iteration = 0; 36 | 37 | // Initialization 38 | allocateBBuffers(3); 39 | allocateXBuffers(2); 40 | // First obtain poit-wise inverse of row sum 41 | std::shared_ptr invrowsum_bbuf; 42 | std::shared_ptr discrepancy_bbuf, partial_discrepancy_bbuf; 43 | std::shared_ptr ones_bbuf; 44 | std::shared_ptr ones_xbuf, update_xbuf; 45 | std::shared_ptr partial_invcolsum_xbuf; 46 | invrowsum_bbuf = getBBuffer(0); 47 | ones_xbuf = getXBuffer(0); 48 | Q[0]->enqueueFillBuffer(*ones_xbuf, FLOATONE, 0, XDIM * sizeof(float)); 49 | project(*ones_xbuf, *invrowsum_bbuf); 50 | update_xbuf = ones_xbuf; 51 | ones_xbuf = nullptr; 52 | algFLOATvector_invert_except_zero(*invrowsum_bbuf, BDIM); 53 | double norm, NB0 = std::sqrt(normBBuffer_barrier_double(*b_buf)); 54 | // These will share single buffer 55 | discrepancy_bbuf = getBBuffer(1); 56 | partial_discrepancy_bbuf = getBBuffer(1); 57 | if(useVolumeAsInitialX0) 58 | { 59 | project(*x_buf, *discrepancy_bbuf); 60 | algFLOATvector_A_equals_Ac_plus_B(*discrepancy_bbuf, *b_buf, -1.0, BDIM); 61 | norm = std::sqrt(normBBuffer_barrier_double(*discrepancy_bbuf)); 62 | LOGI << io::xprintf_green("\nInitialization: |Ax-b|=%0.1f representing %0.2f%% of |b|.", norm, 63 | 100.0 * norm / NB0); 64 | } else 65 | { 66 | Q[0]->enqueueFillBuffer(*x_buf, FLOATZERO, 0, XDIM * sizeof(float)); 67 | norm = NB0; 68 | } 69 | ones_bbuf = getBBuffer(2); 70 | Q[0]->enqueueFillBuffer(*ones_bbuf, FLOATONE, 0, BDIM * sizeof(float)); 71 | partial_invcolsum_xbuf = getXBuffer(1); 72 | // x_buf now stores x0, discrepancy_bbuf initial discrepancy 73 | 74 | while(norm / NB0 > errCondition && iteration < maxIterations) 75 | { 76 | for(uint32_t subsetIndex = 0; subsetIndex != subsetCount; subsetIndex++) 77 | { 78 | backproject(*ones_bbuf, *partial_invcolsum_xbuf, subsetIndex, subsetCount); 79 | algFLOATvector_invert_except_zero(*partial_invcolsum_xbuf, XDIM); 80 | backproject(*partial_discrepancy_bbuf, *update_xbuf, subsetIndex, subsetCount); 81 | project(*x_buf, *partial_discrepancy_bbuf, subsetIndex, subsetCount); 82 | algFLOATvector_A_equals_Ac_plus_B(*partial_discrepancy_bbuf, *b_buf, -1.0, BDIM); 83 | algFLOATvector_A_equals_A_times_B(*partial_discrepancy_bbuf, *invrowsum_bbuf, BDIM); 84 | backproject(*partial_discrepancy_bbuf, *update_xbuf, subsetIndex, subsetCount); 85 | algFLOATvector_A_equals_A_times_B(*update_xbuf, *partial_invcolsum_xbuf, XDIM); 86 | algFLOATvector_A_equals_A_plus_cB(*x_buf, *update_xbuf, relaxationParameter, XDIM); 87 | } 88 | if(upperBoxCondition) 89 | { 90 | algFLOATvector_substitute_greater_than(*x_buf, upperBound, upperBoundSubstitution, 91 | XDIM); 92 | } 93 | if(lowerBoxCondition) 94 | { 95 | algFLOATvector_substitute_lower_than(*x_buf, lowerBound, lowerBoundSubstitution, XDIM); 96 | } 97 | iteration++; 98 | reportTime(io::xprintf("Iteration %d", iteration), false, true); 99 | project(*x_buf, *discrepancy_bbuf); 100 | algFLOATvector_A_equals_Ac_plus_B(*discrepancy_bbuf, *b_buf, -1.0, BDIM); 101 | norm = std::sqrt(normBBuffer_barrier_double(*discrepancy_bbuf)); 102 | LOGI << io::xprintf_green("\nIteration %d: |Ax-b|=%0.1f representing %0.2f%% of |b|.", 103 | iteration, norm, 100.0 * norm / NB0); 104 | if(reportKthIteration > 0 && iteration % reportKthIteration == 0) 105 | { 106 | LOGD << io::xprintf("Writing file %sx_it%02d.den", intermediatePrefix.c_str(), 107 | iteration); 108 | writeVolume(*x_buf, 109 | io::xprintf("%sx_it%02d.den", intermediatePrefix.c_str(), iteration)); 110 | } 111 | } 112 | Q[0]->enqueueReadBuffer(*x_buf, CL_TRUE, 0, sizeof(float) * XDIM, x); 113 | return 0; 114 | } 115 | 116 | } // namespace KCT 117 | -------------------------------------------------------------------------------- /src/Perfusion/CGLSPerfusionReconstructor.cpp: -------------------------------------------------------------------------------- 1 | #include "Perfusion/CGLSPerfusionReconstructor.hpp" 2 | 3 | namespace KCT { 4 | 5 | int CGLSPerfusionReconstructor::reconstruct(uint32_t maxIterations, 6 | float errCondition, 7 | bool blocking) 8 | { 9 | reportTime("WELCOME TO CGLS, init perfusion", blocking, true); 10 | uint32_t iteration = 1; 11 | 12 | // Initialization 13 | double norm, residualNorm2_old, residualNorm2_now, AdirectionNorm2, alpha, beta; 14 | double NB0 = std::sqrt(normBBuffer_barrier_double(b_buf)); 15 | double NR0, NX; 16 | LOGI << io::xprintf("||b||=%f", NB0); 17 | std::vector> directionVector_xbuf, residualVector_xbuf; // X buffers 18 | allocateXBuffers(2); 19 | directionVector_xbuf = getXBuffers(0); 20 | residualVector_xbuf = getXBuffers(1); 21 | allocateBBuffers(2); 22 | std::vector> discrepancy_bbuf, AdirectionVector_bbuf; // B buffers 23 | discrepancy_bbuf = getBBuffers(0); 24 | AdirectionVector_bbuf = getBBuffers(1); 25 | 26 | // INITIALIZATION x_0 is initialized typically by zeros but in general by supplied array 27 | // c_0 is filled by b 28 | // v_0=w_0=BACKPROJECT(c_0) 29 | // writeProjections(*discrepancy_bbuf, io::xprintf("/tmp/cgls/c_0.den")); 30 | copyFloatVector(b_buf, discrepancy_bbuf, BDIM); // discrepancy_bbuf stores initial discrepancy 31 | if(useVolumeAsInitialX0) 32 | { 33 | setTimestamp(blocking); 34 | project(x_buf, AdirectionVector_bbuf); 35 | reportTime("Projection x0", blocking, true); 36 | addIntoFirstVectorSecondVectorScaled(discrepancy_bbuf, AdirectionVector_bbuf, -1.0, BDIM); 37 | } else 38 | { 39 | zeroXBuffers(x_buf); 40 | } 41 | setTimestamp(blocking); 42 | backproject(discrepancy_bbuf, residualVector_xbuf); 43 | reportTime("Backprojection 0", blocking, true); 44 | copyFloatVector(residualVector_xbuf, directionVector_xbuf, XDIM); 45 | residualNorm2_old = normXBuffer_barrier_double(residualVector_xbuf); 46 | NR0 = std::sqrt(residualNorm2_old); 47 | setTimestamp(blocking); 48 | project(directionVector_xbuf, AdirectionVector_bbuf); 49 | reportTime("Projection 1", blocking, true); 50 | AdirectionNorm2 = normBBuffer_barrier_double(AdirectionVector_bbuf); 51 | alpha = residualNorm2_old / AdirectionNorm2; 52 | addIntoFirstVectorSecondVectorScaled(x_buf, directionVector_xbuf, alpha, XDIM); 53 | addIntoFirstVectorSecondVectorScaled(discrepancy_bbuf, AdirectionVector_bbuf, -alpha, BDIM); 54 | norm = std::sqrt(normBBuffer_barrier_double(discrepancy_bbuf)); 55 | while(norm / NB0 > errCondition && iteration < maxIterations) 56 | { 57 | if(reportKthIteration > 0 && iteration % reportKthIteration == 0) 58 | { 59 | LOGD << io::xprintf("Writing file %sx_it%02d.den", progressPrefixPath.c_str(), 60 | iteration); 61 | writeVolume(x_buf, 62 | io::xprintf("%sx_it%02d.den", progressPrefixPath.c_str(), iteration)); 63 | } 64 | // DEBUG 65 | if(iteration % 10 == 0) 66 | { 67 | setTimestamp(blocking); 68 | project(x_buf, discrepancy_bbuf); 69 | reportTime(io::xprintf("Reothrogonalization projection %d", iteration), blocking, true); 70 | addIntoFirstVectorScaledSecondVector(discrepancy_bbuf, b_buf, -1.0, BDIM); 71 | double norm2 = std::sqrt(normBBuffer_barrier_double(discrepancy_bbuf)); 72 | 73 | LOGE << io::xprintf( 74 | "Iteration %d, the norm of |Ax-b| is %f that is %0.2f%% of |b|, norms " 75 | "loss of orthogonality %f%%.", 76 | iteration, norm2, 100.0 * norm2 / NB0, 100 * (norm2 - norm) / norm); 77 | } 78 | // DEBUG 79 | setTimestamp(blocking); 80 | backproject(discrepancy_bbuf, residualVector_xbuf); 81 | reportTime(io::xprintf("Backprojection %d", iteration), blocking, true); 82 | residualNorm2_now = normXBuffer_barrier_double(residualVector_xbuf); 83 | // Delayed update of residual vector 84 | beta = residualNorm2_now / residualNorm2_old; 85 | NX = std::sqrt(residualNorm2_now); 86 | LOGE << io::xprintf("Iteration %d: |Ax-b|=%0.1f that is %0.2f%% of |b|, |AT(Ax-b)|=%0.2f " 87 | "that is %0.3f%% of |AT(Ax0-b)|.", 88 | iteration, norm, 100.0 * norm / NB0, NX, 100 * NX / NR0); 89 | addIntoFirstVectorScaledSecondVector(directionVector_xbuf, residualVector_xbuf, beta, XDIM); 90 | // Delayed update of direction vector 91 | iteration = iteration + 1; 92 | residualNorm2_old = residualNorm2_now; 93 | setTimestamp(blocking); 94 | project(directionVector_xbuf, AdirectionVector_bbuf); 95 | reportTime(io::xprintf("Projection %d", iteration), blocking, true); 96 | AdirectionNorm2 = normBBuffer_barrier_double(AdirectionVector_bbuf); 97 | alpha = residualNorm2_old / AdirectionNorm2; 98 | addIntoFirstVectorSecondVectorScaled(x_buf, directionVector_xbuf, alpha, XDIM); 99 | addIntoFirstVectorSecondVectorScaled(discrepancy_bbuf, AdirectionVector_bbuf, -alpha, BDIM); 100 | norm = std::sqrt(normBBuffer_barrier_double(discrepancy_bbuf)); 101 | } 102 | LOGE << io::xprintf("Iteration %d, the norm of |Ax-b| is %f that is %0.2f%% of |b|.", iteration, 103 | norm, 100.0 * norm / NB0); 104 | for(uint32_t vectorID = 0; vectorID != XVNUM; vectorID++) 105 | { 106 | Q[0]->enqueueReadBuffer(*x_buf[vectorID], CL_TRUE, 0, sizeof(float) * XDIM, x[vectorID]); 107 | } 108 | return 0; 109 | } 110 | 111 | } // namespace KCT 112 | -------------------------------------------------------------------------------- /src/projectVolume.cpp: -------------------------------------------------------------------------------- 1 | // Logging 2 | #include "PLOG/PlogSetup.h" 3 | 4 | // External libraries 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // External libraries 13 | #include "CLI/CLI.hpp" //Command line parser 14 | #include "ctpl_stl.h" //Threadpool 15 | 16 | // Internal libraries 17 | #include "SMA/BufferedSparseMatrixDoubleReader.hpp" 18 | #include "rawop.h" 19 | 20 | using namespace KCT; 21 | 22 | int main(int argc, char* argv[]) 23 | { 24 | plog::Severity verbosityLevel = plog::debug; // Set to debug to see the 25 | // debug messages, info 26 | // messages 27 | std::string csvLogFile = "/tmp/dacprojector.csv"; // Set NULL to disable 28 | bool logToConsole = true; 29 | plog::PlogSetup plogSetup(verbosityLevel, csvLogFile, logToConsole); 30 | plogSetup.initLogging(); 31 | LOGI << "START"; 32 | // Argument parsing 33 | int a_threads = 1; 34 | // It is evaluated from -0.5, pixels are centerred at integer coordinates 35 | int projectionSizeX = 616; 36 | int projectionSizeY = 480; 37 | int projectionSizeZ = 1; 38 | // Here (0,0,0) is in the center of the volume 39 | int volumeSizeX = 256; 40 | int volumeSizeY = 256; 41 | int volumeSizeZ = 199; 42 | 43 | std::string a_inputVolume; 44 | std::string a_inputSystemMatrix; 45 | std::string a_projectionFile; 46 | 47 | CLI::App app{ "Using divide and conquer techniques to construct CT system matrix.." }; 48 | app.add_option("-j,--threads", a_threads, "Number of extra threads that application can use.") 49 | ->check(CLI::Range(1, 65535)); 50 | app.add_option("input_volume", a_inputVolume, 51 | "Files in a DEN format to process. These files represents projection matrices.") 52 | ->required() 53 | ->check(CLI::ExistingFile); 54 | app.add_option("system_matrix", a_inputSystemMatrix, 55 | "Files in a DEN format to process. These files represents projection matrices.") 56 | ->required() 57 | ->check(CLI::ExistingFile); 58 | app.add_option("output_file", a_projectionFile, "File in a sparse matrix format to output.") 59 | ->required(); 60 | app.parse(argc, argv); 61 | // Frames to process 62 | uint32_t totalVolumeSize = volumeSizeX * volumeSizeY * volumeSizeZ; 63 | float* volume = new float[volumeSizeX * volumeSizeY * volumeSizeZ]; 64 | io::readBytesFrom(a_inputVolume, 6, (uint8_t*)volume, totalVolumeSize * 4); 65 | uint32_t i, j; 66 | double v; 67 | 68 | matrix::BufferedSparseMatrixDoubleReader A(a_inputSystemMatrix); 69 | uint64_t elements = A.getNumberOfElements(); 70 | uint64_t totalProjectionSize = projectionSizeX * projectionSizeY * projectionSizeZ; 71 | float* projection = new float[totalProjectionSize](); // Initialized by zeros 72 | bool* acessed = new bool[totalProjectionSize](); // Initialized by zeros 73 | 74 | uint8_t buf[6]; 75 | 76 | float* testVolumeSlice = new float[volumeSizeX * volumeSizeY](); 77 | 78 | std::memcpy(testVolumeSlice, &volume[198 * volumeSizeX * volumeSizeY], 79 | volumeSizeX * volumeSizeY * 4); 80 | util::putUint16((uint16_t)volumeSizeY, &buf[0]); 81 | util::putUint16((uint16_t)volumeSizeX, &buf[2]); 82 | util::putUint16((uint16_t)1, &buf[4]); 83 | io::createEmptyFile("/b/git/DivideConquerProjector/build/xxx", 84 | 6 + volumeSizeX * volumeSizeY * 4, true); 85 | io::writeFirstBytes("/b/git/DivideConquerProjector/build/xxx", buf, 6); 86 | io::writeBytesFrom("/b/git/DivideConquerProjector/build/xxx", 6, (uint8_t*)testVolumeSlice, 87 | volumeSizeX * volumeSizeY * 4); 88 | 89 | float addme; 90 | while(elements != 0) 91 | { 92 | A.readNextValue(&i, &j, &v); 93 | if(i >= totalVolumeSize) 94 | { 95 | LOGE << io::xprintf("Coordinates vol=(%d, %d, %d) are invalid!", i % volumeSizeX, 96 | (i / volumeSizeX) % volumeSizeY, (i / volumeSizeX) / volumeSizeY); 97 | } 98 | /* 99 | if(j%projectionSizeX == 2 && j/projectionSizeX ==2) 100 | { 101 | LOGE << io::xprintf("v=%e,i=%d,vol=(%d, %d, %d), volume[i] =%e, 102 | v*volume[i]=%e ", v,i, i%volumeSizeX, (i/volumeSizeX)%volumeSizeY, 103 | (i/volumeSizeX)/volumeSizeY, volume[i], v*volume[i]); LOGE << 104 | io::xprintf("vol(0,0,199)=%e", volume[199*volumeSizeX*volumeSizeY]); 105 | } 106 | */ 107 | if(j >= totalProjectionSize) 108 | { 109 | LOGD << "BIG"; 110 | } 111 | // LOGD << io::xprintf("elements = %lu, i=%d, j=%d, v=%e.", elements, i, j, v); 112 | addme = volume[i] * v; 113 | projection[j] += addme; 114 | acessed[j] = true; 115 | elements--; 116 | } 117 | /* 118 | for(j = 0; j!= totalProjectionSize; j++) 119 | { 120 | 121 | if(acessed[j] == true) 122 | LOGD << io::xprintf("The (i,j) = (%d, %d) was acessed", j%projectionSizeX, j/projectionSizeX); 123 | } 124 | */ uint64_t totalFileSize 125 | = uint64_t(6) + totalProjectionSize * 4; 126 | io::createEmptyFile(a_projectionFile, totalFileSize, true); 127 | /// io::createEmptyFile(a_projectionFile, 0, true); //Try if this is faster 128 | util::putUint16((uint16_t)projectionSizeY, &buf[0]); 129 | util::putUint16((uint16_t)projectionSizeX, &buf[2]); 130 | util::putUint16((uint16_t)projectionSizeZ, &buf[4]); 131 | io::writeFirstBytes(a_projectionFile, buf, 6); 132 | io::writeBytesFrom(a_projectionFile, 6, (uint8_t*)projection, totalProjectionSize * 4); 133 | // io::appendBytes(a_projectionFile, buf, 6); 134 | // io::appendBytes(a_projectionFile, projection, totalProjectionSize*4); 135 | delete[] volume; 136 | delete[] projection; 137 | LOGI << "END"; 138 | } 139 | -------------------------------------------------------------------------------- /src/BasePBCT2DReconstructor.cpp: -------------------------------------------------------------------------------- 1 | #include "BasePBCT2DReconstructor.hpp" 2 | 3 | namespace KCT { 4 | 5 | /** 6 | * @brief 7 | * 8 | * @param projections The b vector to invert. 9 | * @param volume Allocated memory to store x. Might contain the initial guess. 10 | * 11 | * @return 12 | */ 13 | int BasePBCT2DReconstructor::initializeVectors(float* projections, 14 | float* volume, 15 | bool useVolumeAsInitialX0) 16 | { 17 | this->useVolumeAsInitialX0 = useVolumeAsInitialX0; 18 | this->b = projections; 19 | this->x = volume; 20 | cl_int err; 21 | 22 | // Initialize buffers 23 | if(useVolumeAsInitialX0) 24 | { 25 | x_buf = std::make_shared(*context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, 26 | sizeof(float) * XDIM, (void*)volume, &err); 27 | } else 28 | { 29 | x_buf = std::make_shared(*context, CL_MEM_READ_WRITE, sizeof(float) * XDIM, 30 | nullptr, &err); 31 | } 32 | if(err != CL_SUCCESS) 33 | { 34 | LOGE << io::xprintf("Unsucessful initialization of buffer with error code %d!", err); 35 | return -1; 36 | } 37 | size_t BDIM_bs = sizeof(float) * uint64_t(BDIM); 38 | b_buf = std::make_shared(*context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, BDIM_bs, 39 | (void*)projections, &err); 40 | if(err != CL_SUCCESS) 41 | { 42 | LOGE << io::xprintf("Unsucessful initialization of buffer with error code %d!", err); 43 | return -1; 44 | } 45 | tmp_b_buf = std::make_shared(*context, CL_MEM_READ_WRITE, BDIM_bs, nullptr, &err); 46 | if(err != CL_SUCCESS) 47 | { 48 | LOGE << io::xprintf("Unsucessful initialization of buffer with error code %d!", err); 49 | return -1; 50 | } 51 | return 0; 52 | } 53 | 54 | void BasePBCT2DReconstructor::simpleProjection() 55 | { 56 | Q[0]->enqueueFillBuffer(*tmp_b_buf, FLOATZERO, 0, BDIM * sizeof(float)); 57 | project(*x_buf, *tmp_b_buf); 58 | Q[0]->enqueueReadBuffer(*tmp_b_buf, CL_TRUE, 0, sizeof(float) * BDIM, b); 59 | } 60 | 61 | const float pi = 3.1415927; 62 | 63 | void BasePBCT2DReconstructor::simpleBackprojection(BackprojectorScalingMethod scalingType) 64 | { 65 | Q[0]->enqueueFillBuffer(*x_buf, FLOATZERO, 0, XDIM * sizeof(float)); 66 | float backprojectorScaling = 1.0; 67 | if(scalingType == BackprojectorScalingMethod::FBPScaling) 68 | { 69 | backprojectorScaling = pi / pdimz; 70 | backproject(*b_buf, *x_buf, 0, 1, backprojectorScaling); 71 | } else if(scalingType == BackprojectorScalingMethod::NaturalScaling) 72 | { 73 | allocateBBuffers(2); 74 | allocateXBuffers(1); 75 | std::shared_ptr ones_xbuf = getXBuffer(0); 76 | std::shared_ptr lengths_bbuf = getBBuffer(0); 77 | std::shared_ptr bscaled_bbuf = getBBuffer(1); 78 | Q[0]->enqueueFillBuffer(*ones_xbuf, FLOATONE, 0, XDIM * sizeof(float)); 79 | project(*ones_xbuf, *lengths_bbuf); 80 | algFLOATvector_invert_except_zero(*lengths_bbuf, BDIM); // Invert for multiplication 81 | algFLOATvector_C_equals_A_times_B(*b_buf, *lengths_bbuf, *bscaled_bbuf, BDIM); 82 | backprojectorScaling = 1.0f / pdimz; 83 | backproject(*bscaled_bbuf, *x_buf, 0, 1, backprojectorScaling); 84 | } else if(scalingType == BackprojectorScalingMethod::KaczmarzScaling) 85 | { 86 | allocateBBuffers(2); 87 | std::shared_ptr kaczmarz_bbuf = getBBuffer(0); 88 | std::shared_ptr bscaled_bbuf = getBBuffer(1); 89 | kaczmarz_product(*kaczmarz_bbuf); 90 | algFLOATvector_invert_except_zero(*kaczmarz_bbuf, BDIM); // Invert it for multiplication 91 | algFLOATvector_C_equals_A_times_B(*b_buf, *kaczmarz_bbuf, *bscaled_bbuf, BDIM); 92 | backprojectorScaling = 1.0f / pdimz; 93 | backproject_kaczmarz(*bscaled_bbuf, *x_buf, 0, 1, backprojectorScaling); 94 | } else// scalingType == BackprojectorScalingMethod::NoScaling 95 | { 96 | backproject(*b_buf, *x_buf); 97 | } 98 | Q[0]->enqueueReadBuffer(*x_buf, CL_TRUE, 0, sizeof(float) * XDIM, x); 99 | } 100 | 101 | void BasePBCT2DReconstructor::writeVolume(cl::Buffer& X, std::string path) 102 | { 103 | bufferIntoArray(X, x, XDIM); 104 | bool arrayxmajor = true; 105 | bool outxmajor = true; 106 | io::DenFileInfo::create3DDenFileFromArray(x, arrayxmajor, path, io::DenSupportedType::FLOAT32, 107 | vdimx, vdimy, vdimz, outxmajor); 108 | } 109 | 110 | void BasePBCT2DReconstructor::writeProjections(cl::Buffer& B, std::string path) 111 | { 112 | bufferIntoArray(B, b, BDIM); 113 | bool arrayxmajor = false; 114 | bool outxmajor = true; 115 | io::DenFileInfo::create3DDenFileFromArray(b, arrayxmajor, path, io::DenSupportedType::FLOAT32, 116 | pdimx, pdimy, pdimz, outxmajor); 117 | } 118 | 119 | void BasePBCT2DReconstructor::setReportingParameters(bool verbose, 120 | uint32_t reportKthIteration, 121 | std::string intermediatePrefix) 122 | { 123 | this->verbose = verbose; 124 | this->reportKthIteration = reportKthIteration; 125 | this->intermediatePrefix = intermediatePrefix; 126 | } 127 | 128 | double BasePBCT2DReconstructor::adjointProductTest() 129 | { 130 | std::shared_ptr xa_buf; // X buffers 131 | allocateXBuffers(1); 132 | xa_buf = getXBuffer(0); 133 | allocateBBuffers(1); 134 | std::shared_ptr ba_buf; // B buffers 135 | ba_buf = getBBuffer(0); 136 | project(*x_buf, *ba_buf); 137 | backproject(*b_buf, *xa_buf); 138 | double bdotAx = scalarProductBBuffer_barrier_double(*b_buf, *ba_buf); 139 | double ATbdotx = scalarProductXBuffer_barrier_double(*x_buf, *xa_buf); 140 | return (bdotAx / ATbdotx); 141 | } 142 | } // namespace KCT 143 | -------------------------------------------------------------------------------- /src/createLinkStructure.cpp: -------------------------------------------------------------------------------- 1 | // Logging 2 | #include "PLOG/PlogSetup.h" 3 | 4 | // External libraries 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // External libraries 13 | #include "CLI/CLI.hpp" //Command line parser 14 | #include "ctpl_stl.h" //Threadpool 15 | 16 | // Internal libraries 17 | #include "ARGPARSE/parseArgs.h" 18 | #include "SMA/BufferedSparseMatrixFloatReader.hpp" 19 | #include "SMA/BufferedSparseMatrixFloatWritter.hpp" 20 | 21 | using namespace KCT; 22 | 23 | void insertvectopix(std::string file, uint16_t num) {} 24 | 25 | int main(int argc, char* argv[]) 26 | { 27 | 28 | uint16_t* vectopixbuf = new uint16_t[1024]; 29 | uint32_t* pixtonumbuf = new uint8_t[5 * 1024]; 30 | uint8_t* consecutivebuf = new uint8_t[1024]; 31 | float* floatbuf = new float[1024]; 32 | int vectopixpos = 0, pixtonumpos = 0, consetutivepos = 0, floatpos = 0; 33 | plog::Severity verbosityLevel = plog::debug; // Set to debug to see the 34 | // debug messages, info 35 | // messages 36 | std::string csvLogFile = "/tmp/dacprojector.csv"; // Set NULL to disable 37 | bool logToConsole = true; 38 | plog::PlogSetup plogSetup(verbosityLevel, csvLogFile, logToConsole); 39 | plogSetup.initLogging(); 40 | LOGI << "sortsortsort"; 41 | // Argument parsing 42 | std::string a_sortedFloat; 43 | std::string a_vectopix; 44 | std::string a_pixtoorder; 45 | std::string a_floats; 46 | CLI::App app{ "Using divide and conquer techniques to construct CT system matrix.." }; 47 | app.add_option("sorted_float", a_sortedFloat, 48 | "Files in a DEN format to process. These files represents projection matrices.") 49 | ->required() 50 | ->check(CLI::ExistingFile); 51 | app.add_option("vectopix", a_vectopix, "Contains number of pixel records in pixtoorder.") 52 | ->required() 53 | ->check(CLI::NonexistentPath); 54 | app.add_option("pixtoorder", a_pixtoorder, 55 | "Contains pixel index and number of records for this pixel.") 56 | ->required() 57 | ->check(CLI::NonexistentPath); 58 | app.add_option("pixtoorder", a_floats, "Contains floats.") 59 | ->required() 60 | ->check(CLI::NonexistentPath); 61 | app.parse(argc, argv); 62 | // Frames to process 63 | matrix::BufferedSparseMatrixFloatReader readmatrix(a_sortedFloat); 64 | io::createEmptyFile(a_vectopix, 0, true); // Try if this is faster 65 | io::createEmptyFile(a_pixtoorder, 0, true); // Try if this is faster 66 | io::createEmptyFile(a_floats, 0, true); // Try if this is faster 67 | io::appendBytes(a_projectionFile, (uint8_t*)projection, totalProjectionSize * 4); 68 | uint32_t previ = 256 * 256 * 199; 69 | uint32_t prevj = 616 * 480 * 248; 70 | uint32_t initseqj = 616 * 480 * 248; 71 | uint16_t pixrecords = 0; 72 | uint8_t consecutive = 0; 73 | uint32_t i, j; 74 | float v; 75 | uint64_t totalfloatpos = 0; 76 | while(!readmatrix.atEnd()) 77 | { 78 | readmatrix.readNextValue(&i, &j, &v); 79 | if(floatpos != 1024) 80 | { 81 | floatbuf[floatpos] = v; 82 | floatpos++; 83 | } else 84 | { 85 | io::appendBytes(a_floats, (uint8_t*)floatbuf, 1024 * 4); 86 | floatbuf[0] = v; 87 | floatpos = 1; 88 | } 89 | if(i == previ) 90 | { 91 | if(j == prevj + 1) 92 | { 93 | consecutive++; 94 | } else 95 | { 96 | if(consecutive != 0) 97 | { 98 | if(pixtonumpos != 1024) 99 | { 100 | std::memcpy(pixtonumbuf + 5 * pixtonumpos, &initseqj, 4); 101 | std::memcpy(pixtonumbuf + 5 * pixtonumpos + 4, &consecutive, 1); 102 | pixtonumpos++; 103 | 104 | } else 105 | { 106 | io::appendBytes(a_pixtoorder, (uint8_t*)pixtonumbuf, 5 * 1024); 107 | std::memcpy(pixtonumbuf, &initseqj, 4); 108 | std::memcpy(pixtonumbuf + 4, &consecutive, 1); 109 | pixtonumpos = 1; 110 | } 111 | } 112 | initseqj = j; 113 | consecutive = 1; 114 | pixrecords++; 115 | } 116 | } else 117 | { 118 | 119 | if(consecutive != 0) 120 | { 121 | if(pixtonumpos != 1024) 122 | { 123 | std::memcpy(pixtonumbuf + 5 * pixtonumpos, &initseqj, 4); 124 | std::memcpy(pixtonumbuf + 5 * pixtonumpos + 4, &consecutive, 1); 125 | pixtonumpos++; 126 | 127 | } else 128 | { 129 | io::appendBytes(a_pixtoorder, (uint8_t*)pixtonumbuf, 5 * 1024); 130 | std::memcpy(pixtonumbuf, &initseqj, 4); 131 | std::memcpy(pixtonumbuf + 4, &consecutive, 1); 132 | pixtonumpos = 1; 133 | } 134 | } 135 | initseqj = j; 136 | consecutive = 1; 137 | if(pixrecords != 0) 138 | { 139 | if(vectopixpos != 1024) 140 | { 141 | std::memcpy(vectopixbuf + vectopixpos, &pixrecords, 2); 142 | vectopixpos++; 143 | } else 144 | { 145 | io::appendBytes(a_vectopixbuf, (uint8_t*)vectopixbuf, 2 * 1024); 146 | } 147 | } 148 | pixrecords = 0; 149 | } 150 | } 151 | 152 | if(vectopixpos != 0) 153 | { 154 | io::appendBytes(a_vectopixbuf, (uint8_t*)vectopixbuf, 2 * vectopixpos); 155 | } 156 | if(pixtonumpos != 0) 157 | { 158 | io::appendBytes(a_pixtoorder, (uint8_t*)pixtonumbuf, 5 * pixtonumpos); 159 | } 160 | if(floatpos != 0) 161 | { 162 | io::appendBytes(a_floats, (uint8_t*)floatbuf, 4 * floatpos); 163 | } 164 | LOGI << "END"; 165 | } 166 | -------------------------------------------------------------------------------- /include/CGLSPBCT2DReconstructor.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Logging 4 | #include "PLOG/PlogSetup.h" 5 | 6 | // External libraries 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // Internal libraries 13 | #include "BasePBCT2DReconstructor.hpp" 14 | #include "DEN/DenProjectionMatrixReader.hpp" 15 | #include "GEOMETRY/Geometry3DParallel.hpp" 16 | #include "GEOMETRY/Geometry3DParallelI.hpp" 17 | #include "OPENCL/OpenCLManager.hpp" 18 | #include "rawop.h" 19 | #include "stringFormatter.h" 20 | 21 | namespace KCT { 22 | 23 | class CGLSPBCT2DReconstructor : virtual public BasePBCT2DReconstructor 24 | { 25 | public: 26 | /** 27 | * Initialize Cutting Voxel Projector 28 | * 29 | * @param volume Pointer to volume file 30 | * @param vdimx Volume x dimension 31 | * @param vdimy Volume y dimension 32 | * @param vdimz Volume z dimension 33 | * @param xpath Path of cl kernel files 34 | * @param debug Should debugging be used by suppliing source and -g as options 35 | */ 36 | CGLSPBCT2DReconstructor(uint32_t pdimx, 37 | uint32_t pdimy, 38 | uint32_t pdimz, 39 | uint32_t vdimx, 40 | uint32_t vdimy, 41 | uint32_t vdimz, 42 | uint32_t workGroupSize = 256) 43 | : BasePBCT2DOperator(pdimx, pdimy, pdimz, vdimx, vdimy, vdimz, workGroupSize) 44 | , BasePBCT2DReconstructor(pdimx, pdimy, pdimz, vdimx, vdimy, vdimz, workGroupSize) 45 | 46 | { 47 | removeTikhonovRegularization(); 48 | useGradient3D(true); 49 | useLaplace3D(true); 50 | } 51 | 52 | virtual int reconstruct(uint32_t maxIterations = 100, float errCondition = 0.01); 53 | 54 | int reconstruct_experimental(uint32_t maxIterations = 100, float errCondition = 0.01); 55 | 56 | /** 57 | * Tikhonov regularized tomographic reconstruction using CGLS. Sometimes the problem is also 58 | * referred as ridge regression, see https://en.wikipedia.org/wiki/Ridge_regression 59 | * 60 | * This procedure can be used also for preconditioning. In this case we compute the problem with 61 | * two diagonal matrices C and W. 62 | * 63 | * 64 | * @param maxIterations 65 | * @param errCondition 66 | * @param invCpr_xbuf Right preconditioner. 67 | * @param leftPreconditioner_bbuf Left preconditioner W. We are solving min_x || W (b - Ax)||^2, 68 | * wehre W is the diagonal matrix constructed out of left preconditioner. In weighted least 69 | * squares, this matrix is often named W^{1/2} and can represent the reciprocal of the standard 70 | * deviation of the measurements. In the out of center scan, it can be also used as square root 71 | * of the ray weight, reciprocal of the number of measurements for given ray. In SIRT, the 72 | * weighting scheme is chosen such that W is the square root of the row sums of the system 73 | * matrix, this scheme is adapted for CGLS in function reconstructSumPreconditioning. 74 | * 75 | * @return 0 if success, 1 if error 76 | */ 77 | int reconstructTikhonov(uint32_t maxIterations = 100, 78 | float errCondition = 0.01, 79 | std::shared_ptr invCpr_xbuf = nullptr, 80 | std::shared_ptr invSqrtRpr_bbuf = nullptr); 81 | 82 | int reconstructDiagonalPreconditioner(std::shared_ptr invertedpreconditioner_xbuf, 83 | uint32_t maxIterations = 100, 84 | float errCondition = 0.01); 85 | 86 | int reconstructDiagonalPreconditioner(float* invertedpreconditioner, 87 | uint32_t maxIterations = 100, 88 | float errCondition = 0.01); 89 | 90 | int reconstructJacobi(uint32_t maxIterations = 100, float errCondition = 0.01); 91 | 92 | int reconstructSumPreconditioning(uint32_t maxIterations = 100, float errCondition = 0.01); 93 | 94 | int reconstructWLS(uint32_t maxIterations = 100, 95 | float errCondition = 0.01, 96 | float* weighs_BDIM = nullptr); 97 | 98 | void precomputeJacobiPreconditioner(std::shared_ptr X); 99 | 100 | void addTikhonovRegularization(float L2, float V2, float Laplace); 101 | 102 | void useGradient3D(bool gradient3D); 103 | 104 | void useLaplace3D(bool laplace3D); 105 | 106 | void removeTikhonovRegularization(); 107 | 108 | private: 109 | void tikhonovMatrixActionToAdirectionAndScale(cl::Buffer XIN); 110 | void tikhonovMatrixActionToDiscrepancyAndScale(cl::Buffer XIN); 111 | void tikhonovMatrixActionOnDiscrepancyToUpdateResidualVector(cl::Buffer residualVector); 112 | void tikhonov_discrepancy_equals_discrepancy_minus_alphaAdirection(double alpha); 113 | void tikhonovZeroDiscrepancyBuffers(); 114 | void tikhonovSetRegularizingBuffersNull(); 115 | int preconditionnedLeastSquares(float* preconditionerXDIM); 116 | double tikhonovSumOfAdirectionNorms2(); 117 | 118 | std::shared_ptr residualVector_xbuf_L2add, residualVector_xbuf_V2xadd, 119 | residualVector_xbuf_V2yadd, residualVector_xbuf_V2zadd, 120 | residualVector_xbuf_Laplaceadd; // X buffers 121 | std::shared_ptr discrepancy_bbuf_xpart_L2, discrepancy_bbuf_xpart_V2x, 122 | discrepancy_bbuf_xpart_V2y, discrepancy_bbuf_xpart_V2z, 123 | discrepancy_bbuf_xpart_Laplace; // X buffers 124 | std::shared_ptr AdirectionVector_bbuf_xpart_L2, AdirectionVector_bbuf_xpart_V2x, 125 | AdirectionVector_bbuf_xpart_V2y, AdirectionVector_bbuf_xpart_V2z, 126 | AdirectionVector_bbuf_xpart_Laplace; // X buffers 127 | std::shared_ptr weighting_bbuf = nullptr; 128 | std::shared_ptr preconditioning_xbuf = nullptr; 129 | bool tikhonovRegularization; 130 | bool tikhonovRegularizationL2; 131 | bool tikhonovRegularizationV2; 132 | bool tikhonovRegularizationLaplace; 133 | bool laplace3D; 134 | bool gradient3D; 135 | float effectSizeL2, effectSizeV2, effectSizeLaplace; 136 | }; 137 | 138 | } // namespace KCT 139 | -------------------------------------------------------------------------------- /cmake/FindOpenCL.cmake: -------------------------------------------------------------------------------- 1 | # Distributed under the OSI-approved BSD 3-Clause License. See accompanying 2 | # file Copyright.txt or https://cmake.org/licensing for details. 3 | 4 | #[=======================================================================[.rst: 5 | FindOpenCL 6 | ---------- 7 | 8 | .. versionadded:: 3.1 9 | 10 | Finds Open Computing Language (OpenCL) 11 | 12 | .. versionadded:: 3.10 13 | Detection of OpenCL 2.1 and 2.2. 14 | 15 | Imported Targets 16 | ^^^^^^^^^^^^^^^^ 17 | 18 | .. versionadded:: 3.7 19 | 20 | This module defines :prop_tgt:`IMPORTED` target ``OpenCL::OpenCL``, if 21 | OpenCL has been found. 22 | 23 | Result Variables 24 | ^^^^^^^^^^^^^^^^ 25 | 26 | This module defines the following variables:: 27 | 28 | OpenCL_FOUND - True if OpenCL was found 29 | OpenCL_INCLUDE_DIRS - include directories for OpenCL 30 | OpenCL_LIBRARIES - link against this library to use OpenCL 31 | OpenCL_VERSION_STRING - Highest supported OpenCL version (eg. 1.2) 32 | OpenCL_VERSION_MAJOR - The major version of the OpenCL implementation 33 | OpenCL_VERSION_MINOR - The minor version of the OpenCL implementation 34 | 35 | The module will also define two cache variables:: 36 | 37 | OpenCL_INCLUDE_DIR - the OpenCL include directory 38 | OpenCL_LIBRARY - the path to the OpenCL library 39 | 40 | #]=======================================================================] 41 | 42 | set(_OPENCL_x86 "(x86)") 43 | 44 | function(_FIND_OPENCL_VERSION) 45 | include(CheckSymbolExists) 46 | include(CMakePushCheckState) 47 | set(CMAKE_REQUIRED_QUIET ${OpenCL_FIND_QUIETLY}) 48 | 49 | cmake_push_check_state() 50 | foreach(VERSION "3_0" "2_2" "2_1" "2_0" "1_2" "1_1" "1_0") 51 | set(CMAKE_REQUIRED_INCLUDES "${OpenCL_INCLUDE_DIR}") 52 | 53 | if(EXISTS ${OpenCL_INCLUDE_DIR}/Headers/cl.h) 54 | check_symbol_exists( 55 | CL_VERSION_${VERSION} 56 | "Headers/cl.h" 57 | OPENCL_VERSION_${VERSION}) 58 | else() 59 | check_symbol_exists( 60 | CL_VERSION_${VERSION} 61 | "CL/cl.h" 62 | OPENCL_VERSION_${VERSION}) 63 | endif() 64 | 65 | if(OPENCL_VERSION_${VERSION}) 66 | string(REPLACE "_" "." VERSION "${VERSION}") 67 | set(OpenCL_VERSION_STRING ${VERSION} PARENT_SCOPE) 68 | string(REGEX MATCHALL "[0-9]+" version_components "${VERSION}") 69 | list(GET version_components 0 major_version) 70 | list(GET version_components 1 minor_version) 71 | set(OpenCL_VERSION_MAJOR ${major_version} PARENT_SCOPE) 72 | set(OpenCL_VERSION_MINOR ${minor_version} PARENT_SCOPE) 73 | break() 74 | endif() 75 | endforeach() 76 | cmake_pop_check_state() 77 | endfunction() 78 | 79 | find_path(OpenCL_INCLUDE_DIR 80 | NAMES 81 | CL/cl.h OpenCL/cl.h 82 | PATHS 83 | ENV "PROGRAMFILES(X86)" 84 | ENV "PROGRAMFILES" 85 | $ENV{PROGRAMFILES${_OPENCL_x86}}/OpenCLHeaders 86 | $ENV{PROGRAMFILES}/OpenCLHeaders 87 | ENV AMDAPPSDKROOT 88 | ENV INTELOCLSDKROOT 89 | ENV NVSDKCOMPUTE_ROOT 90 | ENV CUDA_PATH 91 | ENV ATISTREAMSDKROOT 92 | ENV OCL_ROOT 93 | /usr/local/cuda 94 | /opt/cuda 95 | PATH_SUFFIXES 96 | include 97 | OpenCL/common/inc 98 | "AMD APP/include") 99 | 100 | _FIND_OPENCL_VERSION() 101 | 102 | if(WIN32) 103 | if(CMAKE_SIZEOF_VOID_P EQUAL 4) 104 | find_library(OpenCL_LIBRARY 105 | NAMES OpenCL 106 | PATHS 107 | ENV "PROGRAMFILES(X86)" 108 | ENV "PROGRAMFILES" 109 | $ENV{PROGRAMFILES${_OPENCL_x86}}/OpenCL-ICD-Loader 110 | $ENV{PROGRAMFILES}/OpenCL-ICD-Loader 111 | ENV AMDAPPSDKROOT 112 | ENV INTELOCLSDKROOT 113 | ENV CUDA_PATH 114 | ENV NVSDKCOMPUTE_ROOT 115 | ENV ATISTREAMSDKROOT 116 | ENV OCL_ROOT 117 | PATH_SUFFIXES 118 | "AMD APP/lib/x86" 119 | lib/x86 120 | lib/Win32 121 | OpenCL/common/lib/Win32) 122 | elseif(CMAKE_SIZEOF_VOID_P EQUAL 8) 123 | find_library(OpenCL_LIBRARY 124 | NAMES OpenCL 125 | PATHS 126 | ENV "PROGRAMFILES(X86)" 127 | ENV "PROGRAMFILES" 128 | $ENV{PROGRAMFILES${_OPENCL_x86}}/OpenCL-ICD-Loader 129 | $ENV{PROGRAMFILES}/OpenCL-ICD-Loader 130 | ENV AMDAPPSDKROOT 131 | ENV INTELOCLSDKROOT 132 | ENV CUDA_PATH 133 | ENV NVSDKCOMPUTE_ROOT 134 | ENV ATISTREAMSDKROOT 135 | ENV OCL_ROOT 136 | PATH_SUFFIXES 137 | "AMD APP/lib/x86_64" 138 | lib/x86_64 139 | lib/x64 140 | lib 141 | OpenCL/common/lib/x64) 142 | endif() 143 | else() 144 | if(CMAKE_SIZEOF_VOID_P EQUAL 4) 145 | find_library(OpenCL_LIBRARY 146 | NAMES OpenCL 147 | PATHS 148 | /usr/lib64 /usr/lib /lib64 /lib # System paths 149 | ENV AMDAPPSDKROOT 150 | ENV CUDA_PATH 151 | /usr/local/cuda 152 | /opt/cuda 153 | PATH_SUFFIXES 154 | lib/x86 155 | lib 156 | NO_CMAKE_ENVIRONMENT_PATH) 157 | elseif(CMAKE_SIZEOF_VOID_P EQUAL 8) 158 | find_library(OpenCL_LIBRARY 159 | NAMES OpenCL 160 | PATHS 161 | /usr/lib64 /usr/lib /lib64 /lib # System paths 162 | ENV AMDAPPSDKROOT 163 | ENV CUDA_PATH 164 | /usr/local/cuda 165 | /opt/cuda 166 | PATH_SUFFIXES 167 | lib/x86_64 168 | lib/x64 169 | lib 170 | lib64 171 | NO_CMAKE_ENVIRONMENT_PATH) 172 | endif() 173 | endif() 174 | 175 | unset(_OPENCL_x86) 176 | 177 | set(OpenCL_LIBRARIES ${OpenCL_LIBRARY}) 178 | set(OpenCL_INCLUDE_DIRS ${OpenCL_INCLUDE_DIR}) 179 | 180 | include(FindPackageHandleStandardArgs) 181 | find_package_handle_standard_args( 182 | OpenCL 183 | REQUIRED_VARS OpenCL_LIBRARY OpenCL_INCLUDE_DIR 184 | VERSION_VAR OpenCL_VERSION_STRING) 185 | 186 | mark_as_advanced( 187 | OpenCL_INCLUDE_DIR 188 | OpenCL_LIBRARY) 189 | 190 | if(OpenCL_FOUND AND NOT TARGET OpenCL::OpenCL) 191 | if(OpenCL_LIBRARY MATCHES "/([^/]+)\\.framework$") 192 | add_library(OpenCL::OpenCL INTERFACE IMPORTED) 193 | set_target_properties(OpenCL::OpenCL PROPERTIES 194 | INTERFACE_LINK_LIBRARIES "${OpenCL_LIBRARY}") 195 | else() 196 | add_library(OpenCL::OpenCL UNKNOWN IMPORTED) 197 | set_target_properties(OpenCL::OpenCL PROPERTIES 198 | IMPORTED_LOCATION "${OpenCL_LIBRARY}") 199 | endif() 200 | set_target_properties(OpenCL::OpenCL PROPERTIES 201 | INTERFACE_INCLUDE_DIRECTORIES "${OpenCL_INCLUDE_DIRS}") 202 | endif() 203 | -------------------------------------------------------------------------------- /include/VolumeConvolutionOperator.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Logging 4 | #include "PLOG/PlogSetup.h" 5 | 6 | // External libraries 7 | #include 8 | #include 9 | #include 10 | 11 | // Internal libraries 12 | #include "Kniha.hpp" 13 | #include "MATRIX/LUDoolittleForm.hpp" 14 | #include "MATRIX/ProjectionMatrix.hpp" 15 | #include "MATRIX/SquareMatrix.hpp" 16 | #include "OPENCL/OpenCLManager.hpp" 17 | #include "rawop.h" 18 | #include "stringFormatter.h" 19 | 20 | namespace KCT { 21 | 22 | class VolumeConvolutionOperator : public virtual Kniha 23 | { 24 | public: 25 | /** 26 | * Class that encapsulates projector and backprojector implementation of Cutting Voxel Projector 27 | * and other algorithms. 28 | * 29 | * @param pdimx Number of pixels 30 | * @param pdimy Number of pixels 31 | * @param vdimx Number of voxels 32 | * @param vdimy Number of voxels 33 | * @param vdimz Number of voxels 34 | */ 35 | VolumeConvolutionOperator(uint64_t vdimx, 36 | uint64_t vdimy, 37 | uint64_t vdimz, 38 | cl::NDRange projectorLocalNDRange = cl::NullRange) 39 | : vdimx(vdimx) 40 | , vdimy(vdimy) 41 | , vdimz(vdimz) 42 | { 43 | vdims = cl_int3({ int(vdimx), int(vdimy), int(vdimz) }); 44 | totalVoxelNum = vdimx * vdimy * vdimz; 45 | totalVolumeBufferSize = totalVoxelNum * sizeof(float); 46 | timestamp = std::chrono::steady_clock::now(); 47 | std::size_t projectorLocalNDRangeDim = projectorLocalNDRange.dimensions(); 48 | if(projectorLocalNDRangeDim == 3) 49 | { 50 | if(projectorLocalNDRange[0] == 0 && projectorLocalNDRange[1] == 0 51 | && projectorLocalNDRange[2] == 0) 52 | { 53 | this->projectorLocalNDRange = cl::NullRange; 54 | this->projectorLocalNDRangeBarrier = cl::NullRange; 55 | } else if(projectorLocalNDRange[0] == 0 || projectorLocalNDRange[1] == 0 56 | || projectorLocalNDRange[2] == 0) 57 | { 58 | this->projectorLocalNDRange = guessProjectionLocalNDRange(false); 59 | this->projectorLocalNDRangeBarrier = guessProjectionLocalNDRange(true); 60 | } else 61 | { 62 | this->projectorLocalNDRange = projectorLocalNDRange; 63 | this->projectorLocalNDRangeBarrier = projectorLocalNDRange; 64 | } 65 | } else 66 | { 67 | if(projectorLocalNDRangeDim != 0) 68 | { 69 | LOGE << io::xprintf( 70 | "Wrong specification of projectorLocalNDRange, trying guessing!"); 71 | } 72 | this->projectorLocalNDRange = guessProjectionLocalNDRange(false); 73 | this->projectorLocalNDRangeBarrier = guessProjectionLocalNDRange(true); 74 | } 75 | } 76 | 77 | cl::NDRange guessProjectionLocalNDRange(bool barrierCalls); 78 | 79 | void initializeConvolution(); 80 | void initializeAllAlgorithms(); 81 | int problemSetup(double voxelSizeX, double voxelSizeY, double voxelSizeZ); 82 | /** 83 | * Initialize volume buffer by given size. 84 | * 85 | * @param volumeSizeX 86 | * @param volumeSizeY 87 | * @param volumeSizeZ 88 | * @param volumeArray If its nullptr, initialize by zero. 89 | * 90 | * @return 91 | */ 92 | int initializeOrUpdateVolumeBuffer(float* volumeArray = nullptr); 93 | /** 94 | * Initialize volume buffer by given size, updates voxel size of the projector. 95 | * 96 | * @param volumeSizeX 97 | * @param volumeSizeY 98 | * @param volumeSizeZ 99 | * @param volumeArray If its nullptr, initialize by zero. 100 | * 101 | * @return 102 | */ 103 | int initializeOrUpdateVolumeBuffer(uint32_t vdimx, 104 | uint32_t vdimy, 105 | uint32_t vdimz, 106 | float* volumeArray = nullptr); 107 | 108 | int fillVolumeBufferByConstant(float constant); 109 | int initializeOrUpdateOutputBuffer(); 110 | int initializeOrUpdateGradientOutputBuffers(); 111 | 112 | int convolve(std::string kernelName, 113 | float* volume, 114 | double hx = 1.0, 115 | double hy = 1.0, 116 | bool reflectionBoundaryConditions = false); 117 | int sobelGradient3D(cl_float3 voxelSizes, 118 | float* vx, 119 | float* vy, 120 | float* vz, 121 | bool reflectionBoundaryConditions = false); 122 | int faridGradient3D(cl_float3 voxelSizes, 123 | float* vx, 124 | float* vy, 125 | float* vz, 126 | bool reflectionBoundaryConditions = false); 127 | int isotropicGradient3D(cl_float3 voxelSizes, float* outputX, float* outputY, float* outputZ); 128 | int laplace3D(cl_float3 voxelSizes, float* outputVolume); 129 | 130 | private: 131 | const cl_float FLOATZERO = 0.0f; 132 | const cl_double DOUBLEZERO = 0.0; 133 | float FLOATONE = 1.0f; 134 | float* volume = nullptr; 135 | uint32_t vdimx, vdimy, vdimz; 136 | uint64_t totalVoxelNum, totalVolumeBufferSize, totalOutputBufferSize; 137 | uint64_t frameSize; 138 | cl::NDRange projectorLocalNDRange; 139 | cl::NDRange projectorLocalNDRangeBarrier; 140 | 141 | cl_int3 vdims; 142 | cl_double3 voxelSizes; 143 | cl_double3 volumeCenter; 144 | bool useBarrierImplementation = false; 145 | uint32_t LOCALARRAYSIZE = 0; 146 | 147 | std::shared_ptr volumeBuffer = nullptr; 148 | std::shared_ptr outputBuffer = nullptr; 149 | uint64_t totalOutputGradientBuffersSize; 150 | std::shared_ptr outputGradientX = nullptr; 151 | std::shared_ptr outputGradientY = nullptr; 152 | std::shared_ptr outputGradientZ = nullptr; 153 | size_t tmpBuffer_size = 0; 154 | std::vector invertProjectionMatrices(std::vector CM); 155 | std::vector computeScalingFactors(std::vector PM); 156 | std::shared_ptr> FLOAT_CopyVector; 157 | std::chrono::time_point timestamp; 158 | }; 159 | 160 | } // namespace KCT 161 | -------------------------------------------------------------------------------- /src/alg/ParallelBeamProjector.cpp: -------------------------------------------------------------------------------- 1 | #include "ParallelBeamProjector.hpp" 2 | 3 | namespace KCT { 4 | 5 | int ParallelBeamProjector::arrayIntoBuffer(float* c_array, cl::Buffer cl_buffer, uint64_t size) 6 | { 7 | uint64_t bufferSize = size * sizeof(float); 8 | cl_int err = CL_SUCCESS; 9 | if(c_array != nullptr) 10 | { 11 | err = Q[0]->enqueueWriteBuffer(cl_buffer, CL_TRUE, 0, bufferSize, (void*)c_array); 12 | } else 13 | { 14 | KCTERR("Null pointer exception!"); 15 | } 16 | if(err != CL_SUCCESS) 17 | { 18 | std::string msg = io::xprintf("Failed arrayIntoBuffer with code %d!", err); 19 | KCTERR(msg); 20 | } 21 | return 0; 22 | } 23 | 24 | int ParallelBeamProjector::bufferIntoArray(cl::Buffer cl_buffer, float* c_array, uint64_t size) 25 | { 26 | uint64_t bufferSize = size * sizeof(float); 27 | cl_int err = CL_SUCCESS; 28 | if(c_array != nullptr) 29 | { 30 | err = Q[0]->enqueueReadBuffer(cl_buffer, CL_TRUE, 0, bufferSize, (void*)c_array); 31 | } else 32 | { 33 | KCTERR("Null pointer exception!"); 34 | } 35 | if(err != CL_SUCCESS) 36 | { 37 | std::string msg = io::xprintf("Failed bufferIntoArray with code %d!", err); 38 | KCTERR(msg); 39 | } 40 | return 0; 41 | } 42 | 43 | int ParallelBeamProjector::fillVolumeBufferByConstant(float constant) 44 | { 45 | std::string msg; 46 | if(volumeBuffer == nullptr) 47 | { 48 | msg = io::xprintf( 49 | "Volume buffer is not yet initialized, call initializeVolumeBuffer first!"); 50 | LOGE << msg; 51 | throw std::runtime_error(msg); 52 | } 53 | return Q[0]->enqueueFillBuffer(*volumeBuffer, constant, 0, totalVolumeBufferSize); 54 | } 55 | 56 | int ParallelBeamProjector::fillProjectionBufferByConstant(float constant) 57 | { 58 | std::string msg; 59 | if(projectionBuffer == nullptr) 60 | { 61 | msg = io::xprintf( 62 | "Projection buffer is not yet initialized, call initializeProjectionBuffer first!"); 63 | LOGE << msg; 64 | throw std::runtime_error(msg); 65 | } 66 | return Q[0]->enqueueFillBuffer(*projectionBuffer, constant, 0, 67 | totalProjectionBufferSize); 68 | } 69 | 70 | int ParallelBeamProjector::project(float* volume, float* projection) 71 | { 72 | allocateXBuffers(1); 73 | allocateBBuffers(1); 74 | std::shared_ptr x_buf, b_buf; 75 | x_buf = getXBuffer(0); 76 | b_buf = getBBuffer(0); 77 | arrayIntoBuffer(volume, *x_buf, XDIM); 78 | BasePBCTOperator::project(*x_buf, *b_buf); 79 | bufferIntoArray(*b_buf, projection, BDIM); 80 | return 0; 81 | } 82 | int ParallelBeamProjector::project_print_discrepancy(float* volume, float* projection, float* rhs) 83 | { 84 | allocateXBuffers(1); 85 | allocateBBuffers(2); 86 | std::shared_ptr x_buf, b_buf, bb_buf; 87 | x_buf = getXBuffer(0); 88 | b_buf = getBBuffer(0); 89 | bb_buf = getBBuffer(1); 90 | arrayIntoBuffer(volume, *x_buf, XDIM); 91 | arrayIntoBuffer(rhs, *bb_buf, BDIM); 92 | BasePBCTOperator::project(*x_buf, *b_buf); 93 | double normbb = std::sqrt(normBBuffer_barrier_double(*bb_buf)); 94 | algFLOATvector_A_equals_A_plus_cB(*bb_buf, *b_buf, -1.0f, BDIM); 95 | double normDiscrepancy = std::sqrt(normBBuffer_barrier_double(*bb_buf)); 96 | LOGI << io::xprintf("|Ax-rhs|=%f, |rhs|=%f, discrepancy is %f%% of the initial norm.", 97 | normDiscrepancy, normbb, 100.0 * normDiscrepancy / normbb); 98 | bufferIntoArray(*b_buf, projection, BDIM); 99 | return 0; 100 | } 101 | int ParallelBeamProjector::backproject(float* projection, float* volume) 102 | { 103 | 104 | allocateXBuffers(1); 105 | allocateBBuffers(1); 106 | std::shared_ptr x_buf, b_buf; 107 | x_buf = getXBuffer(0); 108 | b_buf = getBBuffer(0); 109 | arrayIntoBuffer(projection, *b_buf, BDIM); 110 | BasePBCTOperator::backproject(*b_buf, *x_buf); 111 | bufferIntoArray(*x_buf, volume, XDIM); 112 | return 0; 113 | } 114 | 115 | double ParallelBeamProjector::normSquare(float* v, uint32_t pdimx, uint32_t pdimy) 116 | { 117 | size_t vecsize = sizeof(float) * pdimx * pdimy; 118 | if(tmpBuffer == nullptr || vecsize != tmpBuffer_size) 119 | { 120 | tmpBuffer_size = vecsize; 121 | tmpBuffer = std::make_shared(*context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, 122 | tmpBuffer_size, (void*)v); 123 | } else 124 | { 125 | Q[0]->enqueueWriteBuffer(*tmpBuffer, CL_TRUE, 0, tmpBuffer_size, (void*)v); 126 | } 127 | cl::Buffer onedouble(*context, CL_MEM_READ_WRITE, sizeof(double), nullptr); 128 | double sum; 129 | uint32_t framesize = pdimx * pdimy; 130 | cl::EnqueueArgs eargs(*Q[0], cl::NDRange(1)); 131 | (*vector_NormSquarePartial)(eargs, *tmpBuffer, onedouble, framesize).wait(); 132 | Q[0]->enqueueReadBuffer(onedouble, CL_TRUE, 0, sizeof(double), &sum); 133 | return sum; 134 | } 135 | 136 | double ParallelBeamProjector::normSquareDifference(float* v, uint32_t pdimx, uint32_t pdimy) 137 | { 138 | size_t vecsize = sizeof(float) * pdimx * pdimy; 139 | if(projectionBuffer == nullptr) 140 | { 141 | std::string msg = "Comparing to empty buffer is not possible."; 142 | KCTERR(msg); 143 | } 144 | if(vecsize != totalProjectionBufferSize) 145 | { 146 | std::string msg = "Can not compare buffers of incompatible dimensions."; 147 | KCTERR(msg); 148 | } 149 | 150 | if(tmpBuffer == nullptr || vecsize != tmpBuffer_size) 151 | { 152 | tmpBuffer_size = vecsize; 153 | tmpBuffer = std::make_shared(*context, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR, 154 | tmpBuffer_size, (void*)v); 155 | } else 156 | { 157 | Q[0]->enqueueWriteBuffer(*tmpBuffer, CL_TRUE, 0, tmpBuffer_size, (void*)v); 158 | } 159 | uint32_t framesize = pdimx * pdimy; 160 | cl::EnqueueArgs eargs(*Q[0], cl::NDRange(framesize)); 161 | float factor = -1.0; 162 | (*FLOATvector_A_equals_Ac_plus_B)(eargs, *tmpBuffer, *projectionBuffer, factor).wait(); 163 | cl::Buffer onedouble(*context, CL_MEM_READ_WRITE, sizeof(double), nullptr); 164 | double sum; 165 | cl::EnqueueArgs ear(*Q[0], cl::NDRange(1)); 166 | (*vector_NormSquarePartial)(ear, *tmpBuffer, onedouble, framesize).wait(); 167 | Q[0]->enqueueReadBuffer(onedouble, CL_TRUE, 0, sizeof(double), &sum); 168 | return sum; 169 | } 170 | 171 | } // namespace KCT 172 | -------------------------------------------------------------------------------- /pythonScripts/generateConvolutionKernels.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding: utf-8 -*- 3 | """ 4 | Created on Mon Aug 30 16:26:42 2021 5 | 6 | Code to generate convolution kernels code when I have separable d0 and d1 vectors such that d0 * d1 is 2D kernel and d0 * d0 * d1 is 3D kernel 7 | 8 | @author: Vojtech Kulvait 9 | """ 10 | import numpy as np 11 | 12 | def normalizeVectorL1(v): 13 | return v/np.linalg.norm(v, ord=1) 14 | 15 | def generateBracket(plusKeys, minusKeys, key): 16 | outplus="" 17 | outminus="" 18 | if key in plusKeys: 19 | outplus="+".join(plusKeys[key]) 20 | if key in minusKeys: 21 | outminus="-".join(minusKeys[key]) 22 | outminus="-%s"%(outminus) 23 | if not outplus: 24 | return outminus 25 | elif not outminus: 26 | return outplus 27 | else: 28 | return "%s%s"%(outplus, outminus) 29 | 30 | def generateConvolution2D(d0, d1, normalize=None): 31 | if normalize is None: 32 | normalize=True 33 | dx=len(d0) 34 | dy=len(d1) 35 | if normalize: 36 | normalizationTerm=np.sqrt(np.linalg.norm(np.outer(d0,d1).flatten(), ord=1)) 37 | d0=d0/normalizationTerm 38 | d1=d1/normalizationTerm 39 | sumstr="" 40 | for i in range(dx): 41 | if not sumstr.endswith("\n") and not len(sumstr)==0: 42 | sumstr="%s\n"%(sumstr) 43 | for j in range(dy): 44 | if np.float32(d0[i]*d1[j]) != 0: 45 | term = "%sf*cube[%d][%d]"%(np.format_float_positional(np.float32(d0[i]*d1[j])), i, j) 46 | if np.float32(d0[i]*d1[j]) > 0: 47 | sumstr="%s +%s"%(sumstr, term) 48 | else: 49 | sumstr="%s %s"%(sumstr, term) 50 | return sumstr; 51 | 52 | 53 | def generateConvolutionCompact2D(d0, d1, normalize=None): 54 | if normalize is None: 55 | normalize=True 56 | dx=len(d0) 57 | dy=len(d1) 58 | if normalize: 59 | normalizationTerm=np.sqrt(np.linalg.norm(np.outer(d0,d1).flatten(), ord=1)) 60 | d0=d0/normalizationTerm 61 | d1=d1/normalizationTerm 62 | plusTerms={} 63 | minusTerms={} 64 | for i in range(dx): 65 | for j in range(dy): 66 | cubestr="cube[%d][%d]"%(i,j) 67 | convitem=np.float32(d0[i]*d1[j]) 68 | if convitem != 0: 69 | if convitem > 0: 70 | if convitem not in plusTerms: 71 | plusTerms[convitem]=[] 72 | plusTerms[convitem].append(cubestr) 73 | else: 74 | if -convitem not in minusTerms: 75 | minusTerms[-convitem]=[] 76 | minusTerms[-convitem].append(cubestr) 77 | allkeys=[] 78 | allkeys.extend(plusTerms.keys()) 79 | allkeys.extend(minusTerms.keys()) 80 | allkeys=list(set(allkeys))#Just unique 81 | allstr=[] 82 | for key in allkeys: 83 | itm="%sf*(%s)"%(np.float32(key), generateBracket(plusTerms, minusTerms, key)) 84 | allstr.append(itm) 85 | return "+\n".join(allstr) 86 | 87 | def generateConvolutionCompact3D(d0, d1, d2, normalize=None): 88 | if normalize is None: 89 | normalize=True 90 | dx=len(d0) 91 | dy=len(d1) 92 | dz=len(d2) 93 | if normalize: 94 | normalizationTerm=np.power(np.linalg.norm(np.outer(np.outer(d0,d1).flatten(), d2).flatten(), ord=1), 1.0/3.0) 95 | d0=d0/normalizationTerm 96 | d1=d1/normalizationTerm 97 | d2=d2/normalizationTerm 98 | plusTerms={} 99 | minusTerms={} 100 | for i in range(dx): 101 | for j in range(dy): 102 | for k in range(dz): 103 | cubestr="cube[%d][%d][%d]"%(i,j,k) 104 | convitem=np.float32(d0[i]*d1[j]*d2[k]) 105 | if convitem != 0: 106 | if convitem > 0: 107 | if convitem not in plusTerms: 108 | plusTerms[convitem]=[] 109 | plusTerms[convitem].append(cubestr) 110 | else: 111 | if -convitem not in minusTerms: 112 | minusTerms[-convitem]=[] 113 | minusTerms[-convitem].append(cubestr) 114 | allkeys=[] 115 | allkeys.extend(plusTerms.keys()) 116 | allkeys.extend(minusTerms.keys()) 117 | allkeys=list(set(allkeys))#Just unique 118 | allstr=[] 119 | for key in allkeys: 120 | itm="%sf*(%s)"%(np.float32(key), generateBracket(plusTerms, minusTerms, key)) 121 | allstr.append(itm) 122 | return "+\n".join(allstr) 123 | 124 | def generateConvolution3D(d0, d1, d2, normalize=None): 125 | if normalize is None: 126 | normalize=True 127 | dx=len(d0) 128 | dy=len(d1) 129 | dz=len(d2) 130 | if normalize: 131 | normalizationTerm=np.power(np.linalg.norm(np.outer(np.outer(d0,d1).flatten(), d2).flatten(), ord=1), 1.0/3.0) 132 | d0=d0/normalizationTerm 133 | d1=d1/normalizationTerm 134 | d2=d2/normalizationTerm 135 | 136 | sumstr="" 137 | for i in range(dx): 138 | for j in range(dy): 139 | if not sumstr.endswith("\n") and not len(sumstr)==0: 140 | sumstr="%s\n"%(sumstr) 141 | for k in range(dz): 142 | if np.float32(d0[i]*d1[j]*d2[k]) != 0: 143 | term = "%sf*cube[%d][%d][%d]"%(np.format_float_positional(np.float32(d0[i]*d1[j]*d2[k])), i, j, k) 144 | if np.float32(d0[i]*d1[j]*d2[k]) > 0: 145 | sumstr="%s +%s"%(sumstr, term) 146 | else: 147 | sumstr="%s %s"%(sumstr, term) 148 | return sumstr; 149 | 150 | 151 | 152 | sobeld0=[1,2,1] 153 | sobeld1=[-1,0,1] 154 | gx=generateConvolutionCompact2D(sobeld0, sobeld1, False)#Sobel2Dy 155 | gy=generateConvolutionCompact2D(sobeld1, sobeld0, False)#Sobel2Dy 156 | print("Sobel 2D") 157 | print("grad.x=%s;"%gx) 158 | print("") 159 | print("grad.y=%s;"%gy) 160 | print("") 161 | #Scaled sobel so that the derivatives can be just scaled by voxel sizes 162 | gx=generateConvolutionCompact2D(sobeld1, sobeld0)#Sobel2Dy 163 | gy=generateConvolutionCompact2D(sobeld0, sobeld1)#Sobel2Dy 164 | print("Sobel 2D normalized") 165 | print("grad.x=%s;"%gx) 166 | print("") 167 | print("grad.y=%s;"%gy) 168 | print("") 169 | sx=generateConvolutionCompact3D(sobeld1, sobeld0, sobeld0)#Sobel3Dy 170 | sy=generateConvolutionCompact3D(sobeld0, sobeld1, sobeld0)#Sobel3Dy 171 | sz=generateConvolutionCompact3D(sobeld0, sobeld0, sobeld1)#Sobel3Dz 172 | print("Sobel 3D normalized") 173 | print("grad.x=%s;"%sx) 174 | print("") 175 | print("grad.y=%s;"%sy) 176 | print("") 177 | print("grad.z=%s;"%sz) 178 | 179 | faridd0=[0.229879,0.540242,0.229879] 180 | faridd1=[-0.425287,0,0.425287] 181 | nd0=faridd0 182 | nd1=faridd1 183 | gx=generateConvolutionCompact2D(nd1, nd0) 184 | gy=generateConvolutionCompact2D(nd0, nd1) 185 | print("Farid3 2D normalized") 186 | print("grad.x=%s;"%gx) 187 | print("") 188 | print("grad.y=%s;"%gy) 189 | print("") 190 | gx=generateConvolutionCompact3D(nd1, nd0, nd0) 191 | gy=generateConvolutionCompact3D(nd0, nd1, nd0) 192 | gz=generateConvolutionCompact3D(nd0, nd0, nd1) 193 | print("Farid3 3D normalized") 194 | print("grad.x=%s;"%gx) 195 | print("") 196 | print("grad.y=%s;"%gy) 197 | print("") 198 | print("grad.z=%s;"%gz) 199 | print("") 200 | 201 | faridd0=[0.037659, 0.249153, 0.426375, 0.249153, 0.037659] 202 | faridd1=[-0.109604,-0.276691, 0, 0.276691, 0.109604] 203 | nd0=faridd0 204 | nd1=faridd1 205 | gx=generateConvolutionCompact2D(nd1, nd0) 206 | gy=generateConvolutionCompact2D(nd0, nd1) 207 | print("Farid5 2D normalized") 208 | print("grad.x=%s;"%gx) 209 | print("") 210 | print("grad.y=%s;"%gy) 211 | print("") 212 | gx=generateConvolutionCompact3D(nd1, nd0, nd0) 213 | gy=generateConvolutionCompact3D(nd0, nd1, nd0) 214 | gz=generateConvolutionCompact3D(nd0, nd0, nd1) 215 | print("Farid5 3D normalized") 216 | print("grad.x=%s;"%gx) 217 | print("") 218 | print("grad.y=%s;"%gy) 219 | print("") 220 | print("grad.z=%s;"%gz) 221 | print("") 222 | -------------------------------------------------------------------------------- /include/AlgorithmsBarrierBuffers.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Logging 4 | #include "PLOG/PlogSetup.h" 5 | 6 | // External libraries 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // Internal libraries 13 | #include "DEN/DenProjectionMatrixReader.hpp" 14 | #include "Kniha.hpp" 15 | #include "MATRIX/LightProjectionMatrix.hpp" 16 | #include "MATRIX/ProjectionMatrix.hpp" 17 | #include "MATRIX/utils.hpp" 18 | #include "OPENCL/OpenCLManager.hpp" 19 | #include "PROG/KCTException.hpp" 20 | #include "ReductionParameters.hpp" 21 | #include "rawop.h" 22 | #include "stringFormatter.h" 23 | 24 | using namespace KCT::matrix; 25 | namespace KCT { 26 | 27 | class AlgorithmsBarrierBuffers : public virtual Kniha 28 | { 29 | public: 30 | AlgorithmsBarrierBuffers() 31 | { 32 | rp = nullptr; 33 | CLINCLUDEutils(); 34 | } 35 | 36 | AlgorithmsBarrierBuffers(uint32_t pdimx, 37 | uint32_t pdimy, 38 | uint32_t pdimz, 39 | uint32_t vdimx, 40 | uint32_t vdimy, 41 | uint32_t vdimz, 42 | uint32_t workGroupSize = 256) 43 | { 44 | initReductionParameters(pdimx, pdimy, pdimz, vdimx, vdimy, vdimz, workGroupSize); 45 | CLINCLUDEutils(); 46 | } 47 | 48 | void initReductionParameters(uint32_t pdimx, 49 | uint32_t pdimy, 50 | uint32_t pdimz, 51 | uint32_t vdimx, 52 | uint32_t vdimy, 53 | uint32_t vdimz, 54 | uint32_t workGroupSize = 256); 55 | 56 | int updateReductionParameters(uint32_t pdimx, 57 | uint32_t pdimy, 58 | uint32_t pdimz, 59 | uint32_t vdimx, 60 | uint32_t vdimy, 61 | uint32_t vdimz, 62 | uint32_t workGroupSize = 256); 63 | // Initialization of buffers 64 | int initReductionBuffers(); 65 | int updateReductionBuffers(); 66 | 67 | protected: 68 | std::shared_ptr rp; 69 | 70 | // Functions to manipulate with buffers 71 | float normBBuffer_barrier(cl::Buffer& B, 72 | std::shared_ptr rp = nullptr, 73 | uint32_t QID = 0); 74 | float normXBuffer_barrier(cl::Buffer& X, 75 | std::shared_ptr rp = nullptr, 76 | uint32_t QID = 0); 77 | float normBBuffer_frame(cl::Buffer& B, 78 | std::shared_ptr rp = nullptr, 79 | uint32_t QID = 0); 80 | float normXBuffer_frame(cl::Buffer& X, 81 | std::shared_ptr rp = nullptr, 82 | uint32_t QID = 0); 83 | float sumBBuffer_barrier_float(cl::Buffer& B, 84 | std::shared_ptr rp = nullptr, 85 | uint32_t QID = 0); 86 | float sumXBuffer_barrier_float(cl::Buffer& X, 87 | std::shared_ptr rp = nullptr, 88 | uint32_t QID = 0); 89 | float maxBBuffer_barrier_float(cl::Buffer& B, 90 | std::shared_ptr rp = nullptr, 91 | uint32_t QID = 0); 92 | float maxXBuffer_barrier_float(cl::Buffer& X, 93 | std::shared_ptr rp = nullptr, 94 | uint32_t QID = 0); 95 | float isotropicTVNormXBuffer_barrier_float(cl::Buffer& GX, 96 | cl::Buffer& GY, 97 | std::shared_ptr rp = nullptr, 98 | uint32_t QID = 0); 99 | double normBBuffer_barrier_double(cl::Buffer& B, 100 | std::shared_ptr rp = nullptr, 101 | uint32_t QID = 0); 102 | double normXBuffer_barrier_double(cl::Buffer& X, 103 | std::shared_ptr rp = nullptr, 104 | uint32_t QID = 0); 105 | double normBBuffer_frame_double(cl::Buffer& B, 106 | std::shared_ptr rp = nullptr, 107 | uint32_t QID = 0); 108 | double normXBuffer_frame_double(cl::Buffer& X, 109 | std::shared_ptr rp = nullptr, 110 | uint32_t QID = 0); 111 | double scalarProductBBuffer_barrier_double(cl::Buffer& A, 112 | cl::Buffer& B, 113 | std::shared_ptr rp = nullptr, 114 | uint32_t QID = 0); 115 | double scalarProductXBuffer_barrier_double(cl::Buffer& A, 116 | cl::Buffer& B, 117 | std::shared_ptr rp = nullptr, 118 | uint32_t QID = 0); 119 | 120 | double isotropicTVNormXBuffer_barrier_double(cl::Buffer& GX, 121 | cl::Buffer& GY, 122 | std::shared_ptr rp = nullptr, 123 | uint32_t QID = 0); 124 | /** 125 | * Copy float* array of size elements into the CL::buffer. The buffer must have appropriate 126 | * size. 127 | * 128 | * @param c_array Block of C memory 129 | * @param cl_buffer Block of OpenCL memory 130 | * @param size number of elements in c_array 131 | * 132 | * @return 0 on success 133 | */ 134 | int arrayIntoBuffer(float* c_array, cl::Buffer cl_buffer, uint64_t size, uint32_t QID = 0); 135 | /** 136 | * Copy CL:buffer into the float* array of size elements. The buffer must have appropriate size. 137 | * 138 | * @param cl_buffer Block of OpenCL memory 139 | * @param c_array Block of C memory 140 | * @param size number of elements in c_array 141 | * 142 | * @return 0 on success 143 | */ 144 | int bufferIntoArray(cl::Buffer cl_buffer, float* c_array, uint64_t size, uint32_t QID = 0); 145 | std::vector> tmp_red1; 146 | std::vector> tmp_red2; 147 | 148 | private: 149 | bool reductionParametersSet = false; 150 | bool algorithmsBuffersInitialized = false; 151 | uint64_t tmp_red1_bytesize = 0, tmp_red2_bytesize = 0; 152 | }; 153 | 154 | } // namespace KCT 155 | -------------------------------------------------------------------------------- /src/linalg-projector.cpp: -------------------------------------------------------------------------------- 1 | // Logging 2 | #include "PLOG/PlogSetup.h" 3 | 4 | // External libraries 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // External libraries 13 | #include "CLI/CLI.hpp" //Command line parser 14 | #include "ctpl_stl.h" //Threadpool 15 | 16 | // Internal libraries 17 | #include "SMA/BufferedSparseMatrixDoubleReader.hpp" 18 | #include "SMA/BufferedSparseMatrixFloatReader.hpp" 19 | #include "rawop.h" 20 | 21 | using namespace KCT; 22 | 23 | struct Args 24 | { 25 | std::vector typeStrings; 26 | Args() 27 | { 28 | typeStrings.push_back("float"); 29 | typeStrings.push_back("double"); 30 | } 31 | std::string inputVolume; 32 | std::string inputSystemMatrix; 33 | std::string systemMatrixType; 34 | std::string outputProjection; 35 | uint32_t threads = 1; 36 | // It is evaluated from -0.5, pixels are centerred at integer coordinates 37 | uint16_t projectionSizeX = 616; 38 | uint16_t projectionSizeY = 480; 39 | uint16_t projectionSizeZ = 1; 40 | // Here (0,0,0) is in the center of the volume 41 | uint16_t volumeSizeX = 256; 42 | uint16_t volumeSizeY = 256; 43 | uint16_t volumeSizeZ = 199; 44 | 45 | bool force = false; 46 | int parseArguments(int argc, char* argv[]); 47 | std::string checkTypeConsistency(const std::string& s) 48 | { 49 | if(std::find(typeStrings.begin(), typeStrings.end(), s) == typeStrings.end()) 50 | { 51 | return io::xprintf("The string that represents type is float or double not %s!", 52 | s.c_str()); 53 | } 54 | return ""; 55 | } 56 | }; 57 | 58 | int Args::parseArguments(int argc, char* argv[]) 59 | { 60 | // Checking type of system matrix 61 | std::function f 62 | = std::bind(&Args::checkTypeConsistency, this, std::placeholders::_1); 63 | 64 | CLI::App app{ "Project volume based on sparse system matrix." }; 65 | app.add_option("input_volume", inputVolume, 66 | "Volume in a DEN format to process. It is expected that the type is float.") 67 | ->required() 68 | ->check(CLI::ExistingFile); 69 | app.add_option("system_matrix", inputSystemMatrix, 70 | "System matrix to process to project volume data.") 71 | ->required() 72 | ->check(CLI::ExistingFile); 73 | app.add_option("system_matrix_type", systemMatrixType, 74 | "Type of the system matrix, that is float or double.") 75 | ->required() 76 | ->check(f); 77 | app.add_option("output_projection", outputProjection, 78 | "DEN file with the projections to output as floats.") 79 | ->required(); 80 | 81 | app.add_option("-j,--threads", threads, "Number of extra threads that application can use.") 82 | ->check(CLI::Range(1, 65535)); 83 | app.add_flag("-f,--force", force, "Overwrite output_projection if it exists."); 84 | CLI::Option* px 85 | = app.add_option("--projx", projectionSizeX, "Dimension of detector, defaults to 616."); 86 | CLI::Option* py 87 | = app.add_option("--projy", projectionSizeY, "Dimension of detector, defaults to 480."); 88 | CLI::Option* vx 89 | = app.add_option("--volumex", volumeSizeX, "Dimension of volume, defaults to 256."); 90 | CLI::Option* vy 91 | = app.add_option("--volumey", volumeSizeY, "Dimension of volume, defaults to 256."); 92 | CLI::Option* vz 93 | = app.add_option("--volumez", volumeSizeZ, "Dimension of volume, defaults to 199."); 94 | px->needs(py); 95 | py->needs(px); 96 | vx->needs(vy)->needs(vz); 97 | vy->needs(vx)->needs(vz); 98 | vz->needs(vx)->needs(vy); 99 | try 100 | { 101 | app.parse(argc, argv); 102 | if(!force) 103 | { 104 | if(io::pathExists(outputProjection)) 105 | { 106 | std::string msg 107 | = "Error: output file already exists, use --force to force overwrite."; 108 | LOGE << msg; 109 | return 1; 110 | } 111 | } 112 | } catch(const CLI::CallForHelp& e) 113 | { 114 | app.exit(e); // Prints help message 115 | return 1; 116 | } catch(const CLI::ParseError& e) 117 | { 118 | int exitcode = app.exit(e); 119 | LOGE << io::xprintf("There was perse error with exit code %d catched.\n %s", exitcode, 120 | app.help().c_str()); 121 | return -1; 122 | } catch(...) 123 | { 124 | LOGE << "Unknown exception catched"; 125 | return -1; 126 | } 127 | return 0; 128 | } 129 | 130 | int main(int argc, char* argv[]) 131 | { 132 | plog::Severity verbosityLevel = plog::debug; // debug, info, ... 133 | std::string csvLogFile = io::xprintf( 134 | "/tmp/%s.csv", io::getBasename(std::string(argv[0])).c_str()); // Set NULL to disable 135 | bool logToConsole = true; 136 | plog::PlogSetup plogSetup(verbosityLevel, csvLogFile, logToConsole); 137 | plogSetup.initLogging(); 138 | // Argument parsing 139 | Args a; 140 | int parseResult = a.parseArguments(argc, argv); 141 | if(parseResult != 0) 142 | { 143 | if(parseResult > 0) 144 | { 145 | return 0; // Exited sucesfully, help message printed 146 | } else 147 | { 148 | return -1; // Exited somehow wrong 149 | } 150 | } 151 | LOGI << io::xprintf("START %s", argv[0]); 152 | // Argument parsing 153 | 154 | // Frames to process 155 | uint64_t totalVolumeSize = uint64_t(a.volumeSizeX) * a.volumeSizeY * a.volumeSizeZ; 156 | float* volume = new float[totalVolumeSize]; 157 | io::readBytesFrom(a.inputVolume, 6, (uint8_t*)volume, totalVolumeSize * 4); 158 | uint64_t totalProjectionSize 159 | = uint64_t(a.projectionSizeX) * a.projectionSizeY * a.projectionSizeZ; 160 | float* projection = new float[totalProjectionSize](); // Initialized by zeros 161 | if(a.systemMatrixType == "float") 162 | { 163 | uint32_t i, j; 164 | float v; 165 | matrix::BufferedSparseMatrixFloatReader A(a.inputSystemMatrix, 16384); 166 | uint64_t elements = A.getNumberOfElements(); 167 | 168 | while(elements != 0) 169 | { 170 | A.readNextValue(&i, &j, &v); 171 | projection[j] += volume[i] * v; 172 | elements--; 173 | } 174 | } else if(a.systemMatrixType == "double") 175 | { 176 | uint32_t i, j; 177 | double v; 178 | matrix::BufferedSparseMatrixDoubleReader A(a.inputSystemMatrix, 16384); 179 | uint64_t elements = A.getNumberOfElements(); 180 | while(elements != 0) 181 | { 182 | A.readNextValue(&i, &j, &v); 183 | projection[j] += float(volume[i] * v); 184 | elements--; 185 | } 186 | } 187 | uint16_t buf[3]; 188 | buf[0] = a.projectionSizeY; 189 | buf[1] = a.projectionSizeX; 190 | buf[2] = a.projectionSizeZ; 191 | io::createEmptyFile(a.outputProjection, 0, true); // Try if this is faster 192 | io::appendBytes(a.outputProjection, (uint8_t*)buf, 6); 193 | io::appendBytes(a.outputProjection, (uint8_t*)projection, totalProjectionSize * 4); 194 | delete[] volume; 195 | delete[] projection; 196 | LOGI << io::xprintf("END %s", argv[0]); 197 | } 198 | -------------------------------------------------------------------------------- /src/linalg-sort.cpp: -------------------------------------------------------------------------------- 1 | // Logging 2 | #include "PLOG/PlogSetup.h" 3 | 4 | // External libraries 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | // External libraries 14 | #include "CLI/CLI.hpp" //Command line parser 15 | #include "ctpl_stl.h" //Threadpool 16 | 17 | // Internal libraries 18 | #include "SMA/BufferedSparseMatrixDoubleReader.hpp" 19 | #include "SMA/BufferedSparseMatrixDoubleWritter.hpp" 20 | #include "SMA/BufferedSparseMatrixFloatReader.hpp" 21 | #include "SMA/BufferedSparseMatrixFloatWritter.hpp" 22 | 23 | using namespace KCT; 24 | 25 | struct Args 26 | { 27 | std::vector typeStrings; 28 | Args() 29 | { 30 | typeStrings.push_back("float"); 31 | typeStrings.push_back("double"); 32 | } 33 | std::string unsortedMatrix; 34 | std::string unsortedType; 35 | std::string sortedMatrix; 36 | std::string sortedType; 37 | bool force = false; 38 | bool bySecondIndex = false; 39 | int parseArguments(int argc, char* argv[]); 40 | std::string checkTypeConsistency(const std::string& s) 41 | { 42 | if(std::find(typeStrings.begin(), typeStrings.end(), s) == typeStrings.end()) 43 | { 44 | return io::xprintf("The string that represents type is float or double not %s!", 45 | s.c_str()); 46 | } 47 | return ""; 48 | } 49 | }; 50 | 51 | int Args::parseArguments(int argc, char* argv[]) 52 | { 53 | CLI::App app{ "Sort sparse matrices." }; 54 | app.add_flag("-f,--force", force, "Overwrite outputFile if it exists."); 55 | app.add_flag("-j,--bySecondIndex", bySecondIndex, 56 | "Sort by the second index, if this flag is not specified sorting will by by the " 57 | "first index."); 58 | 59 | std::function f 60 | = std::bind(&Args::checkTypeConsistency, this, std::placeholders::_1); 61 | app.add_option("unsorted_matrix", unsortedMatrix, "File with the unsorted matrix.") 62 | ->required() 63 | ->check(CLI::ExistingFile); 64 | app.add_option("unsorted_type", unsortedType, 65 | "Type of the unsorted matrix, that is float or double.") 66 | ->required() 67 | ->check(f); 68 | app.add_option("sorted_matrix", sortedMatrix, "Output file with the sorted matrix.") 69 | ->required(); 70 | app.add_option("sorted_type", sortedType, "Type of the sorted matrix, that is float or double.") 71 | ->required() 72 | ->check(f); 73 | try 74 | { 75 | app.parse(argc, argv); 76 | if(!force) 77 | { 78 | if(io::pathExists(sortedMatrix)) 79 | { 80 | std::string msg 81 | = "Error: output file already exists, use --force to force overwrite."; 82 | LOGE << msg; 83 | return 1; 84 | } 85 | } 86 | } catch(const CLI::CallForHelp& e) 87 | { 88 | app.exit(e); // Prints help message 89 | return 1; 90 | } catch(const CLI::ParseError& e) 91 | { 92 | int exitcode = app.exit(e); 93 | LOGE << io::xprintf("There was perse error with exit code %d catched.\n %s", exitcode, 94 | app.help().c_str()); 95 | return -1; 96 | } catch(...) 97 | { 98 | LOGE << "Unknown exception catched"; 99 | } 100 | return 0; 101 | } 102 | 103 | int main(int argc, char* argv[]) 104 | { 105 | plog::Severity verbosityLevel = plog::debug; // debug, info, ... 106 | std::string csvLogFile = io::xprintf( 107 | "/tmp/%s.csv", io::getBasename(std::string(argv[0])).c_str()); // Set NULL to disable 108 | bool logToConsole = true; 109 | plog::PlogSetup plogSetup(verbosityLevel, csvLogFile, logToConsole); 110 | plogSetup.initLogging(); 111 | // Argument parsing 112 | Args a; 113 | int parseResult = a.parseArguments(argc, argv); 114 | if(parseResult != 0) 115 | { 116 | if(parseResult > 0) 117 | { 118 | return 0; // Exited sucesfully, help message printed 119 | } else 120 | { 121 | return -1; // Exited somehow wrong 122 | } 123 | } 124 | LOGI << io::xprintf("START %s", argv[0]); 125 | // Frames to process 126 | if(a.unsortedType == "double") 127 | { 128 | matrix::BufferedSparseMatrixDoubleReader input(a.unsortedMatrix); 129 | uint64_t numberOfElements = input.getNumberOfElements(); 130 | std::vector elements; 131 | for(uint64_t k = 0; k != numberOfElements; k++) 132 | { 133 | elements.push_back(input.readNextElement()); 134 | } 135 | if(a.bySecondIndex) 136 | { 137 | std::sort(elements.begin(), elements.end(), std::greater()); 138 | } else 139 | { 140 | std::sort(elements.begin(), elements.end()); 141 | } 142 | if(a.sortedType == "double") 143 | { 144 | matrix::BufferedSparseMatrixDoubleWritter output(a.sortedMatrix); 145 | for(uint64_t k = 0; k != numberOfElements; k++) 146 | { 147 | output.insertValue(elements[k].i, elements[k].j, elements[k].v); 148 | } 149 | output.flush(); 150 | } else if(a.sortedType == "float") 151 | { 152 | matrix::BufferedSparseMatrixFloatWritter output(a.sortedMatrix); 153 | for(uint64_t k = 0; k != numberOfElements; k++) 154 | { 155 | output.insertValue(elements[k].i, elements[k].j, elements[k].v); 156 | } 157 | output.flush(); 158 | } else 159 | { 160 | io::throwerr("Unsupported output type"); 161 | } 162 | } else if(a.unsortedType == "float") 163 | { 164 | matrix::BufferedSparseMatrixFloatReader input(a.unsortedMatrix); 165 | uint64_t numberOfElements = input.getNumberOfElements(); 166 | std::vector elements; 167 | for(uint64_t k = 0; k != numberOfElements; k++) 168 | { 169 | elements.push_back(input.readNextElement()); 170 | } 171 | if(a.bySecondIndex) 172 | { 173 | std::sort(elements.begin(), elements.end(), std::greater()); 174 | } else 175 | { 176 | std::sort(elements.begin(), elements.end()); 177 | } 178 | if(a.sortedType == "double") 179 | { 180 | matrix::BufferedSparseMatrixDoubleWritter output(a.sortedMatrix); 181 | for(uint64_t k = 0; k != numberOfElements; k++) 182 | { 183 | output.insertValue(elements[k].i, elements[k].j, elements[k].v); 184 | } 185 | output.flush(); 186 | } else if(a.sortedType == "float") 187 | { 188 | matrix::BufferedSparseMatrixFloatWritter output(a.sortedMatrix); 189 | for(uint64_t k = 0; k != numberOfElements; k++) 190 | { 191 | output.insertValue(elements[k].i, elements[k].j, elements[k].v); 192 | } 193 | output.flush(); 194 | } else 195 | { 196 | io::throwerr("Unsupported output type"); 197 | } 198 | } else 199 | { 200 | io::throwerr("Unsupported input type"); 201 | } 202 | LOGI << io::xprintf("END %s", argv[0]); 203 | } 204 | -------------------------------------------------------------------------------- /src/Perfusion/GLSQRPerfusionReconstructor.cpp: -------------------------------------------------------------------------------- 1 | #include "Perfusion/GLSQRPerfusionReconstructor.hpp" 2 | 3 | namespace KCT { 4 | 5 | int GLSQRPerfusionReconstructor::reconstruct(uint32_t maxIterations, 6 | float errCondition, 7 | bool blocking) 8 | { 9 | reportTime("WELCOME TO GLSQR, init perfusion", false, true); 10 | uint32_t iteration = 0; 11 | 12 | // Initialization 13 | double NB0 = std::sqrt(normBBuffer_barrier_double(b_buf)); 14 | LOGI << io::xprintf("||b||=%f", NB0); 15 | std::vector> u_prev, u_cur, u_next; 16 | std::vector> v_prev, v_cur, v_next; 17 | std::vector> w_prev_prev, w_prev, w_cur; 18 | std::vector> x_cur; 19 | std::vector> XZ, BZ; 20 | allocateXBuffers(4); 21 | allocateTmpXBuffers(1); 22 | allocateBBuffers(2); 23 | allocateTmpBBuffers(1); 24 | 25 | // Anything might be supplied here, but we will do standard initialization first 26 | v_next = getXBuffers(0); 27 | zeroXBuffers(v_next); 28 | backproject(b_buf, v_next); 29 | // LOGD << io::xprintf("Writing file v_init.den"); 30 | // writeVolume(*v_next, io::xprintf("v_init.den")); 31 | double vnextnorm = std::sqrt(normXBuffer_barrier_double(v_next)); 32 | LOGI << io::xprintf("vnextnorm=%f", vnextnorm); 33 | scaleFloatVector(v_next, float(1.0 / vnextnorm), XDIM); 34 | bool initializedByScaledBackprojectedRightSide = true; 35 | 36 | double d = 0.0; 37 | 38 | u_cur = getBBuffers(0); 39 | zeroBBuffers(u_cur); 40 | 41 | v_cur = getXBuffers(1); 42 | zeroXBuffers(v_cur); 43 | 44 | double varphi_hat = NB0; 45 | 46 | u_next = getBBuffers(1); 47 | zeroBBuffers(u_next); 48 | addIntoFirstVectorSecondVectorScaled(u_next, b_buf, float(1.0 / varphi_hat), BDIM); 49 | 50 | x_cur = x_buf; 51 | zeroXBuffers(x_cur); 52 | 53 | w_cur = getXBuffers(2); 54 | zeroXBuffers(w_cur); 55 | 56 | w_prev = getXBuffers(3); 57 | zeroXBuffers(w_prev); 58 | 59 | double rho_cur = 1.0; 60 | double rho_prev = 1.0; 61 | double c_cur = -1.0; 62 | double c_prev = -1.0; 63 | double s_cur = 0.0; 64 | double s_prev = 0.0; 65 | 66 | XZ = getTmpXBuffers(0); 67 | BZ = getTmpBBuffers(0); 68 | double c_prev_prev; 69 | double s_prev_prev; 70 | double rho_prev_prev; 71 | double sigma_prev; 72 | double sigma_cur; 73 | double sigma_next; 74 | double sigma_tol = 0.001; // Based on the fact that numerical error is on the level ~0.0002 75 | double tau_cur, tau_prev, tau_next; 76 | double gamma; 77 | double varphi; 78 | double theta; 79 | double rho_hat; 80 | 81 | while(std::abs(varphi_hat) / NB0 > errCondition && iteration < maxIterations) 82 | { 83 | // Iteration 84 | iteration = iteration + 1; 85 | 86 | u_prev = u_cur; 87 | u_cur = u_next; 88 | // u_next = u_prev; will be issued after u_prev is not used 89 | 90 | v_prev = v_cur; 91 | v_cur = v_next; 92 | // v_next=v_prev will be issued after v_prev is not used 93 | 94 | c_prev_prev = c_prev; 95 | c_prev = c_cur; 96 | 97 | s_prev_prev = s_prev; 98 | s_prev = s_cur; 99 | 100 | w_prev_prev = w_prev; 101 | w_prev = w_cur; 102 | // w_cur=w_prev_prev will be issued after it is possible 103 | 104 | rho_prev_prev = rho_prev; 105 | rho_prev = rho_cur; 106 | 107 | backproject(u_cur, XZ); 108 | sigma_prev = scalarProductXBuffer_barrier_double(XZ, v_prev); 109 | addIntoFirstVectorSecondVectorScaled(XZ, v_prev, float(-sigma_prev), XDIM); 110 | v_next = v_prev; 111 | LOGI << io::xprintf("sigma_prev=%f", sigma_prev); 112 | 113 | if(d == 0.0) 114 | { 115 | LOGI << "d=0.0"; 116 | sigma_cur = scalarProductXBuffer_barrier_double(XZ, v_cur); 117 | addIntoFirstVectorSecondVectorScaled(XZ, v_cur, float(-sigma_cur), XDIM); 118 | 119 | sigma_next = std::sqrt(normXBuffer_barrier_double(XZ)); 120 | LOGI << io::xprintf("sigma_next=%f", sigma_next); 121 | 122 | if(initializedByScaledBackprojectedRightSide) 123 | { 124 | LOGI << io::xprintf("Size of numerical error sigma_next=%f", sigma_next); 125 | sigma_next = 0; 126 | } 127 | 128 | if(sigma_next > sigma_tol) 129 | { 130 | algFLOATvector_A_equals_cB(v_next, XZ, float(1.0f / sigma_next), XDIM); 131 | } else 132 | { 133 | d = 1.0; 134 | } 135 | } else 136 | { 137 | LOGI << "d=1.0"; 138 | sigma_cur = std::sqrt(normXBuffer_barrier_double(XZ)); 139 | LOGI << io::xprintf("sigma_cur=%f", sigma_cur); 140 | 141 | if(sigma_cur > sigma_tol) 142 | { 143 | algFLOATvector_A_equals_cB(v_cur, XZ, float(1.0f / sigma_cur), XDIM); 144 | } else 145 | { 146 | LOGI << "Ending due to the convergence"; 147 | break; 148 | } 149 | } 150 | 151 | project(v_cur, BZ); 152 | tau_prev = scalarProductBBuffer_barrier_double(BZ, u_prev); 153 | addIntoFirstVectorSecondVectorScaled(BZ, u_prev, float(-tau_prev), BDIM); 154 | u_next = u_prev; 155 | 156 | tau_cur = scalarProductBBuffer_barrier_double(BZ, u_cur); 157 | addIntoFirstVectorSecondVectorScaled(BZ, u_cur, float(-tau_cur), BDIM); 158 | tau_next = std::sqrt(normBBuffer_barrier_double(BZ)); 159 | LOGE << io::xprintf("tau_prev=%f, tau_cur=%f, tau_next=%f", tau_prev, tau_cur, tau_next); 160 | 161 | if(tau_next != 0) 162 | { 163 | algFLOATvector_A_equals_cB(u_next, BZ, float(1.0f / tau_next), BDIM); 164 | } 165 | 166 | gamma = s_prev_prev * tau_prev; 167 | theta = -c_prev * c_prev_prev * tau_prev + s_prev * tau_cur; 168 | rho_hat = -s_prev * c_prev_prev * tau_prev - c_prev * tau_cur; 169 | LOGE << io::xprintf("gamma=%f, theta=%f, rho_hat=%f", gamma, theta, rho_hat); 170 | 171 | rho_cur = std::sqrt(rho_hat * rho_hat + tau_next * tau_next); 172 | c_cur = rho_hat / rho_cur; 173 | s_cur = tau_next / rho_cur; 174 | LOGE << io::xprintf("rho_cur=%f, s_cur=%f, c_cur=%f", rho_cur, s_cur, c_cur); 175 | // 24 176 | varphi = c_cur * varphi_hat; 177 | varphi_hat = s_cur * varphi_hat; 178 | // 25 179 | w_cur = w_prev_prev; 180 | addIntoFirstVectorScaledSecondVector(w_cur, v_cur, float(-gamma / rho_prev_prev), XDIM); 181 | addIntoFirstVectorSecondVectorScaled(w_cur, w_prev, float(-theta / rho_prev), XDIM); 182 | 183 | // 26 184 | addIntoFirstVectorSecondVectorScaled(x_cur, w_cur, float(varphi / rho_cur), XDIM); 185 | if(tau_next == 0) 186 | { 187 | LOGI << "Ending due to the convergence"; 188 | break; 189 | } 190 | 191 | LOGW << io::xprintf("After iteration %d, the norm of |Ax-b| is %f that is %0.2f%% of NB0.", 192 | iteration, std::abs(varphi_hat), 100.0 * std::abs(varphi_hat) / NB0); 193 | if(reportKthIteration > 0 && iteration % reportKthIteration == 0) 194 | { 195 | LOGD << io::xprintf("Writing file %sx_it%02d.den", progressPrefixPath.c_str(), 196 | iteration); 197 | writeVolume(x_cur, 198 | io::xprintf("%sx_it%02d.den", progressPrefixPath.c_str(), iteration)); 199 | } 200 | } 201 | for(std::uint32_t vectorID = 0; vectorID != XVNUM; vectorID++) 202 | { 203 | Q[0]->enqueueReadBuffer(*x_cur[vectorID], CL_TRUE, 0, sizeof(float) * XDIM, x[vectorID]); 204 | } 205 | return 0; 206 | } 207 | 208 | } // namespace KCT 209 | -------------------------------------------------------------------------------- /src/PSIRTReconstructor.cpp: -------------------------------------------------------------------------------- 1 | #include "PSIRTReconstructor.hpp" 2 | 3 | namespace KCT { 4 | 5 | void PSIRTReconstructor::setup(double alpha) { this->alpha = alpha; } 6 | 7 | int PSIRTReconstructor::reconstruct(uint32_t maxIterations, float errCondition) 8 | { 9 | bool boxconditions = false; 10 | LOGD << printTime("WELCOME TO PSIRT, init", false, true); 11 | int iteration = 0; 12 | 13 | // Initialization 14 | allocateBBuffers(2); 15 | allocateXBuffers(2); 16 | std::shared_ptr rowsums_bbuf, invrowsums_bbuf, discrepancy_bbuf; // B buffers 17 | std::shared_ptr ones_xbuf, update_xbuf; // X buffers 18 | rowsums_bbuf = getBBuffer(0); 19 | discrepancy_bbuf = getBBuffer(1); 20 | ones_xbuf = getXBuffer(0); 21 | update_xbuf = getXBuffer(1); 22 | Q[0]->enqueueFillBuffer(*ones_xbuf, FLOATONE, 0, XDIM * sizeof(float)); 23 | Q[0]->enqueueFillBuffer(*discrepancy_bbuf, FLOATONE, 0, BDIM * sizeof(float)); 24 | project(*ones_xbuf, *rowsums_bbuf); 25 | // Ones used to store col sums 26 | backproject(*discrepancy_bbuf, *ones_xbuf); 27 | double A1norm = maxXBuffer_barrier_float(*ones_xbuf); 28 | // double A2norm = std::sqrt(normBBuffer_barrier_double(*rowsums_bbuf)); 29 | // double p = 0.001 * BDIM / A1norm; 30 | double p = 1.0 / A1norm; // In 10.1109/TMI.2008.923696 authors probably mistakedly call the 31 | // ||A||_1 what should be the largest col sum of A as they claim 32 | // Since the largest row sum of AT in turn equals the largest column 33 | // sum of A and thus the 1-norm of A. Tried here with 34 | // ||A||_1 without success 35 | if(!useVolumeAsInitialX0) 36 | { 37 | Q[0]->enqueueFillBuffer(*x_buf, FLOATZERO, 0, XDIM * sizeof(float)); 38 | } 39 | algFLOATvector_invert_except_zero(*rowsums_bbuf, BDIM); 40 | invrowsums_bbuf = rowsums_bbuf; 41 | double norm, normupdate, normx; 42 | double NB0 = std::sqrt(normBBuffer_barrier_double(*b_buf)); 43 | norm = NB0; 44 | LOGI << io::xprintf("||b||=%f, p=%f, A1norm=%f, alpha=%f", NB0, p, A1norm, alpha); 45 | // LOGI << io::xprintf("||b||=%f, p=%f, A2norm=%f", NB0, p, A2norm); 46 | 47 | while(norm / NB0 > errCondition && iteration - 1 < int(maxIterations)) 48 | { 49 | project(*x_buf, *discrepancy_bbuf); 50 | algFLOATvector_A_equals_Ac_plus_B(*discrepancy_bbuf, *b_buf, -1.0, BDIM); 51 | norm = std::sqrt(normBBuffer_barrier_double(*discrepancy_bbuf)); 52 | LOGI << io::xprintf_green("\nIteration %d: |Ax-b|=%0.1f representing %0.2f%% of |b|.", 53 | iteration, norm, 100.0 * norm / NB0); 54 | iteration++; 55 | algFLOATvector_A_equals_A_times_B(*discrepancy_bbuf, *invrowsums_bbuf, BDIM); 56 | backproject(*discrepancy_bbuf, *update_xbuf); 57 | if(iteration == 1) 58 | { 59 | LOGD << "Scaling in the first iteration"; 60 | algFLOATvector_scale(*update_xbuf, p, XDIM); 61 | } else 62 | { 63 | algFLOATvector_scale(*update_xbuf, alpha * p, XDIM); 64 | } 65 | normupdate = std::sqrt(normXBuffer_barrier_double(*update_xbuf)); 66 | normx = std::sqrt(normXBuffer_barrier_double(*x_buf)); 67 | algFLOATvector_A_equals_A_plus_cB(*x_buf, *update_xbuf, 1.0, XDIM); 68 | if(boxconditions) 69 | { 70 | algFLOATvector_substitute_greater_than(*x_buf, 1.0, 1.0, XDIM); 71 | algFLOATvector_substitute_lower_than(*x_buf, 0.0, 0.0, XDIM); 72 | } 73 | LOGI << io::xprintf_green("Size of x=%f and size of the update=%f.", normx, normupdate); 74 | // algFLOATvector_A_equals_A_plus_cB(*x_buf, *update_xbuf, alpha * p, XDIM); 75 | // algFLOATvector_A_equals_A_plus_cB(*x_buf, *update_xbuf, alpha * p, XDIM); 76 | if(reportKthIteration > 0 && iteration % reportKthIteration == 0) 77 | { 78 | LOGD << io::xprintf("Writing file %sx_it%02d.den", intermediatePrefix.c_str(), 79 | iteration); 80 | writeVolume(*x_buf, 81 | io::xprintf("%sx_it%02d.den", intermediatePrefix.c_str(), iteration)); 82 | } 83 | } 84 | LOGI << io::xprintf_green("\nIteration %d: |Ax-b|=%0.1f representing %0.2f%% of |b|.", 85 | iteration, norm, 100.0 * norm / NB0); 86 | Q[0]->enqueueReadBuffer(*x_buf, CL_TRUE, 0, sizeof(float) * XDIM, x); 87 | return 0; 88 | } 89 | 90 | int PSIRTReconstructor::reconstruct_sirt(uint32_t maxIterations, float errCondition) 91 | { 92 | bool boxconditions = true; 93 | LOGD << printTime("WELCOME TO SIRT, init", false, true); 94 | uint32_t iteration = 0; 95 | 96 | // Initialization 97 | allocateBBuffers(2); 98 | allocateXBuffers(2); 99 | std::shared_ptr rowsums_bbuf, invrowsums_bbuf, discrepancy_bbuf; // B buffers 100 | std::shared_ptr invcolsums_xbuf, update_xbuf; // X buffers 101 | rowsums_bbuf = getBBuffer(0); 102 | discrepancy_bbuf = getBBuffer(1); 103 | invcolsums_xbuf = getXBuffer(0); 104 | update_xbuf = getXBuffer(1); 105 | Q[0]->enqueueFillBuffer(*invcolsums_xbuf, FLOATONE, 0, XDIM * sizeof(float)); 106 | Q[0]->enqueueFillBuffer(*discrepancy_bbuf, FLOATONE, 0, BDIM * sizeof(float)); 107 | project(*invcolsums_xbuf, *rowsums_bbuf); 108 | backproject(*discrepancy_bbuf, *invcolsums_xbuf); 109 | algFLOATvector_invert_except_zero(*rowsums_bbuf, BDIM); 110 | algFLOATvector_invert_except_zero(*invcolsums_xbuf, XDIM); 111 | invrowsums_bbuf = rowsums_bbuf; 112 | if(!useVolumeAsInitialX0) 113 | { 114 | Q[0]->enqueueFillBuffer(*x_buf, FLOATZERO, 0, XDIM * sizeof(float)); 115 | } 116 | double norm, normupdate, normx; 117 | double NB0 = std::sqrt(normBBuffer_barrier_double(*b_buf)); 118 | norm = NB0; 119 | while(norm / NB0 > errCondition && iteration < maxIterations) 120 | { 121 | iteration++; 122 | project(*x_buf, *discrepancy_bbuf); 123 | algFLOATvector_A_equals_Ac_plus_B(*discrepancy_bbuf, *b_buf, -1.0, BDIM); 124 | norm = std::sqrt(normBBuffer_barrier_double(*discrepancy_bbuf)); 125 | LOGI << io::xprintf_green("Iteration %d, the norm of |Ax-b| is %f that is %0.2f%% of |b|.", 126 | iteration, norm, 100.0 * norm / NB0); 127 | algFLOATvector_A_equals_A_times_B(*discrepancy_bbuf, *invrowsums_bbuf, BDIM); 128 | backproject(*discrepancy_bbuf, *update_xbuf); 129 | algFLOATvector_A_equals_A_times_B(*update_xbuf, *invcolsums_xbuf, XDIM); 130 | algFLOATvector_scale(*update_xbuf, alpha, XDIM); 131 | normupdate = std::sqrt(normXBuffer_barrier_double(*update_xbuf)); 132 | normx = std::sqrt(normXBuffer_barrier_double(*x_buf)); 133 | algFLOATvector_A_equals_A_plus_cB(*x_buf, *update_xbuf, 1.0, XDIM); 134 | if(boxconditions) 135 | { 136 | algFLOATvector_substitute_greater_than(*x_buf, 1.0, 1.0, XDIM); 137 | algFLOATvector_substitute_lower_than(*x_buf, 0.0, 0.0, XDIM); 138 | } 139 | LOGI << io::xprintf_green("Size of x=%f and size of the update=%f.", normx, normupdate); 140 | // algFLOATvector_A_equals_A_plus_cB(*x_buf, *update_xbuf, alpha * p, XDIM); 141 | // algFLOATvector_A_equals_A_plus_cB(*x_buf, *update_xbuf, alpha * p, XDIM); 142 | if(reportKthIteration > 0 && iteration % reportKthIteration == 0) 143 | { 144 | LOGD << io::xprintf("Writing file %sx_it%02d.den", intermediatePrefix.c_str(), 145 | iteration); 146 | writeVolume(*x_buf, 147 | io::xprintf("%sx_it%02d.den", intermediatePrefix.c_str(), iteration)); 148 | } 149 | } 150 | LOGI << io::xprintf_green("Iteration %d, the norm of |Ax-b| is %f that is %0.2f%% of |b|.", 151 | iteration, norm, 100.0 * norm / NB0); 152 | Q[0]->enqueueReadBuffer(*x_buf, CL_TRUE, 0, sizeof(float) * XDIM, x); 153 | return 0; 154 | } 155 | } // namespace KCT 156 | -------------------------------------------------------------------------------- /include/BasePBCTOperator.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Logging 4 | #include "PLOG/PlogSetup.h" 5 | 6 | // External libraries 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // Internal libraries 13 | #include "AlgorithmsBarrierBuffers.hpp" 14 | #include "BufferedFrame2D.hpp" 15 | #include "DEN/DenAsyncFrame2DWritter.hpp" 16 | #include "DEN/DenProjectionMatrixReader.hpp" 17 | #include "GEOMETRY/Geometry3DParallelI.hpp" 18 | #include "Kniha.hpp" 19 | #include "MATRIX/LightProjectionMatrix.hpp" 20 | #include "MATRIX/ProjectionMatrix.hpp" 21 | #include "MATRIX/utils.hpp" 22 | #include "NDRange/NDRangeHelper.hpp" 23 | #include "NDRange/PBCTLocalNDRangeFactory.hpp" 24 | #include "OPENCL/OpenCLManager.hpp" 25 | #include "rawop.h" 26 | #include "stringFormatter.h" 27 | 28 | using namespace KCT::matrix; 29 | namespace KCT { 30 | 31 | class BasePBCTOperator : public virtual Kniha, public AlgorithmsBarrierBuffers 32 | { 33 | public: 34 | cl::NDRange guessProjectionLocalNDRange(bool barrierCalls); 35 | cl::NDRange guessBackprojectorLocalNDRange(); 36 | 37 | BasePBCTOperator(uint32_t pdimx, 38 | uint32_t pdimy, 39 | uint32_t pdimz, 40 | uint32_t vdimx, 41 | uint32_t vdimy, 42 | uint32_t vdimz, 43 | uint32_t workGroupSize = 256) 44 | : AlgorithmsBarrierBuffers(pdimx, pdimy, pdimz, vdimx, vdimy, vdimz, workGroupSize) 45 | , pdimx(pdimx) 46 | , pdimy(pdimy) 47 | , pdimz(pdimz) 48 | , vdimx(vdimx) 49 | , vdimy(vdimy) 50 | , vdimz(vdimz) 51 | , workGroupSize(workGroupSize) 52 | { 53 | XDIM = uint64_t(vdimx) * uint64_t(vdimy) * uint64_t(vdimz); 54 | BDIM = uint64_t(pdimx) * uint64_t(pdimy) * uint64_t(pdimz); 55 | pdims = cl_int2({ int(pdimx), int(pdimy) }); 56 | pdims_uint = cl_uint2({ pdimx, pdimy }); 57 | vdims = cl_int3({ int(vdimx), int(vdimy), int(vdimz) }); 58 | timestamp = std::chrono::steady_clock::now(); 59 | } 60 | 61 | void initializeCVPProjector(bool barrierVariant, uint32_t LOCALARRAYSIZE = 7680); 62 | void initializeSiddonProjector(uint32_t probesPerEdgeX, uint32_t probesPerEdgeY); 63 | void initializeTTProjector(); 64 | void initializeVolumeConvolution(); 65 | 66 | int initializeOpenCL(uint32_t platformID, 67 | uint32_t* deviceIds, 68 | uint32_t deviceIdsLength, 69 | std::string xpath, 70 | bool debug, 71 | bool relaxed, 72 | cl::NDRange projectorLocalNDRange = cl::NullRange, 73 | cl::NDRange backprojectorLocalNDRange = cl::NullRange); 74 | 75 | void useJacobiVectorCLCode(); 76 | 77 | int problemSetup(std::vector> geometries, 78 | double voxelSpacingX, 79 | double voxelSpacingY, 80 | double voxelSpacingZ, 81 | double volumeCenterX = 0.0, 82 | double volumeCenterY = 0.0, 83 | double volumeCenterZ = 0.0); 84 | 85 | int allocateXBuffers(uint32_t xBufferCount); 86 | int allocateBBuffers(uint32_t bBufferCount); 87 | int allocateTmpXBuffers(uint32_t xBufferCount); 88 | int allocateTmpBBuffers(uint32_t bBufferCount); 89 | std::shared_ptr getBBuffer(uint32_t i); 90 | std::shared_ptr getXBuffer(uint32_t i); 91 | std::shared_ptr getTmpBBuffer(uint32_t i); 92 | std::shared_ptr getTmpXBuffer(uint32_t i); 93 | 94 | double adjointProductTest(float* x, float* b); 95 | 96 | void setVerbose(bool verbose, std::string intermediatePrefix = ""); 97 | 98 | std::vector computeScalingFactors(); 99 | 100 | protected: 101 | const cl_float FLOATZERO = 0.0f; 102 | const cl_double DOUBLEZERO = 0.0; 103 | float FLOATONE = 1.0f; 104 | // Constructor defined variables 105 | cl_int2 pdims; 106 | cl_uint2 pdims_uint; 107 | cl_int3 vdims; 108 | 109 | // Problem setup variables 110 | double voxelSpacingX, voxelSpacingY, voxelSpacingZ; 111 | cl_double3 voxelSizes; 112 | cl_double3 volumeCenter; 113 | std::vector> geometries; 114 | std::vector PM8Vector; 115 | std::vector scalingFactorVector; 116 | 117 | // Variables for projectors and openCL initialization 118 | bool useCVPProjector = true; 119 | bool useBarrierImplementation = false; 120 | uint32_t LOCALARRAYSIZE = 0; 121 | bool useSiddonProjector = false; 122 | cl_uint2 pixelGranularity = { 1, 1 }; 123 | bool useTTProjector = false; 124 | bool useVolumeAsInitialX0 = false; 125 | 126 | uint32_t xBufferCount, bBufferCount, tmpXBufferCount, tmpBBufferCount; 127 | 128 | // Class functions 129 | /** 130 | * Write volume of the size XDIM into the DEN file. 131 | * 132 | * @param X buffer to write 133 | * @param x auxiliary vector to store float data from X 134 | * @param path output DEN file 135 | */ 136 | void writeVolume(cl::Buffer& X, float* x, std::string path); 137 | /** 138 | * Write projections of the size BDIM into DEN file. 139 | * 140 | * @param B buffer to write 141 | * @param b auxiliary vector to store float data from B 142 | * @param path output DEN file 143 | */ 144 | void writeProjections(cl::Buffer& B, float* b, std::string path); 145 | std::vector inverseProjectionMatrices(); 146 | 147 | // Printing and reporting 148 | void setTimestamp(bool finishCommandQueue); 149 | std::chrono::milliseconds millisecondsFromTimestamp(bool setNewTimestamp); 150 | std::string printTime(std::string msg, bool finishCommandQueue, bool setNewTimestamp); 151 | void reportTime(std::string msg, bool finishCommandQueue, bool setNewTimestamp); 152 | 153 | cl::NDRange projectorLocalNDRange; 154 | cl::NDRange projectorLocalNDRangeBarrier; 155 | cl::NDRange backprojectorLocalNDRange; 156 | /** 157 | * Backprojection X = AT(B) 158 | * 159 | * @param B Buffer of all projections from all reconstructed angles of the minimal size 160 | * BDIM*sizeof(float). 161 | * @param X Buffer of the size at least XDIM*sizeof(float) to be backprojected to. 162 | * @param initialProjectionIndex For OS SART 0 by default 163 | * @param projectionIncrement For OS SART 1 by default 164 | * @param additionalScaling Additional scaling. 165 | * 166 | * @return 0 on success 167 | */ 168 | int backproject(cl::Buffer& B, 169 | cl::Buffer& X, 170 | uint32_t initialProjectionIndex = 0, 171 | uint32_t projectionIncrement = 1, 172 | float additionalScaling = 1.0f); 173 | 174 | /** 175 | * Projection B = A (X) 176 | * 177 | * @param X Buffer of the size at least XDIM*sizeof(float) to be projected. 178 | * @param B Buffer to write all projections from all reconstructed angles of the minimal size 179 | * BDIM*sizeof(float). 180 | * @param initialProjectionIndex For OS SART 0 by default 181 | * @param projectionIncrement For OS SART 1 by default 182 | * @param additionalScaling Additional scaling. 183 | * 184 | * @return 185 | */ 186 | int project(cl::Buffer& X, 187 | cl::Buffer& B, 188 | uint32_t initialProjectionIndex = 0, 189 | uint32_t projectionIncrement = 1, 190 | float additionalScaling = 1.0f); 191 | 192 | std::vector> x_buffers, tmp_x_buffers; 193 | std::vector> b_buffers, tmp_b_buffers; 194 | std::chrono::time_point timestamp; 195 | 196 | bool verbose = false; 197 | std::string intermediatePrefix = ""; 198 | 199 | const uint32_t pdimx, pdimy, pdimz, vdimx, vdimy, vdimz; 200 | const uint32_t workGroupSize; 201 | uint64_t BDIM, XDIM; 202 | 203 | private: 204 | bool isLocalRangeAdmissible(cl::NDRange& localRange); 205 | void checkLocalRange(cl::NDRange& localRange, std::string name); 206 | }; 207 | 208 | } // namespace KCT 209 | -------------------------------------------------------------------------------- /include/CuttingVoxelProjector.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Logging 4 | #include "PLOG/PlogSetup.h" 5 | 6 | // External libraries 7 | #include 8 | #include 9 | #include 10 | 11 | // Internal libraries 12 | #include "Kniha.hpp" 13 | #include "MATRIX/LUDoolittleForm.hpp" 14 | #include "MATRIX/ProjectionMatrix.hpp" 15 | #include "MATRIX/SquareMatrix.hpp" 16 | #include "OPENCL/OpenCLManager.hpp" 17 | #include "rawop.h" 18 | #include "stringFormatter.h" 19 | 20 | namespace KCT { 21 | 22 | class CuttingVoxelProjector : public virtual Kniha 23 | { 24 | public: 25 | /** 26 | * Class that encapsulates projector and backprojector implementation of Cutting Voxel Projector 27 | * and other algorithms. 28 | * 29 | * @param pdimx Number of pixels 30 | * @param pdimy Number of pixels 31 | * @param vdimx Number of voxels 32 | * @param vdimy Number of voxels 33 | * @param vdimz Number of voxels 34 | */ 35 | CuttingVoxelProjector(uint64_t pdimx, 36 | uint64_t pdimy, 37 | uint64_t vdimx, 38 | uint64_t vdimy, 39 | uint64_t vdimz, 40 | cl::NDRange projectorLocalNDRange = cl::NDRange()) 41 | : pdimx(pdimx) 42 | , pdimy(pdimy) 43 | , vdimx(vdimx) 44 | , vdimy(vdimy) 45 | , vdimz(vdimz) 46 | { 47 | pdimz = 1; // Default 48 | pdims = cl_int2({ int(pdimx), int(pdimy) }); 49 | pdims_uint = cl_uint2({ uint32_t(pdimx), uint32_t(pdimy) }); 50 | vdims = cl_int3({ int(vdimx), int(vdimy), int(vdimz) }); 51 | totalVoxelNum = vdimx * vdimy * vdimz; 52 | totalVolumeBufferSize = totalVoxelNum * sizeof(float); 53 | frameSize = pdimx * pdimy; 54 | timestamp = std::chrono::steady_clock::now(); 55 | std::size_t projectorLocalNDRangeDim = projectorLocalNDRange.dimensions(); 56 | if(projectorLocalNDRangeDim == 3) 57 | { 58 | if(projectorLocalNDRange[0] == 0 && projectorLocalNDRange[1] == 0 59 | && projectorLocalNDRange[2] == 0) 60 | { 61 | this->projectorLocalNDRange = cl::NDRange(); 62 | this->projectorLocalNDRangeBarrier = cl::NDRange(); 63 | } else if(projectorLocalNDRange[0] == 0 || projectorLocalNDRange[1] == 0 64 | || projectorLocalNDRange[2] == 0) 65 | { 66 | this->projectorLocalNDRange = guessProjectionLocalNDRange(false); 67 | this->projectorLocalNDRangeBarrier = guessProjectionLocalNDRange(true); 68 | } else 69 | { 70 | this->projectorLocalNDRange = projectorLocalNDRange; 71 | this->projectorLocalNDRangeBarrier = projectorLocalNDRange; 72 | } 73 | } else 74 | { 75 | if(projectorLocalNDRangeDim != 0) 76 | { 77 | LOGE << io::xprintf( 78 | "Wrong specification of projectorLocalNDRange, trying guessing!"); 79 | } 80 | this->projectorLocalNDRange = guessProjectionLocalNDRange(false); 81 | this->projectorLocalNDRangeBarrier = guessProjectionLocalNDRange(true); 82 | } 83 | } 84 | 85 | cl::NDRange guessProjectionLocalNDRange(bool barrierCalls); 86 | 87 | void initializeCVPProjector(bool useExactScaling, 88 | bool useElevationCorrection, 89 | bool useBarrierCalls, 90 | uint32_t LOCALARRAYSIZE); 91 | void initializeSiddonProjector(uint32_t probesPerEdgeX, uint32_t probesPerEdgeY); 92 | void initializeTTProjector(); 93 | void initializeAllAlgorithms(); 94 | int problemSetup(double voxelSizeX, 95 | double voxelSizeY, 96 | double voxelSizeZ, 97 | double volumeCenterX, 98 | double volumeCenterY, 99 | double volumeCenterZ); 100 | /** 101 | * Initialize volume buffer by given size. 102 | * 103 | * @param volumeSizeX 104 | * @param volumeSizeY 105 | * @param volumeSizeZ 106 | * @param volumeArray If its nullptr, initialize by zero. 107 | * 108 | * @return 109 | */ 110 | int initializeOrUpdateVolumeBuffer(float* volumeArray = nullptr); 111 | /** 112 | * Initialize volume buffer by given size, updates voxel size of the projector. 113 | * 114 | * @param volumeSizeX 115 | * @param volumeSizeY 116 | * @param volumeSizeZ 117 | * @param volumeArray If its nullptr, initialize by zero. 118 | * 119 | * @return 120 | */ 121 | int initializeOrUpdateVolumeBuffer(uint32_t vdimx, 122 | uint32_t vdimy, 123 | uint32_t vdimz, 124 | float* volumeArray = nullptr); 125 | 126 | int fillVolumeBufferByConstant(float constant); 127 | 128 | /** 129 | * Initialize projection buffer by given size. With or without updating dimensions 130 | * 131 | * @param projectionSizeX 132 | * @param projectionSizeY 133 | * @param projectionSizeZ 134 | * @param projectionArray If is nullptr, initialize by zero. 135 | * 136 | * @return 137 | */ 138 | int initializeOrUpdateProjectionBuffer(uint32_t pdimx, 139 | uint32_t pdimy, 140 | uint32_t pdimz, 141 | float* projectionArray = nullptr); 142 | int initializeOrUpdateProjectionBuffer(uint32_t projectionSizeZ, 143 | float* projectionArray = nullptr); 144 | int initializeOrUpdateProjectionBuffer(float* projectionArray = nullptr); 145 | 146 | int fillProjectionBufferByConstant(float constant); 147 | 148 | int project(float* projection, std::shared_ptr pm); 149 | int projectCos(float* projection, std::shared_ptr pm); 150 | int projectorWithoutScaling(float* projection, std::shared_ptr pm); 151 | 152 | int projectExact(float* projection, std::shared_ptr pm); 153 | int projectTA3(float* projection, std::shared_ptr pm); 154 | 155 | int projectSiddon(float* projection, std::shared_ptr pm); 156 | 157 | double normSquare(float* projection, uint32_t pdimx, uint32_t pdimy); 158 | double normSquareDifference(float* projection, uint32_t pdimx, uint32_t pdimy); 159 | int backproject(float* volume, 160 | std::vector>& cameraVector, 161 | uint64_t baseOffset = 0); 162 | 163 | int backproject_minmax(float* volume, 164 | std::vector>& cameraVector, 165 | uint64_t baseOffset = 0); 166 | 167 | private: 168 | float FLOATONE = 1.0f; 169 | uint32_t pdimx, pdimy, pdimz; 170 | uint32_t vdimx, vdimy, vdimz; 171 | uint64_t totalVoxelNum, totalVolumeBufferSize; 172 | uint64_t frameSize; 173 | uint64_t totalPixelNum, totalProjectionBufferSize; 174 | cl::NDRange projectorLocalNDRange; 175 | cl::NDRange projectorLocalNDRangeBarrier; 176 | 177 | cl_int3 vdims; 178 | cl_int2 pdims; 179 | cl_uint2 pdims_uint; 180 | cl_double3 voxelSizes; 181 | cl_double3 volumeCenter; 182 | bool useCVPProjector = true; 183 | bool useCVPExactProjectionsScaling = true; 184 | bool useCVPElevationCorrection = false; 185 | bool useBarrierImplementation = false; 186 | uint32_t LOCALARRAYSIZE = 0; 187 | bool useSiddonProjector = false; 188 | cl_uint2 pixelGranularity = { 1, 1 }; 189 | bool useTTProjector = false; 190 | 191 | std::shared_ptr volumeBuffer = nullptr; 192 | std::shared_ptr projectionBuffer = nullptr; 193 | std::shared_ptr tmpBuffer = nullptr; 194 | size_t tmpBuffer_size = 0; 195 | std::vector invertProjectionMatrices(std::vector CM); 196 | std::vector computeScalingFactors(std::vector PM); 197 | std::shared_ptr> FLOAT_CopyVector; 198 | std::chrono::time_point timestamp; 199 | }; 200 | 201 | } // namespace KCT 202 | -------------------------------------------------------------------------------- /include/PartialPBCT2DOperator.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Logging 4 | #include "PLOG/PlogSetup.h" 5 | 6 | // External libraries 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // Internal libraries 13 | #include "AlgorithmsBarrierBuffers.hpp" 14 | #include "BufferedFrame2D.hpp" 15 | #include "DEN/DenAsyncFrame2DWritter.hpp" 16 | #include "DEN/DenProjectionMatrixReader.hpp" 17 | #include "GEOMETRY/Geometry3DParallelI.hpp" 18 | #include "Kniha.hpp" 19 | #include "MATRIX/LightProjectionMatrix.hpp" 20 | #include "MATRIX/ProjectionMatrix.hpp" 21 | #include "MATRIX/utils.hpp" 22 | #include "NDRange/PBCT2DLocalNDRangeFactory.hpp" 23 | #include "OPENCL/OpenCLManager.hpp" 24 | #include "rawop.h" 25 | #include "stringFormatter.h" 26 | 27 | using namespace KCT::matrix; 28 | namespace KCT { 29 | 30 | /** 31 | * This class encapsulates partial projection operation. 32 | * The main difference between PartialPBCT2DOperator and BasePBCTOperator is that 33 | * PartialPBCT2DOperator will not erase destination array before projection or backprojection. So it 34 | * behaves additivelly. 35 | */ 36 | class PartialPBCT2DOperator : public virtual Kniha, public AlgorithmsBarrierBuffers 37 | { 38 | public: 39 | cl::NDRange guessProjectionLocalNDRange(bool barrierCalls); 40 | cl::NDRange guessBackprojectorLocalNDRange(); 41 | 42 | PartialPBCT2DOperator(uint32_t pdimx, 43 | uint32_t pdimy, 44 | uint32_t pzblock_maxsize, 45 | uint32_t vdimx, 46 | uint32_t vdimy, 47 | uint32_t vzblock_maxsize, 48 | uint32_t workGroupSize = 256) 49 | : AlgorithmsBarrierBuffers() 50 | , pdimx(pdimx) 51 | , pdimy(pdimy) 52 | , pzblock_maxsize(pzblock_maxsize) 53 | , vdimx(vdimx) 54 | , vdimy(vdimy) 55 | , vzblock_maxsize(vzblock_maxsize) 56 | , workGroupSize(workGroupSize) 57 | { 58 | XDIM_maxsize = (uint64_t)vdimx * (uint64_t)vdimy * (uint64_t)vzblock_maxsize; 59 | BDIM_maxsize = (uint64_t)pdimx * (uint64_t)pdimy * (uint64_t)pzblock_maxsize; 60 | initReductionParameters(pdimx, pdimy, pzblock_maxsize, vdimx, vdimy, vzblock_maxsize, workGroupSize); 61 | pdims = cl_int2({ int(pdimx), int(pdimy) }); 62 | pdims_uint = cl_uint2({ pdimx, pdimy }); 63 | timestamp = std::chrono::steady_clock::now(); 64 | } 65 | 66 | void initializeCVPProjector(bool barrierVariant, uint32_t LOCALARRAYSIZE = 7680); 67 | void initializeSiddonProjector(uint32_t probesPerEdgeX, uint32_t probesPerEdgeY); 68 | void initializeTTProjector(); 69 | void initializeVolumeConvolution(); 70 | 71 | int initializeOpenCL(uint32_t platformID, 72 | uint32_t* deviceIds, 73 | uint32_t deviceIdsLength, 74 | std::string xpath, 75 | bool debug, 76 | bool relaxed, 77 | cl::NDRange projectorLocalNDRange = cl::NullRange, 78 | cl::NDRange backprojectorLocalNDRange = cl::NullRange); 79 | 80 | void useJacobiVectorCLCode(); 81 | 82 | int problemSetup(std::vector> geometries, 83 | double voxelSpacingX, 84 | double voxelSpacingY, 85 | double voxelSpacingZ, 86 | double volumeCenterX = 0.0, 87 | double volumeCenterY = 0.0, 88 | double volumeCenterZ = 0.0); 89 | 90 | int allocateXBuffers(uint32_t xBufferCount); 91 | int allocateBBuffers(uint32_t bBufferCount); 92 | int allocateTmpXBuffers(uint32_t xBufferCount); 93 | int allocateTmpBBuffers(uint32_t bBufferCount); 94 | std::shared_ptr getBBuffer(uint32_t i); 95 | std::shared_ptr getXBuffer(uint32_t i); 96 | std::shared_ptr getTmpBBuffer(uint32_t i); 97 | std::shared_ptr getTmpXBuffer(uint32_t i); 98 | 99 | double adjointProductTest(float* x, float* b); 100 | 101 | void setVerbose(bool verbose, std::string intermediatePrefix = ""); 102 | 103 | std::vector computeScalingFactors(); 104 | 105 | /** 106 | * Backprojection X = AT(B) 107 | * 108 | * @param B Buffer of all projections from all reconstructed angles of the minimal size 109 | * BDIM*sizeof(float). 110 | * @param X Buffer of the size at least XDIM*sizeof(float) to be backprojected to. 111 | * @param initialProjectionIndex For OS SART 0 by default 112 | * @param projectionIncrement For OS SART 1 by default 113 | * 114 | * @return 0 on success 115 | */ 116 | int backproject(cl::Buffer& B, cl::Buffer& X, uint32_t initialProjectionIndex = 0, uint32_t projectionIncrement = 1); 117 | 118 | /** 119 | * Projection B = A x restricted on particular angles by using just projections in the range 120 | * [geometriesFrom, geometriesTo) and particular strips of k indices in the range [k_from, k_count) 121 | * 122 | * @param X Buffer of the size at least XDIM*sizeof(float) to be projected. 123 | * @param B Buffer to write all projections from angles in the range [reconstruction_from, 124 | * reconstruction_to) zero index starts at the projection reconstruction_from 125 | * BDIM*sizeof(float). 126 | * @param xslab_z_offset Offset of the volume in X buffer and z offset of the projection in B buffer 127 | * @param k_count Volume xslab hieght 128 | * @param geometries_from indexing of gemetry object start inclusive 129 | * @param geometries_to indexing of gemetry object end exclusive 130 | * @param initialProjectionIndex For OS SART 0 by default 131 | * @param projectionIncrement For OS SART 1 by default 132 | * 133 | * @return 134 | */ 135 | int project_partial(uint32_t QID, 136 | cl::Buffer& X, 137 | cl::Buffer& B, 138 | uint32_t xslab_z_offset, 139 | uint32_t xslab_vdimz_local, 140 | uint32_t geometries_from, 141 | uint32_t geometries_to, 142 | uint32_t initialProjectionIndex = 0, 143 | uint32_t projectionIncrement1 = 1); 144 | 145 | protected: 146 | const cl_float FLOATZERO = 0.0f; 147 | const cl_double DOUBLEZERO = 0.0; 148 | float FLOATONE = 1.0f; 149 | // Constructor defined variables 150 | cl_int2 pdims; 151 | cl_uint2 pdims_uint; 152 | 153 | // Problem setup variables 154 | double voxelSpacingX, voxelSpacingY, voxelSpacingZ; 155 | cl_double3 voxelSizes; 156 | cl_double3 volumeCenter; 157 | std::vector> geometries; 158 | std::vector PM8Vector; 159 | std::vector scalingFactorVector; 160 | 161 | // Variables for projectors and openCL initialization 162 | bool useCVPProjector = true; 163 | bool useBarrierImplementation = false; 164 | uint32_t LOCALARRAYSIZE = 0; 165 | bool useSiddonProjector = false; 166 | cl_uint2 pixelGranularity = { 1, 1 }; 167 | bool useTTProjector = false; 168 | bool useVolumeAsInitialX0 = false; 169 | 170 | uint32_t xBufferCount, bBufferCount, tmpXBufferCount, tmpBBufferCount; 171 | 172 | // Class functions 173 | /** 174 | * Write volume of the size XDIM into the DEN file. 175 | * 176 | * @param X buffer to write 177 | * @param x auxiliary vector to store float data from X 178 | * @param path output DEN file 179 | */ 180 | void writeVolume(cl::Buffer& X, float* x, std::string path); 181 | /** 182 | * Write projections of the size BDIM into DEN file. 183 | * 184 | * @param B buffer to write 185 | * @param b auxiliary vector to store float data from B 186 | * @param path output DEN file 187 | */ 188 | void writeProjections(cl::Buffer& B, float* b, std::string path); 189 | std::vector inverseProjectionMatrices(); 190 | 191 | // Printing and reporting 192 | void setTimestamp(bool finishCommandQueue); 193 | std::chrono::milliseconds millisecondsFromTimestamp(bool setNewTimestamp); 194 | std::string printTime(std::string msg, bool finishCommandQueue, bool setNewTimestamp); 195 | void reportTime(std::string msg, bool finishCommandQueue, bool setNewTimestamp); 196 | 197 | cl::NDRange projectorLocalNDRange; 198 | cl::NDRange projectorLocalNDRangeBarrier; 199 | cl::NDRange backprojectorLocalNDRange; 200 | 201 | std::vector> x_buffers, tmp_x_buffers; 202 | std::vector> b_buffers, tmp_b_buffers; 203 | std::chrono::time_point timestamp; 204 | 205 | bool verbose = false; 206 | std::string intermediatePrefix = ""; 207 | 208 | const uint32_t pdimx, pdimy, pzblock_maxsize, vdimx, vdimy, vzblock_maxsize; 209 | uint64_t XDIM_maxsize, BDIM_maxsize; 210 | const uint32_t workGroupSize; 211 | }; 212 | 213 | } // namespace KCT 214 | --------------------------------------------------------------------------------