CASToR  1.1
Tomographic Reconstruction (PET/SPECT)
 All Classes Files Functions Variables Typedefs Macros Groups Pages
oSensitivityGenerator.cc
Go to the documentation of this file.
1 
2 /*
3  Implementation of class oSensitivityGenerator
4 
5  - separators:
6  - doxygen:
7  - default initialization:
8  - CASTOR_DEBUG:
9  - CASTOR_VERBOSE:
10 */
11 
18 #include "gVariables.hh"
19 #include "oSensitivityGenerator.hh"
20 #include "iDataFilePET.hh"
21 
22 // =====================================================================
23 // ---------------------------------------------------------------------
24 // ---------------------------------------------------------------------
25 // =====================================================================
26 
28 {
29  // Simply default all members to "empty" values
32  mp_ImageSpace = NULL;
33  mp_Scanner = NULL;
34  mp_ProjectorManager = NULL;
36  mp_DeformationManager = NULL;
37  m2p_DataFile = NULL;
45  m_mumapAttenuationFlag = false;
49  mp_lineCounter = NULL;
50  m_flagGPU = false;
51  m_verbose = -1;
52  m_checked = false;
53  m_initialized = false;
54 }
55 
56 // =====================================================================
57 // ---------------------------------------------------------------------
58 // ---------------------------------------------------------------------
59 // =====================================================================
60 
62 {
63  // Delete all normalization data files if any
65  {
66  for (int bed=0; bed<mp_ImageDimensionsAndQuantification->GetNbBeds(); bed++) if (m3p_NormalizationDataFile[bed])
67  {
68  for (int fr=0; fr<mp_ImageDimensionsAndQuantification->GetNbTimeFrames(); fr++)
69  if (m3p_NormalizationDataFile[bed][fr]) delete m3p_NormalizationDataFile[bed][fr];
70  free(m3p_NormalizationDataFile[bed]);
71  }
73  }
74  if (mp_lineCounter) free(mp_lineCounter);
75 }
76 
77 // =====================================================================
78 // ---------------------------------------------------------------------
79 // ---------------------------------------------------------------------
80 // =====================================================================
81 
83 {
84  // Check all mandatory parameters
86  {
87  Cerr("***** oSensitivityGenerator::CheckParameters() -> Image dimensions and quantification object is null !" << endl);
88  return 1;
89  }
90  if (mp_ImageSpace==NULL)
91  {
92  Cerr("***** oSensitivityGenerator::CheckParameters() -> Image space object is null !" << endl);
93  return 1;
94  }
95  if (mp_Scanner==NULL)
96  {
97  Cerr("***** oSensitivityGenerator::CheckParameters() -> Scanner object is null !" << endl);
98  return 1;
99  }
100  if (mp_ProjectorManager==NULL)
101  {
102  Cerr("***** oSensitivityGenerator::CheckParameters() -> Projector manager object is null !" << endl);
103  return 1;
104  }
105  if (mp_ImageConvolverManager==NULL)
106  {
107  Cerr("***** oSensitivityGenerator::CheckParameters() -> Convolver manager object is null !" << endl);
108  return 1;
109  }
110  if (mp_DeformationManager==NULL)
111  {
112  Cerr("***** oSensitivityGenerator::CheckParameters() -> Deformation manager object is null !" << endl);
113  return 1;
114  }
115  if (m2p_DataFile==NULL)
116  {
117  Cerr("***** oSensitivityGenerator::CheckParameters() -> Data file array is null !" << endl);
118  return 1;
119  }
120  for (int b=0; b<mp_ImageDimensionsAndQuantification->GetNbBeds(); b++)
121  {
122  if (m2p_DataFile[b]==NULL)
123  {
124  Cerr("***** oSensitivityGenerator::CheckParameters() -> Data file object for bed " << b+1 << " is null !" << endl);
125  return 1;
126  }
127  }
128  if (m_verbose<0)
129  {
130  Cerr("***** oSensitivityGenerator::CheckParameters() -> Verbose level is negative !" << endl);
131  return 1;
132  }
133  // If compute the sensitivity from a histogram datafile, then check if the datafile is actually an histogram
134  if (m_computeFromHistogramFlag && m2p_DataFile[0]->GetDataMode()!=MODE_HISTOGRAM)
135  {
136  Cerr("***** oSensitivityGenerator::CheckParameters() -> It was asked to compute global sensitivity from the provided datafile whereas it is not a histogram !" << endl);
137  return 1;
138  }
139  // Now it is checked
140  m_checked = true;
141  // End
142  return 0;
143 }
144 
145 // =====================================================================
146 // ---------------------------------------------------------------------
147 // ---------------------------------------------------------------------
148 // =====================================================================
149 
151 {
152  // First check that the parameters has been checked !
153  if (!m_checked)
154  {
155  Cerr("***** oSensitivityGenerator::Initialize() -> Must call the CheckParameters() function before initialization !" << endl);
156  return 1;
157  }
158  // Verbose
159  if (m_verbose>=2) Cout("oSensitivityGenerator::Initialize() -> Start initialization" << endl);
160  // For the moment, SPECT sensitivity is not implemented
161  if (m2p_DataFile[0]->GetDataType()==TYPE_SPECT)
162  {
163  Cerr("***** oSensitivityGenerator::Initialize() -> Sensitivity for SPECT not yet implemented !" << endl);
164  return 1;
165  }
166  // For the moment, PET sensitivity when using TOF is not possible, will soon be !
167  if (m2p_DataFile[0]->GetDataType()==TYPE_PET && (dynamic_cast<iDataFilePET*>(m2p_DataFile[0]))->GetTOFInfoFlag())
168  {
169  Cerr("***** oSensitivityGenerator::Initialize() -> Sensitivity for PET with TOF is not yet possible, will soon be !" << endl);
170  return 1;
171  }
172  // Initialization of normalization files:
173  // --> must be done before attenuation files, because attenuation can be inside the normalization data file
174  // --> is not done if sensitivity generated from the histogram datafile
176  {
177  Cerr("***** oSensitivityGenerator::Initialize() -> A problem occured while initializing the normalization data files !" << endl);
178  return 1;
179  }
180  // Initialization of attenuation related stuff: not done if sensitivity generated from the histogram datafile
182  {
183  Cerr("***** oSensitivityGenerator::Initialize() -> A problem occured while initializing the attenuation files !" << endl);
184  return 1;
185  }
186  // We want to know if we will need to forward project into the attenuation image, so here the full condition
187  if (
188  m_mumapAttenuationFlag && // 1. We must have an attenuation image that is loaded
189  m2p_DataFile[0]->GetDataType()==TYPE_PET && // 2. This is only for PET
190  ( m3p_NormalizationDataFile==NULL || // 3.1 There is no normalization data file (potentially including ACF)
191  !(dynamic_cast<iDataFilePET*>(m3p_NormalizationDataFile[0][0]))->GetAtnCorrectionFlag() ) // 3.2 OR the normalization data file does not contain ACF
192  )
193  {
194  // We use a specific boolean that says we need to forward project into the attenuation image
196  }
197  else
198  {
199  // Otherwise, we don't
201  }
202  // Allocate the backward image for multi-thread
204  // Create sensitivity image file name
205  sOutputManager* p_outputManager = sOutputManager::GetInstance();
206  m_pathToSensitivityImage = p_outputManager->GetPathName() + p_outputManager->GetBaseName() + "_sensitivity";
207  // Allocate line counters
208  mp_lineCounter = (uint64_t*)calloc(mp_ImageDimensionsAndQuantification->GetNbThreadsForProjection(),sizeof(uint64_t));
209  // End
210  return 0;
211 }
212 
213 // =====================================================================
214 // ---------------------------------------------------------------------
215 // ---------------------------------------------------------------------
216 // =====================================================================
217 
219 {
220  // TODO: check the consistency between all normalization files (atnflag, normfactor, etc)
221 
222  // If no normalization file name provided, then we will exit, but we do some checks before
223  if (mp_pathToNormalizationFileName.size()==0)
224  {
225  // If the ignore-normalization-correction-flag is on, then we can exit the function
227  // In PET, throw an error if normalization correction is in the datafile and is taken into account (only if the datafile is a list-mode)
228  if (m2p_DataFile[0]->GetDataType()==TYPE_PET && m2p_DataFile[0]->GetDataMode()==MODE_LIST)
229  {
230  // Cast the vDataFile into iDataFilePET
231  iDataFilePET* p_pet_file = (dynamic_cast<iDataFilePET*>(m2p_DataFile[0]));
232  // Check if the normalization data are in the file and we do not ignore it
233  if (p_pet_file->GetNormCorrectionFlag())
234  {
235  Cerr("***** oSensitivityGenerator::InitializeNormalizationFiles() -> Normalization correction is included in the data file while it is not in the sensitivity computation !" << endl);
236  return 1;
237  }
238  }
239  // We can exit now
240  return 0;
241  }
242 
243  // Verbose
244  if (m_verbose>=2) Cout("oSensitivityGenerator::InitializeNormalizationFiles() -> Initialize normalization files" << endl);
245 
246  // Check that the number of normalization files options is the same as the number of beds
248  {
249  // If only one is provided, then we assume that it is the same for all bed positions
251  // Otherwise, throw an error
252  else
253  {
254  Cerr("***** oSensitivityGenerator::InitializeNormalizationFiles() -> Number of normalization files options should be one or equal to the number of data files !" << endl);
255  return 1;
256  }
257  }
258 
259  // Allocate the normalization data files array for the bed positions
261 
262  // Get the scanner manager
263  sScannerManager* p_ScannerManager = sScannerManager::GetInstance();
264 
265  // Loop on the number of beds
266  for (int bed=0; bed<mp_ImageDimensionsAndQuantification->GetNbBeds(); bed++)
267  {
268  // --------------------------------------------------------------------------
269  // Step 0: When only one normalization file names is provided for all beds
270  // --------------------------------------------------------------------------
272  {
273  // If not the first bed
274  if (bed!=0)
275  {
276  // We copy the pointer of the first bed into this one
278  // And we continue the loop
279  continue;
280  }
281  }
282  // --------------------------------------------------------------------------
283  // Step 1: Get filenames and check consistency with number of beds and frames
284  // --------------------------------------------------------------------------
285  // We will get the normalization file names for this bed
286  vector<string> normalization_files;
287  // Compute the bed index associated to the file name; in case of reverse order, we change the index only for datafile management here
288  int bed_data_file_name_index = bed;
289  if (m_inverseDataFileOrderFlag) bed_data_file_name_index = mp_ImageDimensionsAndQuantification->GetNbBeds() - 1 - bed;
290  // Then we search for commas separating the file name associated to each frame
291  size_t comma = mp_pathToNormalizationFileName[bed_data_file_name_index].find_first_of(",");
292  // Loop to get all file names
293  while (comma!=string::npos)
294  {
295  // Get the file name before the comma
296  normalization_files.push_back(mp_pathToNormalizationFileName[bed_data_file_name_index].substr(0,comma));
297  // Remove this part from the collection of file names
298  mp_pathToNormalizationFileName[bed_data_file_name_index] = mp_pathToNormalizationFileName[bed_data_file_name_index].substr(comma+1);
299  // Search for the next comma
300  comma = mp_pathToNormalizationFileName[bed_data_file_name_index].find_first_of(",");
301  }
302  // Get the last file name
303  normalization_files.push_back(mp_pathToNormalizationFileName[bed_data_file_name_index]);
304  // If we have only one frame, then set the m_oneNormalizationFileForAllFrames to true right now
306  // Check that the number of file names found is equal to the number of frames
307  if (normalization_files.size()!=((size_t)(mp_ImageDimensionsAndQuantification->GetNbTimeFrames())))
308  {
309  // If only one is provided, then we assume that it is the same for all frames
310  if (normalization_files.size()==1) m_oneNormalizationFileForAllFrames = true;
311  // Otherwise, throw an error
312  else
313  {
314  Cerr("***** oSensitivityGenerator::InitializeNormalizationFiles() -> Number of normalization files for bed " << bed+1 << " should be one or equal to the number of frames !" << endl);
315  return 1;
316  }
317  }
318  // If this is the case, then check for previous beds that it was so
319  else if (bed!=0 && !m_oneNormalizationFileForAllFrames)
320  {
321  Cerr("***** oSensitivityGenerator::InitializeNormalizationFiles() -> If only one normalization file is provided for all frames, then it must be so for all beds !" << endl);
322  return 1;
323  }
324  // --------------------------------------------------------------------------
325  // Step 2: Create the normalization data file objects
326  // --------------------------------------------------------------------------
327  // Allocate the normalization data file array for the frames
329  // Loop on the number of frames
330  for (int fr=0; fr<mp_ImageDimensionsAndQuantification->GetNbTimeFrames(); fr++)
331  {
332  // If one normalization file for all frames
334  {
335  // Then, if not the first frame
336  if (fr!=0)
337  {
338  // We copy the pointer of the first frame into this one
340  // And we continue the loop
341  continue;
342  }
343  }
344  // Switch on the scanner type and create the specific data files
345  if (p_ScannerManager->GetScannerType() == SCANNER_PET) m3p_NormalizationDataFile[bed][fr] = new iDataFilePET();
346  else
347  {
348  Cerr("***** oSensitivityGenerator::InitializeNormalizationFiles() -> Unknown scanner type (" << p_ScannerManager->GetScannerType() << ") or not yet implemented !" << endl);
349  return 1;
350  }
351  m3p_NormalizationDataFile[bed][fr]->SetHeaderDataFileName(normalization_files[fr]);
352  m3p_NormalizationDataFile[bed][fr]->SetBedIndex(bed);
353  m3p_NormalizationDataFile[bed][fr]->SetPercentageLoad(m2p_DataFile[0]->GetPercentageLoad());
354  m3p_NormalizationDataFile[bed][fr]->SetVerbose(m2p_DataFile[0]->GetVerbose());
356  bool affect_quantification_flag = false;
357  if (m3p_NormalizationDataFile[bed][fr]->ReadInfoInHeader(affect_quantification_flag))
358  {
359  Cerr("***** oSensitivityGenerator::InitializeNormalizationFiles() -> A problem occurred during normalization datafile header reading !" << endl);
360  return 1;
361  }
363  {
364  Cerr("***** oSensitivityGenerator::InitializeNormalizationFiles() -> A problem occurred while checking normalization datafile parameters !" << endl);
365  return 1;
366  }
367  if (m3p_NormalizationDataFile[bed][fr]->ComputeSizeEvent())
368  {
369  Cerr("***** oSensitivityGenerator::InitializeNormalizationFiles() -> A problem occurred in normalization datafile event size computation !" << endl);
370  return 1;
371  }
372  if (m3p_NormalizationDataFile[bed][fr]->InitializeFile())
373  {
374  Cerr("***** oSensitivityGenerator::InitializeNormalizationFiles() -> A problem occurred in normalization datafile initialization !" << endl);
375  return 1;
376  }
377  if (m3p_NormalizationDataFile[bed][fr]->PrepareDataFile())
378  {
379  Cerr("***** oSensitivityGenerator::InitializeNormalizationFiles() -> A problem occured in normalization datafile preparation !" << endl);
380  return 1;
381  }
382  // Check that the normalization data mode is histogram or normalization
383  if (m3p_NormalizationDataFile[bed][fr]->GetDataMode()!=MODE_HISTOGRAM && m3p_NormalizationDataFile[bed][fr]->GetDataMode()!=MODE_NORMALIZATION)
384  {
385  Cerr("***** oSensitivityGenerator::InitializeNormalizationFiles() -> Normalization data file used for sensitivity computation must be either histogram or normalization mode !" << endl);
386  return 1;
387  }
388  }
389  }
390 
391  // End
392  return 0;
393 }
394 
395 // =====================================================================
396 // ---------------------------------------------------------------------
397 // ---------------------------------------------------------------------
398 // =====================================================================
399 
401 {
402  // If it is asked to ignore attenuation correction, then nothing to do
404 
405  // If attenuation image file name is empty, then we do some checks before
406  if (m_pathToAttenuationImage=="")
407  {
408  // Case for PET: if no normalization data file OR no ACF in the normalization data file
409  if (m2p_DataFile[0]->GetDataType()==TYPE_PET && (m3p_NormalizationDataFile==NULL || !(dynamic_cast<iDataFilePET*>(m3p_NormalizationDataFile[0][0]))->GetAtnCorrectionFlag()))
410  {
411  // Cast the vDataFile into iDataFilePET
412  iDataFilePET* p_pet_file = (dynamic_cast<iDataFilePET*>(m2p_DataFile[0]));
413  // Throw an error if attenuation correction is in the datafile (at this step we know we do not ignore it)
414  if (p_pet_file->GetAtnCorrectionFlag())
415  {
416  Cerr("***** oSensitivityGenerator::InitializeAttenuationFiles() -> Attenuation correction is included in the data file while it is not in the sensitivity computation !" << endl);
417  return 1;
418  }
419  }
420  // We can exit now
421  return 0;
422  }
423 
424  // In PET, if the ACF is already present in the normalization data file, then say it and ignore mumap
425  if (m2p_DataFile[0]->GetDataType()==TYPE_PET && m3p_NormalizationDataFile!=NULL && (dynamic_cast<iDataFilePET*>(m3p_NormalizationDataFile[0][0]))->GetAtnCorrectionFlag())
426  {
427  Cout("oSensitivityGenerator::InitializeAttenuationFiles() -> Ignore provided mumap and consider ACF provided in the normalization data file" << endl);
428  return 0;
429  }
430 
431  // Verbose
432  if (m_verbose>=2) Cout("oSensitivityGenerator::InitializeAttenuationFiles() -> Allocate and read attenuation images (assumed to be in cm-1)" << endl);
433 
434  // Allocate and read the attenuation image (this puts the image into the m4p_attenuation buffer of oImageSpace)
436  {
437  Cerr("***** oSensitivityGenerator::Initialize() -> A problem occured while initializing the attenuation image into the image space !" << endl);
438  return 1;
439  }
440 
441  // Allocate the foward image, where the attenuation will be copied and deformed if needed
443 
444  // Copy attenuation image into forward-image buffer
446 
447  // We do not need the m4p_attenuation buffer of oImageSpace anymore, so free it now
449 
450  // TODO: Think about adding a field in the attenuation header to specify if the attenuation images have the same spatial resolution as the
451  // scanner in use, in order to apply a smoothing on it. For the moment, we assume it has been done beforehand.
452 
453  // TODO: for the moment, we assume that the attenuation image is in cm-1, maybe use a header field to detect that and convert it
454  // automatically.
455 
456  // Put attenuation flag on
457  m_mumapAttenuationFlag = true;
458 
459  // End
460  return 0;
461 }
462 
463 // =====================================================================
464 // ---------------------------------------------------------------------
465 // ---------------------------------------------------------------------
466 // =====================================================================
467 
469 {
470  // Verbose
471  if (m_verbose>=1) Cout("oSensitivityGenerator::Launch() -> Start the sensitivity computation" << endl);
472  // Simply switches between the CPU and GPU versions
473  #ifdef CASTOR_GPU
474  if (m_flagGPU) return LaunchGPU();
475  else return LaunchCPU();
476  #else
477  return LaunchCPU();
478  #endif
479 }
480 
481 // =====================================================================
482 // ---------------------------------------------------------------------
483 // ---------------------------------------------------------------------
484 // =====================================================================
485 
487 {
488  // Loop on the bed positions
489  for (int bed=0; bed<mp_ImageDimensionsAndQuantification->GetNbBeds(); bed++)
490  {
491  // Reset line counters
493  // Apply the bed offset for this bed position
495  // Case where the computation is performed directly from the histogram datafile
497  {
499  {
500  Cerr("***** oSensitivityGenerator::LaunchCPU() -> A problem occured while computing the sensitivity using the histogram data file for bed " << bed+1 << " !" << endl);
501  return 1;
502  }
503  }
504  // If a normalization file is provided, then use them to iterate on the elements to be taken into account
505  else if (m3p_NormalizationDataFile!=NULL)
506  {
508  {
509  Cerr("***** oSensitivityGenerator::LaunchCPU() -> A problem occured while computing the sensitivity using the normalization file for bed " << bed+1 << " !" << endl);
510  return 1;
511  }
512  }
513  // Otherwise, use a generic method from the scanner elements
514  else
515  {
517  {
518  Cerr("***** oSensitivityGenerator::LaunchCPU() -> A problem occured while computing the sensitivity from scanner elements for bed " << bed+1 << " !" << endl);
519  return 1;
520  }
521  // Synchronize MPI processes here as the sensitivity computation from scanner elements has not MPI implementation yet
522  #ifdef CASTOR_MPI
523  MPI_Barrier(MPI_COMM_WORLD);
524  #endif
525  }
526  // Sum up the line counter into the first thread
528  // Verbose
529  if (m_verbose>=2) Cout(" --> Number of effectively projected lines: " << mp_lineCounter[0] << endl);
530  }
531  // Set the number of threads for image computations
532  #ifdef CASTOR_OMP
534  #endif
535  // Deallocate the forward image only if attenuation was used
537  // Reduce all results (merging parallel computation)
538  for (int fr=0 ; fr<mp_ImageDimensionsAndQuantification->GetNbTimeFrames() ; fr++)
539  for (int rg=0 ; rg<mp_ImageDimensionsAndQuantification->GetSensNbRespGates() ; rg++)
540  for (int cg=0 ; cg<mp_ImageDimensionsAndQuantification->GetSensNbCardGates() ; cg++)
541  {
542  // Merge parallel results into the backward image
543  int img_0 = 0;
544  mp_ImageSpace->ReduceBackwardImage(img_0, fr, rg, cg);
545  // Perform any deformations on the backward image
547  //mp_DeformationManager->ApplyDeformationForSensitivityGeneration(mp_ImageSpace, BACKWARD_DEFORMATION, 1, fr, rg, cg);
548  //mp_DeformationManager->ApplyDeformationForSensitivityGeneration(mp_ImageSpace, BACKWARD_DEFORMATION, 2, fr, rg, cg);
549  }
550  // Allocate sensitivity image
552  // Copy backward image to sensitivity image
554  // Deallocate backward image
556  // Apply PSF and save only for first instance
558  {
559  // Apply PSF if needed
561  // Save sensitivity image
563  }
564  // Deallocate sensitivity image
566  // End
567  return 0;
568 }
569 
570 // =====================================================================
571 // ---------------------------------------------------------------------
572 // ---------------------------------------------------------------------
573 // =====================================================================
574 
576 {
577  // For the moment, we restrict the validity of this function to non-gated data
579  {
580  Cerr("***** oSensitivityGenerator::ComputeSensitivityFromHistogramDataFile() -> Cannot compute sensitivity from histogram file with gating !" << endl);
581  return 1;
582  }
583 
584  // Verbose
585  if (m_verbose>=2)
586  {
587  if (mp_ImageDimensionsAndQuantification->GetNbBeds()>1) Cout("oSensitivityGenerator::ComputeSensitivityFromHistogramDataFile() -> Start computation for bed " << a_bed+1 << endl);
588  else Cout("oSensitivityGenerator::ComputeSensitivityFromHistogramDataFile() -> Start computation" << endl);
589  }
590 
591  // Initial clock
592  clock_t clock_start = clock();
593  time_t time_start = time(NULL);
594 
595  // In case a problem occurs in the parallel loop
596  bool problem = false;
597  // Set the number of threads for projections
598  #ifdef CASTOR_OMP
600  #endif
601 
602  // Get index start and stop
603  int64_t index_start = 0;
604  int64_t index_stop = 0;
605  m2p_DataFile[a_bed]->GetEventIndexStartAndStop(&index_start, &index_stop);
606  // Reset the file buffer range before launching the loop over the datafile (this is done only if the percentage load is under 100)
607  m2p_DataFile[a_bed]->ResetBufferRange();
608  // Reinitialize 4D gate indexes
610 
611  // Compute the last index that each thread will manage here (this is to know when it has finished reading the datafile).
612  // Note that everything here assumes a static scheduling with a chunck size of 1, so do not change that in the parallel loop below!
613  int64_t* p_last_index = (int64_t*)malloc(mp_ImageDimensionsAndQuantification->GetNbThreadsForProjection()*sizeof(int64_t));
615  {
616  int64_t loop_increment = 1;
617  int64_t increment_for_this_thread = loop_increment * mp_ImageDimensionsAndQuantification->GetNbThreadsForProjection();
618  int64_t index_start_for_this_thread = index_start + th * loop_increment;
619  int64_t nb_loop_pass_through = (index_stop - 1 - index_start_for_this_thread) / increment_for_this_thread;
620  p_last_index[th] = index_start_for_this_thread + nb_loop_pass_through * increment_for_this_thread;
621  }
622 
623  // Launch the loop on all events
624  int64_t index = 0, printing_index = 0;
625  #pragma omp parallel for private(index) schedule(static, 1)
626  for ( index = index_start ; index < index_stop ; index++)
627  {
628  // Get the thread index
629  int th = 0;
630  #ifdef CASTOR_OMP
631  th = omp_get_thread_num();
632  #endif
633  // Verbose
635  {
636  if (printing_index%1000==0)
637  {
638  int percent = ((int)( ((FLTNB)(index-index_start)) * 100. / ((FLTNB)(index_stop-index_start)) ));
639  cout << "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b "
640  << percent << " % " << flush;
641  }
642  printing_index++;
643  }
644  // Get the current event for that thread index
645  vEvent* event = m2p_DataFile[a_bed]->GetEventWithAscendingOrderAssumption(index, p_last_index[th], th);
646  if (event==NULL)
647  {
648  Cerr("***** oSensitivityGenerator::ComputeSensitivityFromHistogramDataFile() -> An error occured while getting the event from index "
649  << index << " (thread " << th << ") !" << endl);
650  // A problem was encountered
651  problem = true;
652  // We must continue here because we are inside an OpenMP loop
653  continue;
654  }
655  // Call the dynamic switch function that updates the current frame and gate numbers, and also detects involuntary patient motion
656  int dynamic_switch_value = mp_ImageDimensionsAndQuantification->DynamicSwitch(index, event->GetTimeInMs(), a_bed, th);
657  // If the DYNAMIC_SWITCH_CONTINUE is returned, then it means that we are not yet at the first frame
658  if (dynamic_switch_value==DYNAMIC_SWITCH_CONTINUE)
659  {
660  // Then we just skip this event
661  continue;
662  }
663  // Compute the projection line
665  if (line==NULL)
666  {
667  Cerr("***** oSensitivityGenerator::ComputeSensitivityFromHistogramDataFile() -> A problem occured while computing the projection line !" << endl);
668  // Specify that there was a problem
669  problem = true;
670  // We must continue here because we are inside an OpenMP loop
671  continue;
672  }
673  // Process this line
674  int no_resp_gate = 0;
675  int no_card_gate = 0;
676  if (line->NotEmptyLine() && ProcessThisLine(line, event, a_bed, mp_ImageDimensionsAndQuantification->GetCurrentTimeFrame(th), no_resp_gate, no_card_gate, th))
677  {
678  Cerr("***** oSensitivityGenerator::ComputeSensitivityFromHistogramDataFile() -> A problem occured while processing a line !" << endl);
679  }
680  }
681 
682  // Synchronize MPI processes
683  #ifdef CASTOR_MPI
684  MPI_Barrier(MPI_COMM_WORLD);
685  #endif
686 
687  // End of progression printing (do not log out with Cout here)
689  cout << "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"
690  << " --> 100 % " << endl;
691  // If a problem was encountered, then report it here
692  if (problem)
693  {
694  Cerr("***** oSensitivityGenerator::ComputeSensitivityFromHistogramDataFile() -> A problem occured inside the parallel loop over events !" << endl);
695  return 1;
696  }
697 
698  // Clock total
699  clock_t clock_stop = clock();
700  time_t time_stop = time(NULL);
702  Cout(" --> Time spent for sensitivity generation for bed " << a_bed+1 << " | User: " << time_stop-time_start
703  << " sec | CPU: " << (clock_stop-clock_start)/((FLTNB)CLOCKS_PER_SEC) << " sec" << endl);
704  else
705  Cout(" --> Time spent for sensitivity generation | User: " << time_stop-time_start
706  << " sec | CPU: " << (clock_stop-clock_start)/((FLTNB)CLOCKS_PER_SEC) << " sec" << endl);
707 
708  // End
709  return 0;
710 }
711 
712 // =====================================================================
713 // ---------------------------------------------------------------------
714 // ---------------------------------------------------------------------
715 // =====================================================================
716 
718 {
719  // Verbose
720  if (m_verbose>=2)
721  {
722  if (mp_ImageDimensionsAndQuantification->GetNbBeds()>1) Cout("oSensitivityGenerator::ComputeSensitivityFromNormalizationFile() -> Start computation for bed " << a_bed+1 << endl);
723  else Cout("oSensitivityGenerator::ComputeSensitivityFromNormalizationFile() -> Start computation" << endl);
724  }
725 
726  // Initial clock
727  clock_t clock_start = clock();
728  time_t time_start = time(NULL);
729 
730  // Loop on frames
731  for (int fr=0 ; fr<mp_ImageDimensionsAndQuantification->GetNbTimeFrames() ; fr++)
732  {
733  // Verbose
735  cout << " --> Processing frame " << fr+1 << endl;
736  // Loop on respiratory gates
737  for (int rg=0 ; rg<mp_ImageDimensionsAndQuantification->GetSensNbRespGates() ; rg++)
738  {
739  // Verbose
741  cout << " --> Processing respiratory gate " << rg+1 << endl;
742  // Loop on cardiac gates
743  for (int cg=0 ; cg<mp_ImageDimensionsAndQuantification->GetSensNbCardGates() ; cg++)
744  {
745  // Verbose
747  cout << " --> Processing cardiac gate " << cg+1 << endl;
748  // Perform any forward deformations on the forward image (only if attenuation is used)
750  {
752  //mp_DeformationManager->ApplyDeformationForSensitivityGeneration(mp_ImageSpace, FORWARD_DEFORMATION, DEF_CARD_MOT, fr, rg, cg);
753  // TODO: not sure that patient motion can be handle simply like this
754  //mp_DeformationManager->ApplyDeformationForSensitivityGeneration(mp_ImageSpace, FORWARD_DEFORMATION, DEF_IPAT_MOT, fr, rg, cg);
755  }
756  // Reset the file buffer range before launching the loop over the datafile (this is done only if the percentage load is under 100)
758  // In case a problem occurs in the parallel loop
759  bool problem = false;
760  // Set the number of threads for projections
761  #ifdef CASTOR_OMP
763  #endif
764 
765  // Get index start and stop
766  int64_t index_start = 0;
767  int64_t index_stop = 0;
768  m3p_NormalizationDataFile[a_bed][fr]->GetEventIndexStartAndStop(&index_start, &index_stop);
769 
770  // Compute the last index that each thread will manage here (this is to know when it has finished reading the datafile).
771  // Note that everything here assumes a static scheduling with a chunck size of 1, so do not change that in the parallel loop below!
772  int64_t* p_last_index = (int64_t*)malloc(mp_ImageDimensionsAndQuantification->GetNbThreadsForProjection()*sizeof(int64_t));
774  {
775  int64_t loop_increment = 1;
776  int64_t increment_for_this_thread = loop_increment * mp_ImageDimensionsAndQuantification->GetNbThreadsForProjection();
777  int64_t index_start_for_this_thread = index_start + th * loop_increment;
778  int64_t nb_loop_pass_through = (index_stop - 1 - index_start_for_this_thread) / increment_for_this_thread;
779  p_last_index[th] = index_start_for_this_thread + nb_loop_pass_through * increment_for_this_thread;
780  }
781 
782  // Launch the loop on all events
783  int64_t index = 0, printing_index = 0;
784  #pragma omp parallel for private(index) schedule(static, 1)
785  for ( index = index_start ; index < index_stop ; index++)
786  {
787  // Get the thread index
788  int th = 0;
789  #ifdef CASTOR_OMP
790  th = omp_get_thread_num();
791  #endif
792  // Verbose
794  {
795  if (printing_index%1000==0)
796  {
797  int percent = ((int)( ((FLTNB)(index-index_start)) * 100. / ((FLTNB)(index_stop-index_start)) ));
798  cout << "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b "
799  << percent << " % " << flush;
800  }
801  printing_index++;
802  }
803  // Get the current event for that thread index
804  vEvent* event = m3p_NormalizationDataFile[a_bed][fr]->GetEventWithAscendingOrderAssumption(index, p_last_index[th], th);
805  if (event==NULL)
806  {
807  Cerr("***** oSensitivityGenerator::ComputeSensitivityFromNormalizationFile() -> An error occured while getting the event from index "
808  << index << " (thread " << th << ") !" << endl);
809  // A problem was encountered
810  problem = true;
811  // We must continue here because we are inside an OpenMP loop
812  continue;
813  }
814  // Compute the projection line
816  if (line==NULL)
817  {
818  Cerr("***** oSensitivityGenerator::ComputeSensitivityFromNormalizationFile() -> A problem occured while computing the projection line !" << endl);
819  // Specify that there was a problem
820  problem = true;
821  // We must continue here because we are inside an OpenMP loop
822  continue;
823  }
824  // Process this line
825  if (line->NotEmptyLine() && ProcessThisLine(line, event, a_bed, fr, rg, cg, th))
826  {
827  Cerr("***** oSensitivityGenerator::ComputeSensitivityFromNormalizationFile() -> A problem occured while processing a line !" << endl);
828  }
829  }
830  // End of progression printing (do not log out with Cout here)
832  cout << "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"
833  << " --> 100 % " << endl;
834  // If a problem was encountered, then report it here
835  if (problem)
836  {
837  Cerr("***** oSensitivityGenerator::ComputeSensitivityFromNormalizationFile() -> A problem occured inside the parallel loop over events !" << endl);
838  return 1;
839  }
840  }
841  }
842  }
843 
844  // Clock total
845  clock_t clock_stop = clock();
846  time_t time_stop = time(NULL);
848  Cout(" --> Time spent for sensitivity generation for bed " << a_bed+1 << " | User: " << time_stop-time_start
849  << " sec | CPU: " << (clock_stop-clock_start)/((FLTNB)CLOCKS_PER_SEC) << " sec" << endl);
850  else
851  Cout(" --> Time spent for sensitivity generation | User: " << time_stop-time_start
852  << " sec | CPU: " << (clock_stop-clock_start)/((FLTNB)CLOCKS_PER_SEC) << " sec" << endl);
853 
854  // End
855  return 0;
856 }
857 
858 // =====================================================================
859 // ---------------------------------------------------------------------
860 // ---------------------------------------------------------------------
861 // =====================================================================
862 
864 {
865  // No MPI implementation for this function yet, so we exit if not the first instance
867 
868  // Verbose
869  if (m_verbose>=2)
870  {
871  if (mp_ImageDimensionsAndQuantification->GetNbBeds()>1) Cout("oSensitivityGenerator::ComputeSensitivityFromScanner() -> Start computation for bed " << a_bed+1 << endl);
872  else Cout("oSensitivityGenerator::ComputeSensitivityFromScanner() -> Start computation" << endl);
873  }
874 
875  // Get the scanner manager
876  sScannerManager* p_scannerManager = sScannerManager::GetInstance();
877 
878  // Total number of elements
879  int nb_total_elts = mp_Scanner->GetSystemNbElts();
880 
881  // Initial clock
882  clock_t clock_start = clock();
883  time_t time_start = time(NULL);
884 
885  // Initialize main loop start and stop values
886  int64_t main_loop_start_index = 0 ;
887  int64_t main_loop_stop_index = 0;
888 
889  // Check beforehand any issue with the loop start/stop values (not possible in the inner multithreaded loop)
890  if (p_scannerManager->PROJ_GetModalityStopValueMainLoop()>0) main_loop_stop_index = p_scannerManager->PROJ_GetModalityStopValueMainLoop();
891  else
892  {
893  Cerr("***** oSensitivityGenerator::ComputeSensitivityFromScanner() -> An error occured when trying to initialize main loop stop index !" << endl);
894  return 1;
895  }
896  if (p_scannerManager->PROJ_GetModalityStartValueInnerLoop(0)<=0)
897  {
898  Cerr("***** oSensitivityGenerator::ComputeSensitivityFromScanner() -> An error occured when trying to initialize inner loop start index !" << endl);
899  return 1;
900  }
901 
902  // Prepare pre-computed sums of events to avoid the exponential evolution of the percentage (for PET)
903  // TODO Perhaps replace this with a call to scannerManager for error management
904  int64_t* progression_elts_array = new int64_t[nb_total_elts*sizeof(int64_t)];
905  progression_elts_array[0] = 0;
906  for (int idx_elt=1 ; idx_elt<mp_Scanner->GetSystemNbElts() ; idx_elt++)
907  progression_elts_array[idx_elt] = progression_elts_array[idx_elt-1] + (mp_Scanner->GetSystemNbElts()-idx_elt);
908 
909  // Index for progression printing
910  uint64_t printing_index = 0;
911  uint64_t progression_index_total = p_scannerManager->PROJ_GetProgressionFinalValue()
915  // Loop on frames
916  for (int fr=0 ; fr<mp_ImageDimensionsAndQuantification->GetNbTimeFrames() ; fr++)
917  {
918  // Verbose
920  cout << " --> Processing frame " << fr+1 << endl;
921  // Loop on respiratory gates
922  for (int rg=0 ; rg<mp_ImageDimensionsAndQuantification->GetSensNbRespGates() ; rg++)
923  {
924  // Verbose
926  cout << " --> Processing respiratory gate " << rg+1 << endl;
927  // Loop on cardiac gates
928  for (int cg=0 ; cg<mp_ImageDimensionsAndQuantification->GetSensNbCardGates() ; cg++)
929  {
930  // Verbose
932  cout << " --> Processing cardiac gate " << cg+1 << endl;
933  // Perform any forward deformations on the forward image (only if attenuation is used)
935  {
937  //mp_DeformationManager->ApplyDeformationForSensitivityGeneration(mp_ImageSpace, FORWARD_DEFORMATION, 1, fr, rg, cg);
938  // TODO: not sure that patient motion can be handle simply like this
939  //mp_DeformationManager->ApplyDeformationForSensitivityGeneration(mp_ImageSpace, FORWARD_DEFORMATION, 2, fr, rg, cg);
940  }
941  // In case a problem occurs in the parallel loop
942  bool problem = false;
943  // Set the number of threads for projections
944  #ifdef CASTOR_OMP
946  #endif
947 
948  // Start the loop
949  int64_t idx_elt1;
950 
951  #pragma omp parallel for private(idx_elt1) schedule(static, 1)
952  for(idx_elt1=main_loop_start_index ; idx_elt1<main_loop_stop_index ; idx_elt1++)
953  {
954  // Get the thread index
955  int th = 0;
956  #ifdef CASTOR_OMP
957  th = omp_get_thread_num();
958  #endif
959 
960  // Initialize inner loop start and stop values
961  int64_t inner_loop_start_index = p_scannerManager->PROJ_GetModalityStartValueInnerLoop(idx_elt1) ;
962  int64_t inner_loop_stop_index = mp_Scanner->GetSystemNbElts();
963 
964  // Inner loop on scanner elements (idx_elt2) which are used to form LOR using the first scanner element (idx_elt1)
965  for (int64_t idx_elt2=inner_loop_start_index ; idx_elt2<inner_loop_stop_index ; idx_elt2++)
966  {
967  // Print progression (do not log out with Cout here)
968  if (th==0)
969  {
970  if (m_verbose>=2 && printing_index%10000==0)
971  {
972  int64_t progression_index_current = p_scannerManager->PROJ_GetCurrentProgression(idx_elt1, idx_elt2, progression_elts_array,
975  fr, rg, cg);
976  int64_t percent = (int64_t) (( ((FLTNB)progression_index_current)/((FLTNB)progression_index_total) ) * ((FLTNB)100));
977  cout << "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b "
978  << percent << " % ";
979  }
980  printing_index++;
981  }
982 
983  // Allocate an event using the iDataFile
984  vEvent* event = m2p_DataFile[a_bed]->PROJ_GenerateEvent(idx_elt1, idx_elt2, th);
985 
986  // Check from the scanner requirements that this LOR is allowed
987  if (!mp_Scanner->IsAvailableLOR(event->GetID1(0), event->GetID2(0))) continue;
988 
989  // Generate the projection event and compute the projection line
991  if (line==NULL)
992  {
993  Cerr("***** oSensitivityGenerator::ComputeSensitivityFromScanner() -> A problem occured while computing the projection line !" << endl);
994  // Specify that there was a problem
995  problem = true;
996  // We must continue here because we are inside an OpenMP loop
997  continue;
998  }
999 
1000  // Process this line
1001  if (line->NotEmptyLine() && ProcessThisLine(line, event, a_bed, fr, rg, cg, th))
1002  {
1003  Cerr("***** oSensitivityGenerator::ComputeSensitivityFromScanner() -> A problem occured while processing a line !" << endl);
1004  }
1005  }
1006  }
1007  // End of progression printing (do not log out with Cout here)
1009  cout << "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"
1010  << " --> 100 % " << endl;
1011  // If a problem was encountered, then report it here
1012  if (problem)
1013  {
1014  Cerr("***** oSensitivityGenerator::ComputeSensitivityFromScanner() -> A problem occured inside the parallel loop over events !" << endl);
1015  return 1;
1016  }
1017  }
1018  }
1019  }
1020  delete[] progression_elts_array;
1021 
1022  // Clock total
1023  clock_t clock_stop = clock();
1024  time_t time_stop = time(NULL);
1026  Cout(" --> Time spent for sensitivity generation for bed " << a_bed+1 << " | User: " << time_stop-time_start
1027  << " sec | CPU: " << (clock_stop-clock_start)/((FLTNB)CLOCKS_PER_SEC) << " sec" << endl);
1028  else
1029  Cout(" --> Time spent for sensitivity generation | User: " << time_stop-time_start
1030  << " sec | CPU: " << (clock_stop-clock_start)/((FLTNB)CLOCKS_PER_SEC) << " sec" << endl);
1031 
1032  // End
1033  return 0;
1034 }
1035 
1036 // =====================================================================
1037 // ---------------------------------------------------------------------
1038 // ---------------------------------------------------------------------
1039 // =====================================================================
1040 
1041 int oSensitivityGenerator::ProcessThisLine(oProjectionLine* ap_Line, vEvent* ap_Event, int a_bed, int a_frame, int a_respGate, int a_cardGate, int a_thread)
1042 {
1043  // ----------------------------------------------------------------------------------------------
1044  // Part 0: get the multiplicative corrections from the vEvent and the quantification factor
1045  // ----------------------------------------------------------------------------------------------
1046 
1047  // The multiplicative corrections from the vEvent can be:
1048  // 1: generated from vDataFile::GenerateEvent(), this will be a default value, so this will be 1.
1049  // 2: taken from the normalization data file, so this will be the normalization correction factor times the attenuation correction factor
1050  FLTNB multiplicative_factor = ap_Event->GetMultiplicativeCorrections();
1051  // If null, then skip this event
1052  if (multiplicative_factor<=0.) return 0;
1053  // Get the quantification factor
1054  FLTNB quantification_factor = mp_ImageDimensionsAndQuantification->GetQuantificationFactor(a_bed, a_frame, a_respGate, a_cardGate);
1055  // If null, then skip this event
1056  if (quantification_factor<=0.) return 0;
1057 
1058  // ----------------------------------------------------------------------------------------------
1059  // Part 1: deal with the attenuation forward projection for PET if any
1060  // ----------------------------------------------------------------------------------------------
1061 
1062  // The ACF
1063  FLTNB attenuation_correction_factor = 1.;
1064 
1065  // Do a forward projection only if the attenuation image was provided and the ACF was not included in the normalization data file
1067  {
1068  // Cumulative mu (in cm-1)
1069  FLTNB cumulative_mu = 0.;
1070  // Loop on TOF bins
1071  for (int b=0; b<ap_Line->GetNbTOFBins(); b++)
1072  {
1073  // Projection operation (the attenuation image in the m4p_forwardImage buffer of the oImageSpace)
1074  for (int vl=0 ; vl<ap_Line->GetCurrentNbVoxels(FORWARD, b) ; vl++)
1075  cumulative_mu += ap_Line->GetVoxelWeights(FORWARD, b, vl) * mp_ImageSpace->m4p_forwardImage[a_frame][a_respGate][a_cardGate][ap_Line->GetVoxelIndex(FORWARD, b,vl)];
1076  }
1077  // Update the ACF (converting the cumulative mu in mm-1)
1078  attenuation_correction_factor = max(((FLTNB)1.),exp(cumulative_mu*((FLTNB)0.1)));
1079  }
1080 
1081  // ----------------------------------------------------------------------------------------------
1082  // Part 2: back-projection of the LOR sensitivity
1083  // ----------------------------------------------------------------------------------------------
1084 
1085  // Compute the global sensitivity (calibration / (ACF * norm))
1086  FLTNB lor_sensitivity = 1. / (quantification_factor * attenuation_correction_factor * multiplicative_factor);
1087 
1088  // Loop on TOF bins
1089  for (int b=0; b<ap_Line->GetNbTOFBins(); b++)
1090  {
1091  // Backprojection operation into the backward image
1092  for (int vl=0 ; vl<ap_Line->GetCurrentNbVoxels(BACKWARD, b) ; vl++)
1093  mp_ImageSpace->m6p_backwardImage[0][a_thread][a_frame][a_respGate][a_cardGate][ap_Line->GetVoxelIndex(BACKWARD, b, vl)] += ap_Line->GetVoxelWeights(BACKWARD, b, vl)
1094  * lor_sensitivity;
1095  }
1096 
1097  // Increment line counters
1098  mp_lineCounter[a_thread]++;
1099 
1100  // End
1101  return 0;
1102 }
1103 
1104 // =====================================================================
1105 // ---------------------------------------------------------------------
1106 // ---------------------------------------------------------------------
1107 // =====================================================================
1108 
1110 {
1111  // Get the flag that says if we merge the dynamic files or not
1112  bool merge_dynamic_files = sOutputManager::GetInstance()->MergeDynImages();
1113  // If we merge dynamic file, or we are in a static case (no dynamic), we stay with the hdr extension
1117  merge_dynamic_files )
1118  return m_pathToSensitivityImage + ".hdr";
1119  else
1120  return m_pathToSensitivityImage + ".mhd";
1121 }
int ApplyDeformationForSensitivityGeneration(oImageSpace *ap_Image, int a_defDirection, int fr, int rg, int cg)
Apply deformations during the list-mode sensitivity image generation.
oImageConvolverManager * mp_ImageConvolverManager
FLTNB **** m4p_forwardImage
Definition: oImageSpace.hh:68
This class is designed to be a mother virtual class for Datafile.
Definition: vDataFile.hh:67
This header file is mainly used to declare some macro definitions and all includes needed from the st...
bool GetNormCorrectionFlag()
Simply return m_normCorrectionFlag.
oProjectorManager * mp_ProjectorManager
static sScannerManager * GetInstance()
Instanciate the singleton object and Initialize member variables if not already done, return a pointer to this object otherwise.
void GetEventIndexStartAndStop(int64_t *ap_indexStart, int64_t *ap_indexStop, int a_subsetNum=0, int a_NbSubsets=1)
Compute the index start and stop of the events loop with respect to the current subset and MPI size a...
Definition: vDataFile.cc:873
#define MODE_HISTOGRAM
Definition: vDataFile.hh:36
#define TYPE_PET
Definition: vDataFile.hh:51
int ProcessThisLine(oProjectionLine *ap_Line, vEvent *ap_Event, int a_bed, int a_frame, int a_respGate, int a_cardGate, int a_thread)
This function manages the computation of the sensitivity contribution of the projection line provided...
#define MODE_LIST
Definition: vDataFile.hh:34
int64_t PROJ_GetModalityStartValueInnerLoop(int64_t a_elt1)
Get the start value for the inner loop of analytic projection depending on the modality.
#define FLTNB
Definition: gVariables.hh:55
#define MODE_NORMALIZATION
Definition: vDataFile.hh:38
oSensitivityGenerator()
The constructor of oSensitivityGenerator.
int Initialize()
A public function used to initialize the sensitivity generator.
#define DYNAMIC_SWITCH_CONTINUE
int LMS_SaveSensitivityImage(const string &a_pathToSensitivityImage, oDeformationManager *ap_DeformationManager)
Call the interfile function to write the sensitivity image on disk.
vDataFile *** m3p_NormalizationDataFile
oDeformationManager * mp_DeformationManager
string GetPathToSensitivityImage()
This function return the path to the sensitivity image.
int64_t PROJ_GetProgressionFinalValue()
Get numerator value according to the modality to compute percent progression during the projection pr...
int DynamicSwitch(int64_t a_currentEventIndex, uint32_t a_currentTime, int a_bed, int a_th)
Call the eponym function from the oDynamicDataManager class using the member object.
void SetVerbose(int a_verboseLevel)
set verbosity
Definition: vDataFile.hh:394
bool GetIgnoreAttnCorrectionFlag()
Get the boolean that says if the attenuation correction is ignored or not.
~oSensitivityGenerator()
The destructor of oSensitivityGenerator.
int Launch()
A public function used to launch the sensitivity generator (compute the sensitivity image) ...
virtual FLTNB GetMultiplicativeCorrections()=0
This is a pure virtual function implemented in the child classes.
void LMS_InstantiateForwardImage()
Allocate memory for the forward image matrices (for list-mode sensitivity generation) ...
static sOutputManager * GetInstance()
Instanciate the singleton object and Initialize member variables if not already done, return a pointer to this object otherwise.
#define TYPE_SPECT
Definition: vDataFile.hh:53
#define SCANNER_PET
int InitAttenuationImage(const string &a_pathToAtnImage)
Memory allocation and initialisation for the attenuation image using either :
Definition: oImageSpace.cc:966
Declaration of class iDataFilePET.
bool GetIgnoreNormCorrectionFlag()
Get the boolean that says if the normalization correction is ignored or not.
INTNB GetVoxelIndex(int a_direction, int a_TOFBin, INTNB a_voxelInLine)
This function is used to get the contributing voxel index of the provided direction, TOF bin and voxel rank.
#define Cerr(MESSAGE)
const string & GetPathName()
FLTNB ****** m6p_backwardImage
Definition: oImageSpace.hh:75
Singleton class that manages output writing on disk (images, sinograms, etc). It also manages loggi...
int ComputeSensitivityFromNormalizationFile(int a_bed)
Launch the computation of the sensitivity image for this bed, based on normalization data files...
void LMS_DeallocateSensitivityImage()
Free memory for the sensitivity image matrices (for list-mode sensitivity generation) ...
int GetNbBeds()
Get the number of bed positions.
Singleton class that Instantiate and initialize the scanner object.
void ResetBufferRange()
Simply set the m_1stIdxArrayEvents and m_lastIdxArrayEvents to -1 only if the percentage load is stri...
Definition: vDataFile.cc:491
#define BACKWARD_DEFORMATION
Definition: vDeformation.hh:16
void ResetCurrentDynamicIndices()
Call the eponym function from the oDynamicDataManager class using the member object.
int GetSensNbRespGates()
call the eponym function from the oDynamicDataManager object
INTNB GetCurrentNbVoxels(int a_direction, int a_TOFBin)
This function is used to get the current number of contributing voxels to the line.
oProjectionLine * ComputeProjectionLine(vEvent *ap_Event, int a_th)
This function is used to compute system matrix elements from the associated projector or pre-computed...
FLTNB GetQuantificationFactor(int a_bed, int a_frame, int a_respGate, int a_cardGate)
Get the quantification factor corresponding to the provided bed, frame, respiratory and cardiac gates...
int InitializeAttenuationFiles()
Initialize the attenuation images provided for sensitivity computation.
void SetHeaderDataFileName(const string &a_headerFileName)
set the data header file name
Definition: vDataFile.hh:431
void ApplyBedOffset(int a_bed)
Compute the bed offset from the provided bed index and apply it to all projection lines...
vEvent * PROJ_GenerateEvent(int idx_elt1, int idx_elt2, int a_th)
Generate a standard event and set up its ID Used by the projection, list-mode sensitivity generatio...
Definition: vDataFile.cc:1056
bool NotEmptyLine()
This function is used to know if the line contains any voxel contribution.
vEvent * GetEventWithAscendingOrderAssumption(int64_t a_eventIndex, int64_t a_eventIndexLimit, int a_th)
According to the current part of the datafile loaded in memory, either read from this buffer or direc...
Definition: vDataFile.cc:609
int LaunchCPU()
Launch the computation of the sensitivity image (CPU version)
virtual int GetSystemNbElts()=0
This is a pure virtual method that must be implemented by children.
void ReduceBackwardImage(int a_imageIndex, int a_timeIndex, int a_respIndex, int a_cardIndex)
Merge parallel results into the backward image matrix of the first thread for the specific image / ti...
This class is designed to manage and store system matrix elements associated to a vEvent...
const string & GetBaseName()
oImageDimensionsAndQuantification * mp_ImageDimensionsAndQuantification
void InstantiateBackwardImageFromDynamicBins()
Allocate memory for the backward image matrices and initialize them.
Definition: oImageSpace.cc:290
Declaration of class oSensitivityGenerator.
void LMS_DeallocateAttenuationImage()
Free memory for the Attenuation image matrices (for analytical projection or list-mode sensitivity ge...
Definition: oImageSpace.cc:928
int GetNbCardGates()
Get the number of cardiac gates.
bool MergeDynImages()
Indicate if a dynamic serie of 3D images should be merged in one file (true) or written on disk as on...
void SetBedIndex(int a_bedIndex)
set the bed index corresponding to this data file
Definition: vDataFile.hh:373
Mother class for the Event objects.
Definition: vEvent.hh:23
int GetNbThreadsForImageComputation()
Get the number of threads used for image operations.
int GetDataMode()
Definition: vDataFile.hh:280
int GetNbTimeFrames()
Get the number of time frames.
int InitializeNormalizationFiles()
Initialize the normalization datafiles provided for sensitivity computation.
int CheckParameters()
A public function used to check the parameters settings.
int64_t PROJ_GetCurrentProgression(int64_t a_elt1, int64_t a_elt2, int64_t *ap_nbEltsArray, int a_nbRGates, int a_nbCGates, int a_fr, int a_rg, int a_cg)
Get numerator value according to the modality to compute percent progression during the analytical pr...
int GetNbTOFBins()
This function is used to get the number of TOF bins in use.
int GetNbThreadsForProjection()
Get the number of threads used for projections.
FLTNB GetVoxelWeights(int a_direction, int a_TOFBin, INTNB a_voxelInLine)
This function is used to get the contributing voxel weight of the provided direction, TOF bin and voxel rank.
vector< string > mp_pathToNormalizationFileName
int ComputeSensitivityFromHistogramDataFile(int a_bed)
Launch the computation of the sensitivity image for this bed, based on the input histogram data files...
int GetNbRespGates()
Get the number of respiratory gates.
#define FORWARD
#define Cout(MESSAGE)
#define FORWARD_DEFORMATION
Definition: vDeformation.hh:15
int64_t PROJ_GetModalityStopValueMainLoop()
Get the stop value for the main loop of analytic projection depending on the modality.
void LMS_CopyAtnToForwardImage()
Copy the attenuation image contained in the 'm2p_attenuation' matrix inside the m4p_forwardImage matr...
int ConvolveSensitivity(oImageSpace *ap_ImageSpace)
A function used to apply convolvers onto the sensitivity image of the oImageSpace.
virtual int IsAvailableLOR(int a_elt1, int a_elt2)
This function is implemented in child classes. Check if the LOR is available according to the scann...
Definition: vScanner.cc:115
int ComputeSensitivityFromScanner(int a_bed)
Launch the computation of the sensitivity image for this bed, based on a loop over all scanner elemen...
bool GetAtnCorrectionFlag()
Simply return m_atnCorrectionFlag.
void SetImageDimensionsAndQuantification(oImageDimensionsAndQuantification *ap_ImageDimensionsAndQuantification)
set the pointer to the oImageDimensionsAndQuantification object
Definition: vDataFile.hh:408
void DeallocateBackwardImageFromDynamicBins()
Free memory of the backward image matrices.
Definition: oImageSpace.cc:326
Inherit from vDataFile. Class that manages the reading of a PET input file (header + data)...
Definition: iDataFilePET.hh:26
void LMS_InstantiateSensitivityImage()
Allocate memory for the sensitivity image matrices (for list-mode sensitivity generation) ...
void SetPercentageLoad(int a_percentageLoad)
Set the percentage of the data file that will be loaded in memory.
Definition: vDataFile.hh:380
int GetMPIRank()
Get the MPI instance number (the rank)
void LMS_CopyBackwardToSensitivity()
int GetCurrentTimeFrame(int a_th)
call the eponym function from the oDynamicDataManager object
#define BACKWARD
void LMS_DeallocateForwardImage()
Free memory for the forward image matrices (for list-mode sensitivity generation) ...