CASToR  3.0
Tomographic Reconstruction (PET/SPECT/CT)
iLinearPatlakModel.cc
Go to the documentation of this file.
1 /*
2 This file is part of CASToR.
3 
4  CASToR is free software: you can redistribute it and/or modify it under the
5  terms of the GNU General Public License as published by the Free Software
6  Foundation, either version 3 of the License, or (at your option) any later
7  version.
8 
9  CASToR is distributed in the hope that it will be useful, but WITHOUT ANY
10  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12  details.
13 
14  You should have received a copy of the GNU General Public License along with
15  CASToR (in file GNU_GPL.TXT). If not, see <http://www.gnu.org/licenses/>.
16 
17 Copyright 2017-2019 all CASToR contributors listed below:
18 
19  --> Didier BENOIT, Claude COMTAT, Marina FILIPOVIC, Thibaut MERLIN, Mael MILLARDET, Simon STUTE, Valentin VIELZEUF
20 
21 This is CASToR version 3.0.
22 */
23 
31 #include "iLinearPatlakModel.hh"
32 
33 // =====================================================================
34 // ---------------------------------------------------------------------
35 // ---------------------------------------------------------------------
36 // =====================================================================
37 /*
38  \fn iLinearPatlakModel
39  \brief Constructor of iLinearPatlakModel. Simply set all data members to default values.
40 */
42 {
43  // Hard coded number as Patlak has always only two basis functions and hence nbModelParameters
44  m_nbTimeBF = 2;
45  m_nbModelParam = 2;
46  m_nnlsN = 2;
49 }
50 
51 
52 
53 
54 // =====================================================================
55 // ---------------------------------------------------------------------
56 // ---------------------------------------------------------------------
57 // =====================================================================
58 /*
59  \fn ~iLinearPatlakModel
60  \brief Destructor of iLinearPatlakModel
61 */
63 {
64  if(m_initialized)
65  {
66 
67  }
68 }
69 
70 
71 
72 
73 // =====================================================================
74 // ---------------------------------------------------------------------
75 // ---------------------------------------------------------------------
76 // =====================================================================
77 /*
78  \fn ShowHelp
79  \brief Print out specific help about the implementation of the Patlak
80  model and its initialization
81 */
83 {
84  cout << "-- This class implements the Patlak Reference Tissue Model : " << endl;
85  cout << "-- Patlak CS, Blasberg RG: Graphical evaluation of blood-to-brain transfer constants from multiple-time uptake data" << endl;
86  cout << "-- J Cereb Blood Flow Metab 1985, 5(4):5 84-590." << endl;
87  cout << "-- DOI http://dx.doi.org/10.1038/jcbfm.1985.87" << endl;
88  cout << "-- It is used to model radiotracers which follows as 2-tissue compartment model with irreversible trapping " << endl;
89  cout << "-- The Patlak temporal basis functions are composed of the Patlak slope (integral of the reference TAC from the injection time " << endl;
90  cout << " divided by the instantaneous reference activity), and intercept (reference tissue TAC) " << endl;
91  cout << endl;
92  cout << " It can be initialized using either an ASCII file or a list of option with the following keywords and information :" << endl;
93  cout << " As this class inherits from the iLinearModel class, the following parameters must be declared inside the couple of the following specific tags: " << endl;
94  cout << " - DYNAMIC FRAMING/ENDDF " << endl;
95  cout << " - The ASCII file must contain the following keywords :" << endl;
96  cout << " 'Basis_functions:' (mandatory) Enter the coefficients of Patlak plot and intercept for each time frame (tf) " << endl;
97  cout << " on two successive lines, separated by ',' :" << endl;
98  cout << " -> Patlak_functions: " << endl;
99  cout << " -> coeff_Pplot_tf1,coeff_Pplot_tf2,...,coeff_Pplot_tfn" << endl;
100  cout << " -> coeff_Pintc_tf1,coeff_Pintc_tf2,...,coeff_Pintc_tfn" << endl;
101  cout << " 'Parametric_image_init: path ' (optional) path to an interfile image to be used as initialization for the parametric images." << endl;
102  cout << " -> Optimisation_method : x (mandatory) optimization method available options: " << endl;
103  cout << " x=0: Direct ( Implementation of basis functions side by system matrix in each tomographic iterative loop " << endl;
104  cout << " x=1: Nested EM " << endl;
105  cout << " x=2: Iterative non-negative Least-Square " << endl;
106  cout << " (C.L. Lawson and R.J. Hanson, Solving Least Squares Problems)" << endl;
107  cout << " x=3: Least-Squares linear regression " << endl;
108  cout << endl;
109  cout << " - The list of options must contain the coefficients of both Patlak functions separated by commas, with the following template :" << endl;
110  cout << " coeff_Pplot_tf1,coeff_Pplot_tf2,...,coeff_Pplot_tfn,";
111  cout << " coeff_Pintc_tf1,coeff_Pintc_tf2,...,coeff_Pintc_tfn "<< endl;
112  cout << " Default optimization method is Nested EM "<< endl;
113  cout << " Parametric images will be uniformly initialized with 0.001 and 1. for Patlak slope and intercept by default " << endl;
114  cout << " The parametric images estimations will be written on disk for each iteration" << endl;
115  cout << " " << endl;
116  cout << " The following keywords are common to all dynamic models :" << endl;
117  cout << " 'AIC_input_file: path/to/file' : This option will enable the Creation of Patlak Basis functions for direct Patlak Reconstruction ( For nested recon look in -help-dynamic-model ) . " << endl;
118  cout << " Provide text file with the Arterial Input Curve data points and time points, in two different horizontal lines starting with " << endl;
119  cout << " 'AIC_time_points:'" << endl;
120  cout << " and " << endl;
121  cout << " 'AIC_data_points:' " << endl;
122  cout << " to indicate which dataset corresponds to each line. Values must be separated by commas." << endl;
123  cout << " Also provide a value of the total number of data points, on a new line starting with " << endl;
124  cout << " 'AIC_number_of_points:'" << endl;
125  cout << " 'Number of iterations before image update: x' Set a number 'x' of iteration to reach before using the model to generate the images at each frames/gates" << endl;
126  cout << " (Default x == 0) " << endl;
127  cout << " 'No image update: x' If set to 1, the reconstructed images for the next iteration/subset are not reestimated using the model" << endl;
128  cout << " (Default x == 0) (the code just performs standard independent reconstruction of each frames/gates) " << endl;
129  cout << " 'No parameters update: x' If set to 1, the parameters / functions of the model are not estimated with the image" << endl;
130  cout << " (Default x == 0) (this could be used to test The EstimateImageWithModel() function with specific user-provided parametric images) " << endl;
131  cout << " 'Save parametric images : x' Enable (1)/Disable(0) saving parametric images on disk" << endl;
132  cout << " (Default x == 1) " << endl;
133  cout << " 'Save blacklisted voxels images : x' Enable (1)/Disable(0) saving blacklisted voxels images on disk" << endl;
134  cout << " (Default x == 0) " << endl;
135 
136  cout << " " << endl;
137 }
138 
139 
140 
141 
142 // =====================================================================
143 // ---------------------------------------------------------------------
144 // ---------------------------------------------------------------------
145 // =====================================================================
146 /*
147  \fn ReadAndCheckConfigurationFileSpecific
148  \param const string& a_configurationFile : ASCII file containing information about a dynamic model
149  \brief This function is used to read options from a configuration file.
150  \return 0 if success, other value otherwise.
151 */
153 {
154  if(m_verbose >=3) Cout("iLinearPatlakModel::ReadAndCheckConfigurationFileSpecific ..."<< endl);
155 
156  // Apply the generic linear parameter read for all Linear Models
158  {
159  Cerr("***** iLinearPatlakModel::ReadAndCheckConfigurationFileSpecific -> Error while trying to read configuration file for generic options of all linear models" << endl);
160  return 1;
161  }
162  // Normal End
163  return 0;
164 }
165 
166 
167 
168 
169 // =====================================================================
170 // ---------------------------------------------------------------------
171 // ---------------------------------------------------------------------
172 // =====================================================================
173 /*
174  \fn ReadAndCheckOptionsList
175  \brief This function is used to read parameters from a string.
176  \return 0 if success, other value otherwise.
177 */
179 {
180  if(m_verbose >=3) Cout("iLinearPatlakModel::ReadAndCheckOptionsList ..."<< endl);
181 
182  // Just recover the string here, it will be processed in the Initialize() function
183  m_listOptions = a_listOptions;
184 
185  // Normal end
186  return 0;
187 }
188 
189 
190 // =====================================================================
191 // ---------------------------------------------------------------------
192 // ---------------------------------------------------------------------
193 // =====================================================================
194 /*
195  \fn CheckSpecificParameters
196  \brief This function is used to check whether all member variables
197  have been correctly initialized or not.
198  \return 0 if success, positive value otherwise.
199 */
201 {
202 
203  // Perform generic checks that apply for the Linear Models
205  {
206  Cerr("***** iLinearPatlakModel::CheckSpecificParameters -> A problem occurred while checking specific parameters ! " << endl);
207  return 1;
208  }
209 
210  // Normal end
211  return 0;
212 }
213 
214 
215 // =====================================================================
216 // ---------------------------------------------------------------------
217 // ---------------------------------------------------------------------
218 // =====================================================================
219 /*
220  \fn InitializeSpecific
221  \brief This function is used to initialize Patlak parametric images and basis functions
222  \return 0 if success, other value otherwise.
223 */
225 {
226  if(m_verbose >=2) Cout("iLinearPatlakModel::InitializeSpecific ..."<< endl);
227 
228  // Run generic Initialization for all Linear Models
230  {
231  Cerr("***** iLinearPatlakModel::InitializeSpecific() -> Error while performing generic initialisations for linear models !" << endl);
232  return 1;
233  }
234 
235  // Initialization with a list of options
236  if(m_listOptions != "")
237  {
238  // Default initialization : Nested-EM
240 
241  // We expect here the coefficients of the functions for each time point
242  // Patlak slope before Patlak intercept
243 
244  // Allocate memory to recover the elements in one tmp vector
245  FLTNB *p_coeffs = new FLTNB[m_nbTimeBF * mp_ID->GetNbTimeFrames()];
246 
247  // Read them
249  p_coeffs,
251  ",",
252  "Patlak model configuration"))
253  {
254  Cerr("***** iPatlakModel::Initialize() -> Failed to correctly read the list of parameters in command-line options !" << endl);
255  return 1;
256  }
257 
258  // Affect coeffs
259  for(int c=0 ; c<m_nbTimeBF * mp_ID->GetNbTimeFrames() ; c++)
260  {
261  int bf = int(c/mp_ID->GetNbTimeFrames()); // Patlak basis function index
262  int fr = int(c%mp_ID->GetNbTimeFrames()); // Frame index
263  m2p_nestedModelTimeBasisFunctions[ bf ][ fr ] = p_coeffs[ c ];
264  }
265 
266  // Delete the tmp vector
267  delete[] p_coeffs;
268  }
269 
270 
271  if (m_AICfileProvided)
272  {
273  if(m_verbose >=2) Cout("iLinearPatlakModel::Estimating Patlak basis functions ..."<< endl);
274  // Calculate the Patlak Basis functions and set the m2p_nestedModelTimeBasisFunctions --------------------------------------/
275  uint32_t* a_frameTimeStopInMs = mp_ID->GetFramesTimeStopArray(0);
276  uint32_t* a_frameTimeStartInMs = mp_ID->GetFramesTimeStartsArray(0);
277  int a_nbTimeFrames = mp_ID->GetNbTimeFrames();
278 
279  // Get pointer to interpolated Arterial Input Curve
281  // Calculation of the 'Patlak Time' integral in the discrete level with the trapezoidal method
282  // For uniform spacing that is $ \frac{\Delta T}{2} ( f(x_0) + \sum_{k=0}^{N-1} f(x_k) + f(x_N)) $
283  HPFLTNB* a_PatlakTAC = (HPFLTNB*)malloc((a_frameTimeStopInMs[a_nbTimeFrames-1])*sizeof(HPFLTNB));
284  HPFLTNB RunningSum = 0 ;
285  HPFLTNB halfDeltaT = (0.001/2);
286  // First value of integration over the AIC will be the first value of the AIC * DeltaT
287  a_PatlakTAC[0] = a_AICIntrpY[0] * 0.001;
288  // Then iterate though all the other points using the trapezoidal function for uniform spacing
289  for (uint32_t i=1 ;i<(a_frameTimeStopInMs[a_nbTimeFrames - 1]);i++)
290  {
291  RunningSum += a_AICIntrpY[i-1] ;
292  a_PatlakTAC[i] = (a_AICIntrpY[0] + 2 * RunningSum + a_AICIntrpY[i])*halfDeltaT ;
293  }
294 
295  // Allocate memory for the Patlak Basis functions
296  m2p_nestedModelTimeBasisFunctions = (FLTNB**)malloc(2*sizeof(FLTNB*));
297  // Setting initial values to 0
298  for (int tbf=0; tbf<2; tbf++) m2p_nestedModelTimeBasisFunctions[tbf] = (FLTNB*) calloc(a_nbTimeFrames,sizeof(FLTNB));
299 
300  // Calculate first basis function - Integration of Patlak time over each frame and division by duration-//
301  for (int fr = 0; fr < a_nbTimeFrames; fr++)
302  {
303  RunningSum = 0 ;
304  // iteration over all the datapoints within the frame
305  for (uint32_t i = a_frameTimeStartInMs[fr]+1 ;i <(a_frameTimeStopInMs[fr]);i++)
306  {
307  RunningSum+=a_PatlakTAC[i];
308  }
309  m2p_nestedModelTimeBasisFunctions[0][fr] = (FLTNB) ((a_PatlakTAC[a_frameTimeStartInMs[fr]] +
310  2 * RunningSum + a_PatlakTAC[a_frameTimeStopInMs[fr]])*halfDeltaT) ;
311  m2p_nestedModelTimeBasisFunctions[0][fr] /= ((FLTNB)(a_frameTimeStopInMs[fr] - a_frameTimeStartInMs[fr]))/1000;
312  }
313 
314  // Calculate second basis function - Average of interpolated AIC over each frame and division by duration-//
315  for (int fr = 0; fr < a_nbTimeFrames; fr++)
316  {
317  RunningSum = 0;
318  // iteration over all the datapoints within the frame
319  for (uint32_t i = a_frameTimeStartInMs[fr]+1; i < (a_frameTimeStopInMs[fr]); i++)
320  {
321  RunningSum += a_AICIntrpY[i];
322  }
323  m2p_nestedModelTimeBasisFunctions[1][fr] = (FLTNB) ((a_AICIntrpY[a_frameTimeStartInMs[fr]] +
324  2 * RunningSum + a_AICIntrpY[a_frameTimeStopInMs[fr]]) * halfDeltaT);
325  m2p_nestedModelTimeBasisFunctions[1][fr] /= ((FLTNB)(a_frameTimeStopInMs[fr] - a_frameTimeStartInMs[fr]))/1000;
326  }
327 
328  if ( a_PatlakTAC ) delete a_PatlakTAC;
329  // --------------------------------------------------------------------------------------------------------------/
330  }
331  else
332  {
333  // --- Default Initialization of time basis functions --- //
334  for(int v=0 ; v<mp_ID->GetNbVoxXYZ() ; v++)
335  {
336  m2p_parametricImages[0][v] = .001;
337  m2p_parametricImages[1][v] = 1.0;
338  }
339  }
340 
341  // Print the basis functions
343 
344  // Normal end
345  m_initialized = true;
346  return 0;
347 }
348 
int m_OptimisationMethod
#define FLTNB
Definition: gVariables.hh:81
string m_listOptions
#define HPFLTNB
Definition: gVariables.hh:83
oArterialInputCurve * mp_ArterialInputCurve
uint16_t m_nnlsN
oImageDimensionsAndQuantification * mp_ID
int InitializeSpecificToAllLinearModels()
This function is used to initialize the parametric images and basis functions for all Linear Models...
int InitializeSpecific()
This function is used to initialize Patlak parametric images and basis functions. ...
This class implements a general linear dynamic model applied between the images of a dynamic acquisit...
Definition: iLinearModel.hh:62
Declaration of class iLinearPatlakModel.
void ShowBasisFunctions()
This function is used to print the basis functions.
#define Cerr(MESSAGE)
int CheckSpecificParametersForAllLinearModels()
This function is used to check parameters for all Linear Models. .
int ReadAndCheckConfigurationFileSpecific()
This function is used to read options from a configuration file.
FLTNB ** m2p_nestedModelTimeBasisFunctions
uint32_t * GetFramesTimeStartsArray(int a_bed)
Get the array of frame start times for a bed in Ms at uint32_t.
FLTNB ** m2p_parametricImages
~iLinearPatlakModel()
Destructor of iLinearPatlakModel.
void ShowHelp()
Print out specific help about the implementation of the Patlak model and its initialization.
int GetNbTimeFrames()
Get the number of time frames.
INTNB GetNbVoxXYZ()
Get the total number of voxels.
int ReadAndCheckOptionsList(string a_listOptions)
This function is used to read parameters from a string.
#define OPTIMISATION_METHOD_NESTEM
Definition: iLinearModel.hh:44
int CheckSpecificParameters()
This function is used to check whether all member variables have been correctly initialized or not...
iLinearPatlakModel()
Constructor of iLinearPatlakModel. Simply set all data members to default values. ...
#define Cout(MESSAGE)
int ReadAndCheckConfigurationFileSpecificToAllLinearModels()
This function is used to read parameters that are generic for all Linear Models. ...
int ReadStringOption(const string &a_input, T *ap_return, int a_nbElts, const string &sep, const string &a_option)
Parse the &#39;a_input&#39; string corresponding to the &#39;a_option&#39; into &#39;a_nbElts&#39; elements, using the &#39;sep&#39; separator. The results are returned in the templated &#39;ap_return&#39; dynamic templated array. Call "ConvertFromString()" to perform the correct conversion depending on the type of the data to convert.
Definition: gOptions.cc:50
HPFLTNB * GetInterpolatedAIC()
Set the framing of the reconstruction for the AIC object.