CASToR  3.1
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-2020 all CASToR contributors listed below:
18 
19  --> Didier BENOIT, Claude COMTAT, Marina FILIPOVIC, Thibaut MERLIN, Mael MILLARDET, Simon STUTE, Valentin VIELZEUF, Zacharias CHALAMPALAKIS
20 
21 This is CASToR version 3.1.
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 ShowHelpModelSpecific
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 << endl;
94  cout << " For ASCII file options: " << endl;
95  cout << " As this class inherits from the iLinearModel class, the following parameters must be declared inside the couple of the following specific tags: " << endl;
96  cout << " - DYNAMIC FRAMING/ENDDF " << endl;
97  cout << " - The ASCII file must contain the following keywords :" << endl;
98  cout << " 'Basis_functions:' (optional) Enter the coefficients of the Patlak basis functions for each time frame (tf) " << endl;
99  cout << " on two successive lines, separated by ',' :" << endl;
100  cout << " -> Patlak_functions: " << endl;
101  cout << " -> coeff_Pplot_tf1,coeff_Pplot_tf2,...,coeff_Pplot_tfn" << endl;
102  cout << " -> coeff_Pintc_tf1,coeff_Pintc_tf2,...,coeff_Pintc_tfn" << endl;
103  cout << endl;
104  cout << " 'AIC_input_file: path/to/file' (optional) As an alternative to direct input of the basis functions, the sampled Arterial Input Function can be given for " << endl;
105  cout << " estimation of the Patlak basis " << endl;
106  cout << " The file must contain the following information in successive lines, separated by ',' " << endl;
107  cout << " -> AIC_number_of_points: " << endl;
108  cout << " -> AIC_time_points: " << endl;
109  cout << " -> AIC_data_points: " << endl;
110  cout << " -> AIC_units: 'seconds' or 'minutes' " << endl;
111  cout << endl;
112  cout << " 'Parametric_image_init: path' (optional) path to an interfile image to be used as initialization for the parametric images." << endl;
113  cout << endl;
114  cout << " 'Optimisation_method:' x (mandatory) optimization method available options: " << endl;
115  cout << " x=0: Direct ( Implementation of basis functions side by system matrix within each tomographic iterative loop ) " << endl;
116  cout << " x=1: Nested EM " << endl;
117  cout << " x=2: Iterative non-negative Least-Square " << endl;
118  cout << " (C.L. Lawson and R.J. Hanson, Solving Least Squares Problems)" << endl;
119  cout << " x=3: Least-Squares linear regression " << endl;
120  cout << endl;
121  cout << " For command line list of options: " << endl;
122  cout << " The list of options must contain the coefficients of both Patlak functions separated by commas, with the following template :" << endl;
123  cout << " coeff_Pplot_tf1,coeff_Pplot_tf2,...,coeff_Pplot_tfn,";
124  cout << " coeff_Pintc_tf1,coeff_Pintc_tf2,...,coeff_Pintc_tfn "<< endl;
125  cout << " Default optimization method is Nested EM "<< endl;
126  cout << " Parametric images will be uniformly initialized with 0.001 and 1. for Patlak slope and intercept by default " << endl;
127  cout << " The parametric images estimations will be written on disk for each iteration" << endl;
128  cout << " " << endl;
129 
130  // Print general help for all dynamic models
131  ShowHelp();
132 
133 }
134 
135 
136 
137 
138 // =====================================================================
139 // ---------------------------------------------------------------------
140 // ---------------------------------------------------------------------
141 // =====================================================================
142 /*
143  \fn ReadAndCheckConfigurationFileSpecific
144  \param const string& a_configurationFile : ASCII file containing information about a dynamic model
145  \brief This function is used to read options from a configuration file.
146  \return 0 if success, other value otherwise.
147 */
149 {
150  if(m_verbose >=3) Cout("iLinearPatlakModel::ReadAndCheckConfigurationFileSpecific ..."<< endl);
151 
152  // Apply the generic linear parameter read for all Linear Models
154  {
155  Cerr("***** iLinearPatlakModel::ReadAndCheckConfigurationFileSpecific -> Error while trying to read configuration file for generic options of all linear models" << endl);
156  return 1;
157  }
158  // Normal End
159  return 0;
160 }
161 
162 
163 
164 
165 // =====================================================================
166 // ---------------------------------------------------------------------
167 // ---------------------------------------------------------------------
168 // =====================================================================
169 /*
170  \fn ReadAndCheckOptionsList
171  \brief This function is used to read parameters from a string.
172  \return 0 if success, other value otherwise.
173 */
175 {
176  if(m_verbose >=3) Cout("iLinearPatlakModel::ReadAndCheckOptionsList ..."<< endl);
177 
178  // Just recover the string here, it will be processed in the Initialize() function
179  m_listOptions = a_listOptions;
180 
181  // Normal end
182  return 0;
183 }
184 
185 
186 // =====================================================================
187 // ---------------------------------------------------------------------
188 // ---------------------------------------------------------------------
189 // =====================================================================
190 /*
191  \fn CheckSpecificParameters
192  \brief This function is used to check whether all member variables
193  have been correctly initialized or not.
194  \return 0 if success, positive value otherwise.
195 */
197 {
198 
199  // Perform generic checks that apply for the Linear Models
201  {
202  Cerr("***** iLinearPatlakModel::CheckSpecificParameters -> A problem occurred while checking specific parameters ! " << endl);
203  return 1;
204  }
205 
206  // Normal end
207  return 0;
208 }
209 
210 
211 // =====================================================================
212 // ---------------------------------------------------------------------
213 // ---------------------------------------------------------------------
214 // =====================================================================
215 /*
216  \fn InitializeSpecific
217  \brief This function is used to initialize Patlak parametric images and basis functions
218  \return 0 if success, other value otherwise.
219 */
221 {
222  if(m_verbose >=2) Cout("iLinearPatlakModel::InitializeSpecific ..."<< endl);
223 
224  // Run generic Initialization for all Linear Models
226  {
227  Cerr("***** iLinearPatlakModel::InitializeSpecific() -> Error while performing generic initialisations for linear models !" << endl);
228  return 1;
229  }
230 
231  // Initialization with a list of options
232  if(m_listOptions != "")
233  {
234  // Default initialization : Nested-EM
236 
237  // We expect here the coefficients of the functions for each time point
238  // Patlak slope before Patlak intercept
239 
240  // Allocate memory to recover the elements in one tmp vector
241  FLTNB *p_coeffs = new FLTNB[m_nbTimeBF * mp_ID->GetNbTimeFrames()];
242 
243  // Read them
245  p_coeffs,
247  ",",
248  "Patlak model configuration"))
249  {
250  Cerr("***** iPatlakModel::Initialize() -> Failed to correctly read the list of parameters in command-line options !" << endl);
251  return 1;
252  }
253 
254  // Affect coeffs
255  for(int c=0 ; c<m_nbTimeBF * mp_ID->GetNbTimeFrames() ; c++)
256  {
257  int bf = int(c/mp_ID->GetNbTimeFrames()); // Patlak basis function index
258  int fr = int(c%mp_ID->GetNbTimeFrames()); // Frame index
259  m2p_nestedModelTimeBasisFunctions[ bf ][ fr ] = p_coeffs[ c ];
260  }
261 
262  // Delete the tmp vector
263  delete[] p_coeffs;
264  }
265 
266 
267  if (m_AICfileProvided)
268  {
269  if(m_verbose >=2) Cout("iLinearPatlakModel::Estimating Patlak basis functions ..."<< endl);
270  // Calculate the Patlak Basis functions and set the m2p_nestedModelTimeBasisFunctions --------------------------------------/
271  uint32_t* a_frameTimeStopInMs = mp_ID->GetFramesTimeStopArray(0);
272  uint32_t* a_frameTimeStartInMs = mp_ID->GetFramesTimeStartsArray(0);
273  int a_nbTimeFrames = mp_ID->GetNbTimeFrames();
274 
275  // Get pointer to interpolated Arterial Input Curve
277  // Calculation of the 'Patlak Time' integral in the discrete level with the trapezoidal method
278  // For uniform spacing that is $ \frac{\Delta T}{2} ( f(x_0) + \sum_{k=0}^{N-1} f(x_k) + f(x_N)) $
279  HPFLTNB* a_PatlakTAC = (HPFLTNB*)malloc((a_frameTimeStopInMs[a_nbTimeFrames-1])*sizeof(HPFLTNB));
280  HPFLTNB RunningSum = 0 ;
281  HPFLTNB halfDeltaT = (0.001/2);
282  // First value of integration over the AIC will be the first value of the AIC * DeltaT
283  a_PatlakTAC[0] = a_AICIntrpY[0] * 0.001;
284  // Then iterate though all the other points using the trapezoidal function for uniform spacing
285  for (uint32_t i=1 ;i<(a_frameTimeStopInMs[a_nbTimeFrames - 1]);i++)
286  {
287  RunningSum += a_AICIntrpY[i-1] ;
288  a_PatlakTAC[i] = (a_AICIntrpY[0] + 2 * RunningSum + a_AICIntrpY[i])*halfDeltaT ;
289  }
290 
291  // Allocate memory for the Patlak Basis functions
292  m2p_nestedModelTimeBasisFunctions = (FLTNB**)malloc(2*sizeof(FLTNB*));
293  // Setting initial values to 0
294  for (int tbf=0; tbf<2; tbf++) m2p_nestedModelTimeBasisFunctions[tbf] = (FLTNB*) calloc(a_nbTimeFrames,sizeof(FLTNB));
295 
296  // Calculate first basis function - Integration of Patlak time over each frame and division by duration-//
297  for (int fr = 0; fr < a_nbTimeFrames; fr++)
298  {
299  RunningSum = 0 ;
300  // iteration over all the datapoints within the frame
301  for (uint32_t i = a_frameTimeStartInMs[fr]+1 ;i <(a_frameTimeStopInMs[fr]);i++)
302  {
303  RunningSum+=a_PatlakTAC[i];
304  }
305  m2p_nestedModelTimeBasisFunctions[0][fr] = (FLTNB) ((a_PatlakTAC[a_frameTimeStartInMs[fr]] +
306  2 * RunningSum + a_PatlakTAC[a_frameTimeStopInMs[fr]])*halfDeltaT) ;
307  m2p_nestedModelTimeBasisFunctions[0][fr] /= ((FLTNB)(a_frameTimeStopInMs[fr] - a_frameTimeStartInMs[fr]))/1000;
308  }
309 
310  // Calculate second basis function - Average of interpolated AIC over each frame and division by duration-//
311  for (int fr = 0; fr < a_nbTimeFrames; fr++)
312  {
313  RunningSum = 0;
314  // iteration over all the datapoints within the frame
315  for (uint32_t i = a_frameTimeStartInMs[fr]+1; i < (a_frameTimeStopInMs[fr]); i++)
316  {
317  RunningSum += a_AICIntrpY[i];
318  }
319  m2p_nestedModelTimeBasisFunctions[1][fr] = (FLTNB) ((a_AICIntrpY[a_frameTimeStartInMs[fr]] +
320  2 * RunningSum + a_AICIntrpY[a_frameTimeStopInMs[fr]]) * halfDeltaT);
321  m2p_nestedModelTimeBasisFunctions[1][fr] /= ((FLTNB)(a_frameTimeStopInMs[fr] - a_frameTimeStartInMs[fr]))/1000;
322  }
323 
324  if ( a_PatlakTAC ) delete a_PatlakTAC;
325  // --------------------------------------------------------------------------------------------------------------/
326  }
327  else
328  {
329  // --- Default Initialization of time basis functions --- //
330  for(int v=0 ; v<mp_ID->GetNbVoxXYZ() ; v++)
331  {
332  m2p_parametricImages[0][v] = .001;
333  m2p_parametricImages[1][v] = 1.0;
334  }
335  }
336 
337  // Print the basis functions
339 
340  // Normal end
341  m_initialized = true;
342  return 0;
343 }
344 
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
void ShowHelp()
This function is used to print out general help about dynamic models.
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.
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.
void ShowHelpModelSpecific()
Print out specific help about the implementation of the Patlak model and its initialization.
#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.