diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a00be5..422b8f9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,298 +1,297 @@ #----------------------------------------------------------------------------- # This is the root RTToolbox CMakeList file. #----------------------------------------------------------------------------- PROJECT(RTToolbox) CMAKE_MINIMUM_REQUIRED(VERSION 2.8.11.2) IF(CMAKE_BACKWARDS_COMPATIBILITY GREATER 2.8.11.2) SET(CMAKE_BACKWARDS_COMPATIBILITY 2.8.11.2 CACHE STRING "Latest version of CMake when this project was released." FORCE) ENDIF(CMAKE_BACKWARDS_COMPATIBILITY GREATER 2.8.11.2) # RTToolbox version number. SET(RTToolbox_VERSION_MAJOR "4") -SET(RTToolbox_VERSION_MINOR "0") +SET(RTToolbox_VERSION_MINOR "1") SET(RTToolbox_VERSION_PATCH "0") # Version string should not include patch level. The major.minor is # enough to distinguish available features of the toolbox. SET(RTToolbox_VERSION_STRING "${RTToolbox_VERSION_MAJOR}.${RTToolbox_VERSION_MINOR}") SET(RTToolbox_FULL_VERSION_STRING "${RTToolbox_VERSION_MAJOR}.${RTToolbox_VERSION_MINOR}.${RTToolbox_VERSION_PATCH}") # default build type SET(CMAKE_BUILD_TYPE Release) MARK_AS_ADVANCED(BUILD_SHARED_LIBS) IF (WIN32) IF (MSVC_VERSION LESS 1600) MESSAGE(FATAL_ERROR "RTToolbox requires at least Visual Studio 2010.") ENDIF(MSVC_VERSION LESS 1600) add_definitions(-D_SCL_SECURE_NO_WARNINGS) ELSE (WIN32) IF (CMAKE_COMPILER_IS_GNUCC) IF (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6 OR CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL 5.0 OR CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 5.0) MESSAGE(AUTHOR_WARNING "RTToolbox was only tested with GCC 4.6 and GCC 4.9. You are using GCC " ${CMAKE_CXX_COMPILER_VERSION} ". This compiler version might not work.") ENDIF() ENDIF() ENDIF(WIN32) IF (NOT (CMAKE_MAJOR_VERSION LESS 3)) IF(COMMAND CMAKE_POLICY) # Enable old CMake behaviour when dealing with export_library_dependencies(). # This is necessary to avoid warnings in CMake versions # greater than 3.0 # See http://www.cmake.org/cmake/help/v3.0/policy/CMP0033.html CMAKE_POLICY(SET CMP0033 OLD) ENDIF(COMMAND CMAKE_POLICY) ENDIF() -message(STATUS ${CMAKE_BUILD_TYPE}) #----------------------------------------------------------------------------- # CMake Function(s) and Macro(s) #----------------------------------------------------------------------------- include(cmake/MacroParseArguments.cmake) include(cmake/rttbMacroCreateModuleConf.cmake) include(cmake/rttbMacroCreateModule.cmake) include(cmake/rttbMacroCreateApplication.cmake) include(cmake/rttbMacroCheckModule.cmake) include(cmake/rttbMacroUseModule.cmake) include(cmake/rttbMacroCreateTestModule.cmake) include(cmake/rttbFunctionOrganizeSources.cmake) #----------------------------------------------------------------------------- # Basis config RTTB module infrastructure #----------------------------------------------------------------------------- set(RTTB_MODULES_CONF_DIR ${RTToolbox_BINARY_DIR}/modulesConf CACHE INTERNAL "Modules Conf") set(RTTB_MODULES_PACKAGE_DEPENDS_DIR ${RTToolbox_SOURCE_DIR}/cmake/PackageDepends) set(MODULES_PACKAGE_DEPENDS_DIRS ${RTTB_MODULES_PACKAGE_DEPENDS_DIR}) #----------------------------------------------------------------------------- # Testing setup # Configure Dart testing support. This should be done before any # MESSAGE(FATAL_ERROR ...) commands are invoked. #----------------------------------------------------------------------------- SET(CTEST_NEW_FORMAT 1) INCLUDE(CTest) ENABLE_TESTING() IF(BUILD_TESTING) CONFIGURE_FILE(${RTToolbox_SOURCE_DIR}/cmake/RemoveTemporaryFiles.cmake.in ${RTToolbox_BINARY_DIR}/cmake/RemoveTemporaryFiles.cmake @ONLY IMMEDIATE) CONFIGURE_FILE(${RTToolbox_SOURCE_DIR}/cmake/rttbSampleBuildTest.cmake.in ${RTToolbox_BINARY_DIR}/cmake/rttbSampleBuildTest.cmake @ONLY) CONFIGURE_FILE(${RTToolbox_SOURCE_DIR}/cmake/CTestCustom.ctest.in ${RTToolbox_BINARY_DIR}/cmake/CTestCustom.ctest @ONLY) FILE(WRITE ${RTToolbox_BINARY_DIR}/CTestCustom.cmake "INCLUDE(\"${RTToolbox_BINARY_DIR}/cmake/CTestCustom.ctest\")\n") SET(BUILDNAME "${BUILDNAME}" CACHE STRING "Name of build on the dashboard") MARK_AS_ADVANCED(BUILDNAME) ENDIF(BUILD_TESTING) #----------------------------------------------------------------------------- # Output directories. #----------------------------------------------------------------------------- IF(NOT LIBRARY_OUTPUT_PATH) SET (LIBRARY_OUTPUT_PATH ${RTToolbox_BINARY_DIR}/bin CACHE PATH "Single output directory for building all libraries.") ENDIF(NOT LIBRARY_OUTPUT_PATH) IF(NOT EXECUTABLE_OUTPUT_PATH) SET (EXECUTABLE_OUTPUT_PATH ${RTToolbox_BINARY_DIR}/bin CACHE PATH "Single output directory for building all executables.") ENDIF(NOT EXECUTABLE_OUTPUT_PATH) MARK_AS_ADVANCED(EXECUTABLE_OUTPUT_PATH LIBRARY_OUTPUT_PATH) MARK_AS_ADVANCED(LIBRARY_OUTPUT_PATH EXECUTABLE_OUTPUT_PATH) SET(RTToolbox_LIBRARY_PATH "${LIBRARY_OUTPUT_PATH}") SET(RTToolbox_EXECUTABLE_PATH "${EXECUTABLE_OUTPUT_PATH}") #----------------------------------------------------------------------------- # Find Doxygen. #----------------------------------------------------------------------------- FIND_PROGRAM(DOXYGEN_EXECUTABLE "doxygen") #----------------------------------------------------------------------------- # Installation vars. # RTToolbox_INSTALL_BIN_DIR - binary dir (executables) # RTToolbox_INSTALL_LIB_DIR - library dir (libs) # RTToolbox_INSTALL_INCLUDE_DIR - include dir (headers) # RTToolbox_INSTALL_NO_DEVELOPMENT - do not install development files # RTToolbox_INSTALL_NO_RUNTIME - do not install runtime files # RTToolbox_INSTALL_NO_DOCUMENTATION - do not install documentation files # Remark: needs directory are stored with no leading slash (CMake 2.4 and newer) #----------------------------------------------------------------------------- IF(NOT RTTOOLBOX_INSTALL_BIN_DIR) SET(RTTOOLBOX_INSTALL_BIN_DIR "bin") ENDIF(NOT RTTOOLBOX_INSTALL_BIN_DIR) IF(NOT RTTOOLBOX_INSTALL_LIB_DIR) SET(RTTOOLBOX_INSTALL_LIB_DIR "lib") ENDIF(NOT RTTOOLBOX_INSTALL_LIB_DIR) IF(NOT RTTOOLBOX_INSTALL_PACKAGE_DIR) SET(RTTOOLBOX_INSTALL_PACKAGE_DIR "lib") ENDIF(NOT RTTOOLBOX_INSTALL_PACKAGE_DIR) IF(NOT RTTOOLBOX_INSTALL_INCLUDE_DIR) SET(RTTOOLBOX_INSTALL_INCLUDE_DIR "include") ENDIF(NOT RTTOOLBOX_INSTALL_INCLUDE_DIR) IF(NOT RTTOOLBOX_INSTALL_NO_DEVELOPMENT) SET(RTTOOLBOX_INSTALL_NO_DEVELOPMENT 0) ENDIF(NOT RTTOOLBOX_INSTALL_NO_DEVELOPMENT) IF(NOT RTTOOLBOX_INSTALL_NO_RUNTIME) SET(RTTOOLBOX_INSTALL_NO_RUNTIME 0) ENDIF(NOT RTTOOLBOX_INSTALL_NO_RUNTIME) IF(NOT RTTOOLBOX_INSTALL_NO_DOCUMENTATION) SET(RTTOOLBOX_INSTALL_NO_DOCUMENTATION 0) ENDIF(NOT RTTOOLBOX_INSTALL_NO_DOCUMENTATION) SET(RTTOOLBOX_INSTALL_NO_LIBRARIES) IF(RTTOOLBOX_BUILD_SHARED_LIBS) IF(RTTOOLBOX_INSTALL_NO_RUNTIME AND RTTOOLBOX_INSTALL_NO_DEVELOPMENT) SET(RTTOOLBOX_INSTALL_NO_LIBRARIES 1) ENDIF(RTTOOLBOX_INSTALL_NO_RUNTIME AND RTTOOLBOX_INSTALL_NO_DEVELOPMENT) ELSE(RTTOOLBOX_BUILD_SHARED_LIBS) IF(RTTOOLBOX_INSTALL_NO_DEVELOPMENT) SET(RTTOOLBOX_INSTALL_NO_LIBRARIES 1) ENDIF(RTTOOLBOX_INSTALL_NO_DEVELOPMENT) ENDIF(RTTOOLBOX_BUILD_SHARED_LIBS) # set RTToolbox_DIR so it can be used by subprojects SET(RTToolbox_DIR "${CMAKE_BINARY_DIR}" CACHE INTERNAL "RTToolbox dir to be used by subprojects") #----------------------------------------------------------------------------- # DCMTK MT-Flag treat #----------------------------------------------------------------------------- option(RTTB_DCMTK_COMPLIANCE_ENFORCE_MT "This enforces the whole RTToolbox to be compiled with /MT,/MTd to be compliant with DCMTK" OFF) string(FIND ${CMAKE_GENERATOR} "Visual Studio" RTTB_VS_USED) if(RTTB_DCMTK_COMPLIANCE_ENFORCE_MT AND RTTB_VS_USED EQUAL 0) message(STATUS "Enforce DCMTK compliance: /MT and /MTd flags are used") string(REPLACE "/MD" "/MT" CMAKE_C_FLAGS_DEBUG ${CMAKE_C_FLAGS_DEBUG}) message(STATUS "CMAKE_C_FLAGS_DEBUG set to: ${CMAKE_C_FLAGS_DEBUG}") string(REPLACE "/MD" "/MT" CMAKE_C_FLAGS_RELEASE ${CMAKE_C_FLAGS_RELEASE}) message(STATUS "CMAKE_C_FLAGS_RELEASE set to: ${CMAKE_C_FLAGS_RELEASE}") string(REPLACE "/MD" "/MT" CMAKE_C_FLAGS_MINSIZEREL ${CMAKE_C_FLAGS_MINSIZEREL}) message(STATUS "CMAKE_C_FLAGS_MINSIZEREL set to: ${CMAKE_C_FLAGS_MINSIZEREL}") string(REPLACE "/MD" "/MT" CMAKE_C_FLAGS_RELWITHDEBINFO ${CMAKE_C_FLAGS_RELWITHDEBINFO}) message(STATUS "CMAKE_C_FLAGS_RELWITHDEBINFO set to: ${CMAKE_C_FLAGS_RELWITHDEBINFO}") string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG}) message(STATUS "CMAKE_CXX_FLAGS_DEBUG set to: ${CMAKE_CXX_FLAGS_DEBUG}") string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE}) message(STATUS "CMAKE_CXX_FLAGS_RELEASE set to: ${CMAKE_CXX_FLAGS_RELEASE}") string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_MINSIZEREL ${CMAKE_CXX_FLAGS_MINSIZEREL}) message(STATUS "CMAKE_CXX_FLAGS_MINSIZEREL set to: ${CMAKE_CXX_FLAGS_MINSIZEREL}") string(REPLACE "/MD" "/MT" CMAKE_CXX_FLAGS_RELWITHDEBINFO ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}) message(STATUS "CMAKE_CXX_FLAGS_RELWITHDEBINFO set to: ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") endif() #----------------------------------------------------------------------------- # Advanced RTToolbox configuration #----------------------------------------------------------------------------- #----------------------------------------------------------------------------- # RTToolbox build configuration options. IF (WIN32) OPTION(BUILD_SHARED_LIBS "Build RTToolbox with shared libraries." OFF) ELSE (WIN32) OPTION(BUILD_SHARED_LIBS "Build RTToolbox with shared libraries." ON) ENDIF (WIN32) IF(BUILD_SHARED_LIBS) IF(WIN32) MESSAGE(FATAL_ERROR "RTToolbox currently does not support a dynamic build on Windows. We are working on that...") ENDIF(WIN32) ELSE(BUILD_SHARED_LIBS) IF(UNIX) MESSAGE(FATAL_ERROR "RTToolbox currently does not support a static build on unix like systems. We are working on that...") ENDIF(UNIX) ENDIF(BUILD_SHARED_LIBS) SET(RTToolbox_BUILD_SHARED_LIBS ${BUILD_SHARED_LIBS}) IF(NOT RTToolbox_NO_LIBRARY_VERSION) # This setting of SOVERSION assumes that any API change # will increment either the minor or major version number of RTToolbox. SET(RTToolbox_LIBRARY_PROPERTIES VERSION "${RTToolbox_VERSION_MAJOR}.${RTToolbox_VERSION_MINOR}.${RTToolbox_VERSION_PATCH}" SOVERSION "${RTToolbox_VERSION_MAJOR}.${RTToolbox_VERSION_MINOR}" ) ENDIF(NOT RTToolbox_NO_LIBRARY_VERSION) #----------------------------------------------------------------------------- # Configure files with settings for use by the build. # #----------------------------------------------------------------------------- CONFIGURE_FILE(${RTToolbox_SOURCE_DIR}/RTToolboxConfigure.h.in ${RTToolbox_BINARY_DIR}/RTToolboxConfigure.h) IF(NOT RTTOOLBOX_INSTALL_NO_DEVELOPMENT) INSTALL(FILES ${RTToolbox_BINARY_DIR}/RTToolboxConfigure.h DESTINATION ${RTTOOLBOX_INSTALL_INCLUDE_DIR} COMPONENT Development) ENDIF(NOT RTTOOLBOX_INSTALL_NO_DEVELOPMENT) #----------------------------------------------------------------------------- # The entire RTToolbox tree should use the same include path #----------------------------------------------------------------------------- #Default include dir. Others dirs will be defined by activated subprojects INCLUDE_DIRECTORIES(${RTToolbox_BINARY_DIR}) LINK_DIRECTORIES(${LIBARY_OUTPUT_PATH}) #Prepare the correct target information export by the subprojects SET(RTToolbox_TARGETS_FILE "${RTToolbox_BINARY_DIR}/RTToolboxTargets.cmake") FILE(WRITE ${RTToolbox_TARGETS_FILE} "# Generated by CMake, do not edit!") #----------------------------------------------------------------------------- # Dispatch the build into the proper subdirectories. #----------------------------------------------------------------------------- MESSAGE (STATUS "generating Project RTToolbox") ADD_SUBDIRECTORY (code) ADD_SUBDIRECTORY (demoapps) IF (BUILD_TESTING) ADD_SUBDIRECTORY (testing) ENDIF (BUILD_TESTING) ADD_SUBDIRECTORY (documentation) #----------------------------------------------------------------------------- # Help other projects use RTToolbox. #----------------------------------------------------------------------------- EXPORT(PACKAGE RTToolbox) # Copy the UseRTToolbox.cmake file to the binary tree for backward compatability. CONFIGURE_FILE(${RTToolbox_SOURCE_DIR}/UseRTToolbox.cmake.in ${RTToolbox_BINARY_DIR}/UseRTToolbox.cmake COPYONLY IMMEDIATE) # Save library dependencies. EXPORT_LIBRARY_DEPENDENCIES(${RTToolbox_BINARY_DIR}/RTToolboxLibraryDepends.cmake) # Create the RTToolboxConfig.cmake file containing the RTToolbox configuration. INCLUDE (${RTToolbox_SOURCE_DIR}/rttbGenerateRTToolboxConfig.cmake) IF(NOT RTToolbox_INSTALL_NO_DEVELOPMENT) INSTALL(FILES ${RTToolbox_BINARY_DIR}/RTToolboxConfig.cmake ${RTToolbox_BINARY_DIR}/RTToolboxTargets.cmake ${RTToolbox_BINARY_DIR}/RTToolboxLibraryDepends.cmake ${RTToolbox_BINARY_DIR}/UseRTToolbox.cmake DESTINATION ${RTTOOLBOX_INSTALL_PACKAGE_DIR} COMPONENT Development ) ENDIF(NOT RTToolbox_INSTALL_NO_DEVELOPMENT) diff --git a/code/algorithms/files.cmake b/code/algorithms/files.cmake index 458f698..4ec421d 100644 --- a/code/algorithms/files.cmake +++ b/code/algorithms/files.cmake @@ -1,12 +1,14 @@ SET(CPP_FILES rttbDoseStatistics.cpp + rttbDoseStatisticsCalculator.cpp rttbArithmetic.cpp ) SET(H_FILES rttbDoseStatistics.h rttbArithmetic.h rttbArithmetic.tpp rttbBinaryFunctorDoseAccessor.h rttbBinaryFunctorDoseAccessor.tpp + rttbDoseStatisticsCalculator.h ) diff --git a/code/algorithms/rttbDoseStatistics.cpp b/code/algorithms/rttbDoseStatistics.cpp index 0878fce..21efc7d 100644 --- a/code/algorithms/rttbDoseStatistics.cpp +++ b/code/algorithms/rttbDoseStatistics.cpp @@ -1,476 +1,315 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ -#include -#include -#include -#include -#include -#include -#include -#include - #include "rttbDoseStatistics.h" -#include "rttbNullPointerException.h" -#include "rttbInvalidDoseException.h" +#include "rttbDataNotAvailableException.h" namespace rttb { namespace algorithms { DoseStatistics::DoseStatistics(DoseStatisticType minimum, DoseStatisticType maximum, DoseStatisticType mean, - DoseStatisticType stdDeviation, VolumeType numVoxels, VolumeType volume, + DoseStatisticType stdDeviation, unsigned int numVoxels, VolumeType volume, ResultListPointer maximumVoxelPositions /*= ResultListPointer()*/, ResultListPointer minimumVoxelPositions /*= ResultListPointer()*/, VolumeToDoseFunctionType Dx /*= std::map()*/, DoseToVolumeFunctionType Vx /*= std::map()*/, VolumeToDoseFunctionType MOHx /*= std::map()*/, VolumeToDoseFunctionType MOCx /*= std::map()*/, VolumeToDoseFunctionType MaxOHx /*= std::map()*/, VolumeToDoseFunctionType MinOCx /*= std::map()*/) : _minimum(minimum), _maximum(maximum), _mean(mean), _stdDeviation(stdDeviation), _numVoxels(numVoxels), _volume(volume), _maximumVoxelPositions(maximumVoxelPositions), _minimumVoxelPositions(minimumVoxelPositions), _Dx(Dx), _Vx(Vx), _MOHx(MOHx), _MOCx(MOCx), _MaxOHx(MaxOHx), _MinOCx(MinOCx) { - initSuccess = false; + } - DoseStatistics::DoseStatistics(DoseIteratorPointer aDoseIterator) + + DoseStatistics::~DoseStatistics() { - _doseIterator = aDoseIterator; - initSuccess = false; - this->init(); + } - void DoseStatistics::setDoseIterator(DoseIteratorPointer aDoseIterator) + + void DoseStatistics::setMinimumVoxelPositions(ResultListPointer minimumVoxelPositions) { - _doseIterator = aDoseIterator; - initSuccess = false; - this->init(); + _minimumVoxelPositions = minimumVoxelPositions; } - DoseStatistics::DoseIteratorPointer DoseStatistics::getDoseIterator() const + void DoseStatistics::setMaximumVoxelPositions(ResultListPointer maximumVoxelPositions) { - return _doseIterator; + _maximumVoxelPositions = maximumVoxelPositions; } - - bool DoseStatistics::init() + void DoseStatistics::setDx(const DoseToVolumeFunctionType& DxValues) { - - if (!_doseIterator) - { - throw core::NullPointerException("_doseIterator must not be NULL!"); - } - - doseVector.clear(); - voxelProportionVector.clear(); - - std::multimap doseValueVSIndexMap; - std::vector voxelProportionVectorTemp; - - - this->_maximum = 0; - this->_mean = 0; - this->_stdDeviation = 0; - this->_variance = 0; - - float sum = 0; - _numVoxels = 0; - float squareSum = 0; - - _doseIterator->reset(); - int i = 0; - DoseTypeGy doseValue = 0; - - while (_doseIterator->isPositionValid()) - { - doseValue = _doseIterator->getCurrentDoseValue(); - - if (i == 0) - { - _minimum = doseValue; - } - - rttb::FractionType voxelProportion = _doseIterator->getCurrentRelevantVolumeFraction(); - sum += doseValue * voxelProportion; - _numVoxels += voxelProportion; - squareSum += doseValue * doseValue * voxelProportion; - - if (doseValue > this->_maximum) - { - _maximum = doseValue; - } - else if (doseValue < this->_minimum) - { - _minimum = doseValue; - } - - voxelProportionVectorTemp.push_back(voxelProportion); - doseValueVSIndexMap.insert(std::pair(doseValue, i)); - - i++; - _doseIterator->next(); - } - - if (_numVoxels != 0) - { - _mean = sum / _numVoxels; - _variance = (squareSum / _numVoxels - _mean * _mean); - - if (_variance < errorConstant) - { - _stdDeviation = 0; - } - else - { - _stdDeviation = pow(_variance, 0.5); - } - } - - //sort dose values and corresponding volume fractions in member variables - std::multimap::iterator it; - - for (it = doseValueVSIndexMap.begin(); it != doseValueVSIndexMap.end(); ++it) - { - doseVector.push_back((float)(*it).first); - voxelProportionVector.push_back(voxelProportionVectorTemp.at((*it).second)); - } - - initSuccess = true; - - return true; + _Dx = DxValues; } - double DoseStatistics::getNumberOfVoxels() + void DoseStatistics::setVx(const VolumeToDoseFunctionType& VxValues) { - if (!initSuccess) - { - throw core::InvalidDoseException("DoseStatistics is not initialized: set dose using setDoseIterator()! "); - } + _Vx = VxValues; + } - VolumeType DoseStatistics::getNumberOfVoxels() const + void DoseStatistics::setMOHx(const VolumeToDoseFunctionType& MOHxValues) { - return _numVoxels; + _MOHx = MOHxValues; } - DoseStatisticType DoseStatistics::getMaximum(ResultListPointer maxVoxelVector) const + void DoseStatistics::setMOCx(const VolumeToDoseFunctionType& MOCxValues) { - if (!initSuccess) - { - throw core::InvalidDoseException("DoseStatistics is not initialized: set dose using setDoseIterator()! "); + _MOCx = MOCxValues; + } - } + void DoseStatistics::setMaxOHx(const VolumeToDoseFunctionType& MaxOHValues) + { + _MaxOHx = MaxOHValues; + } - if (maxVoxelVector == NULL) - { - throw core::NullPointerException("resultsVector must not be NULL! "); - } + void DoseStatistics::setMinOCx(const VolumeToDoseFunctionType& MinOCValues) + { + _MinOCx = MinOCValues; + } - if (maxVoxelVector->size() == 0) - { - this->_doseIterator->reset(); - DoseTypeGy doseValue = 0; + unsigned int DoseStatistics::getNumberOfVoxels() const + { + return _numVoxels; + } - while (_doseIterator->isPositionValid()) - { - doseValue = _doseIterator->getCurrentDoseValue(); - if (doseValue == _maximum) - { - VoxelGridID currentID = _doseIterator->getCurrentVoxelGridID(); - std::pair voxel(doseValue, currentID); - maxVoxelVector->push_back(voxel); - } + VolumeType DoseStatistics::getVolume() const + { + return _volume; + } - _doseIterator->next(); - } - } + DoseStatisticType DoseStatistics::getMaximum() const + { return _maximum; } - DoseStatisticType DoseStatistics::getMinimum(ResultListPointer minVoxelVector, int number) const + DoseStatisticType DoseStatistics::getMinimum() const { - if (!initSuccess) - { - throw core::InvalidDoseException("DoseStatistics is not initialized: set dose using setDoseIterator()! "); - - } - - if (minVoxelVector == NULL) - { - throw core::NullPointerException("resultsVector must not be NULL! "); - } - - /*! @todo: Architecture Annotation: - Finding the positions for the minimum only once reduces computation time, - but will require sensible use by the programmers. To be save the output vector - minVoxelVector will be always cleared here to garantee that no false values are - presented. This change may be revoced to increase computation speed later on - (only compute if(minVoxelVector->size()==0)). - */ - minVoxelVector->clear(); - int count = 0; - this->_doseIterator->reset(); - DoseTypeGy doseValue = 0; - - while (_doseIterator->isPositionValid() && count < number) - { - doseValue = _doseIterator->getCurrentDoseValue(); - - if (doseValue == _minimum) - { - VoxelGridID currentID = _doseIterator->getCurrentVoxelGridID(); - std::pair voxel(doseValue, currentID); - minVoxelVector->push_back(voxel); - count++; - } - - _doseIterator->next(); - } - return _minimum; } DoseStatisticType DoseStatistics::getMean() const { - if (!initSuccess) - { - throw core::InvalidDoseException("DoseStatistics is not initialized: set dose using setDoseIterator()! "); - } - return _mean; } DoseStatisticType DoseStatistics::getStdDeviation() const { - if (!initSuccess) - { - throw core::InvalidDoseException("DoseStatistics is not initialized: set dose using setDoseIterator()! "); - } - return _stdDeviation; } DoseStatisticType DoseStatistics::getVariance() const { - if (!initSuccess) - { - throw core::InvalidDoseException("DoseStatistics is not initialized: set dose using setDoseIterator()! "); - } + return _stdDeviation * _stdDeviation; + } + + VolumeType DoseStatistics::getVx(DoseTypeGy xDoseAbsolute, bool findNearestValue, + DoseTypeGy& nearestXDose) const + { + return getValue(_Vx, xDoseAbsolute, findNearestValue, nearestXDose); - return _variance; } VolumeType DoseStatistics::getVx(DoseTypeGy xDoseAbsolute) const { - rttb::FractionType count = 0; - _doseIterator->reset(); + DoseTypeGy dummy; + return getValue(_Vx, xDoseAbsolute, false, dummy); + } DoseTypeGy DoseStatistics::getDx(VolumeType xVolumeAbsolute, bool findNearestValue, VolumeType& nearestXVolume) const { return getValue(_Dx, xVolumeAbsolute, findNearestValue, nearestXVolume); } - while (_doseIterator->isPositionValid()) - { - currentDose = _doseIterator->getCurrentDoseValue(); - - if (currentDose >= xDoseAbsolute) - { - count += _doseIterator->getCurrentRelevantVolumeFraction(); - } - - _doseIterator->next(); - } + DoseTypeGy DoseStatistics::getDx(VolumeType xVolumeAbsolute) const + { + VolumeType dummy; + return getValue(_Dx, xVolumeAbsolute, false, dummy); + } - return count * this->_doseIterator->getCurrentVoxelVolume(); + DoseTypeGy DoseStatistics::getMOHx(VolumeType xVolumeAbsolute, bool findNearestValue, + VolumeType& nearestXVolume) const + { + return getValue(_MOHx, xVolumeAbsolute, findNearestValue, nearestXVolume); } - DoseTypeGy DoseStatistics::getDx(DoseTypeGy xVolumeAbsolute) const + DoseTypeGy DoseStatistics::getMOHx(VolumeType xVolumeAbsolute) const { - double noOfVoxel = xVolumeAbsolute / _doseIterator->getCurrentVoxelVolume(); - DoseTypeGy resultDose = 0; + VolumeType dummy; + return getValue(_MOHx, xVolumeAbsolute, false, dummy); + } - double countVoxels = 0; - int i = doseVector.size() - 1; + DoseTypeGy DoseStatistics::getMOCx(VolumeType xVolumeAbsolute, bool findNearestValue, + VolumeType& maximumDistanceFromOriginalVolume) const + { + return getValue(_MOCx, xVolumeAbsolute, findNearestValue, maximumDistanceFromOriginalVolume); + } - for (; i >= 0; i--) - { - countVoxels += voxelProportionVector.at(i); + DoseTypeGy DoseStatistics::getMOCx(VolumeType xVolumeAbsolute) const + { + VolumeType dummy; + return getValue(_MOCx, xVolumeAbsolute, false, dummy); + } - if (countVoxels >= noOfVoxel) - { - break; - } - } + DoseTypeGy DoseStatistics::getMaxOHx(VolumeType xVolumeAbsolute, bool findNearestValue, + VolumeType& maximumDistanceFromOriginalVolume) const + { + return getValue(_MaxOHx, xVolumeAbsolute, findNearestValue, maximumDistanceFromOriginalVolume); + } - if (i >= 0) - { - resultDose = doseVector.at(i); - } - else - { - resultDose = _minimum; - } + DoseTypeGy DoseStatistics::getMaxOHx(VolumeType xVolumeAbsolute) const + { + VolumeType dummy; + return getValue(_MaxOHx, xVolumeAbsolute, false, dummy); + } - return resultDose; + DoseTypeGy DoseStatistics::getMinOCx(VolumeType xVolumeAbsolute, bool findNearestValue, + VolumeType& maximumDistanceFromOriginalVolume) const + { + return getValue(_MinOCx, xVolumeAbsolute, findNearestValue, maximumDistanceFromOriginalVolume); } - DoseTypeGy DoseStatistics::getMOHx(DoseTypeGy xVolumeAbsolute) const + DoseTypeGy DoseStatistics::getMinOCx(VolumeType xVolumeAbsolute) const { - double noOfVoxel = xVolumeAbsolute / _doseIterator->getCurrentVoxelVolume(); + VolumeType dummy; + return getValue(_MinOCx, xVolumeAbsolute, false, dummy); + } double DoseStatistics::getValue(const std::map& aMap, double key, bool findNearestValueInstead, double& storedKey) const { if (aMap.find(key) != std::end(aMap)) { - return 0; + return aMap.find(key)->second; } else { - double countVoxels = 0; - double sum = 0; - - for (int i = doseVector.size() - 1; i >= 0; i--) + //value not in map. We have to find the nearest value + if (aMap.empty()) { - double voxelProportion = voxelProportionVector.at(i); - countVoxels += voxelProportion; - sum += doseVector.at(i) * voxelProportion; - - if (countVoxels >= noOfVoxel) + throw core::DataNotAvailableException("No Vx values are defined"); + } + else + { + if (findNearestValueInstead) { - break; + auto iterator = findNearestKeyInMap(aMap, key); + storedKey = iterator->first; + return iterator->second; + } + else + { + throw core::DataNotAvailableException("No Vx value with required dose is defined"); } } - - return (DoseTypeGy)(sum / noOfVoxel); } } std::map::const_iterator DoseStatistics::findNearestKeyInMap(const std::map& aMap, double key) const { - double noOfVoxel = xVolumeAbsolute / _doseIterator->getCurrentVoxelVolume(); + double minDistance = 1e19; + double minDistanceLast = 1e20; + auto iterator = std::begin(aMap); - if (noOfVoxel == 0) - { - return 0; - } - else + while (iterator != std::end(aMap)) { - double countVoxels = 0; - double sum = 0; - std::vector::const_iterator it = doseVector.begin(); - std::vector::const_iterator itD = voxelProportionVector.begin(); + minDistanceLast = minDistance; + minDistance = fabs(iterator->first - key); - for (; it != doseVector.end(); ++it, ++itD) + if (minDistanceLast > minDistance) { - double voxelProportion = *itD; - countVoxels += voxelProportion; - sum += (*it) * voxelProportion; - - if (countVoxels >= noOfVoxel) + ++iterator; + } + else + { + if (iterator != std::begin(aMap)) + { + --iterator; + return iterator; + } + else { - break; + return std::begin(aMap); } } - - return (DoseTypeGy)(sum / noOfVoxel); } + + --iterator; + return iterator; } - DoseTypeGy DoseStatistics::getMaxOHx(DoseTypeGy xVolumeAbsolute) const + DoseStatistics::ResultListPointer DoseStatistics::getMaximumPositions() const { - double noOfVoxel = xVolumeAbsolute / _doseIterator->getCurrentVoxelVolume(); - DoseTypeGy resultDose = 0; - - double countVoxels = 0; - int i = doseVector.size() - 1; - - for (; i >= 0; i--) - { - countVoxels += voxelProportionVector.at(i); - - if (countVoxels >= noOfVoxel) - { - break; - } - } + return _maximumVoxelPositions; + } - if (i - 1 >= 0) - { - resultDose = doseVector.at(i - 1); - } + DoseStatistics::ResultListPointer DoseStatistics::getMinimumPositions() const + { + return _minimumVoxelPositions; + } - return resultDose; + DoseStatistics::DoseToVolumeFunctionType DoseStatistics::getAllVx() const + { + return _Vx; } - DoseTypeGy DoseStatistics::getMinOCx(DoseTypeGy xVolumeAbsolute) const + DoseStatistics::VolumeToDoseFunctionType DoseStatistics::getAllDx() const { - double noOfVoxel = xVolumeAbsolute / _doseIterator->getCurrentVoxelVolume(); - DoseTypeGy resultDose = 0; + return _Dx; + } - double countVoxels = 0; - std::vector::const_iterator it = doseVector.begin(); - std::vector::const_iterator itD = voxelProportionVector.begin(); + DoseStatistics::VolumeToDoseFunctionType DoseStatistics::getAllMOHx() const + { + return _MOHx; + } - for (; itD != voxelProportionVector.end(); ++itD, ++it) - { - countVoxels += *itD; + DoseStatistics::VolumeToDoseFunctionType DoseStatistics::getAllMOCx() const + { + return _MOCx; + } - if (countVoxels >= noOfVoxel) - { - break; - } - } + DoseStatistics::VolumeToDoseFunctionType DoseStatistics::getAllMaxOHx() const + { + return _MaxOHx; + } - if (it != doseVector.end()) - { - ++it; + DoseStatistics::VolumeToDoseFunctionType DoseStatistics::getAllMinOCx() const + { + return _MinOCx; + } - if (it != doseVector.end()) - { - resultDose = *it; - } - else - { - resultDose = (DoseTypeGy)_maximum; - } - } - else - { - resultDose = (DoseTypeGy)_maximum; - } - return resultDose; - } }//end namespace algorithms }//end namespace rttb diff --git a/code/algorithms/rttbDoseStatistics.h b/code/algorithms/rttbDoseStatistics.h index a138d5b..91d42c6 100644 --- a/code/algorithms/rttbDoseStatistics.h +++ b/code/algorithms/rttbDoseStatistics.h @@ -1,270 +1,207 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DOSE_STATISTICS_H #define __DOSE_STATISTICS_H #include +#include + +#include #include "rttbBaseType.h" #include "rttbDoseIteratorInterface.h" -namespace rttb{ +namespace rttb +{ - namespace algorithms{ + namespace algorithms + { /*! @class DoseStatistics - @brief Data class for storing different statistical values from a RT dose distribution - @details DoseStatisticsCalculator is used to compute the DoseStatistics + @brief This is a data class storing different statistical values from a rt dose distribution + @sa DoseStatisticsCalculator */ class DoseStatistics - { - public: - typedef core::DoseIteratorInterface::DoseIteratorPointer DoseIteratorPointer; - typedef boost::shared_ptr > > ResultListPointer; + { + public: + enum complexStatistics { Dx, Vx, MOHx, MOCx, MaxOHx, MinOCx }; + typedef boost::shared_ptr > > ResultListPointer; + typedef boost::shared_ptr DoseStatisticsPointer; + typedef std::map DoseToVolumeFunctionType; + typedef std::map VolumeToDoseFunctionType; private: - /*! @brief Returns the value of a map belonging to a key - @details if findNearestValueInstead=true and the key is not in the map, the value belonging to the nearest key is returned. This key is then storedKey. - */ double getValue(const std::map& aMap, double key, bool findNearestValueInstead, double& storedKey) const; std::map::const_iterator findNearestKeyInMap(const std::map& aMap, double key) const; DoseStatisticType _maximum; DoseStatisticType _minimum; ResultListPointer _maximumVoxelPositions; ResultListPointer _minimumVoxelPositions; DoseStatisticType _mean; DoseStatisticType _stdDeviation; - VolumeType _numVoxels; + unsigned int _numVoxels; VolumeType _volume; VolumeToDoseFunctionType _Dx; DoseToVolumeFunctionType _Vx; VolumeToDoseFunctionType _MOHx; VolumeToDoseFunctionType _MOCx; VolumeToDoseFunctionType _MaxOHx; VolumeToDoseFunctionType _MinOCx; public: + /*! @brief Standard Constructor + */ + //DoseStatistics(); + /*! @brief Constructor - @details the dose statistic values are set. Minimum, maximum, mean, stdDeviation, numVoxels and volume are mandatory. minimumVoxelPositions, maximumVoxelPositions, Dx, Vx, MOHx, MOCx, MaxOHx and MinOCx are optional. - @param minimum the minimum dose in Gy - @param maximum the maximum dose in Gy - @param mean the mean dose in Gy - @param stdDeviation the stdDeviation of the dose in Gy - @param numVoxels the amount of voxels (sub-voxel accurate, i.e. not necessarily whole voxels) - @param volume the volume in cm^3 - @param minimumVoxelPositions a vector containing the function minDose --> VoxelGrid as a pair - @param maximumVoxelPositions a vector containing the function maxDose --> VoxelGrid as a pair - @param Dx a map containing the function Volume x --> Dose y with: the minimal dose y is delivered to the volume x. - @param Vx a map containing the function Dose x --> Volume y with: the volume y is irradiated with a dose >= x. - @param MOHx a map containing the function Volume x --> Dose y with: the mean dose y of the hottest voxels in volume x. - @param MOCx a map containing the function Volume x --> Dose y with: the mean dose y of the coldest voxels in volume x. - @param MaxOHx a map containing the function Volume x --> Dose y with: the maximum dose y outside of the hottest voxels in volume x. - @param MinOCx a map containing the function Volume x --> Dose y with: the minimum dose y outside of the coldest voxels in volume x. + @detail the dose statistic values are set. Complex values maximumVoxelLocation, maximumVoxelLocation, Dx, Vx, MOHx, MOCx, MaxOHx and MinOCx are optional */ DoseStatistics(DoseStatisticType minimum, DoseStatisticType maximum, DoseStatisticType mean, - DoseStatisticType stdDeviation, VolumeType numVoxels, VolumeType volume, + DoseStatisticType stdDeviation, unsigned int numVoxels, VolumeType volume, ResultListPointer minimumVoxelPositions = boost::make_shared > > (std::vector >()), ResultListPointer maximumVoxelPositions = boost::make_shared > > (std::vector >()), VolumeToDoseFunctionType Dx = VolumeToDoseFunctionType(), DoseToVolumeFunctionType Vx = DoseToVolumeFunctionType(), VolumeToDoseFunctionType MOHx = VolumeToDoseFunctionType(), VolumeToDoseFunctionType MOCx = VolumeToDoseFunctionType(), VolumeToDoseFunctionType MaxOHx = VolumeToDoseFunctionType(), VolumeToDoseFunctionType MinOCx = VolumeToDoseFunctionType()); + DoseStatistics::~DoseStatistics(); + void setMinimumVoxelPositions(ResultListPointer minimumVoxelPositions); void setMaximumVoxelPositions(ResultListPointer maximumVoxelPositions); - void setDx(const VolumeToDoseFunctionType& DxValues); - void setVx(const DoseToVolumeFunctionType& VxValues); + void setDx(const DoseToVolumeFunctionType& DxValues); + void setVx(const VolumeToDoseFunctionType& VxValues); void setMOHx(const VolumeToDoseFunctionType& MOHxValues); void setMOCx(const VolumeToDoseFunctionType& MOCxValues); void setMaxOHx(const VolumeToDoseFunctionType& MaxOHxValues); void setMinOCx(const VolumeToDoseFunctionType& MinOCxValues); /*! @brief Get number of voxels in doseIterator, with sub-voxel accuracy. */ - VolumeType getNumberOfVoxels() const; + unsigned int getNumberOfVoxels() const; - /*! @brief Constructor - */ - DoseStatistics(DoseIteratorPointer aDoseIterator); + VolumeType getVolume() const; /*! @brief Get the maximum of the current dose distribution. - @return the maximum dose in Gy + @return Return the maximum dose in Gy */ DoseStatisticType getMaximum() const; - /*! @brief Get a vector of pairs of the the maximum dose VoxelGridIDs together with their dose value in Gy + /*! @brief Get a vector of the the maximum dose VoxelGridIDs together with their dose value in Gy + @exception InvalidDoseException if the vector has not been set (i.e. is empty) */ ResultListPointer getMaximumPositions() const; /*! @brief Get the minimum of the current dose distribution. - @return the minimum dose in Gy + @return Return the minimum dose in Gy */ DoseStatisticType getMinimum() const; - /*! @brief Get a vector of pairs of the the minimum dose VoxelGridIDs together with their dose value in Gy + /*! @brief Get a vector of the the minimum dose VoxelGridIDs together with their dose value in Gy + @exception InvalidDoseException if the vector has not been set (i.e. is empty) */ ResultListPointer getMinimumPositions() const; /*! @brief Get the mean of the current dose distribution. - @return the mean dose in Gy + @return Return the mean dose in Gy */ DoseStatisticType getMean() const; /*! @brief Get the standard deviation of the current dose distribution. - @return the standard deviation in Gy + @return Return the standard deviation in Gy */ DoseStatisticType getStdDeviation() const; /*! @brief Get the variance of of the current dose distribution. - @return the variance in Gy + @return Return the variance in Gy */ DoseStatisticType getVariance() const; - /*! @overload - @details calls getVx(xDoseAbsolute, false, Dummy) - */ - VolumeType getVx(DoseTypeGy xDoseAbsolute) const; + /*! @brief Get Vx: the volume irradiated with a dose >= x. - @param xDoseAbsolute the dose - @param findNearestValue if false: only the value (=volume) is returned that corresponds to the exact key (=dose). - If true: the value corresponding to the nearest key given is returned if the exact value is not in the map - @param nearestXDose the nearest key (=dose) found - @return Absolute volume in cm^3. + @return Return absolute volume in absolute cm^3. @exception NoDataException if the Vx values have not been set (i.e. the vector is empty) - @exception NoDataException if the requested Dose is not in the precomputed vector + @exception NoDataException if the requested Dose is not in the vector */ + VolumeType getVx(DoseTypeGy xDoseAbsolute) const; VolumeType getVx(DoseTypeGy xDoseAbsolute, bool findNearestValue, DoseTypeGy& nearestXDose) const; - /*! @brief Get all computed Dx values - */ DoseToVolumeFunctionType getAllVx() const; - /*! - @brief Get Dx: the minimal dose delivered to part x of the current volume. - @param xVolumeAbsolute the absolute volume in cm^3 - @param findNearestValue if false: only the value (=dose) is returned that corresponds to the exact key (=volume). - If true: the value corresponding to the nearest key given is returned if the exact value is not in the map - @param nearestXVolume the nearest key (=volume) found - @return dose value in Gy. - @exception NoDataException if the Dx values have not been set (i.e. the vector is empty) - @exception NoDataException if the requested volume is not in the precomputed vector + /*! @brief Get Dx: the minimal dose delivered to part x of the current volume. + @return Return dose value in Gy. + @exception InvalidDoseException if the Dx values have not been set (i.e. the vector is empty) */ DoseTypeGy getDx(VolumeType xVolumeAbsolute, bool findNearestValue, VolumeType& nearestXVolume) const; - /*! @overload - @details calls getDx(xVolumeAbsolute, false, Dummy) - */ DoseTypeGy getDx(VolumeType xVolumeAbsolute) const; - /*! @brief Get all computed Vx values - */ VolumeToDoseFunctionType getAllDx() const; /*! @brief Get MOHx: mean dose of the hottest x voxels. @return Return dose value in Gy. - @exception NoDataException if the MOHx values have not been set (i.e. the vector is empty) - @exception NoDataException if the requested volume is not in the precomputed vector - @sa getMOHx() + @exception InvalidDoseException if the values have not been set (i.e. the vector is empty) */ DoseTypeGy getMOHx(VolumeType xVolumeAbsolute, bool findNearestValue, VolumeType& nearestXVolume) const; - /*! @overload - @details calls getMOHx(xVolumeAbsolute, false, Dummy) - */ DoseTypeGy getMOHx(VolumeType xVolumeAbsolute) const; - /*! @brief Get all computed MOHx values - @return Return dose value in Gy. - */ VolumeToDoseFunctionType getAllMOHx() const; /*! @brief Get MOCx: mean dose of the coldest x voxels. @return Return dose value in Gy. - @exception NoDataException if the MOCx values have not been set (i.e. the vector is empty) - @exception NoDataException if the requested volume is not in the precomputed vector - @sa getDx() + @exception InvalidDoseException if the values have not been set (i.e. the vector is empty) */ DoseTypeGy getMOCx(VolumeType xVolumeAbsolute, bool findNearestValue, VolumeType& nearestXVolume) const; - /*! @overload - @details calls getMOCx(xVolumeAbsolute, false, Dummy) - */ DoseTypeGy getMOCx(VolumeType xVolumeAbsolute) const; - /*! @brief Get all computed MOCx values - @return Return dose value in Gy. - */ VolumeToDoseFunctionType getAllMOCx() const; /*! @brief Get MaxOHx: Maximum outside of the hottest x voxels. @return Return dose value in Gy. - @exception NoDataException if the MaxOHx values have not been set (i.e. the vector is empty) - @exception NoDataException if the requested volume is not in the precomputed vector - @sa getDx() + @exception InvalidDoseException if the values have not been set (i.e. the vector is empty) */ DoseTypeGy getMaxOHx(VolumeType xVolumeAbsolute, bool findNearestValue, VolumeType& nearestXVolume) const; - /*! @overload - @details calls getMaxOHx(xVolumeAbsolute, false, Dummy) - */ DoseTypeGy getMaxOHx(VolumeType xVolumeAbsolute) const; - /*! @brief Get all computed MaxOHx values - */ VolumeToDoseFunctionType getAllMaxOHx() const; /*! @brief Get MinOCx: Minimum outside of the coldest x voxels. @return Return dose value in Gy. - @exception NoDataException if the MinOCx values have not been set (i.e. the vector is empty) - @exception NoDataException if the requested volume is not in the precomputed vector - @sa getDx() + @exception InvalidDoseException if the values have not been set (i.e. the vector is empty) */ DoseTypeGy getMinOCx(VolumeType xVolumeAbsolute, bool findNearestValue, VolumeType& nearestXVolume) const; - /*! @overload - @details calls getMinOCx(xVolumeAbsolute, false, Dummy) - */ DoseTypeGy getMinOCx(VolumeType xVolumeAbsolute) const; - /*! @brief Get all computed MinOCx values - */ VolumeToDoseFunctionType getAllMinOCx() const; }; - /*! @brief Get MaxOHx: Maximum outside of the hottest x voxels. - @return Return dose value in Gy. - */ - DoseTypeGy getMaxOHx(VolumeType xVolumeAbsolute) const; - - /*! @brief Get MinOCx: Minimum outside of the coldest x voxels. - @return Return ose value in Gy. - */ - DoseTypeGy getMinOCx(VolumeType xVolumeAbsolute) const; - }; - - } } +} #endif diff --git a/code/core/files.cmake b/code/core/files.cmake index 60d2b55..1510e4f 100644 --- a/code/core/files.cmake +++ b/code/core/files.cmake @@ -1,60 +1,64 @@ SET(CPP_FILES rttbDoseIteratorInterface.cpp rttbDVH.cpp rttbDVHCalculator.cpp rttbDVHSet.cpp + rttbDataNotAvailableException.cpp rttbException.cpp rttbGenericDoseIterator.cpp rttbGenericMaskedDoseIterator.cpp rttbGeometricInfo.cpp rttbIndexOutOfBoundsException.cpp rttbInvalidDoseException.cpp rttbInvalidParameterException.cpp rttbMappingOutsideOfImageException.cpp rttbMaskedDoseIteratorInterface.cpp rttbMaskVoxel.cpp rttbNullPointerException.cpp rttbPaddingException.cpp rttbPhysicalInfo.cpp rttbStructure.cpp rttbStructureSet.cpp rttbStrVectorStructureSetGenerator.cpp + rttbDoseAccessorWithGeoInfoBase.cpp ) SET(H_FILES rttbBaseType.h + rttbDataNotAvailableException.h rttbDoseAccessorGeneratorBase.h rttbDoseAccessorGeneratorInterface.h rttbDoseAccessorInterface.h + rttbDoseAccessorWithGeoInfoBase.h rttbDoseIteratorInterface.h rttbDVH.h rttbDVHCalculator.h rttbDVHGeneratorInterface.h rttbDVHSet.h rttbException.h rttbExceptionMacros.h rttbGenericDoseIterator.h rttbGenericMaskedDoseIterator.h rttbGeometricInfo.h rttbIndexConversionInterface.h rttbIndexOutOfBoundsException.h rttbInvalidDoseException.h rttbInvalidParameterException.h rttbMappingOutsideOfImageException.h rttbMaskAccessorGeneratorBase.h rttbMaskAccessorGeneratorInterface.h rttbMaskAccessorInterface.h rttbMaskAccessorProcessorBase.h rttbMaskAccessorProcessorInterface.h rttbMaskedDoseIteratorInterface.h rttbMaskVoxel.h rttbMutableDoseAccessorInterface.h rttbMutableMaskAccessorInterface.h rttbNullPointerException.h rttbPaddingException.h rttbPhysicalInfo.h rttbStructure.h rttbStructureSet.h rttbStructureSetGeneratorInterface.h rttbStrVectorStructureSetGenerator.h ) diff --git a/code/core/rttbDataNotAvailableException.cpp b/code/core/rttbDataNotAvailableException.cpp new file mode 100644 index 0000000..357c781 --- /dev/null +++ b/code/core/rttbDataNotAvailableException.cpp @@ -0,0 +1,43 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notices for more information. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision: 741 $ (last changed revision) +// @date $Date: 2014-09-16 16:34:22 +0200 (Di, 16 Sep 2014) $ (last change date) +// @author $Author: hentsch $ (last changed by) +*/ + +#include +#include + +#include "rttbDataNotAvailableException.h" + +namespace rttb +{ + namespace core + { + + const char* DataNotAvailableException::what() const throw() + { + return rttb_what.c_str(); + } + + const char* DataNotAvailableException::GetNameOfClass() const + { + return "DataNotAvailableException"; + } + + }//end namespace core +}//end namespace rttb diff --git a/code/core/rttbDataNotAvailableException.h b/code/core/rttbDataNotAvailableException.h new file mode 100644 index 0000000..bfa78c1 --- /dev/null +++ b/code/core/rttbDataNotAvailableException.h @@ -0,0 +1,58 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notices for more information. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision: 741 $ (last changed revision) +// @date $Date: 2014-09-16 16:34:22 +0200 (Di, 16 Sep 2014) $ (last change date) +// @author $Author: hentsch $ (last changed by) +*/ + +#ifndef __DATA_NOT_AVAILABLE_EXCEPTION_H +#define __DATA_NOT_AVAILABLE_EXCEPTION_H + +#include +#include + +#include "rttbException.h" + + +namespace rttb +{ + namespace core + { + + /*! @class DataNotAvailableException + @brief This exception will be thrown if the requested data is not available. + */ + class DataNotAvailableException : public Exception + { + public: + DataNotAvailableException(const std::string& aWhat) : Exception(aWhat) {} + + virtual ~DataNotAvailableException() throw() {} + + /*! @brief Get the exception description + */ + virtual const char* what() const throw(); + + /*! @brief Get the name of the exception class + */ + virtual const char* GetNameOfClass() const; + }; + + } +} + +#endif diff --git a/code/core/rttbDoseAccessorInterface.h b/code/core/rttbDoseAccessorInterface.h index e5f8e24..c6b1727 100644 --- a/code/core/rttbDoseAccessorInterface.h +++ b/code/core/rttbDoseAccessorInterface.h @@ -1,81 +1,92 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DOSE_ACCESSOR_INTERFACE_NEW_H #define __DOSE_ACCESSOR_INTERFACE_NEW_H #include #include "rttbBaseType.h" #include "rttbGeometricInfo.h" #include "rttbIndexConversionInterface.h" namespace rttb { - namespace core - { - - /*! @class IndexConversionInterface - @brief This class represents the conversion of 3D grid indices to 1D grid IDs. - */ - class DoseAccessorInterface: public IndexConversionInterface - { - public: - typedef boost::shared_ptr DoseAccessorPointer; - private: - DoseAccessorInterface(const DoseAccessorInterface&); //not implemented on purpose -> non-copyable - DoseAccessorInterface& operator=(const - DoseAccessorInterface&);//not implemented on purpose -> non-copyable - - public: - DoseAccessorInterface() {}; - virtual ~DoseAccessorInterface() {}; - - inline const core::GeometricInfo& getGeometricInfo() const - { - return _geoInfo; - }; - - inline GridSizeType getGridSize() const - { - return _geoInfo.getNumberOfVoxels(); - }; - - virtual DoseTypeGy getDoseAt(const VoxelGridID aID) const = 0; - - virtual DoseTypeGy getDoseAt(const VoxelGridIndex3D& aIndex) const = 0; - - /*! @brief is true if dose is on a homogeneous grid - @remarks Inhomogeneous grids are not supported at the moment, but if they will be supported in the future - the interface does not need to change. - */ - virtual bool isGridHomogeneous() const - { - return true; - } - - virtual const IDType getDoseUID() const = 0; - protected: - core::GeometricInfo _geoInfo; - }; - } + namespace core + { + + /*! @class IndexConversionInterface + @brief This class represents the conversion of 3D grid indices to 1D grid IDs. + */ + class DoseAccessorInterface: public IndexConversionInterface + { + public: + typedef boost::shared_ptr DoseAccessorPointer; + private: + DoseAccessorInterface(const DoseAccessorInterface&); //not implemented on purpose -> non-copyable + DoseAccessorInterface& operator=(const + DoseAccessorInterface&);//not implemented on purpose -> non-copyable + + public: + DoseAccessorInterface() {}; + virtual ~DoseAccessorInterface() {}; + + /*! @brief test if given ID is inside current dose grid + */ + bool validID(const VoxelGridID aID) const + { + return this->getGeometricInfo().validID(aID); + }; + + + /*! @brief test if given index is inside current dose grid + */ + bool validIndex(const VoxelGridIndex3D& aIndex) const + { + return this->getGeometricInfo().validIndex(aIndex); + }; + + virtual const core::GeometricInfo& getGeometricInfo() const = 0; + + virtual GridSizeType getGridSize() const + { + return this->getGeometricInfo().getNumberOfVoxels(); + }; + + virtual DoseTypeGy getDoseAt(const VoxelGridID aID) const = 0; + + virtual DoseTypeGy getDoseAt(const VoxelGridIndex3D& aIndex) const = 0; + + /*! @brief is true if dose is on a homogeneous grid + @remarks Inhomogeneous grids are not supported at the moment, but if they will be supported in the future + the interface does not need to change. + */ + virtual bool isGridHomogeneous() const + { + return true; + } + + virtual const IDType getDoseUID() const = 0; + + }; + } } #endif diff --git a/code/core/rttbDoseAccessorWithGeoInfoBase.cpp b/code/core/rttbDoseAccessorWithGeoInfoBase.cpp new file mode 100644 index 0000000..15b9452 --- /dev/null +++ b/code/core/rttbDoseAccessorWithGeoInfoBase.cpp @@ -0,0 +1,47 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notices for more information. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision: 877 $ (last changed revision) +// @date $Date: 2015-01-09 10:51:10 +0100 (Fr, 09 Jan 2015) $ (last change date) +// @author $Author: hentsch $ (last changed by) +*/ + + +#include "rttbDoseAccessorWithGeoInfoBase.h" + +namespace rttb +{ + namespace core + { + + const core::GeometricInfo& + DoseAccessorWithGeoInfoBase:: + getGeometricInfo() const + { + return _geoInfo; + } + + DoseAccessorWithGeoInfoBase::~DoseAccessorWithGeoInfoBase() + { + } + + DoseAccessorWithGeoInfoBase::DoseAccessorWithGeoInfoBase() + { + } + + } +} + diff --git a/code/core/rttbDoseAccessorWithGeoInfoBase.h b/code/core/rttbDoseAccessorWithGeoInfoBase.h new file mode 100644 index 0000000..2891d36 --- /dev/null +++ b/code/core/rttbDoseAccessorWithGeoInfoBase.h @@ -0,0 +1,50 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notices for more information. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision: 877 $ (last changed revision) +// @date $Date: 2015-01-09 10:51:10 +0100 (Fr, 09 Jan 2015) $ (last change date) +// @author $Author: hentsch $ (last changed by) +*/ +#ifndef __DOSE_ACCESSOR_WITH_GEO_INFO_BASE_H +#define __DOSE_ACCESSOR_WITH_GEO_INFO_BASE_H + +#include "rttbDoseAccessorInterface.h" + +namespace rttb +{ + namespace core + { + + /*! @class DoseAccessorWithGeoInfoBase + @brief Base class for all accessor implementations that have there own geometric info. + */ + class DoseAccessorWithGeoInfoBase: public core::DoseAccessorInterface + { + protected: + core::GeometricInfo _geoInfo; + + public: + ~DoseAccessorWithGeoInfoBase(); + + DoseAccessorWithGeoInfoBase(); + + virtual const core::GeometricInfo& getGeometricInfo() const; + + }; + } +} + +#endif diff --git a/code/core/rttbExceptionMacros.h b/code/core/rttbExceptionMacros.h index 70a0be8..98e8bd9 100644 --- a/code/core/rttbExceptionMacros.h +++ b/code/core/rttbExceptionMacros.h @@ -1,69 +1,109 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include "rttbException.h" /*!@def rttbDefaultExceptionMacro * This macro is used to throw a basic ExceptionObject within an object method. * It will generate the exception message and throw the exception.\n -* Use mapGenericDefaultExceptionMacro() for other objects that do not compli with the api or for +* Use rttbDefaultExceptionStaticMacro() for other objects that do not compli with the api or for * static functions.\n * Use rttbExceptionMacro() if you want to specifiy a arbitrary exception class that should be thrown. * Example usage looks like: * rttbDefaultExceptionMacro(<< "this is an exception" << this->SomeVariable); * @ingroup Exception -* @todo for future extension of the exception classes: Use if file and line are supported in Exception +* @todo for future extension of the exception classes: Use if file and line are supported in Exception * ::rttb::core::Exception e_(__FILE__, __LINE__, message.str().c_str()); */ #define rttbDefaultExceptionMacro(x) \ { \ - std::ostringstream message; \ - message << "Exception: " \ - << "(" << this << "): " x; \ - ::rttb::core::Exception e_(message.str().c_str()); \ - throw e_; /* Explicit naming to work around Intel compiler bug. */ \ + std::ostringstream message; \ + message << "Exception: " \ + << "(" << this << "): " x; \ + ::rttb::core::Exception e_(message.str().c_str()); \ + throw e_; /* Explicit naming to work around Intel compiler bug. */ \ } - + /*!@def mapExceptionMacro * This macro is used to throw the passed exception class within an object method. * The macro presumes that the object owns a method this->GetNameOfClass().\n * The macro will set file name, line number and function signiture to the exception * and log the exception as error in the logbook before throwing it.\n -* Use mapGenericExceptionMacro() for other objects that do not compli with the api or for +* Use rttbExceptionStaticMacro() for other objects that do not compli with the api or for * static functions.\n * @sa mapGenericExceptionMacro * * Example usage looks like: * rttbExceptionMacro(AnExceptionClass, << "this is an exception" << this->SomeVariable); * @ingroup Exception -* @todo for future extension of the exception classes: Use if file and line are supported in Exception +* @todo for future extension of the exception classes: Use if file and line are supported in Exception * EType e_(__FILE__, __LINE__, message.str().c_str()); */ #define rttbExceptionMacro( EType, x) \ { \ - std::ostringstream message; \ - message << "Exception: "\ - << "(" << this << "): " x; \ - EType e_(message.str().c_str()); \ - throw e_; /* Explicit naming to work around Intel compiler bug. */ \ + std::ostringstream message; \ + message << "Exception: "\ + << "(" << this << "): " x; \ + EType e_(message.str().c_str()); \ + throw e_; /* Explicit naming to work around Intel compiler bug. */ \ + } + +/*!@def rttbDefaultExceptionStaticMacro +* This macro is used to throw a basic ExceptionObject within a static method. +* It will generate the exception message and throw the exception.\n +* Use rttbExceptionStaticMacro() if you want to specifiy a arbitrary exception class that should be thrown. +* Example usage looks like: +* rttbDefaultExceptionMacro(<< "this is an exception" << SomeVariable); +* @ingroup Exception +* @todo for future extension of the exception classes: Use if file and line are supported in Exception +* ::rttb::core::Exception e_(__FILE__, __LINE__, message.str().c_str()); +*/ +#define rttbDefaultExceptionStaticMacro(x) \ + { \ + std::ostringstream message; \ + message << "Exception: " x; \ + ::rttb::core::Exception e_(message.str().c_str()); \ + throw e_; /* Explicit naming to work around Intel compiler bug. */ \ + } + +/*!@def rttbExceptionStaticMacro +* This macro is used to throw the passed exception class within a static method. +* The macro will set file name, line number and function signiture to the exception +* and log the exception as error in the logbook before throwing it.\n +* Use mapGenericExceptionMacro() for other objects that do not compli with the api or for +* static functions.\n +* @sa mapGenericExceptionMacro +* +* Example usage looks like: +* rttbExceptionMacro(AnExceptionClass, << "this is an exception" << this->SomeVariable); +* @ingroup Exception +* @todo for future extension of the exception classes: Use if file and line are supported in Exception +* EType e_(__FILE__, __LINE__, message.str().c_str()); +*/ +#define rttbExceptionStaticMacro( EType, x) \ + { \ + std::ostringstream message; \ + message << "Exception: " x; \ + EType e_(message.str().c_str()); \ + throw e_; /* Explicit naming to work around Intel compiler bug. */ \ } diff --git a/code/io/dicom/rttbDicomDoseAccessor.h b/code/io/dicom/rttbDicomDoseAccessor.h index 1e609fc..13f935e 100644 --- a/code/io/dicom/rttbDicomDoseAccessor.h +++ b/code/io/dicom/rttbDicomDoseAccessor.h @@ -1,101 +1,101 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DICOM_DOSE_ACCESSOR_H #define __DICOM_DOSE_ACCESSOR_H #include #include #include #include #include "osconfig.h" /* make sure OS specific configuration is included first */ #include "drtdose.h" -#include "rttbDoseAccessorInterface.h" +#include "rttbDoseAccessorWithGeoInfoBase.h" #include "rttbBaseType.h" namespace rttb { - namespace io - { - namespace dicom - { - - /*! @class DicomDoseAccessor - @brief This class gives access to dose information from DRTDoseIOD and DcmItem - */ - class DicomDoseAccessor: public core::DoseAccessorInterface - { - public: - typedef boost::shared_ptr DRTDoseIODPtr; - typedef boost::shared_ptr DcmItemPtr; - - private: - DRTDoseIODPtr _dose; - DcmItemPtr _dataSet; - - /*! vector of dose data(absolute Gy dose/doseGridScaling)*/ - std::vector doseData; - - double _doseGridScaling; - - IDType _doseUID; - - DicomDoseAccessor(); - - protected: - /*! @brief Initialize dose data - @exception InvalidDoseException Thrown if _dose is invalid: one of column/row/numberOfFrames/doseGridScaling/pixelSpacing=0 - @exception DcmrtException Throw if dcmrt error - @exception boost/bad_lexical_cast Thrown if the imported header tags are not numerical. - */ - bool begin(); - - /*! @brief get all required data from dicom information contained in _dose - @exception boost/bad_lexical_cast Thrown if the imported header tags are not numerical. - */ - bool assembleGeometricInfo(); - - - public: - ~DicomDoseAccessor(); - - /*! @brief Constructor. Initialisation with a boost::shared_ptr of DRTDoseIOD and of DcmItem to get the pixel data - @exception DcmrtException Throw if dcmrt error - */ - DicomDoseAccessor(DRTDoseIODPtr aDRTDoseIODP, DcmItemPtr aDcmDataset); - - DoseTypeGy getDoseAt(const VoxelGridID aID) const; - - DoseTypeGy getDoseAt(const VoxelGridIndex3D& aIndex) const; - - const IDType getDoseUID() const - { - return _doseUID; - }; - }; - } - } + namespace io + { + namespace dicom + { + + /*! @class DicomDoseAccessor + @brief This class gives access to dose information from DRTDoseIOD and DcmItem + */ + class DicomDoseAccessor: public core::DoseAccessorWithGeoInfoBase + { + public: + typedef boost::shared_ptr DRTDoseIODPtr; + typedef boost::shared_ptr DcmItemPtr; + + private: + DRTDoseIODPtr _dose; + DcmItemPtr _dataSet; + + /*! vector of dose data(absolute Gy dose/doseGridScaling)*/ + std::vector doseData; + + double _doseGridScaling; + + IDType _doseUID; + + DicomDoseAccessor(); + + protected: + /*! @brief Initialize dose data + @exception InvalidDoseException Thrown if _dose is invalid: one of column/row/numberOfFrames/doseGridScaling/pixelSpacing=0 + @exception DcmrtException Throw if dcmrt error + @exception boost/bad_lexical_cast Thrown if the imported header tags are not numerical. + */ + bool begin(); + + /*! @brief get all required data from dicom information contained in _dose + @exception boost/bad_lexical_cast Thrown if the imported header tags are not numerical. + */ + bool assembleGeometricInfo(); + + + public: + ~DicomDoseAccessor(); + + /*! @brief Constructor. Initialisation with a boost::shared_ptr of DRTDoseIOD and of DcmItem to get the pixel data + @exception DcmrtException Throw if dcmrt error + */ + DicomDoseAccessor(DRTDoseIODPtr aDRTDoseIODP, DcmItemPtr aDcmDataset); + + DoseTypeGy getDoseAt(const VoxelGridID aID) const; + + DoseTypeGy getDoseAt(const VoxelGridIndex3D& aIndex) const; + + const IDType getDoseUID() const + { + return _doseUID; + }; + }; + } + } } #endif diff --git a/code/io/dicom/rttbDicomFileDoseAccessorWriter.cpp b/code/io/dicom/rttbDicomFileDoseAccessorWriter.cpp index e70bd26..49b5a57 100644 --- a/code/io/dicom/rttbDicomFileDoseAccessorWriter.cpp +++ b/code/io/dicom/rttbDicomFileDoseAccessorWriter.cpp @@ -1,242 +1,257 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision: 747 $ (last changed revision) // @date $Date: 2014-09-17 12:01:00 +0200 (Mi, 17 Sep 2014) $ (last change date) // @author $Author: hentsch $ (last changed by) */ #include #include #include #include #include "rttbDicomFileDoseAccessorWriter.h" #include "rttbInvalidDoseException.h" #include "rttbGeometricInfo.h" #include "rttbGeometricInfo.h" #include "rttbGenericDoseIterator.h" -#include "rttbDoseStatistics.h" +#include "rttbDoseStatisticsCalculator.h" namespace rttb { namespace io { namespace dicom { DicomFileDoseAccessorWriter::DicomFileDoseAccessorWriter() { _doseIOD = boost::make_shared(); _dataset = _fileformat.getDataset(); } - void DicomFileDoseAccessorWriter::setFileName(DICOMRTFileNameString aFileName) + void DicomFileDoseAccessorWriter::setFileName(DICOMRTFileNameString aFileName) { _fileName = aFileName; } bool DicomFileDoseAccessorWriter::process() - { - OFCondition status; - - /* Prepare dcmtk */ - DcmItem *dcm_item = 0; - - //get geometric info - rttb::core::GeometricInfo geometricInfo = _doseAccessor->getGeometricInfo(); - - - /* ----------------------------------------------------------------- */ - /* Part 1 -- General header */ - /* ----------------------------------------------------------------- */ - OFString CreationUID(_doseAccessor->getDoseUID().c_str()); - _dataset->putAndInsertString (DCM_ImageType, - "DERIVED\\SECONDARY\\REFORMATTED"); - _dataset->putAndInsertOFStringArray(DCM_InstanceCreationDate, - "");//Creation Date - _dataset->putAndInsertOFStringArray(DCM_InstanceCreationTime, - "");//Creation Time - _dataset->putAndInsertOFStringArray(DCM_InstanceCreatorUID, - CreationUID); - _dataset->putAndInsertString (DCM_SOPClassUID, UID_RTDoseStorage); - _dataset->putAndInsertString (DCM_SOPInstanceUID, - _doseAccessor->getDoseUID().c_str()); - _dataset->putAndInsertOFStringArray (DCM_StudyDate, - ""); - _dataset->putAndInsertOFStringArray (DCM_StudyTime, - ""); - _dataset->putAndInsertOFStringArray (DCM_AccessionNumber, ""); - _dataset->putAndInsertOFStringArray (DCM_Modality, "RTDOSE"); - _dataset->putAndInsertString (DCM_Manufacturer, "RTToolbox"); - _dataset->putAndInsertString (DCM_InstitutionName, ""); - _dataset->putAndInsertString (DCM_ReferringPhysicianName, ""); - _dataset->putAndInsertString (DCM_StationName, ""); - _dataset->putAndInsertString (DCM_ManufacturerModelName, "RTToolbox"); - - - /* (0008,1140) DCM_ReferencedImageSequence -- MIM likes this */ - dcm_item = 0; - _dataset->findOrCreateSequenceItem ( - DCM_ReferencedImageSequence, dcm_item, -2); - dcm_item->putAndInsertString (DCM_ReferencedSOPClassUID, - UID_CTImageStorage); - dcm_item->putAndInsertString (DCM_ReferencedSOPInstanceUID, - ""); - - _dataset->putAndInsertString (DCM_PatientName, ""); - _dataset->putAndInsertString (DCM_PatientID, ""); - _dataset->putAndInsertString (DCM_PatientBirthDate, ""); - _dataset->putAndInsertString (DCM_PatientSex, "O"); - _dataset->putAndInsertString (DCM_SliceThickness, boost::lexical_cast(geometricInfo.getSliceThickness()).c_str()); - _dataset->putAndInsertString (DCM_SoftwareVersions, - ""); - _dataset->putAndInsertString (DCM_StudyInstanceUID, - ""); - _dataset->putAndInsertString (DCM_SeriesInstanceUID, - ""); - _dataset->putAndInsertString (DCM_StudyID, "10001"); - _dataset->putAndInsertString (DCM_SeriesNumber, ""); - _dataset->putAndInsertString (DCM_InstanceNumber, "1"); - - - /* GCS FIX: PatientOrientation */ - std::ostringstream sstr; - sstr << geometricInfo.getImagePositionPatient().x() << "\\" << geometricInfo.getImagePositionPatient().y() - << "\\" << geometricInfo.getImagePositionPatient().z(); - _dataset->putAndInsertString (DCM_PatientOrientation, "L/P"); - _dataset->putAndInsertString (DCM_ImagePositionPatient, sstr.str().c_str()); - - sstr.str(""); - sstr << geometricInfo.getImageOrientationRow().x() << "\\" - << geometricInfo.getImageOrientationRow().y() << "\\" - << geometricInfo.getImageOrientationRow().z() << "\\" - << geometricInfo.getImageOrientationColumn().x() << "\\" - << geometricInfo.getImageOrientationColumn().y() << "\\" - << geometricInfo.getImageOrientationColumn().z(); - _dataset->putAndInsertString (DCM_ImageOrientationPatient, sstr.str().c_str()); - _dataset->putAndInsertString (DCM_FrameOfReferenceUID, - ""); - - _dataset->putAndInsertString (DCM_SamplesPerPixel, "1"); - _dataset->putAndInsertString (DCM_PhotometricInterpretation, "MONOCHROME2"); - sstr.str(""); - sstr << geometricInfo.getNumSlices(); - _dataset->putAndInsertString (DCM_NumberOfFrames, sstr.str().c_str()); - - /* GCS FIX: Add FrameIncrementPointer */ - _dataset->putAndInsertString (DCM_FrameIncrementPointer, - "(3004,000c)"); - - _dataset->putAndInsertUint16 (DCM_Rows, geometricInfo.getNumRows()); - _dataset->putAndInsertUint16 (DCM_Columns, geometricInfo.getNumColumns()); - sstr.str(""); - sstr << geometricInfo.getSpacing()(1) << "\\"<putAndInsertString (DCM_PixelSpacing, sstr.str().c_str()); - - _dataset->putAndInsertString (DCM_BitsAllocated, "32"); - _dataset->putAndInsertString (DCM_BitsStored, "32"); - _dataset->putAndInsertString (DCM_HighBit, "31"); - - _dataset->putAndInsertString (DCM_DoseUnits, "GY"); - - _dataset->putAndInsertString (DCM_DoseSummationType, "PLAN"); - - sstr.str("0"); - for (int i = 1; i < geometricInfo.getNumSlices(); i++) { - sstr << "\\" << i * geometricInfo.getSpacing()(2); - } - _dataset->putAndInsertString (DCM_GridFrameOffsetVector, sstr.str().c_str()); - - - /* We need to convert image to uint16_t, but first we need to - scale it so that the maximum dose fits in a 16-bit unsigned - integer. Compute an appropriate scaling factor based on the - maximum dose. */ - - /* Find the maximum value in the image */ - boost::shared_ptr spTestDoseIterator = boost::make_shared(_doseAccessor); - rttb::core::GenericDoseIterator::DoseIteratorPointer spDoseIterator (spTestDoseIterator); - rttb::algorithms::DoseStatistics doseStat (spDoseIterator); - boost::shared_ptr< std::vector > > myResultPairs = - boost::make_shared< std::vector > >(); - rttb::algorithms::DoseStatistics::ResultListPointer spMyResultPairs(myResultPairs); - double minDose = doseStat.getMinimum(myResultPairs); - double maxDose = doseStat.getMaximum(myResultPairs); - - /* Find scale factor */ - float dose_scale; - dose_scale = maxDose /PixelDataMaxValue; - - /* Scale the image and add scale factor to _dataset */ - sstr.str(""); - sstr << dose_scale; - _dataset->putAndInsertString (DCM_DoseGridScaling, sstr.str().c_str()); - - /* (300c,0002) ReferencedRTPlanSequence -- for future expansion */ - dcm_item = 0; - _dataset->findOrCreateSequenceItem ( - DCM_ReferencedRTPlanSequence, dcm_item, -2); - dcm_item->putAndInsertString (DCM_ReferencedSOPClassUID, - UID_RTPlanStorage); - dcm_item->putAndInsertString (DCM_ReferencedSOPInstanceUID, - ""); - - /* (300c,0060) DCM_ReferencedStructureSetSequence -- MIM likes this */ - dcm_item = 0; - _dataset->findOrCreateSequenceItem ( - DCM_ReferencedStructureSetSequence, dcm_item, -2); - dcm_item->putAndInsertString (DCM_ReferencedSOPClassUID, - UID_RTStructureSetStorage); - dcm_item->putAndInsertString (DCM_ReferencedSOPInstanceUID, - ""); - - /* Convert image bytes to integer, then add to _dataset */ - Uint16* pixelData; - int pixelCount = geometricInfo.getNumRows() * geometricInfo.getNumColumns() * geometricInfo.getNumSlices(); - pixelData = new Uint16[pixelCount]; - for(unsigned int i=0; igetDoseAt(i); - double pixelValue = doseValue/dose_scale; - if(pixelValue > PixelDataMaxValue){ - pixelValue = PixelDataMaxValue; - } - - pixelData[i] =boost::numeric_cast(pixelValue); - } - - status = _dataset->putAndInsertUint16Array (DCM_PixelData, - pixelData, pixelCount); - - if(!status.good()){ - throw core::InvalidDoseException("Error: put and insert pixel data failed!"); - } + { + OFCondition status; + + /* Prepare dcmtk */ + DcmItem* dcm_item = 0; + + //get geometric info + rttb::core::GeometricInfo geometricInfo = _doseAccessor->getGeometricInfo(); + + + /* ----------------------------------------------------------------- */ + /* Part 1 -- General header */ + /* ----------------------------------------------------------------- */ + OFString CreationUID(_doseAccessor->getDoseUID().c_str()); + _dataset->putAndInsertString(DCM_ImageType, + "DERIVED\\SECONDARY\\REFORMATTED"); + _dataset->putAndInsertOFStringArray(DCM_InstanceCreationDate, + "");//Creation Date + _dataset->putAndInsertOFStringArray(DCM_InstanceCreationTime, + "");//Creation Time + _dataset->putAndInsertOFStringArray(DCM_InstanceCreatorUID, + CreationUID); + _dataset->putAndInsertString(DCM_SOPClassUID, UID_RTDoseStorage); + _dataset->putAndInsertString(DCM_SOPInstanceUID, + _doseAccessor->getDoseUID().c_str()); + _dataset->putAndInsertOFStringArray(DCM_StudyDate, + ""); + _dataset->putAndInsertOFStringArray(DCM_StudyTime, + ""); + _dataset->putAndInsertOFStringArray(DCM_AccessionNumber, ""); + _dataset->putAndInsertOFStringArray(DCM_Modality, "RTDOSE"); + _dataset->putAndInsertString(DCM_Manufacturer, "RTToolbox"); + _dataset->putAndInsertString(DCM_InstitutionName, ""); + _dataset->putAndInsertString(DCM_ReferringPhysicianName, ""); + _dataset->putAndInsertString(DCM_StationName, ""); + _dataset->putAndInsertString(DCM_ManufacturerModelName, "RTToolbox"); + + + /* (0008,1140) DCM_ReferencedImageSequence -- MIM likes this */ + dcm_item = 0; + _dataset->findOrCreateSequenceItem( + DCM_ReferencedImageSequence, dcm_item, -2); + dcm_item->putAndInsertString(DCM_ReferencedSOPClassUID, + UID_CTImageStorage); + dcm_item->putAndInsertString(DCM_ReferencedSOPInstanceUID, + ""); + + _dataset->putAndInsertString(DCM_PatientName, ""); + _dataset->putAndInsertString(DCM_PatientID, ""); + _dataset->putAndInsertString(DCM_PatientBirthDate, ""); + _dataset->putAndInsertString(DCM_PatientSex, "O"); + _dataset->putAndInsertString(DCM_SliceThickness, + boost::lexical_cast(geometricInfo.getSliceThickness()).c_str()); + _dataset->putAndInsertString(DCM_SoftwareVersions, + ""); + _dataset->putAndInsertString(DCM_StudyInstanceUID, + ""); + _dataset->putAndInsertString(DCM_SeriesInstanceUID, + ""); + _dataset->putAndInsertString(DCM_StudyID, "10001"); + _dataset->putAndInsertString(DCM_SeriesNumber, ""); + _dataset->putAndInsertString(DCM_InstanceNumber, "1"); + + + /* GCS FIX: PatientOrientation */ + std::ostringstream sstr; + sstr << geometricInfo.getImagePositionPatient().x() << "\\" << geometricInfo.getImagePositionPatient().y() + << "\\" << geometricInfo.getImagePositionPatient().z(); + _dataset->putAndInsertString(DCM_PatientOrientation, "L/P"); + _dataset->putAndInsertString(DCM_ImagePositionPatient, sstr.str().c_str()); + + sstr.str(""); + sstr << geometricInfo.getImageOrientationRow().x() << "\\" + << geometricInfo.getImageOrientationRow().y() << "\\" + << geometricInfo.getImageOrientationRow().z() << "\\" + << geometricInfo.getImageOrientationColumn().x() << "\\" + << geometricInfo.getImageOrientationColumn().y() << "\\" + << geometricInfo.getImageOrientationColumn().z(); + _dataset->putAndInsertString(DCM_ImageOrientationPatient, sstr.str().c_str()); + _dataset->putAndInsertString(DCM_FrameOfReferenceUID, + ""); + + _dataset->putAndInsertString(DCM_SamplesPerPixel, "1"); + _dataset->putAndInsertString(DCM_PhotometricInterpretation, "MONOCHROME2"); + sstr.str(""); + sstr << geometricInfo.getNumSlices(); + _dataset->putAndInsertString(DCM_NumberOfFrames, sstr.str().c_str()); + + /* GCS FIX: Add FrameIncrementPointer */ + _dataset->putAndInsertString(DCM_FrameIncrementPointer, + "(3004,000c)"); + + _dataset->putAndInsertUint16(DCM_Rows, geometricInfo.getNumRows()); + _dataset->putAndInsertUint16(DCM_Columns, geometricInfo.getNumColumns()); + sstr.str(""); + sstr << geometricInfo.getSpacing()(1) << "\\" << geometricInfo.getSpacing()(0); + _dataset->putAndInsertString(DCM_PixelSpacing, sstr.str().c_str()); + + _dataset->putAndInsertString(DCM_BitsAllocated, "32"); + _dataset->putAndInsertString(DCM_BitsStored, "32"); + _dataset->putAndInsertString(DCM_HighBit, "31"); + + _dataset->putAndInsertString(DCM_DoseUnits, "GY"); + + _dataset->putAndInsertString(DCM_DoseSummationType, "PLAN"); + + sstr.str("0"); + + for (int i = 1; i < geometricInfo.getNumSlices(); i++) + { + sstr << "\\" << i* geometricInfo.getSpacing()(2); + } + + _dataset->putAndInsertString(DCM_GridFrameOffsetVector, sstr.str().c_str()); + + + /* We need to convert image to uint16_t, but first we need to + scale it so that the maximum dose fits in a 16-bit unsigned + integer. Compute an appropriate scaling factor based on the + maximum dose. */ + + /* Find the maximum value in the image */ + boost::shared_ptr spTestDoseIterator = + boost::make_shared(_doseAccessor); + rttb::core::GenericDoseIterator::DoseIteratorPointer spDoseIterator(spTestDoseIterator); + rttb::algorithms::DoseStatisticsCalculator myDoseStatsCalculator(spDoseIterator); + rttb::algorithms::DoseStatistics::DoseStatisticsPointer doseStatistics = + myDoseStatsCalculator.calculateDoseStatistics(); + //rttb::algorithms::DoseStatistics doseStat(spDoseIterator); + //boost::shared_ptr< std::vector > > myResultPairs = + // boost::make_shared< std::vector > >(); + //rttb::algorithms::DoseStatistics::ResultListPointer spMyResultPairs(myResultPairs); + + double maxDose = doseStatistics->getMaximum(); + + /* Find scale factor */ + float dose_scale; + dose_scale = maxDose / PixelDataMaxValue; + + /* Scale the image and add scale factor to _dataset */ + sstr.str(""); + sstr << dose_scale; + _dataset->putAndInsertString(DCM_DoseGridScaling, sstr.str().c_str()); + + /* (300c,0002) ReferencedRTPlanSequence -- for future expansion */ + dcm_item = 0; + _dataset->findOrCreateSequenceItem( + DCM_ReferencedRTPlanSequence, dcm_item, -2); + dcm_item->putAndInsertString(DCM_ReferencedSOPClassUID, + UID_RTPlanStorage); + dcm_item->putAndInsertString(DCM_ReferencedSOPInstanceUID, + ""); + + /* (300c,0060) DCM_ReferencedStructureSetSequence -- MIM likes this */ + dcm_item = 0; + _dataset->findOrCreateSequenceItem( + DCM_ReferencedStructureSetSequence, dcm_item, -2); + dcm_item->putAndInsertString(DCM_ReferencedSOPClassUID, + UID_RTStructureSetStorage); + dcm_item->putAndInsertString(DCM_ReferencedSOPInstanceUID, + ""); + + /* Convert image bytes to integer, then add to _dataset */ + Uint16* pixelData; + int pixelCount = geometricInfo.getNumRows() * geometricInfo.getNumColumns() * geometricInfo.getNumSlices(); + pixelData = new Uint16[pixelCount]; + + for (unsigned int i = 0; i < pixelCount; ++i) + { + double doseValue = _doseAccessor->getDoseAt(i); + double pixelValue = doseValue / dose_scale; + + if (pixelValue > PixelDataMaxValue) + { + pixelValue = PixelDataMaxValue; + } + + pixelData[i] = boost::numeric_cast(pixelValue); + } + + status = _dataset->putAndInsertUint16Array(DCM_PixelData, + pixelData, pixelCount); + + if (!status.good()) + { + throw core::InvalidDoseException("Error: put and insert pixel data failed!"); + } //Write dose to file - status = _fileformat.saveFile (_fileName.c_str(), EXS_LittleEndianExplicit); - if (status.bad()) { - std::cerr << "Error: cannot write DICOM RTDOSE!" << std::endl; + status = _fileformat.saveFile(_fileName.c_str(), EXS_LittleEndianExplicit); + + if (status.bad()) + { + std::cerr << "Error: cannot write DICOM RTDOSE!" << std::endl; } return true; } }//end namespace itk }//end namespace io }//end namespace rttb diff --git a/code/io/helax/rttbDicomHelaxDoseAccessor.h b/code/io/helax/rttbDicomHelaxDoseAccessor.h index c08c2f8..3eee9e4 100644 --- a/code/io/helax/rttbDicomHelaxDoseAccessor.h +++ b/code/io/helax/rttbDicomHelaxDoseAccessor.h @@ -1,105 +1,105 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DICOM_HELAX_DOSE_ACCESSOR_H #define __DICOM_HELAX_DOSE_ACCESSOR_H #include #include #include #include #include "osconfig.h" /* make sure OS specific configuration is included first */ #include "drtdose.h" -#include "rttbDoseAccessorInterface.h" +#include "rttbDoseAccessorWithGeoInfoBase.h" #include "rttbGeometricInfo.h" #include "rttbBaseType.h" namespace rttb { - namespace io - { - namespace helax - { + namespace io + { + namespace helax + { - /*! @class DicomHelaxDoseAccessor - @brief Load dose data from a directory containing dicom dose files, each file describes the helax dose in one slice. - */ - class DicomHelaxDoseAccessor: public core::DoseAccessorInterface - { - public: - typedef boost::shared_ptr DRTDoseIODPtr; + /*! @class DicomHelaxDoseAccessor + @brief Load dose data from a directory containing dicom dose files, each file describes the helax dose in one slice. + */ + class DicomHelaxDoseAccessor: public core::DoseAccessorWithGeoInfoBase + { + public: + typedef boost::shared_ptr DRTDoseIODPtr; - private: - /*! vector of DRTDoseIOD shared pointers, each DRTDoseIOD pointer presents the dose in one slice*/ - std::vector _doseVector; + private: + /*! vector of DRTDoseIOD shared pointers, each DRTDoseIOD pointer presents the dose in one slice*/ + std::vector _doseVector; - /*! vector of dose data(absolute Gy dose/doseGridScaling)*/ - std::vector _doseData; + /*! vector of dose data(absolute Gy dose/doseGridScaling)*/ + std::vector _doseData; - double _doseGridScaling; + double _doseGridScaling; - IDType _doseUID; + IDType _doseUID; - DicomHelaxDoseAccessor(); + DicomHelaxDoseAccessor(); - protected: - /*! @brief Initialize dose data - @exception InvalidDoseException Thrown if any DRTDoseIOD pointer of _doseVector is invalid: one of column/row/numberOfFrames/doseGridScaling/pixelSpacing=0 - @exception DcmrtException Throw if dcmrt error - @exception boost/bad_lexical_cast Thrown if the imported header tags are not numerical. - */ - bool begin(); + protected: + /*! @brief Initialize dose data + @exception InvalidDoseException Thrown if any DRTDoseIOD pointer of _doseVector is invalid: one of column/row/numberOfFrames/doseGridScaling/pixelSpacing=0 + @exception DcmrtException Throw if dcmrt error + @exception boost/bad_lexical_cast Thrown if the imported header tags are not numerical. + */ + bool begin(); - /*! @brief get all required data from dicom information contained in _dose - @exception boost/bad_lexical_cast Thrown if the imported header tags are not numerical. - */ - bool assembleGeometricInfo(); + /*! @brief get all required data from dicom information contained in _dose + @exception boost/bad_lexical_cast Thrown if the imported header tags are not numerical. + */ + bool assembleGeometricInfo(); - public: + public: - ~DicomHelaxDoseAccessor(); + ~DicomHelaxDoseAccessor(); - /*! @brief Constructor. Initialisation with a vector of DRTDoseIOD pointers - @exception InvalidDoseException Thrown if any DRTDoseIOD pointer of _doseVector is invalid: one of column/row/numberOfFrames/doseGridScaling/pixelSpacing=0 - @exception DcmrtException Throw if dcmrt error - */ - DicomHelaxDoseAccessor(std::vector aDICOMRTDoseVector); + /*! @brief Constructor. Initialisation with a vector of DRTDoseIOD pointers + @exception InvalidDoseException Thrown if any DRTDoseIOD pointer of _doseVector is invalid: one of column/row/numberOfFrames/doseGridScaling/pixelSpacing=0 + @exception DcmrtException Throw if dcmrt error + */ + DicomHelaxDoseAccessor(std::vector aDICOMRTDoseVector); - DoseTypeGy getDoseAt(const VoxelGridID aID) const; + DoseTypeGy getDoseAt(const VoxelGridID aID) const; - DoseTypeGy getDoseAt(const VoxelGridIndex3D& aIndex) const; + DoseTypeGy getDoseAt(const VoxelGridIndex3D& aIndex) const; - const IDType getDoseUID() const - { - return _doseUID; - }; - }; - } - } + const IDType getDoseUID() const + { + return _doseUID; + }; + }; + } + } } #endif diff --git a/code/io/itk/rttbITKImageDoseAccessor.h b/code/io/itk/rttbITKImageDoseAccessor.h index 827795a..85c9255 100644 --- a/code/io/itk/rttbITKImageDoseAccessor.h +++ b/code/io/itk/rttbITKImageDoseAccessor.h @@ -1,97 +1,97 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __ITK_DOSE_ACCESSOR_H #define __ITK_DOSE_ACCESSOR_H #include #include -#include "rttbDoseAccessorInterface.h" +#include "rttbDoseAccessorWithGeoInfoBase.h" #include "rttbGeometricInfo.h" #include "rttbBaseType.h" #include "itkImage.h" namespace rttb { - namespace io - { - namespace itk - { - typedef ::itk::Image ITKDoseImageType; - typedef ::itk::ImageBase<3> ITKImageBaseType; - /*! @class ITKImageDoseAccessor - @brief This class gives access to dose information stored in an itk image - @details _doseGridScaling is always 1.0. Thus, it is assumed that the values in the itkImage are absolute. - */ - class ITKImageDoseAccessor: public core::DoseAccessorInterface - { - private: - /** @brief The dose as itkImage */ - ITKDoseImageType::ConstPointer _dose; - - IDType _doseUID; - - /** @brief The dosegridscaling - * @note is always 1.0 - */ - double _doseGridScaling; - - /*! @brief constructor - @exception InvalidDoseException if _dose is NULL - */ - ITKImageDoseAccessor(); - - /*! @brief get all required data from the itk image contained in _dose - @exception InvalidDoseException if PixelSpacing is 0 or size in any dimension is 0. - */ - bool assembleGeometricInfo(); - - - public: - ~ITKImageDoseAccessor(); - - /*! @brief Constructor. Initialization with a itk image containing the dose - @pre doseImage must be a valid instance (and not null) - @note the doseImage pixels are dose (i.e. _doseGridScaling=1.0 is assumed always) - */ - ITKImageDoseAccessor(ITKDoseImageType::ConstPointer doseImage); - - /*! @brief returns the dose for an id - */ - DoseTypeGy getDoseAt(const VoxelGridID aID) const; - - /*! @brief returns the dose for an index - */ - DoseTypeGy getDoseAt(const VoxelGridIndex3D& aIndex) const; - - const IDType getDoseUID() const - { - return _doseUID; - }; - - }; - } - } + namespace io + { + namespace itk + { + typedef ::itk::Image ITKDoseImageType; + typedef ::itk::ImageBase<3> ITKImageBaseType; + /*! @class ITKImageDoseAccessor + @brief This class gives access to dose information stored in an itk image + @details _doseGridScaling is always 1.0. Thus, it is assumed that the values in the itkImage are absolute. + */ + class ITKImageDoseAccessor: public core::DoseAccessorWithGeoInfoBase + { + private: + /** @brief The dose as itkImage */ + ITKDoseImageType::ConstPointer _dose; + + IDType _doseUID; + + /** @brief The dosegridscaling + * @note is always 1.0 + */ + double _doseGridScaling; + + /*! @brief constructor + @exception InvalidDoseException if _dose is NULL + */ + ITKImageDoseAccessor(); + + /*! @brief get all required data from the itk image contained in _dose + @exception InvalidDoseException if PixelSpacing is 0 or size in any dimension is 0. + */ + bool assembleGeometricInfo(); + + + public: + ~ITKImageDoseAccessor(); + + /*! @brief Constructor. Initialization with a itk image containing the dose + @pre doseImage must be a valid instance (and not null) + @note the doseImage pixels are dose (i.e. _doseGridScaling=1.0 is assumed always) + */ + ITKImageDoseAccessor(ITKDoseImageType::ConstPointer doseImage); + + /*! @brief returns the dose for an id + */ + DoseTypeGy getDoseAt(const VoxelGridID aID) const; + + /*! @brief returns the dose for an index + */ + DoseTypeGy getDoseAt(const VoxelGridIndex3D& aIndex) const; + + const IDType getDoseUID() const + { + return _doseUID; + }; + + }; + } + } } #endif diff --git a/code/io/virtuos/rttbVirtuosDoseAccessor.cpp b/code/io/virtuos/rttbVirtuosDoseAccessor.cpp index d302bc4..84fad28 100644 --- a/code/io/virtuos/rttbVirtuosDoseAccessor.cpp +++ b/code/io/virtuos/rttbVirtuosDoseAccessor.cpp @@ -1,230 +1,228 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "rttbVirtuosDoseAccessor.h" #include "rttbNullPointerException.h" #include "rttbInvalidDoseException.h" #include "rttbInvalidParameterException.h" #include "rttbIndexOutOfBoundsException.h" //VIRTUOS #include "pln1file.h" #include "plt_type.h" #include "rtp_type.h" namespace rttb { - namespace io - { - namespace virtuos - { - - VirtuosDoseAccessor::~VirtuosDoseAccessor() - { - if (_freeVirtuosData) - { - this->freeVirtuosData(); - } - } - - VirtuosDoseAccessor::VirtuosDoseAccessor(Cubeinfo* aPointerOnVirtuosCube, bool freeVirtuosData, - DoseTypeGy normalizationDose, DoseTypeGy prescribedDose): - _pPointerOnVirtuosCube(new Cubeinfo*), _freeVirtuosData(freeVirtuosData), _doseGridScaling(0), - _doseUID(""), _doseScalingFactor(0) - { - //initialize cube pointer - *_pPointerOnVirtuosCube = create_cubeinfo(0); - *_pPointerOnVirtuosCube = aPointerOnVirtuosCube; - - - _prescribedDose = prescribedDose; - _normalizationDose = normalizationDose; - - if (_prescribedDose == 0) - { - _prescribedDose = 1; - } - - if (_normalizationDose == 0) - { - _normalizationDose = 1; - } - - _doseScalingFactor = _prescribedDose / _normalizationDose; - std::cout << "Prescribed dose: " << _prescribedDose << std::endl; - std::cout << "Normalization dose: " << _normalizationDose << std::endl; - - //dose import - this->begin(); - - - } - - void VirtuosDoseAccessor::begin() - { - if (!_pPointerOnVirtuosCube) - { - throw core::NullPointerException(" *_pPointerOnVirtuosCube must not be NULL!"); - } - - assembleGeometricInfo(); - - //load data - if ((*_pPointerOnVirtuosCube)->data_type == 1) - { - this->importPixelData(); - } - else if ((*_pPointerOnVirtuosCube)->data_type == 2) - { - this->importPixelData(); - } - else - { - throw core::InvalidParameterException(" cube has wrong data type!"); - } - } - - template - void VirtuosDoseAccessor::importPixelData() - { - doseData.clear(); - - int dimX = (*_pPointerOnVirtuosCube)->dimx; - int dimY = (*_pPointerOnVirtuosCube)->dimy; - int dimZ = (*_pPointerOnVirtuosCube)->dimz; - - GridVolumeType pixelSpacing = (*_pPointerOnVirtuosCube)->pixdist; - GridVolumeType sliceThickness = (*_pPointerOnVirtuosCube)->slicedist; - - TPixelType** * access_pointer = (TPixelType***)(*_pPointerOnVirtuosCube)->cube_direct_access; - - for (int k = 0; k < dimZ; k++) - { - for (int j = 0; j < dimY; j++) - { - for (int i = 0; i < dimX; i++) - { - TPixelType voxel_value = access_pointer[k][j][i]; - doseData.push_back(voxel_value * _doseScalingFactor); - } - - }//end for j - }//end for k - } - - void VirtuosDoseAccessor::assembleGeometricInfo() - { - if (!_pPointerOnVirtuosCube) - { - throw core::NullPointerException(" _pPointerOnVirtuosCube must not be NULL!"); - } - - _geoInfo.setNumColumns((*_pPointerOnVirtuosCube)->dimx); - - _geoInfo.setNumRows((*_pPointerOnVirtuosCube)->dimy); - - _geoInfo.setNumSlices((*_pPointerOnVirtuosCube)->dimz); - - if (_geoInfo.getNumColumns() == 0 || _geoInfo.getNumRows() == 0 || _geoInfo.getNumSlices() == 0) - { - throw core::InvalidDoseException("Empty Virtuos dose!") ; - } - - OrientationMatrix orientation; - _geoInfo.setOrientationMatrix(orientation); - - WorldCoordinate3D imagePositionPatient; - imagePositionPatient(0) = (*this->_pPointerOnVirtuosCube)->pixdist / 2; - imagePositionPatient(1) = (*this->_pPointerOnVirtuosCube)->pixdist / 2; - - if (!((*this->_pPointerOnVirtuosCube)->pos_list)) - { - throw core::InvalidDoseException("Empty Virtuos dose!") ; - } - - imagePositionPatient(2) = (*this->_pPointerOnVirtuosCube)->pos_list[0].position; - - _geoInfo.setImagePositionPatient(imagePositionPatient); - - SpacingVectorType3D spacingVector; - spacingVector(0) = (*_pPointerOnVirtuosCube)->pixdist; - spacingVector(1) = (*_pPointerOnVirtuosCube)->pixdist; - _geoInfo.setSpacing(spacingVector); - - if (_geoInfo.getPixelSpacingRow() == 0 || _geoInfo.getPixelSpacingColumn() == 0) - { - throw core::InvalidDoseException("Pixel spacing = 0!"); - } - - spacingVector(2) = (*_pPointerOnVirtuosCube)->slicedist; - - if (spacingVector(2) == 0) - { - std::cerr << "sliceThickness == 0! It will be replaced with pixelSpacingRow=" << - _geoInfo.getPixelSpacingRow() - << "!" << std::endl; - spacingVector(2) = spacingVector(0); - } - - _geoInfo.setSpacing(spacingVector); - } - - - DoseTypeGy VirtuosDoseAccessor::getDoseAt(const VoxelGridID aID) const - { - return doseData.at(aID); - } - - DoseTypeGy VirtuosDoseAccessor::getDoseAt(const VoxelGridIndex3D& aIndex) const - { - VoxelGridID aVoxelGridID; - - if (_geoInfo.convert(aIndex, aVoxelGridID)) - { - return getDoseAt(aVoxelGridID); - } - else - { - return -1; - } - } - - void VirtuosDoseAccessor::freeVirtuosData() - { - if (*(this->_pPointerOnVirtuosCube) != NULL) - { - closecube((*(this->_pPointerOnVirtuosCube))); - nc_free_cubeinfo((*(this->_pPointerOnVirtuosCube))); - delete this->_pPointerOnVirtuosCube; - - // initialize attributes again - //this->_pPointerOnVirtuosCube = new Cubeinfo*; - //*(this->_pPointerOnVirtuosCube) = create_cubeinfo(0); - } - - } - - } - } + namespace io + { + namespace virtuos + { + + VirtuosDoseAccessor::~VirtuosDoseAccessor() + { + if (_freeVirtuosData) + { + this->freeVirtuosData(); + } + } + + VirtuosDoseAccessor::VirtuosDoseAccessor(Cubeinfo* aPointerOnVirtuosCube, bool freeVirtuosData, + DoseTypeGy normalizationDose, DoseTypeGy prescribedDose): + _pPointerOnVirtuosCube(new Cubeinfo*), _freeVirtuosData(freeVirtuosData), _doseGridScaling(0), + _doseUID(""), _doseScalingFactor(0) + { + //initialize cube pointer + *_pPointerOnVirtuosCube = create_cubeinfo(0); + *_pPointerOnVirtuosCube = aPointerOnVirtuosCube; + + + _prescribedDose = prescribedDose; + _normalizationDose = normalizationDose; + + if (_prescribedDose == 0) + { + _prescribedDose = 1; + } + + if (_normalizationDose == 0) + { + _normalizationDose = 1; + } + + _doseScalingFactor = _prescribedDose / _normalizationDose; + std::cout << "Prescribed dose: " << _prescribedDose << std::endl; + std::cout << "Normalization dose: " << _normalizationDose << std::endl; + + //dose import + this->begin(); + } + + void VirtuosDoseAccessor::begin() + { + if (!_pPointerOnVirtuosCube) + { + throw core::NullPointerException(" *_pPointerOnVirtuosCube must not be NULL!"); + } + + assembleGeometricInfo(); + + //load data + if ((*_pPointerOnVirtuosCube)->data_type == 1) + { + this->importPixelData(); + } + else if ((*_pPointerOnVirtuosCube)->data_type == 2) + { + this->importPixelData(); + } + else + { + throw core::InvalidParameterException(" cube has wrong data type!"); + } + } + + template + void VirtuosDoseAccessor::importPixelData() + { + doseData.clear(); + + int dimX = (*_pPointerOnVirtuosCube)->dimx; + int dimY = (*_pPointerOnVirtuosCube)->dimy; + int dimZ = (*_pPointerOnVirtuosCube)->dimz; + + GridVolumeType pixelSpacing = (*_pPointerOnVirtuosCube)->pixdist; + GridVolumeType sliceThickness = (*_pPointerOnVirtuosCube)->slicedist; + + TPixelType** * access_pointer = (TPixelType***)(*_pPointerOnVirtuosCube)->cube_direct_access; + + for (int k = 0; k < dimZ; k++) + { + for (int j = 0; j < dimY; j++) + { + for (int i = 0; i < dimX; i++) + { + TPixelType voxel_value = access_pointer[k][j][i]; + doseData.push_back(voxel_value * _doseScalingFactor); + } + + }//end for j + }//end for k + } + + void VirtuosDoseAccessor::assembleGeometricInfo() + { + if (!_pPointerOnVirtuosCube) + { + throw core::NullPointerException(" _pPointerOnVirtuosCube must not be NULL!"); + } + + _geoInfo.setNumColumns((*_pPointerOnVirtuosCube)->dimx); + + _geoInfo.setNumRows((*_pPointerOnVirtuosCube)->dimy); + + _geoInfo.setNumSlices((*_pPointerOnVirtuosCube)->dimz); + + if (_geoInfo.getNumColumns() == 0 || _geoInfo.getNumRows() == 0 || _geoInfo.getNumSlices() == 0) + { + throw core::InvalidDoseException("Empty Virtuos dose!") ; + } + + OrientationMatrix orientation; + _geoInfo.setOrientationMatrix(orientation); + + WorldCoordinate3D imagePositionPatient; + imagePositionPatient(0) = (*this->_pPointerOnVirtuosCube)->pixdist / 2; + imagePositionPatient(1) = (*this->_pPointerOnVirtuosCube)->pixdist / 2; + + if (!((*this->_pPointerOnVirtuosCube)->pos_list)) + { + throw core::InvalidDoseException("Empty Virtuos dose!") ; + } + + imagePositionPatient(2) = (*this->_pPointerOnVirtuosCube)->pos_list[0].position; + + _geoInfo.setImagePositionPatient(imagePositionPatient); + + SpacingVectorType3D spacingVector; + spacingVector(0) = (*_pPointerOnVirtuosCube)->pixdist; + spacingVector(1) = (*_pPointerOnVirtuosCube)->pixdist; + _geoInfo.setSpacing(spacingVector); + + if (_geoInfo.getPixelSpacingRow() == 0 || _geoInfo.getPixelSpacingColumn() == 0) + { + throw core::InvalidDoseException("Pixel spacing = 0!"); + } + + spacingVector(2) = (*_pPointerOnVirtuosCube)->slicedist; + + if (spacingVector(2) == 0) + { + std::cerr << "sliceThickness == 0! It will be replaced with pixelSpacingRow=" << + _geoInfo.getPixelSpacingRow() + << "!" << std::endl; + spacingVector(2) = spacingVector(0); + } + + _geoInfo.setSpacing(spacingVector); + } + + + DoseTypeGy VirtuosDoseAccessor::getDoseAt(const VoxelGridID aID) const + { + return doseData.at(aID); + } + + DoseTypeGy VirtuosDoseAccessor::getDoseAt(const VoxelGridIndex3D& aIndex) const + { + VoxelGridID aVoxelGridID; + + if (_geoInfo.convert(aIndex, aVoxelGridID)) + { + return getDoseAt(aVoxelGridID); + } + else + { + return -1; + } + } + + void VirtuosDoseAccessor::freeVirtuosData() + { + if (*(this->_pPointerOnVirtuosCube) != NULL) + { + closecube((*(this->_pPointerOnVirtuosCube))); + nc_free_cubeinfo((*(this->_pPointerOnVirtuosCube))); + delete this->_pPointerOnVirtuosCube; + + // initialize attributes again + //this->_pPointerOnVirtuosCube = new Cubeinfo*; + //*(this->_pPointerOnVirtuosCube) = create_cubeinfo(0); + } + + } + + } + } } diff --git a/code/io/virtuos/rttbVirtuosDoseAccessor.h b/code/io/virtuos/rttbVirtuosDoseAccessor.h index bdcf93d..36530b2 100644 --- a/code/io/virtuos/rttbVirtuosDoseAccessor.h +++ b/code/io/virtuos/rttbVirtuosDoseAccessor.h @@ -1,129 +1,129 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __VIRTUOS_DOSE_ACCESSOR_H #define __VIRTUOS_DOSE_ACCESSOR_H #include #include #include -#include "rttbDoseAccessorInterface.h" +#include "rttbDoseAccessorWithGeoInfoBase.h" #include "rttbGeometricInfo.h" #include "rttbBaseType.h" #include "ncfile.h" namespace rttb { - namespace io - { - namespace virtuos - { + namespace io + { + namespace virtuos + { - /*! @class VirtuosDoseAccessor - @brief This class gives access to dose information from Virtuos Cubeinfo - */ - class VirtuosDoseAccessor: public core::DoseAccessorInterface - { - private: - Cubeinfo** _pPointerOnVirtuosCube; + /*! @class VirtuosDoseAccessor + @brief This class gives access to dose information from Virtuos Cubeinfo + */ + class VirtuosDoseAccessor : public core::DoseAccessorWithGeoInfoBase + { + private: + Cubeinfo** _pPointerOnVirtuosCube; - /*! absolute Gy dose/doseGridScaling*/ - std::vector doseData; + /*! absolute Gy dose/doseGridScaling*/ + std::vector doseData; - double _doseGridScaling; + double _doseGridScaling; - IDType _doseUID; + IDType _doseUID; - DoseTypeGy _prescribedDose; - DoseTypeGy _normalizationDose; + DoseTypeGy _prescribedDose; + DoseTypeGy _normalizationDose; - DoseTypeGy _doseScalingFactor; + DoseTypeGy _doseScalingFactor; - bool _freeVirtuosData;//if virtuos cube info should be closed + bool _freeVirtuosData;//if virtuos cube info should be closed - /*! close virtuos data cube. - */ - void freeVirtuosData(); + /*! close virtuos data cube. + */ + void freeVirtuosData(); - /*! load actual pixel data from virtuos cube to doseData. TPixelType is usually int but may be float for - special virtuos cubes (data_type = 2). - @pre virtuos cube contains data (dimensions are at least 1) + /*! load actual pixel data from virtuos cube to doseData. TPixelType is usually int but may be float for + special virtuos cubes (data_type = 2). + @pre virtuos cube contains data (dimensions are at least 1) - */ - template - void importPixelData(); + */ + template + void importPixelData(); - protected: - /*! @brief import dose data and relevant geometric information - @throw NullPointerException Thrown if _pPointerOnVirtuosCube is NULL - @throw InvalidDoseException Thrown if one dimension of the virtuos cube is zero - @throw InvalidParameterException Thrown if _pPointerOnVirtuosCube is invalid - */ - void begin(); + protected: + /*! @brief import dose data and relevant geometric information + @throw NullPointerException Thrown if _pPointerOnVirtuosCube is NULL + @throw InvalidDoseException Thrown if one dimension of the virtuos cube is zero + @throw InvalidParameterException Thrown if _pPointerOnVirtuosCube is invalid + */ + void begin(); - /*! @brief get all required geometrical data from virtuos cube - */ - void assembleGeometricInfo(); + /*! @brief get all required geometrical data from virtuos cube + */ + void assembleGeometricInfo(); - public: - ~VirtuosDoseAccessor(); + public: + ~VirtuosDoseAccessor(); - /*! @brief Constructor. Initialisation with a Cubeinfo pointer. - @param normalizationDose is defined as (prescribedDose*1000)/maxDoseInGy. Default is 1 Gy. - @param prescribedDose the does that was planned in the reference point in Gy. Default is 1 Gy. - @param freeVirtuoData If virtuos cube info should be closed, freeVirtuosData should be true. - @throw NullPointerException Thrown if _pPointerOnVirtuosCube is NULL - @throw InvalidDoseException Thrown if one dimension of the virtuos cube is zero - @throw InvalidParameterException Thrown if aPointerOnVirtuosCube is invalid - */ - VirtuosDoseAccessor(Cubeinfo* aPointerOnVirtuosCube, bool freeVirtuosData, - DoseTypeGy normalizationDose = 1, DoseTypeGy prescribedDose = 1); + /*! @brief Constructor. Initialisation with a Cubeinfo pointer. + @param normalizationDose is defined as (prescribedDose*1000)/maxDoseInGy. Default is 1 Gy. + @param prescribedDose the does that was planned in the reference point in Gy. Default is 1 Gy. + @param freeVirtuoData If virtuos cube info should be closed, freeVirtuosData should be true. + @throw NullPointerException Thrown if _pPointerOnVirtuosCube is NULL + @throw InvalidDoseException Thrown if one dimension of the virtuos cube is zero + @throw InvalidParameterException Thrown if aPointerOnVirtuosCube is invalid + */ + VirtuosDoseAccessor(Cubeinfo* aPointerOnVirtuosCube, bool freeVirtuosData, + DoseTypeGy normalizationDose = 1, DoseTypeGy prescribedDose = 1); - DoseTypeGy getDoseAt(const VoxelGridID aID) const; + DoseTypeGy getDoseAt(const VoxelGridID aID) const; - /*! @return dose value at given grid position. If position is invalid return -1 - */ - DoseTypeGy getDoseAt(const VoxelGridIndex3D& aIndex) const; + /*! @return dose value at given grid position. If position is invalid return -1 + */ + DoseTypeGy getDoseAt(const VoxelGridIndex3D& aIndex) const; - const IDType getDoseUID() const - { - return _doseUID; - }; + const IDType getDoseUID() const + { + return _doseUID; + }; - const DoseTypeGy getPrescribedDose() const - { - return _prescribedDose; - }; + const DoseTypeGy getPrescribedDose() const + { + return _prescribedDose; + }; - const DoseTypeGy getNormalizationDose() const - { - return _normalizationDose; - }; - }; - } - } + const DoseTypeGy getNormalizationDose() const + { + return _normalizationDose; + }; + }; + } + } } #endif diff --git a/code/masks/boost/rttbBoostMaskAccessor.cpp b/code/masks/boost/rttbBoostMaskAccessor.cpp index f8cd931..764d645 100644 --- a/code/masks/boost/rttbBoostMaskAccessor.cpp +++ b/code/masks/boost/rttbBoostMaskAccessor.cpp @@ -1,162 +1,162 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision: 484 $ (last changed revision) // @date $Date: 2014-03-26 16:16:16 +0100 (Mi, 26 Mrz 2014) $ (last change date) // @author $Author: zhangl $ (last changed by) */ #include "rttbBoostMaskAccessor.h" #include "rttbBoostMask.h" #include #include #include #include namespace rttb { namespace masks { namespace boost { - BoostMaskAccessor::BoostMaskAccessor(StructTypePointer aStructurePointer, GeometricInfoPointer aGeometricInfoPtr) - : _spStructure(aStructurePointer), _spGeoInfo(aGeometricInfoPtr) + BoostMaskAccessor::BoostMaskAccessor(StructTypePointer aStructurePointer, const core::GeometricInfo& aGeometricInfo) + : _spStructure(aStructurePointer), _geoInfo(aGeometricInfo) { _spRelevantVoxelVector = MaskVoxelListPointer(); //generate new structure set uid ::boost::uuids::uuid id; ::boost::uuids::random_generator generator; id = generator(); std::stringstream ss; ss << id; _maskUID = "BoostMask_" + ss.str(); } BoostMaskAccessor::~BoostMaskAccessor() { }; void BoostMaskAccessor::updateMask() { MaskVoxelList newRelevantVoxelVector; if (_spRelevantVoxelVector) { return; // already calculated } - BoostMask mask(_spGeoInfo , _spStructure); + BoostMask mask(::boost::make_shared(_geoInfo), _spStructure); _spRelevantVoxelVector = mask.getRelevantVoxelVector(); return; } BoostMaskAccessor::MaskVoxelListPointer BoostMaskAccessor::getRelevantVoxelVector() { // if not already generated start voxelization here updateMask(); return _spRelevantVoxelVector; } BoostMaskAccessor::MaskVoxelListPointer BoostMaskAccessor::getRelevantVoxelVector(float lowerThreshold) { MaskVoxelListPointer filteredVoxelVectorPointer(new MaskVoxelList); updateMask(); // filter relevant voxels BoostMaskAccessor::MaskVoxelList::iterator it = _spRelevantVoxelVector->begin(); while (it != _spRelevantVoxelVector->end()) { if ((*it).getRelevantVolumeFraction() > lowerThreshold) { filteredVoxelVectorPointer->push_back(*it); } ++it; } // if mask calculation was not successful this is empty! return filteredVoxelVectorPointer; } bool BoostMaskAccessor::getMaskAt(VoxelGridID aID, core::MaskVoxel& voxel) const { //initialize return voxel voxel.setRelevantVolumeFraction(0); //check if ID is valid - if (!_spGeoInfo->validID(aID)) + if (!_geoInfo.validID(aID)) { return false; } //determine how a given voxel on the dose grid is masked if (_spRelevantVoxelVector) { BoostMaskAccessor::MaskVoxelList::iterator it = _spRelevantVoxelVector->begin(); while (it != _spRelevantVoxelVector->end()) { if ((*it).getVoxelGridID() == aID) { voxel = (*it); return true; } ++it; } } // returns false if mask was not calculated without triggering calculation (otherwise not const!) else { return false; } return false; } bool BoostMaskAccessor::getMaskAt(const VoxelGridIndex3D& aIndex, core::MaskVoxel& voxel) const { //convert VoxelGridIndex3D to VoxelGridID VoxelGridID aVoxelGridID; - if (_spGeoInfo->convert(aIndex, aVoxelGridID)) + if (_geoInfo.convert(aIndex, aVoxelGridID)) { return getMaskAt(aVoxelGridID, voxel); } else { return false; } } const core::GeometricInfo& BoostMaskAccessor::getGeometricInfo() const { - return *_spGeoInfo; + return _geoInfo; }; } } } \ No newline at end of file diff --git a/code/masks/boost/rttbBoostMaskAccessor.h b/code/masks/boost/rttbBoostMaskAccessor.h index 777dab2..f33d0dc 100644 --- a/code/masks/boost/rttbBoostMaskAccessor.h +++ b/code/masks/boost/rttbBoostMaskAccessor.h @@ -1,119 +1,118 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision: 484 $ (last changed revision) // @date $Date: 2014-03-26 16:16:16 +0100 (Mi, 26 Mrz 2014) $ (last change date) // @author $Author: zhangl $ (last changed by) */ #ifndef __BOOST_MASK_ACCESSOR__H #define __BOOST_MASK_ACCESSOR__H #include "rttbBaseType.h" #include "rttbGeometricInfo.h" #include "rttbMaskVoxel.h" #include "rttbMaskAccessorInterface.h" #include "rttbGenericDoseIterator.h" #include "rttbStructure.h" #include namespace rttb { namespace masks { namespace boost { /*! @class BoostMaskAccessor - * @brief Implementation of the voxelization using boost + * @brief Implementation of the voxelization using boost */ class BoostMaskAccessor: public core::MaskAccessorInterface { public: typedef core::MaskAccessorInterface::MaskVoxelList MaskVoxelList; typedef core::MaskAccessorInterface::MaskVoxelListPointer MaskVoxelListPointer; typedef core::Structure::StructTypePointer StructTypePointer; - typedef ::boost::shared_ptr GeometricInfoPointer; private: - GeometricInfoPointer _spGeoInfo; + core::GeometricInfo _geoInfo; /*! vector containing list of mask voxels*/ MaskVoxelListPointer _spRelevantVoxelVector; StructTypePointer _spStructure; IDType _maskUID; public: /*! @brief constructor with a structure pointer and a geometric info pointer * @param aStructurePointer smart pointer of the structure * @param aGeometricInfoPtr smart pointer of the geometricinfo of the dose */ - BoostMaskAccessor(StructTypePointer aStructurePointer, GeometricInfoPointer aGeometricInfoPtr); + BoostMaskAccessor(StructTypePointer aStructurePointer, const core::GeometricInfo& aGeometricInfo); /*! @brief destructor*/ ~BoostMaskAccessor(); /*! @brief voxelization of the given structures using boost algorithms*/ void updateMask(); /*! @brief get vector containing all relevant voxels that are inside the given structure*/ MaskVoxelListPointer getRelevantVoxelVector(); /*! @brief get vector containing all relevant voxels that have a relevant volume above the given threshold and are inside the given structure*/ MaskVoxelListPointer getRelevantVoxelVector(float lowerThreshold); /*!@brief determine how a given voxel on the dose grid is masked * @param aID ID of the voxel in grid. * @param voxel Reference to the voxel. * @post after a valid call voxel containes the information of the specified grid voxel. If aID is not valid, voxel values are undefined. * The relevant volume fraction will be set to zero. * @return Indicates of the voxel exists and therefore if parameter voxel containes valid values.*/ bool getMaskAt(const VoxelGridID aID, core::MaskVoxel& voxel) const; /*!@brief determine how a given voxel on the dose grid is masked * @param aIndex 3d index of the voxel in grid. * @param voxel Reference to the voxel. * @return Indicates of the voxel exists and therefore if parameter voxel containes valid values.*/ bool getMaskAt(const VoxelGridIndex3D& aIndex, core::MaskVoxel& voxel) const; /*! @brief give access to GeometricInfo*/ const core::GeometricInfo& getGeometricInfo() const; - /* @ brief is true if dose is on a homogeneous grid + /* @ brief is true if dose is on a homogeneous grid * @remark Inhomogeneous grids are not supported at the moment, but if they will be supported in the future the interface does not need to change.*/ bool isGridHomogeneous() const { return true; }; IDType getMaskUID() const { return _maskUID; }; }; } } } #endif diff --git a/code/masks/files.cmake b/code/masks/files.cmake index 0cc43df..370758b 100644 --- a/code/masks/files.cmake +++ b/code/masks/files.cmake @@ -1,7 +1,9 @@ SET(CPP_FILES rttbGenericMutableMaskAccessor.cpp + rttbVOIindexIdentifier.cpp ) SET(H_FILES rttbGenericMutableMaskAccessor.h + rttbVOIindexIdentifier.h ) diff --git a/code/masks/rttbGenericMutableMaskAccessor.h b/code/masks/rttbGenericMutableMaskAccessor.h index 71153a1..038e555 100644 --- a/code/masks/rttbGenericMutableMaskAccessor.h +++ b/code/masks/rttbGenericMutableMaskAccessor.h @@ -1,108 +1,108 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __GENERIC_MUTABLE_MASK_ACCESSOR_H #define __GENERIC_MUTABLE_MASK_ACCESSOR_H #include "rttbMutableMaskAccessorInterface.h" #include "rttbBaseType.h" #include "rttbMaskVoxel.h" namespace rttb { - namespace masks - { + namespace masks + { - /*! @class GenericMutableMaskAccessor - @brief Default implementation of MutableMaskAccessorInterface. - @see MutableMaskAccessorInterface - */ - class GenericMutableMaskAccessor: public core::MutableMaskAccessorInterface - { - public: - typedef core::MutableMaskAccessorInterface::MaskVoxelList MaskVoxelList; - typedef core::MutableMaskAccessorInterface::MaskVoxelListPointer MaskVoxelListPointer; + /*! @class GenericMutableMaskAccessor + @brief Default implementation of MutableMaskAccessorInterface. + @see MutableMaskAccessorInterface + */ + class GenericMutableMaskAccessor: public core::MutableMaskAccessorInterface + { + public: + typedef core::MutableMaskAccessorInterface::MaskVoxelList MaskVoxelList; + typedef core::MutableMaskAccessorInterface::MaskVoxelListPointer MaskVoxelListPointer; - private: - core::GeometricInfo _geoInfo; + private: + core::GeometricInfo _geoInfo; - /*! vector containing list of mask voxels*/ - MaskVoxelListPointer _spRelevantVoxelVector; + /*! vector containing list of mask voxels*/ + MaskVoxelListPointer _spRelevantVoxelVector; - IDType _maskUID; + IDType _maskUID; - GenericMutableMaskAccessor(const - GenericMutableMaskAccessor&); //not implemented on purpose -> non-copyable - GenericMutableMaskAccessor& operator=(const - GenericMutableMaskAccessor&);//not implemented on purpose -> non-copyable + GenericMutableMaskAccessor(const + GenericMutableMaskAccessor&); //not implemented on purpose -> non-copyable + GenericMutableMaskAccessor& operator=(const + GenericMutableMaskAccessor&);//not implemented on purpose -> non-copyable - public: - ~GenericMutableMaskAccessor(); + public: + ~GenericMutableMaskAccessor(); - GenericMutableMaskAccessor(const core::GeometricInfo& aGeometricInfo); + GenericMutableMaskAccessor(const core::GeometricInfo& aGeometricInfo); - /*! @brief initialize mask structure if _spRelevantVoxelVector was not previously initialized*/ - void updateMask(); + /*! @brief initialize mask structure if _spRelevantVoxelVector was not previously initialized*/ + void updateMask(); - /*! @brief get vector containing all relevant voxels that are inside the given structure*/ - MaskVoxelListPointer getRelevantVoxelVector(); - /*! @brief get vector containing all relevant voxels that have a relevant volume above the given threshold and are inside the given structure*/ - MaskVoxelListPointer getRelevantVoxelVector(float lowerThreshold); + /*! @brief get vector containing all relevant voxels that are inside the given structure*/ + MaskVoxelListPointer getRelevantVoxelVector(); + /*! @brief get vector containing all relevant voxels that have a relevant volume above the given threshold and are inside the given structure*/ + MaskVoxelListPointer getRelevantVoxelVector(float lowerThreshold); - /*!@brief determine how a given voxel on the dose grid is masked - * @param aID ID of the voxel in grid. - * @param voxel Reference to the voxel. - * @post after a valid call voxel contains the information of the specified grid voxel. If aID is not valid, voxel values are undefined. - * The relevant volume fraction will be set to zero. - * @return Indicates if the voxel exists and therefore if parameter voxel contains valid values.*/ - bool getMaskAt(const VoxelGridID aID, core::MaskVoxel& voxel) const; + /*!@brief determine how a given voxel on the dose grid is masked + * @param aID ID of the voxel in grid. + * @param voxel Reference to the voxel. + * @post after a valid call voxel contains the information of the specified grid voxel. If aID is not valid, voxel values are undefined. + * The relevant volume fraction will be set to zero. + * @return Indicates if the voxel exists and therefore if parameter voxel contains valid values.*/ + bool getMaskAt(const VoxelGridID aID, core::MaskVoxel& voxel) const; - bool getMaskAt(const VoxelGridIndex3D& aIndex, core::MaskVoxel& voxel) const; + bool getMaskAt(const VoxelGridIndex3D& aIndex, core::MaskVoxel& voxel) const; - /* @ brief is true if dose is on a homogeneous grid */ - // Inhomogeneous grids are not supported at the moment, but if they will - // be supported in the future the interface does not need to change. - bool isGridHomogeneous() const - { - return true; - }; + /* @ brief is true if dose is on a homogeneous grid */ + // Inhomogeneous grids are not supported at the moment, but if they will + // be supported in the future the interface does not need to change. + bool isGridHomogeneous() const + { + return true; + }; - /*! @brief give access to GeometricInfo*/ - inline const core::GeometricInfo& getGeometricInfo() const - { - return _geoInfo; - }; + /*! @brief give access to GeometricInfo*/ + inline const core::GeometricInfo& getGeometricInfo() const + { + return _geoInfo; + }; - IDType getMaskUID() const - { - return _maskUID; - }; + IDType getMaskUID() const + { + return _maskUID; + }; - void setMaskAt(VoxelGridID aID, const core::MaskVoxel& voxel); + void setMaskAt(VoxelGridID aID, const core::MaskVoxel& voxel); - void setMaskAt(const VoxelGridIndex3D& gridIndex, const core::MaskVoxel& voxel); + void setMaskAt(const VoxelGridIndex3D& gridIndex, const core::MaskVoxel& voxel); - void setRelevantVoxelVector(MaskVoxelListPointer aVoxelListPointer); + void setRelevantVoxelVector(MaskVoxelListPointer aVoxelListPointer); - }; - } + }; + } } #endif \ No newline at end of file diff --git a/code/masks/rttbVOIindexIdentifier.cpp b/code/masks/rttbVOIindexIdentifier.cpp new file mode 100644 index 0000000..cb98659 --- /dev/null +++ b/code/masks/rttbVOIindexIdentifier.cpp @@ -0,0 +1,147 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notices for more information. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision: +// @date $Date: +// @author $Author: +*/ + + +#include "rttbVOIindexIdentifier.h" +#include "rttbStructureSet.h" +#include "rttbStructure.h" +#include "rttbExceptionMacros.h" +#include +#include + + + +namespace rttb +{ + namespace masks + { + + const unsigned int VOIindexIdentifier::getIndexByVoiName(StructSetTypePointer spStructSet, + const std::string& name) + { + + if (!spStructSet) + { + std::ostringstream message; + message << "Exception: "<< "invalid method call spStructSet invalid"; + ::rttb::core::Exception e_(message.str().c_str()); + throw e_; + } + + + VoiLabelList voiLabelList; + + for (int i = 0; i < spStructSet->getNumberOfStructures(); i++) + { + voiLabelList.push_back(spStructSet->getStructure(i)->getLabel()); + } + + + + int returnValue = -1; + + if (voiLabelList.empty()) + { + std::ostringstream message; + message << "Exception: "<< "invalid method call, object state invalid, voiLabelList empty"; + ::rttb::core::Exception e_(message.str().c_str()); + throw e_; + } + + + ::boost::regex optionalNamesREG("([^\|]*)([\|\|][^\|]*)+"); + ::boost::smatch what; + + typedef std::vector< std::string > OptionalVectorType; + OptionalVectorType optionalVois; + ::boost::split(optionalVois, name, ::boost::is_any_of("||")); + + for (OptionalVectorType::iterator i = optionalVois.begin(); i != optionalVois.end(); i++) + { + int counter = 0; + + /* + Searches for valid entries in the voi list. + Takes the first matching entry! + */ + for (VoiLabelList::const_iterator iter = voiLabelList.begin(); + iter != voiLabelList.end(); iter++) + { + if ((*iter).compare(*i) == 0) + { + returnValue = counter; + } + + counter++; + } + + } + + if (returnValue == -1) + { + std::ostringstream message; + message << "Exception: "<< "specified voi name not found!"; + ::rttb::core::Exception e_(message.str().c_str()); + throw e_; + } + + return returnValue; + } + + const std::string VOIindexIdentifier::getVoiNameByIndex(StructSetTypePointer spStructSet, + const unsigned int& index) + { + if (!spStructSet) + { + std::ostringstream message; + message << "Exception: "<< "invalid method call spStructSet invalid"; + ::rttb::core::Exception e_(message.str().c_str()); + throw e_; + } + + VoiLabelList voiLabelList; + + for (int i = 0; i < spStructSet->getNumberOfStructures(); i++) + { + voiLabelList.push_back(spStructSet->getStructure(i)->getLabel()); + } + + if (voiLabelList.empty()) + { + std::ostringstream message; + message << "Exception: "<< "invalid method call, object state invalid, voiLabelList empty"; + ::rttb::core::Exception e_(message.str().c_str()); + throw e_; + } + + if (index >= voiLabelList.size()) + { + std::ostringstream message; + message << "Exception: "<< "invalid index, index out of range"; + ::rttb::core::Exception e_(message.str().c_str()); + throw e_; + } + + return voiLabelList[index]; + } + } +} + diff --git a/code/masks/rttbVOIindexIdentifier.h b/code/masks/rttbVOIindexIdentifier.h new file mode 100644 index 0000000..13875bf --- /dev/null +++ b/code/masks/rttbVOIindexIdentifier.h @@ -0,0 +1,86 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notices for more information. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision: +// @date $Date: +// @author $Author: +*/ + + + + +#ifndef __VOI_INDEX_IDENTIFIER_H +#define __VOI_INDEX_IDENTIFIER_H + +#include "rttbStructureSet.h" +#include "rttbStructure.h" +#include + + + + +namespace rttb +{ + namespace masks + { + class VOIindexIdentifier + { + + public: + typedef ::boost::shared_ptr Pointer; + typedef ::rttb::core::StructureSet StructSetType; + typedef ::boost::shared_ptr StructSetTypePointer; + typedef ::rttb::core::Structure StructType; + typedef StructType::StructTypePointer StructTypePointer; + typedef std::vector VoiLabelList; + + + public: + + VOIindexIdentifier(){} + virtual ~VOIindexIdentifier() {} + + + /*!@brief get the index of the corresponding VOI + * @pre name must contain a valid voi name + * @pre spStructSet must point to a valid structure set. + * @param spStructSet Pointer to the structur set that should be checked for the named VOI. + * @param name Name of the VOI + * @exception ::rttb::core::Exception on invalid spStructSet + ::rttb::core::Exception on invalid spStructSet + * @return the index */ + static const unsigned int getIndexByVoiName(StructSetTypePointer spStructSet, + const std::string& name); + + + /*!@brief get the VOI of the corresponding index + * @pre index must specify a valid index value + * @pre spStructSet must point to a valid structure set. + * @param spStructSet Pointer to the structur set that should be checked for the named VOI. + * @param name Index of the VOI + * @exception ::rttb::core::Exception on invalid spStructSet + ::rttb::core::Exception on invalid spStructSet + * @return voi name */ + static const std::string getVoiNameByIndex(StructSetTypePointer spStructSet, + const unsigned int& index); + + + }; + + } +} + +#endif __VOI_INDEX_IDENTIFIER_H diff --git a/code/models/files.cmake b/code/models/files.cmake index a6ac489..7174a52 100644 --- a/code/models/files.cmake +++ b/code/models/files.cmake @@ -1,25 +1,30 @@ SET(CPP_FILES rttbBioModel.cpp rttbBioModelCurve.cpp rttbBioModelScatterPlots.cpp rttbNTCPLKBModel.cpp rttbNTCPRSModel.cpp rttbTCPModel.cpp rttbTCPLQModel.cpp + rttbDoseBasedModels.cpp rttbDvhBasedModels.cpp rttbIntegration.cpp + rttbLQModelAccessor.cpp ) SET(H_FILES rttbBaseTypeModels.h rttbBioModel.h rttbBioModelCurve.h rttbBioModelScatterPlots.h rttbNTCPModel.h rttbNTCPLKBModel.h rttbNTCPRSModel.h rttbTCPModel.h rttbTCPLQModel.h + rttbDoseBasedModels.cpp rttbDvhBasedModels.h rttbIntegration.h + rttbBioModelAccessorInterface.h + rttbLQModelAccessor.h ) diff --git a/code/core/rttbDoseAccessorInterface.h b/code/models/rttbBioModelAccessorInterface.h similarity index 53% copy from code/core/rttbDoseAccessorInterface.h copy to code/models/rttbBioModelAccessorInterface.h index e5f8e24..d81bb97 100644 --- a/code/core/rttbDoseAccessorInterface.h +++ b/code/models/rttbBioModelAccessorInterface.h @@ -1,81 +1,82 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) +// @version $Revision: 747 $ (last changed revision) +// @date $Date: 2014-09-17 12:01:00 +0200 (Mi, 17 Sep 2014) $ (last change date) +// @author $Author: hentsch $ (last changed by) */ -#ifndef __DOSE_ACCESSOR_INTERFACE_NEW_H -#define __DOSE_ACCESSOR_INTERFACE_NEW_H +#ifndef __BIO_MODEL_ACCESSOR_INTERFACE_H +#define __BIO_MODEL_ACCESSOR_INTERFACE_H -#include +#include #include "rttbBaseType.h" +#include "rttbBaseTypeModels.h" #include "rttbGeometricInfo.h" #include "rttbIndexConversionInterface.h" namespace rttb { namespace core { - /*! @class IndexConversionInterface - @brief This class represents the conversion of 3D grid indices to 1D grid IDs. + /*! @class BioModelAccessorInterface + @brief Interface for all BioModelAccessor classes */ - class DoseAccessorInterface: public IndexConversionInterface + class BioModelAccessorInterface: public IndexConversionInterface { public: - typedef boost::shared_ptr DoseAccessorPointer; + typedef boost::shared_ptr BioModelAccessorPointer; private: - DoseAccessorInterface(const DoseAccessorInterface&); //not implemented on purpose -> non-copyable - DoseAccessorInterface& operator=(const - DoseAccessorInterface&);//not implemented on purpose -> non-copyable + BioModelAccessorInterface(const BioModelAccessorInterface&); //not implemented on purpose -> non-copyable + BioModelAccessorInterface& operator=(const + BioModelAccessorInterface&);//not implemented on purpose -> non-copyable public: - DoseAccessorInterface() {}; - virtual ~DoseAccessorInterface() {}; + BioModelAccessorInterface() {}; + virtual ~BioModelAccessorInterface() {}; inline const core::GeometricInfo& getGeometricInfo() const { return _geoInfo; }; inline GridSizeType getGridSize() const { return _geoInfo.getNumberOfVoxels(); }; - virtual DoseTypeGy getDoseAt(const VoxelGridID aID) const = 0; + virtual models::BioModelValueType getBioModelValueAt(const VoxelGridID aID) const = 0; - virtual DoseTypeGy getDoseAt(const VoxelGridIndex3D& aIndex) const = 0; + virtual models::BioModelValueType getBioModelValueAt(const VoxelGridIndex3D& aIndex) const = 0; /*! @brief is true if dose is on a homogeneous grid @remarks Inhomogeneous grids are not supported at the moment, but if they will be supported in the future the interface does not need to change. */ virtual bool isGridHomogeneous() const { return true; } - virtual const IDType getDoseUID() const = 0; + virtual const IDType getBioModelUID() const = 0; protected: core::GeometricInfo _geoInfo; }; } } #endif diff --git a/code/models/rttbDoseBasedModels.cpp b/code/models/rttbDoseBasedModels.cpp new file mode 100644 index 0000000..90147ce --- /dev/null +++ b/code/models/rttbDoseBasedModels.cpp @@ -0,0 +1,41 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notices for more information. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision $ (last changed revision) +// @date $Date $ (last change date) +// @author $Author $ (last changed by) +*/ +#include "rttbDoseBasedModels.h" +#include "rttbInvalidParameterException.h" + +#include + +namespace rttb +{ + namespace models + { + rttb::models::BioModelValueType calcLQ(const DoseTypeGy dose, const DoseCalcType alpha, const DoseCalcType beta) + { + if (dose < 0 || alpha < 0 || beta < 0) + { + throw core::InvalidParameterException("Parameter invalid: dose, alpha, beta must be >=0!"); + } + + return exp(-((alpha * dose) + (beta * dose * dose))); + } + + } +} \ No newline at end of file diff --git a/code/models/rttbDoseBasedModels.h b/code/models/rttbDoseBasedModels.h new file mode 100644 index 0000000..ff8b6ce --- /dev/null +++ b/code/models/rttbDoseBasedModels.h @@ -0,0 +1,43 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notices for more information. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision: 798 $ (last changed revision) +// @date $Date: 2014-10-10 15:27:43 +0200 (Fr, 10 Okt 2014) $ (last change date) +// @author $Author: zhangl $ (last changed by) +*/ +#include "rttbBaseType.h" +#include "rttbBaseTypeModels.h" + + +namespace rttb +{ + namespace models + { + /*! @brief Calculate biological LinearQuadratic Model of a dose + @details LQ = exp(-(alpha*d+beta*d^2)) + @param dose + @param alpha + @param beta + @pre dose>=0 + @pre alpha>=0 + @pre beta>=0 + @return The LQ value + @exception InvalidParameterException Thrown if parameters were not set correctly. + */ + BioModelValueType calcLQ(const DoseTypeGy dose, const DoseCalcType alpha, + const DoseCalcType beta); + } +} \ No newline at end of file diff --git a/code/models/rttbDvhBasedModels.h b/code/models/rttbDvhBasedModels.h index c10b073..d7c9d17 100644 --- a/code/models/rttbDvhBasedModels.h +++ b/code/models/rttbDvhBasedModels.h @@ -1,50 +1,49 @@ #include #include "rttbDVH.h" #include "rttbBaseType.h" namespace rttb{ namespace models{ typedef core::DVH::DataDifferentialType DataDifferentialType; typedef core::DVH::DVHPointer DVHPointer; typedef std::map BEDDVHType; typedef std::map LQEDDVHType; - typedef double BioModelParameterType; /*! @brief Get Equivalent Uniform Dose (EUD) @pre dvh data differential is not empty, @pre aA is not zero, @return Return calculated EUD value, @exception InvalidParameterException Thrown if parameters were not set correctly. */ DoseStatisticType getEUD(const DVHPointer dvh, const DoseCalcType aA); /*! @brief Calculate Biological Effective/Equivalent Dose (BED) of dvh @param relativeVolume default false-> the corresponding volume value is the voxel number of the dose bin; if true-> the corresponding volume value is the relative volume % between 0 and 1, (the voxel number of this dose bin)/(number of voxels) @pre dvh should be an accumulated dvh of all fractions, not a single fraction dvh @pre dvh data differential is not empty @pre alpha_beta > 0 @pre numberOfFractions > 1 @return Return map: keys are BEDi in Gy, values are the volume of the dose bin @exception InvalidParameterException Thrown if parameters were not set correctly. */ BEDDVHType calcBEDDVH(const DVHPointer dvh, const int numberOfFractions, const DoseCalcType alpha_beta, const bool relativeVolume=false); /*! @brief Calculate Linear-quadratic equivalent dose for 2-Gy (LQED2) of dvh @param relativeVolume default false-> the corresponding volume value is the voxel number of the dose bin; if true-> the corresponding volume value is the relative volume % between 0 and 1, (the voxel number of this dose bin)/(number of voxels) @pre dvh should be an accumulated dvh of all fractions, not a single fraction dvh @pre dvh data differential is not empty @pre alpha_beta > 0 @pre numberOfFractions > 1 @return Return map: keys are LQED2 in Gy, values are the volume of the dose bin; return empty map if not initialized @exception InvalidParameterException Thrown if parameters were not set correctly. */ LQEDDVHType calcLQED2DVH(const DVHPointer dvh, const int numberOfFractions, const DoseCalcType alpha_beta, const bool relativeVolume=false); } } \ No newline at end of file diff --git a/code/models/rttbLQModelAccessor.cpp b/code/models/rttbLQModelAccessor.cpp new file mode 100644 index 0000000..7665d32 --- /dev/null +++ b/code/models/rttbLQModelAccessor.cpp @@ -0,0 +1,65 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notices for more information. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision: 793 $ (last changed revision) +// @date $Date: 2014-10-10 10:24:45 +0200 (Fr, 10 Okt 2014) $ (last change date) +// @author $Author: hentsch $ (last changed by) +*/ + +#include "rttbLQModelAccessor.h" +#include "rttbDoseBasedModels.h" +#include "rttbInvalidDoseException.h" + +namespace rttb +{ + namespace models + { + LQModelAccessor::~LQModelAccessor() + { + + } + + LQModelAccessor::LQModelAccessor(DoseAccessorPointer dose, BioModelParamType alpha, BioModelParamType beta) : + _dose(dose), _alpha(alpha), _beta(beta) + { + if (_dose == NULL) + { + throw core::InvalidDoseException("Dose is NULL"); + } + + assembleGeometricInfo(); + } + + BioModelValueType LQModelAccessor::getBioModelValueAt(const VoxelGridID aID) const + { + return calcLQ(_dose->getDoseAt(aID), _alpha, _beta); + } + + BioModelValueType LQModelAccessor::getBioModelValueAt(const VoxelGridIndex3D& aIndex) const + { + return calcLQ(_dose->getDoseAt(aIndex), _alpha, _beta); + } + + bool LQModelAccessor::assembleGeometricInfo() + { + _geoInfo = _dose->getGeometricInfo(); + + return true; + + } + } +} + diff --git a/code/models/rttbLQModelAccessor.h b/code/models/rttbLQModelAccessor.h new file mode 100644 index 0000000..f569d65 --- /dev/null +++ b/code/models/rttbLQModelAccessor.h @@ -0,0 +1,79 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notices for more information. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision: 793 $ (last changed revision) +// @date $Date: 2014-10-10 10:24:45 +0200 (Fr, 10 Okt 2014) $ (last change date) +// @author $Author: hentsch $ (last changed by) +*/ +#ifndef __LQ_MODEL_ACCESSOR_H +#define __LQ_MODEL_ACCESSOR_H + +#include "rttbBioModelAccessorInterface.h" +#include "rttbDoseAccessorInterface.h" +#include "rttbBaseTypeModels.h" + +namespace rttb +{ + namespace models + { + /*! @class LQModelAccessor + @brief This class gives access to the LQ Model information in an image + */ + class LQModelAccessor: public core::BioModelAccessorInterface + { + public: + typedef core::DoseAccessorInterface::DoseAccessorPointer DoseAccessorPointer; + private: + DoseAccessorPointer _dose; + BioModelParamType _alpha; + BioModelParamType _beta; + + IDType _bioModelUID; + + LQModelAccessor(); + + /*! @brief get all required data from the dose geometric info + */ + bool assembleGeometricInfo(); + + + public: + ~LQModelAccessor(); + + /*! @brief Constructor. + @pre dose must be a valid instance (and not null) + @exception InvalidDoseException if _dose is NULL + */ + LQModelAccessor(DoseAccessorPointer dose, BioModelParamType alpha, BioModelParamType beta); + + /*! @brief returns the LQ Model value for an id + */ + BioModelValueType getBioModelValueAt(const VoxelGridID aID) const; + + /*! @brief returns the LQ Model value for an index + */ + BioModelValueType getBioModelValueAt(const VoxelGridIndex3D& aIndex) const; + + const IDType getBioModelUID() const + { + return _bioModelUID; + }; + + }; + } +} + +#endif diff --git a/code/models/rttbTCPLQModel.cpp b/code/models/rttbTCPLQModel.cpp index 3c69723..71ba16e 100644 --- a/code/models/rttbTCPLQModel.cpp +++ b/code/models/rttbTCPLQModel.cpp @@ -1,273 +1,273 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #define _USE_MATH_DEFINES #include #include #include #include #include "rttbTCPLQModel.h" #include "rttbDvhBasedModels.h" #include "rttbBaseTypeModels.h" #include "rttbIntegration.h" #include "rttbInvalidParameterException.h" #include "rttbExceptionMacros.h" namespace rttb { namespace models { TCPLQModel::TCPLQModel(): TCPModel(), _alphaMean(0), _alphaVariance(0), _alpha_beta(0), _rho(0) {} TCPLQModel::TCPLQModel(DVHPointer aDVH, BioModelParamType aAlphaMean, BioModelParamType aBeta, BioModelParamType aRho, int aNumberOfFractions): TCPModel(aDVH, aNumberOfFractions), _alphaMean(aAlphaMean), _alphaVariance(0), _alpha_beta(aAlphaMean / aBeta), _rho(aRho) {} TCPLQModel::TCPLQModel(DVHPointer aDVH, BioModelParamType aRho, int aNumberOfFractions, BioModelParamType aAlpha_Beta, BioModelParamType aAlphaMean, BioModelParamType aAlphaVariance): TCPModel(aDVH, aNumberOfFractions), _alphaMean(aAlphaMean), _alphaVariance(aAlphaVariance), _alpha_beta(aAlpha_Beta), _rho(aRho) {} void TCPLQModel::setParameters(const BioModelParamType aAlphaMean, const BioModelParamType aAlpha_Beta, const BioModelParamType aRho, const BioModelParamType aAlphaVariance) { _alphaMean = aAlphaMean; _alphaVariance = aAlphaVariance; _alpha_beta = aAlpha_Beta; _rho = aRho; //reset _value, because parameters have changed. _value = 0; } void TCPLQModel::setAlpha(const BioModelParamType aAlphaMean, const BioModelParamType aAlphaVariance) { _alphaVariance = aAlphaVariance; _alphaMean = aAlphaMean; } void TCPLQModel::setAlphaBeta(const BioModelParamType aAlpha_Beta) { _alpha_beta = aAlpha_Beta; } void TCPLQModel::setRho(const BioModelParamType aRho) { _rho = aRho; } - const BioModelParamType TCPLQModel::getAlpahBeta() + const BioModelParamType TCPLQModel::getAlphaBeta() { return _alpha_beta; } const BioModelParamType TCPLQModel::getAlphaMean() { return _alphaMean; } const BioModelParamType TCPLQModel::getAlphaVariance() { return _alphaVariance; } const BioModelParamType TCPLQModel::getRho() { return _rho; } long double TCPLQModel::calcTCPi(BioModelParamType aRho, BioModelParamType aAlphaMean, double vj, double bedj) { return exp(-aRho * vj * exp(-aAlphaMean * bedj)); } long double TCPLQModel::calcTCP(std::map aBEDDVH, BioModelParamType aRho, BioModelParamType aAlphaMean, double aDeltaV) { std::map::iterator it; long double tcp = 1; for (it = aBEDDVH.begin(); it != aBEDDVH.end(); ++it) { long double tcpi = this->calcTCPi(aRho, aAlphaMean, (*it).second * aDeltaV, (*it).first); tcp = tcp * tcpi; } return tcp; } long double TCPLQModel::calcTCPAlphaNormalDistribution(std::map aBEDDVH, BioModelParamType aRho, BioModelParamType aAlphaMean, BioModelParamType aAlphaVariance, double aDeltaV) { std::map::iterator it; std::vector volumeV2; std::vector bedV2; int i = 0; for (it = aBEDDVH.begin(); it != aBEDDVH.end(); ++it) { volumeV2.push_back((*it).second * aDeltaV); bedV2.push_back((*it).first); i++; } struct TcpParams params = {aAlphaMean, aAlphaVariance, aRho, volumeV2, bedV2}; double result = integrateTCP(0, params); if (result == -100) { std::cerr << "Integration error!\n"; return -1; } else { long double tcp = 1 / (pow(2 * M_PI, 0.5) * _alphaVariance) * result; return tcp; } } BioModelValueType TCPLQModel::calcModel(const double doseFactor) { core::DVH variantDVH = core::DVH(_dvh->getDataDifferential(), (DoseTypeGy)(_dvh->getDeltaD() * doseFactor), _dvh->getDeltaV(), "temporary", "temporary"); boost::shared_ptr spDVH = boost::make_shared(variantDVH); BioModelValueType value = 0; if (_alphaVariance == 0) { - if (_alphaMean <= 0 && _alpha_beta <= 0 && _rho <= 0) + if (_alphaMean <= 0 || _alpha_beta <= 0 || _rho <= 0) { throw core::InvalidParameterException("Parameter invalid: alpha, alpha/beta, rho and number of fractions must >0!"); } if (_numberOfFractions <= 1) { throw core::InvalidParameterException("Parameter invalid: numberOfFractions must be >1! The dvh should be an accumulated-dvh of all fractions, not a single fraction-dvh!"); } std::map dataBED = calcBEDDVH(spDVH, _numberOfFractions, _alpha_beta); value = (BioModelValueType)this->calcTCP(dataBED, _rho, _alphaMean, variantDVH.getDeltaV()); return value; } //if alpha normal distribution else { - if (this->_alpha_beta <= 0 && this->_alphaMean <= 0 && this->_alphaVariance < 0 && _rho <= 0 && _numberOfFractions <= 0) + if (this->_alpha_beta <= 0 || this->_alphaMean <= 0 || this->_alphaVariance < 0 || _rho <= 0) { throw core::InvalidParameterException("Parameter invalid: alpha/beta, alphaMean, rho and number of fractions must >0!"); } if (_numberOfFractions <= 1) { throw core::InvalidParameterException("Parameter invalid: numberOfFractions must be >1! The dvh should be an accumulated-dvh of all fractions, not a single fraction-dvh!"); } std::map dataBED = calcBEDDVH(spDVH, _numberOfFractions, _alpha_beta); value = (BioModelValueType)(this->calcTCPAlphaNormalDistribution(dataBED, _rho, _alphaMean, _alphaVariance, variantDVH.getDeltaV())); return value; } } void TCPLQModel::setParameterVector(const ParamVectorType& aParameterVector) { if (aParameterVector.size() != 4) { throw core::InvalidParameterException("Parameter invalid: aParameterVector.size must be 4! "); } else { _alphaMean = aParameterVector.at(0); _alphaVariance = aParameterVector.at(1); _alpha_beta = aParameterVector.at(2); _rho = aParameterVector.at(3); } } void TCPLQModel::setParameterByID(const int aParamId, const BioModelParamType aValue) { if (aParamId == 0) { _alphaMean = aValue; } else if (aParamId == 1) { _alphaVariance = aValue; } else if (aParamId == 2) { _alpha_beta = aValue; } else if (aParamId == 3) { _rho = aValue; } else { throw core::InvalidParameterException("Parameter invalid: aParamID must be 0(alphaMean) or 1(alphaVariance) or 2(alpha_beta) or 3(rho)! "); } } const int TCPLQModel::getParameterID(const std::string& aParamName) const { if (aParamName == "alphaMean") { return 0; } else if (aParamName == "alphaVariance") { return 1; } else if (aParamName == "alpha_beta") { return 2; } else if (aParamName == "rho") { return 3; } else { rttbExceptionMacro(core::InvalidParameterException, << "Parameter name " << aParamName << " invalid: it should be alphaMean or alphaVariance or alpha_beta or rho!"); } } }//end namespace models }//end namespace rttb diff --git a/code/models/rttbTCPLQModel.h b/code/models/rttbTCPLQModel.h index 78a2abe..560b33e 100644 --- a/code/models/rttbTCPLQModel.h +++ b/code/models/rttbTCPLQModel.h @@ -1,163 +1,163 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __TCP_LQ_MODEL_H #define __TCP_LQ_MODEL_H #include #include #include #include "rttbBaseType.h" #include "rttbTCPModel.h" #include "rttbBaseTypeModels.h" namespace rttb { namespace models { /*! @class TCPLQModel @brief This class represents a TCP(Tumor Control Probability) LQ model (Nahum and Sanchez-Nieto 2001, Hall and Giaccia 2006) @see TCPModel */ class TCPLQModel: public TCPModel { public: typedef TCPModel::ParamVectorType ParamVectorType; typedef TCPModel::DVHPointer DVHPointer; private: /*! @brief Calculate intermediate tcp using alpha constant. This is a helper function for calcTCP() @see calcTCP */ long double calcTCPi(BioModelParamType aRho, BioModelParamType aAlphaMean, double vj, double bedj); /*! @brief Calculate tcp using alpha constant. */ long double calcTCP(std::map aBEDDVH, BioModelParamType aRho, BioModelParamType aAlphaMean, double aDeltaV); /*! @brief Calculate tcp using a normal distribution for alpha. */ long double calcTCPAlphaNormalDistribution(std::map aBEDDVH, BioModelParamType aRho, BioModelParamType aAlphaMean, BioModelParamType aAlphaVariance, double aDeltaV); protected: BioModelParamType _alphaMean; BioModelParamType _alphaVariance; BioModelParamType _alpha_beta; /*! Roh is the initial clonogenic cell density */ BioModelParamType _rho; /*! @brief Calculate the model value @param doseFactor scaling factor for prescribed dose. The model calculation will use the dvh with each di=old di*doseFactor. @pre _alphaMean >0 @pre _alphaVariance >= 0 @pre _alpha_beta > 0 @pre _rho > 0 @pre _numberOfFractions > 1 @exception InvalidParameterException Thrown if parameters were not set correctly. */ BioModelValueType calcModel(const double doseFactor = 1); public: TCPLQModel(); /*! @brief Constructor initializes member variables with given parameters. @pre aAlphaMean >0 @pre aBeta > 0 @pre aRho > 0 @pre aNumberOfFractions > 1 */ TCPLQModel(DVHPointer aDVH, BioModelParamType aAlphaMean, BioModelParamType aBeta, BioModelParamType aRho, int aNumberOfFractions); /*! @brief Constructor for alpha distribution initializes member variables with given parameters. @pre aAlphaMean >0 @pre aAlphaVariance >0 @pre aAlpha_Beta > 0 @pre aRho > 0 @pre aNumberOfFractions > 1 */ TCPLQModel(DVHPointer aDVH, BioModelParamType aRho, int aNumberOfFractions, BioModelParamType aAlpha_Beta, BioModelParamType aAlphaMean, BioModelParamType aAlphaVariance); const BioModelParamType getRho(); void setRho(const BioModelParamType aRho); const BioModelParamType getAlphaMean(); const BioModelParamType getAlphaVariance(); /*! @brief The distribution of the parameter alpha, which is characteristic for a population of cells, is described by the its mean and variance. If alpha is constant the variance is 0. @param aAlphaVariance The variance of alpha can be given, the default value is 0 resulting in constant alpha. */ void setAlpha(const BioModelParamType aAlphaMean, const BioModelParamType aAlphaVariance = 0); - const BioModelParamType getAlpahBeta(); + const BioModelParamType getAlphaBeta(); void setAlphaBeta(const BioModelParamType aAlpha_Beta); /*! @brief Set parameters for the TCP model. _value will be reset to 0. @param aAlpha_Beta alpha/beta constant . @param aAlphaMean mean of alpha distribution. @param aAlphaVariance variance of alpha distribution. */ void setParameters(const BioModelParamType aAlphaMean, const BioModelParamType aAlpha_Beta, const BioModelParamType aRho, const BioModelParamType aAlphaVariance = 0); /*! @brief Set parameter with ID. "alphaMean":0,"alphaVariance":1,"alpha_beta":2, "rho":3 @exception InvalidParameterException Thrown if aParamId is not 0 or 1 or 2 or 3. */ virtual void setParameterByID(const int aParamId, const BioModelParamType aValue); /*! @brief Set parameter vector, where index of vector is the parameter id. "alphaMean":0,"alphaVariance":1,"alpha_beta":2, "rho":3 @exception InvalidParameterException Thrown if aParamterVector.size()!=4. */ virtual void setParameterVector(const ParamVectorType& aParameterVector); /*! @brief Get parameter id. "alphaMean":0,"alphaVariance":1,"alpha_beta":2, "rho":3 @return 0 for "alphaMean", 1 for "alphaVariance", 2 for "alpha_beta", 3 for "rho" @exception InvalidParameterException Thrown if aParamName is not alphaMean or alphaVariance or alpha_beta or rho. */ virtual const int getParameterID(const std::string& aParamName) const; }; }//end algorithms }//end rttb #endif diff --git a/demoapps/CMakeLists.txt b/demoapps/CMakeLists.txt index 22ca34d..f9a355e 100644 --- a/demoapps/CMakeLists.txt +++ b/demoapps/CMakeLists.txt @@ -1,6 +1,11 @@ MESSAGE(STATUS "processing RTToolbox demo apps") OPTION(BUILD_DemoApp_DoseAcc "Determine if the demo application DoseAcc will be generated." OFF) IF(BUILD_DemoApp_DoseAcc) ADD_SUBDIRECTORY(DoseAcc) ENDIF(BUILD_DemoApp_DoseAcc) + +OPTION(BUILD_DemoApp_DoseMap "Determine if the demo application DoseMap will be generated." OFF) +IF(BUILD_DemoApp_DoseMap) +ADD_SUBDIRECTORY(DoseMap) +ENDIF(BUILD_DemoApp_DoseMap) diff --git a/demoapps/DoseAcc/CMakeLists.txt b/demoapps/DoseAcc/CMakeLists.txt index 8eda38d..d1a475d 100644 --- a/demoapps/DoseAcc/CMakeLists.txt +++ b/demoapps/DoseAcc/CMakeLists.txt @@ -1,3 +1,3 @@ MESSAGE (STATUS "generating demo app: DoseAcc - simple dose accumulation tool example") -RTTB_CREATE_APPLICATION(DoseAcc DEPENDS RTTBCore RTTBAlgorithms RTTBInterpolation RTTBMatchPointBinding RTTBITKIO RTTBVirtuosIO PACKAGE_DEPENDS MatchPoint ITK) \ No newline at end of file +RTTB_CREATE_APPLICATION(DoseAcc DEPENDS RTTBCore RTTBAlgorithms RTTBInterpolation RTTBMatchPointBinding RTTBITKIO RTTBVirtuosIO RTTBDicomIO RTTBHelaxIO PACKAGE_DEPENDS MatchPoint ITK) \ No newline at end of file diff --git a/demoapps/DoseAcc/DoseAcc.cpp b/demoapps/DoseAcc/DoseAcc.cpp index 27e4a82..44e53aa 100644 --- a/demoapps/DoseAcc/DoseAcc.cpp +++ b/demoapps/DoseAcc/DoseAcc.cpp @@ -1,192 +1,171 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "DoseAccApplicationData.h" #include "DoseAccHelper.h" rttb::apps::doseAcc::ApplicationData appData; int main(int argc, char** argv) { int result = 0; std::cout << "DoseAcc - RTTB demo app for simple dose accumulation." << std::endl; switch (rttb::apps::doseAcc::ParseArgumentsForAppData(argc, argv, appData)) { - case 1: + case 1: { //showed version or help info. Done. return 1; } - case 2: + case 2: { std::cerr << "Missing Parameters. Use one of the following flags for more information:" << - std::endl; + std::endl; std::cerr << "-? or --help" << std::endl; return 2; } - case 3: + case 3: { //wrong option usage. return 3; } } if (appData._fileCount < 3) { std::cerr << "Missing Parameters. Use one of the following flags for more information:" << - std::endl; + std::endl; std::cerr << "-? or --help" << std::endl; return 1; } std::cout << std::endl << "*******************************************" << std::endl; std::cout << "Dose 1 file: " << appData._dose1FileName << std::endl; - if (!(appData._dose1VirtuosPlanFileName.empty())) - { - std::cout << " as virtuos. Plan: " << appData._dose1VirtuosPlanFileName << std::endl; - } std::cout << "Dose 2 file: " << appData._dose2FileName << std::endl; - if (!(appData._dose2VirtuosPlanFileName.empty())) - { - std::cout << " as virtuos. Plan: " << appData._dose2VirtuosPlanFileName << std::endl; - } std::cout << "Dose output file: " << appData._outputFileName << std::endl; if (!(appData._regFileName.empty())) { std::cout << "Registration file: " << appData._regFileName << std::endl; } + std::cout << "Dose 1 weight: " << appData._weightDose1 << std::endl; std::cout << "Dose 2 weight: " << appData._weightDose2 << std::endl; try { - if (appData._dose1VirtuosPlanFileName.empty()) - { - appData._Dose1 = rttb::apps::doseAcc::loadDose(appData._dose1FileName); - } - else - { - appData._Dose1 = rttb::apps::doseAcc::loadVirtuosDose(appData._dose1FileName, appData._dose1VirtuosPlanFileName); - } + appData._Dose1 = rttb::apps::doseAcc::loadDose(appData._dose1FileName, appData._dose1LoadStyle); } catch (::itk::ExceptionObject& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e << std::endl; return 4; } catch (std::exception& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 4; } catch (...) { std::cerr << "Error!!! unknown error while reading input image." << std::endl; return 4; } try { - if (appData._dose2VirtuosPlanFileName.empty()) - { - appData._Dose2 = rttb::apps::doseAcc::loadDose(appData._dose2FileName); - } - else - { - appData._Dose2 = rttb::apps::doseAcc::loadVirtuosDose(appData._dose2FileName, appData._dose2VirtuosPlanFileName); - } + appData._Dose2 = rttb::apps::doseAcc::loadDose(appData._dose2FileName, appData._dose2LoadStyle); } catch (::itk::ExceptionObject& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e << std::endl; return 4; } catch (std::exception& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 4; } catch (...) { std::cerr << "Error!!! unknown error while reading input image." << std::endl; return 4; } if (!(appData._regFileName.empty())) { try { appData._spReg = rttb::apps::doseAcc::loadRegistration(appData._regFileName); } catch (::itk::ExceptionObject& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e << std::endl; return 5; } catch (std::exception& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 5; } catch (...) { std::cerr << "Error!!! unknown error while reading registration file." << std::endl; return 5; } } try { rttb::apps::doseAcc::processData(appData); } catch (::itk::ExceptionObject& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e << std::endl; return 9; } catch (std::exception& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 9; } catch (...) { std::cerr << "Error!!! unknown error while mapping and writing image." << std::endl; return 9; } std::cout << std::endl; return result; } diff --git a/demoapps/DoseAcc/DoseAccApplicationData.cpp b/demoapps/DoseAcc/DoseAccApplicationData.cpp index 22995e8..8829e19 100644 --- a/demoapps/DoseAcc/DoseAccApplicationData.cpp +++ b/demoapps/DoseAcc/DoseAccApplicationData.cpp @@ -1,178 +1,194 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "DoseAccApplicationData.h" #include "itksys/SystemTools.hxx" #include "itksys/CommandLineArguments.hxx" #include "RTToolboxConfigure.h" namespace rttb { - namespace apps - { - namespace doseAcc - { - - int unknown_argument(const char* argument, void* call_data) - { - std::cout << "Got unknown argument: \"" << argument << "\"" << std::endl; - return 0; - } - - ApplicationData:: - ApplicationData() - { - this->Reset(); - } - - void - ApplicationData:: - Reset() - { - _dose1FileName = ""; - _dose2FileName = ""; - _outputFileName = ""; - _regFileName = ""; - _dose1VirtuosPlanFileName = ""; - _dose2VirtuosPlanFileName = ""; - - - _showVersion = false; - _showHelp = false; - - _weightDose1 = 1.0; - _weightDose2 = 1.0; - - _fileCount = 0; - } - - unsigned int - ParseArgumentsForAppData(int argc, char** argv, ApplicationData& appData) - { - itksys::CommandLineArguments cmdParser; - - appData.Reset(); - - if (argc > 3) - { - appData._dose1FileName = argv[1]; - ++appData._fileCount; - --argc; - ++argv; - - appData._dose2FileName = argv[1]; - ++appData._fileCount; - --argc; - ++argv; - - appData._outputFileName = argv[1]; - ++appData._fileCount; - --argc; - ++argv; - } - - cmdParser.Initialize(argc, argv); - - cmdParser.SetUnknownArgumentCallback(unknown_argument); - - cmdParser.AddArgument("--weight1", itksys::CommandLineArguments::SPACE_ARGUMENT, &(appData._weightDose1), - "Specifies the weight for dose 1. If not specified the weight is 1.0."); - cmdParser.AddArgument("-w1", itksys::CommandLineArguments::SPACE_ARGUMENT, &(appData._weightDose1), - "Specifies the weight for dose 1. If not specified the weight is 1.0."); - cmdParser.AddArgument("--weight2", itksys::CommandLineArguments::SPACE_ARGUMENT, &(appData._weightDose2), - "Specifies the weight for dose 2. If not specified the weight is 1.0."); - cmdParser.AddArgument("-w2", itksys::CommandLineArguments::SPACE_ARGUMENT, &(appData._weightDose2), - "Specifies the weight for dose 2. If not specified the weight is 1.0."); - - cmdParser.AddArgument("--registration", itksys::CommandLineArguments::SPACE_ARGUMENT, &(appData._regFileName), - "Specifies name and location of the registration file that should be used to map dose 2 befor accumulating it with dose 1. Default is no mapping, thus direct accumulation. The registration should be stored as MatchPoint registration."); - cmdParser.AddArgument("-r", itksys::CommandLineArguments::SPACE_ARGUMENT, &(appData._regFileName), - "Specifies name and location of the registration file that should be used to map dose 2 befor accumulating it with dose 1. Default is no mapping, thus direct accumulation. The registration should be stored as MatchPoint registration."); - - cmdParser.AddArgument("--virtuosPlan1", itksys::CommandLineArguments::SPACE_ARGUMENT, &(appData._dose1VirtuosPlanFileName), - "Indicates that the dose file of dose 1 should be handled as Virtuos dose and specifies the plan file that should be used to load the dose."); - cmdParser.AddArgument("-v1", itksys::CommandLineArguments::SPACE_ARGUMENT, &(appData._dose1VirtuosPlanFileName), - "Indicates that the dose file of dose 1 should be handled as Virtuos dose and specifies the plan file that should be used to load the dose."); - - cmdParser.AddArgument("--virtuosPlan2", itksys::CommandLineArguments::SPACE_ARGUMENT, &(appData._dose2VirtuosPlanFileName), - "Indicates that the dose file of dose 2 should be handled as Virtuos dose and specifies the plan file that should be used to load the dose."); - cmdParser.AddArgument("-v2", itksys::CommandLineArguments::SPACE_ARGUMENT, &(appData._dose2VirtuosPlanFileName), - "Indicates that the dose file of dose 2 should be handled as Virtuos dose and specifies the plan file that should be used to load the dose."); + namespace apps + { + namespace doseAcc + { + + int unknown_argument(const char* argument, void* call_data) + { + std::cout << "Got unknown argument: \"" << argument << "\"" << std::endl; + return 0; + } + + ApplicationData:: + ApplicationData() + { + this->Reset(); + } + + void + ApplicationData:: + Reset() + { + _dose1FileName = ""; + _dose2FileName = ""; + _outputFileName = ""; + _regFileName = ""; + + _interpolatorName = "linear"; + + _showVersion = false; + _showHelp = false; + + _weightDose1 = 1.0; + _weightDose2 = 1.0; + + _fileCount = 0; + } + + unsigned int + ParseArgumentsForAppData(int argc, char** argv, ApplicationData& appData) + { + itksys::CommandLineArguments cmdParser; + + appData.Reset(); + + if (argc > 3) + { + appData._dose1FileName = argv[1]; + ++appData._fileCount; + --argc; + ++argv; + + appData._dose2FileName = argv[1]; + ++appData._fileCount; + --argc; + ++argv; + + appData._outputFileName = argv[1]; + ++appData._fileCount; + --argc; + ++argv; + } + + cmdParser.Initialize(argc, argv); + + cmdParser.SetUnknownArgumentCallback(unknown_argument); + + cmdParser.AddArgument("--interpolator", itksys::CommandLineArguments::SPACE_ARGUMENT, + &(appData._interpolatorName), + "Specifies the interpolator that should be used for mapping. Available options are: \"nn\": nearest neighbour, \"linear\": linear interpolation, \"rosu\" interpolation based on the concept of Rosu et al.. Default interpolator is \"linear\"."); + cmdParser.AddArgument("-i", itksys::CommandLineArguments::SPACE_ARGUMENT, + &(appData._interpolatorName), + "Specifies the interpolator that should be used for mapping. Available options are: \"nn\": nearest neighbour, \"linear\": linear interpolation, \"rosu\" interpolation based on the concept of Rosu et al.. Default interpolator is \"linear\"."); + + cmdParser.AddArgument("--weight1", itksys::CommandLineArguments::SPACE_ARGUMENT, + &(appData._weightDose1), + "Specifies the weight for dose 1. If not specified the weight is 1.0."); + cmdParser.AddArgument("-w1", itksys::CommandLineArguments::SPACE_ARGUMENT, &(appData._weightDose1), + "Specifies the weight for dose 1. If not specified the weight is 1.0."); + cmdParser.AddArgument("--weight2", itksys::CommandLineArguments::SPACE_ARGUMENT, + &(appData._weightDose2), + "Specifies the weight for dose 2. If not specified the weight is 1.0."); + cmdParser.AddArgument("-w2", itksys::CommandLineArguments::SPACE_ARGUMENT, &(appData._weightDose2), + "Specifies the weight for dose 2. If not specified the weight is 1.0."); + + cmdParser.AddArgument("--registration", itksys::CommandLineArguments::SPACE_ARGUMENT, + &(appData._regFileName), + "Specifies name and location of the registration file that should be used to map dose 2 befor accumulating it with dose 1. Default is no mapping, thus direct accumulation. The registration should be stored as MatchPoint registration."); + cmdParser.AddArgument("-r", itksys::CommandLineArguments::SPACE_ARGUMENT, &(appData._regFileName), + "Specifies name and location of the registration file that should be used to map dose 2 befor accumulating it with dose 1. Default is no mapping, thus direct accumulation. The registration should be stored as MatchPoint registration."); + + cmdParser.AddArgument("--loadStyle1", itksys::CommandLineArguments::MULTI_ARGUMENT, + &(appData._dose1LoadStyle), + "Indicates the load style that should be used for dose 1. Available styles: \"dicom\": normal dicom dose (default); \"virtuos\": load of a virtuos dose (This style is a multi argument. The second argument specifies the virtuos plan file, e.g. : \"--loadStyle1 virtuos myFavorite.pln\"); \"itk\": use itk image loading; \"helax\": load a helax dose (choosing this style, the dose path should only be a directory)."); + + cmdParser.AddArgument("--loadStyle2", itksys::CommandLineArguments::MULTI_ARGUMENT, + &(appData._dose2LoadStyle), + "Indicates the load style that should be used for dose 2. Available styles: \"dicom\": normal dicom dose (default); \"virtuos\": load of a virtuos dose (This style is a multi argument. The second argument specifies the virtuos plan file, e.g. : \"--loadStyle2 virtuos myFavorite.pln\"); \"itk\": use itk image loading; \"helax\": load a helax dose (choosing this style, the dose path should only be a directory)."); cmdParser.AddArgument("-v", itksys::CommandLineArguments::NO_ARGUMENT, &(appData._showVersion), - "Shows the version of the program."); - - cmdParser.AddArgument("-h", itksys::CommandLineArguments::NO_ARGUMENT, &(appData._showHelp), - "Shows this help information for the program."); - cmdParser.AddArgument("--help", itksys::CommandLineArguments::NO_ARGUMENT, &(appData._showHelp), - "Shows this help information for the program."); - cmdParser.AddArgument("-?", itksys::CommandLineArguments::NO_ARGUMENT, &(appData._showHelp), - "Shows this help information for the program."); - cmdParser.AddArgument("/h", itksys::CommandLineArguments::NO_ARGUMENT, &(appData._showHelp), - "Shows this help information for the program."); - cmdParser.AddArgument("/?", itksys::CommandLineArguments::NO_ARGUMENT, &(appData._showHelp), - "Shows this help information for the program."); - - if (!cmdParser.Parse()) - { - std::cerr << "Wrong command line option or insufficient number of arguments." << std::endl; - std::cerr << "The last correct argument was: " << argv[cmdParser.GetLastArgument()] << std::endl << - "Use one of the following flags for more information:" << std::endl; - std::cerr << "-? or --help" << std::endl; - return 3; - }; - - if (appData._showHelp) - { - std::cout << std::endl << "Usage: " << std::endl << std::endl; - std::cout << " DoseAcc [options]" << std::endl << std::endl; - std::cout << " Dose1: File path to the 1st dose." << std::endl; - std::cout << " Dose2: File path to the 2nd dose." << std::endl; - std::cout << " DoseOutput: File path where the output should be stored." << std::endl << std::endl; - std::cout << "Command-Line Options:" << std::endl << std::endl; - std::cout << cmdParser.GetHelp() << std::endl << std::endl; - std::cout << " Example:" << std::endl << std::endl; - std::cout << " DoseCalc dose1.mhd dose2.mhd result.mhd -w1 2 -r reg.mapr" << std::endl << std::endl; - std::cout << - " This will accumulate \"dose1.mhd\" and \"dose2.mhd\" by using \"reg.mapr\" to map dose 2. For the accumlation dose 1 will be multiplied by 2. The resulting dose will be stored in \"result.mhd\"." - << std::endl; - return 1; - } - - if (appData._showVersion) - { - std::cout << std::endl << "Version: " << RTT_FULL_VERSION_STRING; - return 1; - } - - if (appData._fileCount < 3) - { - return 2; - } - - return 0; - }; - - } - } + "Shows the version of the program."); + + cmdParser.AddArgument("-h", itksys::CommandLineArguments::NO_ARGUMENT, &(appData._showHelp), + "Shows this help information for the program."); + cmdParser.AddArgument("--help", itksys::CommandLineArguments::NO_ARGUMENT, &(appData._showHelp), + "Shows this help information for the program."); + cmdParser.AddArgument("-?", itksys::CommandLineArguments::NO_ARGUMENT, &(appData._showHelp), + "Shows this help information for the program."); + cmdParser.AddArgument("/h", itksys::CommandLineArguments::NO_ARGUMENT, &(appData._showHelp), + "Shows this help information for the program."); + cmdParser.AddArgument("/?", itksys::CommandLineArguments::NO_ARGUMENT, &(appData._showHelp), + "Shows this help information for the program."); + + if (!cmdParser.Parse()) + { + std::cerr << "Wrong command line option or insufficient number of arguments." << std::endl; + std::cerr << "The last correct argument was: " << argv[cmdParser.GetLastArgument()] << std::endl << + "Use one of the following flags for more information:" << std::endl; + std::cerr << "-? or --help" << std::endl; + return 3; + }; + + if (appData._showHelp) + { + std::cout << std::endl << "Usage: " << std::endl << std::endl; + std::cout << " DoseAcc [options]" << std::endl << std::endl; + std::cout << " Dose1: File path to the 1st dose." << std::endl; + std::cout << " Dose2: File path to the 2nd dose." << std::endl; + std::cout << " DoseOutput: File path where the output should be stored." << std::endl << + std::endl; + std::cout << "Command-Line Options:" << std::endl << std::endl; + std::cout << cmdParser.GetHelp() << std::endl << std::endl; + std::cout << " Example:" << std::endl << std::endl; + std::cout << + " DoseCalc dose1.mhd dose2.mhd result.mhd --loadStyle1 itk --loadStyle2 itk -w1 2 -r reg.mapr" << + std::endl << std::endl; + std::cout << + " This will accumulate \"dose1.mhd\" and \"dose2.mhd\" by using \"reg.mapr\" to map dose 2. For the accumlation dose 1 will be multiplied by 2. The resulting dose will be stored in \"result.mhd\"." + << std::endl << std::endl; + std::cout << + " DoseCalc dose1.dcm dose2.dos.gz result.mhd --loadStyle2 virtuos dose2.pln -r reg.mapr" << + std::endl << std::endl; + std::cout << + " This will accumulate \"dose1.dcm\" (using default dicom io) and \"dose2.dos.gz\" (using virtuos io and plan file dose2.pln) by using \"reg.mapr\" to map dose 2. The resulting dose will be stored in \"result.mhd\"." + << std::endl; + return 1; + } + + if (appData._showVersion) + { + std::cout << std::endl << "Version: " << RTT_FULL_VERSION_STRING; + return 1; + } + + if (appData._fileCount < 3) + { + return 2; + } + + return 0; + }; + + } + } } diff --git a/demoapps/DoseAcc/DoseAccApplicationData.h b/demoapps/DoseAcc/DoseAccApplicationData.h index 06171b2..df9c011 100644 --- a/demoapps/DoseAcc/DoseAccApplicationData.h +++ b/demoapps/DoseAcc/DoseAccApplicationData.h @@ -1,83 +1,89 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DOSE_ACCAPPLICATION_DATA_H #define __DOSE_ACCAPPLICATION_DATA_H #include "mapRegistration.h" #include "rttbBaseType.h" #include "rttbDoseAccessorInterface.h" namespace rttb { - namespace apps - { - namespace doseAcc - { + namespace apps + { + namespace doseAcc + { - class ApplicationData - { - public: + class ApplicationData + { + public: typedef map::core::Registration<3, 3> RegistrationType; - - /** Loaded Dose.*/ - core::DoseAccessorInterface::DoseAccessorPointer _Dose1; - std::string _dose1FileName; - std::string _dose1VirtuosPlanFileName; - core::DoseAccessorInterface::DoseAccessorPointer _Dose2; - std::string _dose2FileName; - std::string _dose2VirtuosPlanFileName; - RegistrationType::Pointer _spReg; - std::string _regFileName; + /**Vector of arguments used to specify the loading style (always the first argument) + * and, if needed, additional arguments for the specified loading style (e.g. location of the + * Virtuos plan file for the Virtuos IO style). + */ + typedef std::vector LoadingStyleArgType; + /** Loaded Dose.*/ + core::DoseAccessorInterface::DoseAccessorPointer _Dose1; + std::string _dose1FileName; + LoadingStyleArgType _dose1LoadStyle; + core::DoseAccessorInterface::DoseAccessorPointer _Dose2; + std::string _dose2FileName; + LoadingStyleArgType _dose2LoadStyle; + RegistrationType::Pointer _spReg; + std::string _regFileName; - std::string _outputFileName; + std::string _outputFileName; - double _weightDose1; - double _weightDose2; + double _weightDose1; + double _weightDose2; - bool _showVersion; - bool _showHelp; + std::string _interpolatorName; - int _fileCount; + bool _showVersion; + bool _showHelp; - void Reset(); + int _fileCount; - ApplicationData(); - }; + void Reset(); - /** Parse the application argument passed when starting the application. - * If no error or special request occurred the return is 0. Otherwise the return values - * have the following meaning: \n - * 0: Normal parsing.\n - * 1: showed help or version (flag was set).\n - * 2: not enough required input files.\n - * 3: Parsing error.\n - * @param argc Number of parameter arguments - * @param argv Pointer to the passed arguments - * @return Result code of the parsing (see above).**/ - unsigned int ParseArgumentsForAppData(int argc, char** argv, ApplicationData& appData); - - } - } + ApplicationData(); + }; + + /** Parse the application argument passed when starting the application. + * If no error or special request occurred the return is 0. Otherwise the return values + * have the following meaning: \n + * 0: Normal parsing.\n + * 1: showed help or version (flag was set).\n + * 2: not enough required input files.\n + * 3: Parsing error.\n + * @param argc Number of parameter arguments + * @param argv Pointer to the passed arguments + * @return Result code of the parsing (see above).**/ + unsigned int ParseArgumentsForAppData(int argc, char** argv, ApplicationData& appData); + + } + } } #endif diff --git a/demoapps/DoseAcc/DoseAccHelper.cpp b/demoapps/DoseAcc/DoseAccHelper.cpp index 905eb74..7b3f11a 100644 --- a/demoapps/DoseAcc/DoseAccHelper.cpp +++ b/demoapps/DoseAcc/DoseAccHelper.cpp @@ -1,129 +1,247 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include "DoseAccHelper.h" #include "mapRegistrationFileReader.h" #include "itkImageFileWriter.h" +#include "rttbExceptionMacros.h" + #include "rttbVirtuosPlanFileDoseAccessorGenerator.h" +#include "rttbDicomFileDoseAccessorGenerator.h" +#include "rttbDicomHelaxFileDoseAccessorGenerator.h" #include "rttbITKImageFileDoseAccessorGenerator.h" #include "rttbSimpleMappableDoseAccessor.h" #include "rttbMatchPointTransformation.h" #include "rttbLinearInterpolation.h" +#include "rttbNearestNeighborInterpolation.h" +#include "rttbRosuMappableDoseAccessor.h" #include "rttbITKImageDoseAccessorConverter.h" #include "rttbArithmetic.h" #include "rttbBinaryFunctorDoseAccessor.h" +rttb::core::DoseAccessorInterface::DoseAccessorPointer +rttb::apps::doseAcc::loadDose(const std::string& fileName, + const rttb::apps::doseAcc::ApplicationData::LoadingStyleArgType& args) +{ + rttb::core::DoseAccessorInterface::DoseAccessorPointer result; + + std::cout << std::endl << "read dose file... "; + + if (args.empty() || args[0] == "dicom") + { + std::cout << "use RTTB dicom IO... "; + result = loadDicomDose(fileName); + } + else if (args[0] == "helax") + { + std::cout << "use RTTB Helax IO... "; + result = loadHelaxDose(fileName); + } + else if (args[0] == "itk") + { + std::cout << "use RTTB itk IO... "; + result = loadITKDose(fileName); + } + else if (args[0] == "virtuos") + { + if (args.size() < 2) + { + rttbDefaultExceptionStaticMacro( << + "Cannot load virtuos dose. Plan file is missing. Specify plan file as 2nd io stlye argument."); + } + + std::cout << "use RTTB virtuos IO... " << std::endl; + std::cout << " virtuos plan file: " << args[1] << " ... "; + result = loadVirtuosDose(fileName, args[1]); + } + else + { + rttbDefaultExceptionStaticMacro( << "Unknown io style selected. Cannot load data. Selected style: " + << args[0]); + } + + std::cout << "done." << std::endl; + + return result; +}; + +rttb::core::DoseAccessorInterface::DoseAccessorPointer +rttb::apps::doseAcc::loadDicomDose(const std::string& fileName) +{ + rttb::io::dicom::DicomFileDoseAccessorGenerator generator(fileName); + return generator.generateDoseAccessor(); +}; + +rttb::core::DoseAccessorInterface::DoseAccessorPointer +rttb::apps::doseAcc::loadHelaxDose(const std::string& path) +{ + rttb::io::helax::DicomHelaxFileDoseAccessorGenerator generator(path); + return generator.generateDoseAccessor(); +}; rttb::core::DoseAccessorInterface::DoseAccessorPointer -rttb::apps::doseAcc::loadDose(const std::string& fileName) +rttb::apps::doseAcc::loadITKDose(const std::string& fileName) { - rttb::io::itk::ITKImageFileDoseAccessorGenerator generator(fileName); - return generator.generateDoseAccessor(); + rttb::io::itk::ITKImageFileDoseAccessorGenerator generator(fileName); + return generator.generateDoseAccessor(); }; rttb::core::DoseAccessorInterface::DoseAccessorPointer rttb::apps::doseAcc::loadVirtuosDose(const std::string& fileName, const std::string& planFileName) { - rttb::io::virtuos::VirtuosPlanFileDoseAccessorGenerator generator(fileName, planFileName); - return generator.generateDoseAccessor(); + rttb::io::virtuos::VirtuosPlanFileDoseAccessorGenerator generator(fileName, planFileName); + return generator.generateDoseAccessor(); }; rttb::apps::doseAcc::ApplicationData::RegistrationType::Pointer rttb::apps::doseAcc::loadRegistration(const std::string& fileName) { - map::io::RegistrationFileReader::Pointer spRegReader = map::io::RegistrationFileReader::New(); + map::io::RegistrationFileReader::Pointer spRegReader = map::io::RegistrationFileReader::New(); - map::io::RegistrationFileReader::LoadedRegistrationPointer spReg; + map::io::RegistrationFileReader::LoadedRegistrationPointer spReg; - std::cout << std::endl << "read registration file... "; - spReg = spRegReader->read(fileName); - std::cout << "done." << std::endl; + std::cout << std::endl << "read registration file... "; + spReg = spRegReader->read(fileName); + std::cout << "done." << std::endl; - ApplicationData::RegistrationType::Pointer resultPtr = - dynamic_cast(spReg.GetPointer()); + ApplicationData::RegistrationType::Pointer resultPtr = + dynamic_cast(spReg.GetPointer()); - if (resultPtr.IsNull()) - { - mapDefaultExceptionStaticMacro( << - "Loaded registration cannot be used. Only 3D 3D registrations are allowed."); - } + if (resultPtr.IsNull()) + { + mapDefaultExceptionStaticMacro( << + "Loaded registration cannot be used. Only 3D 3D registrations are allowed."); + } - return resultPtr; + return resultPtr; }; +rttb::core::DoseAccessorInterface::DoseAccessorPointer generateNNMappableAccessor( + const rttb::core::GeometricInfo& geoInfoTargetImage, + const rttb::core::DoseAccessorInterface::DoseAccessorPointer doseMovingImage, + const rttb::interpolation::TransformationInterface::Pointer aTransformation) +{ + rttb::interpolation::InterpolationBase::Pointer interpolate = + rttb::interpolation::NearestNeighborInterpolation::Pointer(new + rttb::interpolation::NearestNeighborInterpolation()); + + return rttb::core::DoseAccessorInterface::DoseAccessorPointer( + new rttb::interpolation::SimpleMappableDoseAccessor(geoInfoTargetImage, doseMovingImage, + aTransformation, interpolate)); +} + +rttb::core::DoseAccessorInterface::DoseAccessorPointer generateLinearMappableAccessor( + const rttb::core::GeometricInfo& geoInfoTargetImage, + const rttb::core::DoseAccessorInterface::DoseAccessorPointer doseMovingImage, + const rttb::interpolation::TransformationInterface::Pointer aTransformation) +{ + rttb::interpolation::InterpolationBase::Pointer interpolate = + rttb::interpolation::LinearInterpolation::Pointer(new + rttb::interpolation::LinearInterpolation()); + + return rttb::core::DoseAccessorInterface::DoseAccessorPointer( + new rttb::interpolation::SimpleMappableDoseAccessor(geoInfoTargetImage, doseMovingImage, + aTransformation, interpolate)); +} + +rttb::core::DoseAccessorInterface::DoseAccessorPointer generateRosuMappableAccessor( + const rttb::core::GeometricInfo& geoInfoTargetImage, + const rttb::core::DoseAccessorInterface::DoseAccessorPointer doseMovingImage, + const rttb::interpolation::TransformationInterface::Pointer aTransformation) +{ + return rttb::core::DoseAccessorInterface::DoseAccessorPointer( + new rttb::interpolation::RosuMappableDoseAccessor(geoInfoTargetImage, doseMovingImage, + aTransformation)); +} /**Private helper function for processData(). Generates a suitable output accessor * (depending on the configuration in appData a suitable accessor pipeline is established) * which performs the accumulation of the doses and returns the output.to */ rttb::core::DoseAccessorInterface::DoseAccessorPointer assembleOutputAccessor(rttb::apps::doseAcc::ApplicationData& appData) { - rttb::core::DoseAccessorInterface::DoseAccessorPointer dose2Accessor = appData._Dose2; - - if (appData._spReg.IsNotNull()) - { - rttb::interpolation::LinearInterpolation::Pointer interpolate = - rttb::interpolation::LinearInterpolation::Pointer(new - rttb::interpolation::LinearInterpolation()); - rttb::interpolation::TransformationInterface::Pointer transform = - rttb::interpolation::TransformationInterface::Pointer(new - rttb::interpolation::MatchPointTransformation(appData._spReg)); - dose2Accessor = rttb::core::DoseAccessorInterface::DoseAccessorPointer( - new rttb::interpolation::SimpleMappableDoseAccessor(appData._Dose1->getGeometricInfo(), - appData._Dose2, transform, interpolate)); - } - - rttb::algorithms::arithmetic::doseOp::AddWeighted addOp(appData._weightDose1, appData._weightDose2); - rttb::core::DoseAccessorInterface::DoseAccessorPointer outputAccessor = - rttb::core::DoseAccessorInterface::DoseAccessorPointer(new - rttb::algorithms::BinaryFunctorDoseAccessor - (appData._Dose1, dose2Accessor, addOp)); - - return outputAccessor; + rttb::core::DoseAccessorInterface::DoseAccessorPointer dose2Accessor = appData._Dose2; + + if (appData._spReg.IsNotNull()) + { + rttb::interpolation::TransformationInterface::Pointer transform = + rttb::interpolation::TransformationInterface::Pointer(new + rttb::interpolation::MatchPointTransformation(appData._spReg)); + + if (appData._interpolatorName == "rosu") + { + dose2Accessor = generateRosuMappableAccessor(appData._Dose1->getGeometricInfo(), appData._Dose2, + transform); + } + else if (appData._interpolatorName == "nn") + { + dose2Accessor = generateNNMappableAccessor(appData._Dose1->getGeometricInfo(), appData._Dose2, + transform); + } + else if (appData._interpolatorName == "linear") + { + dose2Accessor = generateLinearMappableAccessor(appData._Dose1->getGeometricInfo(), appData._Dose2, + transform); + } + else + { + mapDefaultExceptionStaticMacro( << + "Unkown interpolation type selected. Cannot map dose. Interpolation type: " << + appData._interpolatorName); + } + } + + rttb::algorithms::arithmetic::doseOp::AddWeighted addOp(appData._weightDose1, appData._weightDose2); + rttb::core::DoseAccessorInterface::DoseAccessorPointer outputAccessor = + rttb::core::DoseAccessorInterface::DoseAccessorPointer(new + rttb::algorithms::BinaryFunctorDoseAccessor + (appData._Dose1, dose2Accessor, addOp)); + + return outputAccessor; } void rttb::apps::doseAcc::processData(rttb::apps::doseAcc::ApplicationData& appData) { - rttb::core::DoseAccessorInterface::DoseAccessorPointer outputAccessor = assembleOutputAccessor( - appData); - - std::cout << std::endl << "generate output image... "; - io::itk::ITKImageDoseAccessorConverter converter(outputAccessor); - converter.setFailOnInvalidIDs(true); - converter.process(); - io::itk::ITKDoseImageType::Pointer itkImage = converter.getITKImage(); - std::cout << "done." << std::endl; - - typedef ::itk::ImageFileWriter WriterType; - - std::cout << std::endl << "write output image... "; - WriterType::Pointer writer = WriterType::New(); - writer->SetInput(itkImage); - writer->SetFileName(appData._outputFileName); - writer->Write(); - std::cout << "done." << std::endl; + rttb::core::DoseAccessorInterface::DoseAccessorPointer outputAccessor = assembleOutputAccessor( + appData); + + std::cout << std::endl << "generate output image... "; + io::itk::ITKImageDoseAccessorConverter converter(outputAccessor); + converter.setFailOnInvalidIDs(true); + converter.process(); + io::itk::ITKDoseImageType::Pointer itkImage = converter.getITKImage(); + std::cout << "done." << std::endl; + + typedef ::itk::ImageFileWriter WriterType; + + std::cout << std::endl << "write output image... "; + WriterType::Pointer writer = WriterType::New(); + writer->SetInput(itkImage); + writer->SetFileName(appData._outputFileName); + writer->Write(); + std::cout << "done." << std::endl; }; diff --git a/demoapps/DoseAcc/DoseAccHelper.h b/demoapps/DoseAcc/DoseAccHelper.h index 7bfb6d7..cf51430 100644 --- a/demoapps/DoseAcc/DoseAccHelper.h +++ b/demoapps/DoseAcc/DoseAccHelper.h @@ -1,49 +1,58 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DOSE_ACC_HELPER_H #define __DOSE_ACC_HELPER_H #include "DoseAccApplicationData.h" namespace rttb { namespace apps { namespace doseAcc { + /**loads the dose from a file. Throws exception if loading fails*/ + core::DoseAccessorInterface::DoseAccessorPointer loadDose(const std::string& fileName, + const rttb::apps::doseAcc::ApplicationData::LoadingStyleArgType& args); + + /**loads the dose from a file using the dicom dose generator. Throws exception if loading fails*/ + core::DoseAccessorInterface::DoseAccessorPointer loadDicomDose(const std::string& fileName); + /**loads the dose from a path using the helax io dose generator. Throws exception if loading fails*/ + core::DoseAccessorInterface::DoseAccessorPointer loadHelaxDose(const std::string& path); /**loads the dose from a file stored in an ITK supported data format. Throws exception if loading fails*/ - core::DoseAccessorInterface::DoseAccessorPointer loadDose(const std::string& fileName); + core::DoseAccessorInterface::DoseAccessorPointer loadITKDose(const std::string& fileName); /**loads the dose from a file stored in Virtuos data format. Throws exception if loading fails*/ - core::DoseAccessorInterface::DoseAccessorPointer loadVirtuosDose(const std::string& fileName, const std::string& planFileName); + core::DoseAccessorInterface::DoseAccessorPointer loadVirtuosDose(const std::string& fileName, + const std::string& planFileName); ApplicationData::RegistrationType::Pointer loadRegistration(const std::string& fileName); /**Containes the business logic for the accumulation of the doses and the storing of the result. Uses appData for the input data and the correct configuration.*/ void processData(ApplicationData& appData); } } } #endif diff --git a/demoapps/DoseMap/CMakeLists.txt b/demoapps/DoseMap/CMakeLists.txt new file mode 100644 index 0000000..89153d6 --- /dev/null +++ b/demoapps/DoseMap/CMakeLists.txt @@ -0,0 +1,3 @@ +MESSAGE (STATUS "generating demo app: DoseMap - simple dose mapping tool example") + +RTTB_CREATE_APPLICATION(DoseMap DEPENDS RTTBCore RTTBAlgorithms RTTBInterpolation RTTBMatchPointBinding RTTBITKIO RTTBVirtuosIO RTTBDicomIO RTTBHelaxIO PACKAGE_DEPENDS MatchPoint ITK) \ No newline at end of file diff --git a/demoapps/DoseAcc/DoseAcc.cpp b/demoapps/DoseMap/DoseMap.cpp similarity index 53% copy from demoapps/DoseAcc/DoseAcc.cpp copy to demoapps/DoseMap/DoseMap.cpp index 27e4a82..7f790fa 100644 --- a/demoapps/DoseAcc/DoseAcc.cpp +++ b/demoapps/DoseMap/DoseMap.cpp @@ -1,192 +1,201 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) +// @version $Revision: 741 $ (last changed revision) +// @date $Date: 2014-09-16 16:34:22 +0200 (Di, 16 Sep 2014) $ (last change date) +// @author $Author: hentsch $ (last changed by) */ -#include "DoseAccApplicationData.h" -#include "DoseAccHelper.h" +#include "DoseMapApplicationData.h" +#include "DoseMapHelper.h" -rttb::apps::doseAcc::ApplicationData appData; +#include "mapDummyRegistrationAlgorithm.h" +rttb::apps::doseMap::ApplicationData appData; + +/** + Main function of dose mapper. + @retval 0 normal program execution + @retval 1 showed help or version (flag was set). + @retval 2 not enough required input files. + @retval 3 Argument parsing error + @retval 4 Error loading input dose file + @retval 5 Error loading reference dose file + @retval 6 Error loading registration + @retval 9 Error while mapping or storing result. +*/ int main(int argc, char** argv) { int result = 0; - std::cout << "DoseAcc - RTTB demo app for simple dose accumulation." << std::endl; + std::cout << "DoseMap - RTTB demo app for simple dose mapping." << std::endl; - switch (rttb::apps::doseAcc::ParseArgumentsForAppData(argc, argv, appData)) + switch (rttb::apps::doseMap::ParseArgumentsForAppData(argc, argv, appData)) { - case 1: + case 1: { //showed version or help info. Done. return 1; } - case 2: + case 2: { std::cerr << "Missing Parameters. Use one of the following flags for more information:" << - std::endl; + std::endl; std::cerr << "-? or --help" << std::endl; return 2; } - case 3: + case 3: { //wrong option usage. return 3; } } - if (appData._fileCount < 3) + if (appData._fileCount < 2) { std::cerr << "Missing Parameters. Use one of the following flags for more information:" << - std::endl; + std::endl; std::cerr << "-? or --help" << std::endl; return 1; } std::cout << std::endl << "*******************************************" << std::endl; - std::cout << "Dose 1 file: " << appData._dose1FileName << std::endl; - if (!(appData._dose1VirtuosPlanFileName.empty())) - { - std::cout << " as virtuos. Plan: " << appData._dose1VirtuosPlanFileName << std::endl; - } - std::cout << "Dose 2 file: " << appData._dose2FileName << std::endl; - if (!(appData._dose2VirtuosPlanFileName.empty())) - { - std::cout << " as virtuos. Plan: " << appData._dose2VirtuosPlanFileName << std::endl; - } - std::cout << "Dose output file: " << appData._outputFileName << std::endl; + std::cout << "Input dose file: " << appData._inputDoseFileName << std::endl; if (!(appData._regFileName.empty())) { std::cout << "Registration file: " << appData._regFileName << std::endl; } - std::cout << "Dose 1 weight: " << appData._weightDose1 << std::endl; - std::cout << "Dose 2 weight: " << appData._weightDose2 << std::endl; + + if (!(appData._refDoseFileName.empty())) + { + std::cout << "Reference dose file: " << appData._refDoseFileName << std::endl; + } try { - if (appData._dose1VirtuosPlanFileName.empty()) - { - appData._Dose1 = rttb::apps::doseAcc::loadDose(appData._dose1FileName); - } - else - { - appData._Dose1 = rttb::apps::doseAcc::loadVirtuosDose(appData._dose1FileName, appData._dose1VirtuosPlanFileName); - } + appData._inputDose = rttb::apps::doseMap::loadDose(appData._inputDoseFileName, + appData._inputDoseLoadStyle); } catch (::itk::ExceptionObject& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e << std::endl; return 4; } catch (std::exception& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 4; } catch (...) { std::cerr << "Error!!! unknown error while reading input image." << std::endl; return 4; } - try + if (!(appData._refDoseFileName.empty())) { - if (appData._dose2VirtuosPlanFileName.empty()) + try { - appData._Dose2 = rttb::apps::doseAcc::loadDose(appData._dose2FileName); + appData._inputDose = rttb::apps::doseMap::loadDose(appData._refDoseFileName, + appData._refDoseLoadStyle); } - else + catch (::itk::ExceptionObject& e) { - appData._Dose2 = rttb::apps::doseAcc::loadVirtuosDose(appData._dose2FileName, appData._dose2VirtuosPlanFileName); + std::cerr << "Error!!!" << std::endl; + std::cerr << e << std::endl; + return 5; + } + catch (std::exception& e) + { + std::cerr << "Error!!!" << std::endl; + std::cerr << e.what() << std::endl; + return 5; + } + catch (...) + { + std::cerr << "Error!!! unknown error while reading reference image." << std::endl; + return 5; } } - catch (::itk::ExceptionObject& e) - { - std::cerr << "Error!!!" << std::endl; - std::cerr << e << std::endl; - return 4; - } - catch (std::exception& e) - { - std::cerr << "Error!!!" << std::endl; - std::cerr << e.what() << std::endl; - return 4; - } - catch (...) + else { - std::cerr << "Error!!! unknown error while reading input image." << std::endl; - return 4; + appData._refDose = appData._inputDose; } if (!(appData._regFileName.empty())) { try { - appData._spReg = rttb::apps::doseAcc::loadRegistration(appData._regFileName); + appData._spReg = rttb::apps::doseMap::loadRegistration(appData._regFileName); } catch (::itk::ExceptionObject& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e << std::endl; - return 5; + return 6; } catch (std::exception& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e.what() << std::endl; - return 5; + return 6; } catch (...) { std::cerr << "Error!!! unknown error while reading registration file." << std::endl; - return 5; + return 6; } } + else + { + //generate dummy identity registration + typedef map::algorithm::DummyRegistrationAlgorithm<3> DummyRegType; + DummyRegType::Pointer regAlg = DummyRegType::New(); + + appData._spReg = regAlg->getRegistration(); + } try { - rttb::apps::doseAcc::processData(appData); + rttb::apps::doseMap::processData(appData); } catch (::itk::ExceptionObject& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e << std::endl; return 9; } catch (std::exception& e) { std::cerr << "Error!!!" << std::endl; std::cerr << e.what() << std::endl; return 9; } catch (...) { std::cerr << "Error!!! unknown error while mapping and writing image." << std::endl; return 9; } std::cout << std::endl; return result; } diff --git a/demoapps/DoseMap/DoseMapApplicationData.cpp b/demoapps/DoseMap/DoseMapApplicationData.cpp new file mode 100644 index 0000000..4e4f189 --- /dev/null +++ b/demoapps/DoseMap/DoseMapApplicationData.cpp @@ -0,0 +1,175 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notices for more information. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision: 741 $ (last changed revision) +// @date $Date: 2014-09-16 16:34:22 +0200 (Di, 16 Sep 2014) $ (last change date) +// @author $Author: hentsch $ (last changed by) +*/ + +#include "DoseMapApplicationData.h" + +#include "itksys/SystemTools.hxx" +#include "itksys/CommandLineArguments.hxx" + +#include "RTToolboxConfigure.h" + +namespace rttb +{ + namespace apps + { + namespace doseMap + { + + int unknown_argument(const char* argument, void* call_data) + { + std::cout << "Got unknown argument: \"" << argument << "\"" << std::endl; + return 0; + } + + ApplicationData:: + ApplicationData() + { + this->Reset(); + } + + void + ApplicationData:: + Reset() + { + _inputDoseFileName = ""; + _refDoseFileName = ""; + _outputFileName = ""; + _regFileName = ""; + + _interpolatorName = "linear"; + + _showVersion = false; + _showHelp = false; + + _fileCount = 0; + } + + unsigned int + ParseArgumentsForAppData(int argc, char** argv, ApplicationData& appData) + { + itksys::CommandLineArguments cmdParser; + + appData.Reset(); + + if (argc > 2) + { + appData._inputDoseFileName = argv[1]; + ++appData._fileCount; + --argc; + ++argv; + + appData._outputFileName = argv[1]; + ++appData._fileCount; + --argc; + ++argv; + } + + cmdParser.Initialize(argc, argv); + + cmdParser.SetUnknownArgumentCallback(unknown_argument); + + cmdParser.AddArgument("--interpolator", itksys::CommandLineArguments::SPACE_ARGUMENT, + &(appData._interpolatorName), + "Specifies the interpolator that should be used for mapping. Available options are: \"nn\": nearest neighbour, \"linear\": linear interpolation, \"rosu\" interpolation based on the concept of Rosu et al.. Default interpolator is \"linear\"."); + cmdParser.AddArgument("-i", itksys::CommandLineArguments::SPACE_ARGUMENT, + &(appData._interpolatorName), + "Specifies the interpolator that should be used for mapping. Available options are: \"nn\": nearest neighbour, \"linear\": linear interpolation, \"rosu\" interpolation based on the concept of Rosu et al.. Default interpolator is \"linear\"."); + + cmdParser.AddArgument("--registration", itksys::CommandLineArguments::SPACE_ARGUMENT, + &(appData._regFileName), + "Specifies name and location of the registration file that should be used to map the input dose. Default is no mapping, thus an identity transform is used. The registration should be stored as MatchPoint registration."); + cmdParser.AddArgument("-r", itksys::CommandLineArguments::SPACE_ARGUMENT, &(appData._regFileName), + "Specifies name and location of the registration file that should be used to map the input dose. Default is no mapping, thus an identity transform is used. The registration should be stored as MatchPoint registration."); + + cmdParser.AddArgument("--template", itksys::CommandLineArguments::SPACE_ARGUMENT, + &(appData._refDoseFileName), + "Specifies name and location of the dose file that should be the reference/template for the grid to mapp into. If flag is not specified, the input dose is the reference."); + cmdParser.AddArgument("-t", itksys::CommandLineArguments::SPACE_ARGUMENT, + &(appData._refDoseFileName), + "Specifies name and location of the dose file that should be the reference/template for the grid to mapp into. If flag is not specified, the input dose is the reference."); + + cmdParser.AddArgument("--loadStyleInput", itksys::CommandLineArguments::MULTI_ARGUMENT, + &(appData._inputDoseLoadStyle), + "Indicates the load style that should be used for the input dose. Available styles: \"dicom\": normal dicom dose (default); \"virtuos\": load of a virtuos dose (This style is a multi argument. The second argument specifies the virtuos plan file, e.g. : \"--loadStyle1 virtuos myFavorite.pln\"); \"itk\": use itk image loading; \"helax\": load a helax dose (choosing this style, the dose path should only be a directory)."); + + cmdParser.AddArgument("--loadStyleReference", itksys::CommandLineArguments::MULTI_ARGUMENT, + &(appData._refDoseLoadStyle), + "Indicates the load style that should be used for the reference dose. Available styles: \"dicom\": normal dicom dose (default); \"virtuos\": load of a virtuos dose (This style is a multi argument. The second argument specifies the virtuos plan file, e.g. : \"--loadStyle2 virtuos myFavorite.pln\"); \"itk\": use itk image loading; \"helax\": load a helax dose (choosing this style, the dose path should only be a directory)."); + + cmdParser.AddArgument("-v", itksys::CommandLineArguments::NO_ARGUMENT, &(appData._showVersion), + "Shows the version of the program."); + + cmdParser.AddArgument("-h", itksys::CommandLineArguments::NO_ARGUMENT, &(appData._showHelp), + "Shows this help information for the program."); + cmdParser.AddArgument("--help", itksys::CommandLineArguments::NO_ARGUMENT, &(appData._showHelp), + "Shows this help information for the program."); + cmdParser.AddArgument("-?", itksys::CommandLineArguments::NO_ARGUMENT, &(appData._showHelp), + "Shows this help information for the program."); + cmdParser.AddArgument("/h", itksys::CommandLineArguments::NO_ARGUMENT, &(appData._showHelp), + "Shows this help information for the program."); + cmdParser.AddArgument("/?", itksys::CommandLineArguments::NO_ARGUMENT, &(appData._showHelp), + "Shows this help information for the program."); + + if (!cmdParser.Parse()) + { + std::cerr << "Wrong command line option or insufficient number of arguments." << std::endl; + std::cerr << "The last correct argument was: " << argv[cmdParser.GetLastArgument()] << std::endl << + "Use one of the following flags for more information:" << std::endl; + std::cerr << "-? or --help" << std::endl; + return 3; + }; + + if (appData._showHelp) + { + std::cout << std::endl << "Usage: " << std::endl << std::endl; + std::cout << " DoseMap [options]" << std::endl << std::endl; + std::cout << " Dose1: File path to the input dose." << std::endl; + std::cout << " DoseOutput: File path where the output should be stored." << std::endl << + std::endl; + std::cout << "Command-Line Options:" << std::endl << std::endl; + std::cout << cmdParser.GetHelp() << std::endl << std::endl; + std::cout << " Example:" << std::endl << std::endl; + std::cout << + " DoseMap dose1.mhd result.mhd -r reg.mapr --loadStyleInput itk --loadStyleReference itk" << + std::endl << std::endl; + std::cout << + " This will map \"dose1.mhd\" by using \"reg.mapr\" into the grid geometry of the input dose. The resulting dose will be stored in \"result.mhd\"." + << std::endl; + return 1; + } + + if (appData._showVersion) + { + std::cout << std::endl << "Version: " << RTT_FULL_VERSION_STRING; + return 1; + } + + if (appData._fileCount < 2) + { + return 2; + } + + return 0; + }; + + } + } +} diff --git a/demoapps/DoseMap/DoseMapApplicationData.h b/demoapps/DoseMap/DoseMapApplicationData.h new file mode 100644 index 0000000..344aff0 --- /dev/null +++ b/demoapps/DoseMap/DoseMapApplicationData.h @@ -0,0 +1,87 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notices for more information. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision: 741 $ (last changed revision) +// @date $Date: 2014-09-16 16:34:22 +0200 (Di, 16 Sep 2014) $ (last change date) +// @author $Author: hentsch $ (last changed by) +*/ + + +#ifndef __DOSE_MAP_APPLICATION_DATA_H +#define __DOSE_MAP_APPLICATION_DATA_H + +#include "mapRegistration.h" + +#include "rttbBaseType.h" +#include "rttbDoseAccessorInterface.h" + +namespace rttb +{ + namespace apps + { + namespace doseMap + { + + class ApplicationData + { + public: + typedef map::core::Registration<3, 3> RegistrationType; + + /**Vector of arguments used to specify the loading style (always the first argument) + * and, if needed, additional arguments for the specified loading style (e.g. location of the + * Virtuos plan file for the Virtuos IO style). + */ + typedef std::vector LoadingStyleArgType; + /** Loaded Dose.*/ + core::DoseAccessorInterface::DoseAccessorPointer _inputDose; + std::string _inputDoseFileName; + LoadingStyleArgType _inputDoseLoadStyle; + core::DoseAccessorInterface::DoseAccessorPointer _refDose; + std::string _refDoseFileName; + LoadingStyleArgType _refDoseLoadStyle; + RegistrationType::Pointer _spReg; + std::string _regFileName; + + std::string _outputFileName; + + std::string _interpolatorName; + + bool _showVersion; + bool _showHelp; + + int _fileCount; + + void Reset(); + + ApplicationData(); + }; + + /** Parse the application argument passed when starting the application. + * If no error or special request occurred the return is 0. Otherwise the return values + * have the following meaning: \n + * 0: Normal parsing.\n + * 1: showed help or version (flag was set).\n + * 2: not enough required input files.\n + * 3: Parsing error.\n + * @param argc Number of parameter arguments + * @param argv Pointer to the passed arguments + * @return Result code of the parsing (see above).**/ + unsigned int ParseArgumentsForAppData(int argc, char** argv, ApplicationData& appData); + + } + } +} +#endif diff --git a/demoapps/DoseMap/DoseMapHelper.cpp b/demoapps/DoseMap/DoseMapHelper.cpp new file mode 100644 index 0000000..51bb0f0 --- /dev/null +++ b/demoapps/DoseMap/DoseMapHelper.cpp @@ -0,0 +1,209 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notices for more information. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision: 741 $ (last changed revision) +// @date $Date: 2014-09-16 16:34:22 +0200 (Di, 16 Sep 2014) $ (last change date) +// @author $Author: hentsch $ (last changed by) +*/ + + +#include "DoseMapHelper.h" + +#include "mapRegistrationFileReader.h" +#include "itkImageFileWriter.h" + +#include "rttbVirtuosPlanFileDoseAccessorGenerator.h" +#include "rttbDicomFileDoseAccessorGenerator.h" +#include "rttbDicomHelaxFileDoseAccessorGenerator.h" + +#include "rttbITKImageFileDoseAccessorGenerator.h" +#include "rttbDicomFileDoseAccessorGenerator.h" +#include "rttbSimpleMappableDoseAccessor.h" +#include "rttbMatchPointTransformation.h" +#include "rttbLinearInterpolation.h" +#include "rttbNearestNeighborInterpolation.h" +#include "rttbRosuMappableDoseAccessor.h" +#include "rttbITKImageDoseAccessorConverter.h" +#include "rttbArithmetic.h" +#include "rttbBinaryFunctorDoseAccessor.h" +#include "rttbExceptionMacros.h" + + +rttb::core::DoseAccessorInterface::DoseAccessorPointer +rttb::apps::doseMap::loadDose(const std::string& fileName, + const rttb::apps::doseMap::ApplicationData::LoadingStyleArgType& args) +{ + rttb::core::DoseAccessorInterface::DoseAccessorPointer result; + + std::cout << std::endl << "read dose file... "; + + if (args.empty() || args[0] == "dicom") + { + std::cout << "use RTTB dicom IO... "; + result = loadDicomDose(fileName); + } + else if (args[0] == "helax") + { + std::cout << "use RTTB Helax IO... "; + result = loadHelaxDose(fileName); + } + else if (args[0] == "itk") + { + std::cout << "use RTTB itk IO... "; + result = loadITKDose(fileName); + } + else if (args[0] == "virtuos") + { + if (args.size() < 2) + { + rttbDefaultExceptionStaticMacro( << + "Cannot load virtuos dose. Plan file is missing. Specify plan file as 2nd io stlye argument."); + } + + std::cout << "use RTTB virtuos IO... " << std::endl; + std::cout << " virtuos plan file: " << args[1] << " ... "; + result = loadVirtuosDose(fileName, args[1]); + } + else + { + rttbDefaultExceptionStaticMacro( << "Unknown io style selected. Cannot load data. Selected style: " + << args[0]); + } + + std::cout << "done." << std::endl; + + return result; +}; + +rttb::core::DoseAccessorInterface::DoseAccessorPointer +rttb::apps::doseMap::loadDicomDose(const std::string& fileName) +{ + rttb::io::dicom::DicomFileDoseAccessorGenerator generator(fileName); + return generator.generateDoseAccessor(); +}; + +rttb::core::DoseAccessorInterface::DoseAccessorPointer +rttb::apps::doseMap::loadHelaxDose(const std::string& path) +{ + rttb::io::helax::DicomHelaxFileDoseAccessorGenerator generator(path); + return generator.generateDoseAccessor(); +}; + +rttb::core::DoseAccessorInterface::DoseAccessorPointer +rttb::apps::doseMap::loadITKDose(const std::string& fileName) +{ + rttb::io::itk::ITKImageFileDoseAccessorGenerator generator(fileName); + return generator.generateDoseAccessor(); +}; + +rttb::core::DoseAccessorInterface::DoseAccessorPointer +rttb::apps::doseMap::loadVirtuosDose(const std::string& fileName, const std::string& planFileName) +{ + rttb::io::virtuos::VirtuosPlanFileDoseAccessorGenerator generator(fileName, planFileName); + return generator.generateDoseAccessor(); +}; + +rttb::apps::doseMap::ApplicationData::RegistrationType::Pointer +rttb::apps::doseMap::loadRegistration(const std::string& fileName) +{ + map::io::RegistrationFileReader::Pointer spRegReader = map::io::RegistrationFileReader::New(); + + map::io::RegistrationFileReader::LoadedRegistrationPointer spReg; + + std::cout << std::endl << "read registration file... "; + spReg = spRegReader->read(fileName); + std::cout << "done." << std::endl; + + ApplicationData::RegistrationType::Pointer resultPtr = + dynamic_cast(spReg.GetPointer()); + + if (resultPtr.IsNull()) + { + mapDefaultExceptionStaticMacro( << + "Loaded registration cannot be used. Only 3D 3D registrations are allowed."); + } + + return resultPtr; +}; + + +/**Private helper function for processData(). Generates a suitable output accessor + * (depending on the configuration in appData a suitable accessor pipeline is established) + * which performs the accumulation of the doses and returns the output.to */ +rttb::core::DoseAccessorInterface::DoseAccessorPointer +assembleOutputAccessor(rttb::apps::doseMap::ApplicationData& appData) +{ + + rttb::core::DoseAccessorInterface::DoseAccessorPointer outputAccessor = appData._inputDose; + + rttb::interpolation::TransformationInterface::Pointer transform = + rttb::interpolation::TransformationInterface::Pointer(new + rttb::interpolation::MatchPointTransformation(appData._spReg)); + + if (appData._interpolatorName == "rosu") + { + outputAccessor = rttb::core::DoseAccessorInterface::DoseAccessorPointer( + new rttb::interpolation::RosuMappableDoseAccessor(appData._refDose->getGeometricInfo(), + appData._inputDose, transform)); + } + else + { + rttb::interpolation::InterpolationBase::Pointer interpolate = + rttb::interpolation::LinearInterpolation::Pointer(new + rttb::interpolation::LinearInterpolation()); + + if (appData._interpolatorName == "nn") + { + interpolate = rttb::interpolation::NearestNeighborInterpolation::Pointer(new + rttb::interpolation::NearestNeighborInterpolation()); + } + else if (appData._interpolatorName != "linear") + { + mapDefaultExceptionStaticMacro( << + "Unkown interpolation type selected. Cannot map dose. Interpolation type: " << + appData._interpolatorName); + } + + outputAccessor = rttb::core::DoseAccessorInterface::DoseAccessorPointer( + new rttb::interpolation::SimpleMappableDoseAccessor(appData._refDose->getGeometricInfo(), + appData._inputDose, transform, interpolate)); + } + + return outputAccessor; +} + +void +rttb::apps::doseMap::processData(rttb::apps::doseMap::ApplicationData& appData) +{ + rttb::core::DoseAccessorInterface::DoseAccessorPointer outputAccessor = assembleOutputAccessor( + appData); + + std::cout << std::endl << "generate output image... "; + io::itk::ITKImageDoseAccessorConverter converter(outputAccessor); + converter.setFailOnInvalidIDs(true); + converter.process(); + io::itk::ITKDoseImageType::Pointer itkImage = converter.getITKImage(); + std::cout << "done." << std::endl; + + typedef ::itk::ImageFileWriter WriterType; + + std::cout << std::endl << "write output image... "; + WriterType::Pointer writer = WriterType::New(); + writer->SetInput(itkImage); + writer->SetFileName(appData._outputFileName); + writer->Write(); + std::cout << "done." << std::endl; +}; diff --git a/demoapps/DoseAcc/DoseAccHelper.h b/demoapps/DoseMap/DoseMapHelper.h similarity index 55% copy from demoapps/DoseAcc/DoseAccHelper.h copy to demoapps/DoseMap/DoseMapHelper.h index 7bfb6d7..b12ce94 100644 --- a/demoapps/DoseAcc/DoseAccHelper.h +++ b/demoapps/DoseMap/DoseMapHelper.h @@ -1,49 +1,58 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file -// @version $Revision$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) +// @version $Revision: 741 $ (last changed revision) +// @date $Date: 2014-09-16 16:34:22 +0200 (Di, 16 Sep 2014) $ (last change date) +// @author $Author: hentsch $ (last changed by) */ -#ifndef __DOSE_ACC_HELPER_H -#define __DOSE_ACC_HELPER_H +#ifndef __DOSE_MAP_HELPER_H +#define __DOSE_MAP_HELPER_H -#include "DoseAccApplicationData.h" +#include "DoseMapApplicationData.h" namespace rttb { namespace apps { - namespace doseAcc + namespace doseMap { + /**loads the dose from a file. Throws exception if loading fails*/ + core::DoseAccessorInterface::DoseAccessorPointer loadDose(const std::string& fileName, + const rttb::apps::doseMap::ApplicationData::LoadingStyleArgType& args); + + /**loads the dose from a file using the dicom dose generator. Throws exception if loading fails*/ + core::DoseAccessorInterface::DoseAccessorPointer loadDicomDose(const std::string& fileName); + /**loads the dose from a path using the helax io dose generator. Throws exception if loading fails*/ + core::DoseAccessorInterface::DoseAccessorPointer loadHelaxDose(const std::string& path); /**loads the dose from a file stored in an ITK supported data format. Throws exception if loading fails*/ - core::DoseAccessorInterface::DoseAccessorPointer loadDose(const std::string& fileName); + core::DoseAccessorInterface::DoseAccessorPointer loadITKDose(const std::string& fileName); /**loads the dose from a file stored in Virtuos data format. Throws exception if loading fails*/ - core::DoseAccessorInterface::DoseAccessorPointer loadVirtuosDose(const std::string& fileName, const std::string& planFileName); + core::DoseAccessorInterface::DoseAccessorPointer loadVirtuosDose(const std::string& fileName, + const std::string& planFileName); ApplicationData::RegistrationType::Pointer loadRegistration(const std::string& fileName); /**Containes the business logic for the accumulation of the doses and the storing of the result. Uses appData for the input data and the correct configuration.*/ void processData(ApplicationData& appData); } } } #endif diff --git a/demoapps/DoseMap/files.cmake b/demoapps/DoseMap/files.cmake new file mode 100644 index 0000000..69e97c4 --- /dev/null +++ b/demoapps/DoseMap/files.cmake @@ -0,0 +1,13 @@ +SET(CPP_FILES +DoseMap.cpp +DoseMapHelper.cpp +DoseMapApplicationData.cpp +) + +SET(H_FILES +DoseMapHelper.h +DoseMapApplicationData.h +) + +SET(TPP_FILES +) diff --git a/testing/algorithms/files.cmake b/testing/algorithms/files.cmake index 31ddd28..e056ae8 100644 --- a/testing/algorithms/files.cmake +++ b/testing/algorithms/files.cmake @@ -1,19 +1,20 @@ SET(CPP_FILES DoseStatisticsTest.cpp + DoseStatisticsCalculatorTest.cpp ArithmeticTest.cpp BinaryFunctorDoseAccessorTest.cpp rttbAlgorithmsTests.cpp #include dummy accessor files ../core/DummyDoseAccessor.cpp ../core/DummyMaskAccessor.cpp ../core/DummyMutableDoseAccessor.cpp ) SET(H_FILES #include dummy accessor files ../core/DummyDoseAccessor.h ../core/DummyMaskAccessor.h ../core/DummyMutableDoseAccessor.h ) diff --git a/testing/algorithms/rttbAlgorithmsTests.cpp b/testing/algorithms/rttbAlgorithmsTests.cpp index e03c3e9..69263f6 100644 --- a/testing/algorithms/rttbAlgorithmsTests.cpp +++ b/testing/algorithms/rttbAlgorithmsTests.cpp @@ -1,65 +1,66 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ // this file defines the rttbAlgorithmsTests for the test driver // and all it expects is that you have a function called RegisterTests #if defined(_MSC_VER) #pragma warning ( disable : 4786 ) #endif #include "litMultiTestsMain.h" namespace rttb { namespace testing { void registerTests() { LIT_REGISTER_TEST(DoseStatisticsTest); + LIT_REGISTER_TEST(DoseStatisticsCalculatorTest); LIT_REGISTER_TEST(ArithmeticTest); LIT_REGISTER_TEST(BinaryFunctorDoseAccessorTest); } } } int main(int argc, char* argv[]) { int result = 0; rttb::testing::registerTests(); try { result = lit::multiTestsMain(argc, argv); } catch (const std::exception& /*e*/) { result = -1; } catch (...) { result = -1; } return result; } diff --git a/testing/core/DummyDoseAccessor.h b/testing/core/DummyDoseAccessor.h index e1eaed0..241695a 100644 --- a/testing/core/DummyDoseAccessor.h +++ b/testing/core/DummyDoseAccessor.h @@ -1,80 +1,80 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DUMMY_DOSE_ACCESSOR_H #define __DUMMY_DOSE_ACCESSOR_H #include -#include "rttbDoseAccessorInterface.h" +#include "rttbDoseAccessorWithGeoInfoBase.h" #include "rttbGeometricInfo.h" #include "rttbBaseType.h" namespace rttb { - namespace testing - { + namespace testing + { - /*! @class DummyDoseAccessor - @brief A dummy DoseAccessor for testing filled with random dose values between 0 and 100. - The default grid size is [11,10,5] - */ - class DummyDoseAccessor: public core::DoseAccessorInterface - { + /*! @class DummyDoseAccessor + @brief A dummy DoseAccessor for testing filled with random dose values between 0 and 100. + The default grid size is [11,10,5] + */ + class DummyDoseAccessor: public core::DoseAccessorWithGeoInfoBase + { - private: - /*! vector of dose data(absolute Gy dose/doseGridScaling)*/ - std::vector doseData; + private: + /*! vector of dose data(absolute Gy dose/doseGridScaling)*/ + std::vector doseData; - IDType _doseUID; + IDType _doseUID; - public: - ~DummyDoseAccessor(); + public: + ~DummyDoseAccessor(); - /*! @brief A dummy DoseAccessor for testing filled with random dose values between 0 and 100. - The default grid size is [11,10,5] - */ - DummyDoseAccessor(); + /*! @brief A dummy DoseAccessor for testing filled with random dose values between 0 and 100. + The default grid size is [11,10,5] + */ + DummyDoseAccessor(); - /*! @brief Constructor. - Initialisation of dose with a given vector. - */ - DummyDoseAccessor(const std::vector& aDoseVector, const core::GeometricInfo& geoInfo); + /*! @brief Constructor. + Initialisation of dose with a given vector. + */ + DummyDoseAccessor(const std::vector& aDoseVector, const core::GeometricInfo& geoInfo); - const std::vector* getDoseVector() const - { - return &doseData; - }; + const std::vector* getDoseVector() const + { + return &doseData; + }; - DoseTypeGy getDoseAt(const VoxelGridID aID) const; + DoseTypeGy getDoseAt(const VoxelGridID aID) const; - DoseTypeGy getDoseAt(const VoxelGridIndex3D& aIndex) const; + DoseTypeGy getDoseAt(const VoxelGridIndex3D& aIndex) const; - const IDType getDoseUID() const - { - return _doseUID; - }; - }; - } + const IDType getDoseUID() const + { + return _doseUID; + }; + }; + } } #endif diff --git a/testing/core/DummyMutableDoseAccessor.cpp b/testing/core/DummyMutableDoseAccessor.cpp index a6acc72..3c4502b 100644 --- a/testing/core/DummyMutableDoseAccessor.cpp +++ b/testing/core/DummyMutableDoseAccessor.cpp @@ -1,113 +1,120 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include #include #include "DummyMutableDoseAccessor.h" #include "rttbNullPointerException.h" #include "rttbInvalidDoseException.h" #include "rttbIndexOutOfBoundsException.h" namespace rttb { - namespace testing - { - - DummyMutableDoseAccessor::~DummyMutableDoseAccessor() {} - - DummyMutableDoseAccessor::DummyMutableDoseAccessor() - { - boost::uuids::uuid id; - boost::uuids::random_generator generator; - id = generator(); - std::stringstream ss; - ss << id; - _doseUID = "DummyMutableDoseAccessor_" + ss.str(); - - SpacingVectorType3D aVector(2.5); - _geoInfo.setSpacing(aVector); - WorldCoordinate3D anOtherVector(-25, -2, 35); - _geoInfo.setImagePositionPatient(anOtherVector); - _geoInfo.setNumRows(11); - _geoInfo.setNumColumns(10); - _geoInfo.setNumSlices(5); - - OrientationMatrix unit = OrientationMatrix(); - _geoInfo.setOrientationMatrix(unit); - - for (int i = 0; i < _geoInfo.getNumberOfVoxels(); i++) - { - doseData.push_back((double(rand()) / RAND_MAX) * 1000); - } - } - - DummyMutableDoseAccessor::DummyMutableDoseAccessor(const std::vector& aDoseVector, - const core::GeometricInfo& geoInfo) - { - boost::uuids::uuid id; - boost::uuids::random_generator generator; - id = generator(); - std::stringstream ss; - ss << id; - _doseUID = "DummyMutableDoseAccessor_" + ss.str(); - - doseData = aDoseVector; - _geoInfo = geoInfo; - } - - DoseTypeGy DummyMutableDoseAccessor::getDoseAt(const VoxelGridID aID) const - { - if (!_geoInfo.validID(aID)) - { - throw core::IndexOutOfBoundsException("Not a valid Position!"); - } - - return doseData.at(aID); - } - - DoseTypeGy DummyMutableDoseAccessor::getDoseAt(const VoxelGridIndex3D& aIndex) const - { - VoxelGridID gridID = 0; - _geoInfo.convert(aIndex, gridID); - return getDoseAt(gridID); - } - - void DummyMutableDoseAccessor::setDoseAt(const VoxelGridID aID, DoseTypeGy value) - { - if (!_geoInfo.validID(aID)) - { - throw core::IndexOutOfBoundsException("Not a valid Position!"); - } - - doseData.at(aID) = value; - } - - void DummyMutableDoseAccessor::setDoseAt(const VoxelGridIndex3D& aIndex, DoseTypeGy value) - { - VoxelGridID gridID = 0; - _geoInfo.convert(aIndex, gridID); - setDoseAt(gridID, value); - } - - }//end namespace testing + namespace testing + { + + DummyMutableDoseAccessor::~DummyMutableDoseAccessor() {} + + DummyMutableDoseAccessor::DummyMutableDoseAccessor() + { + boost::uuids::uuid id; + boost::uuids::random_generator generator; + id = generator(); + std::stringstream ss; + ss << id; + _doseUID = "DummyMutableDoseAccessor_" + ss.str(); + + SpacingVectorType3D aVector(2.5); + _geoInfo.setSpacing(aVector); + WorldCoordinate3D anOtherVector(-25, -2, 35); + _geoInfo.setImagePositionPatient(anOtherVector); + _geoInfo.setNumRows(11); + _geoInfo.setNumColumns(10); + _geoInfo.setNumSlices(5); + + OrientationMatrix unit = OrientationMatrix(); + _geoInfo.setOrientationMatrix(unit); + + for (int i = 0; i < _geoInfo.getNumberOfVoxels(); i++) + { + doseData.push_back((double(rand()) / RAND_MAX) * 1000); + } + } + + DummyMutableDoseAccessor::DummyMutableDoseAccessor(const std::vector& aDoseVector, + const core::GeometricInfo& geoInfo) + { + boost::uuids::uuid id; + boost::uuids::random_generator generator; + id = generator(); + std::stringstream ss; + ss << id; + _doseUID = "DummyMutableDoseAccessor_" + ss.str(); + + doseData = aDoseVector; + _geoInfo = geoInfo; + } + + const core::GeometricInfo& + DummyMutableDoseAccessor:: + getGeometricInfo() const + { + return _geoInfo; + } + + DoseTypeGy DummyMutableDoseAccessor::getDoseAt(const VoxelGridID aID) const + { + if (!_geoInfo.validID(aID)) + { + throw core::IndexOutOfBoundsException("Not a valid Position!"); + } + + return doseData.at(aID); + } + + DoseTypeGy DummyMutableDoseAccessor::getDoseAt(const VoxelGridIndex3D& aIndex) const + { + VoxelGridID gridID = 0; + _geoInfo.convert(aIndex, gridID); + return getDoseAt(gridID); + } + + void DummyMutableDoseAccessor::setDoseAt(const VoxelGridID aID, DoseTypeGy value) + { + if (!_geoInfo.validID(aID)) + { + throw core::IndexOutOfBoundsException("Not a valid Position!"); + } + + doseData.at(aID) = value; + } + + void DummyMutableDoseAccessor::setDoseAt(const VoxelGridIndex3D& aIndex, DoseTypeGy value) + { + VoxelGridID gridID = 0; + _geoInfo.convert(aIndex, gridID); + setDoseAt(gridID, value); + } + + }//end namespace testing }//end namespace rttb \ No newline at end of file diff --git a/testing/core/DummyMutableDoseAccessor.h b/testing/core/DummyMutableDoseAccessor.h index 99bb819..496451e 100644 --- a/testing/core/DummyMutableDoseAccessor.h +++ b/testing/core/DummyMutableDoseAccessor.h @@ -1,85 +1,88 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #ifndef __DUMMY_MUTABLE_DOSE_ACCESSOR_H #define __DUMMY_MUTABLE_DOSE_ACCESSOR_H #include #include "rttbMutableDoseAccessorInterface.h" #include "rttbGeometricInfo.h" #include "rttbBaseType.h" namespace rttb { - namespace testing - { + namespace testing + { - /*! @class DummyMutableDoseAccessor - @brief A dummy MutableDoseAccessor for testing filled with random dose values between 0 and 100. - The default grid size is [11,10,5] - */ - class DummyMutableDoseAccessor: public core::MutableDoseAccessorInterface - { + /*! @class DummyMutableDoseAccessor + @brief A dummy MutableDoseAccessor for testing filled with random dose values between 0 and 100. + The default grid size is [11,10,5] + */ + class DummyMutableDoseAccessor: public core::MutableDoseAccessorInterface + { - private: - /*! vector of dose data(absolute Gy dose/doseGridScaling)*/ - std::vector doseData; + private: + /*! vector of dose data(absolute Gy dose/doseGridScaling)*/ + std::vector doseData; - IDType _doseUID; + IDType _doseUID; + core::GeometricInfo _geoInfo; - public: - ~DummyMutableDoseAccessor(); + public: + ~DummyMutableDoseAccessor(); - /*! @brief A dummy DummyMutableDoseAccessor for testing filled with random dose values between 0 and 100. - The default grid size is [11,10,5] - */ - DummyMutableDoseAccessor(); + /*! @brief A dummy DummyMutableDoseAccessor for testing filled with random dose values between 0 and 100. + The default grid size is [11,10,5] + */ + DummyMutableDoseAccessor(); - /*! @brief Constructor. - Initialisation of dose with a given vector. - */ - DummyMutableDoseAccessor(const std::vector& aDoseVector, - const core::GeometricInfo& geoInfo); + /*! @brief Constructor. + Initialisation of dose with a given vector. + */ + DummyMutableDoseAccessor(const std::vector& aDoseVector, + const core::GeometricInfo& geoInfo); - const std::vector* getDoseVector() const - { - return &doseData; - }; + const std::vector* getDoseVector() const + { + return &doseData; + }; - DoseTypeGy getDoseAt(const VoxelGridID aID) const; + virtual const core::GeometricInfo& getGeometricInfo() const; - DoseTypeGy getDoseAt(const VoxelGridIndex3D& aIndex) const; + DoseTypeGy getDoseAt(const VoxelGridID aID) const; - void setDoseAt(const VoxelGridID aID, DoseTypeGy value); + DoseTypeGy getDoseAt(const VoxelGridIndex3D& aIndex) const; - void setDoseAt(const VoxelGridIndex3D& aIndex, DoseTypeGy value); + void setDoseAt(const VoxelGridID aID, DoseTypeGy value); - const IDType getDoseUID() const - { - return _doseUID; - }; - }; - } + void setDoseAt(const VoxelGridIndex3D& aIndex, DoseTypeGy value); + + const IDType getDoseUID() const + { + return _doseUID; + }; + }; + } } #endif diff --git a/testing/examples/CMakeLists.txt b/testing/examples/CMakeLists.txt index 1bbd918..83e2a6f 100644 --- a/testing/examples/CMakeLists.txt +++ b/testing/examples/CMakeLists.txt @@ -1,42 +1,47 @@ #----------------------------------------------------------------------------- # Setup the system information test. Write out some basic failsafe # information in case the test doesn't run. #----------------------------------------------------------------------------- SET(CORE_TEST_EXAMPLES ${EXECUTABLE_OUTPUT_PATH}/rttbExamplesTests) SET(TEST_DATA_ROOT ${RTTBTesting_SOURCE_DIR}/data) SET(TEMP ${RTTBTesting_BINARY_DIR}/temporary) #----------------------------------------------------------------------------- ADD_TEST(RTBioModelExampleTest ${CORE_TEST_EXAMPLES} RTBioModelExampleTest "${TEST_DATA_ROOT}/TestDVH/dvh_PTV_HIT.txt" "${TEST_DATA_ROOT}/TestDVH/dvh_test_HT1.txt" "${TEST_DATA_ROOT}/TestDVH/dvh_test_HT2.txt" "${TEST_DATA_ROOT}/TestDVH/dvh_test_HT3.txt" "${TEST_DATA_ROOT}/TestDVH/dvh_test_TV.txt" "${TEST_DATA_ROOT}/Virtuos/MPM_LR_ah/dvh_diff_trunk6.txt" "${TEST_DATA_ROOT}/Virtuos/MPM_LR_ah/dvh_diff_trunk8.txt") ADD_TEST(DVHCalculatorExampleTest ${CORE_TEST_EXAMPLES} DVHCalculatorExampleTest "${TEST_DATA_ROOT}/DICOM/StructureSet/RS1.3.6.1.4.1.2452.6.841242143.1311652612.1170940299.4217870819.dcm" "${TEST_DATA_ROOT}/DICOM/TestDose/ConstantTwoGridScaling.dcm" "${TEST_DATA_ROOT}/DICOM/TestDose/ConstantTwoGridScaling05.dcm" "${TEST_DATA_ROOT}/DICOM/TestDose/ConstantFiftyGridScaling01.dcm") ADD_TEST(RTDoseIndexTest ${CORE_TEST_EXAMPLES} RTDoseIndexTest "${TEST_DATA_ROOT}/TestDVH/dvh_test_TV.txt" "${TEST_DATA_ROOT}/TestDVH/dvh_test_HT1.txt" "${TEST_DATA_ROOT}/TestDVH/dvh_test_HT2.txt" "${TEST_DATA_ROOT}/TestDVH/dvh_test_HT3.txt") ADD_TEST(RTDoseStatisticsTest ${CORE_TEST_EXAMPLES} RTDoseStatisticsTest "${TEST_DATA_ROOT}/DICOM/TestDose/ConstantTwo_withDoseGridScaling.dcm" "${TEST_DATA_ROOT}/Virtuos/MPM_LR_aa/MPM_LR_aa101.dos.gz" "${TEST_DATA_ROOT}/Virtuos/MPM_LR_aa/MPM_LR_aa000.vdx" "${TEST_DATA_ROOT}/Virtuos/MPM_LR_aa/MPM_LR_aa101.pln") ADD_TEST(RTDVHTest ${CORE_TEST_EXAMPLES} RTDVHTest "${TEST_DATA_ROOT}/TestDVH/dvh_test.txt") ADD_TEST(DVHCalculatorExampleTest ${CORE_TEST_EXAMPLES} DVHCalculatorExampleTest "${TEST_DATA_ROOT}/DICOM/StructureSet/RS1.3.6.1.4.1.2452.6.841242143.1311652612.1170940299.4217870819.dcm" "${TEST_DATA_ROOT}/DICOM/TestDose/ConstantTwo_withDoseGridScaling.dcm" "${TEST_DATA_ROOT}/DICOM/TestDose/LinearIncrease3D.dcm" "${TEST_DATA_ROOT}/DICOM/TestDose/LinearIncreaseX.dcm") ADD_TEST(RTBioModelScatterPlotExampleTest ${CORE_TEST_EXAMPLES} RTBioModelScatterPlotExampleTest "${TEST_DATA_ROOT}/TestDVH/dvh_PTV_HIT.txt" "${TEST_DATA_ROOT}/TestDVH/dvh_test_HT1.txt" "${TEST_DATA_ROOT}/TestDVH/dvh_test_TV.txt") ADD_TEST(VoxelizationValidationTest ${CORE_TEST_EXAMPLES} VoxelizationValidationTest "${TEST_DATA_ROOT}/DICOM/StructureSet/RS1.3.6.1.4.1.2452.6.841242143.1311652612.1170940299.4217870819.dcm" "${TEST_DATA_ROOT}/DICOM/TestDose/LinearIncrease3D.dcm" "${TEST_DATA_ROOT}/boostMask/" "${TEST_DATA_ROOT}/OTBMask/") +ADD_TEST(DoseStatisticsIOVirtuosTest ${CORE_TEST_EXAMPLES} DoseStatisticsIOVirtuosTest +"${TEST_DATA_ROOT}/Virtuos/MPM_LR_aa/MPM_LR_aa000.vdx" +"${TEST_DATA_ROOT}/Virtuos/MPM_LR_aa/MPM_LR_aa000.ctx.gz" +"${TEST_DATA_ROOT}/Virtuos/MPM_LR_aa/MPM_LR_aa101.dos.gz" +"${TEST_DATA_ROOT}/Virtuos/MPM_LR_aa/MPM_LR_aa101.pln" "CTV") -RTTB_CREATE_TEST_MODULE(rttbExamples DEPENDS RTTBCore RTTBAlgorithms RTTBMasks RTTBOTBMask RTTBBoostMask RTTBIndices RTTBDicomIO RTTBOtherIO RTTBModels PACKAGE_DEPENDS Litmus) +RTTB_CREATE_TEST_MODULE(rttbExamples DEPENDS RTTBCore RTTBAlgorithms RTTBMasks RTTBOTBMask RTTBBoostMask RTTBIndices RTTBDicomIO RTTBVirtuosIO RTTBOtherIO RTTBModels PACKAGE_DEPENDS Litmus) diff --git a/testing/examples/DoseStatisticsIOVirtuosTest.cpp b/testing/examples/DoseStatisticsIOVirtuosTest.cpp new file mode 100644 index 0000000..a7ef7a0 --- /dev/null +++ b/testing/examples/DoseStatisticsIOVirtuosTest.cpp @@ -0,0 +1,113 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notices for more information. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision: 922 $ (last changed revision) +// @date $Date: 2015-04-07 06:53:37 +0200 (Di, 07 Apr 2015) $ (last change date) +// @author $Author: hentsch $ (last changed by) +*/ + +// this file defines the rttbCoreTests for the test driver +// and all it expects is that you have a function called RegisterTests + +#include +#include + +#include "litCheckMacros.h" + +#include "rttbBaseType.h" +#include "rttbDoseStatistics.h" +#include "rttbDoseStatisticsCalculator.h" +#include "rttbDoseStatisticsXMLWriter.h" +#include "rttbGenericMaskedDoseIterator.h" +#include "rttbDoseIteratorInterface.h" +#include "rttbVirtuosPlanFileDoseAccessorGenerator.h" +#include "rttbVirtuosDoseAccessor.h" +#include "rttbVirtuosFileStructureSetGenerator.h" +#include "rttbBoostMaskAccessor.h" + + +namespace rttb +{ + + namespace testing + { + + /*! @brief OtherIOTest - test the IO for dose statistics + 1) test exception + 2) test writing statistics to xml file + */ + + int DoseStatisticsIOVirtuosTest(int argc, char* argv[]) + { + typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; + typedef core::DoseIteratorInterface::DoseIteratorPointer DoseIteratorPointer; + typedef core::StructureSetGeneratorInterface::StructureSetPointer StructureSetPointer; + typedef boost::shared_ptr DoseStatisticsPtr; + typedef core::MaskAccessorInterface::MaskAccessorPointer MaskAccessorPointer; + typedef boost::shared_ptr GeometricInfoPointer; + + PREPARE_DEFAULT_TEST_REPORTING; + + std::string Struct_FILENAME; + std::string BPLCT_FILENAME; + std::string Dose_FILENAME; + std::string Plan_FILENAME; + std::string Struct_NAME; + + if (argc > 5) + { + Struct_FILENAME = argv[1]; + BPLCT_FILENAME = argv[2]; + Dose_FILENAME = argv[3]; + Plan_FILENAME = argv[4]; + Struct_NAME = argv[5]; + } + else + { + std::cout << "at least 5 arguments are expected in DoseStatisticsIOVirtuosTest." << std::endl; + } + + /* generate dummy dose */ + io::virtuos::VirtuosPlanFileDoseAccessorGenerator doseAccessorGenerator(Dose_FILENAME.c_str(), Plan_FILENAME.c_str()); + + DoseAccessorPointer doseAccessor(doseAccessorGenerator.generateDoseAccessor()); + + StructureSetPointer rtStructureSet = io::virtuos::VirtuosFileStructureSetGenerator( + Struct_FILENAME.c_str(), BPLCT_FILENAME.c_str()).generateStructureSet(); + + GeometricInfoPointer geometricInfoPtr = boost::make_shared(doseAccessor->getGeometricInfo()); + MaskAccessorPointer maskAccessorPtr = boost::make_shared + (rtStructureSet->getStructure(3), doseAccessor->getGeometricInfo()); + maskAccessorPtr->updateMask(); + + boost::shared_ptr spTestDoseIterator = + boost::make_shared(maskAccessorPtr, doseAccessor); + DoseIteratorPointer spDoseIterator(spTestDoseIterator); + + rttb::algorithms::DoseStatisticsCalculator myDoseStatsCalculator(spDoseIterator); + rttb::algorithms::DoseStatistics::DoseStatisticsPointer doseStatistics = + myDoseStatsCalculator.calculateDoseStatistics(); + + /* test writing statistcs to xml file */ + FileNameString fN = "doseStatisticsVirtuos.xml"; + CHECK_NO_THROW(io::other::writeDoseStatistics(doseStatistics, fN)); + + RETURN_AND_REPORT_TEST_SUCCESS; + } + + }//testing +}//rttb + diff --git a/testing/examples/RTBioModelExampleTest.cpp b/testing/examples/RTBioModelExampleTest.cpp index 38acdf3..8b03060 100644 --- a/testing/examples/RTBioModelExampleTest.cpp +++ b/testing/examples/RTBioModelExampleTest.cpp @@ -1,374 +1,413 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include "litCheckMacros.h" #include "rttbBioModel.h" -#include "rttbDVHTxtFileReader.h" +#include "rttbDVHTxtFileReader.h" #include "rttbDVH.h" #include "rttbTCPLQModel.h" #include "rttbNTCPLKBModel.h" #include "rttbNTCPRSModel.h" #include "rttbBioModelScatterPlots.h" #include "rttbBioModelCurve.h" #include "rttbDvhBasedModels.h" #include "rttbDoseIteratorInterface.h" -namespace rttb{ - namespace testing{ +namespace rttb +{ + namespace testing + { - /*! @brief RTBioModelTest. - TCP calculated using a DVH PTV and LQ Model. + /*! @brief RTBioModelTest. + TCP calculated using a DVH PTV and LQ Model. NTCP tested using 3 Normal Tissue DVHs and LKB/RS Model. - Test if calculation in new architecture returns similar results to the + Test if calculation in new architecture returns similar results to the original implementation. WARNING: The values for comparison need to be adjusted if the input files are changed! */ - int RTBioModelExampleTest(int argc, char* argv[] ) + int RTBioModelExampleTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; typedef rttb::models::CurveDataType CurveDataType; - typedef std::multimap > ScatterPlotType; + typedef std::multimap > ScatterPlotType; typedef core::DVH::DVHPointer DVHPointer; //increased accuracy requires double values in the calculation (rttbBaseType.h) double toleranceEUD = 1e-5; double tolerance = 1e-7; //ARGUMENTS: 1: ptv dvh file name // 2: normal tissue 1 dvh file name // 3: normal tissue 2 dvh file name // 4: normal tissue 3 dvh file name //...........5: Virtuos MPM_LR_ah dvh lung file name //...........6: Virtuos MPM_LR_ah dvh target file name std::string DVH_FILENAME_PTV; std::string DVH_FILENAME_NT1; std::string DVH_FILENAME_NT2; std::string DVH_FILENAME_NT3; std::string DVH_FILENAME_TV_TEST; std::string DVH_Virtuos_Target; std::string DVH_Virtuos_Lung; - if (argc>1) + if (argc > 1) { DVH_FILENAME_PTV = argv[1]; } - if (argc>2) + + if (argc > 2) { DVH_FILENAME_NT1 = argv[2]; } - if (argc>3) + + if (argc > 3) { DVH_FILENAME_NT2 = argv[3]; } - if (argc>4) + + if (argc > 4) { DVH_FILENAME_NT3 = argv[4]; } - if (argc>5) + + if (argc > 5) { DVH_FILENAME_TV_TEST = argv[5]; } - if(argc>6) + + if (argc > 6) { - DVH_Virtuos_Lung=argv[6]; + DVH_Virtuos_Lung = argv[6]; } - if(argc>7) + + if (argc > 7) { - DVH_Virtuos_Target=argv[7]; + DVH_Virtuos_Target = argv[7]; } - //DVH PTV - rttb::io::other::DVHTxtFileReader dvhReader=rttb::io::other::DVHTxtFileReader(DVH_FILENAME_PTV); - DVHPointer dvhPtr=dvhReader.generateDVH(); + //DVH PTV + rttb::io::other::DVHTxtFileReader dvhReader = rttb::io::other::DVHTxtFileReader(DVH_FILENAME_PTV); + DVHPointer dvhPtr = dvhReader.generateDVH(); - CHECK_CLOSE(6.04759613161786830000e+001,models::getEUD(dvhPtr,10),toleranceEUD); + CHECK_CLOSE(6.04759613161786830000e+001, models::getEUD(dvhPtr, 10), toleranceEUD); - rttb::io::other::DVHTxtFileReader dvhReader_test_tv=rttb::io::other::DVHTxtFileReader(DVH_FILENAME_TV_TEST); - DVHPointer dvh_test_tv=dvhReader_test_tv.generateDVH(); + rttb::io::other::DVHTxtFileReader dvhReader_test_tv = rttb::io::other::DVHTxtFileReader(DVH_FILENAME_TV_TEST); + DVHPointer dvh_test_tv = dvhReader_test_tv.generateDVH(); //test TCP LQ Model models::BioModelParamType alpha = 0.35; models::BioModelParamType beta = 0.023333333333333; models::BioModelParamType roh = 10000000; int numFractions = 2; DoseTypeGy normalizationDose = 68; - rttb::models::TCPLQModel tcplq=rttb::models::TCPLQModel(dvhPtr,alpha, beta, roh, numFractions); - CHECK_EQUAL(alpha,tcplq.getAlphaMean()); - CHECK_EQUAL(alpha/beta,tcplq.getAlpahBeta()); - CHECK_EQUAL(roh,tcplq.getRho()); + rttb::models::TCPLQModel tcplq = rttb::models::TCPLQModel(dvhPtr, alpha, beta, roh, numFractions); + CHECK_EQUAL(alpha, tcplq.getAlphaMean()); + CHECK_EQUAL(alpha / beta, tcplq.getAlphaBeta()); + CHECK_EQUAL(roh, tcplq.getRho()); CHECK_NO_THROW(tcplq.init()); - if(tcplq.init()){ - CHECK_CLOSE(1.00497232941856940000e-127,tcplq.getValue(),tolerance); + + if (tcplq.init()) + { + CHECK_CLOSE(1.00497232941856940000e-127, tcplq.getValue(), tolerance); } - CurveDataType curve=models::getCurveDoseVSBioModel(tcplq,normalizationDose); + CurveDataType curve = models::getCurveDoseVSBioModel(tcplq, normalizationDose); CurveDataType::iterator it; - for(it=curve.begin();it!=curve.end();it++){ - if ((*it).first < 72){ - CHECK_EQUAL(0,(*it).second); + + for (it = curve.begin(); it != curve.end(); it++) + { + if ((*it).first < 72) + { + CHECK_EQUAL(0, (*it).second); } - else if ((*it).first >150){ - CHECK((*it).second>0.9); + else if ((*it).first > 150) + { + CHECK((*it).second > 0.9); } } models::BioModelParamType alphaBeta = 10; - tcplq.setParameters(alpha,alphaBeta,roh,0.08); - CHECK_EQUAL(alpha,tcplq.getAlphaMean()); - CHECK_EQUAL(alphaBeta,tcplq.getAlpahBeta()); - CHECK_EQUAL(roh,tcplq.getRho()); - if(tcplq.init()){ - CHECK_CLOSE(1.84e-005,tcplq.getValue(),tolerance); + tcplq.setParameters(alpha, alphaBeta, roh, 0.08); + CHECK_EQUAL(alpha, tcplq.getAlphaMean()); + CHECK_EQUAL(alphaBeta, tcplq.getAlphaBeta()); + CHECK_EQUAL(roh, tcplq.getRho()); + + if (tcplq.init()) + { + CHECK_CLOSE(1.84e-005, tcplq.getValue(), tolerance); } normalizationDose = 40; - curve=models::getCurveDoseVSBioModel(tcplq,normalizationDose); + curve = models::getCurveDoseVSBioModel(tcplq, normalizationDose); alpha = 1; alphaBeta = 14.5; tcplq.setAlpha(alpha); tcplq.setAlphaBeta(alphaBeta); tcplq.setRho(roh); - CHECK_EQUAL(alpha,tcplq.getAlphaMean()); - CHECK_EQUAL(alphaBeta,tcplq.getAlpahBeta()); - CHECK_EQUAL(roh,tcplq.getRho()); - if(tcplq.init()){ + CHECK_EQUAL(alpha, tcplq.getAlphaMean()); + CHECK_EQUAL(alphaBeta, tcplq.getAlphaBeta()); + CHECK_EQUAL(roh, tcplq.getRho()); + + if (tcplq.init()) + { CHECK_CLOSE(0.954885, tcplq.getValue(), toleranceEUD); } alpha = 0.9; alphaBeta = 1; tcplq.setAlpha(alpha); tcplq.setAlphaBeta(alphaBeta); tcplq.setRho(roh); - CHECK_EQUAL(alpha,tcplq.getAlphaMean()); - CHECK_EQUAL(alphaBeta,tcplq.getAlpahBeta()); - CHECK_EQUAL(roh,tcplq.getRho()); - if(tcplq.init()){ - CHECK_EQUAL(1,tcplq.getValue()); + CHECK_EQUAL(alpha, tcplq.getAlphaMean()); + CHECK_EQUAL(alphaBeta, tcplq.getAlphaBeta()); + CHECK_EQUAL(roh, tcplq.getRho()); + + if (tcplq.init()) + { + CHECK_EQUAL(1, tcplq.getValue()); } //TCP LQ Test alpha = 0.3; beta = 0.03; roh = 10000000; numFractions = 20; - rttb::models::TCPLQModel tcplq_test=rttb::models::TCPLQModel(dvh_test_tv,alpha, beta, roh, numFractions); - CHECK_EQUAL(alpha,tcplq_test.getAlphaMean()); - CHECK_EQUAL(alpha/beta,tcplq_test.getAlpahBeta()); - CHECK_EQUAL(roh,tcplq_test.getRho()); + rttb::models::TCPLQModel tcplq_test = rttb::models::TCPLQModel(dvh_test_tv, alpha, beta, roh, numFractions); + CHECK_EQUAL(alpha, tcplq_test.getAlphaMean()); + CHECK_EQUAL(alpha / beta, tcplq_test.getAlphaBeta()); + CHECK_EQUAL(roh, tcplq_test.getRho()); CHECK_NO_THROW(tcplq_test.init()); - if(tcplq_test.init()){ - CHECK_CLOSE(9.79050278878883180000e-001,tcplq_test.getValue(),tolerance); + + if (tcplq_test.init()) + { + CHECK_CLOSE(9.79050278878883180000e-001, tcplq_test.getValue(), tolerance); } + normalizationDose = 60; - curve=models::getCurveDoseVSBioModel(tcplq_test,normalizationDose); + curve = models::getCurveDoseVSBioModel(tcplq_test, normalizationDose); //DVH HT 1 - rttb::io::other::DVHTxtFileReader dvhReader2=rttb::io::other::DVHTxtFileReader(DVH_FILENAME_NT1); - DVHPointer dvhPtr2=dvhReader2.generateDVH(); + rttb::io::other::DVHTxtFileReader dvhReader2 = rttb::io::other::DVHTxtFileReader(DVH_FILENAME_NT1); + DVHPointer dvhPtr2 = dvhReader2.generateDVH(); - CHECK_CLOSE(1.07920836034015810000e+001,models::getEUD(dvhPtr2,10),toleranceEUD); + CHECK_CLOSE(1.07920836034015810000e+001, models::getEUD(dvhPtr2, 10), toleranceEUD); //test RTNTCPLKBModel - rttb::models::NTCPLKBModel lkb=rttb::models::NTCPLKBModel(); + rttb::models::NTCPLKBModel lkb = rttb::models::NTCPLKBModel(); models::BioModelParamType aVal = 10; models::BioModelParamType mVal = 0.16; models::BioModelParamType d50Val = 55; - CHECK_EQUAL(0,lkb.getA()); - CHECK_EQUAL(0,lkb.getM()); - CHECK_EQUAL(0,lkb.getD50()); + CHECK_EQUAL(0, lkb.getA()); + CHECK_EQUAL(0, lkb.getM()); + CHECK_EQUAL(0, lkb.getD50()); lkb.setDVH(dvhPtr2); - CHECK_EQUAL(dvhPtr2,lkb.getDVH()); + CHECK_EQUAL(dvhPtr2, lkb.getDVH()); lkb.setA(aVal); - CHECK_EQUAL(aVal,lkb.getA()); + CHECK_EQUAL(aVal, lkb.getA()); lkb.setM(mVal); - CHECK_EQUAL(mVal,lkb.getM()); + CHECK_EQUAL(mVal, lkb.getM()); lkb.setD50(d50Val); - CHECK_EQUAL(d50Val,lkb.getD50()); + CHECK_EQUAL(d50Val, lkb.getD50()); CHECK_NO_THROW(lkb.init()); - if(lkb.init()){ - CHECK_CLOSE(2.53523522831366570000e-007,lkb.getValue(),tolerance); + + if (lkb.init()) + { + CHECK_CLOSE(2.53523522831366570000e-007, lkb.getValue(), tolerance); } //test RTNTCPRSModel - rttb::models::NTCPRSModel rs=rttb::models::NTCPRSModel(); + rttb::models::NTCPRSModel rs = rttb::models::NTCPRSModel(); models::BioModelParamType gammaVal = 1.7; models::BioModelParamType sVal = 1; - CHECK_EQUAL(0,rs.getGamma()); - CHECK_EQUAL(0,rs.getS()); - CHECK_EQUAL(0,rs.getD50()); + CHECK_EQUAL(0, rs.getGamma()); + CHECK_EQUAL(0, rs.getS()); + CHECK_EQUAL(0, rs.getD50()); rs.setDVH(dvhPtr2); - CHECK_EQUAL(dvhPtr2,rs.getDVH()); + CHECK_EQUAL(dvhPtr2, rs.getDVH()); rs.setD50(d50Val); - CHECK_EQUAL(d50Val,rs.getD50()); + CHECK_EQUAL(d50Val, rs.getD50()); rs.setGamma(gammaVal); - CHECK_EQUAL(gammaVal,rs.getGamma()); + CHECK_EQUAL(gammaVal, rs.getGamma()); rs.setS(sVal); - CHECK_EQUAL(sVal,rs.getS()); + CHECK_EQUAL(sVal, rs.getS()); CHECK_NO_THROW(rs.init()); - if(rs.init()){ - CHECK_CLOSE(3.70385888626145740000e-009,rs.getValue(),tolerance); + + if (rs.init()) + { + CHECK_CLOSE(3.70385888626145740000e-009, rs.getValue(), tolerance); } //DVH HT 2 - rttb::io::other::DVHTxtFileReader dvhReader3=rttb::io::other::DVHTxtFileReader(DVH_FILENAME_NT2); - DVHPointer dvhPtr3=dvhReader3.generateDVH(); - CHECK_CLOSE(1.26287047025885110000e+001,models::getEUD(dvhPtr3,10),toleranceEUD); + rttb::io::other::DVHTxtFileReader dvhReader3 = rttb::io::other::DVHTxtFileReader(DVH_FILENAME_NT2); + DVHPointer dvhPtr3 = dvhReader3.generateDVH(); + CHECK_CLOSE(1.26287047025885110000e+001, models::getEUD(dvhPtr3, 10), toleranceEUD); //test RTNTCPLKBModel aVal = 10; mVal = 0.16; d50Val = 55; lkb.setDVH(dvhPtr3); - CHECK_EQUAL(dvhPtr3,lkb.getDVH()); + CHECK_EQUAL(dvhPtr3, lkb.getDVH()); lkb.setA(aVal); - CHECK_EQUAL(aVal,lkb.getA()); + CHECK_EQUAL(aVal, lkb.getA()); lkb.setM(mVal); - CHECK_EQUAL(mVal,lkb.getM()); + CHECK_EQUAL(mVal, lkb.getM()); lkb.setD50(d50Val); - CHECK_EQUAL(d50Val,lkb.getD50()); - if(lkb.init()){ - CHECK_CLOSE(7.36294657754956700000e-007,lkb.getValue(),tolerance); + CHECK_EQUAL(d50Val, lkb.getD50()); + + if (lkb.init()) + { + CHECK_CLOSE(7.36294657754956700000e-007, lkb.getValue(), tolerance); } //test RTNTCPRSModel - rs=rttb::models::NTCPRSModel(); + rs = rttb::models::NTCPRSModel(); gammaVal = 1.7; sVal = 1; - CHECK_EQUAL(0,rs.getGamma()); - CHECK_EQUAL(0,rs.getS()); - CHECK_EQUAL(0,rs.getD50()); + CHECK_EQUAL(0, rs.getGamma()); + CHECK_EQUAL(0, rs.getS()); + CHECK_EQUAL(0, rs.getD50()); rs.setDVH(dvhPtr3); - CHECK_EQUAL(dvhPtr3,rs.getDVH()); + CHECK_EQUAL(dvhPtr3, rs.getDVH()); rs.setD50(d50Val); - CHECK_EQUAL(d50Val,rs.getD50()); + CHECK_EQUAL(d50Val, rs.getD50()); rs.setGamma(gammaVal); - CHECK_EQUAL(gammaVal,rs.getGamma()); + CHECK_EQUAL(gammaVal, rs.getGamma()); rs.setS(sVal); - CHECK_EQUAL(sVal,rs.getS()); - if(rs.init()){ - CHECK_CLOSE(1.76778795490939440000e-007,rs.getValue(),tolerance); + CHECK_EQUAL(sVal, rs.getS()); + + if (rs.init()) + { + CHECK_CLOSE(1.76778795490939440000e-007, rs.getValue(), tolerance); } //DVH HT 3 - rttb::io::other::DVHTxtFileReader dvhReader4=rttb::io::other::DVHTxtFileReader(DVH_FILENAME_NT3); - DVHPointer dvhPtr4=dvhReader4.generateDVH(); - CHECK_CLOSE(2.18212982041056310000e+001,models::getEUD(dvhPtr4,10),toleranceEUD); + rttb::io::other::DVHTxtFileReader dvhReader4 = rttb::io::other::DVHTxtFileReader(DVH_FILENAME_NT3); + DVHPointer dvhPtr4 = dvhReader4.generateDVH(); + CHECK_CLOSE(2.18212982041056310000e+001, models::getEUD(dvhPtr4, 10), toleranceEUD); //test RTNTCPLKBModel aVal = 10; mVal = 0.16; d50Val = 55; lkb.setDVH(dvhPtr4); - CHECK_EQUAL(dvhPtr4,lkb.getDVH()); + CHECK_EQUAL(dvhPtr4, lkb.getDVH()); lkb.setA(aVal); - CHECK_EQUAL(aVal,lkb.getA()); + CHECK_EQUAL(aVal, lkb.getA()); lkb.setM(mVal); - CHECK_EQUAL(mVal,lkb.getM()); + CHECK_EQUAL(mVal, lkb.getM()); lkb.setD50(d50Val); - CHECK_EQUAL(d50Val,lkb.getD50()); - if(lkb.init()){ - CHECK_CLOSE(8.15234192641929420000e-005,lkb.getValue(),tolerance); + CHECK_EQUAL(d50Val, lkb.getD50()); + + if (lkb.init()) + { + CHECK_CLOSE(8.15234192641929420000e-005, lkb.getValue(), tolerance); } //test RTNTCPRSModel - rs=rttb::models::NTCPRSModel(); + rs = rttb::models::NTCPRSModel(); gammaVal = 1.7; sVal = 1; - CHECK_EQUAL(0,rs.getGamma()); - CHECK_EQUAL(0,rs.getS()); - CHECK_EQUAL(0,rs.getD50()); + CHECK_EQUAL(0, rs.getGamma()); + CHECK_EQUAL(0, rs.getS()); + CHECK_EQUAL(0, rs.getD50()); rs.setDVH(dvhPtr4); - CHECK_EQUAL(dvhPtr4,rs.getDVH()); + CHECK_EQUAL(dvhPtr4, rs.getDVH()); rs.setD50(d50Val); - CHECK_EQUAL(d50Val,rs.getD50()); + CHECK_EQUAL(d50Val, rs.getD50()); rs.setGamma(gammaVal); - CHECK_EQUAL(gammaVal,rs.getGamma()); + CHECK_EQUAL(gammaVal, rs.getGamma()); rs.setS(sVal); - CHECK_EQUAL(sVal,rs.getS()); - if(rs.init()){ - CHECK_CLOSE(2.02607985020919480000e-004,rs.getValue(),tolerance); + CHECK_EQUAL(sVal, rs.getS()); + + if (rs.init()) + { + CHECK_CLOSE(2.02607985020919480000e-004, rs.getValue(), tolerance); } //test using Virtuos Pleuramesotheliom MPM_LR_ah - //DVH PTV + //DVH PTV - rttb::io::other::DVHTxtFileReader dR_Target=rttb::io::other::DVHTxtFileReader(DVH_Virtuos_Target); - DVHPointer dvhPtrTarget=dR_Target.generateDVH(); + rttb::io::other::DVHTxtFileReader dR_Target = rttb::io::other::DVHTxtFileReader(DVH_Virtuos_Target); + DVHPointer dvhPtrTarget = dR_Target.generateDVH(); - rttb::io::other::DVHTxtFileReader dR_Lung=rttb::io::other::DVHTxtFileReader(DVH_Virtuos_Lung); - DVHPointer dvhPtrLung=dR_Lung.generateDVH(); + rttb::io::other::DVHTxtFileReader dR_Lung = rttb::io::other::DVHTxtFileReader(DVH_Virtuos_Lung); + DVHPointer dvhPtrLung = dR_Lung.generateDVH(); //test TCP LQ Model models::BioModelParamType alphaMean = 0.34; - models::BioModelParamType alphaVarianz=0.02; + models::BioModelParamType alphaVarianz = 0.02; models::BioModelParamType alpha_beta = 28; models::BioModelParamType rho = 1200; int numFractionsVirtuos = 27; - rttb::models::TCPLQModel tcplqVirtuos=rttb::models::TCPLQModel(dvhPtrTarget,rho,numFractionsVirtuos,alpha_beta,alphaMean,alphaVarianz); - if(tcplqVirtuos.init()) + rttb::models::TCPLQModel tcplqVirtuos = rttb::models::TCPLQModel(dvhPtrTarget, rho, numFractionsVirtuos, alpha_beta, + alphaMean, alphaVarianz); + + if (tcplqVirtuos.init()) { - CHECK_CLOSE(0.8894,tcplqVirtuos.getValue(),1e-4); + CHECK_CLOSE(0.8894, tcplqVirtuos.getValue(), 1e-4); } - models::BioModelParamType d50Mean=20; - models::BioModelParamType d50Varianz=2; - models::BioModelParamType m=0.36; - models::BioModelParamType a=1.06; + models::BioModelParamType d50Mean = 20; + models::BioModelParamType d50Varianz = 2; + models::BioModelParamType m = 0.36; + models::BioModelParamType a = 1.06; - rttb::models::NTCPLKBModel lkbVirtuos=rttb::models::NTCPLKBModel(dvhPtrLung,d50Mean,m,a); - if(lkbVirtuos.init()){ - CHECK_CLOSE(0.0397,lkbVirtuos.getValue(),1e-4); + rttb::models::NTCPLKBModel lkbVirtuos = rttb::models::NTCPLKBModel(dvhPtrLung, d50Mean, m, a); + + if (lkbVirtuos.init()) + { + CHECK_CLOSE(0.0397, lkbVirtuos.getValue(), 1e-4); } RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb \ No newline at end of file diff --git a/testing/examples/RTBioModelScatterPlotExampleTest.cpp b/testing/examples/RTBioModelScatterPlotExampleTest.cpp index ac78bd8..4cefe2f 100644 --- a/testing/examples/RTBioModelScatterPlotExampleTest.cpp +++ b/testing/examples/RTBioModelScatterPlotExampleTest.cpp @@ -1,480 +1,480 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include "litCheckMacros.h" #include "rttbBioModel.h" #include "rttbDVHTxtFileReader.h" #include "rttbDVH.h" #include "rttbTCPLQModel.h" #include "rttbNTCPLKBModel.h" #include "rttbNTCPRSModel.h" #include "rttbBioModelScatterPlots.h" #include "rttbBioModelCurve.h" #include "rttbDvhBasedModels.h" #include "../models/rttbScatterTester.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace testing { /*! @brief RTBioModelScatterPlotExampleTest. calculating Curves and Scatterplots for TCP and NTCP models. The values on curve and scatterplot need to be similar for similar dose values. The range of difference is given by the variance used to generate the scatter. WARNING: The values for comparison need to be adjusted if the input files are changed! */ int RTBioModelScatterPlotExampleTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; typedef rttb::models::CurveDataType CurveDataType; typedef rttb::models::ScatterPlotType ScatterPlotType; typedef core::DVH::DVHPointer DVHPointer; //increased accuracy requires double values in the calculation (rttbBaseType.h) double toleranceEUD = 1e-5; double tolerance = 1e-7; //ARGUMENTS: 1: ptv dvh file name // 2: normal tissue 1 dvh file name // 3: TV dvh file name std::string DVH_FILENAME_PTV; std::string DVH_FILENAME_NT1; std::string DVH_FILENAME_TV_TEST; if (argc > 1) { DVH_FILENAME_PTV = argv[1]; } if (argc > 2) { DVH_FILENAME_NT1 = argv[2]; } if (argc > 3) { DVH_FILENAME_TV_TEST = argv[3]; } //DVH PTV rttb::io::other::DVHTxtFileReader dvhReader = rttb::io::other::DVHTxtFileReader(DVH_FILENAME_PTV); DVHPointer dvhPtr = dvhReader.generateDVH(); rttb::io::other::DVHTxtFileReader dvhReader_test_tv = rttb::io::other::DVHTxtFileReader( DVH_FILENAME_TV_TEST); DVHPointer dvh_test_tv = dvhReader_test_tv.generateDVH(); //test TCP LQ Model models::BioModelParamType alpha = 0.35; models::BioModelParamType beta = 0.023333333333333; models::BioModelParamType roh = 10000000; int numFractions = 2; DoseTypeGy normalizationDose = 68; rttb::models::TCPLQModel tcplq = rttb::models::TCPLQModel(dvhPtr, alpha, beta, roh, numFractions); CHECK_NO_THROW(tcplq.init()); CurveDataType curve = models::getCurveDoseVSBioModel(tcplq, normalizationDose); CHECK_NO_THROW(models::getScatterPlotVary1Parameter(tcplq, 0, alpha, 0, normalizationDose, 100)); ScatterPlotType tcpScatter = models::getScatterPlotVary1Parameter(tcplq, 0, alpha, 0, normalizationDose, 100); CHECK_EQUAL(100, tcpScatter.size()); ScatterTester scatterCompare(curve, tcpScatter); CHECK_TESTER(scatterCompare); //test also with other parameter tcpScatter = models::getScatterPlotVary1Parameter(tcplq, 3, roh, 0, normalizationDose, 100); scatterCompare.setCompareScatter(tcpScatter); CHECK_TESTER(scatterCompare); std::vector paramIdVec; models::BioModel::ParamVectorType meanVec; models::BioModel::ParamVectorType meanVecTest; meanVecTest.push_back(alpha); models::BioModel::ParamVectorType varianceVec; //"alphaMean":0,"alphaVariance":1,"alpha_beta":2, "rho":3 paramIdVec.push_back(0); meanVec.push_back(tcplq.getAlphaMean()); varianceVec.push_back(0); //setting parameter 1 will change the resulting scatter plot dramatically - is it meant to? //this is unexpected since the value was taken from the original calculation //paramIdVec.push_back(1); meanVec.push_back(tcplq.getAlphaVariance()); varianceVec.push_back(0); paramIdVec.push_back(2); - meanVec.push_back(tcplq.getAlpahBeta()); + meanVec.push_back(tcplq.getAlphaBeta()); varianceVec.push_back(0); paramIdVec.push_back(3); meanVec.push_back(tcplq.getRho()); varianceVec.push_back(0); CHECK_THROW_EXPLICIT(models::getScatterPlotVaryParameters(tcplq, paramIdVec, meanVecTest, varianceVec, normalizationDose, 50), core::InvalidParameterException); ScatterPlotType scatterVary = models::getScatterPlotVaryParameters(tcplq, paramIdVec, meanVec, varianceVec, normalizationDose, 50); CHECK_EQUAL(50, scatterVary.size()); scatterCompare.setCompareScatter(scatterVary); CHECK_TESTER(scatterCompare); models::BioModelParamType variance = 0.00015; CHECK_NO_THROW(models::getScatterPlotVary1Parameter(tcplq, 0, alpha, variance, normalizationDose, 100)); tcpScatter = models::getScatterPlotVary1Parameter(tcplq, 0, alpha, variance, normalizationDose, 100); scatterCompare.setVariance(variance); scatterCompare.setCompareScatter(tcpScatter); //allow 5% of the points to deviate more scatterCompare.setAllowExceptions(true); CHECK_TESTER(scatterCompare); //test also with other parameter tcpScatter = models::getScatterPlotVary1Parameter(tcplq, 3, roh, variance, normalizationDose, 100); scatterCompare.setCompareScatter(tcpScatter); //allow 5% of the points to deviate more scatterCompare.setAllowExceptions(true); CHECK_TESTER(scatterCompare); paramIdVec.clear(); meanVec.clear(); varianceVec.clear(); paramIdVec.push_back(0); meanVec.push_back(tcplq.getAlphaMean()); varianceVec.push_back(variance); //paramIdVec.push_back(1); meanVec.push_back(tcplq.getAlphaVariance()); varianceVec.push_back(variance); paramIdVec.push_back(2); - meanVec.push_back(tcplq.getAlpahBeta()); + meanVec.push_back(tcplq.getAlphaBeta()); varianceVec.push_back(variance); paramIdVec.push_back(3); meanVec.push_back(tcplq.getRho()); varianceVec.push_back(variance); scatterVary = models::getScatterPlotVaryParameters(tcplq, paramIdVec, meanVec, varianceVec, normalizationDose, 50); scatterCompare.setCompareScatter(scatterVary); //allow 5% of the points to deviate more scatterCompare.setAllowExceptions(true); CHECK_TESTER(scatterCompare); models::BioModelParamType alphaBeta = 10; tcplq.setParameters(alpha, alphaBeta, roh, 0.08); tcplq.init(); normalizationDose = 40; curve = models::getCurveDoseVSBioModel(tcplq, normalizationDose); CHECK_NO_THROW(models::getScatterPlotVary1Parameter(tcplq, 0, alpha, 0, normalizationDose, 100)); tcpScatter = models::getScatterPlotVary1Parameter(tcplq, 0, alpha, 0, normalizationDose, 100); scatterCompare.setReferenceCurve(curve); scatterCompare.setVariance(0); //do not allow larger deviations scatterCompare.setAllowExceptions(false); scatterCompare.setCompareScatter(tcpScatter); CHECK_TESTER(scatterCompare); variance = 0.25; CHECK_NO_THROW(models::getScatterPlotVary1Parameter(tcplq, 0, alpha, variance, normalizationDose, 100)); tcpScatter = models::getScatterPlotVary1Parameter(tcplq, 0, alpha, variance, normalizationDose, 100); scatterCompare.setCompareScatter(tcpScatter); scatterCompare.setVariance(variance); //allow 5% of the points to deviate more scatterCompare.setAllowExceptions(true); CHECK_TESTER(scatterCompare); /*TCP LQ Test*/ alpha = 0.3; beta = 0.03; roh = 10000000; numFractions = 20; rttb::models::TCPLQModel tcplq_test = rttb::models::TCPLQModel(dvh_test_tv, alpha, beta, roh, numFractions); CHECK_NO_THROW(tcplq_test.init()); normalizationDose = 60; curve = models::getCurveDoseVSBioModel(tcplq_test, normalizationDose); CHECK_NO_THROW(models::getScatterPlotVary1Parameter(tcplq_test, 0, alpha, 0, normalizationDose, 100)); tcpScatter = models::getScatterPlotVary1Parameter(tcplq_test, 0, alpha, 0, normalizationDose, 100); scatterCompare.setReferenceCurve(curve); scatterCompare.setVariance(0); scatterCompare.setCompareScatter(tcpScatter); CHECK_TESTER(scatterCompare); //test also with other parameter tcpScatter = models::getScatterPlotVary1Parameter(tcplq_test, 3, roh, 0, normalizationDose, 100); scatterCompare.setCompareScatter(tcpScatter); CHECK_TESTER(scatterCompare); paramIdVec.clear(); meanVec.clear(); varianceVec.clear(); paramIdVec.push_back(0); meanVec.push_back(tcplq_test.getAlphaMean()); varianceVec.push_back(0); //paramIdVec.push_back(1); meanVec.push_back(tcplq_test.getAlphaVariance()); varianceVec.push_back(0); paramIdVec.push_back(2); - meanVec.push_back(tcplq_test.getAlpahBeta()); + meanVec.push_back(tcplq_test.getAlphaBeta()); varianceVec.push_back(0); paramIdVec.push_back(3); meanVec.push_back(tcplq_test.getRho()); varianceVec.push_back(0); scatterVary = models::getScatterPlotVaryParameters(tcplq_test, paramIdVec, meanVec, varianceVec, normalizationDose, 50); scatterCompare.setCompareScatter(scatterVary); CHECK_TESTER(scatterCompare); variance = 0.00025; CHECK_NO_THROW(models::getScatterPlotVary1Parameter(tcplq_test, 0, alpha, variance, normalizationDose, 100)); tcpScatter = models::getScatterPlotVary1Parameter(tcplq_test, 0, alpha, variance, normalizationDose, 100); scatterCompare.setCompareScatter(tcpScatter); scatterCompare.setVariance(variance); CHECK_TESTER(scatterCompare); //test also with other parameter tcpScatter = models::getScatterPlotVary1Parameter(tcplq_test, 3, roh, variance, normalizationDose, 100); scatterCompare.setCompareScatter(tcpScatter); scatterCompare.setAllowExceptions(true); CHECK_TESTER(scatterCompare); scatterCompare.setAllowExceptions(false); paramIdVec.clear(); meanVec.clear(); varianceVec.clear(); paramIdVec.push_back(0); meanVec.push_back(tcplq_test.getAlphaMean()); varianceVec.push_back(variance); //paramIdVec.push_back(1); meanVec.push_back(tcplq_test.getAlphaVariance()); varianceVec.push_back(variance); paramIdVec.push_back(2); - meanVec.push_back(tcplq_test.getAlpahBeta()); + meanVec.push_back(tcplq_test.getAlphaBeta()); varianceVec.push_back(variance); paramIdVec.push_back(3); meanVec.push_back(tcplq_test.getRho()); varianceVec.push_back(variance); scatterVary = models::getScatterPlotVaryParameters(tcplq_test, paramIdVec, meanVec, varianceVec, normalizationDose, 50); scatterCompare.setCompareScatter(scatterVary); //allow 5% of the points to deviate more scatterCompare.setAllowExceptions(true); CHECK_TESTER(scatterCompare); //DVH HT 1 rttb::io::other::DVHTxtFileReader dvhReader2 = rttb::io::other::DVHTxtFileReader(DVH_FILENAME_NT1); DVHPointer dvhPtr2 = dvhReader2.generateDVH(); CHECK_CLOSE(1.07920836034015810000e+001, models::getEUD(dvhPtr2, 10), toleranceEUD); //test RTNTCPLKBModel rttb::models::NTCPLKBModel lkb = rttb::models::NTCPLKBModel(); models::BioModelParamType aVal = 10; models::BioModelParamType mVal = 0.16; models::BioModelParamType d50Val = 55; lkb.setDVH(dvhPtr2); lkb.setA(aVal); lkb.setM(mVal); lkb.setD50(d50Val); CHECK_NO_THROW(lkb.init()); normalizationDose = 60; curve = models::getCurveDoseVSBioModel(lkb, normalizationDose); CHECK_NO_THROW(models::getScatterPlotVary1Parameter(lkb, 2, aVal, 0, normalizationDose, 100)); ScatterPlotType scatter = models::getScatterPlotVary1Parameter(lkb, 2, aVal, 0, normalizationDose, 100); scatterCompare.setReferenceCurve(curve); scatterCompare.setVariance(0); scatterCompare.setCompareScatter(scatter); CHECK_TESTER(scatterCompare); //"d50":0,"m":1,"a":2 //test also with other parameter scatter = models::getScatterPlotVary1Parameter(lkb, 0, d50Val, 0, normalizationDose, 100); scatterCompare.setCompareScatter(scatter); CHECK_TESTER(scatterCompare); paramIdVec.clear(); meanVec.clear(); varianceVec.clear(); paramIdVec.push_back(0); meanVec.push_back(lkb.getD50()); varianceVec.push_back(0); paramIdVec.push_back(1); meanVec.push_back(lkb.getM()); varianceVec.push_back(0); paramIdVec.push_back(2); meanVec.push_back(lkb.getA()); varianceVec.push_back(0); scatterVary = models::getScatterPlotVaryParameters(lkb, paramIdVec, meanVec, varianceVec, normalizationDose, 50); scatterCompare.setCompareScatter(scatterVary); CHECK_TESTER(scatterCompare); variance = 0.00025; CHECK_NO_THROW(models::getScatterPlotVary1Parameter(lkb, 2, aVal, variance, normalizationDose, 100)); scatter = models::getScatterPlotVary1Parameter(lkb, 2, aVal, variance, normalizationDose, 100); scatterCompare.setCompareScatter(scatter); scatterCompare.setVariance(variance); CHECK_TESTER(scatterCompare); //test also with other parameter scatter = models::getScatterPlotVary1Parameter(lkb, 0, d50Val, variance, normalizationDose, 100); scatterCompare.setCompareScatter(scatter); CHECK_TESTER(scatterCompare); paramIdVec.clear(); meanVec.clear(); varianceVec.clear(); paramIdVec.push_back(0); meanVec.push_back(lkb.getD50()); varianceVec.push_back(variance); paramIdVec.push_back(1); meanVec.push_back(lkb.getM()); varianceVec.push_back(variance); paramIdVec.push_back(2); meanVec.push_back(lkb.getA()); varianceVec.push_back(variance); scatterVary = models::getScatterPlotVaryParameters(lkb, paramIdVec, meanVec, varianceVec, normalizationDose, 50); scatterCompare.setCompareScatter(scatterVary); CHECK_TESTER(scatterCompare); //test RTNTCPRSModel rttb::models::NTCPRSModel rs = rttb::models::NTCPRSModel(); models::BioModelParamType gammaVal = 1.7; models::BioModelParamType sVal = 1; rs.setDVH(dvhPtr2); rs.setD50(d50Val); rs.setGamma(gammaVal); rs.setS(sVal); CHECK_NO_THROW(rs.init()); normalizationDose = 60; curve = models::getCurveDoseVSBioModel(rs, normalizationDose); CHECK_NO_THROW(models::getScatterPlotVary1Parameter(rs, 0, d50Val, 0, normalizationDose, 100)); scatter = models::getScatterPlotVary1Parameter(rs, 0, d50Val, 0, normalizationDose, 100); scatterCompare.setReferenceCurve(curve); scatterCompare.setVariance(0); scatterCompare.setCompareScatter(scatter); CHECK_TESTER(scatterCompare); //"d50":0,"gamma":1,"s":2 //test also with other parameter scatter = models::getScatterPlotVary1Parameter(rs, 1, gammaVal, 0, normalizationDose, 100); scatterCompare.setCompareScatter(scatter); CHECK_TESTER(scatterCompare); paramIdVec.clear(); meanVec.clear(); varianceVec.clear(); paramIdVec.push_back(0); meanVec.push_back(rs.getD50()); varianceVec.push_back(0); paramIdVec.push_back(1); meanVec.push_back(rs.getGamma()); varianceVec.push_back(0); paramIdVec.push_back(2); meanVec.push_back(rs.getS()); varianceVec.push_back(0); scatterVary = models::getScatterPlotVaryParameters(rs, paramIdVec, meanVec, varianceVec, normalizationDose, 50); scatterCompare.setCompareScatter(scatterVary); CHECK_TESTER(scatterCompare); variance = 0.0075; CHECK_NO_THROW(models::getScatterPlotVary1Parameter(rs, 0, d50Val, variance, normalizationDose, 100)); scatter = models::getScatterPlotVary1Parameter(rs, 0, d50Val, variance, normalizationDose, 100); scatterCompare.setCompareScatter(scatter); scatterCompare.setVariance(variance); CHECK_TESTER(scatterCompare); //test also with other parameter scatter = models::getScatterPlotVary1Parameter(rs, 2, sVal, variance, normalizationDose, 100); scatterCompare.setCompareScatter(scatter); CHECK_TESTER(scatterCompare); paramIdVec.clear(); meanVec.clear(); varianceVec.clear(); paramIdVec.push_back(0); meanVec.push_back(rs.getD50()); varianceVec.push_back(variance); paramIdVec.push_back(1); meanVec.push_back(rs.getGamma()); varianceVec.push_back(variance); paramIdVec.push_back(2); meanVec.push_back(rs.getS()); varianceVec.push_back(variance); scatterVary = models::getScatterPlotVaryParameters(rs, paramIdVec, meanVec, varianceVec, normalizationDose, 50); scatterCompare.setCompareScatter(scatterVary); CHECK_TESTER(scatterCompare); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb \ No newline at end of file diff --git a/testing/examples/RTDoseStatisticsTest.cpp b/testing/examples/RTDoseStatisticsTest.cpp index 5a1a8e1..1545bd0 100644 --- a/testing/examples/RTDoseStatisticsTest.cpp +++ b/testing/examples/RTDoseStatisticsTest.cpp @@ -1,202 +1,202 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include "litCheckMacros.h" #include "rttbDoseStatistics.h" #include "rttbDoseStatisticsCalculator.h" #include "rttbDicomDoseAccessor.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbVirtuosPlanFileDoseAccessorGenerator.h" #include "rttbVirtuosFileStructureSetGenerator.h" #include "rttbOTBMaskAccessor.h" #include "rttbGenericMaskedDoseIterator.h" #include "rttbGenericDoseIterator.h" #include "rttbBaseType.h" namespace rttb { namespace testing { PREPARE_DEFAULT_TEST_REPORTING; /*! @brief RTDoseStatisticsTest. Max, min, mean, standard deviation, variance, Vx, Dx, MOHx, MOCx, MaxOHx, MinOCx are tested. Test if calculation in new architecture returns similar results to the original implementation. WARNING: The values for comparison need to be adjusted if the input files are changed!*/ const double reducedErrorConstant = 0.0001; const double expectedVal = 5.64477e-005; void testWithDummyDoseData(const std::string& doseFilename); void testWithRealVirtuosDoseDataAndStructure(const std::string& doseFilename, const std::string& structFilename, const std::string& planFilename, unsigned int structureNr); int RTDoseStatisticsTest(int argc, char* argv[]) { typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; typedef core::GenericDoseIterator::DoseIteratorPointer DoseIteratorPointer; typedef algorithms::DoseStatistics::ResultListPointer ResultListPointer; std::string RTDOSE_FILENAME; std::string RTDOSE2_FILENAME; std::string RTSTRUCT_FILENAME; std::string RTPLAN_FILENAME; if (argc > 4) { RTDOSE_FILENAME = argv[1]; RTDOSE2_FILENAME = argv[2]; RTSTRUCT_FILENAME = argv[3]; RTPLAN_FILENAME = argv[4]; } else { std::cout << "at least four arguments required for RTDoseStatisticsTest" << std::endl; return -1; } testWithDummyDoseData(RTDOSE_FILENAME); //Structure 2 is RUECKENMARK testWithRealVirtuosDoseDataAndStructure(RTDOSE2_FILENAME, RTSTRUCT_FILENAME, RTPLAN_FILENAME, 2); RETURN_AND_REPORT_TEST_SUCCESS; } void testWithDummyDoseData(const std::string& doseFilename) { typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; typedef core::GenericDoseIterator::DoseIteratorPointer DoseIteratorPointer; typedef ::boost::shared_ptr > > ResultsVectorPointer; io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator1(doseFilename.c_str()); DoseAccessorPointer doseAccessor1(doseAccessorGenerator1.generateDoseAccessor()); //create corresponding DoseIterator ::boost::shared_ptr spDoseIteratorTmp = ::boost::make_shared(doseAccessor1); DoseIteratorPointer spDoseIterator(spDoseIteratorTmp); rttb::algorithms::DoseStatisticsCalculator doseStatisticsCalculator(spDoseIterator); std::vector precomputedDoseValues; precomputedDoseValues.push_back(0); precomputedDoseValues.push_back(expectedVal); precomputedDoseValues.push_back(expectedVal + reducedErrorConstant); std::vector precomputedVolumeValues; precomputedVolumeValues.push_back(20000); precomputedVolumeValues.push_back(24120); rttb::algorithms::DoseStatistics::DoseStatisticsPointer doseStatistics = doseStatisticsCalculator.calculateDoseStatistics(true, precomputedDoseValues, precomputedVolumeValues); CHECK_CLOSE(doseStatistics->getMean(), expectedVal, errorConstant); CHECK_CLOSE(doseStatistics->getStdDeviation(), 0, errorConstant); CHECK_CLOSE(doseStatistics->getVariance(), 0, errorConstant); DoseTypeGy vx = doseStatistics->getVx(expectedVal); CHECK_EQUAL(vx, doseStatistics->getVx(0)); CHECK_CLOSE(expectedVal, doseStatistics->getDx(vx), reducedErrorConstant); CHECK_CLOSE(doseStatistics->getMaximum(), expectedVal, errorConstant); CHECK_CLOSE(doseStatistics->getMinimum(), expectedVal, errorConstant); auto minListPtr = doseStatistics->getMinimumPositions(); auto maxListPtr = doseStatistics->getMaximumPositions(); CHECK_EQUAL(maxListPtr->size(), 100); CHECK_EQUAL(minListPtr->size(), 100); CHECK_CLOSE(doseStatistics->getDx(24120), doseStatistics->getMinimum(), 0.001); CHECK_CLOSE(doseStatistics->getMOHx(24120), doseStatistics->getMean(), reducedErrorConstant); CHECK_CLOSE(doseStatistics->getMOCx(20000), doseStatistics->getMean(), reducedErrorConstant); CHECK_CLOSE(doseStatistics->getMinOCx(20000), doseStatistics->getMean(), reducedErrorConstant); } void testWithRealVirtuosDoseDataAndStructure(const std::string& doseFilename, const std::string& structFilename, const std::string& planFilename, unsigned int structureNr) { typedef core::GenericDoseIterator::DoseIteratorPointer DoseIteratorPointer; typedef core::GenericMaskedDoseIterator::MaskAccessorPointer MaskAccessorPointer; typedef rttb::algorithms::DoseStatistics::DoseStatisticsPointer DoseStatisticsPointer; auto virtuosDoseAccessor = io::virtuos::VirtuosPlanFileDoseAccessorGenerator(doseFilename.c_str(), planFilename.c_str()).generateDoseAccessor(); auto virtuosStructureSet = io::virtuos::VirtuosFileStructureSetGenerator( structFilename.c_str(), doseFilename.c_str()).generateStructureSet(); - boost::shared_ptr spOTBMaskAccessorVirtuos = - boost::make_shared(virtuosStructureSet->getStructure(structureNr), + boost::shared_ptr spOTBMaskAccessorVirtuos = + boost::make_shared(virtuosStructureSet->getStructure(structureNr), virtuosDoseAccessor->getGeometricInfo()); spOTBMaskAccessorVirtuos->updateMask(); MaskAccessorPointer spMaskAccessor(spOTBMaskAccessorVirtuos); //create corresponding MaskedDoseIterator boost::shared_ptr spMaskedDoseIteratorTmp = boost::make_shared(spMaskAccessor, virtuosDoseAccessor); DoseIteratorPointer spMaskedDoseIterator(spMaskedDoseIteratorTmp); rttb::algorithms::DoseStatisticsCalculator doseStatisticsCalculatorVirtuos(spMaskedDoseIterator); DoseStatisticsPointer doseStatisticsVirtuos = doseStatisticsCalculatorVirtuos.calculateDoseStatistics(true); //comparison values computed with "old" DoseStatistics implementation CHECK_EQUAL(doseStatisticsVirtuos->getMinimum(), 0); CHECK_CLOSE(doseStatisticsVirtuos->getMaximum(), 35.3075, reducedErrorConstant); CHECK_CLOSE(doseStatisticsVirtuos->getMean(), 16.1803, reducedErrorConstant); CHECK_CLOSE(doseStatisticsVirtuos->getStdDeviation(), 9.84436, reducedErrorConstant); auto maxPositions = doseStatisticsVirtuos->getMaximumPositions(); auto minPositions = doseStatisticsVirtuos->getMinimumPositions(); CHECK_EQUAL(maxPositions->size(), 1); CHECK_EQUAL(minPositions->size(), 100); CHECK_EQUAL(maxPositions->begin()->first, doseStatisticsVirtuos->getMaximum()); CHECK_EQUAL(maxPositions->begin()->second, 2138227); CHECK_EQUAL(minPositions->begin()->first, doseStatisticsVirtuos->getMinimum()); CHECK_EQUAL(minPositions->begin()->second, 39026); CHECK_CLOSE(doseStatisticsVirtuos->getDx(0.02 * doseStatisticsVirtuos->getVolume()), 30.1528, reducedErrorConstant); CHECK_CLOSE(doseStatisticsVirtuos->getVx(0.9 * doseStatisticsVirtuos->getMaximum()), 0.483529, reducedErrorConstant); CHECK_CLOSE(doseStatisticsVirtuos->getMOHx(0.1 * doseStatisticsVirtuos->getVolume()), 28.7019, reducedErrorConstant); CHECK_CLOSE(doseStatisticsVirtuos->getMOCx(0.05 * doseStatisticsVirtuos->getVolume()), 0, reducedErrorConstant); CHECK_CLOSE(doseStatisticsVirtuos->getMaxOHx(0.95 * doseStatisticsVirtuos->getVolume()), 0, reducedErrorConstant); CHECK_CLOSE(doseStatisticsVirtuos->getMinOCx(0.98 * doseStatisticsVirtuos->getVolume()), 30.1756, reducedErrorConstant); } }//testing }//rttb \ No newline at end of file diff --git a/testing/examples/VoxelizationValidationTest.cpp b/testing/examples/VoxelizationValidationTest.cpp index bda2cfc..08e4018 100644 --- a/testing/examples/VoxelizationValidationTest.cpp +++ b/testing/examples/VoxelizationValidationTest.cpp @@ -1,197 +1,195 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision: 929 $ (last changed revision) // @date $Date: 2015-04-08 14:50:57 +0200 (Mi, 08 Apr 2015) $ (last change date) // @author $Author: zhangl $ (last changed by) */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #include #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbDVHCalculator.h" #include "rttbGenericMaskedDoseIterator.h" #include "rttbGenericDoseIterator.h" #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" #include "rttbDicomDoseAccessor.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbDicomFileStructureSetGenerator.h" #include "rttbOTBMaskAccessor.h" #include "rttbDVHTxtFileReader.h" #include "rttbBoostMaskAccessor.h" //#include "rttbITKImageMaskAccessorConverter.h" //#include "rttbImageWriter.h" namespace rttb { namespace testing { /*! @brief VoxelizationValidationTest. Compare two differnt voxelizations: OTB and Boost. Check dvh maximum and minimum for each structure. Check write mask to itk file for further validation. */ int VoxelizationValidationTest(int argc, char* argv[]) { typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; typedef core::GenericMaskedDoseIterator::MaskAccessorPointer MaskAccessorPointer; typedef core::DVHCalculator::DoseIteratorPointer DoseIteratorPointer; typedef core::StructureSetGeneratorInterface::StructureSetPointer StructureSetPointer; PREPARE_DEFAULT_TEST_REPORTING; //ARGUMENTS: 1: structure file name // 2: dose1 file name // 3: directory name to write boost mask of all structures // 4: directory name to write OTB mask of all structures std::string RTSTRUCT_FILENAME ; std::string RTDOSE_FILENAME; std::string BoostMask_DIRNAME; std::string OTBMask_DIRNAME; if (argc > 4) { RTSTRUCT_FILENAME = argv[1]; RTDOSE_FILENAME = argv[2]; BoostMask_DIRNAME = argv[3]; OTBMask_DIRNAME = argv[4]; } OFCondition status; DcmFileFormat fileformat; /* read dicom-rt dose */ io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator1(RTDOSE_FILENAME.c_str()); DoseAccessorPointer doseAccessor1(doseAccessorGenerator1.generateDoseAccessor()); - boost::shared_ptr geometricPtr = boost::make_shared - (doseAccessor1->getGeometricInfo()); //create a vector of MaskAccessors (one for each structure) StructureSetPointer rtStructureSet = io::dicom::DicomFileStructureSetGenerator( RTSTRUCT_FILENAME.c_str()).generateStructureSet(); std::vector rtStructSetMaskAccessorVec; if (rtStructureSet->getNumberOfStructures() > 0) { for (int j = 0; j < rtStructureSet->getNumberOfStructures(); j++) { std::cout << j << ": " << rtStructureSet->getStructure(j)->getLabel() << std::endl; clock_t start(clock()); //create OTB MaskAccessor ::boost::shared_ptr spOTBMaskAccessor = ::boost::make_shared(rtStructureSet->getStructure(j), doseAccessor1->getGeometricInfo()); spOTBMaskAccessor->updateMask(); MaskAccessorPointer spMaskAccessor(spOTBMaskAccessor); ::boost::shared_ptr spMaskedDoseIteratorTmp = ::boost::make_shared(spMaskAccessor, doseAccessor1); DoseIteratorPointer spMaskedDoseIterator(spMaskedDoseIteratorTmp); rttb::core::DVHCalculator calc(spMaskedDoseIterator, (rtStructureSet->getStructure(j))->getUID(), doseAccessor1->getDoseUID()); rttb::core::DVH dvh = *(calc.generateDVH()); clock_t finish(clock()); std::cout << "OTB Mask Calculation time: " << finish - start << " ms" << std::endl; //Write the mask image to a file. /*! It takes a long time to write all mask files so that RUN_TESTS causes a timeout error. To write all mask files, please use the outcommented code and call the .exe directly! */ /*rttb::io::itk::ITKImageMaskAccessorConverter itkConverter(spOTBMaskAccessor); CHECK(itkConverter.process()); std::stringstream fileNameSstr; fileNameSstr< - (rtStructureSet->getStructure(j), geometricPtr); + (rtStructureSet->getStructure(j), doseAccessor1->getGeometricInfo()); CHECK_NO_THROW(boostMaskAccessorPtr->updateMask()); ::boost::shared_ptr spMaskedDoseIteratorTmp2 = ::boost::make_shared(boostMaskAccessorPtr, doseAccessor1); DoseIteratorPointer spMaskedDoseIterator2(spMaskedDoseIteratorTmp2); rttb::core::DVHCalculator calc2(spMaskedDoseIterator2, (rtStructureSet->getStructure(j))->getUID(), doseAccessor1->getDoseUID()); rttb::core::DVH dvh2 = *(calc2.generateDVH()); clock_t finish2(clock()); std::cout << "Boost Mask Calculation and write file time: " << finish2 - start2 << " ms" << std::endl; //Write the mask image to a file. /*! It takes a long time to write all mask files so that RUN_TESTS causes a timeout error. To write all mask files, please use the outcommented code and call the .exe directly! */ /*rttb::io::itk::ITKImageMaskAccessorConverter itkConverter2(boostMaskAccessorPtr); CHECK(itkConverter2.process()); std::stringstream fileNameSstr2; fileNameSstr2< #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" -#include "rttbDoseStatistics.h" +#include "rttbDoseStatisticsCalculator.h" #include "rttbDoseStatisticsXMLWriter.h" #include "rttbGenericDoseIterator.h" #include "rttbDoseIteratorInterface.h" #include "rttbInvalidParameterException.h" #include "rttbNullPointerException.h" #include "../../core/DummyDoseAccessor.h" namespace rttb { namespace testing { /*! @brief OtherIOTest - test the IO for dose statistics - 1) test exception - 2) test writing statistcs to xml file + 1) test exception + 2) test writing statistics to xml file */ int DoseStatisticsIOTest(int argc, char* argv[]) { typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; typedef core::DoseIteratorInterface::DoseIteratorPointer DoseIteratorPointer; - typedef boost::shared_ptr DoseStatisticsPtr; + typedef boost::shared_ptr DoseStatisticsCalculatorPtr; PREPARE_DEFAULT_TEST_REPORTING; /* generate dummy dose */ boost::shared_ptr spTestDoseAccessor = boost::make_shared(); DoseAccessorPointer spDoseAccessor(spTestDoseAccessor); boost::shared_ptr spTestDoseIterator = boost::make_shared(spDoseAccessor); DoseIteratorPointer spDoseIterator(spTestDoseIterator); - rttb::algorithms::DoseStatistics myDoseStats(spDoseIterator); - DoseStatisticsPtr myDoseStatsPtr = boost::make_shared - (myDoseStats); + rttb::algorithms::DoseStatisticsCalculator myDoseStatsCalculator(spDoseIterator); + auto myDoseStatsSimple = myDoseStatsCalculator.calculateDoseStatistics(); + auto myDoseStatsComplex = myDoseStatsCalculator.calculateDoseStatistics(true); /* test exception */ - CHECK_THROW_EXPLICIT(io::other::writeDoseStatistics(myDoseStatsPtr, "test.test", 0), + CHECK_THROW_EXPLICIT(io::other::writeDoseStatistics(myDoseStatsSimple, "test.test", 0), core::InvalidParameterException); - /* test writing statistcs to xml file */ - FileNameString fN = "testStatistics.xml"; - CHECK_NO_THROW(io::other::writeDoseStatistics(myDoseStatsPtr, fN)); + /* test writing statistics to xml file */ + FileNameString filenameSimple = "testStatisticsSimple.xml"; + CHECK_NO_THROW(io::other::writeDoseStatistics(myDoseStatsSimple, filenameSimple)); - /* test writing statistcs to string */ - boost::property_tree::ptree pt = io::other::writeDoseStatistics(myDoseStatsPtr); - XMLString str = io::other::writerDoseStatisticsToString(myDoseStatsPtr); + FileNameString filenameComplex = "testStatisticsComplex.xml"; + CHECK_NO_THROW(io::other::writeDoseStatistics(myDoseStatsComplex, filenameComplex)); - std::stringstream sstr; - boost::property_tree::xml_parser::write_xml(sstr, pt); - CHECK_EQUAL(str, sstr.str()); + /* test writing statistics to string */ + boost::property_tree::ptree ptSimple = io::other::writeDoseStatistics(myDoseStatsSimple); + XMLString strSimple = io::other::writerDoseStatisticsToString(myDoseStatsSimple); + boost::property_tree::ptree ptComplex = io::other::writeDoseStatistics(myDoseStatsComplex); + XMLString strComplex = io::other::writerDoseStatisticsToString(myDoseStatsComplex); + std::stringstream sstrSimple; + boost::property_tree::xml_parser::write_xml(sstrSimple, ptSimple); + CHECK_EQUAL(strSimple, sstrSimple.str()); + std::stringstream sstrComplex; + boost::property_tree::xml_parser::write_xml(sstrComplex, ptComplex); + CHECK_EQUAL(strComplex, sstrComplex.str()); RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/masks/CMakeLists.txt b/testing/masks/CMakeLists.txt index efaff83..321a611 100644 --- a/testing/masks/CMakeLists.txt +++ b/testing/masks/CMakeLists.txt @@ -1,17 +1,37 @@ MESSAGE (STATUS "Process All Mask Tests...") #----------------------------------------------------------------------------- # Include sub directories #----------------------------------------------------------------------------- - + IF(BUILD_Masks_Boost) ADD_SUBDIRECTORY(boost) ENDIF() IF(BUILD_Masks_OTB) ADD_SUBDIRECTORY(legacy) ENDIF() + +#----------------------------------------------------------------------------- +# Setup the system information test. Write out some basic failsafe +# information in case the test doesn't run. +#----------------------------------------------------------------------------- + + +SET(Masks_TESTS ${EXECUTABLE_OUTPUT_PATH}/rttbMasksTests) + +SET(TEST_DATA_ROOT ${RTTBTesting_SOURCE_DIR}/data) + +SET(TEMP ${RTTBTesting_BINARY_DIR}/temporary) + + +#----------------------------------------------------------------------------- +ADD_TEST(VOIindexIdentifierTest ${Masks_TESTS} VOIindexIdentifierTest +"${TEST_DATA_ROOT}/DICOM/StructureSet/RS1.3.6.1.4.1.2452.6.841242143.1311652612.1170940299.4217870819.dcm" ) + + +RTTB_CREATE_TEST_MODULE(rttbMasks DEPENDS RTTBDicomIO RTTBMasks PACKAGE_DEPENDS Boost Litmus DCMTK) diff --git a/testing/masks/VOIindexIdentifierTest.cpp b/testing/masks/VOIindexIdentifierTest.cpp new file mode 100644 index 0000000..c13f74b --- /dev/null +++ b/testing/masks/VOIindexIdentifierTest.cpp @@ -0,0 +1,87 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html [^] +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notices for more information. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision: +// @date $Date: +// @author $Author: +*/ + +// this file defines the rttbCoreTests for the test driver +// and all it expects is that you have a function called RegisterTests + +#include "litCheckMacros.h" + +#include "rttbBaseType.h" +#include "rttbDicomFileStructureSetGenerator.h" +#include "rttbInvalidParameterException.h" +#include "rttbVOIindexIdentifier.h" + +namespace rttb +{ + + namespace testing + { + + int VOIindexIdentifierTest(int argc, char* argv[]) + { + PREPARE_DEFAULT_TEST_REPORTING; + + typedef core::StructureSetGeneratorInterface::StructureSetPointer StructureSetPointer; + + //ARGUMENTS: 1: structure file name + std::string RTSTRUCT_FILENAME; + + + if (argc > 1) + { + RTSTRUCT_FILENAME = argv[1]; + } + + StructureSetPointer rtStructureSet = io::dicom::DicomFileStructureSetGenerator( + RTSTRUCT_FILENAME.c_str()).generateStructureSet(); + + StructureSetPointer emptyPointer = StructureSetPointer(); + + /* getIndexByVoiName */ + CHECK_NO_THROW(::rttb::masks::VOIindexIdentifier testVOIindexId = ::rttb::masks::VOIindexIdentifier()); + ::rttb::masks::VOIindexIdentifier testVOIindexId = ::rttb::masks::VOIindexIdentifier(); + CHECK_THROW_EXPLICIT(testVOIindexId.getIndexByVoiName(emptyPointer, "Leber"), + ::rttb::core::Exception); + + CHECK_NO_THROW(testVOIindexId.getIndexByVoiName(rtStructureSet, "Leber")); + int intVoi = 5; + CHECK_EQUAL(testVOIindexId.getIndexByVoiName(rtStructureSet, "Leber"), intVoi); + + CHECK_NO_THROW(testVOIindexId.getIndexByVoiName(rtStructureSet, "Leber||Leb")); + + CHECK_EQUAL(testVOIindexId.getIndexByVoiName(rtStructureSet, "Leber"), intVoi); + CHECK_EQUAL(testVOIindexId.getIndexByVoiName(rtStructureSet, "Leber||Leb"), intVoi); + + CHECK_THROW_EXPLICIT(testVOIindexId.getIndexByVoiName(rtStructureSet, "Herz"), ::rttb::core::Exception); + + /* getVoiNameByIndex */ + CHECK_THROW_EXPLICIT(testVOIindexId.getVoiNameByIndex(emptyPointer, 5), + ::rttb::core::Exception); + CHECK_EQUAL(testVOIindexId.getVoiNameByIndex(rtStructureSet, 5), "Leber"); + std::string voiName = "Herz"; + CHECK_THROW_EXPLICIT(testVOIindexId.getVoiNameByIndex(rtStructureSet, 20), ::rttb::core::Exception); + + RETURN_AND_REPORT_TEST_SUCCESS; + } + + }//testing +}//rttb + diff --git a/testing/masks/boost/BoostMaskAccessorTest.cpp b/testing/masks/boost/BoostMaskAccessorTest.cpp index 6102ffb..c67ca6e 100644 --- a/testing/masks/boost/BoostMaskAccessorTest.cpp +++ b/testing/masks/boost/BoostMaskAccessorTest.cpp @@ -1,128 +1,128 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision: 880 $ (last changed revision) // @date $Date: 2015-01-13 14:14:24 +0100 (Di, 13 Jan 2015) $ (last change date) // @author $Author: zhangl $ (last changed by) */ #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbMaskVoxel.h" -#include "rttbNullPointerException.h" -#include "rttbException.h" + #include "../../core/DummyStructure.h" #include "../../core/DummyDoseAccessor.h" #include "rttbBoostMask.h" #include "rttbBoostMaskAccessor.h" namespace rttb { namespace testing { /*! @brief BoostMaskAccessorTest. 1) test constructors - 2) test getRelevantVoxelVector + 2) test getRelevantVoxelVector 3) test getMaskAt */ int BoostMaskAccessorTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; typedef core::Structure::StructTypePointer StructTypePointer; typedef masks::boost::BoostMaskAccessor::MaskVoxelListPointer MaskVoxelListPointer; typedef masks::boost::BoostMaskAccessor::MaskVoxelList MaskVoxelList; // generate test structure set boost::shared_ptr spTestDoseAccessor = boost::make_shared(); DummyStructure myStructGenerator(spTestDoseAccessor->getGeometricInfo()); GridIndexType zPlane = 4; core::Structure myTestStruct = myStructGenerator.CreateRectangularStructureCentered(zPlane); StructTypePointer spMyStruct = boost::make_shared(myTestStruct); - boost::shared_ptr geometricPtr = boost::make_shared(spTestDoseAccessor->getGeometricInfo()); + boost::shared_ptr geometricPtr = boost::make_shared + (spTestDoseAccessor->getGeometricInfo()); - //1) test BoostMask and BoostMaskAccessor constructor - CHECK_NO_THROW( rttb::masks::boost::BoostMask(geometricPtr, spMyStruct)); + //1) test BoostMask and BoostMaskAccessor constructor + CHECK_NO_THROW(rttb::masks::boost::BoostMask(geometricPtr, spMyStruct)); rttb::masks::boost::BoostMask boostMask = rttb::masks::boost::BoostMask(geometricPtr, spMyStruct); - CHECK_NO_THROW(rttb::masks::boost::BoostMaskAccessor(spMyStruct, geometricPtr)); - rttb::masks::boost::BoostMaskAccessor boostMaskAccessor(spMyStruct, geometricPtr); - - //2) test getRelevantVoxelVector + CHECK_NO_THROW(rttb::masks::boost::BoostMaskAccessor(spMyStruct, spTestDoseAccessor->getGeometricInfo())); + rttb::masks::boost::BoostMaskAccessor boostMaskAccessor(spMyStruct, spTestDoseAccessor->getGeometricInfo()); + + //2) test getRelevantVoxelVector CHECK_NO_THROW(boostMask.getRelevantVoxelVector()); CHECK_NO_THROW(boostMaskAccessor.getRelevantVoxelVector()); - + //3) test getMaskAt const VoxelGridIndex3D inMask1(2, 1, 4); //corner -> volumeFraction = 0.25 const VoxelGridIndex3D inMask2(3, 4, 4); //inside ->volumeFraction = 1 const VoxelGridIndex3D inMask3(4, 5, 4); //side -> volumeFraction = 0.5 const VoxelGridIndex3D outMask1(7, 5, 4); const VoxelGridIndex3D outMask2(2, 1, 2); VoxelGridID testId; double errorConstant = 1e-7; core::MaskVoxel tmpMV1(0), tmpMV2(0); CHECK(boostMaskAccessor.getMaskAt(inMask1, tmpMV1)); geometricPtr->convert(inMask1, testId); CHECK(boostMaskAccessor.getMaskAt(testId, tmpMV2)); CHECK_EQUAL(tmpMV1, tmpMV2); CHECK_CLOSE(0.25, tmpMV1.getRelevantVolumeFraction(), errorConstant); CHECK_EQUAL(testId, tmpMV1.getVoxelGridID()); CHECK(boostMaskAccessor.getMaskAt(inMask2, tmpMV1)); CHECK(geometricPtr->convert(inMask2, testId)); CHECK(boostMaskAccessor.getMaskAt(testId, tmpMV2)); CHECK_EQUAL(tmpMV1, tmpMV2); CHECK_EQUAL(1, tmpMV1.getRelevantVolumeFraction()); CHECK_EQUAL(testId, tmpMV1.getVoxelGridID()); CHECK(boostMaskAccessor.getMaskAt(inMask3, tmpMV1)); CHECK(geometricPtr->convert(inMask3, testId)); CHECK(boostMaskAccessor.getMaskAt(testId, tmpMV2)); CHECK_EQUAL(tmpMV1, tmpMV2); CHECK_CLOSE(0.5, tmpMV1.getRelevantVolumeFraction(), errorConstant); CHECK_EQUAL(testId, tmpMV1.getVoxelGridID()); CHECK(!boostMaskAccessor.getMaskAt(outMask1, tmpMV1)); CHECK(geometricPtr->convert(outMask1, testId)); CHECK(!boostMaskAccessor.getMaskAt(testId, tmpMV2)); CHECK_EQUAL(tmpMV1, tmpMV2); CHECK_EQUAL(0, tmpMV1.getRelevantVolumeFraction()); //CHECK_EQUAL(testId,tmpMV1.getVoxelGridID()); -> return value will not be valid outside the mask CHECK(!boostMaskAccessor.getMaskAt(outMask2, tmpMV1)); CHECK(geometricPtr->convert(outMask2, testId)); CHECK(!boostMaskAccessor.getMaskAt(testId, tmpMV2)); CHECK_EQUAL(tmpMV1, tmpMV2); CHECK_EQUAL(0, tmpMV1.getRelevantVolumeFraction()); //CHECK_EQUAL(testId,tmpMV1.getVoxelGridID()); -> return value will not be valid outside the mask RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb diff --git a/testing/masks/files.cmake b/testing/masks/files.cmake new file mode 100644 index 0000000..b5c92ab --- /dev/null +++ b/testing/masks/files.cmake @@ -0,0 +1,7 @@ +SET(CPP_FILES + VOIindexIdentifierTest.cpp + rttbMasksTests.cpp + ) + +SET(H_FILES +) diff --git a/testing/masks/rttbMasksTests.cpp b/testing/masks/rttbMasksTests.cpp index b55efc5..c13bce8 100644 --- a/testing/masks/rttbMasksTests.cpp +++ b/testing/masks/rttbMasksTests.cpp @@ -1,63 +1,63 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #if defined(_MSC_VER) #pragma warning ( disable : 4786 ) #endif #include "litMultiTestsMain.h" namespace rttb { namespace testing { void registerTests() { - LIT_REGISTER_TEST(OTBMaskAccessorTest); + LIT_REGISTER_TEST(VOIindexIdentifierTest); } } } int main(int argc, char* argv[]) { int result = 0; rttb::testing::registerTests(); try { result = lit::multiTestsMain(argc, argv); } catch (const std::exception& /*e*/) { result = -1; } catch (...) { result = -1; } return result; } diff --git a/testing/models/BioModelTest.cpp b/testing/models/BioModelTest.cpp index f79ef4f..c74d09a 100644 --- a/testing/models/BioModelTest.cpp +++ b/testing/models/BioModelTest.cpp @@ -1,288 +1,299 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ #include #include #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbBaseTypeModels.h" #include "rttbBioModel.h" #include "rttbDVH.h" #include "rttbTCPLQModel.h" #include "rttbNTCPLKBModel.h" #include "rttbNTCPRSModel.h" #include "rttbBaseTypeModels.h" #include "rttbBioModelCurve.h" #include "rttbInvalidParameterException.h" #include "rttbBioModelScatterPlots.h" -namespace rttb{ - namespace testing{ +namespace rttb +{ + namespace testing + { typedef core::DVH::DataDifferentialType DataDifferentialType; /*! @brief RTBioModelTest. TCP calculated using a DVH PTV and LQ Model. NTCP tested using 3 Normal Tissue DVHs and LKB/RS Model. TCPLQ: 1) test constructors (values as expected?) 2) test init (calcTCPxxx) 3) test set/get NTCP (LKB): 1) test constructors (values as expected?) 2) test init (calcxxx) 3) test set/get NTCP (RS): 1) test constructors (values as expected?) 2) test init (calcxxx) 3) test set/get */ - int BioModelTest(int argc, char* argv[] ) + int BioModelTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; //generate artificial DVH and corresponding statistical values DoseTypeGy binSize = DoseTypeGy(0.1); DoseVoxelVolumeType voxelVolume = 8; DataDifferentialType aDataDifferential; DoseCalcType value = 0; DVHVoxelNumber numberOfVoxels = 0; // creat default values - for(int i = 0; i < 98; i++){ + for (int i = 0; i < 98; i++) + { value = 0; - numberOfVoxels+=value; - aDataDifferential.push_back( value ); + numberOfVoxels += value; + aDataDifferential.push_back(value); } - aDataDifferential.push_back( 10 ); - aDataDifferential.push_back( 20 ); + + aDataDifferential.push_back(10); + aDataDifferential.push_back(20); const IDType structureID = "myStructure"; const IDType doseID = "myDose"; const IDType voxelizationID = "myVoxelization"; - core::DVH::DVHPointer dvhPtr = boost::make_shared(aDataDifferential, binSize, voxelVolume, structureID, doseID, voxelizationID); + core::DVH::DVHPointer dvhPtr = boost::make_shared(aDataDifferential, binSize, voxelVolume, structureID, + doseID, voxelizationID); //test TCP LQ Model models::BioModelParamType alpha = 0.35; models::BioModelParamType beta = 0.023333333333333; models::BioModelParamType roh = 10000000; int numFractions = 8; DoseTypeGy normalizationDose = 50; //1) test constructors (values as expected?) - rttb::models::TCPLQModel tcplq=rttb::models::TCPLQModel(); - CHECK_EQUAL(0,tcplq.getAlphaMean()); - CHECK_EQUAL(0,tcplq.getAlpahBeta()); - CHECK_EQUAL(0,tcplq.getRho()); - CHECK_EQUAL(0,tcplq.getValue()); - - tcplq=rttb::models::TCPLQModel(dvhPtr,roh, numFractions,alpha/beta, alpha,0.08); - CHECK_EQUAL(alpha,tcplq.getAlphaMean()); - CHECK_EQUAL(alpha/beta,tcplq.getAlpahBeta()); - CHECK_EQUAL(roh,tcplq.getRho()); - CHECK_EQUAL(0,tcplq.getValue()); - - tcplq=rttb::models::TCPLQModel(); - CHECK_EQUAL(0,tcplq.getAlphaMean()); - CHECK_EQUAL(0,tcplq.getAlpahBeta()); - CHECK_EQUAL(0,tcplq.getRho()); - CHECK_EQUAL(0,tcplq.getValue()); - - tcplq=rttb::models::TCPLQModel(dvhPtr,alpha, beta, roh, numFractions); - CHECK_EQUAL(alpha,tcplq.getAlphaMean()); - CHECK_EQUAL(alpha/beta,tcplq.getAlpahBeta()); - CHECK_EQUAL(roh,tcplq.getRho()); - CHECK_EQUAL(0,tcplq.getValue()); + rttb::models::TCPLQModel tcplq = rttb::models::TCPLQModel(); + CHECK_EQUAL(0, tcplq.getAlphaMean()); + CHECK_EQUAL(0, tcplq.getAlphaBeta()); + CHECK_EQUAL(0, tcplq.getRho()); + CHECK_EQUAL(0, tcplq.getValue()); + + tcplq = rttb::models::TCPLQModel(dvhPtr, roh, numFractions, alpha / beta, alpha, 0.08); + CHECK_EQUAL(alpha, tcplq.getAlphaMean()); + CHECK_EQUAL(alpha / beta, tcplq.getAlphaBeta()); + CHECK_EQUAL(roh, tcplq.getRho()); + CHECK_EQUAL(0, tcplq.getValue()); + + tcplq = rttb::models::TCPLQModel(); + CHECK_EQUAL(0, tcplq.getAlphaMean()); + CHECK_EQUAL(0, tcplq.getAlphaBeta()); + CHECK_EQUAL(0, tcplq.getRho()); + CHECK_EQUAL(0, tcplq.getValue()); + + tcplq = rttb::models::TCPLQModel(dvhPtr, alpha, beta, roh, numFractions); + CHECK_EQUAL(alpha, tcplq.getAlphaMean()); + CHECK_EQUAL(alpha / beta, tcplq.getAlphaBeta()); + CHECK_EQUAL(roh, tcplq.getRho()); + CHECK_EQUAL(0, tcplq.getValue()); //2) test init (calcTCPxxx) CHECK_NO_THROW(tcplq.init(1)); //3) test set/get - CHECK_EQUAL(0,tcplq.getValue()); - CHECK_NO_THROW(tcplq.setParameters(alpha,10,roh,0.08)); - CHECK_EQUAL(10,tcplq.getAlpahBeta()); - CHECK_EQUAL(0.08,tcplq.getAlphaVariance()); - CHECK_EQUAL(alpha,tcplq.getAlphaMean()); - CHECK_EQUAL(roh,tcplq.getRho()); + CHECK_EQUAL(0, tcplq.getValue()); + CHECK_NO_THROW(tcplq.setParameters(alpha, 10, roh, 0.08)); + CHECK_EQUAL(10, tcplq.getAlphaBeta()); + CHECK_EQUAL(0.08, tcplq.getAlphaVariance()); + CHECK_EQUAL(alpha, tcplq.getAlphaMean()); + CHECK_EQUAL(roh, tcplq.getRho()); - CHECK_NO_THROW(models::getCurveDoseVSBioModel(tcplq,normalizationDose)); + CHECK_NO_THROW(models::getCurveDoseVSBioModel(tcplq, normalizationDose)); std::vector aParameterVector; - aParameterVector.push_back(alpha+0.02); - CHECK_THROW_EXPLICIT(tcplq.setParameterVector(aParameterVector),core::InvalidParameterException); + aParameterVector.push_back(alpha + 0.02); + CHECK_THROW_EXPLICIT(tcplq.setParameterVector(aParameterVector), core::InvalidParameterException); aParameterVector.push_back(0.06); aParameterVector.push_back(8); - aParameterVector.push_back(roh/10); + aParameterVector.push_back(roh / 10); CHECK_NO_THROW(tcplq.setParameterVector(aParameterVector)); - CHECK_EQUAL(8,tcplq.getAlpahBeta()); - CHECK_EQUAL(0.06,tcplq.getAlphaVariance()); - CHECK_EQUAL(alpha+0.02,tcplq.getAlphaMean()); - CHECK_EQUAL(roh/10,tcplq.getRho()); - - for (int i = 0; i < 4; i++){ - CHECK_NO_THROW(tcplq.setParameterByID(i,models::BioModelParamType(i))); + CHECK_EQUAL(8, tcplq.getAlphaBeta()); + CHECK_EQUAL(0.06, tcplq.getAlphaVariance()); + CHECK_EQUAL(alpha + 0.02, tcplq.getAlphaMean()); + CHECK_EQUAL(roh / 10, tcplq.getRho()); + + for (int i = 0; i < 4; i++) + { + CHECK_NO_THROW(tcplq.setParameterByID(i, models::BioModelParamType(i))); } - CHECK_THROW_EXPLICIT(tcplq.setParameterByID(4,4.0),core::InvalidParameterException); + CHECK_THROW_EXPLICIT(tcplq.setParameterByID(4, 4.0), core::InvalidParameterException); - CHECK_EQUAL(0,tcplq.getParameterID("alphaMean")); - CHECK_EQUAL(0,tcplq.getAlphaMean()); - CHECK_EQUAL(1,tcplq.getParameterID("alphaVariance")); - CHECK_EQUAL(1,tcplq.getAlphaVariance()); - CHECK_EQUAL(2,tcplq.getParameterID("alpha_beta")); - CHECK_EQUAL(2,tcplq.getAlpahBeta()); - CHECK_EQUAL(3,tcplq.getParameterID("rho")); - CHECK_EQUAL(3,tcplq.getRho()); + CHECK_EQUAL(0, tcplq.getParameterID("alphaMean")); + CHECK_EQUAL(0, tcplq.getAlphaMean()); + CHECK_EQUAL(1, tcplq.getParameterID("alphaVariance")); + CHECK_EQUAL(1, tcplq.getAlphaVariance()); + CHECK_EQUAL(2, tcplq.getParameterID("alpha_beta")); + CHECK_EQUAL(2, tcplq.getAlphaBeta()); + CHECK_EQUAL(3, tcplq.getParameterID("rho")); + CHECK_EQUAL(3, tcplq.getRho()); //test NTCPLKBModel //1) test constructors (values as expected?) models::BioModelParamType aVal = 10; models::BioModelParamType mVal = 0.16; models::BioModelParamType d50Val = 35; CHECK_NO_THROW(rttb::models::NTCPLKBModel()); - rttb::models::NTCPLKBModel lkb=rttb::models::NTCPLKBModel(); - CHECK_EQUAL(0,lkb.getA()); - CHECK_EQUAL(0,lkb.getM()); - CHECK_EQUAL(0,lkb.getD50()); - CHECK_EQUAL(0,lkb.getValue()); + rttb::models::NTCPLKBModel lkb = rttb::models::NTCPLKBModel(); + CHECK_EQUAL(0, lkb.getA()); + CHECK_EQUAL(0, lkb.getM()); + CHECK_EQUAL(0, lkb.getD50()); + CHECK_EQUAL(0, lkb.getValue()); CHECK_NO_THROW(rttb::models::NTCPLKBModel(dvhPtr, d50Val, mVal, aVal)); - lkb=rttb::models::NTCPLKBModel(dvhPtr, d50Val, mVal, aVal); - CHECK_EQUAL(0,lkb.getValue()); - CHECK_EQUAL(dvhPtr,lkb.getDVH()); - CHECK_EQUAL(aVal,lkb.getA()); - CHECK_EQUAL(mVal,lkb.getM()); - CHECK_EQUAL(d50Val,lkb.getD50()); + lkb = rttb::models::NTCPLKBModel(dvhPtr, d50Val, mVal, aVal); + CHECK_EQUAL(0, lkb.getValue()); + CHECK_EQUAL(dvhPtr, lkb.getDVH()); + CHECK_EQUAL(aVal, lkb.getA()); + CHECK_EQUAL(mVal, lkb.getM()); + CHECK_EQUAL(d50Val, lkb.getD50()); //2) test init (calcxxx) CHECK_NO_THROW(lkb.init(1)); lkb.getValue(); //3) test set/get - lkb=rttb::models::NTCPLKBModel(); - CHECK_EQUAL(0,lkb.getA()); - CHECK_EQUAL(0,lkb.getM()); - CHECK_EQUAL(0,lkb.getD50()); + lkb = rttb::models::NTCPLKBModel(); + CHECK_EQUAL(0, lkb.getA()); + CHECK_EQUAL(0, lkb.getM()); + CHECK_EQUAL(0, lkb.getD50()); lkb.setDVH(dvhPtr); - CHECK_EQUAL(dvhPtr,lkb.getDVH()); + CHECK_EQUAL(dvhPtr, lkb.getDVH()); lkb.setA(aVal); - CHECK_EQUAL(aVal,lkb.getA()); + CHECK_EQUAL(aVal, lkb.getA()); lkb.setM(mVal); - CHECK_EQUAL(mVal,lkb.getM()); + CHECK_EQUAL(mVal, lkb.getM()); lkb.setD50(d50Val); - CHECK_EQUAL(d50Val,lkb.getD50()); + CHECK_EQUAL(d50Val, lkb.getD50()); CHECK_NO_THROW(models::getCurveEUDVSBioModel(lkb)); aParameterVector.clear(); - aParameterVector.push_back(d50Val+5); - CHECK_THROW_EXPLICIT(lkb.setParameterVector(aParameterVector),core::InvalidParameterException); - aParameterVector.push_back(mVal+0.2); - aParameterVector.push_back(aVal+0.5); + aParameterVector.push_back(d50Val + 5); + CHECK_THROW_EXPLICIT(lkb.setParameterVector(aParameterVector), core::InvalidParameterException); + aParameterVector.push_back(mVal + 0.2); + aParameterVector.push_back(aVal + 0.5); CHECK_NO_THROW(lkb.setParameterVector(aParameterVector)); - CHECK_EQUAL(aVal+0.5,lkb.getA()); - CHECK_EQUAL(mVal+0.2,lkb.getM()); - CHECK_EQUAL(d50Val+5,lkb.getD50()); + CHECK_EQUAL(aVal + 0.5, lkb.getA()); + CHECK_EQUAL(mVal + 0.2, lkb.getM()); + CHECK_EQUAL(d50Val + 5, lkb.getD50()); - for (int i = 0; i < 3; i++){ - CHECK_NO_THROW(lkb.setParameterByID(i,models::BioModelParamType(i))); + for (int i = 0; i < 3; i++) + { + CHECK_NO_THROW(lkb.setParameterByID(i, models::BioModelParamType(i))); } - CHECK_THROW_EXPLICIT(lkb.setParameterByID(3,4.0),core::InvalidParameterException); + CHECK_THROW_EXPLICIT(lkb.setParameterByID(3, 4.0), core::InvalidParameterException); - CHECK_EQUAL(0,lkb.getParameterID("d50")); - CHECK_EQUAL(0,lkb.getD50()); - CHECK_EQUAL(1,lkb.getParameterID("m")); - CHECK_EQUAL(1,lkb.getM()); - CHECK_EQUAL(2,lkb.getParameterID("a")); - CHECK_EQUAL(2,lkb.getA()); + CHECK_EQUAL(0, lkb.getParameterID("d50")); + CHECK_EQUAL(0, lkb.getD50()); + CHECK_EQUAL(1, lkb.getParameterID("m")); + CHECK_EQUAL(1, lkb.getM()); + CHECK_EQUAL(2, lkb.getParameterID("a")); + CHECK_EQUAL(2, lkb.getA()); //test NTCPRSModel //1) test constructors (values as expected?) CHECK_NO_THROW(rttb::models::NTCPRSModel()); models::BioModelParamType gammaVal = 1.7; models::BioModelParamType sVal = 1; - CHECK_NO_THROW(rttb::models::NTCPRSModel(dvhPtr,d50Val,gammaVal,sVal)); - rttb::models::NTCPRSModel rs=rttb::models::NTCPRSModel(dvhPtr,d50Val,gammaVal,sVal); - CHECK_EQUAL(dvhPtr,rs.getDVH()); - CHECK_EQUAL(d50Val,rs.getD50()); - CHECK_EQUAL(gammaVal,rs.getGamma()); - CHECK_EQUAL(sVal,rs.getS()); - - rs=rttb::models::NTCPRSModel(); - CHECK_EQUAL(0,rs.getGamma()); - CHECK_EQUAL(0,rs.getS()); - CHECK_EQUAL(0,rs.getD50()); + CHECK_NO_THROW(rttb::models::NTCPRSModel(dvhPtr, d50Val, gammaVal, sVal)); + rttb::models::NTCPRSModel rs = rttb::models::NTCPRSModel(dvhPtr, d50Val, gammaVal, sVal); + CHECK_EQUAL(dvhPtr, rs.getDVH()); + CHECK_EQUAL(d50Val, rs.getD50()); + CHECK_EQUAL(gammaVal, rs.getGamma()); + CHECK_EQUAL(sVal, rs.getS()); + + rs = rttb::models::NTCPRSModel(); + CHECK_EQUAL(0, rs.getGamma()); + CHECK_EQUAL(0, rs.getS()); + CHECK_EQUAL(0, rs.getD50()); //3) test set/get rs.setDVH(dvhPtr); - CHECK_EQUAL(dvhPtr,rs.getDVH()); + CHECK_EQUAL(dvhPtr, rs.getDVH()); rs.setD50(d50Val); - CHECK_EQUAL(d50Val,rs.getD50()); + CHECK_EQUAL(d50Val, rs.getD50()); rs.setGamma(gammaVal); - CHECK_EQUAL(gammaVal,rs.getGamma()); + CHECK_EQUAL(gammaVal, rs.getGamma()); rs.setS(sVal); - CHECK_EQUAL(sVal,rs.getS()); + CHECK_EQUAL(sVal, rs.getS()); //2) test init (calcxxx) CHECK_NO_THROW(rs.init(1)); //3) test set/get continued aParameterVector.clear(); - aParameterVector.push_back(d50Val+5); - CHECK_THROW_EXPLICIT(rs.setParameterVector(aParameterVector),core::InvalidParameterException); - aParameterVector.push_back(gammaVal+0.2); - aParameterVector.push_back(sVal+0.5); + aParameterVector.push_back(d50Val + 5); + CHECK_THROW_EXPLICIT(rs.setParameterVector(aParameterVector), core::InvalidParameterException); + aParameterVector.push_back(gammaVal + 0.2); + aParameterVector.push_back(sVal + 0.5); CHECK_NO_THROW(rs.setParameterVector(aParameterVector)); - CHECK_EQUAL(gammaVal+0.2,rs.getGamma()); - CHECK_EQUAL(sVal+0.5,rs.getS()); - CHECK_EQUAL(d50Val+5,rs.getD50()); + CHECK_EQUAL(gammaVal + 0.2, rs.getGamma()); + CHECK_EQUAL(sVal + 0.5, rs.getS()); + CHECK_EQUAL(d50Val + 5, rs.getD50()); - for (int i = 0; i < 3; i++){ - CHECK_NO_THROW(rs.setParameterByID(i,models::BioModelParamType(i))); + for (int i = 0; i < 3; i++) + { + CHECK_NO_THROW(rs.setParameterByID(i, models::BioModelParamType(i))); } - CHECK_THROW_EXPLICIT(rs.setParameterByID(3,4.0),core::InvalidParameterException); + CHECK_THROW_EXPLICIT(rs.setParameterByID(3, 4.0), core::InvalidParameterException); - CHECK_EQUAL(0,rs.getParameterID("d50")); - CHECK_EQUAL(0,rs.getD50()); - CHECK_EQUAL(1,rs.getParameterID("gamma")); - CHECK_EQUAL(1,rs.getGamma()); - CHECK_EQUAL(2,rs.getParameterID("s")); - CHECK_EQUAL(2,rs.getS()); + CHECK_EQUAL(0, rs.getParameterID("d50")); + CHECK_EQUAL(0, rs.getD50()); + CHECK_EQUAL(1, rs.getParameterID("gamma")); + CHECK_EQUAL(1, rs.getGamma()); + CHECK_EQUAL(2, rs.getParameterID("s")); + CHECK_EQUAL(2, rs.getS()); //Scatter plot tests - CHECK_NO_THROW(models::getScatterPlotVary1Parameter(tcplq,0,alpha,0,normalizationDose));//variance=0, will be set to 1e-30 - CHECK_THROW_EXPLICIT(models::getScatterPlotVary1Parameter(tcplq,0,alpha,alpha*0.1,0),core::InvalidParameterException);//normalisationdose=0 - CHECK_THROW_EXPLICIT(models::getScatterPlotVary1Parameter(tcplq,0,alpha,alpha*0.1,normalizationDose,10000,0,0),core::InvalidParameterException);//maxDose-minDose=0 + CHECK_NO_THROW(models::getScatterPlotVary1Parameter(tcplq, 0, alpha, 0, + normalizationDose)); //variance=0, will be set to 1e-30 + CHECK_THROW_EXPLICIT(models::getScatterPlotVary1Parameter(tcplq, 0, alpha, alpha * 0.1, 0), + core::InvalidParameterException);//normalisationdose=0 + CHECK_THROW_EXPLICIT(models::getScatterPlotVary1Parameter(tcplq, 0, alpha, alpha * 0.1, normalizationDose, 10000, 0, 0), + core::InvalidParameterException);//maxDose-minDose=0 RETURN_AND_REPORT_TEST_SUCCESS; } }//testing }//rttb \ No newline at end of file diff --git a/testing/models/CMakeLists.txt b/testing/models/CMakeLists.txt index 504fd5f..c81cb75 100644 --- a/testing/models/CMakeLists.txt +++ b/testing/models/CMakeLists.txt @@ -1,21 +1,22 @@ #----------------------------------------------------------------------------- # Setup the system information test. Write out some basic failsafe # information in case the test doesn't run. #----------------------------------------------------------------------------- SET(MODELS_TESTS ${EXECUTABLE_OUTPUT_PATH}/rttbModelTests) SET(MODELS_HEADER_TEST ${EXECUTABLE_OUTPUT_PATH}/rttbModelsHeaderTest) SET(TEST_DATA_ROOT ${RTTBTesting_SOURCE_DIR}/data) SET(TEMP ${RTTBTesting_BINARY_DIR}/temporary) #----------------------------------------------------------------------------- ADD_TEST(BioModelTest ${MODELS_TESTS} BioModelTest) ADD_TEST(BioModelScatterPlotTest ${MODELS_TESTS} BioModelScatterPlotTest) ADD_TEST(DvhBasedModelsTest ${MODELS_TESTS} DvhBasedModelsTest) +ADD_TEST(LQModelAccessorTest ${MODELS_TESTS} LQModelAccessorTest "${TEST_DATA_ROOT}/DICOM/TestDose/ConstantTwo.dcm" "${TEST_DATA_ROOT}/DICOM/TestDose/LinearIncreaseX.dcm") -RTTB_CREATE_TEST_MODULE(rttbModel DEPENDS RTTBModels RTTBOtherIO PACKAGE_DEPENDS Boost Litmus DCMTK) +RTTB_CREATE_TEST_MODULE(rttbModel DEPENDS RTTBModels RTTBOtherIO RTTBDicomIO PACKAGE_DEPENDS Boost Litmus DCMTK) diff --git a/testing/models/LQModelAccessorTest.cpp b/testing/models/LQModelAccessorTest.cpp new file mode 100644 index 0000000..b7c3c3c --- /dev/null +++ b/testing/models/LQModelAccessorTest.cpp @@ -0,0 +1,114 @@ +// ----------------------------------------------------------------------- +// RTToolbox - DKFZ radiotherapy quantitative evaluation library +// +// Copyright (c) German Cancer Research Center (DKFZ), +// Software development for Integrated Diagnostics and Therapy (SIDT). +// ALL RIGHTS RESERVED. +// See rttbCopyright.txt or +// http://www.dkfz.de/en/sidt/projects/rttb/copyright.html +// +// This software is distributed WITHOUT ANY WARRANTY; without even +// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the above copyright notices for more information. +// +//------------------------------------------------------------------------ +/*! +// @file +// @version $Revision: 4047 $ (last changed revision) +// @date $Date: 2012-10-29 16:19:15 +0100 (Mo, 29 Okt 2012) $ (last change date) +// @author $Author: mang $ (last changed by) +*/ +#include "litCheckMacros.h" + +#include + +#include "rttbLQModelAccessor.h" +#include "rttbGenericDoseIterator.h" +#include "rttbDicomFileDoseAccessorGenerator.h" +#include "rttbInvalidDoseException.h" + +namespace rttb +{ + namespace testing + { + + /*! @brief LQModelAccessorTest. + 1) Test constructor + 2) Test getGeometricInfo() + 3) Test getBioModelValueAt() + + */ + int LQModelAccessorTest(int argc, char* argv[]) + { + PREPARE_DEFAULT_TEST_REPORTING; + + std::string RTDOSE_FILENAME_CONSTANT_TWO; + std::string RTDOSE_FILENAME_INCREASE_X; + + if (argc > 2) + { + RTDOSE_FILENAME_CONSTANT_TWO = argv[1]; + RTDOSE_FILENAME_INCREASE_X = argv[2]; + } + else + { + + std::cout << "at least two parameters for LQModelAccessorTest are expected" << + std::endl; + return -1; + } + + typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; + + rttb::io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator1( + RTDOSE_FILENAME_CONSTANT_TWO.c_str()); + DoseAccessorPointer doseAccessor1(doseAccessorGenerator1.generateDoseAccessor()); + + rttb::io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator2( + RTDOSE_FILENAME_INCREASE_X.c_str()); + DoseAccessorPointer doseAccessor2(doseAccessorGenerator2.generateDoseAccessor()); + + core::GeometricInfo doseAccessor1GeometricInfo = doseAccessor1->getGeometricInfo(); + core::GeometricInfo doseAccessor2GeometricInfo = doseAccessor2->getGeometricInfo(); + + DoseAccessorPointer doseAccessorNull; + + core::BioModelAccessorInterface::BioModelAccessorPointer LQWithConstantDose; + core::BioModelAccessorInterface::BioModelAccessorPointer LQWithIncreaseXDose; + + //1) test constructor + CHECK_THROW_EXPLICIT(models::LQModelAccessor(doseAccessorNull, 0, 0), core::InvalidDoseException); + + CHECK_NO_THROW(LQWithConstantDose = boost::make_shared(doseAccessor1, + 0.2, 0.02)); + CHECK_NO_THROW(LQWithIncreaseXDose = boost::make_shared(doseAccessor2, + 0.3, 0.01)); + + //2) Test getGeometricInfo() + CHECK_EQUAL(LQWithConstantDose->getGeometricInfo(), doseAccessor1GeometricInfo); + CHECK_EQUAL(LQWithIncreaseXDose->getGeometricInfo(), doseAccessor2GeometricInfo); + + //3) Test getBioModelValueAt() + + models::BioModelParamType expectedLQWithDoseTwo = exp(-(0.2 * 2 + (0.02 * 2 * 2))); + CHECK_EQUAL(LQWithConstantDose->getBioModelValueAt(0), expectedLQWithDoseTwo); + CHECK_EQUAL(LQWithConstantDose->getBioModelValueAt(LQWithConstantDose->getGridSize() - 1), expectedLQWithDoseTwo); + CHECK_EQUAL(LQWithConstantDose->getBioModelValueAt(VoxelGridIndex3D(1, 2, 6)), expectedLQWithDoseTwo); + CHECK_EQUAL(LQWithConstantDose->getBioModelValueAt(VoxelGridIndex3D(65, 40, 60)), expectedLQWithDoseTwo); + CHECK_EQUAL(LQWithIncreaseXDose->getBioModelValueAt(0), 1); + models::BioModelParamType expectedLQWithIncreaseX = exp(-(0.3 * 66 * 2.822386e-5 + (0.01 * 66 * 2.822386e-5 * 66 * + 2.822386e-5))); + CHECK_CLOSE(LQWithIncreaseXDose->getBioModelValueAt(LQWithIncreaseXDose->getGridSize() - 1), expectedLQWithIncreaseX, + errorConstant); + expectedLQWithIncreaseX = exp(-(0.3 * 1 * 2.822386e-5 + (0.01 * 1 * 2.822386e-5 * 1 * 2.822386e-5))); + CHECK_CLOSE(LQWithIncreaseXDose->getBioModelValueAt(VoxelGridIndex3D(1, 2, 6)), expectedLQWithIncreaseX, errorConstant); + expectedLQWithIncreaseX = exp(-(0.3 * 45 * 2.822386e-5 + (0.01 * 45 * 2.822386e-5 * 45 * 2.822386e-5))); + CHECK_CLOSE(LQWithIncreaseXDose->getBioModelValueAt(VoxelGridIndex3D(45, 40, 60)), expectedLQWithIncreaseX, + errorConstant); + + RETURN_AND_REPORT_TEST_SUCCESS; + + } + + }//testing +}//rttb \ No newline at end of file diff --git a/testing/models/files.cmake b/testing/models/files.cmake index 1e5c4fa..ca92f5f 100644 --- a/testing/models/files.cmake +++ b/testing/models/files.cmake @@ -1,15 +1,16 @@ SET(CPP_FILES rttbModelsTest.cpp BioModelTest.cpp rttbScatterTester.cpp BioModelScatterPlotTest.cpp DummyModel.cpp ../core/DummyDVHGenerator.cpp DvhBasedModelsTest.cpp + LQModelAccessorTest.cpp ) SET(H_FILES rttbScatterTester.h DummyModel.h ../core/DummyDVHGenerator.h ) diff --git a/testing/models/rttbModelsTest.cpp b/testing/models/rttbModelsTest.cpp index 59953f0..ee706c1 100644 --- a/testing/models/rttbModelsTest.cpp +++ b/testing/models/rttbModelsTest.cpp @@ -1,65 +1,66 @@ // ----------------------------------------------------------------------- // RTToolbox - DKFZ radiotherapy quantitative evaluation library // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See rttbCopyright.txt or // http://www.dkfz.de/en/sidt/projects/rttb/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) */ // this file defines the rttbCoreTests for the test driver // and all it expects is that you have a function called RegisterTests #if defined(_MSC_VER) #pragma warning ( disable : 4786 ) #endif #include "litMultiTestsMain.h" namespace rttb { namespace testing { void registerTests() { LIT_REGISTER_TEST(BioModelTest); LIT_REGISTER_TEST(BioModelScatterPlotTest); LIT_REGISTER_TEST(DvhBasedModelsTest); + LIT_REGISTER_TEST(LQModelAccessorTest); } } } int main(int argc, char* argv[]) { int result = 0; rttb::testing::registerTests(); try { result = lit::multiTestsMain(argc, argv); } catch (const std::exception& /*e*/) { result = -1; } catch (...) { result = -1; } return result; }