Medical Imaging Interaction Toolkit  2026.06.00
Medical Imaging Interaction Toolkit
mitkModelTestFixture.h
Go to the documentation of this file.
1 /*============================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
19 #ifndef mitkModelTestFixture_h
20 #define mitkModelTestFixture_h
21 
22 
23 #include <mitkTestingMacros.h>
24 #include <mitkTestingConfig.h>
25 #include <mitkTestFixture.h>
26 #include <itksys/SystemTools.hxx>
27 #include <mitkModelBase.h>
28 #include <mitkModelFitException.h>
29 
30 #include <nlohmann/json.hpp>
31 #include <iostream>
32 #include <fstream>
33 #include <mitkVector.h>
34 
36 
37 namespace mitk
38 {
56  {
57  public:
64  static json ParseJSONFile(const std::string path)
65  {
66  std::string pathToFile = GetTestDataFilePath(path);
67  std::ifstream file(pathToFile);
68  json json_obj;
69  if (!file.is_open())
70  {
71  MITK_ERROR << "Could not open \"" << pathToFile << "\"!";
72  }
73  try
74  {
75  json_obj = nlohmann::json::parse(file);
76  }
77  catch (const json::exception& e)
78  {
79  MITK_ERROR << "Could not parse JSON file!";
80  }
81  return json_obj;
82  }
83 
93  static ModelBase::ParametersType ParseTestParameters(const json modelValues_json_obj)
94  {
95  ModelBase::ParametersType testparameters;
96  testparameters.SetSize(modelValues_json_obj["modelParameterValues"].size());
97  for (unsigned long i = 0; i < modelValues_json_obj["modelParameterValues"].size(); ++i)
98  {
99  testparameters[i] = modelValues_json_obj["modelParameterValues"][i];
100  }
101  return testparameters;
102  }
103 
111  static ModelBase::StaticParameterMapType ParseStaticParameters(const json profile_json_obj, const json modelValues_json_obj)
112  {
113  ModelBase::StaticParameterMapType staticParameterMap;
114  for (unsigned long i = 0; i < modelValues_json_obj["staticParameterValues"].size(); ++i)
115  {
116  ModelBase::StaticParameterValuesType staticParameterValues;
117  ModelBase::ParameterNameType staticParameterName;
118  staticParameterName = profile_json_obj["staticParameterNames"][i];
119  for (unsigned int j = 0; j < modelValues_json_obj["staticParameterValues"][i].size(); ++j)
120  {
121  staticParameterValues.push_back(modelValues_json_obj["staticParameterValues"][i][j]);
122  }
123  staticParameterMap.insert(std::make_pair(staticParameterName, staticParameterValues));
124  }
125  return staticParameterMap;
126  }
127 
135  static void SetStaticParametersForTest(mitk::ModelBase::Pointer testmodel, const json profile_json_obj, const json modelValues_json_obj)
136  {
137  mitk::ModelBase::StaticParameterMapType staticParameterMap;
138  staticParameterMap = ParseStaticParameters(profile_json_obj, modelValues_json_obj);
139  testmodel->SetStaticParameters(staticParameterMap);
140  }
141 
152  static void CompareModelAndReferenceProfile(const mitk::ModelBase::Pointer testmodel, const json profile_json_obj)
153  {
154  CPPUNIT_ASSERT_MESSAGE("Checking number of parameters in model.", testmodel->GetNumberOfParameters() == profile_json_obj["numberOfParameters"].get<unsigned int>());
155  for (unsigned long i = 0; i < profile_json_obj["numberOfParameters"]; i++)
156  {
157  CPPUNIT_ASSERT_MESSAGE("Checking parameter names.", testmodel->GetParameterNames()[i] == profile_json_obj["parameterNames"][i].get<std::string>());
158  CPPUNIT_ASSERT_MESSAGE("Checking parameter scales.", testmodel->GetParameterScales()[testmodel->GetParameterNames()[i]] == profile_json_obj["parameterScales"][i].get<double>());
159  CPPUNIT_ASSERT_MESSAGE("Checking parameter units.", testmodel->GetParameterUnits()[testmodel->GetParameterNames()[i]] == profile_json_obj["parameterUnits"][i].get<std::string>());
160  }
161  CPPUNIT_ASSERT_MESSAGE("Checking number of derived parameters in model.", testmodel->GetNumberOfDerivedParameters() == profile_json_obj["numberOfDerivedParameters"].get<unsigned int>());
162  for (unsigned long i = 0; i < profile_json_obj["numberOfDerivedParameters"]; i++)
163  {
164  CPPUNIT_ASSERT_MESSAGE("Checking derived parameter names.", testmodel->GetDerivedParameterNames()[i] == profile_json_obj["derivedParameterNames"][i].get<std::string>());
165  CPPUNIT_ASSERT_MESSAGE("Checking derived parameter scales.", testmodel->GetDerivedParameterScales()[testmodel->GetDerivedParameterNames()[i]] == profile_json_obj["derivedParameterScales"][i].get<double>());
166  CPPUNIT_ASSERT_MESSAGE("Checking derived parameter units.", testmodel->GetDerivedParameterUnits()[testmodel->GetDerivedParameterNames()[i]] == profile_json_obj["derivedParameterUnits"][i].get<std::string>());
167  }
168  CPPUNIT_ASSERT_MESSAGE("Checking number of static parameters in model.", testmodel->GetNumberOfStaticParameters() == profile_json_obj["numberOfStaticParameters"].get<unsigned int>());
169  for (unsigned long i = 0; i < profile_json_obj["numberOfStaticParameters"]; i++)
170  {
171  CPPUNIT_ASSERT_MESSAGE("Checking static parameter names.", testmodel->GetStaticParameterNames()[i] == profile_json_obj["staticParameterNames"][i].get<std::string>());
172  CPPUNIT_ASSERT_MESSAGE("Checking static parameter units.", testmodel->GetStaticParameterUnits()[testmodel->GetStaticParameterNames()[i]] == profile_json_obj["staticParameterUnits"][i].get<std::string>());
173  }
174  CPPUNIT_ASSERT_MESSAGE("Checking function string.", testmodel->GetFunctionString() == profile_json_obj["functionString"].get<std::string>());
175  CPPUNIT_ASSERT_MESSAGE("Checking class ID.", testmodel->GetClassID() == profile_json_obj["classID"].get<std::string>());
176  CPPUNIT_ASSERT_MESSAGE("Checking model display name.", testmodel->GetModelDisplayName() == profile_json_obj["modelDisplayName"].get<std::string>());
177  CPPUNIT_ASSERT_MESSAGE("Checking model type.", testmodel->GetModelType() == profile_json_obj["modelType"].get<std::string>());
178  CPPUNIT_ASSERT_MESSAGE("Checking x name.", testmodel->GetXName() == profile_json_obj["xName"].get<std::string>());
179  CPPUNIT_ASSERT_MESSAGE("Checking x axis name.", testmodel->GetXAxisName() == profile_json_obj["xAxisName"].get<std::string>());
180  CPPUNIT_ASSERT_MESSAGE("Checking x axis unit.", testmodel->GetXAxisUnit() == profile_json_obj["xAxisUnit"].get<std::string>());
181  CPPUNIT_ASSERT_MESSAGE("Checking y axis name.", testmodel->GetYAxisName() == profile_json_obj["yAxisName"].get<std::string>());
182  CPPUNIT_ASSERT_MESSAGE("Checking y axis unit.", testmodel->GetYAxisUnit() == profile_json_obj["yAxisUnit"].get<std::string>());
183  }
184 
196  static void CompareModelAndReferenceSignal(mitk::ModelBase::Pointer testmodel, const json modelValues_json_obj, const json profile_json_obj)
197  {
198 
199  for (unsigned int j = 0; j < modelValues_json_obj["modelValues"].size(); j++)
200  {
201  json modelValues_json_obj_current = modelValues_json_obj["modelValues"][j];
202 
203  SetStaticParametersForTest(testmodel, profile_json_obj, modelValues_json_obj_current);
204 
205  // Set time grid
207  timeGrid.SetSize(modelValues_json_obj_current["timeGrid"].size());
208  for (unsigned long i = 0; i < modelValues_json_obj_current["timeGrid"].size(); ++i)
209  {
210  timeGrid[i] = modelValues_json_obj_current["timeGrid"][i];
211  }
212  testmodel->SetTimeGrid(timeGrid);
213 
214  // Parse test parameters
215  mitk::ModelBase::ParametersType testparameters;
216  testparameters = ParseTestParameters(modelValues_json_obj_current);
217 
218  //Generate signal
220  signal = testmodel->GetSignal(testparameters);
221 
222 
223  //ComputeModelfunction is called within GetSignal(), therefore no explicit testing of ComputeModelFunction()
224  // The reference signal has been calculated in a matlab script.
225  std::stringstream ss;
226  ss << "Checking signal for model parameter set " << j << ".";
227  std::string message = ss.str();
228  for (unsigned long i = 0; i < signal.size(); i++)
229  {
230  CPPUNIT_ASSERT_MESSAGE(message, mitk::Equal(signal[i], modelValues_json_obj_current["signal"][i], 1e-6, true) == true);
231  }
232  }
233  }
234 
245  static void CompareModelAndReferenceDerivedParameters(const mitk::ModelBase::Pointer testmodel, json modelValues_json_obj)
246  {
247  for (unsigned int j = 0; j < modelValues_json_obj["modelValues"].size(); j++)
248  {
249  json modelValues_json_obj_current = modelValues_json_obj["modelValues"][j];
250 
251  // Set time grid
253  timeGrid.SetSize(modelValues_json_obj_current["timeGrid"].size());
254  for (unsigned long i = 0; i < modelValues_json_obj_current["timeGrid"].size(); ++i)
255  {
256  timeGrid[i] = modelValues_json_obj_current["timeGrid"][i];
257  }
258  testmodel->SetTimeGrid(timeGrid);
259  mitk::ModelBase::ParametersType testparameters;
260  testparameters = mitk::mitkModelTestFixture::ParseTestParameters(modelValues_json_obj_current);
261  mitk::ModelBase::DerivedParameterMapType derivedParameterMap;
262  derivedParameterMap = testmodel->GetDerivedParameters(testparameters);
263  std::stringstream ss;
264  ss << "Checking derived parameters for model parameter set " << j << ".";
265  std::string message = ss.str();
266  for (unsigned long i = 0; i < modelValues_json_obj_current["derivedParameterValues"].size(); i++)
267  {
268  CPPUNIT_ASSERT_MESSAGE(message, mitk::Equal(derivedParameterMap[testmodel->GetDerivedParameterNames()[i]], modelValues_json_obj_current["derivedParameterValues"][i], 1e-6, true) == true);
269  }
270  }
271  }
272  };
273 }
274 #endif // mitkModelTestFixture_h
std::map< ParameterNameType, DerivedParameterValueType > DerivedParameterMapType
Definition: mitkModelBase.h:83
std::map< ParameterNameType, StaticParameterValuesType > StaticParameterMapType
Definition: mitkModelBase.h:80
std::vector< StaticParameterValueType > StaticParameterValuesType
Definition: mitkModelBase.h:79
ModelTraitsInterface::ParameterNameType ParameterNameType
Definition: mitkModelBase.h:71
ModelTraitsInterface::ModelResultType ModelResultType
Definition: mitkModelBase.h:63
itk::Array< double > TimeGridType
Type defining the time grid used by models.
Definition: mitkModelBase.h:70
ModelTraitsInterface::ParametersType ParametersType
Definition: mitkModelBase.h:67
Test fixture for parameterized tests.
static std::string GetTestDataFilePath(const std::string &testData)
Get the absolute path for test data.
Test fixture base class for model fit unit tests.
static ModelBase::StaticParameterMapType ParseStaticParameters(const json profile_json_obj, const json modelValues_json_obj)
Parse static parameter names and values from JSON into a StaticParameterMapType.
static ModelBase::ParametersType ParseTestParameters(const json modelValues_json_obj)
Extract model parameter values from a JSON object into a ParametersType array.
static void CompareModelAndReferenceDerivedParameters(const mitk::ModelBase::Pointer testmodel, json modelValues_json_obj)
Assert that a model's derived parameters match a JSON reference for all parameter sets.
static void CompareModelAndReferenceSignal(mitk::ModelBase::Pointer testmodel, const json modelValues_json_obj, const json profile_json_obj)
Assert that a model's computed signal matches a JSON reference for all parameter sets.
static void CompareModelAndReferenceProfile(const mitk::ModelBase::Pointer testmodel, const json profile_json_obj)
Assert that a model's profile (parameter names, scales, units, etc.) matches a JSON reference.
static json ParseJSONFile(const std::string path)
Parse a JSON file from the test data directory.
static void SetStaticParametersForTest(mitk::ModelBase::Pointer testmodel, const json profile_json_obj, const json modelValues_json_obj)
Convenience method that parses static parameters from JSON and applies them to a model.
#define MITK_ERROR
Log an error message.
Definition: mitkLog.h:372
nlohmann::json json
Find image slices visible on a given plane.
MITKNEWMODULE_EXPORT bool Equal(mitk::ExampleDataStructure *leftHandSide, mitk::ExampleDataStructure *rightHandSide, mitk::ScalarType eps, bool verbose)
Returns true if the example data structures are considered equal.