diff --git a/Modules/Pharmacokinetics/src/Models/mitkExtendedToftsModel.cpp b/Modules/Pharmacokinetics/src/Models/mitkExtendedToftsModel.cpp index 4c53a5c238..dedc6d3917 100644 --- a/Modules/Pharmacokinetics/src/Models/mitkExtendedToftsModel.cpp +++ b/Modules/Pharmacokinetics/src/Models/mitkExtendedToftsModel.cpp @@ -1,177 +1,182 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkExtendedToftsModel.h" #include "mitkConvolutionHelper.h" #include #include const std::string mitk::ExtendedToftsModel::MODEL_DISPLAY_NAME = "Extended Tofts Model"; const std::string mitk::ExtendedToftsModel::NAME_PARAMETER_Ktrans = "KTrans"; const std::string mitk::ExtendedToftsModel::NAME_PARAMETER_ve = "ve"; const std::string mitk::ExtendedToftsModel::NAME_PARAMETER_vp = "vp"; const std::string mitk::ExtendedToftsModel::UNIT_PARAMETER_Ktrans = "ml/min/100ml"; const std::string mitk::ExtendedToftsModel::UNIT_PARAMETER_ve = "ml/ml"; const std::string mitk::ExtendedToftsModel::UNIT_PARAMETER_vp = "ml/ml"; const unsigned int mitk::ExtendedToftsModel::POSITION_PARAMETER_Ktrans = 0; const unsigned int mitk::ExtendedToftsModel::POSITION_PARAMETER_ve = 1; const unsigned int mitk::ExtendedToftsModel::POSITION_PARAMETER_vp = 2; const unsigned int mitk::ExtendedToftsModel::NUMBER_OF_PARAMETERS = 3; std::string mitk::ExtendedToftsModel::GetModelDisplayName() const { return MODEL_DISPLAY_NAME; }; std::string mitk::ExtendedToftsModel::GetModelType() const { return "Perfusion.MR"; }; mitk::ExtendedToftsModel::ExtendedToftsModel() { } mitk::ExtendedToftsModel::~ExtendedToftsModel() { } mitk::ExtendedToftsModel::ParameterNamesType mitk::ExtendedToftsModel::GetParameterNames() const { ParameterNamesType result; result.push_back(NAME_PARAMETER_Ktrans); result.push_back(NAME_PARAMETER_ve); result.push_back(NAME_PARAMETER_vp); return result; } mitk::ExtendedToftsModel::ParametersSizeType mitk::ExtendedToftsModel::GetNumberOfParameters() const { return NUMBER_OF_PARAMETERS; } mitk::ExtendedToftsModel::ParamterUnitMapType mitk::ExtendedToftsModel::GetParameterUnits() const { ParamterUnitMapType result; result.insert(std::make_pair(NAME_PARAMETER_Ktrans, UNIT_PARAMETER_Ktrans)); result.insert(std::make_pair(NAME_PARAMETER_vp, UNIT_PARAMETER_vp)); result.insert(std::make_pair(NAME_PARAMETER_ve, UNIT_PARAMETER_ve)); return result; }; mitk::ExtendedToftsModel::ParameterNamesType mitk::ExtendedToftsModel::GetDerivedParameterNames() const { ParameterNamesType result; result.push_back("kep"); return result; }; mitk::ExtendedToftsModel::ParametersSizeType mitk::ExtendedToftsModel::GetNumberOfDerivedParameters() const { return 1; }; mitk::ExtendedToftsModel::ParamterUnitMapType mitk::ExtendedToftsModel::GetDerivedParameterUnits() const { ParamterUnitMapType result; result.insert(std::make_pair("kep", "1/min")); return result; }; mitk::ExtendedToftsModel::ModelResultType mitk::ExtendedToftsModel::ComputeModelfunction( const ParametersType& parameters) const { if (this->m_TimeGrid.GetSize() == 0) { itkExceptionMacro("No Time Grid Set! Cannot Calculate Signal"); } AterialInputFunctionType aterialInputFunction; aterialInputFunction = GetAterialInputFunction(this->m_TimeGrid); unsigned int timeSteps = this->m_TimeGrid.GetSize(); //Model Parameters double ktrans = parameters[POSITION_PARAMETER_Ktrans] / 6000.0; double ve = parameters[POSITION_PARAMETER_ve]; double vp = parameters[POSITION_PARAMETER_vp]; + if (ve == 0.0) + { + itkExceptionMacro("ve is 0! Cannot calculate signal"); + } + double lambda = ktrans / ve; mitk::ModelBase::ModelResultType convolution = mitk::convoluteAIFWithExponential(this->m_TimeGrid, aterialInputFunction, lambda); //Signal that will be returned by ComputeModelFunction mitk::ModelBase::ModelResultType signal(timeSteps); signal.fill(0.0); mitk::ModelBase::ModelResultType::iterator signalPos = signal.begin(); mitk::ModelBase::ModelResultType::const_iterator res = convolution.begin(); for (AterialInputFunctionType::iterator Cp = aterialInputFunction.begin(); Cp != aterialInputFunction.end(); ++res, ++signalPos, ++Cp) { *signalPos = (*Cp) * vp + ktrans * (*res); } return signal; } mitk::ModelBase::DerivedParameterMapType mitk::ExtendedToftsModel::ComputeDerivedParameters( const mitk::ModelBase::ParametersType& parameters) const { DerivedParameterMapType result; double kep = parameters[POSITION_PARAMETER_Ktrans] / parameters[POSITION_PARAMETER_ve]; result.insert(std::make_pair("kep", kep)); return result; }; itk::LightObject::Pointer mitk::ExtendedToftsModel::InternalClone() const { ExtendedToftsModel::Pointer newClone = ExtendedToftsModel::New(); newClone->SetTimeGrid(this->m_TimeGrid); return newClone.GetPointer(); }; void mitk::ExtendedToftsModel::PrintSelf(std::ostream& os, ::itk::Indent indent) const { Superclass::PrintSelf(os, indent); }; diff --git a/Modules/Pharmacokinetics/test/files.cmake b/Modules/Pharmacokinetics/test/files.cmake index 7667169492..d6ce07a366 100644 --- a/Modules/Pharmacokinetics/test/files.cmake +++ b/Modules/Pharmacokinetics/test/files.cmake @@ -1,6 +1,7 @@ SET(MODULE_TESTS mitkDescriptivePharmacokineticBrixModelTest.cpp + mitkStandardToftsModelTest.cpp #ConvertToConcentrationTest.cpp mitkTwoCompartmentExchangeModelTest.cpp mitkExtendedToftsModelTest.cpp ) diff --git a/Modules/Pharmacokinetics/test/mitkStandardToftsModelTest.cpp b/Modules/Pharmacokinetics/test/mitkStandardToftsModelTest.cpp new file mode 100644 index 0000000000..5b0c907166 --- /dev/null +++ b/Modules/Pharmacokinetics/test/mitkStandardToftsModelTest.cpp @@ -0,0 +1,162 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + +// Testing +#include "mitkTestingMacros.h" +#include "mitkTestFixture.h" + +//MITK includes +#include "mitkVector.h" +#include "mitkStandardToftsModel.h" +#include "mitkAIFBasedModelBase.h" + +class mitkStandardToftsModelTestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE(mitkStandardToftsModelTestSuite); + MITK_TEST(GetModelDisplayNameTest); + MITK_TEST(GetModelTypeTest); + MITK_TEST(GetParameterNamesTest); + MITK_TEST(GetNumberOfParametersTest); + MITK_TEST(GetParameterUnitsTest); + MITK_TEST(GetDerivedParameterNamesTest); + MITK_TEST(GetNumberOfDerivedParametersTest); + MITK_TEST(GetDerivedParameterUnitsTest); + MITK_TEST(ComputeModelfunctionTest); + MITK_TEST(ComputeDerivedParametersTest); + CPPUNIT_TEST_SUITE_END(); + +private: + mitk::StandardToftsModel::Pointer m_testmodel; + mitk::ModelBase::ModelResultType m_output; + mitk::ModelBase::DerivedParameterMapType m_derivedParameters; + +public: + void setUp() override + { + mitk::ModelBase::TimeGridType m_grid(22); + mitk::ModelBase::ParametersType m_testparameters(2); + mitk::AIFBasedModelBase::AterialInputFunctionType m_arterialInputFunction (22); + + m_testparameters[mitk::StandardToftsModel::POSITION_PARAMETER_Ktrans] = 35.0; + m_testparameters(mitk::StandardToftsModel::POSITION_PARAMETER_ve) = 0.5; + + for (int i = 0; i < 22; ++i) + { + // time grid in seconds, 14s between frames + m_grid[i] = (double)14 * i; + } + + // AIF from Weinmann, H. J., Laniado, M., and W.Mützel (1984). Pharmacokinetics of GD - DTPA / dimeglumine after intravenous injection into healthy volunteers. Phys Chem Phys Med NMR, 16(2) : 167–72. + int D = 1; + double a1 = 3.99; + double m1 = 0.144; + double a2 = 4.78; + double m2 = 0.0111; + for (int i = 0; i < 22; ++i) + { + if (i < 5) + m_arterialInputFunction[i] = 0; + else + m_arterialInputFunction[i] = D * (a1 * exp(-m1 * m_grid[i]) + a2 * exp(-m2 * m_grid[i])); + } + + m_testmodel = mitk::StandardToftsModel::New(); + m_testmodel->SetTimeGrid(m_grid); + m_testmodel->SetAterialInputFunctionValues(m_arterialInputFunction); + m_testmodel->SetAterialInputFunctionTimeGrid(m_grid); + + //ComputeModelfunction is called within GetSignal(), therefore no explicit testing of ComputeModelFunction() + m_output = m_testmodel->GetSignal(m_testparameters); + m_derivedParameters = m_testmodel->GetDerivedParameters(m_testparameters); + } + + void tearDown() override + { + m_testmodel = nullptr; + m_output.clear(); + m_derivedParameters.clear(); + } + + void GetModelDisplayNameTest() + { + m_testmodel->GetModelDisplayName(); + CPPUNIT_ASSERT_MESSAGE("Checking model display name.", m_testmodel->GetModelDisplayName() == "Standard Tofts Model"); + } + + + void GetModelTypeTest() + { + CPPUNIT_ASSERT_MESSAGE("Checking model type.", m_testmodel->GetModelType() == "Perfusion.MR"); + } + + + void GetParameterNamesTest() + { + mitk::StandardToftsModel::ParameterNamesType parameterNames; + parameterNames.push_back("KTrans"); + parameterNames.push_back("ve"); + CPPUNIT_ASSERT_MESSAGE("Checking parameter names.", m_testmodel->GetParameterNames() == parameterNames); + } + + void GetNumberOfParametersTest() + { + CPPUNIT_ASSERT_MESSAGE("Checking number of parameters in model.", m_testmodel->GetNumberOfParameters() == 2); + } + + + void GetParameterUnitsTest() + { + mitk::StandardToftsModel::ParamterUnitMapType parameterUnits; + parameterUnits.insert(std::make_pair("KTrans", "ml/min/100ml")); + parameterUnits.insert(std::make_pair("ve", "ml/ml")); + + CPPUNIT_ASSERT_MESSAGE("Checking parameter units.", m_testmodel->GetParameterUnits() == parameterUnits); + } + + void GetDerivedParameterNamesTest() + { + mitk::StandardToftsModel::ParameterNamesType derivedParameterNames; + + derivedParameterNames.push_back("kep"); + + CPPUNIT_ASSERT_MESSAGE("Checking derived parameter names.", m_testmodel->GetDerivedParameterNames() == derivedParameterNames); + } + + void GetNumberOfDerivedParametersTest() + { + CPPUNIT_ASSERT_MESSAGE("Checking number of parameters in model.", m_testmodel->GetNumberOfDerivedParameters() == 1); + } + + void GetDerivedParameterUnitsTest() + { + mitk::StandardToftsModel::ParamterUnitMapType derivedParameterUnits; + derivedParameterUnits.insert(std::make_pair("kep", "1/min")); + + CPPUNIT_ASSERT_MESSAGE("Checking parameter units.", m_testmodel->GetDerivedParameterUnits() == derivedParameterUnits); + } + + void ComputeModelfunctionTest() + { + CPPUNIT_ASSERT_MESSAGE("Checking signal at time frame 0.", mitk::Equal(0.0, m_output[0], 1e-6, true) == true); + CPPUNIT_ASSERT_MESSAGE("Checking signal at time frame 5.", mitk::Equal(0.085056, m_output[5], 1e-6, true) == true); + CPPUNIT_ASSERT_MESSAGE("Checking signal at time frame 10.", mitk::Equal(0.442948, m_output[10], 1e-6, true) == true); + CPPUNIT_ASSERT_MESSAGE("Checking signal at time frame 20.", mitk::Equal(0.254551, m_output[20], 1e-6, true) == true); + } + + void ComputeDerivedParametersTest() + { + CPPUNIT_ASSERT_MESSAGE("Checking kep.", mitk::Equal(70.0, m_derivedParameters["kep"], 1e-6, true) == true); + } + +}; + +MITK_TEST_SUITE_REGISTRATION(mitkStandardToftsModel)