diff --git a/code/algorithms/rttbArithmetic.cpp b/code/algorithms/rttbArithmetic.cpp index 52bdf2b..fa10e9a 100644 --- a/code/algorithms/rttbArithmetic.cpp +++ b/code/algorithms/rttbArithmetic.cpp @@ -1,106 +1,99 @@ // ----------------------------------------------------------------------- // 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 "rttbArithmetic.h" - namespace rttb { namespace algorithms { namespace arithmetic { void add(const DoseAccessorPointer dose1, const DoseAccessorPointer dose2, MutableDoseAccessorPointer result) { doseOp::Add addOP; arithmetic(dose1, dose2, result, addOP); } void add(const MaskAccessorPointer mask1, const MaskAccessorPointer mask2, MutableMaskAccessorPointer result) { maskOp::Add addOP; arithmetic(mask1, mask2, result, addOP); } void subtract(const MaskAccessorPointer mask1, const MaskAccessorPointer mask2, MutableMaskAccessorPointer result) { maskOp::Subtract subOP; arithmetic(mask1, mask2, result, subOP); } void multiply(const DoseAccessorPointer dose, const MaskAccessorPointer mask, MutableDoseAccessorPointer result) { doseMaskOp::Multiply multOP; arithmetic(dose, mask, result, multOP); } namespace doseOp { DoseTypeGy Add::calc(const DoseTypeGy dose1Val, const DoseTypeGy dose2Val) const { return dose1Val + dose2Val; } AddWeighted::AddWeighted(const DoseCalcType w1, const DoseCalcType w2): weight1(w1), weight2(w2) {}; DoseTypeGy AddWeighted::calc(const DoseTypeGy dose1Val, const DoseTypeGy dose2Val) const { return weight1 * dose1Val + weight2 * dose2Val; } rttb::DoseTypeGy Multiply::calc(const DoseTypeGy dose1Val, const DoseTypeGy dose2Val) const { return dose1Val * dose2Val; } } namespace doseMaskOp { DoseTypeGy Multiply::calc(const DoseTypeGy doseVal, const FractionType maskVal) const { return doseVal * maskVal; } } namespace maskOp { FractionType Add::calc(const FractionType mask1Val, const FractionType mask2Val) const { FractionType added = mask1Val + mask2Val; return (1 < added ? 1 : added); } FractionType Subtract::calc(const FractionType mask1Val, const FractionType mask2Val) const { FractionType sub = mask1Val - mask2Val; return (0 > sub ? 0 : sub); } } } } } \ No newline at end of file diff --git a/code/algorithms/rttbArithmetic.h b/code/algorithms/rttbArithmetic.h index d62e403..3049953 100644 --- a/code/algorithms/rttbArithmetic.h +++ b/code/algorithms/rttbArithmetic.h @@ -1,159 +1,153 @@ // ----------------------------------------------------------------------- // 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 __ARITHMETIC_H #define __ARITHMETIC_H #include "rttbDoseAccessorInterface.h" #include "rttbMutableMaskAccessorInterface.h" #include "rttbMutableDoseAccessorInterface.h" #include "rttbMaskAccessorInterface.h" namespace rttb { namespace algorithms { namespace arithmetic { using DoseAccessorPointer = core::DoseAccessorInterface::Pointer; using MutableDoseAccessorPointer = core::MutableDoseAccessorInterface::Pointer; using MutableMaskAccessorPointer = core::MutableMaskAccessorInterface::Pointer; using MaskAccessorPointer = core::MaskAccessorInterface::Pointer; using MaskVoxelList = core::MaskAccessorInterface::MaskVoxelList; using MaskVoxelListPointer = core::MaskAccessorInterface::MaskVoxelListPointer; /*! Applies the given dose operation to the given doses and stores the result in <i>result</i> @pre pointers to accessors are !nullptr. The geometric Info of the individual accessors must be equal. @exception NullPointerException thrown if one of the input accessors is nullptr. @exception InvalidParameterException thrown if the geometricInfo of the given accessors does not match. */ template <class TDoseOperation> void arithmetic(const DoseAccessorPointer dose1, const DoseAccessorPointer dose2, MutableDoseAccessorPointer result, TDoseOperation op); ///*! Applies the given dose operation to the mapped given doses (transformation given by MatchPoint) and stores the result in <i>result</i> // @pre pointers to accessors are ! nullptr. // @exception NullPointerException thrown if one of the input accessors is nullptr. // @exception TransformationOutsideImageException thrown if the transformation maps to a position outside the original image. // */ // template <class TDoseOperation> // void arithmetic (const DoseAccessorPointer dose1, const MappableDoseAccessorPointer dose2, // MutableDoseAccessorPointer result, TDoseOperation op); /*! Applies the given dose-mask operation to the given dose and mask and stores the result in <i>result</i> @pre pointers to accessors are ! nullptr. The geometric Info of the individual accessors must be equal. @exception NullPointerException thrown if one of the input accessors is nullptr. @exception InvalidParameterException thrown if the geometricInfo of the given accessors does not match. */ template <class TDoseMaskOperation> void arithmetic(const DoseAccessorPointer dose, const MaskAccessorPointer mask, MutableDoseAccessorPointer result, TDoseMaskOperation op); /*! Applies the given mask operation to the given masks and stores the result in <i>result</i> @pre pointers to accessors are !nullptr. The geometric Info of the individual accessors must be equal. @exception NullPointerException thrown if one of the input accessors is nullptr. @exception InvalidParameterException thrown if the geometricInfo of the given accessors does not match. */ template <class TMaskOperation> void arithmetic(const MaskAccessorPointer mask1, const MaskAccessorPointer mask2, MutableMaskAccessorPointer result, TMaskOperation op); //convenience functions void add(const DoseAccessorPointer dose1, const DoseAccessorPointer dose2, MutableDoseAccessorPointer result); //void add(const DoseAccessorPointer dose1, const MappableDoseAccessorPointer dose2, // MutableDoseAccessorPointer result); void add(const MaskAccessorPointer mask1, const MaskAccessorPointer mask2, MutableMaskAccessorPointer result); void subtract(const MaskAccessorPointer mask1, const MaskAccessorPointer mask2, MutableMaskAccessorPointer result); void multiply(const DoseAccessorPointer dose, const MaskAccessorPointer mask, MutableDoseAccessorPointer result); /*all operation classes need to implement the function calc() that performs the entry wise operation The operations are sorted into name spaces according to useful application. If the input values are compatible the operations can also be applied to accessors they were not meant for. */ //Operations for binary-dose-operation template namespace doseOp { class Add { public: DoseTypeGy calc(const DoseTypeGy dose1Val, const DoseTypeGy dose2Val) const; }; class AddWeighted { private: DoseCalcType weight1, weight2; public: /* ! Constructor initializes weights applied to individual doses values on adding. */ AddWeighted(const DoseCalcType w1 = 1, const DoseCalcType w2 = 1); DoseTypeGy calc(const DoseTypeGy dose1Val, const DoseTypeGy dose2Val) const; }; class Multiply { public: DoseTypeGy calc(const DoseTypeGy dose1Val, const DoseTypeGy dose2Val) const; }; } //Operations for binary-dose-mask-operation template namespace doseMaskOp { class Multiply { public: DoseTypeGy calc(const DoseTypeGy doseVal, const FractionType maskVal) const; }; } //Operations for binary-mask-operation template //the result of these operations needs to be between 0 and 1 namespace maskOp { class Add { public: FractionType calc(const FractionType mask1Val, const FractionType mask2Val) const; }; class Subtract { public: FractionType calc(const FractionType mask1Val, const FractionType mask2Val) const; }; } }//end namespace arithmetic }//end namespace algorithms }//end namespace core #include "rttbArithmetic.tpp" #endif diff --git a/code/algorithms/rttbArithmetic.tpp b/code/algorithms/rttbArithmetic.tpp index 21de034..09eabec 100644 --- a/code/algorithms/rttbArithmetic.tpp +++ b/code/algorithms/rttbArithmetic.tpp @@ -1,129 +1,123 @@ // ----------------------------------------------------------------------- // 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 "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" #ifndef __ARITHMETIC_TPP #define __ARITHMETIC_TPP namespace rttb { namespace algorithms { namespace arithmetic { template <class TDoseOperation> void arithmetic(const DoseAccessorPointer dose1, const DoseAccessorPointer dose2, MutableDoseAccessorPointer result, TDoseOperation op) { //handle null pointers if (dose1 == nullptr || dose2 == nullptr || result == nullptr) { throw core::NullPointerException("Pointers to input accessors cannot be nullptr."); } //handle differences in geometricInfo if (!(dose1->getGeometricInfo().equalsAlmost(dose2->getGeometricInfo()) && dose1->getGeometricInfo().equalsAlmost(result->getGeometricInfo()))) { throw core::InvalidParameterException("The geometricInfo of all given accessors needs to be equal."); } //apply operation op to doses with equal geometricInfo (same grid) GridSizeType numVoxels = dose1->getGridSize(); for (VoxelGridID id = 0; id < numVoxels; ++id) { DoseTypeGy opVal = op.calc(dose1->getValueAt(id), dose2->getValueAt(id)); result->setDoseAt(id, opVal); } } template <class TDoseMaskOperation> void arithmetic(const DoseAccessorPointer dose, const MaskAccessorPointer mask, MutableDoseAccessorPointer result, TDoseMaskOperation op) { //handle null pointers if (dose == nullptr || mask == nullptr || result == nullptr) { throw core::NullPointerException("Pointers to input accessors cannot be nullptr."); } //handle differences in geometricInfo if (!(dose->getGeometricInfo().equalsAlmost(mask->getGeometricInfo()) && dose->getGeometricInfo().equalsAlmost(result->getGeometricInfo()))) { throw core::InvalidParameterException("The geometricInfo of all given accessors needs to be equal."); } //apply operation op to accessors with equal geometricInfo (same grid) core::MaskVoxel mVoxel(0); GridSizeType numVoxels = dose->getGridSize(); for (VoxelGridID id = 0; id < numVoxels; ++id) { mask->getMaskAt(id, mVoxel); DoseTypeGy opVal = op.calc(dose->getValueAt(id), mVoxel.getRelevantVolumeFraction()); result->setDoseAt(id, opVal); } } template <class TMaskOperation> void arithmetic(const MaskAccessorPointer mask1, const MaskAccessorPointer mask2, MutableMaskAccessorPointer result, TMaskOperation op) { //handle null pointers if (mask1 == nullptr || mask2 == nullptr || result == nullptr) { throw core::NullPointerException("Pointers to input accessors cannot be nullptr."); } //handle differences in geometricInfo if (!(mask1->getGeometricInfo().equalsAlmost(mask2->getGeometricInfo()) && mask1->getGeometricInfo().equalsAlmost(result->getGeometricInfo()))) { throw core::InvalidParameterException("The geometricInfo of all given accessors needs to be equal."); } //apply operation op to accessors with equal geometricInfo (same grid) core::MaskVoxel m1Voxel(0); //initialize results list with mask1 values result->setRelevantVoxelVector(mask1->getRelevantVoxelVector()); MaskVoxelListPointer voxelListMask2 = mask2->getRelevantVoxelVector(); auto it = voxelListMask2->begin(); while (it != voxelListMask2->end()) { mask1->getMaskAt(it->getVoxelGridID(), m1Voxel); FractionType opVal = op.calc(m1Voxel.getRelevantVolumeFraction(), it->getRelevantVolumeFraction()); result->setMaskAt(it->getVoxelGridID(), core::MaskVoxel(it->getVoxelGridID(), opVal)); ++it; } } } } } #endif \ No newline at end of file diff --git a/code/algorithms/rttbBinaryFunctorAccessor.h b/code/algorithms/rttbBinaryFunctorAccessor.h index ffa3e45..0b927a9 100644 --- a/code/algorithms/rttbBinaryFunctorAccessor.h +++ b/code/algorithms/rttbBinaryFunctorAccessor.h @@ -1,99 +1,94 @@ // ----------------------------------------------------------------------- // 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 __BINARY_FUNCTOR_ACCESSOR_H #define __BINARY_FUNCTOR_ACCESSOR_H #include "rttbAccessorInterface.h" #include "rttbBaseType.h" namespace rttb { namespace algorithms { /*! @class BinaryFunctorAccessor @brief Class that allows to access the results of a binary operation. @details this Accessor takes two accessors as operants (the operants must have the same geometry) and computes a resulting value by using a given operation functor. The resulting value will be returned from the accessor as its value upon request. @remark this can be seen as a lazy filter pattern, thus the accessor is filtering/operating on dose values upon request. */ template <class TDoseOperation> class BinaryFunctorAccessor: public core::AccessorInterface { protected: core::AccessorInterface::ConstPointer _spData1; core::AccessorInterface::ConstPointer _spData2; TDoseOperation _functor; public: /*! @brief Constructor. @param data1 pointer to the 1st data operand @param data2 pointer to the 2nd data operand @param functor Instance of the operation that should be used @pre all input parameters have to be valid @exception core::NullPointerException if one input parameter is nullptr or if geometricInfos don't match */ BinaryFunctorAccessor(core::AccessorInterface::ConstPointer data1, core::AccessorInterface::ConstPointer data2, const TDoseOperation& functor); /*! @brief Virtual destructor */ ~BinaryFunctorAccessor() override = default; /*! @pre: the geometricInfo of both doseAccessors are equal */ inline const core::GeometricInfo& getGeometricInfo() const override { return _spData1->getGeometricInfo(); }; /*! @pre: the geometricInfo of both doseAccessors are equal */ inline GridSizeType getGridSize() const override { return _spData1->getGeometricInfo().getNumberOfVoxels(); }; /*! @brief Returns the result dose computed by the functor. It uses the dose values of both operand doses specified via the passed ID. @return the dose value if inside, -1 else @pre <TDoseOperation>.calc(dose1,dose2) has to be implemented */ GenericValueType getValueAt(const VoxelGridID aID) const override; /*! @brief Returns the result dose computed by the functor. It uses the dose values of both operand doses specified via the passed index. @return the dose value if inside, -1 else @pre <TDoseOperation>.calc(dose1,dose2) has to be implemented */ GenericValueType getValueAt(const VoxelGridIndex3D& aIndex) const override; const IDType getUID() const override { return IDType(); } }; } } #include "rttbBinaryFunctorAccessor.tpp" #endif diff --git a/code/algorithms/rttbBinaryFunctorAccessor.tpp b/code/algorithms/rttbBinaryFunctorAccessor.tpp index 7b2887d..c56e9ed 100644 --- a/code/algorithms/rttbBinaryFunctorAccessor.tpp +++ b/code/algorithms/rttbBinaryFunctorAccessor.tpp @@ -1,82 +1,76 @@ // ----------------------------------------------------------------------- // 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 "rttbBinaryFunctorAccessor.h" #ifndef __BINARY_FUNCTOR_ACCESSOR_TPP #define __BINARY_FUNCTOR_ACCESSOR_TPP namespace rttb { namespace algorithms { template <class TDoseOperation> BinaryFunctorAccessor<TDoseOperation>::BinaryFunctorAccessor(core::AccessorInterface::ConstPointer data1, core::AccessorInterface::ConstPointer data2, const TDoseOperation& functor) { if (data1 == nullptr || data2 == nullptr) { throw core::NullPointerException("Pointers to input accessors cannot be nullptr."); } if (!(data1->getGeometricInfo() == data2->getGeometricInfo())) { throw core::InvalidParameterException("The geometricInfo of all given accessors needs to be equal."); } _spData1 = data1; _spData2 = data2; _functor = functor; } template <class TDoseOperation> GenericValueType BinaryFunctorAccessor<TDoseOperation>::getValueAt( const VoxelGridID aID) const { if (getGeometricInfo().validID(aID)) { GenericValueType value = _functor.calc(_spData1->getValueAt(aID), _spData2->getValueAt(aID)); return value; } else { return -1; } } template <class TDoseOperation> DoseTypeGy BinaryFunctorAccessor<TDoseOperation>::getValueAt( const VoxelGridIndex3D& aIndex) const { VoxelGridID aVoxelGridID; if (_spData1->getGeometricInfo().convert(aIndex, aVoxelGridID)) { return getValueAt(aVoxelGridID); } else { return -1; } } } } #endif \ No newline at end of file diff --git a/code/algorithms/rttbDoseStatistics.cpp b/code/algorithms/rttbDoseStatistics.cpp index 464a80f..a1147a0 100644 --- a/code/algorithms/rttbDoseStatistics.cpp +++ b/code/algorithms/rttbDoseStatistics.cpp @@ -1,293 +1,287 @@ // ----------------------------------------------------------------------- // 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 "rttbDoseStatistics.h" #include "boost/make_shared.hpp" #include "rttbDataNotAvailableException.h" #include "rttbInvalidParameterException.h" namespace rttb { namespace algorithms { DoseStatistics::DoseStatistics(DoseStatisticType minimum, DoseStatisticType maximum, DoseStatisticType mean, DoseStatisticType stdDeviation, VoxelNumberType numVoxels, VolumeType volume, ResultListPointer maximumVoxelPositions /*= ResultListPointer()*/, ResultListPointer minimumVoxelPositions /*= ResultListPointer()*/, VolumeToDoseMeasureCollection Dx, DoseToVolumeMeasureCollection Vx, VolumeToDoseMeasureCollection MOHx, VolumeToDoseMeasureCollection MOCx, VolumeToDoseMeasureCollection MaxOHx, VolumeToDoseMeasureCollection MinOCx, DoseTypeGy referenceDose /*=-1*/): _minimum(minimum), _maximum(maximum), _mean(mean), _stdDeviation(stdDeviation), _numVoxels(numVoxels), _volume(volume), _Dx(::boost::make_shared<VolumeToDoseMeasureCollection>(Dx)), _Vx(::boost::make_shared<DoseToVolumeMeasureCollection>(Vx)), _MOHx(::boost::make_shared<VolumeToDoseMeasureCollection>(MOHx)), _MOCx(::boost::make_shared<VolumeToDoseMeasureCollection>(MOCx)), _MaxOHx(::boost::make_shared<VolumeToDoseMeasureCollection>(MaxOHx)), _MinOCx(::boost::make_shared<VolumeToDoseMeasureCollection>(MinOCx)) { if (maximumVoxelPositions == nullptr) { _maximumVoxelPositions = boost::make_shared<std::vector<std::pair<DoseTypeGy, VoxelGridID> > > (std::vector<std::pair<DoseTypeGy, VoxelGridID> >()); } else { _maximumVoxelPositions = maximumVoxelPositions; } if (minimumVoxelPositions == nullptr) { _minimumVoxelPositions = boost::make_shared<std::vector<std::pair<DoseTypeGy, VoxelGridID> > > (std::vector<std::pair<DoseTypeGy, VoxelGridID> >()); } else { _minimumVoxelPositions = minimumVoxelPositions; } if (referenceDose <= 0) { _referenceDose = _maximum; } else { _referenceDose = referenceDose; } } DoseStatistics::~DoseStatistics() = default; void DoseStatistics::setMinimumVoxelPositions(ResultListPointer minimumVoxelPositions) { _minimumVoxelPositions = minimumVoxelPositions; } void DoseStatistics::setMaximumVoxelPositions(ResultListPointer maximumVoxelPositions) { _maximumVoxelPositions = maximumVoxelPositions; } void DoseStatistics::setDx(VolumeToDoseMeasureCollection::Pointer DxValues) { _Dx = DxValues; } void DoseStatistics::setVx(DoseToVolumeMeasureCollection::Pointer VxValues) { _Vx = VxValues; } void DoseStatistics::setMOHx(VolumeToDoseMeasureCollection::Pointer MOHxValues) { _MOHx = MOHxValues; } void DoseStatistics::setMOCx(VolumeToDoseMeasureCollection::Pointer MOCxValues) { _MOCx = MOCxValues; } void DoseStatistics::setMaxOHx(VolumeToDoseMeasureCollection::Pointer MaxOHValues) { _MaxOHx = MaxOHValues; } void DoseStatistics::setMinOCx(VolumeToDoseMeasureCollection::Pointer MinOCValues) { _MinOCx = MinOCValues; } void DoseStatistics::setReferenceDose(DoseTypeGy referenceDose) { if (referenceDose <= 0) { _referenceDose = _maximum; } else { _referenceDose = referenceDose; } } VoxelNumberType DoseStatistics::getNumberOfVoxels() const { return _numVoxels; } VolumeType DoseStatistics::getVolume() const { return _volume; } DoseTypeGy DoseStatistics::getReferenceDose() const { return _referenceDose; } DoseStatisticType DoseStatistics::getMaximum() const { return _maximum; } DoseStatisticType DoseStatistics::getMinimum() const { return _minimum; } DoseStatisticType DoseStatistics::getMean() const { return _mean; } DoseStatisticType DoseStatistics::getStdDeviation() const { return _stdDeviation; } DoseStatisticType DoseStatistics::getVariance() const { return _stdDeviation * _stdDeviation; } double DoseStatistics::getValue(const std::map<double, double>& aMap, double key, bool findNearestValueInstead, double& storedKey) const { if (aMap.find(key) != std::end(aMap)) { return aMap.find(key)->second; } else { //value not in map. We have to find the nearest value if (aMap.empty()) { throw core::DataNotAvailableException("No Vx values are defined"); } else { if (findNearestValueInstead) { auto iterator = findNearestKeyInMap(aMap, key); storedKey = iterator->first; return iterator->second; } else { throw core::DataNotAvailableException("No Vx value with required dose is defined"); } } } } std::map<double, double>::const_iterator DoseStatistics::findNearestKeyInMap( const std::map<double, double>& aMap, double key) const { double minDistance = 1e19; double minDistanceLast = 1e20; auto iterator = std::begin(aMap); while (iterator != std::end(aMap)) { minDistanceLast = minDistance; minDistance = fabs(iterator->first - key); if (minDistanceLast > minDistance) { ++iterator; } else { if (iterator != std::begin(aMap)) { --iterator; return iterator; } else { return std::begin(aMap); } } } --iterator; return iterator; } DoseStatistics::ResultListPointer DoseStatistics::getMaximumVoxelPositions() const { return _maximumVoxelPositions; } DoseStatistics::ResultListPointer DoseStatistics::getMinimumVoxelPositions() const { return _minimumVoxelPositions; } DoseToVolumeMeasureCollection DoseStatistics::getVx() const { return *_Vx; } VolumeToDoseMeasureCollection DoseStatistics::getDx() const { return *_Dx; } VolumeToDoseMeasureCollection DoseStatistics::getMOHx() const { return *_MOHx; } VolumeToDoseMeasureCollection DoseStatistics::getMOCx() const { return *_MOCx; } VolumeToDoseMeasureCollection DoseStatistics::getMaxOHx() const { return *_MaxOHx; } VolumeToDoseMeasureCollection DoseStatistics::getMinOCx() const { return *_MinOCx; } }//end namespace algorithms }//end namespace rttb diff --git a/code/algorithms/rttbDoseStatistics.h b/code/algorithms/rttbDoseStatistics.h index 6bd70bb..2480321 100644 --- a/code/algorithms/rttbDoseStatistics.h +++ b/code/algorithms/rttbDoseStatistics.h @@ -1,178 +1,172 @@ // ----------------------------------------------------------------------- // 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 <vector> #include <map> #include <rttbCommon.h> #include <boost/make_shared.hpp> #include "rttbBaseType.h" #include "RTTBAlgorithmsExports.h" #include "rttbVolumeToDoseMeasureCollection.h" #include "rttbDoseToVolumeMeasureCollection.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace algorithms { /*! @class DoseStatistics @brief This is a data class storing different statistical values from a rt dose distribution @sa DoseStatisticsCalculator */ class RTTBAlgorithms_EXPORT DoseStatistics { public: rttbClassMacroNoParent(DoseStatistics); typedef boost::shared_ptr<std::vector<std::pair<DoseTypeGy, VoxelGridID> > > ResultListPointer; private: double getValue(const std::map<double, double>& aMap, double key, bool findNearestValueInstead, double& storedKey) const; std::map<double, double>::const_iterator findNearestKeyInMap(const std::map<double, double>& aMap, double key) const; DoseStatisticType _minimum; DoseStatisticType _maximum; DoseStatisticType _mean; DoseStatisticType _stdDeviation; VoxelNumberType _numVoxels; VolumeType _volume; ResultListPointer _minimumVoxelPositions; ResultListPointer _maximumVoxelPositions; VolumeToDoseMeasureCollection::Pointer _Dx; DoseToVolumeMeasureCollection::Pointer _Vx; VolumeToDoseMeasureCollection::Pointer _MOHx; VolumeToDoseMeasureCollection::Pointer _MOCx; VolumeToDoseMeasureCollection::Pointer _MaxOHx; VolumeToDoseMeasureCollection::Pointer _MinOCx; DoseTypeGy _referenceDose; //for Vx computation public: /*! @brief Standard Constructor */ //DoseStatistics(); /*! @brief Constructor @details 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, VoxelNumberType numVoxels, VolumeType volume, ResultListPointer minimumVoxelPositions = nullptr, ResultListPointer maximumVoxelPositions = nullptr, VolumeToDoseMeasureCollection Dx = VolumeToDoseMeasureCollection(VolumeToDoseMeasureCollection::Dx), DoseToVolumeMeasureCollection Vx = DoseToVolumeMeasureCollection(DoseToVolumeMeasureCollection::Vx), VolumeToDoseMeasureCollection MOHx = VolumeToDoseMeasureCollection(VolumeToDoseMeasureCollection::MOHx), VolumeToDoseMeasureCollection MOCx = VolumeToDoseMeasureCollection(VolumeToDoseMeasureCollection::MOCx), VolumeToDoseMeasureCollection MaxOHx = VolumeToDoseMeasureCollection(VolumeToDoseMeasureCollection::MaxOHx), VolumeToDoseMeasureCollection MinOCx = VolumeToDoseMeasureCollection(VolumeToDoseMeasureCollection::MinOCx), DoseTypeGy referenceDose = -1); ~DoseStatistics(); void setMinimumVoxelPositions(ResultListPointer minimumVoxelPositions); void setMaximumVoxelPositions(ResultListPointer maximumVoxelPositions); void setDx(VolumeToDoseMeasureCollection::Pointer DxValues); void setVx(DoseToVolumeMeasureCollection::Pointer VxValues); void setMOHx(VolumeToDoseMeasureCollection::Pointer MOHxValues); void setMOCx(VolumeToDoseMeasureCollection::Pointer MOCxValues); void setMaxOHx(VolumeToDoseMeasureCollection::Pointer MaxOHxValues); void setMinOCx(VolumeToDoseMeasureCollection::Pointer MinOCxValues); void setReferenceDose(DoseTypeGy referenceDose); /*! @brief Get number of voxels in doseIterator, with sub-voxel accuracy. */ VoxelNumberType getNumberOfVoxels() const; /*! @brief Get the volume of the voxels in doseIterator (in cm3), with sub-voxel accuracy */ VolumeType getVolume() const; /*! @brief Get the reference dose for Vx computation */ DoseTypeGy getReferenceDose() const; /*! @brief Get the maximum of the current dose distribution. @return Return the maximum dose in Gy */ DoseStatisticType getMaximum() const; /*! @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 getMaximumVoxelPositions() const; /*! @brief Get the minimum of the current dose distribution. @return Return the minimum dose in Gy */ DoseStatisticType getMinimum() const; /*! @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 getMinimumVoxelPositions() const; /*! @brief Get the mean of the current dose distribution. @return Return the mean dose in Gy */ DoseStatisticType getMean() const; /*! @brief Get the standard deviation of the current dose distribution. @return Return the standard deviation in Gy */ DoseStatisticType getStdDeviation() const; /*! @brief Get the variance of of the current dose distribution. @return Return the variance in Gy */ DoseStatisticType getVariance() const; VolumeToDoseMeasureCollection getDx() const; DoseToVolumeMeasureCollection getVx() const; VolumeToDoseMeasureCollection getMOHx() const; VolumeToDoseMeasureCollection getMOCx() const; VolumeToDoseMeasureCollection getMaxOHx() const; VolumeToDoseMeasureCollection getMinOCx() const; }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/algorithms/rttbDoseStatisticsCalculator.cpp b/code/algorithms/rttbDoseStatisticsCalculator.cpp index f46b77c..6969acb 100644 --- a/code/algorithms/rttbDoseStatisticsCalculator.cpp +++ b/code/algorithms/rttbDoseStatisticsCalculator.cpp @@ -1,419 +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) -*/ #include "rttbDoseStatisticsCalculator.h" #include <boost/shared_ptr.hpp> #include <boost/make_shared.hpp> #include <boost/assign/list_of.hpp> #include <boost/thread/locks.hpp> #include "rttbNullPointerException.h" #include "rttbInvalidDoseException.h" #include "rttbInvalidParameterException.h" #include <boost/thread/thread.hpp> namespace rttb { namespace algorithms { DoseStatisticsCalculator::DoseStatisticsCalculator(DoseIteratorPointer aDoseIterator) { if (aDoseIterator == nullptr) { throw core::NullPointerException("DoseIterator must not be nullptr"); } else { _doseIterator = aDoseIterator; } _simpleDoseStatisticsCalculated = false; _complexDoseStatisticsCalculated = false; _multiThreading = false; _mutex = ::boost::make_shared<::boost::shared_mutex>(); } DoseStatisticsCalculator::~DoseStatisticsCalculator() = default; DoseStatisticsCalculator::DoseIteratorPointer DoseStatisticsCalculator::getDoseIterator() const { return _doseIterator; } DoseStatisticsCalculator::DoseStatisticsPointer DoseStatisticsCalculator::calculateDoseStatistics( bool computeComplexMeasures, unsigned int maxNumberMinimaPositions, unsigned int maxNumberMaximaPositions) { if (_doseIterator == nullptr) { throw core::NullPointerException("_doseIterator must not be nullptr!"); } //"simple" dose statistics are mandatory calculateSimpleDoseStatistics(maxNumberMinimaPositions, maxNumberMaximaPositions); if (computeComplexMeasures) { //more complex dose statistics are optional with default maximum dose and default relative x values calculateComplexDoseStatistics(_statistics->getMaximum(), std::vector<double>(), std::vector<double>()); } return _statistics; } DoseStatisticsCalculator::DoseStatisticsPointer DoseStatisticsCalculator::calculateDoseStatistics( DoseTypeGy referenceDose, unsigned int maxNumberMinimaPositions, unsigned int maxNumberMaximaPositions) { if (_doseIterator == nullptr) { throw core::NullPointerException("_doseIterator must not be nullptr!"); } if (referenceDose <= 0) { throw rttb::core::InvalidParameterException("Reference dose must be > 0 !"); } //simple dose statistics calculateSimpleDoseStatistics(maxNumberMinimaPositions, maxNumberMaximaPositions); //more complex dose statistics with given reference dose and default x values calculateComplexDoseStatistics(referenceDose, std::vector<double>(), std::vector<double>()); return _statistics; } DoseStatisticsCalculator::DoseStatisticsPointer DoseStatisticsCalculator::calculateDoseStatistics( const std::vector<double>& precomputeDoseValues, const std::vector<double>& precomputeVolumeValues, DoseTypeGy referenceDose, unsigned int maxNumberMinimaPositions, unsigned int maxNumberMaximaPositions) { if (_doseIterator == nullptr) { throw core::NullPointerException("_doseIterator must not be nullptr!"); } //"simple" dose statistics calculateSimpleDoseStatistics(maxNumberMinimaPositions, maxNumberMaximaPositions); if (referenceDose <= 0) { //more complex dose statistics with default maximum dose and relative x values calculateComplexDoseStatistics(_statistics->getMaximum(), precomputeDoseValues, precomputeVolumeValues); } else { //more complex dose statistics with given reference dose and relative x values calculateComplexDoseStatistics(referenceDose, precomputeDoseValues, precomputeVolumeValues); } return _statistics; } void DoseStatisticsCalculator::calculateSimpleDoseStatistics(unsigned int maxNumberMinimaPositions, unsigned int maxNumberMaximaPositions) { _doseVector.clear(); _voxelProportionVector.clear(); std::multimap<double, int> doseValueVSIndexMap; std::vector<double> voxelProportionVectorTemp; DoseStatisticType maximumDose = 0; DoseStatisticType minimumDose = std::numeric_limits<DoseStatisticType>::max(); DoseStatisticType meanDose; DoseStatisticType stdDeviationDose; DoseTypeGy sum = 0; VolumeType numVoxels = 0.0; DoseTypeGy squareSum = 0; VolumeType volume = 0; _doseIterator->reset(); int i = 0; DoseTypeGy doseValue = 0; while (_doseIterator->isPositionValid()) { doseValue = _doseIterator->getCurrentDoseValue(); if (i == 0) { minimumDose = doseValue; volume = _doseIterator->getCurrentVoxelVolume(); } rttb::FractionType voxelProportion = _doseIterator->getCurrentRelevantVolumeFraction(); sum += doseValue * voxelProportion; numVoxels += voxelProportion; squareSum += doseValue * doseValue * voxelProportion; if (doseValue > maximumDose) { maximumDose = doseValue; } else if (doseValue < minimumDose) { minimumDose = doseValue; } voxelProportionVectorTemp.push_back(voxelProportion); doseValueVSIndexMap.insert(std::pair<double, int>(doseValue, i)); i++; _doseIterator->next(); } if (numVoxels != 0) { meanDose = sum / numVoxels; //standard deviation is defined only for n>=2 if (numVoxels >= 2) { //uncorrected variance is calculated DoseStatisticType varianceDose = (squareSum / numVoxels - meanDose * meanDose); if (varianceDose < errorConstant) { stdDeviationDose = 0; } else { stdDeviationDose = pow(varianceDose, 0.5); } } else { stdDeviationDose = 0; } } //sort dose values and corresponding volume fractions in member variables for (auto & it : doseValueVSIndexMap) { _doseVector.push_back((float)it.first); _voxelProportionVector.push_back(voxelProportionVectorTemp.at(it.second)); } volume *= numVoxels; _statistics = boost::make_shared<DoseStatistics>(minimumDose, maximumDose, meanDose, stdDeviationDose, numVoxels, volume); _simpleDoseStatisticsCalculated = true; ResultListPointer minimumVoxelPositions = computeMinimumPositions(maxNumberMinimaPositions); ResultListPointer maximumVoxelPositions = computeMaximumPositions(maxNumberMaximaPositions); _statistics->setMinimumVoxelPositions(minimumVoxelPositions); _statistics->setMaximumVoxelPositions(maximumVoxelPositions); } void DoseStatisticsCalculator::calculateComplexDoseStatistics(DoseTypeGy referenceDose, const std::vector<double>& precomputeDoseValues, const std::vector<double>& precomputeVolumeValues) { if (!_simpleDoseStatisticsCalculated) { throw core::InvalidDoseException("simple DoseStatistics have to be computed in order to call calculateComplexDoseStatistics()"); } std::vector<double> precomputeDoseValuesNonConst = precomputeDoseValues; std::vector<double> precomputeVolumeValuesNonConst = precomputeVolumeValues; //set default values if (precomputeDoseValues.empty()) { std::vector<double> defaultPrecomputeDoseValues = boost::assign::list_of(0.02)(0.05)(0.1)(0.9)( 0.95)(0.98); precomputeDoseValuesNonConst = defaultPrecomputeDoseValues; } if (precomputeVolumeValues.empty()) { std::vector<double> defaultPrecomputeVolumeValues = boost::assign::list_of(0.02)(0.05)(0.1)(0.9)( 0.95)(0.98); precomputeVolumeValuesNonConst = defaultPrecomputeVolumeValues; } _Vx = ::boost::make_shared<VxDoseToVolumeMeasureCollectionCalculator>(precomputeDoseValuesNonConst, referenceDose, _doseIterator); _Vx->compute(); _Dx = ::boost::make_shared<DxVolumeToDoseMeasureCollectionCalculator>(precomputeVolumeValuesNonConst, _statistics->getVolume(), this->_doseVector, this->_voxelProportionVector, this->_doseIterator->getCurrentVoxelVolume(), _statistics->getMinimum()); _Dx->compute(); _MOHx = ::boost::make_shared<MOHxVolumeToDoseMeasureCollectionCalculator>(precomputeVolumeValuesNonConst, _statistics->getVolume(), this->_doseVector, this->_voxelProportionVector, this->_doseIterator->getCurrentVoxelVolume()); _MOHx->compute(); _MOCx = ::boost::make_shared<MOCxVolumeToDoseMeasureCollectionCalculator>(precomputeVolumeValuesNonConst, _statistics->getVolume(), this->_doseVector, this->_voxelProportionVector, this->_doseIterator->getCurrentVoxelVolume()); _MOCx->compute(); _MaxOHx = ::boost::make_shared<MaxOHxVolumeToDoseMeasureCollectionCalculator>(precomputeVolumeValuesNonConst, _statistics->getVolume(), this->_doseVector, this->_voxelProportionVector, this->_doseIterator->getCurrentVoxelVolume()); _MaxOHx->compute(); _MinOCx = ::boost::make_shared<MinOCxVolumeToDoseMeasureCollectionCalculator>(precomputeVolumeValuesNonConst, _statistics->getVolume(), this->_doseVector, this->_voxelProportionVector, this->_doseIterator->getCurrentVoxelVolume(), _statistics->getMinimum(), _statistics->getMaximum()); _MinOCx->compute(); _statistics->setVx(_Vx->getMeasureCollection()); _statistics->setDx(_Dx->getMeasureCollection()); _statistics->setMOHx(_MOHx->getMeasureCollection()); _statistics->setMOCx(_MOCx->getMeasureCollection()); _statistics->setMaxOHx(_MaxOHx->getMeasureCollection()); _statistics->setMinOCx(_MinOCx->getMeasureCollection()); _statistics->setReferenceDose(referenceDose); _complexDoseStatisticsCalculated = true; } void DoseStatisticsCalculator::addPrecomputeValues(const std::vector<double>& values) { if (!_complexDoseStatisticsCalculated) { throw core::InvalidDoseException("Complex DoseStatistics have to be computed in order to call addPrecomputeDoseValues()"); } _Vx->addPrecomputeDoseValues(values); _Dx->addPrecomputeVolumeValues(values); _MOHx->addPrecomputeVolumeValues(values); _MOCx->addPrecomputeVolumeValues(values); _MaxOHx->addPrecomputeVolumeValues(values); _MinOCx->addPrecomputeVolumeValues(values); } void DoseStatisticsCalculator::recalculateDoseStatistics() { if (!_complexDoseStatisticsCalculated) { throw core::InvalidDoseException("Complex DoseStatistics have to be computed in order to call recalculateDoseStatistics()"); } _Vx->compute(); _Dx->compute(); _MOHx->compute(); _MOCx->compute(); _MaxOHx->compute(); _MinOCx->compute(); } DoseStatisticsCalculator::ResultListPointer DoseStatisticsCalculator::computeMaximumPositions( unsigned int maxNumberMaxima) const { if (!_simpleDoseStatisticsCalculated) { throw core::InvalidDoseException("simple DoseStatistics have to be computed in order to call computeMaximumPositions()"); } ResultListPointer maxVoxelVector = boost::make_shared<std::vector<std::pair<DoseTypeGy, VoxelGridID> > >(); unsigned int count = 0; this->_doseIterator->reset(); DoseTypeGy doseValue = 0; while (_doseIterator->isPositionValid() && count < maxNumberMaxima) { doseValue = _doseIterator->getCurrentDoseValue(); if (doseValue == _statistics->getMaximum()) { VoxelGridID currentID = _doseIterator->getCurrentVoxelGridID(); std::pair<DoseTypeGy, VoxelGridID> voxel(doseValue, currentID); maxVoxelVector->push_back(voxel); count++; } _doseIterator->next(); } return maxVoxelVector; } DoseStatisticsCalculator::ResultListPointer DoseStatisticsCalculator::computeMinimumPositions( unsigned int maxNumberMinima) const { if (!_simpleDoseStatisticsCalculated) { throw core::InvalidDoseException("simple DoseStatistics have to be computed in order to call computeMinimumPositions()"); } ResultListPointer minVoxelVector = boost::make_shared<std::vector<std::pair<DoseTypeGy, VoxelGridID> > >(); /*! @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)). */ unsigned int count = 0; this->_doseIterator->reset(); DoseTypeGy doseValue = 0; while (_doseIterator->isPositionValid() && count < maxNumberMinima) { doseValue = _doseIterator->getCurrentDoseValue(); if (doseValue == _statistics->getMinimum()) { VoxelGridID currentID = _doseIterator->getCurrentVoxelGridID(); std::pair<DoseTypeGy, VoxelGridID> voxel(doseValue, currentID); minVoxelVector->push_back(voxel); count++; } _doseIterator->next(); } return minVoxelVector; } void DoseStatisticsCalculator::setMultiThreading(const bool choice) { _multiThreading = choice; } }//end namespace algorithms }//end namespace rttb diff --git a/code/algorithms/rttbDoseStatisticsCalculator.h b/code/algorithms/rttbDoseStatisticsCalculator.h index 431850a..3f075be 100644 --- a/code/algorithms/rttbDoseStatisticsCalculator.h +++ b/code/algorithms/rttbDoseStatisticsCalculator.h @@ -1,207 +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) -*/ #ifndef __DOSE_STATISTICS_CALCULATOR_H #define __DOSE_STATISTICS_CALCULATOR_H #include <vector> #include <boost/shared_ptr.hpp> #include <boost/thread/shared_mutex.hpp> #include "rttbDoseIteratorInterface.h" #include "rttbDoseStatistics.h" #include "RTTBAlgorithmsExports.h" #include "rttbDxVolumeToDoseMeasureCollectionCalculator.h" #include "rttbVxDoseToVolumeMeasureCollectionCalculator.h" #include "rttbMOHxVolumeToDoseMeasureCollectionCalculator.h" #include "rttbMOCxVolumeToDoseMeasureCollectionCalculator.h" #include "rttbMaxOHxVolumeToDoseMeasureCollectionCalculator.h" #include "rttbMinOCxVolumeToDoseMeasureCollectionCalculator.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace algorithms { /*! @class DoseStatisticsCalculator @brief Class for calculating different statistical values from a RT dose distribution @details These values range from standard statistical values such as minimum, maximum and mean to more complex dose specific measures such as Vx (volume irradiated with a dose >=x), Dx (minimal dose delivered to x% of the VOI) or MOHx (mean in the hottest volume). For a complete list, see calculateDoseStatistics(). @note the complex dose statistics are precomputed and cannot be computed "on the fly" lateron! The doses/volumes that should be used for precomputation have to be set in calculateDoseStatistics() */ class RTTBAlgorithms_EXPORT DoseStatisticsCalculator { public: using DoseIteratorPointer = core::DoseIteratorInterface::Pointer; using ResultListPointer = DoseStatistics::ResultListPointer; using DoseStatisticsPointer = DoseStatistics::Pointer; private: DoseIteratorPointer _doseIterator; /*! @brief Contains relevant dose values sorted in descending order. */ std::vector<DoseTypeGy> _doseVector; /*! @brief Contains the corresponding voxel proportions to the values in doseVector. */ std::vector<double> _voxelProportionVector; /*! @brief The doseStatistics are stored here. */ DoseStatisticsPointer _statistics; bool _simpleDoseStatisticsCalculated; bool _complexDoseStatisticsCalculated; bool _multiThreading; ::boost::shared_ptr<boost::shared_mutex> _mutex; VxDoseToVolumeMeasureCollectionCalculator::Pointer _Vx; DxVolumeToDoseMeasureCollectionCalculator::Pointer _Dx; MOHxVolumeToDoseMeasureCollectionCalculator::Pointer _MOHx; MOCxVolumeToDoseMeasureCollectionCalculator::Pointer _MOCx; MaxOHxVolumeToDoseMeasureCollectionCalculator::Pointer _MaxOHx; MinOCxVolumeToDoseMeasureCollectionCalculator::Pointer _MinOCx; /*! @brief Calculates the positions where the dose has its maximum @param maxNumberMaximaPositions the maximal amount of computed positions @pre maximumDose must be defined in _statistics with the correct value */ ResultListPointer computeMaximumPositions(unsigned int maxNumberMaximaPositions) const; /*! @brief Calculates the positions where the dose has its minimum @param maxNumberMinimaPositions the maximal amount of computed positions (they are read sequentially using the iterator until maxNumberMinimaPositions have been read, other positions are not considered) @pre minimumDose must be defined in _statistics with the correct value */ ResultListPointer computeMinimumPositions(unsigned int maxNumberMinimaPositions) const; /*! @brief Calculates simple dose statistics (min, mean, max, stdDev, minDosePositions, maxDosePositions) @param maxNumberMinimaPositions the maximal amount of computed positions where the dose has its minimum that is computed @param maxNumberMaximaPositions the maximal amount of computed positions where the dose has its maximum that is computed */ void calculateSimpleDoseStatistics(unsigned int maxNumberMinimaPositions, unsigned int maxNumberMaximaPositions); /*! @brief Calculates complex dose statistics (Dx, Vx, MOHx, MOCx, MaxOHx, MinOCx) @warning computations can take quite long (>1 min) for large structures as many statistics are precomputed */ void calculateComplexDoseStatistics(DoseTypeGy referenceDose, const std::vector<double>& precomputeDoseValues, const std::vector<double>& precomputeVolumeValues); public: ~DoseStatisticsCalculator(); /*! @brief Constructor @param aDoseIterator the dose to be analyzed */ DoseStatisticsCalculator(DoseIteratorPointer aDoseIterator); DoseIteratorPointer getDoseIterator() const; /*! @brief Compute simple or complex dose statistics with default relative x values and the maximum dose as default reference dose (for Vx computation) @details The following statistics are calculated always (i.e. also if computeComplexMeasures=false): <ul> <li>minimum dose <li>mean dose <li>maximum dose <li>standard deviation dose <li>voxel positions of minimum dose <li>voxel positions of maximum dose </ul> Additionally, these statistics are computed if computeComplexMeasures=true: <ul> <li>Dx (the minimal dose delivered to a volume >= x) <li>Vx (the volume irradiated with a dose >= x) <li>MOHx (mean dose of the hottest x volume) <li>MOCx (mean dose of the coldest x volume) <li>MaxOHx (Maximum outside of the hottest x volume) <li>MinOCx (Minimum outside of the coldest x volume) </ul> Default x values for Vx are 0.02, 0.05, 0.1, 0.9, 0.95 and 0.98, with respect to maxDose. Default x values for Dx, MOHx, MOCx, MaxOHx and MinOCx are 0.02, 0.05, 0.1, 0.9, 0.95 and 0.98, with respect to volume. @param computeComplexMeasures should complex statistics be calculated? If it is true, the complex dose statistics will be calculated with default relative x values and the maximum dose as reference dose @param maxNumberMinimaPositions the maximal amount of computed positions where the dose has its minimum that is computed @param maxNumberMaximaPositions the maximal amount of computed positions where the dose has its maximum that is computed @warning If computeComplexMeasures==true, computations can take quite long (>1 min) for large structures as many statistics are precomputed @note The complex dose statistics are precomputed and cannot be computed "on the fly" lateron! Only the default x values can be requested in DoseStatistics! */ DoseStatisticsPointer calculateDoseStatistics(bool computeComplexMeasures = false, unsigned int maxNumberMinimaPositions = 10, unsigned int maxNumberMaximaPositions = 10); /*! @brief Compute complex dose statistics with given reference dose and default relative x values @param referenceDose the reference dose to compute Vx, normally it should be the prescribed dose @param maxNumberMinimaPositions the maximal amount of computed positions where the dose has its minimum that is computed @param maxNumberMaximaPositions the maximal amount of computed positions where the dose has its maximum that is computed @exception InvalidParameterException thrown if referenceDose <= 0 @warning Computations can take quite long (>1 min) for large structures as many statistics are precomputed @note The complex dose statistics are precomputed and cannot be computed "on the fly" lateron! Only the default x values can be requested in DoseStatistics! */ DoseStatisticsPointer calculateDoseStatistics(DoseTypeGy referenceDose, unsigned int maxNumberMinimaPositions = 10, unsigned int maxNumberMaximaPositions = 10); /*! @brief Compute complex dose statistics with given relative x values and reference dose @param precomputeDoseValues the relative dose values for Vx precomputation, e.g. 0.02, 0.05, 0.95... @param precomputeVolumeValues the relative volume values for Dx, MOHx, MOCx, MaxOHx and MinOCx precomputation, e.g. 0.02, 0.05, 0.95... @param referenceDose the reference dose to compute Vx, normally it should be the prescribed dose. Default value is the maximum dose. @param maxNumberMinimaPositions the maximal amount of computed positions where the dose has its minimum that is computed @param maxNumberMaximaPositions the maximal amount of computed positions where the dose has its maximum that is computed @warning Computations can take quite long (>1 min) for large structures as many statistics are precomputed @note The complex dose statistics are precomputed and cannot be computed "on the fly" lateron! The doses/volumes that should be used for precomputation have to be set by in precomputeDoseValues and precomputeVolumeValues. Only these values can be requested in DoseStatistics! */ DoseStatisticsPointer calculateDoseStatistics(const std::vector<double>& precomputeDoseValues, const std::vector<double>& precomputeVolumeValues, DoseTypeGy referenceDose = -1, unsigned int maxNumberMinimaPositions = 10, unsigned int maxNumberMaximaPositions = 10); /*! @brief Adds additonal precompute values for all complex Dose Statistics @exception InvalidDoseException if complexDoseStatistics are not already calculated */ void addPrecomputeValues(const std::vector<double>& values); /*! @brief Recalculates the DoseMeasures for all complex Dose Statistics @exception InvalidDoseException if complexDoseStatistics are not already calculated */ void recalculateDoseStatistics(); void setMultiThreading(bool choice); }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/algorithms/rttbDoseToVolumeMeasureCollection.cpp b/code/algorithms/rttbDoseToVolumeMeasureCollection.cpp index f4e3546..bc97a13 100644 --- a/code/algorithms/rttbDoseToVolumeMeasureCollection.cpp +++ b/code/algorithms/rttbDoseToVolumeMeasureCollection.cpp @@ -1,91 +1,85 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include "rttbDoseToVolumeMeasureCollection.h" #include "rttbInvalidParameterException.h" #include "rttbDataNotAvailableException.h" namespace rttb { namespace algorithms { DoseToVolumeMeasureCollection::DoseToVolumeMeasureCollection(complexStatistics name, DoseTypeGy referenceDose) : _name(name), _referenceDose(referenceDose), _values(std::map<VolumeType, DoseTypeGy>()) {} void DoseToVolumeMeasureCollection::setReferenceDose(DoseTypeGy referenceDose) { this->_referenceDose = referenceDose; } void DoseToVolumeMeasureCollection::insertValue(DoseTypeGy dose, VolumeType volume) { this->_values.insert(std::pair<DoseTypeGy, VolumeType>(dose, volume)); } VolumeType DoseToVolumeMeasureCollection::getValue(DoseTypeGy xVolumeAbsolute) const { VolumeType dummy; return getSpecificValue(_values, xVolumeAbsolute, false, dummy); } VolumeType DoseToVolumeMeasureCollection::getValue(DoseTypeGy xDoseAbsolute, bool findNearestValue, DoseTypeGy & nearestXDose) const { return getSpecificValue(_values, xDoseAbsolute, findNearestValue, nearestXDose); } VolumeType DoseToVolumeMeasureCollection::getValueRelative(DoseTypeGy xDoseRelative) const { if (_referenceDose != -1 && xDoseRelative >= 0 && xDoseRelative <= 1) { DoseTypeGy xDoseAbsolute = xDoseRelative * _referenceDose; DoseTypeGy dummy; return getSpecificValue(_values, xDoseAbsolute, false, dummy); } else { throw rttb::core::InvalidParameterException("Reference dose must be > 0 and 0 <= relative Dose <= 1"); } } VolumeType DoseToVolumeMeasureCollection::getValueRelative(DoseTypeGy xDoseRelative, bool findNearestValue, DoseTypeGy & nearestXDose) const { if (_referenceDose != -1 && xDoseRelative >= 0 && xDoseRelative <= 1) { DoseTypeGy xDoseAbsolute = xDoseRelative * _referenceDose; return getSpecificValue(_values, xDoseAbsolute, findNearestValue, nearestXDose); } else { throw rttb::core::InvalidParameterException("Reference dose must be > 0 and 0 <= relative Dose <= 1"); } } DoseToVolumeMeasureCollection::DoseToVolumeFunctionType DoseToVolumeMeasureCollection::getAllValues() const { return this->_values; } bool operator==(const DoseToVolumeMeasureCollection& volumeToDoseMesureCollection, const DoseToVolumeMeasureCollection& otherVolumeToDoseMesureCollection) { if (volumeToDoseMesureCollection.getName() == otherVolumeToDoseMesureCollection.getName() && volumeToDoseMesureCollection.getAllValues() == otherVolumeToDoseMesureCollection.getAllValues()) { return true; } return false; } } } diff --git a/code/algorithms/rttbDoseToVolumeMeasureCollection.h b/code/algorithms/rttbDoseToVolumeMeasureCollection.h index 83af22b..c335296 100644 --- a/code/algorithms/rttbDoseToVolumeMeasureCollection.h +++ b/code/algorithms/rttbDoseToVolumeMeasureCollection.h @@ -1,82 +1,76 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #ifndef __DOSE_TO_VOLUME_MEASURE_COLLECTION_H #define __DOSE_TO_VOLUME_MEASURE_COLLECTION_H #include "rttbMeasureCollection.h" #include <rttbCommon.h> #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace algorithms { /*! @class DoseToVolumeMeasureCollection @brief This class handels the access to the DoseToVolumeMeasureCollection elements for a specific complex statistic @note _referenceDose has to be set to use getValueRelative() otherwise an exception is thrown */ class RTTBAlgorithms_EXPORT DoseToVolumeMeasureCollection : public MeasureCollection { public: rttbClassMacro(DoseToVolumeMeasureCollection, MeasureCollection) typedef std::map<DoseTypeGy, VolumeType> DoseToVolumeFunctionType; private: complexStatistics _name; DoseTypeGy _referenceDose; DoseToVolumeFunctionType _values; public: DoseToVolumeMeasureCollection(complexStatistics name, DoseTypeGy referenceDose = -1); /*! @brief This has to be set >=0 to use getValueRelative() */ void setReferenceDose(DoseTypeGy referenceDose); void insertValue(DoseTypeGy dose, VolumeType volume); /*! @brief Gets the volume irradiated with a dose >= x, depending on the complexStatistics name. @return Return absolute volume in absolute cm^3. @exception InvalidDoseException if the vector values is empty or _referenceDose is -1 @exception NoDataException if the requested Dose is not in the vector */ VolumeType getValue(DoseTypeGy xVolumeAbsolute) const; VolumeType getValue(DoseTypeGy xVolumeAbsolute, bool findNearestValue, DoseTypeGy& nearestXDose) const; VolumeType getValueRelative(DoseTypeGy xDoseRelative) const; VolumeType getValueRelative(DoseTypeGy xDoseRelative, bool findNearestValue, DoseTypeGy& nearestXDose) const; DoseToVolumeFunctionType getAllValues() const; friend bool operator==(const DoseToVolumeMeasureCollection& volumeToDoseMesureCollection, const DoseToVolumeMeasureCollection& otherVolumeToDoseMesureCollection); }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/algorithms/rttbDoseToVolumeMeasureCollectionCalculator.cpp b/code/algorithms/rttbDoseToVolumeMeasureCollectionCalculator.cpp index 9709cbf..419c861 100644 --- a/code/algorithms/rttbDoseToVolumeMeasureCollectionCalculator.cpp +++ b/code/algorithms/rttbDoseToVolumeMeasureCollectionCalculator.cpp @@ -1,92 +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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include "rttbDoseToVolumeMeasureCollectionCalculator.h" #include <boost/thread/thread.hpp> #include "rttbInvalidParameterException.h" #include "rttbUtils.h" #include <boost/make_shared.hpp> //#include <boost/thread/locks.hpp> namespace rttb { namespace algorithms { DoseToVolumeMeasureCollectionCalculator::DoseToVolumeMeasureCollectionCalculator(const std::vector<double>& precomputeDoseValues, const DoseTypeGy referenceDose, const core::DoseIteratorInterface::Pointer doseIterator, DoseToVolumeMeasureCollection::complexStatistics name, bool multiThreading) : _doseIterator(doseIterator), _referenceDose(referenceDose), _measureCollection(::boost::make_shared<DoseToVolumeMeasureCollection>(name)), _multiThreading(multiThreading) { addPrecomputeDoseValues(precomputeDoseValues); } void DoseToVolumeMeasureCollectionCalculator::compute() { std::vector<boost::thread> threads; for (double _precomputeDoseValue : _precomputeDoseValues) { double xAbsolute = _precomputeDoseValue * _referenceDose; if (!rttb::core::isKey(_measureCollection->getAllValues(), xAbsolute)) { if (_multiThreading) { throw rttb::core::InvalidParameterException("MultiThreading is not implemented yet."); //threads.push_back(boost::thread(&DoseToVolumeMeasureCollectionCalculator::insertIntoMeasureCollection, this , xAbsolute, computeSpecificValue(xAbsolute))); } else { insertIntoMeasureCollection(xAbsolute, this->computeSpecificValue(xAbsolute)); } } } for (auto & thread : threads) { thread.join(); } } void DoseToVolumeMeasureCollectionCalculator::addPrecomputeDoseValues(const std::vector<double>& values) { for (double value : values) { if (value > 1 || value < 0) { throw rttb::core::InvalidParameterException("Values must be between 1 and 0!"); } if (!rttb::core::isKey(_precomputeDoseValues, value)) { _precomputeDoseValues.push_back(value); } } } DoseToVolumeMeasureCollection::Pointer DoseToVolumeMeasureCollectionCalculator::getMeasureCollection() { return _measureCollection; } void DoseToVolumeMeasureCollectionCalculator::insertIntoMeasureCollection(DoseTypeGy xAbsolute, VolumeType resultVolume) { _measureCollection->insertValue(xAbsolute, resultVolume); } } } diff --git a/code/algorithms/rttbDoseToVolumeMeasureCollectionCalculator.h b/code/algorithms/rttbDoseToVolumeMeasureCollectionCalculator.h index b07d0e3..dedfd9f 100644 --- a/code/algorithms/rttbDoseToVolumeMeasureCollectionCalculator.h +++ b/code/algorithms/rttbDoseToVolumeMeasureCollectionCalculator.h @@ -1,99 +1,93 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #ifndef __DOSE_TO_VOLUME_MEASURE_COLLECTION_CALCULATOR_H #define __DOSE_TO_VOLUME_MEASURE_COLLECTION_CALCULATOR_H #include <vector> #include <map> #include "rttbBaseType.h" #include "RTTBAlgorithmsExports.h" #include "rttbDoseToVolumeMeasureCollection.h" #include "rttbDoseIteratorInterface.h" #include <rttbCommon.h> #include "rttbDoseStatistics.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace algorithms { /*! @class DoseToVolumeMeasureCollectionCalculator @brief Class for calculating DoseToVolume measures @details This class is used as a basis for DoseToVolumeMeasureCollectionCalculators. It implements the compute() method that is the same for every inheriting subclass, it accesses computeSpecificValue, which has to be implemented for each different complex statistic. */ class RTTBAlgorithms_EXPORT DoseToVolumeMeasureCollectionCalculator { public: rttbClassMacroNoParent(DoseToVolumeMeasureCollectionCalculator) typedef std::map<DoseTypeGy, VolumeType> VolumeToDoseFunctionType; protected: core::DoseIteratorInterface::Pointer _doseIterator; private: std::vector<double> _precomputeDoseValues; DoseTypeGy _referenceDose; DoseToVolumeMeasureCollection::Pointer _measureCollection; bool _multiThreading; public: /*! @brief Computes not already computed values for the measureCollection. Algorithm for the specific complex Statistic has to be implemented in the corresponding subclass. */ void compute(); /*! @brief Adds additional values to the _precomputeDoseValues vector. @exception InvalidParameterException If values vector contains values that are not between 0 and 1 */ void addPrecomputeDoseValues(const std::vector<double>& values); DoseToVolumeMeasureCollection::Pointer getMeasureCollection(); protected: DoseToVolumeMeasureCollectionCalculator(const std::vector<double>& precomputeDoseValues, const DoseTypeGy referenceDose, const core::DoseIteratorInterface::Pointer doseIterator, DoseToVolumeMeasureCollection::complexStatistics name, bool multiThreading); void insertIntoMeasureCollection(DoseTypeGy xAbsolute, VolumeType resultVolume); /*! @brief Computes the specific VolumeType depending on the complext statistic @note has to be overwritten */ virtual VolumeType computeSpecificValue(double xAbsolute) const = 0; }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/algorithms/rttbDxVolumeToDoseMeasureCollectionCalculator.cpp b/code/algorithms/rttbDxVolumeToDoseMeasureCollectionCalculator.cpp index d91a6b8..be8e0e9 100644 --- a/code/algorithms/rttbDxVolumeToDoseMeasureCollectionCalculator.cpp +++ b/code/algorithms/rttbDxVolumeToDoseMeasureCollectionCalculator.cpp @@ -1,61 +1,55 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include "rttbDxVolumeToDoseMeasureCollectionCalculator.h" namespace rttb { namespace algorithms { DxVolumeToDoseMeasureCollectionCalculator::DxVolumeToDoseMeasureCollectionCalculator(const std::vector<double>& precomputeVolumeValues, const VolumeType volume, const std::vector<DoseTypeGy>& doseVector, const std::vector<double>& voxelProportionVector, const DoseVoxelVolumeType currentVoxelVolume, const DoseStatisticType minimum, bool multiThreading) : VolumeToDoseMeasureCollectionCalculator(precomputeVolumeValues, volume, doseVector, voxelProportionVector, currentVoxelVolume, VolumeToDoseMeasureCollection::Dx, multiThreading), _minimum(minimum) {} DoseTypeGy DxVolumeToDoseMeasureCollectionCalculator::computeSpecificValue(double xAbsolute) const { double noOfVoxel = xAbsolute / _currentVoxelVolume; DoseTypeGy resultDose = 0; double countVoxels = 0; bool voxelOverflow = false; for (auto i = _doseVector.size() - 1; i != static_cast<size_t>(-1); i--) { countVoxels += _voxelProportionVector.at(i); if (countVoxels >= noOfVoxel) { voxelOverflow = true; resultDose = _doseVector.at(i); break; } } if (!voxelOverflow) { resultDose = _minimum; } return resultDose; } } } \ No newline at end of file diff --git a/code/algorithms/rttbDxVolumeToDoseMeasureCollectionCalculator.h b/code/algorithms/rttbDxVolumeToDoseMeasureCollectionCalculator.h index aac332d..a6e1509 100644 --- a/code/algorithms/rttbDxVolumeToDoseMeasureCollectionCalculator.h +++ b/code/algorithms/rttbDxVolumeToDoseMeasureCollectionCalculator.h @@ -1,56 +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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #ifndef __DX_VOLUME_TO_DOSE_MEASURE_COLLECTION_CALCULATOR_H #define __DX_VOLUME_TO_DOSE_MEASURE_COLLECTION_CALCULATOR_H #include "rttbVolumeToDoseMeasureCollectionCalculator.h" #include <rttbCommon.h> namespace rttb { namespace algorithms { /*! @class DxVolumeToDoseMeasureCollectionCalculator @brief Class for calculating Dx VolumeToDose measures */ class RTTBAlgorithms_EXPORT DxVolumeToDoseMeasureCollectionCalculator: public VolumeToDoseMeasureCollectionCalculator { public: rttbClassMacro(DxVolumeToDoseMeasureCollectionCalculator, VolumeToDoseMeasureCollectionCalculator) private: DoseStatisticType _minimum; public: DxVolumeToDoseMeasureCollectionCalculator(const std::vector<double>& precomputeVolumeValues, const VolumeType volume, const std::vector<DoseTypeGy>& doseVector, const std::vector<double>& voxelProportionVector, const DoseVoxelVolumeType currentVoxelVolume, const DoseStatisticType minimum, bool multiThreading = false); protected: DoseTypeGy computeSpecificValue(double xAbsolute) const override; }; } } #endif diff --git a/code/algorithms/rttbMOCxVolumeToDoseMeasureCollectionCalculator.cpp b/code/algorithms/rttbMOCxVolumeToDoseMeasureCollectionCalculator.cpp index 7b0330d..6cf1a3c 100644 --- a/code/algorithms/rttbMOCxVolumeToDoseMeasureCollectionCalculator.cpp +++ b/code/algorithms/rttbMOCxVolumeToDoseMeasureCollectionCalculator.cpp @@ -1,63 +1,57 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include "rttbMOCxVolumeToDoseMeasureCollectionCalculator.h" namespace rttb { namespace algorithms { MOCxVolumeToDoseMeasureCollectionCalculator::MOCxVolumeToDoseMeasureCollectionCalculator(const std::vector<double>& precomputeVolumeValues, const VolumeType volume, const std::vector<DoseTypeGy>& doseVector, const std::vector<double>& voxelProportionVector, const DoseVoxelVolumeType currentVoxelVolume, bool multiThreading) : VolumeToDoseMeasureCollectionCalculator(precomputeVolumeValues, volume, doseVector, voxelProportionVector, currentVoxelVolume, VolumeToDoseMeasureCollection::MOCx, multiThreading) {} DoseTypeGy MOCxVolumeToDoseMeasureCollectionCalculator::computeSpecificValue(double xAbsolute) const { double noOfVoxel = xAbsolute / _currentVoxelVolume; if (noOfVoxel == 0) { return 0; } else { double countVoxels = 0; double sum = 0; auto it = _doseVector.begin(); auto itD = _voxelProportionVector.begin(); for (; it != _doseVector.end(); ++it, ++itD) { double voxelProportion = *itD; countVoxels += voxelProportion; sum += (*it) * voxelProportion; if (countVoxels >= noOfVoxel) { break; } } return static_cast<DoseTypeGy>(sum / noOfVoxel); } } } } \ No newline at end of file diff --git a/code/algorithms/rttbMOCxVolumeToDoseMeasureCollectionCalculator.h b/code/algorithms/rttbMOCxVolumeToDoseMeasureCollectionCalculator.h index 0e0251a..36614a9 100644 --- a/code/algorithms/rttbMOCxVolumeToDoseMeasureCollectionCalculator.h +++ b/code/algorithms/rttbMOCxVolumeToDoseMeasureCollectionCalculator.h @@ -1,52 +1,46 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #ifndef __MOCX_VOLUME_TO_DOSE_MEASURE_COLLECTION_CALCULATOR_H #define __MOCX_VOLUME_TO_DOSE_MEASURE_COLLECTION_CALCULATOR_H #include "rttbVolumeToDoseMeasureCollectionCalculator.h" #include <rttbCommon.h> namespace rttb { namespace algorithms { /*! @class MOCxVolumeToDoseMeasureCollectionCalculator @brief Class for calculating MOCx VolumeToDose measures */ class RTTBAlgorithms_EXPORT MOCxVolumeToDoseMeasureCollectionCalculator : public VolumeToDoseMeasureCollectionCalculator { public: rttbClassMacro(MOCxVolumeToDoseMeasureCollectionCalculator, VolumeToDoseMeasureCollectionCalculator) MOCxVolumeToDoseMeasureCollectionCalculator(const std::vector<double>& precomputeVolumeValues, const VolumeType volume, const std::vector<DoseTypeGy>& doseVector, const std::vector<double>& voxelProportionVector, const DoseVoxelVolumeType currentVoxelVolume, bool multiThreading = false); protected: DoseTypeGy computeSpecificValue(double xAbsolute) const override; }; } } #endif diff --git a/code/algorithms/rttbMOHxVolumeToDoseMeasureCollectionCalculator.cpp b/code/algorithms/rttbMOHxVolumeToDoseMeasureCollectionCalculator.cpp index fe4c776..713a5b9 100644 --- a/code/algorithms/rttbMOHxVolumeToDoseMeasureCollectionCalculator.cpp +++ b/code/algorithms/rttbMOHxVolumeToDoseMeasureCollectionCalculator.cpp @@ -1,63 +1,57 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include "rttbMOHxVolumeToDoseMeasureCollectionCalculator.h" namespace rttb { namespace algorithms { MOHxVolumeToDoseMeasureCollectionCalculator::MOHxVolumeToDoseMeasureCollectionCalculator(const std::vector<double>& precomputeVolumeValues, const VolumeType volume, const std::vector<DoseTypeGy>& doseVector, const std::vector<double>& voxelProportionVector, const DoseVoxelVolumeType currentVoxelVolume, bool multiThreading) : VolumeToDoseMeasureCollectionCalculator(precomputeVolumeValues, volume, doseVector, voxelProportionVector, currentVoxelVolume, VolumeToDoseMeasureCollection::MOHx, multiThreading) {} DoseTypeGy MOHxVolumeToDoseMeasureCollectionCalculator::computeSpecificValue(double xAbsolute) const { double noOfVoxel = xAbsolute / _currentVoxelVolume; if (noOfVoxel == 0) { return 0; } else { double countVoxels = 0; double sum = 0; for (auto i = _doseVector.size() - 1; i!=static_cast<size_t>(-1); i--) { double voxelProportion = _voxelProportionVector.at(i); countVoxels += voxelProportion; sum += _doseVector.at(i) * voxelProportion; if (countVoxels >= noOfVoxel) { break; } } return static_cast<DoseTypeGy>(sum / noOfVoxel); } } } } \ No newline at end of file diff --git a/code/algorithms/rttbMOHxVolumeToDoseMeasureCollectionCalculator.h b/code/algorithms/rttbMOHxVolumeToDoseMeasureCollectionCalculator.h index 291af78..f7b2f06 100644 --- a/code/algorithms/rttbMOHxVolumeToDoseMeasureCollectionCalculator.h +++ b/code/algorithms/rttbMOHxVolumeToDoseMeasureCollectionCalculator.h @@ -1,55 +1,49 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #ifndef __MOHX_VOLUME_TO_DOSE_MEASURE_COLLECTION_CALCULATOR_H #define __MOHX_VOLUME_TO_DOSE_MEASURE_COLLECTION_CALCULATOR_H #include "rttbVolumeToDoseMeasureCollectionCalculator.h" #include <rttbCommon.h> namespace rttb { namespace algorithms { /*! @class MOHxVolumeToDoseMeasureCollectionCalculator @brief Class for calculating MOHx VolumeToDose measures */ class RTTBAlgorithms_EXPORT MOHxVolumeToDoseMeasureCollectionCalculator : public VolumeToDoseMeasureCollectionCalculator { public: rttbClassMacro(MOHxVolumeToDoseMeasureCollectionCalculator, VolumeToDoseMeasureCollectionCalculator) private: DoseStatisticType _minimum; public: MOHxVolumeToDoseMeasureCollectionCalculator(const std::vector<double>& precomputeVolumeValues, const VolumeType volume, const std::vector<DoseTypeGy>& doseVector, const std::vector<double>& voxelProportionVector, const DoseVoxelVolumeType currentVoxelVolume, bool multiThreading = false); protected: DoseTypeGy computeSpecificValue(double xAbsolute) const override; }; } } #endif diff --git a/code/algorithms/rttbMaxOHxVolumeToDoseMeasureCollectionCalculator.cpp b/code/algorithms/rttbMaxOHxVolumeToDoseMeasureCollectionCalculator.cpp index edcc8c0..47e63ed 100644 --- a/code/algorithms/rttbMaxOHxVolumeToDoseMeasureCollectionCalculator.cpp +++ b/code/algorithms/rttbMaxOHxVolumeToDoseMeasureCollectionCalculator.cpp @@ -1,57 +1,51 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include "rttbMaxOHxVolumeToDoseMeasureCollectionCalculator.h" namespace rttb { namespace algorithms { MaxOHxVolumeToDoseMeasureCollectionCalculator::MaxOHxVolumeToDoseMeasureCollectionCalculator(const std::vector<double>& precomputeVolumeValues, const VolumeType volume, const std::vector<DoseTypeGy>& doseVector, const std::vector<double>& voxelProportionVector, const DoseVoxelVolumeType currentVoxelVolume, bool multiThreading) : VolumeToDoseMeasureCollectionCalculator(precomputeVolumeValues, volume, doseVector, voxelProportionVector, currentVoxelVolume, VolumeToDoseMeasureCollection::MaxOHx, multiThreading) {} DoseTypeGy MaxOHxVolumeToDoseMeasureCollectionCalculator::computeSpecificValue(double xAbsolute) const { double noOfVoxel = xAbsolute / _currentVoxelVolume; DoseTypeGy resultDose = 0; double countVoxels = 0; for (auto i = _doseVector.size() - 1; i!=static_cast<size_t>(-1); i--) { countVoxels += _voxelProportionVector.at(i); if (countVoxels >= noOfVoxel) { if (i > 0) { resultDose = _doseVector.at(i - 1); } break; } } return resultDose; } } } \ No newline at end of file diff --git a/code/algorithms/rttbMaxOHxVolumeToDoseMeasureCollectionCalculator.h b/code/algorithms/rttbMaxOHxVolumeToDoseMeasureCollectionCalculator.h index e4fcd7b..7767a07 100644 --- a/code/algorithms/rttbMaxOHxVolumeToDoseMeasureCollectionCalculator.h +++ b/code/algorithms/rttbMaxOHxVolumeToDoseMeasureCollectionCalculator.h @@ -1,50 +1,44 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #ifndef __MAXOHX_VOLUME_TO_DOSE_MEASURE_CALCULATOR_COLLECTION_H #define __MAXOHX_VOLUME_TO_DOSE_MEASURE_CALCULATOR_COLLECTION_H #include "rttbVolumeToDoseMeasureCollectionCalculator.h" namespace rttb { namespace algorithms { /*! @class MaxOHxVolumeToDoseMeasureCollectionCalculator @brief Class for calculating MaxOH VolumeToDose measures */ class RTTBAlgorithms_EXPORT MaxOHxVolumeToDoseMeasureCollectionCalculator : public VolumeToDoseMeasureCollectionCalculator { public: rttbClassMacro(MaxOHxVolumeToDoseMeasureCollectionCalculator, VolumeToDoseMeasureCollectionCalculator) MaxOHxVolumeToDoseMeasureCollectionCalculator(const std::vector<double>& precomputeVolumeValues, const VolumeType volume, const std::vector<DoseTypeGy>& doseVector, const std::vector<double>& voxelProportionVector, const DoseVoxelVolumeType currentVoxelVolume, bool multiThreading = false); protected: DoseTypeGy computeSpecificValue(double xAbsolute) const override; }; } } #endif diff --git a/code/algorithms/rttbMeasureCollection.cpp b/code/algorithms/rttbMeasureCollection.cpp index 7f441ec..39209e8 100644 --- a/code/algorithms/rttbMeasureCollection.cpp +++ b/code/algorithms/rttbMeasureCollection.cpp @@ -1,100 +1,94 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include "rttbMeasureCollection.h" #include "rttbDataNotAvailableException.h" namespace rttb { namespace algorithms { MeasureCollection::complexStatistics MeasureCollection::getName() const { return this->_name; } double MeasureCollection::getSpecificValue(const std::map<double, double>& values, double key, bool findNearestValueInstead, double& storedKey) const { if (values.find(key) != std::end(values)) { return values.find(key)->second; } else { //value not in map. We have to find the nearest value if (values.empty()) { throw core::DataNotAvailableException("No Vx values are defined"); } else { if (findNearestValueInstead) { auto iterator = findNearestKeyInMap(values, key); storedKey = iterator->first; return iterator->second; } else { throw core::DataNotAvailableException("No Vx value with required dose is defined"); } } } } std::map<double, double>::const_iterator MeasureCollection::findNearestKeyInMap( const std::map<double, double>& values, double key) const { double minDistance = 1e19; double minDistanceLast = 1e20; auto iterator = std::begin(values); while (iterator != std::end(values)) { minDistanceLast = minDistance; minDistance = fabs(iterator->first - key); if (minDistanceLast > minDistance) { ++iterator; } else { if (iterator != std::begin(values)) { --iterator; return iterator; } else { return std::begin(values); } } } --iterator; return iterator; } } } \ No newline at end of file diff --git a/code/algorithms/rttbMeasureCollection.h b/code/algorithms/rttbMeasureCollection.h index fd8de9e..2487e97 100644 --- a/code/algorithms/rttbMeasureCollection.h +++ b/code/algorithms/rttbMeasureCollection.h @@ -1,60 +1,54 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #ifndef __MEASURE_COLLECTION_H #define __MEASURE_COLLECTION_H #include <map> #include <rttbCommon.h> #include "rttbBaseType.h" #include "RTTBAlgorithmsExports.h" namespace rttb { namespace algorithms { /*! @class MeasureCollection @brief This class handels the access to the MeasureCollection elements and defines which names can be used for them */ class RTTBAlgorithms_EXPORT MeasureCollection { public: rttbClassMacroNoParent(MeasureCollection) enum complexStatistics { Dx, Vx, MOHx, MOCx, MaxOHx, MinOCx }; protected: complexStatistics _name; public: complexStatistics getName() const; protected: double getSpecificValue(const std::map<double, double>& values, double key, bool findNearestValueInstead, double& storedKey) const; std::map<double, double>::const_iterator findNearestKeyInMap(const std::map<double, double>& values, double key) const; }; } } #endif diff --git a/code/algorithms/rttbMinOCxVolumeToDoseMeasureCollectionCalculator.cpp b/code/algorithms/rttbMinOCxVolumeToDoseMeasureCollectionCalculator.cpp index cefd42b..0b743ce 100644 --- a/code/algorithms/rttbMinOCxVolumeToDoseMeasureCollectionCalculator.cpp +++ b/code/algorithms/rttbMinOCxVolumeToDoseMeasureCollectionCalculator.cpp @@ -1,75 +1,69 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include "rttbMinOCxVolumeToDoseMeasureCollectionCalculator.h" namespace rttb { namespace algorithms { MinOCxVolumeToDoseMeasureCollectionCalculator::MinOCxVolumeToDoseMeasureCollectionCalculator(const std::vector<double>& precomputeVolumeValues, const VolumeType volume, const std::vector<DoseTypeGy>& doseVector, const std::vector<double>& voxelProportionVector, const DoseVoxelVolumeType currentVoxelVolume, const DoseStatisticType minimum, const DoseStatisticType maximum, bool multiThreading) : VolumeToDoseMeasureCollectionCalculator(precomputeVolumeValues, volume, doseVector, voxelProportionVector, currentVoxelVolume, VolumeToDoseMeasureCollection::MinOCx, multiThreading), _minimum(minimum), _maximum(maximum) {} DoseTypeGy MinOCxVolumeToDoseMeasureCollectionCalculator::computeSpecificValue(double xAbsolute) const { double noOfVoxel = xAbsolute / _currentVoxelVolume; DoseTypeGy resultDose = 0; double countVoxels = 0; auto it = _doseVector.begin(); auto itD = _voxelProportionVector.begin(); for (; itD != _voxelProportionVector.end(); ++itD, ++it) { countVoxels += *itD; if (countVoxels >= noOfVoxel) { break; } } if (it != _doseVector.end()) { ++it; if (it != _doseVector.end()) { resultDose = *it; } else { resultDose = (DoseTypeGy)_maximum; } } else { resultDose = (DoseTypeGy)_minimum; } return resultDose; } } } \ No newline at end of file diff --git a/code/algorithms/rttbMinOCxVolumeToDoseMeasureCollectionCalculator.h b/code/algorithms/rttbMinOCxVolumeToDoseMeasureCollectionCalculator.h index a33b34e..756f618 100644 --- a/code/algorithms/rttbMinOCxVolumeToDoseMeasureCollectionCalculator.h +++ b/code/algorithms/rttbMinOCxVolumeToDoseMeasureCollectionCalculator.h @@ -1,55 +1,49 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #ifndef __MINOCX_VOLUME_TO_DOSE_MEASURE_COLLECTION_CALCULATOR_H #define __MINOCX_VOLUME_TO_DOSE_MEASURE_COLLECTION_CALCULATOR_H #include "rttbVolumeToDoseMeasureCollectionCalculator.h" namespace rttb { namespace algorithms { /*! @class MinOCxVolumeToDoseMeasureCollectionCalculator @brief Class for calculating MinOC VolumeToDose measures */ class RTTBAlgorithms_EXPORT MinOCxVolumeToDoseMeasureCollectionCalculator : public VolumeToDoseMeasureCollectionCalculator { public: rttbClassMacro(MinOCxVolumeToDoseMeasureCollectionCalculator, VolumeToDoseMeasureCollectionCalculator) private: DoseStatisticType _minimum; DoseStatisticType _maximum; public: MinOCxVolumeToDoseMeasureCollectionCalculator(const std::vector<double>& precomputeVolumeValues, const VolumeType volume, const std::vector<DoseTypeGy>& doseVector, const std::vector<double>& voxelProportionVector, const DoseVoxelVolumeType currentVoxelVolume, const DoseStatisticType minimum, const DoseStatisticType maximum, bool multiThreading = false); protected: DoseTypeGy computeSpecificValue(double xAbsolute) const override; }; } } #endif diff --git a/code/algorithms/rttbVolumeToDoseMeasureCollection.cpp b/code/algorithms/rttbVolumeToDoseMeasureCollection.cpp index 759cb1a..7847d64 100644 --- a/code/algorithms/rttbVolumeToDoseMeasureCollection.cpp +++ b/code/algorithms/rttbVolumeToDoseMeasureCollection.cpp @@ -1,98 +1,91 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ - #include "rttbVolumeToDoseMeasureCollection.h" #include "rttbInvalidParameterException.h" #include "rttbDataNotAvailableException.h" namespace rttb { namespace algorithms { VolumeToDoseMeasureCollection::VolumeToDoseMeasureCollection(complexStatistics name, VolumeType volume) : _name(name), _volume(volume), _values(std::map<VolumeType, DoseTypeGy>()) {} void VolumeToDoseMeasureCollection::setVolume(VolumeType volume) { this->_volume = volume; } void VolumeToDoseMeasureCollection::insertValue(VolumeType volume, DoseTypeGy dose) { this->_values.insert(std::pair<VolumeType, DoseTypeGy>(volume, dose)); } DoseTypeGy VolumeToDoseMeasureCollection::getValue(VolumeType xVolumeAbsolute) const { VolumeType dummy; return getSpecificValue(_values, xVolumeAbsolute, false, dummy); } DoseTypeGy VolumeToDoseMeasureCollection::getValue(VolumeType xVolumeAbsolute, bool findNearestValue, VolumeType & nearestXVolume) const { return getSpecificValue(_values, xVolumeAbsolute, findNearestValue, nearestXVolume); } DoseTypeGy VolumeToDoseMeasureCollection::getValueRelative(VolumeType xVolumeRelative) const { if (_volume == -1) { throw rttb::core::DataNotAvailableException("Volume is not set"); } if (xVolumeRelative >= 0 && xVolumeRelative <= 1) { DoseTypeGy xVolumeAbsolute = xVolumeRelative * _volume; VolumeType dummy; return getSpecificValue(_values, xVolumeAbsolute, false, dummy); } else { throw rttb::core::InvalidParameterException("Relative Volume must be >= 0 and <=1"); } } DoseTypeGy VolumeToDoseMeasureCollection::getValueRelative(VolumeType xVolumeRelative, bool findNearestValue, VolumeType & nearestXVolume) const { if (_volume == -1) { throw rttb::core::DataNotAvailableException("Volume is not set"); } if (xVolumeRelative >= 0 && xVolumeRelative <= 1) { DoseTypeGy xVolumeAbsolute = xVolumeRelative * _volume; return getSpecificValue(_values, xVolumeAbsolute, findNearestValue, nearestXVolume); } else { throw rttb::core::InvalidParameterException("Relative Volume must be >= 0 and <=1"); } } VolumeToDoseMeasureCollection::VolumeToDoseFunctionType VolumeToDoseMeasureCollection::getAllValues() const { return this->_values; } bool operator==(const VolumeToDoseMeasureCollection& volumeToDoseMesureCollection,const VolumeToDoseMeasureCollection& otherVolumeToDoseMesureCollection) { if (volumeToDoseMesureCollection.getName() == otherVolumeToDoseMesureCollection.getName() && volumeToDoseMesureCollection.getAllValues() == otherVolumeToDoseMesureCollection.getAllValues()) { return true; } return false; } } } diff --git a/code/algorithms/rttbVolumeToDoseMeasureCollection.h b/code/algorithms/rttbVolumeToDoseMeasureCollection.h index 0f0b39a..c9e4f71 100644 --- a/code/algorithms/rttbVolumeToDoseMeasureCollection.h +++ b/code/algorithms/rttbVolumeToDoseMeasureCollection.h @@ -1,82 +1,76 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #ifndef __VOLUME_TO_DOSE_MEASURE_COLLECTION_H #define __VOLUME_TO_DOSE_MEASURE_COLLECTION_H #include "rttbMeasureCollection.h" #include <rttbCommon.h> #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace algorithms { /*! @class VolumeToDoseMeasureCollection @brief This class handels the access to the VolumeToDoseMeasureCollection elements for a specific complex statistic @note _volume has to be set to use getValueRelative() otherwise an exception is thrown */ class RTTBAlgorithms_EXPORT VolumeToDoseMeasureCollection : public MeasureCollection { public: rttbClassMacro(VolumeToDoseMeasureCollection, MeasureCollection) typedef std::map<VolumeType, DoseTypeGy> VolumeToDoseFunctionType; private: complexStatistics _name; VolumeType _volume; VolumeToDoseFunctionType _values; public: VolumeToDoseMeasureCollection(complexStatistics name, VolumeType volume = -1); /*! @brief This has to be set >=0 to use getValueRelative() */ void setVolume(VolumeType volume); void insertValue(VolumeType volume, DoseTypeGy dose); /*! @brief Gets the x of the current volume, depending on the complexStatistics name. @return Return dose value in Gy. @exception InvalidDoseException if the vector values is empty @exception DataNotAvailableException if _volume is not set */ DoseTypeGy getValue(VolumeType xVolumeAbsolute) const; DoseTypeGy getValue(VolumeType xVolumeAbsolute, bool findNearestValue, VolumeType& nearestXDose) const; DoseTypeGy getValueRelative(VolumeType xDoseRelative) const; DoseTypeGy getValueRelative(VolumeType xDoseRelative, bool findNearestValue, VolumeType& nearestXDose) const; VolumeToDoseFunctionType getAllValues() const; friend bool operator==(const VolumeToDoseMeasureCollection& volumeToDoseMesureCollection, const VolumeToDoseMeasureCollection& otherVolumeToDoseMesureCollection); }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/algorithms/rttbVolumeToDoseMeasureCollectionCalculator.cpp b/code/algorithms/rttbVolumeToDoseMeasureCollectionCalculator.cpp index 3a84ac2..abc876b 100644 --- a/code/algorithms/rttbVolumeToDoseMeasureCollectionCalculator.cpp +++ b/code/algorithms/rttbVolumeToDoseMeasureCollectionCalculator.cpp @@ -1,90 +1,84 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include "rttbVolumeToDoseMeasureCollectionCalculator.h" #include <boost/thread/thread.hpp> #include "rttbInvalidParameterException.h" #include "rttbUtils.h" #include <boost/make_shared.hpp> //#include <boost/thread/locks.hpp> namespace rttb { namespace algorithms { VolumeToDoseMeasureCollectionCalculator::VolumeToDoseMeasureCollectionCalculator(const std::vector<double>& precomputeVolumeValues, const VolumeType volume, const std::vector<DoseTypeGy>& doseVector, const std::vector<double>& voxelProportionVector, const DoseVoxelVolumeType currentVoxelVolume, VolumeToDoseMeasureCollection::complexStatistics name, bool multiThreading) : _doseVector(doseVector), _currentVoxelVolume(currentVoxelVolume), _voxelProportionVector(voxelProportionVector), _volume(volume), _measureCollection(::boost::make_shared<VolumeToDoseMeasureCollection>(name)), _multiThreading(multiThreading) { addPrecomputeVolumeValues(precomputeVolumeValues); } void VolumeToDoseMeasureCollectionCalculator::compute() { std::vector<boost::thread> threads; for (double _precomputeVolumeValue : _precomputeVolumeValues) { double xAbsolute = _precomputeVolumeValue * _volume; if (!rttb::core::isKey(_measureCollection->getAllValues(), xAbsolute)) { if (_multiThreading) { throw rttb::core::InvalidParameterException("MultiThreading is not implemented yet."); //threads.push_back(boost::thread(&VolumeToDoseMeasureCollectionCalculator::insertIntoMeasureCollection, this, xAbsolute, computeSpecificValue(xAbsolute))); } else { insertIntoMeasureCollection(xAbsolute, this->computeSpecificValue(xAbsolute)); } } } for (auto & thread : threads) { thread.join(); } } void VolumeToDoseMeasureCollectionCalculator::addPrecomputeVolumeValues(const std::vector<double>& values) { for (double value : values) { if (value > 1 || value < 0) { throw rttb::core::InvalidParameterException("Values must be between 1 and 0!"); } if (!rttb::core::isKey(_precomputeVolumeValues, value)) { _precomputeVolumeValues.push_back(value); } } } VolumeToDoseMeasureCollection::Pointer VolumeToDoseMeasureCollectionCalculator::getMeasureCollection() { return _measureCollection; } void VolumeToDoseMeasureCollectionCalculator::insertIntoMeasureCollection(VolumeType xAbsolute, DoseTypeGy resultDose) { _measureCollection->insertValue(xAbsolute, resultDose); } } } diff --git a/code/algorithms/rttbVolumeToDoseMeasureCollectionCalculator.h b/code/algorithms/rttbVolumeToDoseMeasureCollectionCalculator.h index d9bf743..3838437 100644 --- a/code/algorithms/rttbVolumeToDoseMeasureCollectionCalculator.h +++ b/code/algorithms/rttbVolumeToDoseMeasureCollectionCalculator.h @@ -1,92 +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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #ifndef __VOLUME_TO_DOSE_MEASURE_COLLECTION_CALCULATOR_H #define __VOLUME_TO_DOSE_MEASURE_COLLECTION_CALCULATOR_H #include "rttbVolumeToDoseMeasureCollection.h" #include <rttbCommon.h> #include "rttbDoseStatistics.h" #ifdef _MSC_VER #pragma warning(push) #pragma warning(disable: 4251) #endif namespace rttb { namespace algorithms { /*! @class VolumeToDoseMeasureCollectionCalculator @brief Class for calculating VolumeToDose measures @details This class is used as a basis for VolumeToDoseMeasureCollectionCalculator. It implements the compute() method that is the same for every inheriting subclass, it accesses computeSpecificValue, which has to be implemented for each different complex statistic. */ class RTTBAlgorithms_EXPORT VolumeToDoseMeasureCollectionCalculator { public: rttbClassMacroNoParent(VolumeToDoseMeasureCollectionCalculator) typedef std::map<VolumeType, DoseTypeGy> VolumeToDoseFunctionType; protected: std::vector<DoseTypeGy> _doseVector; DoseVoxelVolumeType _currentVoxelVolume; std::vector<double> _voxelProportionVector; private: std::vector<double> _precomputeVolumeValues; VolumeType _volume; VolumeToDoseMeasureCollection::Pointer _measureCollection; bool _multiThreading; public: /*! @brief Computes not already computed values for the measureCollection. Algorithm for the specific complex Statistic has to be implemented in the corresponding subclass. */ void compute(); /*! @brief Adds additional values to the _precomputeVolumeValues vector. @exception InvalidParameterException If values vector contains values that are not between 0 and 1 */ void addPrecomputeVolumeValues(const std::vector<double>& values); VolumeToDoseMeasureCollection::Pointer getMeasureCollection(); protected: VolumeToDoseMeasureCollectionCalculator(const std::vector<double>& precomputeVolumeValues, const VolumeType volume, const std::vector<DoseTypeGy>& doseVector, const std::vector<double>& voxelProportionVector, const DoseVoxelVolumeType currentVoxelVolume, VolumeToDoseMeasureCollection::complexStatistics name, bool multiThreading); void insertIntoMeasureCollection(VolumeType xAbsolute, DoseTypeGy resultDose); /*! @brief Computes the specific DoseTypeGy depending on the complext statistic @note has to be overwritten */ virtual DoseTypeGy computeSpecificValue(double xAbsolute) const = 0; }; } } #ifdef _MSC_VER #pragma warning(pop) #endif #endif diff --git a/code/algorithms/rttbVxDoseToVolumeMeasureCollectionCalculator.cpp b/code/algorithms/rttbVxDoseToVolumeMeasureCollectionCalculator.cpp index 2325fe1..1fe63cd 100644 --- a/code/algorithms/rttbVxDoseToVolumeMeasureCollectionCalculator.cpp +++ b/code/algorithms/rttbVxDoseToVolumeMeasureCollectionCalculator.cpp @@ -1,55 +1,49 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include "rttbVxDoseToVolumeMeasureCollectionCalculator.h" namespace rttb { namespace algorithms { VxDoseToVolumeMeasureCollectionCalculator::VxDoseToVolumeMeasureCollectionCalculator(const std::vector<double>& precomputeDoseValues, const DoseTypeGy referenceDose, const core::DoseIteratorInterface::Pointer doseIterator, bool multiThreading) : DoseToVolumeMeasureCollectionCalculator(precomputeDoseValues, referenceDose, doseIterator, DoseToVolumeMeasureCollection::Vx, multiThreading) {} VolumeType VxDoseToVolumeMeasureCollectionCalculator::computeSpecificValue(double xAbsolute) const { rttb::FractionType count = 0; _doseIterator->reset(); DoseTypeGy currentDose = 0; while (_doseIterator->isPositionValid()) { currentDose = _doseIterator->getCurrentDoseValue(); if (currentDose >= xAbsolute) { count += _doseIterator->getCurrentRelevantVolumeFraction(); } _doseIterator->next(); } return count * this->_doseIterator->getCurrentVoxelVolume(); } } } \ No newline at end of file diff --git a/code/algorithms/rttbVxDoseToVolumeMeasureCollectionCalculator.h b/code/algorithms/rttbVxDoseToVolumeMeasureCollectionCalculator.h index 5a7ea85..6b7c97a 100644 --- a/code/algorithms/rttbVxDoseToVolumeMeasureCollectionCalculator.h +++ b/code/algorithms/rttbVxDoseToVolumeMeasureCollectionCalculator.h @@ -1,52 +1,46 @@ // ----------------------------------------------------------------------- // 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: 1674 $ (last changed revision) -// @date $Date: 2017-01-27 10:34:46 +0100 (Fr, 27 Jan 2017) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #ifndef __DV_DOSE_TO_VOLUME_MEASURE_CALCULATOR_H #define __DV_DOSE_TO_VOLUME_MEASURE_CALCULATOR_H #include "rttbDoseToVolumeMeasureCollectionCalculator.h" #include <rttbCommon.h> namespace rttb { namespace algorithms { /*! @class VxDoseToVolumeMeasureCollectionCalculator @brief Class for calculating Vx DoseToVolume measures */ class RTTBAlgorithms_EXPORT VxDoseToVolumeMeasureCollectionCalculator : public DoseToVolumeMeasureCollectionCalculator { public: rttbClassMacro(VxDoseToVolumeMeasureCollectionCalculator, DoseToVolumeMeasureCollectionCalculator) VxDoseToVolumeMeasureCollectionCalculator(const std::vector<double>& precomputeDoseValues, const DoseTypeGy referenceDose, const core::DoseIteratorInterface::Pointer doseIterator, bool multiThreading = false); protected: VolumeType computeSpecificValue(double xAbsolute) const override; }; } } #endif diff --git a/code/io/other/rttbDoseStatisticsXMLReader.cpp b/code/io/other/rttbDoseStatisticsXMLReader.cpp index 63d35ed..b4530f5 100644 --- a/code/io/other/rttbDoseStatisticsXMLReader.cpp +++ b/code/io/other/rttbDoseStatisticsXMLReader.cpp @@ -1,220 +1,214 @@ // ----------------------------------------------------------------------- // 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: 1328 $ (last changed revision) -// @date $Date: 2016-04-22 09:50:01 +0200 (Fr, 22 Apr 2016) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ #include <boost/foreach.hpp> #include <boost/lexical_cast.hpp> #include <boost/algorithm/string.hpp> #include <boost/property_tree/ptree.hpp> #include <boost/property_tree/xml_parser.hpp> #include <boost/make_shared.hpp> #include "rttbDoseStatisticsXMLReader.h" #include "rttbInvalidParameterException.h" #include "rttbVolumeToDoseMeasureCollection.h" namespace rttb { namespace io { namespace other { DoseStatisticsXMLReader::DoseStatisticsXMLReader(const std::string& filename) : _filename(filename), _newFile(true) { } DoseStatisticsXMLReader::~DoseStatisticsXMLReader() = default; void DoseStatisticsXMLReader::setFilename(const std::string& filename) { _filename = filename; _newFile = true; } algorithms::DoseStatistics::Pointer DoseStatisticsXMLReader::generateDoseStatistic() { if (_newFile) { this->createDoseStatistic(); } return _doseStatistic; } void DoseStatisticsXMLReader::createDoseStatistic() { boost::property_tree::ptree pt; // Load the XML file into the property tree. If reading fails // (cannot open file, parse error), an exception is thrown. try { read_xml(_filename, pt); } catch (boost::property_tree::xml_parser_error& /*e*/) { throw rttb::core::InvalidParameterException("DoseStatistics file name invalid: could not open the xml file!"); } // data to fill the parameter for the DoseStatistics std::string name; std::string datum; unsigned int x; std::pair<double, int> voxelid; std::vector < std::pair<double, int>> vec; //initialize all parameters for the DoseStatistics double minimum=-1; double maximum=-1; double numVoxels=-1; double volume=-1; double referenceDose = -1; double mean=-1; double stdDeviation=-1; boost::shared_ptr<std::vector<std::pair<double, int> > > minimumVoxelPositions = nullptr; boost::shared_ptr<std::vector<std::pair<double, int> > > maximumVoxelPositions = nullptr; rttb::algorithms::VolumeToDoseMeasureCollection Dx(rttb::algorithms::VolumeToDoseMeasureCollection::Dx); rttb::algorithms::DoseToVolumeMeasureCollection Vx(rttb::algorithms::DoseToVolumeMeasureCollection::Vx); rttb::algorithms::VolumeToDoseMeasureCollection MOHx(rttb::algorithms::VolumeToDoseMeasureCollection::MOHx); rttb::algorithms::VolumeToDoseMeasureCollection MOCx(rttb::algorithms::VolumeToDoseMeasureCollection::MOCx); rttb::algorithms::VolumeToDoseMeasureCollection MaxOHx(rttb::algorithms::VolumeToDoseMeasureCollection::MaxOHx); rttb::algorithms::VolumeToDoseMeasureCollection MinOCx(rttb::algorithms::VolumeToDoseMeasureCollection::MinOCx); BOOST_FOREACH(boost::property_tree::ptree::value_type & data, pt.get_child("statistics.results")) { datum = data.second.data(); BOOST_FOREACH(boost::property_tree::ptree::value_type & middle, data.second) { BOOST_FOREACH(boost::property_tree::ptree::value_type & innernode, middle.second) { std::string mia = innernode.first; if (innernode.first == "name") { name = innernode.second.data(); } else if (innernode.first == "voxelGridID") { boost::replace_all(datum, "\r\n", ""); boost::replace_all(datum, "\n", ""); boost::trim(datum); voxelid.first = boost::lexical_cast<double>(datum); voxelid.second = boost::lexical_cast<unsigned int>(innernode.second.data()); vec.push_back(voxelid); } else if (innernode.first == "x") { x = boost::lexical_cast<unsigned int>(innernode.second.data()); } } } // fill with the extracted data if (name == "numberOfVoxels") { numVoxels = boost::lexical_cast<double>(datum); } else if (name == "volume") { volume = boost::lexical_cast<double>(datum); Dx.setVolume(volume); MOHx.setVolume(volume); MOCx.setVolume(volume); MaxOHx.setVolume(volume); } else if (name == "referenceDose") { referenceDose = boost::lexical_cast<double>(datum); Vx.setReferenceDose(referenceDose); } else if (name == "mean") { mean = boost::lexical_cast<double>(datum); } else if (name == "standardDeviation") { stdDeviation = boost::lexical_cast<double>(datum); } else if (name == "minimum") { minimum = boost::lexical_cast<double>(datum); if (!vec.empty()) { minimumVoxelPositions = boost::make_shared<std::vector<std::pair<double, int>>>(vec); vec.clear(); } } else if (name == "maximum") { maximum = boost::lexical_cast<double>(datum); if (!vec.empty()) { maximumVoxelPositions = boost::make_shared<std::vector<std::pair<double, int>>>(vec); vec.clear(); } } else if (name == "Dx") { Dx.insertValue(static_cast<double>(x)*volume / 100, boost::lexical_cast<double>(datum)); } else if (name == "Vx") { Vx.insertValue(static_cast<double>(x)*referenceDose / 100, boost::lexical_cast<double>(datum)); } else if (name == "MOHx") { MOHx.insertValue(static_cast<double>(x)*volume / 100, boost::lexical_cast<double>(datum)); } else if (name == "MOCx") { MOCx.insertValue(static_cast<double>(x)*volume / 100, boost::lexical_cast<double>(datum)); } else if (name == "MaxOHx") { MaxOHx.insertValue(static_cast<double>(x)*volume / 100, boost::lexical_cast<double>(datum)); } else if (name == "MinOCx") { MinOCx.insertValue(static_cast<double>(x)*volume / 100, boost::lexical_cast<double>(datum)); } } // make DoseStatistcs _doseStatistic = boost::make_shared<rttb::algorithms::DoseStatistics>( minimum, maximum, mean, stdDeviation, numVoxels, volume, minimumVoxelPositions, maximumVoxelPositions , Dx, Vx, MOHx, MOCx, MaxOHx, MinOCx, referenceDose); } }//end namespace other }//end namespace io }//end namespace rttb diff --git a/code/io/other/rttbDoseStatisticsXMLReader.h b/code/io/other/rttbDoseStatisticsXMLReader.h index d214111..79aff6f 100644 --- a/code/io/other/rttbDoseStatisticsXMLReader.h +++ b/code/io/other/rttbDoseStatisticsXMLReader.h @@ -1,63 +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: 1250 $ (last changed revision) -// @date $Date: 2016-02-18 15:25:55 +0100 (Do, 18 Feb 2016) $ (last change date) -// @author $Author: zhangl $ (last changed by) -*/ + #ifndef __DOSE_STATISTICS_XML_READER_H #define __DOSE_STATISTICS_XML_READER_H #include "rttbDoseStatistics.h" namespace rttb { namespace io { namespace other { /*! @class DoseStatisticsXMLReader @brief Reads a dose statistics XML into a DoseStatistics object */ class DoseStatisticsXMLReader{ public: DoseStatisticsXMLReader(const std::string& filename); ~DoseStatisticsXMLReader(); void setFilename(const std::string& filename); /*! @brief Generate a Model, createModel() will be called @return Return new shared pointer of a Model. @exception InvalidParameterException Thrown if _filename invalid */ algorithms::DoseStatistics::Pointer generateDoseStatistic(); private: std::string _filename; bool _newFile; algorithms::DoseStatistics::Pointer _doseStatistic; /*! @brief Create new Model object using the info from model xml file @exception InvalidParameterException Thrown if _filename invalid */ void createDoseStatistic(); }; } } } #endif diff --git a/testing/algorithms/ArithmeticTest.cpp b/testing/algorithms/ArithmeticTest.cpp index 763f6d2..bad153d 100644 --- a/testing/algorithms/ArithmeticTest.cpp +++ b/testing/algorithms/ArithmeticTest.cpp @@ -1,358 +1,352 @@ // ----------------------------------------------------------------------- // 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 <boost/make_shared.hpp> #include <boost/shared_ptr.hpp> #include "litCheckMacros.h" #include "rttbBaseType.h" #include "../core/DummyDoseAccessor.h" #include "../core/DummyMaskAccessor.h" #include "../core/DummyMutableDoseAccessor.h" #include "rttbDoseAccessorInterface.h" #include "rttbMutableDoseAccessorInterface.h" #include "rttbMutableMaskAccessorInterface.h" #include "rttbArithmetic.h" #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" #include "rttbGenericMutableMaskAccessor.h" #include "rttbMaskAccessorInterface.h" namespace rttb { namespace testing { typedef core::DoseAccessorInterface::Pointer DoseAccessorPointer; typedef core::MutableDoseAccessorInterface::Pointer MutableDoseAccessorPointer; typedef DummyMaskAccessor::MaskVoxelListPointer MaskVoxelListPointer; typedef DummyMaskAccessor::MaskVoxelList MaskVoxelList; typedef core::MaskAccessorInterface::Pointer MaskAccessorPointer; typedef core::MutableMaskAccessorInterface::Pointer MutableMaskAccessorPointer; /*! @brief ArithmeticTest - tests arithmetic combinations of accessors 1) test dose-dose operations 2) test dose-mask operations 3) test mask-mask operations 4) test convenience functions */ int ArithmeticTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; // initialize accessors for arithmetic //DOSE: //Null pointers DoseAccessorPointer spDoseNull; MutableDoseAccessorPointer spMutableDoseNull; //dose with random values between 0 and 100 boost::shared_ptr<DummyDoseAccessor> spTestDoseAccessor1 = boost::make_shared<DummyDoseAccessor>(); DoseAccessorPointer spDoseAccessor1(spTestDoseAccessor1); //generate a 2nd dose with fixed values core::GeometricInfo geoInfo = spDoseAccessor1->getGeometricInfo(); DoseTypeGy valFix = 101; // to ensure values are larger than 100 on adding std::vector<DoseTypeGy> dose2Vals(geoInfo.getNumberOfVoxels(), valFix); boost::shared_ptr<DummyDoseAccessor> spTestDoseAccessor2 = boost::make_shared<DummyDoseAccessor> (dose2Vals, geoInfo); DoseAccessorPointer spDoseAccessor2(spTestDoseAccessor2); //generate result acessor std::vector<DoseTypeGy> doseResultVals(geoInfo.getNumberOfVoxels(), -1); boost::shared_ptr<DummyMutableDoseAccessor> spTestMutableDoseAccessor = boost::make_shared<DummyMutableDoseAccessor>(doseResultVals, geoInfo); MutableDoseAccessorPointer spMutableDoseAccessor(spTestMutableDoseAccessor); // different geometricInfo core::GeometricInfo geoInfo2 = geoInfo; geoInfo2.setNumColumns(5); geoInfo2.setNumRows(5); geoInfo2.setNumSlices(5); std::vector<DoseTypeGy> dose3Vals(geoInfo2.getNumberOfVoxels(), valFix); boost::shared_ptr<DummyDoseAccessor> spTestDoseAccessor3 = boost::make_shared<DummyDoseAccessor> (dose3Vals, geoInfo2); DoseAccessorPointer spDoseAccessorDiffGeoInfo(spTestDoseAccessor3); boost::shared_ptr<DummyMutableDoseAccessor> spTestMutableDoseAccessor2 = boost::make_shared<DummyMutableDoseAccessor>(dose3Vals, geoInfo2); MutableDoseAccessorPointer spMutableDoseAccessorDiffGeoInfo(spTestMutableDoseAccessor2); //MASK: //null pointer MaskAccessorPointer spMaskAccessorNull; MutableMaskAccessorPointer spMutableMaskAccessorNull; MaskVoxelList voxelList; FractionType aVolumeFraction = 1; VoxelGridID aVoxelGridID = 10; //generate a dummy mask while (aVoxelGridID < geoInfo.getNumberOfVoxels() && aVoxelGridID <= 30) { voxelList.push_back(core::MaskVoxel(aVoxelGridID, aVolumeFraction)); ++aVoxelGridID; } MaskVoxelListPointer voxelListPtr = boost::make_shared<MaskVoxelList>(voxelList); boost::shared_ptr<DummyMaskAccessor> dummyMask1 = boost::make_shared<DummyMaskAccessor>(geoInfo, voxelListPtr); MaskAccessorPointer spMaskAccessor1(dummyMask1); MaskVoxelList voxelList2; aVoxelGridID = 20; //generate a 2nd dummy mask that partly overlaps with the 1st one while (aVoxelGridID < geoInfo.getNumberOfVoxels() && aVoxelGridID <= 40) { voxelList2.push_back(core::MaskVoxel(aVoxelGridID, aVolumeFraction)); ++aVoxelGridID; } MaskVoxelListPointer voxelListPtr2 = boost::make_shared<MaskVoxelList>(voxelList2); boost::shared_ptr<DummyMaskAccessor> dummyMask2 = boost::make_shared<DummyMaskAccessor>(geoInfo, voxelListPtr2); MaskAccessorPointer spMaskAccessor2(dummyMask2); // result accessor boost::shared_ptr<masks::GenericMutableMaskAccessor> mMask1 = boost::make_shared<masks::GenericMutableMaskAccessor>(geoInfo); MutableMaskAccessorPointer spMutableMask(mMask1); // different geometricInfo boost::shared_ptr<DummyMaskAccessor> spDummyMaskDiffGeoInfo = boost::make_shared<DummyMaskAccessor> (geoInfo2, voxelListPtr2); MaskAccessorPointer spMaskAccessorDiffGeoInfo(spDummyMaskDiffGeoInfo); boost::shared_ptr<masks::GenericMutableMaskAccessor> mMask2 = boost::make_shared<masks::GenericMutableMaskAccessor>(geoInfo2); MutableMaskAccessorPointer spMutableMaskDiffGeoInfo(mMask2); // 1) test dose-dose operations //ADD algorithms::arithmetic::doseOp::Add addOP; CHECK_NO_THROW(algorithms::arithmetic::arithmetic(spDoseAccessor1, spDoseAccessor2, spMutableDoseAccessor, addOP)); VoxelGridID id = 5; CHECK(spMutableDoseAccessor->getValueAt(id) > 100); CHECK_EQUAL(spDoseAccessor1->getValueAt(id) + valFix, spMutableDoseAccessor->getValueAt(id)); id = 10; CHECK(spMutableDoseAccessor->getValueAt(id) > 100); CHECK_EQUAL(spDoseAccessor1->getValueAt(id) + valFix, spMutableDoseAccessor->getValueAt(id)); //handling exceptions is tested once for dose-dose operations, because this does not change if the operation changes. //handling null pointers CHECK_THROW_EXPLICIT(algorithms::arithmetic::arithmetic(spDoseAccessor1, spDoseNull, spMutableDoseAccessor, addOP), core::NullPointerException); CHECK_THROW_EXPLICIT(algorithms::arithmetic::arithmetic(spDoseNull, spDoseAccessor2, spMutableDoseAccessor, addOP), core::NullPointerException); CHECK_THROW_EXPLICIT(algorithms::arithmetic::arithmetic(spDoseAccessor1, spDoseAccessor2, spMutableDoseNull, addOP), core::NullPointerException); //handle different geometricInfos CHECK_THROW_EXPLICIT(algorithms::arithmetic::arithmetic(spDoseAccessor1, spDoseAccessorDiffGeoInfo, spMutableDoseAccessor, addOP), core::InvalidParameterException); CHECK_THROW_EXPLICIT(algorithms::arithmetic::arithmetic(spDoseAccessorDiffGeoInfo, spDoseAccessor2, spMutableDoseAccessor, addOP), core::InvalidParameterException); CHECK_THROW_EXPLICIT(algorithms::arithmetic::arithmetic(spDoseAccessor1, spDoseAccessor2, spMutableDoseAccessorDiffGeoInfo, addOP), core::InvalidParameterException); //ADD_WEIGHTED algorithms::arithmetic::doseOp::AddWeighted addWOP(1, 2); CHECK_NO_THROW(algorithms::arithmetic::arithmetic(spDoseAccessor1, spDoseAccessor2, spMutableDoseAccessor, addWOP)); id = 5; CHECK(spMutableDoseAccessor->getValueAt(id) > 201); CHECK_EQUAL(spDoseAccessor1->getValueAt(id) + 2 * valFix, spMutableDoseAccessor->getValueAt(id)); id = 10; CHECK(spMutableDoseAccessor->getValueAt(id) > 201); CHECK_EQUAL(spDoseAccessor1->getValueAt(id) + 2 * valFix, spMutableDoseAccessor->getValueAt(id)); //MULTIPLY algorithms::arithmetic::doseOp::Multiply multiplyOP; CHECK_NO_THROW(algorithms::arithmetic::arithmetic(spDoseAccessor1, spDoseAccessor2, spMutableDoseAccessor, multiplyOP)); id = 5; CHECK(spMutableDoseAccessor->getValueAt(id) > 201); CHECK_EQUAL(spDoseAccessor1->getValueAt(id) * valFix, spMutableDoseAccessor->getValueAt(id)); id = 10; CHECK(spMutableDoseAccessor->getValueAt(id) > 201); CHECK_EQUAL(spDoseAccessor1->getValueAt(id) * valFix, spMutableDoseAccessor->getValueAt(id)); // 2) test dose-mask operations //MULTIPLY algorithms::arithmetic::doseMaskOp::Multiply multOP; CHECK_NO_THROW(algorithms::arithmetic::arithmetic(spDoseAccessor2, spMaskAccessor1, spMutableDoseAccessor, multOP)); core::MaskVoxel mVoxel(0); id = 5; CHECK_EQUAL(0, spMutableDoseAccessor->getValueAt(id)); spMaskAccessor1->getMaskAt(id, mVoxel); CHECK_EQUAL(spMutableDoseAccessor->getValueAt(id), mVoxel.getRelevantVolumeFraction()); id = 15; CHECK_EQUAL(valFix, spMutableDoseAccessor->getValueAt(id)); id = 35; CHECK_EQUAL(0, spMutableDoseAccessor->getValueAt(id)); //handling exceptions is tested once for dose-dose operations, because this does not change if the operation changes. //handling null pointers CHECK_THROW_EXPLICIT(algorithms::arithmetic::arithmetic(spDoseAccessor1, spMaskAccessorNull, spMutableDoseAccessor, multOP), core::NullPointerException); CHECK_THROW_EXPLICIT(algorithms::arithmetic::arithmetic(spDoseNull, spDoseAccessor2, spMutableDoseAccessor, multOP), core::NullPointerException); CHECK_THROW_EXPLICIT(algorithms::arithmetic::arithmetic(spDoseAccessor2, spMaskAccessor1, spMutableDoseNull, multOP), core::NullPointerException); //handle different geometricInfos CHECK_THROW_EXPLICIT(algorithms::arithmetic::arithmetic(spDoseAccessor2, spMaskAccessorDiffGeoInfo, spMutableDoseAccessor, multOP), core::InvalidParameterException); CHECK_THROW_EXPLICIT(algorithms::arithmetic::arithmetic(spDoseAccessorDiffGeoInfo, spMaskAccessor1, spMutableDoseAccessor, multOP), core::InvalidParameterException); CHECK_THROW_EXPLICIT(algorithms::arithmetic::arithmetic(spDoseAccessor2, spMaskAccessor1, spMutableDoseAccessorDiffGeoInfo, multOP), core::InvalidParameterException); // 3) test mask-mask operations //ADD algorithms::arithmetic::maskOp::Add maskAddOP; CHECK_NO_THROW(algorithms::arithmetic::arithmetic(spMaskAccessor1, spMaskAccessor2, spMutableMask, maskAddOP)); id = 5; spMutableMask->getMaskAt(id, mVoxel); CHECK_EQUAL(0, mVoxel.getRelevantVolumeFraction()); id = 15; spMutableMask->getMaskAt(id, mVoxel); CHECK_EQUAL(1, mVoxel.getRelevantVolumeFraction()); id = 35; spMutableMask->getMaskAt(id, mVoxel); CHECK_EQUAL(1, mVoxel.getRelevantVolumeFraction()); id = 45; spMutableMask->getMaskAt(id, mVoxel); CHECK_EQUAL(0, mVoxel.getRelevantVolumeFraction()); //handling exceptions is tested once for dose-dose operations, because this does not change if the operation changes. //handling null pointers CHECK_THROW_EXPLICIT(algorithms::arithmetic::arithmetic(spMaskAccessor1, spMaskAccessorNull, spMutableMask, maskAddOP), core::NullPointerException); CHECK_THROW_EXPLICIT(algorithms::arithmetic::arithmetic(spMaskAccessorNull, spMaskAccessor2, spMutableMask, maskAddOP), core::NullPointerException); CHECK_THROW_EXPLICIT(algorithms::arithmetic::arithmetic(spMaskAccessor1, spMaskAccessor1, spMutableMaskAccessorNull, maskAddOP), core::NullPointerException); //handle different geometricInfos CHECK_THROW_EXPLICIT(algorithms::arithmetic::arithmetic(spMaskAccessor1, spMaskAccessorDiffGeoInfo, spMutableMask, maskAddOP), core::InvalidParameterException); CHECK_THROW_EXPLICIT(algorithms::arithmetic::arithmetic(spMaskAccessorDiffGeoInfo, spMaskAccessor2, spMutableMask, maskAddOP), core::InvalidParameterException); CHECK_THROW_EXPLICIT(algorithms::arithmetic::arithmetic(spMaskAccessor1, spMaskAccessor1, spMutableMaskDiffGeoInfo, maskAddOP), core::InvalidParameterException); //SUBTRACT algorithms::arithmetic::maskOp::Subtract maskSubOP; CHECK_NO_THROW(algorithms::arithmetic::arithmetic(spMaskAccessor1, spMaskAccessor2, spMutableMask, maskSubOP)); id = 5; spMutableMask->getMaskAt(id, mVoxel); CHECK_EQUAL(0, mVoxel.getRelevantVolumeFraction()); id = 15; spMutableMask->getMaskAt(id, mVoxel); CHECK_EQUAL(1, mVoxel.getRelevantVolumeFraction()); id = 35; spMutableMask->getMaskAt(id, mVoxel); CHECK_EQUAL(0, mVoxel.getRelevantVolumeFraction()); id = 45; spMutableMask->getMaskAt(id, mVoxel); CHECK_EQUAL(0, mVoxel.getRelevantVolumeFraction()); // 4) test convenience functions // tests are similar to explicit calls CHECK_NO_THROW(algorithms::arithmetic::add(spDoseAccessor1, spDoseAccessor2, spMutableDoseAccessor)); id = 5; CHECK(spMutableDoseAccessor->getValueAt(id) > 100); CHECK_EQUAL(spDoseAccessor1->getValueAt(id) + valFix, spMutableDoseAccessor->getValueAt(id)); id = 10; CHECK(spMutableDoseAccessor->getValueAt(id) > 100); CHECK_EQUAL(spDoseAccessor1->getValueAt(id) + valFix, spMutableDoseAccessor->getValueAt(id)); CHECK_NO_THROW(algorithms::arithmetic::add(spMaskAccessor1, spMaskAccessor2, spMutableMask)); id = 5; spMutableMask->getMaskAt(id, mVoxel); CHECK_EQUAL(0, mVoxel.getRelevantVolumeFraction()); id = 15; spMutableMask->getMaskAt(id, mVoxel); CHECK_EQUAL(1, mVoxel.getRelevantVolumeFraction()); id = 35; spMutableMask->getMaskAt(id, mVoxel); CHECK_EQUAL(1, mVoxel.getRelevantVolumeFraction()); id = 45; spMutableMask->getMaskAt(id, mVoxel); CHECK_EQUAL(0, mVoxel.getRelevantVolumeFraction()); CHECK_NO_THROW(algorithms::arithmetic::subtract(spMaskAccessor1, spMaskAccessor2, spMutableMask)); id = 5; spMutableMask->getMaskAt(id, mVoxel); CHECK_EQUAL(0, mVoxel.getRelevantVolumeFraction()); id = 15; spMutableMask->getMaskAt(id, mVoxel); CHECK_EQUAL(1, mVoxel.getRelevantVolumeFraction()); id = 35; spMutableMask->getMaskAt(id, mVoxel); CHECK_EQUAL(0, mVoxel.getRelevantVolumeFraction()); id = 45; spMutableMask->getMaskAt(id, mVoxel); CHECK_EQUAL(0, mVoxel.getRelevantVolumeFraction()); CHECK_NO_THROW(algorithms::arithmetic::multiply(spDoseAccessor2, spMaskAccessor1, spMutableDoseAccessor)); id = 5; CHECK_EQUAL(0, spMutableDoseAccessor->getValueAt(id)); spMaskAccessor1->getMaskAt(id, mVoxel); CHECK_EQUAL(spMutableDoseAccessor->getValueAt(id), mVoxel.getRelevantVolumeFraction()); id = 15; CHECK_EQUAL(valFix, spMutableDoseAccessor->getValueAt(id)); id = 35; CHECK_EQUAL(0, spMutableDoseAccessor->getValueAt(id)); RETURN_AND_REPORT_TEST_SUCCESS; } } } \ No newline at end of file diff --git a/testing/algorithms/BinaryFunctorAccessorTest.cpp b/testing/algorithms/BinaryFunctorAccessorTest.cpp index 8aea246..301933f 100644 --- a/testing/algorithms/BinaryFunctorAccessorTest.cpp +++ b/testing/algorithms/BinaryFunctorAccessorTest.cpp @@ -1,131 +1,125 @@ // ----------------------------------------------------------------------- // 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 <boost/make_shared.hpp> #include <boost/shared_ptr.hpp> #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbDoseAccessorInterface.h" #include "rttbDicomDoseAccessor.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbArithmetic.h" #include "rttbNullPointerException.h" #include "rttbInvalidParameterException.h" #include "rttbBinaryFunctorAccessor.h" namespace rttb { namespace testing { typedef core::DoseAccessorInterface::Pointer DoseAccessorPointer; typedef algorithms::BinaryFunctorAccessor<algorithms::arithmetic::doseOp::Add> BinaryFunctorAccessorAddType; typedef algorithms::BinaryFunctorAccessor<algorithms::arithmetic::doseOp::AddWeighted> BinaryFunctorAccessorAddWeightedType; /*! @brief BinaryFunctorAccessorTest - tests functors of two accessors 1) test constructor 2) test getDoseAt */ int BinaryFunctorAccessorTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string RTDOSE_FILENAME; std::string RTDOSE2_FILENAME; if (argc > 1) { RTDOSE_FILENAME = argv[1]; } if (argc > 2) { RTDOSE2_FILENAME = argv[2]; } DoseAccessorPointer spDoseAccessorNull; DoseAccessorPointer spDoseAccessor = io::dicom::DicomFileDoseAccessorGenerator( RTDOSE_FILENAME.c_str()).generateDoseAccessor(); DoseAccessorPointer spDoseAccessor2 = io::dicom::DicomFileDoseAccessorGenerator( RTDOSE2_FILENAME.c_str()).generateDoseAccessor(); algorithms::arithmetic::doseOp::Add addOP; algorithms::arithmetic::doseOp::AddWeighted addWeightedOP(1.0, 10.0); algorithms::arithmetic::doseOp::AddWeighted addWeightedTwoOP(2.0, 2.0); //1) Check constructor CHECK_THROW_EXPLICIT(BinaryFunctorAccessorAddType(spDoseAccessorNull, spDoseAccessor, addOP), core::NullPointerException); CHECK_THROW_EXPLICIT(BinaryFunctorAccessorAddType(spDoseAccessor, spDoseAccessorNull, addOP), core::NullPointerException); CHECK_THROW_EXPLICIT(BinaryFunctorAccessorAddType(spDoseAccessorNull, spDoseAccessorNull, addOP), core::NullPointerException); CHECK_THROW_EXPLICIT(BinaryFunctorAccessorAddType(spDoseAccessor, spDoseAccessor2, addOP), core::InvalidParameterException); CHECK_NO_THROW(BinaryFunctorAccessorAddType(spDoseAccessor, spDoseAccessor, addOP)); CHECK_NO_THROW(BinaryFunctorAccessorAddWeightedType(spDoseAccessor, spDoseAccessor, addWeightedOP)); auto spBinaryFunctorDoseAccessorAdd = boost::make_shared<BinaryFunctorAccessorAddType>(spDoseAccessor, spDoseAccessor, addOP); auto spBinaryFunctorDoseAccessorAddWeighted = boost::make_shared<BinaryFunctorAccessorAddWeightedType>(spDoseAccessor, spDoseAccessor, addWeightedOP); auto spBinaryFunctorDoseAccessorAddWeightedTwo = boost::make_shared<BinaryFunctorAccessorAddWeightedType>(spDoseAccessor, spDoseAccessor, addWeightedTwoOP); //2) Test getDoseAt() int lastIndex = spBinaryFunctorDoseAccessorAdd->getGeometricInfo().getNumberOfVoxels() - 1; VoxelGridID aId[3] = { 5, 6067, lastIndex }; VoxelGridIndex3D aIndex[3] = {VoxelGridIndex3D(5, 0, 0), VoxelGridIndex3D(37, 0, 2), VoxelGridIndex3D(spBinaryFunctorDoseAccessorAdd->getGeometricInfo().getNumColumns() - 1, spBinaryFunctorDoseAccessorAdd->getGeometricInfo().getNumRows() - 1, spBinaryFunctorDoseAccessorAdd->getGeometricInfo().getNumSlices() - 1)}; for (int i = 0; i < 3; ++i) { CHECK_EQUAL(spBinaryFunctorDoseAccessorAdd->getValueAt(aId[i]), 4.0); CHECK_EQUAL(spBinaryFunctorDoseAccessorAddWeighted->getValueAt(aId[i]), 22.0); CHECK_EQUAL(spBinaryFunctorDoseAccessorAdd->getValueAt(aIndex[i]), spBinaryFunctorDoseAccessorAdd->getValueAt(aId[i])); CHECK_EQUAL(spBinaryFunctorDoseAccessorAddWeighted->getValueAt(aIndex[i]), spBinaryFunctorDoseAccessorAddWeighted->getValueAt(aId[i])); CHECK_EQUAL(spBinaryFunctorDoseAccessorAdd->getValueAt(aId[i]) * 2.0, spBinaryFunctorDoseAccessorAddWeightedTwo->getValueAt(aId[i])); } VoxelGridID aIdInvalid(spBinaryFunctorDoseAccessorAdd->getGeometricInfo().getNumberOfVoxels()); VoxelGridIndex3D aIndexInvalid(spBinaryFunctorDoseAccessorAdd->getGeometricInfo().getNumColumns(), spBinaryFunctorDoseAccessorAdd->getGeometricInfo().getNumRows(), spBinaryFunctorDoseAccessorAdd->getGeometricInfo().getNumSlices()); CHECK_EQUAL(spBinaryFunctorDoseAccessorAdd->getValueAt(aIdInvalid), -1.0); CHECK_EQUAL(spBinaryFunctorDoseAccessorAdd->getValueAt(aIndexInvalid), -1.0); CHECK_EQUAL(spBinaryFunctorDoseAccessorAddWeighted->getValueAt(aIdInvalid), -1.0); CHECK_EQUAL(spBinaryFunctorDoseAccessorAddWeighted->getValueAt(aIndexInvalid), -1.0); RETURN_AND_REPORT_TEST_SUCCESS; } } } \ No newline at end of file diff --git a/testing/algorithms/DoseStatisticsCalculatorTest.cpp b/testing/algorithms/DoseStatisticsCalculatorTest.cpp index cfb6c49..682a124 100644 --- a/testing/algorithms/DoseStatisticsCalculatorTest.cpp +++ b/testing/algorithms/DoseStatisticsCalculatorTest.cpp @@ -1,391 +1,385 @@ // ----------------------------------------------------------------------- // 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 <boost/make_shared.hpp> #include <boost/shared_ptr.hpp> #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbGenericDoseIterator.h" #include "rttbDoseIteratorInterface.h" #include "rttbNullPointerException.h" #include "rttbDoseStatisticsCalculator.h" #include "rttbInvalidDoseException.h" #include "rttbInvalidParameterException.h" #include "rttbDataNotAvailableException.h" #include "rttbDicomFileDoseAccessorGenerator.h" #include "rttbDicomFileStructureSetGenerator.h" #include "rttbBoostMaskAccessor.h" #include "rttbGenericMaskedDoseIterator.h" #include "../io/other/CompareDoseStatistic.h" #include "../../code/io/other/rttbDoseStatisticsXMLReader.h" #include "../core/DummyDoseAccessor.h" namespace rttb { namespace testing { typedef core::GenericDoseIterator::DoseAccessorPointer DoseAccessorPointer; typedef core::DoseIteratorInterface::Pointer DoseIteratorPointer; typedef rttb::algorithms::DoseStatistics::ResultListPointer ResultListPointer; typedef rttb::algorithms::DoseStatistics::Pointer DoseStatisticsPointer; /*! @brief DoseStatisticsCalculatorTest - test the API of DoseStatisticsCalculator 1) test constructors 2) test setDoseIterator 3) test calculateDoseSatistics 4) get statistical values */ int DoseStatisticsCalculatorTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; std::string referenceXMLFilename; std::string doseFilename, structFilename; boost::shared_ptr<DummyDoseAccessor> spTestDoseAccessor = boost::make_shared<DummyDoseAccessor>(); DoseAccessorPointer spDoseAccessor(spTestDoseAccessor); const std::vector<DoseTypeGy>* doseVals = spTestDoseAccessor->getDoseVector(); boost::shared_ptr<core::GenericDoseIterator> spTestDoseIterator = boost::make_shared<core::GenericDoseIterator>(spDoseAccessor); DoseIteratorPointer spDoseIterator(spTestDoseIterator); DoseIteratorPointer spDoseIteratorNull; if (argc > 3) { referenceXMLFilename = argv[1]; doseFilename = argv[2]; structFilename = argv[3]; } //1) test constructors // the values cannot be accessed from outside, therefore correct default values are not tested CHECK_THROW_EXPLICIT(rttb::algorithms::DoseStatisticsCalculator myDoseStatsCalculator( spDoseIteratorNull), core::NullPointerException); CHECK_NO_THROW(rttb::algorithms::DoseStatisticsCalculator myDoseStatsCalculator(spDoseIterator)); rttb::algorithms::DoseStatisticsCalculator myDoseStatsCalculator(spDoseIterator); //2) test setDoseIterator //3) test calculateDoseStatistics DoseStatisticsPointer theStatistics; //simple dose statistics CHECK_NO_THROW(theStatistics = myDoseStatsCalculator.calculateDoseStatistics()); CHECK_EQUAL(theStatistics->getMinimumVoxelPositions()->empty(), false); CHECK_EQUAL(theStatistics->getMaximumVoxelPositions()->empty(), false); CHECK_EQUAL(theStatistics->getVx().getAllValues().empty(), true); CHECK_EQUAL(theStatistics->getDx().getAllValues().empty(), true); CHECK_EQUAL(theStatistics->getVx().getAllValues().empty(), true); CHECK_EQUAL(theStatistics->getMaxOHx().getAllValues().empty(), true); CHECK_EQUAL(theStatistics->getMOHx().getAllValues().empty(), true); CHECK_EQUAL(theStatistics->getMOCx().getAllValues().empty(), true); CHECK_EQUAL(theStatistics->getMinOCx().getAllValues().empty(), true); //check default values for computeComplexMeasures=true DoseStatisticsPointer theStatisticsDefault; myDoseStatsCalculator.setMultiThreading(true); CHECK_NO_THROW(theStatisticsDefault = myDoseStatsCalculator.calculateDoseStatistics(true)); CHECK_NO_THROW(theStatisticsDefault->getVx().getValue(0.02 * theStatisticsDefault->getMaximum())); CHECK_NO_THROW(theStatisticsDefault->getVx().getValue(0.05 * theStatisticsDefault->getMaximum())); CHECK_NO_THROW(theStatisticsDefault->getVx().getValue(0.1 * theStatisticsDefault->getMaximum())); CHECK_NO_THROW(theStatisticsDefault->getVx().getValue(0.9 * theStatisticsDefault->getMaximum())); CHECK_NO_THROW(theStatisticsDefault->getVx().getValue(0.95 * theStatisticsDefault->getMaximum())); CHECK_NO_THROW(theStatisticsDefault->getVx().getValue(0.98 * theStatisticsDefault->getMaximum())); CHECK_NO_THROW(theStatisticsDefault->getDx().getValue(0.02 * theStatisticsDefault->getVolume())); CHECK_NO_THROW(theStatisticsDefault->getDx().getValue(0.05 * theStatisticsDefault->getVolume())); CHECK_NO_THROW(theStatisticsDefault->getDx().getValue(0.1 * theStatisticsDefault->getVolume())); CHECK_NO_THROW(theStatisticsDefault->getDx().getValue(0.9 * theStatisticsDefault->getVolume())); CHECK_NO_THROW(theStatisticsDefault->getDx().getValue(0.95 * theStatisticsDefault->getVolume())); CHECK_NO_THROW(theStatisticsDefault->getDx().getValue(0.98 * theStatisticsDefault->getVolume())); //check manually set reference dose and the default x values CHECK_NO_THROW(theStatistics = myDoseStatsCalculator.calculateDoseStatistics(100.0)); CHECK_THROW_EXPLICIT(theStatistics->getVx().getValue(0.1 * theStatistics->getMaximum()), core::DataNotAvailableException); CHECK_NO_THROW(theStatistics->getVx().getValue(0.1 * 100.0)); CHECK_NO_THROW(theStatistics->getDx().getValue(0.1 * theStatistics->getVolume())); CHECK_NO_THROW(theStatistics->getDx().getValue(0.9 * theStatistics->getVolume())); CHECK_NO_THROW(theStatistics->getMOHx().getValue(0.95 * theStatistics->getVolume())); CHECK_NO_THROW(theStatistics->getMOCx().getValue(0.98 * theStatistics->getVolume())); CHECK_EQUAL(theStatistics->getReferenceDose(), 100.0); //check manually set x values std::vector<double> precomputeDoseValues, precomputeVolumeValues, additionalValues, faultyValues; precomputeDoseValues.push_back(0.01); precomputeDoseValues.push_back(0.02); precomputeDoseValues.push_back(0.05); precomputeVolumeValues.push_back(0.9); precomputeVolumeValues.push_back(0.95); precomputeVolumeValues.push_back(0.99); additionalValues.push_back(0.03); additionalValues.push_back(0.04); faultyValues.push_back(2); CHECK_THROW_EXPLICIT(theStatistics = myDoseStatsCalculator.calculateDoseStatistics(precomputeDoseValues, faultyValues), core::InvalidParameterException); CHECK_THROW_EXPLICIT(theStatistics = myDoseStatsCalculator.calculateDoseStatistics(faultyValues, precomputeVolumeValues), core::InvalidParameterException); CHECK_NO_THROW(theStatistics = myDoseStatsCalculator.calculateDoseStatistics(precomputeDoseValues, precomputeVolumeValues)); CHECK_NO_THROW(theStatistics->getVx().getValue(0.01 * theStatistics->getMaximum())); CHECK_NO_THROW(theStatistics->getVx().getValue(0.02 * theStatistics->getMaximum())); CHECK_NO_THROW(theStatistics->getVx().getValue(0.05 * theStatistics->getMaximum())); CHECK_THROW_EXPLICIT(theStatistics->getVx().getValue(0.03 * theStatistics->getMaximum()), core::DataNotAvailableException); CHECK_NO_THROW(theStatistics->getDx().getValue(0.9 * theStatistics->getVolume())); CHECK_NO_THROW(theStatistics->getDx().getValue(0.95 * theStatistics->getVolume())); CHECK_NO_THROW(theStatistics->getDx().getValue(0.99 * theStatistics->getVolume())); CHECK_THROW_EXPLICIT(theStatistics->getDx().getValue(0.04 * theStatistics->getVolume()), core::DataNotAvailableException); CHECK_THROW_EXPLICIT(myDoseStatsCalculator.addPrecomputeValues(faultyValues), core::InvalidParameterException); CHECK_NO_THROW(myDoseStatsCalculator.addPrecomputeValues(additionalValues)); CHECK_NO_THROW(myDoseStatsCalculator.recalculateDoseStatistics()); CHECK_NO_THROW(theStatistics->getVx().getValue(0.03 * theStatistics->getMaximum())); CHECK_NO_THROW(theStatistics->getDx().getValue(0.04 * theStatistics->getVolume())); CHECK_EQUAL(theStatistics->getVx().getValue(0.02 * theStatistics->getMaximum()), theStatisticsDefault->getVx().getValue(0.02 * theStatistics->getMaximum())); CHECK_EQUAL(theStatistics->getVx().getValue(0.05 * theStatistics->getMaximum()), theStatisticsDefault->getVx().getValue(0.05 * theStatistics->getMaximum())); CHECK_EQUAL(theStatistics->getDx().getValue(0.9 * theStatistics->getVolume()), theStatisticsDefault->getDx().getValue(0.9 * theStatistics->getVolume())); CHECK_EQUAL(theStatistics->getDx().getValue(0.95 * theStatistics->getVolume()), theStatisticsDefault->getDx().getValue(0.95 * theStatistics->getVolume())); //check manually set reference dose and x values CHECK_NO_THROW(theStatistics = myDoseStatsCalculator.calculateDoseStatistics(precomputeDoseValues, precomputeVolumeValues, 100.0)); CHECK_THROW_EXPLICIT(theStatistics->getVx().getValue(0.01 * theStatistics->getMaximum()), core::DataNotAvailableException); CHECK_NO_THROW(theStatistics->getVx().getValue(0.01 * 100.0)); CHECK_NO_THROW(theStatistics->getDx().getValue(0.9 * theStatistics->getVolume())); CHECK_EQUAL(theStatistics->getReferenceDose(), 100.0); //MOHx, MOCx, MaxOHx and MinOCx are computed analogous to Dx, they will not be checked. //4) get statistical values CHECK_EQUAL(theStatistics->getNumberOfVoxels(), doseVals->size()); //compute simple statistical values (min, mean, max, stddev) for comparison DoseStatisticType maximum = 0; DoseStatisticType minimum = 1000000; DoseStatisticType mean = 0; DoseStatisticType variance = 0; std::vector<DoseTypeGy>::const_iterator doseIt = doseVals->begin(); while (doseIt != doseVals->end()) { if (maximum < *doseIt) { maximum = *doseIt; } if (minimum > *doseIt) { minimum = *doseIt; } mean += *doseIt; ++doseIt; } mean /= doseVals->size(); doseIt = doseVals->begin(); while (doseIt != doseVals->end()) { variance += pow(*doseIt - mean, 2); ++doseIt; } variance /= doseVals->size(); DoseStatisticType stdDev = pow(variance, 0.5); //we have some precision problems here... double errorConstantLarger = 1e-2; CHECK_EQUAL(theStatistics->getMaximum(), maximum); CHECK_EQUAL(theStatistics->getMinimum(), minimum); CHECK_CLOSE(theStatistics->getMean(), mean, errorConstantLarger); CHECK_CLOSE(theStatistics->getStdDeviation(), stdDev, errorConstantLarger); CHECK_CLOSE(theStatistics->getVariance(), variance, errorConstantLarger); //check for complex doseStatistics (maximumPositions, minimumPositions, Vx, Dx, MOHx, MOCx, MAXOHx, MinOCx) unsigned int nMax = 0, nMin = 0; doseIt = doseVals->begin(); while (doseIt != doseVals->end()) { if (*doseIt == theStatistics->getMaximum()) { nMax++; } if (*doseIt == theStatistics->getMinimum()) { nMin++; } ++doseIt; } //only 100 positions are stored if (nMax > 100) { nMax = 100; } if (nMin > 100) { nMin = 100; } auto maximaPositions = theStatistics->getMaximumVoxelPositions(); auto minimaPositions = theStatistics->getMinimumVoxelPositions(); CHECK_EQUAL(maximaPositions->size(), nMax); CHECK_EQUAL(minimaPositions->size(), nMin); for (auto maximaPositionsIterator = std::begin(*maximaPositions); maximaPositionsIterator != std::end(*maximaPositions); ++maximaPositionsIterator) { CHECK_EQUAL(maximaPositionsIterator->first, theStatistics->getMaximum()); } for (auto minimaPositionsIterator = std::begin(*minimaPositions); minimaPositionsIterator != std::end(*minimaPositions); ++minimaPositionsIterator) { CHECK_EQUAL(minimaPositionsIterator->first, theStatistics->getMinimum()); } //generate specific example dose maximum = 9.5; minimum = 2.5; mean = 6; int sizeTemplate = 500; std::vector<DoseTypeGy> aDoseVector; for (int i = 0; i < sizeTemplate; i++) { aDoseVector.push_back(maximum); aDoseVector.push_back(minimum); } core::GeometricInfo geoInfo = spTestDoseAccessor->getGeometricInfo(); geoInfo.setNumRows(20); geoInfo.setNumColumns(10); geoInfo.setNumSlices(5); boost::shared_ptr<DummyDoseAccessor> spTestDoseAccessor2 = boost::make_shared<DummyDoseAccessor>(aDoseVector, geoInfo); DoseAccessorPointer spDoseAccessor2(spTestDoseAccessor2); boost::shared_ptr<core::GenericDoseIterator> spTestDoseIterator2 = boost::make_shared<core::GenericDoseIterator>(spDoseAccessor2); DoseIteratorPointer spDoseIterator2(spTestDoseIterator2); rttb::algorithms::DoseStatisticsCalculator myDoseStatsCalculator2(spDoseIterator2); DoseStatisticsPointer theStatistics3 = myDoseStatsCalculator2.calculateDoseStatistics(); CHECK_EQUAL(theStatistics3->getMaximum(), maximum); CHECK_EQUAL(theStatistics3->getMinimum(), minimum); CHECK_EQUAL(theStatistics3->getMean(), mean); maximaPositions = theStatistics3->getMaximumVoxelPositions(); minimaPositions = theStatistics3->getMinimumVoxelPositions(); CHECK_EQUAL(maximaPositions->empty(), false); CHECK_EQUAL(minimaPositions->empty(), false); for (auto maximaPositionsIterator = std::begin(*maximaPositions); maximaPositionsIterator != std::end(*maximaPositions); ++maximaPositionsIterator) { CHECK_EQUAL(maximaPositionsIterator->first, theStatistics3->getMaximum()); } for (auto minimaPositionsIterator = std::begin(*minimaPositions); minimaPositionsIterator != std::end(*minimaPositions); ++minimaPositionsIterator) { CHECK_EQUAL(minimaPositionsIterator->first, theStatistics3->getMinimum()); } // compare with actual XML io::dicom::DicomFileDoseAccessorGenerator doseAccessorGenerator(doseFilename.c_str()); core::DoseAccessorInterface::Pointer doseAccessorPointer(doseAccessorGenerator.generateDoseAccessor()); rttb::io::dicom::DicomFileStructureSetGenerator structAccessorGenerator(structFilename.c_str()); structAccessorGenerator.setStructureLabelFilterActive(true); structAccessorGenerator.setFilterRegEx("Heart"); core::StructureSet::Pointer structureSetGeneratorPointer = structAccessorGenerator.generateStructureSet(); CHECK_EQUAL(structureSetGeneratorPointer->getNumberOfStructures(), 1); core::MaskAccessorInterface::Pointer maskAccessorPointer = boost::make_shared<rttb::masks::boost::BoostMaskAccessor> (structureSetGeneratorPointer->getStructure(0), doseAccessorPointer->getGeometricInfo(), true); maskAccessorPointer->updateMask(); boost::shared_ptr<core::GenericMaskedDoseIterator> maskedDoseIterator = boost::make_shared<core::GenericMaskedDoseIterator>(maskAccessorPointer, doseAccessorPointer); rttb::core::DoseIteratorInterface::Pointer doseIteratorPointer(maskedDoseIterator); rttb::algorithms::DoseStatisticsCalculator doseStatisticsCalculator(doseIteratorPointer); DoseStatisticsPointer doseStatisticsActual = doseStatisticsCalculator.calculateDoseStatistics(14.0); io::other::DoseStatisticsXMLReader readerDefaultExpected(referenceXMLFilename); auto doseStatisticsExpected = readerDefaultExpected.generateDoseStatistic(); CHECK(checkEqualDoseStatistic(doseStatisticsExpected, doseStatisticsActual)); RETURN_AND_REPORT_TEST_SUCCESS; } }//end namespace testing }//end namespace rttb diff --git a/testing/algorithms/DoseStatisticsTest.cpp b/testing/algorithms/DoseStatisticsTest.cpp index ef5e610..15a8059 100644 --- a/testing/algorithms/DoseStatisticsTest.cpp +++ b/testing/algorithms/DoseStatisticsTest.cpp @@ -1,251 +1,245 @@ // ----------------------------------------------------------------------- // 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 <boost/make_shared.hpp> #include <boost/shared_ptr.hpp> #include "litCheckMacros.h" #include "rttbBaseType.h" #include "rttbDoseStatistics.h" #include "rttbDataNotAvailableException.h" #include "rttbVolumeToDoseMeasureCollection.h" namespace rttb { namespace testing { typedef rttb::algorithms::DoseStatistics::ResultListPointer ResultListPointer; /*! @brief DoseStatisticsTest - test the API of DoseStatistics 1) test constructors 2) test setters 3) test getters of complex statistics (with stored key and without stored key) */ int DoseStatisticsTest(int argc, char* argv[]) { PREPARE_DEFAULT_TEST_REPORTING; DoseStatisticType minimum = 1.0; DoseStatisticType mean = 5.5; DoseStatisticType maximum = 108.2; DoseStatisticType stdDeviation = 10.1; unsigned int numVoxels = 100000; VolumeType volume = numVoxels * (0.5 * 0.5 * 0.5); std::vector<std::pair<DoseTypeGy, VoxelGridID> > minVoxels; std::vector<std::pair<DoseTypeGy, VoxelGridID> > maxVoxels; minVoxels.push_back(std::make_pair(1.0, 11)); minVoxels.push_back(std::make_pair(1.0, 22)); minVoxels.push_back(std::make_pair(1.0, 33)); minVoxels.push_back(std::make_pair(1.0, 44)); maxVoxels.push_back(std::make_pair(108.2, 5)); maxVoxels.push_back(std::make_pair(108.2, 6)); maxVoxels.push_back(std::make_pair(108.2, 7)); maxVoxels.push_back(std::make_pair(108.2, 8)); ResultListPointer resultsMinVoxels = boost::make_shared<std::vector<std::pair<DoseTypeGy, VoxelGridID> > >(minVoxels); ResultListPointer resultsMaxVoxels = boost::make_shared<std::vector<std::pair<DoseTypeGy, VoxelGridID> > >(maxVoxels); algorithms::DoseToVolumeMeasureCollection Vx(algorithms::DoseToVolumeMeasureCollection::Vx, maximum); Vx.insertValue(1.1, 1000); Vx.insertValue(106.9, 99000); algorithms::VolumeToDoseMeasureCollection Dx(algorithms::VolumeToDoseMeasureCollection::Dx, volume); Dx.insertValue(1000, 1.1); Dx.insertValue(99000, 106.9); algorithms::VolumeToDoseMeasureCollection MOHx(algorithms::VolumeToDoseMeasureCollection::MOHx, volume); MOHx.insertValue(1000, 5); MOHx.insertValue(99000, 105.5); algorithms::VolumeToDoseMeasureCollection MOCx(algorithms::VolumeToDoseMeasureCollection::MOCx, volume); MOCx.insertValue(1000, 10); MOCx.insertValue(99000, 99); algorithms::VolumeToDoseMeasureCollection MaxOHx(algorithms::VolumeToDoseMeasureCollection::MaxOHx, volume); MaxOHx.insertValue(1000, 40); MaxOHx.insertValue(99000, 98.3); algorithms::VolumeToDoseMeasureCollection MinOCx(algorithms::VolumeToDoseMeasureCollection::MinOCx, volume); MinOCx.insertValue(1000, 25.5); MinOCx.insertValue(99000, 102.7); //1) test constructors CHECK_NO_THROW(rttb::algorithms::DoseStatistics aDoseStatistic(minimum, maximum, mean, stdDeviation, numVoxels, volume)); rttb::algorithms::DoseStatistics aDoseStatistic(minimum, maximum, mean, stdDeviation, numVoxels, volume); CHECK_EQUAL(aDoseStatistic.getMinimum(), minimum); CHECK_EQUAL(aDoseStatistic.getMaximum(), maximum); CHECK_EQUAL(aDoseStatistic.getMean(), mean); CHECK_EQUAL(aDoseStatistic.getStdDeviation(), stdDeviation); CHECK_EQUAL(aDoseStatistic.getVariance(), stdDeviation * stdDeviation); CHECK_EQUAL(aDoseStatistic.getNumberOfVoxels(), numVoxels); CHECK_EQUAL(aDoseStatistic.getVolume(), volume); //check default values for unset complex values CHECK_EQUAL(aDoseStatistic.getMaximumVoxelPositions()->empty(), true); CHECK_EQUAL(aDoseStatistic.getMinimumVoxelPositions()->empty(), true); CHECK_EQUAL(aDoseStatistic.getDx().getAllValues().empty(), true); CHECK_EQUAL(aDoseStatistic.getVx().getAllValues().empty(), true); CHECK_EQUAL(aDoseStatistic.getMOHx().getAllValues().empty(), true); CHECK_EQUAL(aDoseStatistic.getMOCx().getAllValues().empty(), true); CHECK_EQUAL(aDoseStatistic.getMaxOHx().getAllValues().empty(), true); CHECK_EQUAL(aDoseStatistic.getMinOCx().getAllValues().empty(), true); CHECK_NO_THROW(rttb::algorithms::DoseStatistics aDoseStatisticComplex(minimum, maximum, mean, stdDeviation, numVoxels, volume, resultsMaxVoxels, resultsMinVoxels, Dx, Vx, MOHx, MOCx, MaxOHx, MinOCx)); rttb::algorithms::DoseStatistics aDoseStatisticComplex(minimum, maximum, mean, stdDeviation, numVoxels, volume, resultsMaxVoxels, resultsMinVoxels, Dx, Vx, MOHx, MOCx, MaxOHx, MinOCx); CHECK_EQUAL(aDoseStatisticComplex.getMaximumVoxelPositions(), resultsMaxVoxels); CHECK_EQUAL(aDoseStatisticComplex.getMinimumVoxelPositions(), resultsMinVoxels); CHECK_EQUAL(aDoseStatisticComplex.getDx() == Dx, true); CHECK_EQUAL(aDoseStatisticComplex.getVx() == Vx, true); CHECK_EQUAL(aDoseStatisticComplex.getMOHx() == MOHx, true); CHECK_EQUAL(aDoseStatisticComplex.getMOCx() == MOCx, true); CHECK_EQUAL(aDoseStatisticComplex.getMaxOHx() == MaxOHx, true); CHECK_EQUAL(aDoseStatisticComplex.getMinOCx() == MinOCx, true); //2) test setters (only complex statistics have setters) CHECK_NO_THROW(aDoseStatistic.setMaximumVoxelPositions(resultsMaxVoxels)); CHECK_NO_THROW(aDoseStatistic.setMinimumVoxelPositions(resultsMinVoxels)); CHECK_NO_THROW(aDoseStatistic.setDx(::boost::make_shared<algorithms::VolumeToDoseMeasureCollection>(Dx))); CHECK_NO_THROW(aDoseStatistic.setVx(::boost::make_shared<algorithms::DoseToVolumeMeasureCollection>(Vx))); CHECK_NO_THROW(aDoseStatistic.setMOHx(::boost::make_shared<algorithms::VolumeToDoseMeasureCollection>(MOHx))); CHECK_NO_THROW(aDoseStatistic.setMOCx(::boost::make_shared<algorithms::VolumeToDoseMeasureCollection>(MOCx))); CHECK_NO_THROW(aDoseStatistic.setMaxOHx(::boost::make_shared<algorithms::VolumeToDoseMeasureCollection>(MaxOHx))); CHECK_NO_THROW(aDoseStatistic.setMinOCx(::boost::make_shared<algorithms::VolumeToDoseMeasureCollection>(MinOCx))); CHECK_EQUAL(aDoseStatistic.getMaximumVoxelPositions(), resultsMaxVoxels); CHECK_EQUAL(aDoseStatistic.getMinimumVoxelPositions(), resultsMinVoxels); CHECK_EQUAL(aDoseStatistic.getDx() == Dx, true); CHECK_EQUAL(aDoseStatistic.getVx() == Vx, true); CHECK_EQUAL(aDoseStatistic.getMOHx() == MOHx, true); CHECK_EQUAL(aDoseStatistic.getMOCx() == MOCx, true); CHECK_EQUAL(aDoseStatistic.getMaxOHx() == MaxOHx, true); CHECK_EQUAL(aDoseStatistic.getMinOCx() == MinOCx, true); //3) test getters of complex statistics(with stored key and without stored key) //getAll*() already tested in (2) Vx = algorithms::DoseToVolumeMeasureCollection(algorithms::DoseToVolumeMeasureCollection::Vx, maximum); Vx.insertValue(1.1, 1000); Vx.insertValue(5.0, 2300); Vx.insertValue(90, 90500); Vx.insertValue(107, 99000); Dx = algorithms::VolumeToDoseMeasureCollection(algorithms::VolumeToDoseMeasureCollection::Dx, volume); Dx.insertValue(1000, 1.1); Dx.insertValue(2000, 2.0); Dx.insertValue(5000, 10.8); Dx.insertValue(90000, 89.5); Dx.insertValue(98000, 104.4); Dx.insertValue(99000, 106.9); rttb::algorithms::DoseStatistics aDoseStatisticNewValues(minimum, maximum, mean, stdDeviation, numVoxels, volume); aDoseStatisticNewValues.setDx(::boost::make_shared<algorithms::VolumeToDoseMeasureCollection>(Dx)); aDoseStatisticNewValues.setVx(::boost::make_shared<algorithms::DoseToVolumeMeasureCollection>(Vx)); CHECK_NO_THROW(aDoseStatisticNewValues.getVx().getValue(1.1)); CHECK_NO_THROW(aDoseStatisticNewValues.getVx().getValue(90)); CHECK_NO_THROW(aDoseStatisticNewValues.getDx().getValue(1000)); CHECK_NO_THROW(aDoseStatisticNewValues.getDx().getValue(98000)); CHECK_EQUAL(aDoseStatisticNewValues.getVx().getValue(1.1), Vx.getAllValues().find(1.1)->second); CHECK_EQUAL(aDoseStatisticNewValues.getVx().getValue(90), Vx.getAllValues().find(90)->second); CHECK_EQUAL(aDoseStatisticNewValues.getDx().getValue(1000), Dx.getAllValues().find(1000)->second); CHECK_EQUAL(aDoseStatisticNewValues.getDx().getValue(98000), Dx.getAllValues().find(98000)->second); //test if key-value combination NOT in map CHECK_THROW_EXPLICIT(aDoseStatisticNewValues.getDx().getValue(1001), core::DataNotAvailableException); CHECK_THROW_EXPLICIT(aDoseStatisticNewValues.getVx().getValue(10), core::DataNotAvailableException); double closestDxKey, closestVxKey; CHECK_NO_THROW(aDoseStatisticNewValues.getDx().getValue(900, true, closestDxKey)); CHECK_NO_THROW(aDoseStatisticNewValues.getDx().getValue(99001, true, closestDxKey)); CHECK_NO_THROW(aDoseStatisticNewValues.getVx().getValue(10, true, closestVxKey)); CHECK_EQUAL(aDoseStatisticNewValues.getDx().getValue(900, true, closestDxKey), Dx.getAllValues().find(1000)->second); CHECK_EQUAL(aDoseStatisticNewValues.getDx().getValue(99001, true, closestDxKey), Dx.getAllValues().find(99000)->second); CHECK_EQUAL(aDoseStatisticNewValues.getVx().getValue(10, true, closestVxKey), Vx.getAllValues().find(5.0)->second); CHECK_EQUAL(closestDxKey, 99000); CHECK_EQUAL(closestVxKey, 5); // relatives only between 0 and 1 CHECK_NO_THROW(aDoseStatisticNewValues.getVx().getValueRelative(1.1 / aDoseStatistic.getReferenceDose())); CHECK_NO_THROW(aDoseStatisticNewValues.getDx().getValueRelative(1000 / aDoseStatistic.getVolume())); CHECK_THROW(aDoseStatisticNewValues.getVx().getValueRelative(-0.3)); CHECK_THROW(aDoseStatisticNewValues.getVx().getValueRelative(1.1)); CHECK_THROW(aDoseStatisticNewValues.getDx().getValueRelative(0.5)); CHECK_NO_THROW(aDoseStatisticNewValues.getDx().getValueRelative(900 / aDoseStatistic.getVolume(), true, closestDxKey)); CHECK_NO_THROW(aDoseStatisticNewValues.getDx().getValueRelative(0.5, true, closestDxKey)); CHECK_NO_THROW(aDoseStatisticNewValues.getVx().getValueRelative(10 / aDoseStatistic.getReferenceDose(), true, closestVxKey)); CHECK_EQUAL(aDoseStatisticNewValues.getDx().getValueRelative(900 / aDoseStatistic.getVolume(), true, closestDxKey), Dx.getAllValues().find(1000)->second); CHECK_EQUAL(aDoseStatisticNewValues.getVx().getValueRelative(10 / aDoseStatistic.getReferenceDose(), true, closestVxKey), Vx.getAllValues().find(5.0)->second); CHECK_EQUAL(closestVxKey, 5); //equal distance to two values. First value is returned. CHECK_NO_THROW(aDoseStatisticNewValues.getDx().getValue(1500, true, closestDxKey)); CHECK_NO_THROW(aDoseStatisticNewValues.getVx().getValue(98.5, true, closestVxKey)); CHECK_EQUAL(aDoseStatisticNewValues.getDx().getValue(1500, true, closestDxKey), Dx.getAllValues().find(1000)->second); CHECK_EQUAL(aDoseStatisticNewValues.getVx().getValue(98.5, true, closestVxKey), Vx.getAllValues().find(90.0)->second); CHECK_EQUAL(closestDxKey, 1000); CHECK_EQUAL(closestVxKey, 90.0); double dummy; CHECK_THROW_EXPLICIT(aDoseStatisticNewValues.getMinOCx().getValue(25), core::DataNotAvailableException); CHECK_THROW_EXPLICIT(aDoseStatisticNewValues.getMOHx().getValue(9999), core::DataNotAvailableException); CHECK_THROW_EXPLICIT(aDoseStatisticNewValues.getMinOCx().getValue(25, true, dummy), core::DataNotAvailableException); CHECK_THROW_EXPLICIT(aDoseStatisticNewValues.getMOHx().getValue(9999, true, dummy), core::DataNotAvailableException); CHECK_THROW_EXPLICIT(aDoseStatisticNewValues.getMinOCx().getValueRelative(25 / aDoseStatistic.getVolume()), core::DataNotAvailableException); CHECK_THROW_EXPLICIT(aDoseStatisticNewValues.getMOHx().getValueRelative(9999 / aDoseStatistic.getVolume()), core::DataNotAvailableException); CHECK_THROW_EXPLICIT(aDoseStatisticNewValues.getMinOCx().getValueRelative(25 / aDoseStatistic.getVolume(), true, dummy), core::DataNotAvailableException); CHECK_THROW_EXPLICIT(aDoseStatisticNewValues.getMOHx().getValueRelative(9999 / aDoseStatistic.getVolume(), true, dummy), core::DataNotAvailableException); RETURN_AND_REPORT_TEST_SUCCESS; } }//end namespace testing }//end namespace rttb diff --git a/testing/algorithms/rttbAlgorithmsTests.cpp b/testing/algorithms/rttbAlgorithmsTests.cpp index e73def6..f5ce005 100644 --- a/testing/algorithms/rttbAlgorithmsTests.cpp +++ b/testing/algorithms/rttbAlgorithmsTests.cpp @@ -1,66 +1,60 @@ // ----------------------------------------------------------------------- // 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(BinaryFunctorAccessorTest); } } } 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.cpp b/testing/core/DummyDoseAccessor.cpp index 5d42d3b..d88c09c 100644 --- a/testing/core/DummyDoseAccessor.cpp +++ b/testing/core/DummyDoseAccessor.cpp @@ -1,100 +1,94 @@ // ----------------------------------------------------------------------- // 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 <boost/uuid/uuid.hpp> #include <boost/uuid/uuid_generators.hpp> #include <boost/uuid/uuid_io.hpp> #include "DummyDoseAccessor.h" #include "rttbNullPointerException.h" #include "rttbInvalidDoseException.h" #include "rttbIndexOutOfBoundsException.h" namespace rttb { namespace testing { DummyDoseAccessor::~DummyDoseAccessor() {} DummyDoseAccessor::DummyDoseAccessor() { boost::uuids::uuid id; boost::uuids::random_generator generator; id = generator(); std::stringstream ss; ss << id; _doseUID = "DummyDoseAccessor_" + ss.str(); assembleGeometricInfo(); for (int i = 0; i < _geoInfo.getNumberOfVoxels(); i++) { doseData.push_back((double(rand()) / RAND_MAX) * 1000); } } DummyDoseAccessor::DummyDoseAccessor(const std::vector<DoseTypeGy>& aDoseVector, const core::GeometricInfo& geoInfo) { boost::uuids::uuid id; boost::uuids::random_generator generator; id = generator(); std::stringstream ss; ss << id; _doseUID = "DummyDoseAccessor_" + ss.str(); doseData = aDoseVector; _geoInfo = geoInfo; } void DummyDoseAccessor::assembleGeometricInfo() { SpacingVectorType3D aVector(2.5); _geoInfo.setSpacing(aVector); WorldCoordinate3D anOtherVector(-25, -2, 35); _geoInfo.setImagePositionPatient(anOtherVector); _geoInfo.setNumRows(11); _geoInfo.setNumColumns(10); _geoInfo.setNumSlices(10); OrientationMatrix unit = OrientationMatrix(); _geoInfo.setOrientationMatrix(unit); } GenericValueType DummyDoseAccessor::getValueAt(const VoxelGridID aID) const { if (!_geoInfo.validID(aID)) { throw core::IndexOutOfBoundsException("Not a valid Position!"); } return doseData.at(aID); } GenericValueType DummyDoseAccessor::getValueAt(const VoxelGridIndex3D& aIndex) const { VoxelGridID gridID = 0; _geoInfo.convert(aIndex, gridID); return getValueAt(gridID); } }//end namespace testing }//end namespace rttb \ No newline at end of file diff --git a/testing/core/DummyDoseAccessor.h b/testing/core/DummyDoseAccessor.h index 067e76f..5f6a89c 100644 --- a/testing/core/DummyDoseAccessor.h +++ b/testing/core/DummyDoseAccessor.h @@ -1,84 +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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ + #ifndef __DUMMY_DOSE_ACCESSOR_H #define __DUMMY_DOSE_ACCESSOR_H #include <vector> #include <boost/throw_exception.hpp> #include "rttbAccessorWithGeoInfoBase.h" #include "rttbGeometricInfo.h" #include "rttbBaseType.h" namespace rttb { 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::AccessorWithGeoInfoBase { private: /*! vector of dose data(absolute Gy dose/doseGridScaling)*/ std::vector<DoseTypeGy> doseData; IDType _doseUID; 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 Constructor. Initialisation of dose with a given vector. */ DummyDoseAccessor(const std::vector<DoseTypeGy>& aDoseVector, const core::GeometricInfo& geoInfo); void assembleGeometricInfo() override; const std::vector<DoseTypeGy>* getDoseVector() const { return &doseData; }; GenericValueType getValueAt(const VoxelGridID aID) const; GenericValueType getValueAt(const VoxelGridIndex3D& aIndex) const; const IDType getUID() const { return _doseUID; }; }; } } #endif diff --git a/testing/core/DummyMaskAccessor.cpp b/testing/core/DummyMaskAccessor.cpp index 46eba43..f6401e7 100644 --- a/testing/core/DummyMaskAccessor.cpp +++ b/testing/core/DummyMaskAccessor.cpp @@ -1,162 +1,156 @@ // ----------------------------------------------------------------------- // 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 <boost/make_shared.hpp> #include <boost/uuid/uuid.hpp> #include <boost/uuid/uuid_generators.hpp> #include <boost/uuid/uuid_io.hpp> #include "DummyMaskAccessor.h" #include "rttbNullPointerException.h" namespace rttb { namespace testing { DummyMaskAccessor::DummyMaskAccessor(const core::GeometricInfo& aGeometricInfo) { _spRelevantVoxelVector = MaskVoxelListPointer(); _geoInfo = aGeometricInfo; boost::uuids::uuid id; boost::uuids::random_generator generator; id = generator(); std::stringstream ss; ss << id; _maskUID = "DummyMask_" + ss.str(); } DummyMaskAccessor::DummyMaskAccessor(const core::GeometricInfo& aGeometricInfo, MaskVoxelListPointer voxelListPtr) { _spRelevantVoxelVector = voxelListPtr; _geoInfo = aGeometricInfo; boost::uuids::uuid id; boost::uuids::random_generator generator; id = generator(); std::stringstream ss; ss << id; _maskUID = "DummyMask_" + ss.str(); } void DummyMaskAccessor::updateMask() { MaskVoxelList newRelevantVoxelVector; if (_spRelevantVoxelVector) { return; } for (int i = 0; i < _geoInfo.getNumberOfVoxels(); i++) { if ((double(rand()) / RAND_MAX) > 0.5) { core::MaskVoxel newMaskVoxel(i); newMaskVoxel.setRelevantVolumeFraction((double(rand()) / RAND_MAX)); newRelevantVoxelVector.push_back(newMaskVoxel); } } _spRelevantVoxelVector = boost::make_shared<MaskVoxelList>(newRelevantVoxelVector); return; } DummyMaskAccessor::MaskVoxelListPointer DummyMaskAccessor::getRelevantVoxelVector() { updateMask(); return _spRelevantVoxelVector; } DummyMaskAccessor::MaskVoxelListPointer DummyMaskAccessor::getRelevantVoxelVector( float lowerThreshold) { auto filteredVoxelVectorPointer = boost::make_shared<MaskVoxelList>(); updateMask(); DummyMaskAccessor::MaskVoxelList::iterator it = _spRelevantVoxelVector->begin(); while (it != _spRelevantVoxelVector->end()) { if ((*it).getRelevantVolumeFraction() > lowerThreshold) { filteredVoxelVectorPointer->push_back(*it); } ++it; } return filteredVoxelVectorPointer; } bool DummyMaskAccessor::getMaskAt(VoxelGridID aID, core::MaskVoxel& voxel) const { voxel.setRelevantVolumeFraction(0); if (!_geoInfo.validID(aID)) { return false; } if (_spRelevantVoxelVector) { DummyMaskAccessor::MaskVoxelList::iterator it = _spRelevantVoxelVector->begin(); while (it != _spRelevantVoxelVector->end()) { if ((*it).getVoxelGridID() == aID) { voxel = (*it); return true; } ++it; } } else { return false; } return false; } bool DummyMaskAccessor::getMaskAt(const VoxelGridIndex3D& aIndex, core::MaskVoxel& voxel) const { VoxelGridID aVoxelGridID; if (_geoInfo.convert(aIndex, aVoxelGridID)) { return getMaskAt(aVoxelGridID, voxel); } else { return false; } } } } \ No newline at end of file diff --git a/testing/core/DummyMaskAccessor.h b/testing/core/DummyMaskAccessor.h index 4255eab..d5d119e 100644 --- a/testing/core/DummyMaskAccessor.h +++ b/testing/core/DummyMaskAccessor.h @@ -1,81 +1,76 @@ // ----------------------------------------------------------------------- // 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_MASK_ACCESSOR_H #define __DUMMY_MASK_ACCESSOR_H #include <vector> #include "rttbMaskAccessorInterface.h" #include "rttbGeometricInfo.h" #include "rttbBaseType.h" namespace rttb { namespace testing { /*! @class DumyMaskAccessor @brief Create a dummy MaskAccessor for testing. */ class DummyMaskAccessor: public core::MaskAccessorInterface { public: typedef core::MaskAccessorInterface::MaskVoxelList MaskVoxelList; typedef core::MaskAccessorInterface::MaskVoxelListPointer MaskVoxelListPointer; private: /*! vector containing list of mask voxels*/ MaskVoxelListPointer _spRelevantVoxelVector; core::GeometricInfo _geoInfo; IDType _maskUID; public: DummyMaskAccessor(const core::GeometricInfo& aGeometricInfo); DummyMaskAccessor(const core::GeometricInfo& aGeometricInfo, MaskVoxelListPointer voxelListPtr); ~DummyMaskAccessor() {}; void updateMask(); const core::GeometricInfo& getGeometricInfo() const { return _geoInfo; }; MaskVoxelListPointer getRelevantVoxelVector(); MaskVoxelListPointer getRelevantVoxelVector(float lowerThreshold); bool getMaskAt(const VoxelGridID aID, core::MaskVoxel& voxel) const; bool getMaskAt(const VoxelGridIndex3D& gridIndex, core::MaskVoxel& voxel) const; IDType getMaskUID() const { return _maskUID; }; }; } } #endif diff --git a/testing/core/DummyMutableDoseAccessor.cpp b/testing/core/DummyMutableDoseAccessor.cpp index 12de4c3..ed82584 100644 --- a/testing/core/DummyMutableDoseAccessor.cpp +++ b/testing/core/DummyMutableDoseAccessor.cpp @@ -1,120 +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$ (last changed revision) -// @date $Date$ (last change date) -// @author $Author$ (last changed by) -*/ #include <boost/uuid/uuid.hpp> #include <boost/uuid/uuid_generators.hpp> #include <boost/uuid/uuid_io.hpp> #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<DoseTypeGy>& 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; } GenericValueType DummyMutableDoseAccessor::getValueAt(const VoxelGridID aID) const { if (!_geoInfo.validID(aID)) { throw core::IndexOutOfBoundsException("Not a valid Position!"); } return doseData.at(aID); } GenericValueType DummyMutableDoseAccessor::getValueAt(const VoxelGridIndex3D& aIndex) const { VoxelGridID gridID = 0; _geoInfo.convert(aIndex, gridID); return getValueAt(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 5dbdae9..14f61a7 100644 --- a/testing/core/DummyMutableDoseAccessor.h +++ b/testing/core/DummyMutableDoseAccessor.h @@ -1,88 +1,83 @@ // ----------------------------------------------------------------------- // 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 <vector> #include "rttbMutableDoseAccessorInterface.h" #include "rttbGeometricInfo.h" #include "rttbBaseType.h" namespace rttb { 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 { private: /*! vector of dose data(absolute Gy dose/doseGridScaling)*/ std::vector<DoseTypeGy> doseData; IDType _doseUID; core::GeometricInfo _geoInfo; 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 Constructor. Initialisation of dose with a given vector. */ DummyMutableDoseAccessor(const std::vector<DoseTypeGy>& aDoseVector, const core::GeometricInfo& geoInfo); const std::vector<DoseTypeGy>* getDoseVector() const { return &doseData; }; virtual const core::GeometricInfo& getGeometricInfo() const; GenericValueType getValueAt(const VoxelGridID aID) const; GenericValueType getValueAt(const VoxelGridIndex3D& aIndex) const; void setDoseAt(const VoxelGridID aID, DoseTypeGy value); void setDoseAt(const VoxelGridIndex3D& aIndex, DoseTypeGy value); const IDType getUID() const { return _doseUID; }; }; } } #endif diff --git a/testing/io/other/CompareDoseStatistic.cpp b/testing/io/other/CompareDoseStatistic.cpp index 9b55a51..75ed451 100644 --- a/testing/io/other/CompareDoseStatistic.cpp +++ b/testing/io/other/CompareDoseStatistic.cpp @@ -1,116 +1,107 @@ // ----------------------------------------------------------------------- // 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: 1221 $ (last changed revision) -// @date $Date: 2015-12-01 13:43:31 +0100 (Di, 01 Dez 2015) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ - #include "CompareDoseStatistic.h" - - namespace rttb { namespace testing { const double errorConstant = 1e-3;// errorConstant is so small because the double are castet to float when they are written bool checkEqualDoseStatistic(DoseStatisticsPtr aDoseStatistic1, DoseStatisticsPtr aDoseStatistic2){ bool result = lit::AreClose(aDoseStatistic1->getNumberOfVoxels(), aDoseStatistic2->getNumberOfVoxels(), 0.01); result = result && lit::AreClose(aDoseStatistic1->getVolume(), aDoseStatistic2->getVolume(), errorConstant); result = result && lit::AreClose(aDoseStatistic1->getMinimum(), aDoseStatistic2->getMinimum(), errorConstant); result = result && lit::AreClose(aDoseStatistic1->getMaximum(), aDoseStatistic2->getMaximum(), errorConstant); result = result && lit::AreClose(aDoseStatistic1->getMean(), aDoseStatistic2->getMean(), errorConstant); result = result && lit::AreClose(aDoseStatistic1->getStdDeviation(), aDoseStatistic2->getStdDeviation(), errorConstant); result = result && mapCompare(aDoseStatistic1->getDx().getAllValues(), aDoseStatistic2->getDx().getAllValues()); result = result && mapCompare(aDoseStatistic1->getVx().getAllValues(), aDoseStatistic2->getVx().getAllValues()); result = result && mapCompare(aDoseStatistic1->getMaxOHx().getAllValues(), aDoseStatistic2->getMaxOHx().getAllValues()); result = result && mapCompare(aDoseStatistic1->getMinOCx().getAllValues(), aDoseStatistic2->getMinOCx().getAllValues()); result = result && mapCompare(aDoseStatistic1->getMOCx().getAllValues(), aDoseStatistic2->getMOCx().getAllValues()); result = result && mapCompare(aDoseStatistic1->getMOHx().getAllValues(), aDoseStatistic2->getMOHx().getAllValues()); return result; } std::map<double, double>::const_iterator findNearestKeyInMap(const std::map<double, double>& aMap, double key) { double minDistance = 1e19; double minDistanceLast = 1e20; auto iterator = std::begin(aMap); while (iterator != std::end(aMap)) { minDistanceLast = minDistance; minDistance = fabs(iterator->first - key); if (minDistanceLast > minDistance) { ++iterator; } else { if (iterator != std::begin(aMap)) { --iterator; return iterator; } else { return std::begin(aMap); } } } --iterator; return iterator; } double getValue(const std::map<double, double>& aMap, double key) { if (aMap.find(key) != std::end(aMap)) { return aMap.find(key)->second; } else { auto iterator = findNearestKeyInMap(aMap, key); return iterator->second; } } bool mapCompare(const std::map<double, double>& lhs, const std::map<double, double>& rhs) { if (lhs.size() != rhs.size()){ return false; } for (std::map<double, double>::const_iterator i = rhs.cbegin(); i != rhs.cend(); ++i) { double a = i->second; double b = getValue(lhs, i->first) ; if (std::abs(a - b ) > errorConstant){// errorConstant is 1e-3 because the double-->float cast when they are written return false; } } return true; } }//testing }//rttb diff --git a/testing/io/other/CompareDoseStatistic.h b/testing/io/other/CompareDoseStatistic.h index 23f3a74..f2b2b27 100644 --- a/testing/io/other/CompareDoseStatistic.h +++ b/testing/io/other/CompareDoseStatistic.h @@ -1,51 +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: 1221 $ (last changed revision) -// @date $Date: 2015-12-01 13:43:31 +0100 (Di, 01 Dez 2015) $ (last change date) -// @author $Author: hentsch $ (last changed by) -*/ - #include "litCheckMacros.h" #include "rttbDoseStatistics.h" #ifndef __DOSE_STATISTICS_COMPARER_H #define __DOSE_STATISTICS_COMPARER_H - namespace rttb { namespace testing { typedef boost::shared_ptr<rttb::algorithms::DoseStatistics> DoseStatisticsPtr; /*! Compare 2 DoseStatistics and return the results. @result Indicates if the test was successful (true) or if it failed (false) */ bool checkEqualDoseStatistic(DoseStatisticsPtr aDoseStatistic1, DoseStatisticsPtr aDoseStatistic2); std::map<double, double>::const_iterator findNearestKeyInMap(const std::map<double, double>& aMap, double key); double getValue(const std::map<double, double>& aMap, double key); bool mapCompare(const std::map<double, double>& lhs, const std::map<double, double>& rhs); }//testing }//rttb #endif