CASToR  3.0
Tomographic Reconstruction (PET/SPECT/CT)
oArterialInputCurve.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 
30 #include "oArterialInputCurve.hh"
31 #include "sOutputManager.hh"
32 #include "gOptions.hh"
33 
34 // =====================================================================
35 // ---------------------------------------------------------------------
36 // ---------------------------------------------------------------------
37 // =====================================================================
38 /*
39  \fn oArterialInputCurve
40  \brief Constructor of oArterialInputCurve. Simply set all data members to default values.
41 */
42 
44 {
45 
46  m_pathToAICfile = "";
47  m_verbose = -1;
48 
50  mp_AICDataPoints = NULL;
51  mp_AICDataPointsTimes = NULL;
52 
53 
54  mp_AICIntrpY = NULL;
56 
57  m_nbTimeFrames = -1;
58  mp_frameTimeStartInMs = NULL;
59  mp_frameTimeStopInMs = NULL;
60 
61 }
62 
64 {
65 
68 
69  if (mp_AICIntrpY) delete(mp_AICIntrpY);
70 
71 }
72 
74 {
75  // Check that the provided sampled AIC covers the first frame
77  {
78  Cerr("***** oArterialInputCurve::CheckParameters() -> AIC datapoints need to start before the first frame " << endl);
79  return 1;
80  }
81  // Check if the provided sampled AIC covers the requested total reconstruction time ( last time point of last frame )
83  {
84  Cerr("***** oArterialInputCurve::CheckParameters() -> Requested reconstruction framing is longer than the provided AIC time points" << endl);
85  return 1;
86  }
87  // End
88  return 0;
89 }
90 
91 void oArterialInputCurve::SetFrames(int a_nbTimeFrames, uint32_t *a_frameTimeStartInMs, uint32_t *a_frameTimeStopInMs)
92 {
93  m_nbTimeFrames = a_nbTimeFrames;
94  mp_frameTimeStartInMs = a_frameTimeStartInMs;
95  mp_frameTimeStopInMs = a_frameTimeStopInMs;
96 }
97 
99 {
100 
101  if (m_verbose>=2) Cout("oArterialInputCurve::InitializeInputData() -> Initializing input from the provided Arterial Input Curve " << endl );
102 
103  // Read number of AIC data points
105  {
106  Cerr("***** oArterialInputCurve::InitializeInputData() -> Error while reading number of data points from AIC file )" << endl);
107  return 1;
108  }
109 
110  // Allocate memory for data points
112  mp_AICDataPointsTimes = (uint32_t*) malloc(m_nbinputDataPoints*sizeof(uint32_t));
113  FLTNB* input_time_points_FLTNB = (FLTNB*) malloc(m_nbinputDataPoints*sizeof(FLTNB));
114 
115 
116  // Populate arrays with data from AIC file
118  {
119  Cerr( "***** oArterialInputCurve::InitializeInputData() -> Error while trying to read Data points from AIC file: " << m_pathToAICfile << endl);
120  return 1;
121  }
122  if ( ReadDataASCIIFile(m_pathToAICfile, "AIC_time_points", input_time_points_FLTNB, m_nbinputDataPoints , KEYWORD_MANDATORY) )
123  {
124  Cerr("***** oArterialInputCurve::InitializeInputData() -> Error while trying to read Time Data points from AIC file: " << m_pathToAICfile << endl);
125  return 1;
126  }
127 
128  // Get Units from file
129  string Units = "";
130  ReadDataASCIIFile(m_pathToAICfile, "AIC_units", &Units,1, KEYWORD_OPTIONAL);
131 
132  bool time_points_inMinutes = false;
133 
134  if (Units=="minutes" || Units=="Minutes")
135  {
136  time_points_inMinutes = true ;
137  }
138 
139  // Case of Time points provided in minutes
140  if (time_points_inMinutes)
141  {
142  // Convert all time points from minutes to milliseconds and cast into the uint32_t variable
143  for (int i=0;i<m_nbinputDataPoints;i++) { mp_AICDataPointsTimes[i] = (uint32_t) (input_time_points_FLTNB[i]*60000);}
144  }
145  // Else case of time points provided in seconds
146  else
147  {
148  // Convert all time points from seconds to milliseconds and cast into the uint32_t variable
149  for (int i = 0; i < m_nbinputDataPoints; i++) { mp_AICDataPointsTimes[i] = (uint32_t) (input_time_points_FLTNB[i]*1000);}
150  }
151 
152  // delete temporary array
153  delete (input_time_points_FLTNB);
154 
155  // Print time points
156 
157  if (m_verbose>=3)
158  {
159  Cout("oArterialInputCurve::InitializeInputData() -> Printing input Data \n Time(ms),Datapoint (Bq/ml) " << endl );
160  for (int i = 0; i < m_nbinputDataPoints; i++)
161  {
162  Cout (mp_AICDataPointsTimes[i] << ", " << mp_AICDataPoints [i]<< endl);
163  }
164  }
165  // End
166  return 0;
167 }
168 
170 {
171  // Creating variables for storing the slopes and intercepts between each pair of datapoints
172  HPFLTNB* slopes = (HPFLTNB*) malloc((m_nbinputDataPoints-1) * sizeof(HPFLTNB));
173  HPFLTNB* intercepts = (HPFLTNB*) malloc((m_nbinputDataPoints-1) * sizeof(HPFLTNB));
174 
175  // Allocating memory for the interpolated data values ( one for each discrete unit -> 1 millisecond )
176  // Only calculating and storing the interpolated values until the end of the last frame
178 
179  // Calculating slopes and intercepts for each pair & interpolate for every millisecond value
180  for (int i=0;i<(m_nbinputDataPoints-1);i++)
181  {
182  // m = (y2-y1)/(x2-x1)
183  slopes[i] = (mp_AICDataPoints[i + 1] - mp_AICDataPoints[i]) / ((HPFLTNB) (mp_AICDataPointsTimes[i + 1] - mp_AICDataPointsTimes[i]));
184  //b = (-1)*(m)*(x2)+y2
185  intercepts[i] = -1 * slopes[i] * ((HPFLTNB)(mp_AICDataPointsTimes[i + 1])) + mp_AICDataPoints[i + 1];
186 
187  // Calculate the interpolated values for the evaluated data-pair and populate mp_AICIntrpY
188  // If first data point is within the range proceed
190  {
191  // Check if second data point is also within the range
193  {
194  // Populate the whole range with interpolated values
195  for (uint32_t k = mp_AICDataPointsTimes[i]; k < mp_AICDataPointsTimes[i + 1]; k++)
196  {
197  mp_AICIntrpY[k] = (HPFLTNB)k * slopes[i] + intercepts[i];
198  }
199  }
200  // if second data point is out of range , populate up until the last frame point
202  {
203  // Populate the whole range with interpolated values
204  for (uint32_t k = mp_AICDataPointsTimes[i]; k <= mp_frameTimeStopInMs[m_nbTimeFrames - 1]; k++)
205  {
206  mp_AICIntrpY[k] = (HPFLTNB)k * slopes[i] + intercepts[i];
207  }
208  }
209  }
210  }
211  // Report any negative values and set to zero
212  for (uint32_t k = 0; k <= mp_frameTimeStopInMs[m_nbTimeFrames - 1]; k++)
213  {
214  if ( mp_AICIntrpY[k] <0 )
215  {
216  mp_AICIntrpY[k] = 0 ;
217  Cout (" Negative interpolated AIF value detected at: " << k <<"ms --> setting AIF to zero" << endl);
218  }
219  }
220 
221  //Normal End
222  return 0;
223 }
224 
225 
226 // =====================================================================
227 // ---------------------------------------------------------------------
228 // ---------------------------------------------------------------------
229 // Downsampling of interpolated AIC for speeding-up convolution operations
230 // =====================================================================
232 {
233  // Number of total samples required
234  int total_samples = (int)(((float)mp_frameTimeStopInMs[m_nbTimeFrames-1]/1000.)*10);
235 
236  if (m_verbose>=3) Cout(" Downsampling to 100 msec time intervals " << endl);
237  // Allocate memory for downsampled AIC
238  mp_AICIntrpY_downsampled = (HPFLTNB*) malloc(total_samples*sizeof(HPFLTNB));
239  // Seting the index and the zero value (first data-point)
240  int index=0;
242  for (int i=1;i<=int(mp_frameTimeStopInMs[m_nbTimeFrames - 1]);i++)
243  {
244  // If exact division by 100 , datapoint is a 0.1 of a second -> set to downsampled datapoints
245  if (i%100==0)
246  {
247  index ++;
249  }
250  }
251  if (m_verbose>=3) Cout( " Downsampling complete to total # of points : " << index << endl);
252 
253  // Normal End
254  return 0;
255 }
int Downsample()
This function downsamples the interpolated arterial input function Currently needed to speed up convo...
#define FLTNB
Definition: gVariables.hh:81
oArterialInputCurve()
Constructor of oArterialInputCurve. Simply set all data members to default values.
#define HPFLTNB
Definition: gVariables.hh:83
int InterpolateAIC()
This function performs a linear interpolation within the provided AIC range for every discrete unit o...
#define Cerr(MESSAGE)
~oArterialInputCurve()
Destructor of oArterialInputCurve. Free memory from all allocated tabs.
int ReadDataASCIIFile(const string &a_file, const string &a_keyword, T *ap_return, int a_nbElts, bool a_mandatoryFlag)
Look for "a_nbElts" elts in the "a_file" file matching the "a_keyword" string passed as parameter a...
Definition: gOptions.cc:129
int InitializeInputData()
This function is used to initialize the input arterial curve samples from the file provided by the us...
Declaration of class oArterialInputCurve.
#define KEYWORD_MANDATORY
Definition: gOptions.hh:47
#define KEYWORD_OPTIONAL
Definition: gOptions.hh:49
Declaration of class sOutputManager.
void SetFrames(int a_nbTimeFrames, uint32_t *a_frameTimeStartInMs, uint32_t *a_frameTimeStopInMs)
Set the framing of the reconstruction for the AIC object.
This file is used for all kind of different functions designed for options parsing and ASCII file rea...
int CheckParameters()
This function is used to check that the required input parameters are provided from the file provided...
#define Cout(MESSAGE)