/*
-----------------------------------------------------------------------
Copyright: 2010-2018, imec Vision Lab, University of Antwerp
2014-2018, CWI, Amsterdam
Contact: astra@astra-toolbox.com
Website: http://www.astra-toolbox.com/
This file is part of the ASTRA Toolbox.
The ASTRA Toolbox is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
The ASTRA Toolbox is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with the ASTRA Toolbox. If not, see .
-----------------------------------------------------------------------
*/
#ifdef ASTRA_CUDA
#include "astra/CudaReconstructionAlgorithm2D.h"
#include "astra/AstraObjectManager.h"
#include "astra/FanFlatProjectionGeometry2D.h"
#include "astra/FanFlatVecProjectionGeometry2D.h"
#include "astra/CudaProjector2D.h"
#include "astra/Logging.h"
#include "astra/cuda/2d/algo.h"
#include
using namespace std;
namespace astra {
//----------------------------------------------------------------------------------------
// Constructor
CCudaReconstructionAlgorithm2D::CCudaReconstructionAlgorithm2D()
{
_clear();
}
//----------------------------------------------------------------------------------------
// Destructor
CCudaReconstructionAlgorithm2D::~CCudaReconstructionAlgorithm2D()
{
delete m_pAlgo;
m_pAlgo = 0;
m_bAlgoInit = false;
}
void CCudaReconstructionAlgorithm2D::clear()
{
delete m_pAlgo;
_clear();
}
void CCudaReconstructionAlgorithm2D::_clear()
{
m_bIsInitialized = false;
m_pAlgo = 0;
m_bAlgoInit = false;
CReconstructionAlgorithm2D::_clear();
m_iGPUIndex = -1;
m_iDetectorSuperSampling = 1;
m_iPixelSuperSampling = 1;
}
//---------------------------------------------------------------------------------------
void CCudaReconstructionAlgorithm2D::initializeFromProjector()
{
m_iPixelSuperSampling = 1;
m_iDetectorSuperSampling = 1;
m_iGPUIndex = -1;
// Projector
CCudaProjector2D* pCudaProjector = dynamic_cast(m_pProjector);
if (!pCudaProjector) {
if (m_pProjector) {
ASTRA_WARN("non-CUDA Projector2D passed");
}
} else {
m_iDetectorSuperSampling = pCudaProjector->getDetectorSuperSampling();
m_iPixelSuperSampling = pCudaProjector->getVoxelSuperSampling();
m_iGPUIndex = pCudaProjector->getGPUIndex();
}
}
//---------------------------------------------------------------------------------------
// Initialize - Config
bool CCudaReconstructionAlgorithm2D::initialize(const Config& _cfg)
{
ASTRA_ASSERT(_cfg.self);
ConfigStackCheck CC("CudaReconstructionAlgorithm2D", this, _cfg);
m_bIsInitialized = CReconstructionAlgorithm2D::initialize(_cfg);
if (!m_bIsInitialized)
return false;
initializeFromProjector();
// Deprecated options
try {
m_iDetectorSuperSampling = _cfg.self.getOptionInt("DetectorSuperSampling", m_iDetectorSuperSampling);
m_iPixelSuperSampling = _cfg.self.getOptionInt("PixelSuperSampling", m_iPixelSuperSampling);
} catch (const StringUtil::bad_cast &e) {
ASTRA_CONFIG_CHECK(false, "CudaReconstructionAlgorithm2D", "Supersampling options must be integers.");
}
CC.markOptionParsed("DetectorSuperSampling");
CC.markOptionParsed("PixelSuperSampling");
// GPU number
try {
m_iGPUIndex = _cfg.self.getOptionInt("GPUindex", -1);
m_iGPUIndex = _cfg.self.getOptionInt("GPUIndex", m_iGPUIndex);
} catch (const StringUtil::bad_cast &e) {
ASTRA_CONFIG_CHECK(false, "CudaReconstructionAlgorithm2D", "GPUIndex must be an integer.");
}
CC.markOptionParsed("GPUIndex");
if (!_cfg.self.hasOption("GPUIndex"))
CC.markOptionParsed("GPUindex");
return _check();
}
//---------------------------------------------------------------------------------------
// Initialize - C++
bool CCudaReconstructionAlgorithm2D::initialize(CProjector2D* _pProjector,
CFloat32ProjectionData2D* _pSinogram,
CFloat32VolumeData2D* _pReconstruction)
{
// if already initialized, clear first
if (m_bIsInitialized) {
clear();
}
m_pProjector = _pProjector;
// required classes
m_pSinogram = _pSinogram;
m_pReconstruction = _pReconstruction;
initializeFromProjector();
return _check();
}
//----------------------------------------------------------------------------------------
// Check
bool CCudaReconstructionAlgorithm2D::_check()
{
if (!CReconstructionAlgorithm2D::_check())
return false;
ASTRA_CONFIG_CHECK(m_iDetectorSuperSampling >= 1, "CudaReconstructionAlgorithm2D", "DetectorSuperSampling must be a positive integer.");
ASTRA_CONFIG_CHECK(m_iPixelSuperSampling >= 1, "CudaReconstructionAlgorithm2D", "PixelSuperSampling must be a positive integer.");
ASTRA_CONFIG_CHECK(m_iGPUIndex >= -1, "CudaReconstructionAlgorithm2D", "GPUIndex must be a non-negative integer or -1.");
// check restrictions
// TODO: check restrictions built into cuda code
// success
m_bIsInitialized = true;
return true;
}
void CCudaReconstructionAlgorithm2D::setGPUIndex(int _iGPUIndex)
{
m_iGPUIndex = _iGPUIndex;
}
//---------------------------------------------------------------------------------------
// Information - All
map CCudaReconstructionAlgorithm2D::getInformation()
{
// TODO: Verify and clean up
map res;
res["ProjectionGeometry"] = getInformation("ProjectionGeometry");
res["ReconstructionGeometry"] = getInformation("ReconstructionGeometry");
res["ProjectionDataId"] = getInformation("ProjectionDataId");
res["ReconstructionDataId"] = getInformation("ReconstructionDataId");
res["ReconstructionMaskId"] = getInformation("ReconstructionMaskId");
res["GPUindex"] = getInformation("GPUindex");
res["DetectorSuperSampling"] = getInformation("DetectorSuperSampling");
res["PixelSuperSampling"] = getInformation("PixelSuperSampling");
res["UseMinConstraint"] = getInformation("UseMinConstraint");
res["MinConstraintValue"] = getInformation("MinConstraintValue");
res["UseMaxConstraint"] = getInformation("UseMaxConstraint");
res["MaxConstraintValue"] = getInformation("MaxConstraintValue");
return mergeMap(CReconstructionAlgorithm2D::getInformation(), res);
}
//---------------------------------------------------------------------------------------
// Information - Specific
boost::any CCudaReconstructionAlgorithm2D::getInformation(std::string _sIdentifier)
{
// TODO: Verify and clean up
if (_sIdentifier == "UseMinConstraint") { return m_bUseMinConstraint ? string("yes") : string("no"); }
if (_sIdentifier == "MinConstraintValue") { return m_fMinValue; }
if (_sIdentifier == "UseMaxConstraint") { return m_bUseMaxConstraint ? string("yes") : string("no"); }
if (_sIdentifier == "MaxConstraintValue") { return m_fMaxValue; }
// TODO: store these so we can return them?
if (_sIdentifier == "ProjectionGeometry") { return string("not implemented"); }
if (_sIdentifier == "ReconstructionGeometry") { return string("not implemented"); }
if (_sIdentifier == "GPUindex") { return m_iGPUIndex; }
if (_sIdentifier == "DetectorSuperSampling") { return m_iDetectorSuperSampling; }
if (_sIdentifier == "PixelSuperSampling") { return m_iPixelSuperSampling; }
if (_sIdentifier == "ProjectionDataId") {
int iIndex = CData2DManager::getSingleton().getIndex(m_pSinogram);
if (iIndex != 0) return iIndex;
return std::string("not in manager");
}
if (_sIdentifier == "ReconstructionDataId") {
int iIndex = CData2DManager::getSingleton().getIndex(m_pReconstruction);
if (iIndex != 0) return iIndex;
return std::string("not in manager");
}
if (_sIdentifier == "ReconstructionMaskId") {
if (!m_bUseReconstructionMask) return string("not used");
int iIndex = CData2DManager::getSingleton().getIndex(m_pReconstructionMask);
if (iIndex != 0) return iIndex;
return std::string("not in manager");
}
return CReconstructionAlgorithm2D::getInformation(_sIdentifier);
}
bool CCudaReconstructionAlgorithm2D::setupGeometry()
{
ASTRA_ASSERT(m_bIsInitialized);
ASTRA_ASSERT(!m_bAlgoInit);
bool ok;
// TODO: Probably not the best place for this...
ok = m_pAlgo->setGPUIndex(m_iGPUIndex);
if (!ok) return false;
const CVolumeGeometry2D& volgeom = *m_pReconstruction->getGeometry();
const CProjectionGeometry2D& projgeom = *m_pSinogram->getGeometry();
ok = m_pAlgo->setGeometry(&volgeom, &projgeom);
if (!ok) return false;
ok = m_pAlgo->setSuperSampling(m_iDetectorSuperSampling, m_iPixelSuperSampling);
if (!ok) return false;
if (m_bUseReconstructionMask)
ok &= m_pAlgo->enableVolumeMask();
if (!ok) return false;
if (m_bUseSinogramMask)
ok &= m_pAlgo->enableSinogramMask();
if (!ok) return false;
ok &= m_pAlgo->init();
if (!ok) return false;
return true;
}
//----------------------------------------------------------------------------------------
void CCudaReconstructionAlgorithm2D::initCUDAAlgorithm()
{
bool ok;
ok = setupGeometry();
ASTRA_ASSERT(ok);
ok = m_pAlgo->allocateBuffers();
ASTRA_ASSERT(ok);
}
//----------------------------------------------------------------------------------------
// Iterate
void CCudaReconstructionAlgorithm2D::run(int _iNrIterations)
{
// check initialized
ASTRA_ASSERT(m_bIsInitialized);
bool ok = true;
const CVolumeGeometry2D& volgeom = *m_pReconstruction->getGeometry();
if (!m_bAlgoInit) {
initCUDAAlgorithm();
m_bAlgoInit = true;
}
ok = m_pAlgo->copyDataToGPU(m_pSinogram->getDataConst(), m_pSinogram->getGeometry()->getDetectorCount(),
m_pReconstruction->getDataConst(), volgeom.getGridColCount(),
m_bUseReconstructionMask ? m_pReconstructionMask->getDataConst() : 0, volgeom.getGridColCount(),
m_bUseSinogramMask ? m_pSinogramMask->getDataConst() : 0, m_pSinogram->getGeometry()->getDetectorCount());
ASTRA_ASSERT(ok);
if (m_bUseMinConstraint) {
bool ret = m_pAlgo->setMinConstraint(m_fMinValue);
if (!ret) {
ASTRA_WARN("This algorithm ignores MinConstraint");
}
}
if (m_bUseMaxConstraint) {
bool ret= m_pAlgo->setMaxConstraint(m_fMaxValue);
if (!ret) {
ASTRA_WARN("This algorithm ignores MaxConstraint");
}
}
ok &= m_pAlgo->iterate(_iNrIterations);
ASTRA_ASSERT(ok);
ok &= m_pAlgo->getReconstruction(m_pReconstruction->getData(),
volgeom.getGridColCount());
ASTRA_ASSERT(ok);
}
bool CCudaReconstructionAlgorithm2D::getResidualNorm(float32& _fNorm)
{
if (!m_bIsInitialized || !m_pAlgo)
return false;
_fNorm = m_pAlgo->computeDiffNorm();
return true;
}
} // namespace astra
#endif // ASTRA_CUDA