CASToR  3.2
Tomographic Reconstruction (PET/SPECT/CT)
castor-recon.cc
Go to the documentation of this file.
1 
12 #include "gVariables.hh"
13 #include "gOptions.hh"
14 #include "iRCPGSAlgorithm.hh"
15 #include "vAlgorithm.hh"
16 #include "iIterativeAlgorithm.hh"
17 #include "oSensitivityGenerator.hh"
18 #include "oImageDimensionsAndQuantification.hh"
19 #include "iDataFilePET.hh"
20 #include "iDataFileSPECT.hh"
21 #include "iDataFileCT.hh"
22 #include "sOutputManager.hh"
23 #include "sScannerManager.hh"
24 #include "sRandomNumberGenerator.hh"
25 #include "iScannerPET.hh"
26 #include "sAddonManager.hh"
27 #include "sChronoManager.hh"
28 
29 // =============================================================================================================================================
30 // =============================================================================================================================================
31 // =============================================================================================================================================
32 // H E L P F U N C T I O N S
33 // =============================================================================================================================================
34 // =============================================================================================================================================
35 // =============================================================================================================================================
36 
37 
42 void ShowHelp()
43 {
44  // Return when using MPI and mpi_rank is not 0
45  #ifdef CASTOR_MPI
46  int mpi_rank = 0;
47  MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
48  if (mpi_rank!=0) return;
49  #endif
50  // Show help
51  cout << endl;
52  cout << "Usage: castor-recon.exe -df file.cdh -(f/d)out output -it iter [settings]" << endl;
53  cout << endl;
54  cout << "[Main options]:" << endl;
55  cout << " -df file.cdh : Give an input CASTOR datafile header (no default)." << endl;
56 //MULTIBED cout << " Can use this option multiple times to specify multiple bed positions." << endl;
57  cout << " -fout name : Give the root name for all output files (no default, alternative to -dout)" << endl;
58  cout << " -dout name : Give the name of the output directory where all output files will be written (no default, alternative to -fout)" << endl;
59  cout << " -it list : Give the sequence of iterations:subsets separated by commas (no default)." << endl;
60  cout << " -dim x,y,z : Give the number of voxels in each dimension (default: those of the scanner)." << endl;
61  cout << " -fov x,y,z : Give the size of the field-of-view in each dimension, in mm (default: those of the scanner, or calculated from" << endl;
62  cout << " the voxel sizes provided using '-vox')." << endl;
63  cout << " -vox x,y,z : Give the size of the voxels in each dimension, in mm (default: those of the scanner, or calculated from the fov" << endl;
64  cout << " if a fov value is provided using '-fov')." << endl;
65  cout << " -vb : Give the general verbosity level, from 0 (no verbose) to 5 and above (at the event level) (default: 1)." << endl;
66  cout << endl;
67  cout << "[Specific help options]:" << endl;
68  cout << " -help-dim : Print out specific help about dimensions settings." << endl; // managed by main
69  cout << " -help-in : Print out specific help about input settings." << endl; // managed by main
70  cout << " -help-out : Print out specific help about output settings." << endl; // managed by main
71  cout << " -help-algo : Print out specific help about reconstruction algorithms and their settings." << endl; // managed by main
72  cout << " -help-proj : Print out specific help about projection operators." << endl; // managed by main
73  cout << " -help-dynamic : Print out specific help about dynamic methodologies settings." << endl; // managed by main
74  cout << " -help-imgp : Print out specific help about image processing modules." << endl; // managed by main
75  cout << " -help-comp : Print out specific help about computing settings." << endl; // managed by main
76  cout << " -help-corr : Print out specific help about all corrections that can be disabled." << endl;
77  cout << " -help-misc : Print out specific help about miscellaneous and verbose settings." << endl; // managed by main
78  cout << endl;
79  cout << "[Implemented Modules]:" << endl;
80  cout << " -help-scan : Show the list of all scanners from the configuration directory." << endl; // managed by sScannerManager
81  cout << " -help-projm : Show the list and description of all implemented projectors." << endl; // managed by oProjectorManager
82  cout << " -help-opti : Show the list and description of all implemented optimizer algorithms." << endl; // managed by oOptimizerManager
83  cout << " -help-pnlt : Show the list and description of all implemented penalties for optimizers." << endl; // managed by oOptimizerManager
84  cout << " -help-motion-model : Show the list and description of all implemented image-based deformation models." << endl; // managed by oImageDeformationManager
85  cout << " -help-dynamic-model : Show the list and description of all implemented dynamic models." << endl; // managed by oDynamicModelManager
86  cout << " -help-conv : Show the list and description of all implemented image convolvers." << endl; // managed by oImageConvolverManager
87  cout << " -help-proc : Show the list and description of all implemented image processing modules." << endl; // managed by oImageProcessingManager
88  cout << endl;
89  cout << endl;
90  cout << " --help,-h,-help : Print out this help page." << endl; // managed by main
91  cout << endl;
92  #ifdef CASTOR_MPI
93  cout << " Compiled with MPI" << endl;
94  #endif
95  #ifdef CASTOR_OMP
96  cout << " Compiled with OpenMP" << endl;
97  #endif
98  #ifdef CASTOR_GPU
99  cout << " Compiled for GPU" << endl;
100  #endif
101  #if defined(CASTOR_OMP) || defined(CASTOR_MPI) || defined(CASTOR_GPU)
102  cout << endl;
103  #endif
104  #ifdef BUILD_DATE
105  cout << " Build date: " << BUILD_DATE << endl;
106  cout << endl;
107  #endif
108  #ifdef CASTOR_VERSION
109  cout << " This program is part of the CASToR release version " << CASTOR_VERSION << "." << endl;
110  cout << endl;
111  #endif
112 }
113 
114 // =====================================================================
115 // ---------------------------------------------------------------------
116 // ---------------------------------------------------------------------
117 // =====================================================================
123 {
124  // Return when using MPI and mpi_rank is not 0
125  #ifdef CASTOR_MPI
126  int mpi_rank = 0;
127  MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
128  if (mpi_rank!=0) return;
129  #endif
130  // Show help
131  cout << endl;
132  cout << "[Input settings]:" << endl;
133  cout << endl;
134 //MULTIBED cout << " -df-inv : Invert the order of provided datafiles corresponding to the different bed positions." << endl;
135 //MULTIBED cout << endl;
136 //MULTIBED cout << " -df file.cdf : Give an input CASTOR datafile (no default). Can use this option multiple times to specify multiple bed positions." << endl;
137  cout << " -df file.cdf : Give an input CASTOR datafile header (no default)." << endl;
138  cout << endl;
139  cout << " -img file.hdr : Give an input image as the initialization of the algorithm (default: uniform value)." << endl;
140  cout << endl;
141  cout << " -sens file.hdr : Provide the sensitivity image (default: sensitivity image is computed before reconstruction)." << endl;
142  cout << " The image file should integrate all sensitivity images if more than one are required. If dual-gating is enabled and if it" << endl;
143  cout << " requires sensitivity images for each gate, the image should integrate nb_resp_gates * nb_card_gates sensitivity images" << endl;
144  cout << " (all cardiac-gated based sensitivity images for each one of the respiratory gates)." << endl;
145  cout << endl;
146  cout << " -multimodal file.hdr : Provide additional images, from other modalities (anatomical, functional), or processed, for use in constrained reconstruction." << endl;
147  cout << " Multiple additional images can be provided by using the option multiple times. The additional images will be linearly interpolated" << endl;
148  cout << " to match the dimensions of the reconstructed images." << endl;
149  cout << endl;
150  cout << " -additional-data file.hdr : Provide additional data, size being the number of events, for use in reconstruction." << endl;
151  cout << " Multiple additional data files can be provided by separating the file names using commas." << endl;
152  cout << " The option must be used multiple times in case of multiple bed positions." << endl;
153  cout << endl;
154  cout << " -mask file.hdr : Provide a mask image for avoiding computations (projection, convolution, penalty) on irrelevant voxels (background)."<<endl;
155  cout << " The mask should contain zero values for the background and non zero values for relevant voxels." << endl;
156  cout << endl;
157  cout << " -norm file.cdh : For list-mode data, provide a normalization data file for sensitivity computation (default: use the scanner LUT and" << endl;
158  cout << " assume all LORs with a weight of 1.). This restricts the computation of the sensitivity to the LORs provided in the" << endl;
159  cout << " normalization file and associated normalization factors and/or attenuation factors." << endl;
160  cout << " For dynamic reconstructions with multiple frames, as many normalization files as frames can be supplied, their names" << endl;
161  cout << " separated by commas. This is useful when dead-times correction is included in the normalization factors." << endl;
162 //MULTIBED cout << " Can also use this option multiple times when multiple bed positions are reconstructed at once." << endl;
163  cout << endl;
164  cout << " -atn file.hdr : Give an input attenuation image (unit has to be cm-1) for sensitivity image generation or SPECT attenuation correction." << endl;
165  cout << endl;
166  cout << " -help-in : Print out this help." << endl;
167  cout << endl;
168 }
169 
170 
171 // =====================================================================
172 // ---------------------------------------------------------------------
173 // ---------------------------------------------------------------------
174 // =====================================================================
180 {
181  // Return when using MPI and mpi_rank is not 0
182  #ifdef CASTOR_MPI
183  int mpi_rank = 0;
184  MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
185  if (mpi_rank!=0) return;
186  #endif
187  // Show help
188  cout << endl;
189  cout << "[Output settings]:" << endl;
190  cout << endl;
191  cout << " -fout name : Give the root name for all output files. All output files will be written as 'name_suffix.ext'." << endl;
192  cout << " So the provided name should not end with '.' or '/' character. (no default, alternative to -dout)" << endl;
193  cout << " -dout name : Give the name of the output directory where all output files will be written. All files will also" << endl;
194  cout << " be prefixed by the name of the directory. The provided name should not end with '.' or '/' character." << endl;
195  cout << " (no default, alternative to -fout)" << endl;
196  cout << endl;
197  cout << " -oit list : Give the sequence of output iterations as a list of 'a:b' pairs separated by commas. This will output one" << endl;
198  cout << " iteration over 'a' until 'b' is reached, then it goes to the next pair of setting." << endl;
199  cout << " Set '-1' to save only the last iteration. (default: save all iterations)" << endl;
200  cout << endl;
201  cout << " -fov-out percent : Give the percentage of the eliptical transaxial FOV to be kept while saving the image (default: no making)." << endl;
202  cout << endl;
203  cout << " -slice-out value : Give the number of axial slices to be masked at each border of the axial field-of-view (default: 0)." << endl;
204  cout << endl;
205  cout << " -flip-out value : Flip the image before saving it (not done in the computation); specify the axis (e.g. 'X', 'XY', 'YZ') (default: no flip)." << endl;
206  cout << endl;
207  cout << " -onbp value : By default, numbers are displayed using scientific format. This option allows to customize the format and precision" << endl;
208  cout << " : The format is format,precision. f is the format (s=scientific, f=fixed), p is the precision" << endl;
209  cout << " eg: -onbp f,5 --> fixed with 5 digits precision, -onbp --> scientific with max precision." << endl;
210  cout << endl;
211  cout << " -omd : (M)erge (D)ynamic images. Indicate if a dynamic serie of 3D images should be written on disk in one file" << endl;
212  cout << " instead of a serie of 3D images associated with an interfile metaheader." << endl;
213  cout << endl;
214  cout << " -odyn : Flag to say that we want to save the dynamic basis function coefficients images too (default: only the frames/gates are saved)." << endl;
215  cout << endl;
216  cout << " -osens : Flag to say that we want to save the sensitivity image of each subset/iteration, when in histogram mode." << endl;
217  cout << endl;
218  cout << " -osub : Flag to say that we want to save the image after each subset." << endl;
219  cout << endl;
220  cout << " -olut : If a scanner LUT (geometry information) is computed from a .geom file, it will be save on disk in the scanner repository." << endl;
221  cout << endl;
222  cout << " -sens-histo : If input file is a histogram, compute the global sensitivity from it (and still proceed to normal reconstruction after)." << endl;
223  cout << endl;
224  cout << " -sens-only : For list-mode data, exit directly after computing and saving the sensitivity." << endl;
225  cout << endl;
226  cout << " -help-out : Print out this help." << endl;
227  cout << endl;
228 }
229 
230 // =====================================================================
231 // ---------------------------------------------------------------------
232 // ---------------------------------------------------------------------
233 // =====================================================================
239 {
240  // Return when using MPI and mpi_rank is not 0
241  #ifdef CASTOR_MPI
242  int mpi_rank = 0;
243  MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
244  if (mpi_rank!=0) return;
245  #endif
246  // Show help
247  cout << endl;
248  cout << "[Dimensions options]:" << endl;
249  cout << endl;
250  cout << " -dim x,y,z : Give the number of voxels in each dimension (default: those of the scanner)." << endl;
251  cout << endl;
252  cout << " -fov x,y,z : Give the size of the field-of-view in each dimension, in mm (default: those of the scanner)." << endl;
253  cout << endl;
254  cout << " -vox x,y,z : Give the size of the voxels in each dimension, in mm (default: those of the scanner, or calculated from the fov if a fov value is provided using '-fov')." << endl;
255  cout << endl;
256  cout << " -off x,y,z : Give the offset of the field-of-view in each dimension, in mm (default: 0.,0.,0.)." << endl;
257  cout << " (note this has no effect when using a pre-computed system matrix)" << endl;
258  cout << endl;
259  cout << " -help-dim : Print out this help." << endl;
260  cout << endl;
261 }
262 
263 // =====================================================================
264 // ---------------------------------------------------------------------
265 // ---------------------------------------------------------------------
266 // =====================================================================
267 
276 {
277  // Return when using MPI and mpi_rank is not 0
278  #ifdef CASTOR_MPI
279  int mpi_rank = 0;
280  MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
281  if (mpi_rank!=0) return;
282  #endif
283  // Show help
284  cout << "[Algorithm settings]:" << endl;
285  cout << endl;
286  cout << " -skip it : Specify the number of first iterations not needed for the computation. This option can be used to pursue a previous" << endl;
287  cout << " computation with more iterations." << endl;
288  cout << endl;
289  cout << " -opti param : Specify the iterative optimization algorithm to be used, along with a configuration file (algo:file.conf) or the list of parameters" << endl;
290  cout << " associated to the algorithm (algo,param1,param2,...). If the algorithm only is specified, the default" << endl;
291  cout << " configuration file is used if any. By default, the MLEM algorithm is used. For specific help, use option -help-opti." << endl;
292  cout << endl;
293  cout << " -opti-fom : Flag to say that we want to compute and print figures-of-merit (likelihood and RMSE) in the data-space." << endl;
294  cout << endl;
295  cout << " -opti-stat : Flag to say that we want to compute and print basic statistics about the image update." << endl;
296  cout << endl;
297  cout << " -pnlt param : Give the penalty to be used with the algorithm (if the latter allows to do so), along with a configuration file (penalty:file.conf)" << endl;
298  cout << " or the list of parameters associated to the penalty (penalty,param1,param2,...). If only the penalty name is specified, the default" << endl;
299  cout << " configuration file is used if any. By default, no penalty is used. For specific help, use option -help-pnlt." << endl;
300  cout << " -pnlt-beta : Give the strength of the penalty defined by the '-pnlt' option." << endl;
301  cout << " -prob : Specify the probabilistic (Bayesian inference) algorithm, along with a configuration file or a list of parameters, use option -help-prob for more details." << endl;
302  cout << endl;
303  cout << " -help-opti : Print out specific help about optimizer settings." << endl; // managed by oOptimizerManager
304  cout << endl;
305  cout << " -help-pnlt : Print out specific help about penalty settings." << endl;
306  cout << " -help-algo : Print out specific help about the available algorithms." << endl;
307  cout << endl;
308 }
309 
310 // =====================================================================
311 // ---------------------------------------------------------------------
312 // ---------------------------------------------------------------------
313 // =====================================================================
319 {
320  // Return when using MPI and mpi_rank is not 0
321  #ifdef CASTOR_MPI
322  int mpi_rank = 0;
323  MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
324  if (mpi_rank!=0) return;
325  #endif
326  // Show help
327  cout << "[Projector settings]:" << endl;
328  cout << endl;
329  cout << " -proj param : Give the projector to be used for both forward and backward projections, along with a configuration file (proj:file.conf)" << endl;
330  cout << " or the list of parameters associated to the projector (proj,param1,param2,...). If the projector only is specified, the" << endl;
331  cout << " default configuration file is used. By default, the Siddon projector is used. For specific help, use option -help-proj." << endl;
332  cout << endl;
333  cout << " -projF param : Give the projector to be used for forward projections. See option -proj for details." << endl;
334  cout << endl;
335  cout << " -projB param : Give the projector to be used for backward projections. See option -proj for details." << endl;
336  cout << endl;
337  cout << " -proj-common : Give common projector-related options, such as TOF implementation options, see -help-projm for more details." << endl;
338  cout << endl;
339 /* TO BE IMPLEMENTED
340  cout << " -ignore-POI : Flag to say that we want to ignore any potential POI information (default: use it if present in the datafile)." << endl;
341  cout << endl;
342  * */
343  cout << " -ignore-TOF : Flag to say that we want to ignore any potential TOF information (default: use it if present in the datafile)." << endl;
344  cout << endl;
345  cout << " -help-projm : Print out specific help about projector settings." << endl; // managed by oProjectorManager
346  cout << endl;
347 }
348 
349 // =====================================================================
350 // ---------------------------------------------------------------------
351 // ---------------------------------------------------------------------
352 // =====================================================================
358 {
359  // Return when using MPI and mpi_rank is not 0
360  #ifdef CASTOR_MPI
361  int mpi_rank = 0;
362  MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
363  if (mpi_rank!=0) return;
364  #endif
365  // Show help
366  cout << "[Image processing settings]:" << endl;
367  cout << endl;
368  cout << " -conv param;when : Give an image convolver model to be used within the algorithm, along with a configuration file (conv:file.conf::when) or the" << endl;
369  cout << " list of parameters associated to the convolver (conv,param1,param2,...::when). If the convolver only is specified, its default" << endl;
370  cout << " configuration file is used. By default, no convolver is applied. Multiple convolvers can be combined simply by repeating this" << endl;
371  cout << " this option. The mandatory 'when' parameter specifies when the convolver is applied (psf, sieve, forward, backward, post, intra)." << endl;
372  cout << " For more specific help, use option -help-conv." << endl;
373  cout << endl;
374  cout << " -help-conv : Print out specific help about the image convolver settings." << endl; // managed by oImageConvolverManager
375  cout << endl;
376  cout << " -proc param;when : Give an image processing module to be used within the algorithm, along with a configuration file (proc:file.conf;when) or the" << endl;
377  cout << " list of parameters associated to the module (proc,param1,param2,...;when). If the module only is specified, its default" << endl;
378  cout << " configuration file is used. By default, no image processing module is applied. Multiple modules can be combined simply by" << endl;
379  cout << " repeating this this option. The mandatory 'when' parameter specifies when the module is applied (forward, backward, post, intra)." << endl;
380  cout << " For more specific help, use option -help-proc." << endl;
381  cout << endl;
382  cout << " -help-proc : Print out specific help about the image processing module settings." << endl; // managed by oImageProcessingManager
383  cout << endl;
384 }
385 
386 // =====================================================================
387 // ---------------------------------------------------------------------
388 // ---------------------------------------------------------------------
389 // =====================================================================
395 {
396  // Return when using MPI and mpi_rank is not 0
397  #ifdef CASTOR_MPI
398  int mpi_rank = 0;
399  MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
400  if (mpi_rank!=0) return;
401  #endif
402  // Show help
403  cout << endl;
404  cout << "[Dynamic settings]:" << endl;
405  cout << endl;
406  cout << " -frm list : Give the framing details for the reconstruction where 'list' is a list of frame start times, separated with commas. " << endl;
407  cout << " Duration for each frame can also be specified using a colon after the frame start time. "<< endl;
408  cout << " When no duration is specified for a frame, the duration will be set equal to the difference between the start of this frame and the next one."<< endl;
409  cout << " It is mandatory to specify the duration of the last frame. For example '-frm start1:duration1,start2,start3:duration3'."<< endl;
410  cout << " Add 's' or 'm' to specify if values are seconds or minutes (seconds is the default if none provided). " << endl;
411  cout << " Maximum precision of frames is milliseconds. (default: 1 frame of the whole input file duration)." << endl;
412  cout << endl;
413  cout << " -g path_to_file : Provide text file for dynamic data splitting associated to respiratory/cardiac gating or involuntary patient motion correction" << endl;
414  cout << endl;
415 /* TODO: Remove if not necessary
416  * Options for input of basis functions before the implementation of the dynamic manager
417  cout << " -time-basis nb:file : Give the number of time basis functions related to the frames given by option -frm." << endl;
418  cout << " The file should contain one line for each time-basis function, and as many numbers as frames." << endl;
419  cout << " -resp-basis nb:file : Give the number of intrinsic respiratory basis functions related to the respiratory gates" << endl;
420  cout << " The file should contain one line for each respiratory basis function, and as many numbers as respiratory gates." << endl;
421  cout << " -card-basis nb:file : Give the number of intrinsic cardiac basis functions related to the cardiac gates" << endl;
422  cout << " The file should contain one line for each cardiac basis function, and as many numbers as cardiac gates." << endl;
423  cout << endl;
424 */
425  cout << " -dynamic-model param : Dynamic model applied to either the frames of a dynamic acquisition, respiratory-gated frames, cardiac-gated frames, or simultaneously between these datasets." << endl;
426  cout << " Select the dynamic model to be used, along with a configuration file (model:file) or the list of parameters associated to the model (model_name,param1,param2,...)." << endl;
427  cout << endl;
428  cout << " -rm param : Provide an image-based deformation model to be used for respiratory motion correction, along with a configuration file (deformation:file)" << endl;
429  cout << " or the list of parameters associated to the projector (deformation,param1,param2,...)." << endl;
430  cout << endl;
431  cout << " -cm param : Provide an image-based deformation model to be used for cardiac motion correction, along with a configuration file (deformation:file)" << endl;
432  cout << " or the list of parameters associated to the projector (deformation,param1,param2,...)." << endl;
433  cout << endl;
434  //cout << " -rcm param : Provide an image-based deformation model to be used for both respiratory and cardiac motion corrections, along with a configuration file (deformation:file)" << endl;
435  //cout << " or the list of parameters associated to the projector (deformation,param1,param2,...)." << endl;
436  //cout << endl;
437  cout << " -im param : Provide an image-based deformation model to be used for involuntary motion correction, along with a configuration file (deformation:file)" << endl;
438  cout << " or the list of parameters associated to the projector (deformation,param1,param2,...)." << endl;
439  cout << endl;
440  cout << " -qdyn file : Provide a text file containing quantitative factors specific to dynamic frames, respiratory or cardiac gates." << endl;
441  cout << " The file should provide factors with the keywords 'FRAME_QUANTIFICATION_FACTORS' and 'GATE_QUANTIFICATION_FACTORS' " << endl;
442  cout << " The number of factors must be consistent with the number of frames/gates " << endl;
443  cout << " If the data contains several frames and gates, the gate quantification factors should be entered on a separate line for each frame " << endl;
444  cout << endl;
445  cout << " -help-dynamic-model : Print out specific help about dynamic model." << endl; // managed by oDynamicModelManager
446  cout << endl;
447  cout << " -help-motion-model : Print out specific help about deformation models." << endl; // managed by oImageDeformationManager
448  cout << endl;
449  cout << " -help-dynamic : Print out this help." << endl;
450  cout << endl;
451 
452 }
453 
454 // =====================================================================
455 // ---------------------------------------------------------------------
456 // ---------------------------------------------------------------------
457 // =====================================================================
463 {
464  // Return when using MPI and mpi_rank is not 0
465  #ifdef CASTOR_MPI
466  int mpi_rank = 0;
467  MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
468  if (mpi_rank!=0) return;
469  #endif
470  // Show help
471  cout << endl;
472  cout << "[Computation settings]:" << endl;
473  cout << endl;
474  #ifdef CASTOR_OMP
475  cout << " -th param : Set the number of threads for parallel computation (default: 1). If 0 is given, then the maximum number of available threads is automatically determined." << endl;
476  cout << " Can also give two parameters separated by a comma (e.g. 16,4), to distinguish between the number of threads for projection and image operations respectively." << endl;
477  cout << endl;
478  #endif
479  #ifdef CASTOR_GPU
480  cout << " -gpu : Flag to say that we want to use the GPU device (default: use the CPU only)." << endl;
481  cout << endl;
482  #endif
483  cout << " -proj-comp : Give the strategy for projection line computation. Here are the three different strategies that can be used:" << endl;
484  cout << " 1 : Image-based system matrix elements storage: The voxels weights are added in a matrix representing the whole image, so" << endl;
485  cout << " the addition of a new line to the previous ones is straightforward only by adding the weights to the corresponding voxels." << endl;
486  cout << " As it is insanely long, it can possibly be used for example with extremely complex projectors that makes use of huge number" << endl;
487  cout << " of ray tracings for a single event, where the list of contributions can become longer than the number of voxels in the image." << endl;
488  cout << " This strategy is not compatible with SPECT reconstruction including attenuation correction." << endl;
489  cout << " 2 : Fixed-size list storage of system matrix elements: The voxels are added one by one in two separated lists, one containing voxel" << endl;
490  cout << " indices and the other voxel weights. When a voxel is added to the oProjectionLine, it is simply pilled-up to the list. The list" << endl;
491  cout << " has a fixed size which is provided by the EstimateMaxNumberOfVoxelsPerLine() function from the vProjector class. There are no" << endl;
492  cout << " ckecks at all for possible buffer overflows. This is the fastest strategy and default one." << endl;
493  cout << " 3 : Adaptative-size list storage of system matrix elements: This is the same as the fixed-size strategy except that the size can be" << endl;
494  cout << " upgraded if the current number of contributing voxels exceed the list's size. The first allocated size corresponds to the diagonal" << endl;
495  cout << " of the image. During the first iteration, this size will be upgraded until it will reach a size suitable for all events. Thus it" << endl;
496  cout << " is a bit slower than the fixed-list strategy during the first iteration, but is optimal with respect to RAM usage." << endl;
497  cout << endl;
498  cout << " -rng-seed : Give a seed for the random number generator (should be >=0)" << endl;
499  cout << endl;
500  cout << " -rng-extra : Give the number of additional random number generators, if needed (in addition to one rng per thread) " << endl;
501  cout << endl;
502  cout << " -help-comp : Print out this help." << endl;
503  cout << endl;
504  #ifdef CASTOR_MPI
505  cout << " Compiled with MPI" << endl;
506  #endif
507  #ifdef CASTOR_OMP
508  cout << " Compiled with OpenMP" << endl;
509  #endif
510  #ifdef CASTOR_GPU
511  cout << " Compiled for GPU" << endl;
512  #endif
513  #if defined(CASTOR_OMP) || defined(CASTOR_MPI) || defined(CASTOR_GPU)
514  cout << endl;
515  #endif
516 }
517 
518 // =====================================================================
519 // ---------------------------------------------------------------------
520 // ---------------------------------------------------------------------
521 // =====================================================================
527 {
528  // Return when using MPI and mpi_rank is not 0
529  #ifdef CASTOR_MPI
530  int mpi_rank = 0;
531  MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
532  if (mpi_rank!=0) return;
533  #endif
534  // Show help
535  cout << endl;
536  cout << "[Miscellaneous settings]:" << endl;
537  cout << endl;
538  cout << " -vb : Give the general verbosity level, from 0 (no verbose) to 5 and above (at the event level) (default: 1)." << endl;
539  cout << " -vb-algo : Give the verbose level specific to the algorithm (default: same as general verbose level)." << endl;
540  cout << " -vb-opti : Give the verbose level specific to the optimizer (default: same as general verbose level)." << endl;
541  cout << " -vb-proj : Give the verbose level specific to the projector (default: same as general verbose level)." << endl;
542  cout << " -vb-conv : Give the verbose level specific to the image convolver (default: same as general verbose level)." << endl;
543  cout << " -vb-proc : Give the verbose level specific to the image processing (default: same as general verbose level)." << endl;
544  cout << " -vb-scan : Give the verbose level specific to the scanner (default: same as general verbose level)." << endl;
545  cout << " -vb-data : Give the verbose level specific to the data and image management (default: same as general verbose level)." << endl;
546  cout << " -vb-defo : Give the verbose level specific to the deformation (default: same as general verbose level)." << endl;
547  cout << " -vb-dyna : Give the verbose level specific to the dynamic model (default: same as general verbose level)." << endl;
548  cout << " -vb-sens : Give the verbose level specific to the sensitivity computation (default: same as general verbose level)." << endl;
549  cout << endl;
550  cout << " -conf : Give the path to the CASToR config directory (default: located through the CASTOR_CONFIG environment variable)." << endl;
551  cout << endl;
552  cout << " -help-misc : Print out this help." << endl;
553  cout << endl;
554 }
555 
556 // =====================================================================
557 // ---------------------------------------------------------------------
558 // ---------------------------------------------------------------------
559 // =====================================================================
565 {
566  // Return when using MPI and mpi_rank is not 0
567  #ifdef CASTOR_MPI
568  int mpi_rank = 0;
569  MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
570  if (mpi_rank!=0) return;
571  #endif
572  // Show help
573  cout << endl;
574  cout << "[Correction settings]:" << endl;
575  cout << endl;
576  cout << " -ignore-corr list : Give the list of corrections that should be ignored, separated by commas (default: all corrections applied if present)." << endl;
577  cout << " Here is a list of all corrections that can be ignored:" << endl;
578  cout << " - attn: to ignore the attenuation correction (emission only)" << endl;
579  cout << " - norm: to ignore the normalization correction (emission only)" << endl;
580  cout << " - rand: to ignore the random correction (PET only)" << endl;
581  cout << " - scat: to ignore the scatter correction" << endl;
582  cout << " - deca: to ignore the decay correction (emission only)" << endl;
583  cout << " - brat: to ignore the branching ratio correction (emission only)" << endl;
584  cout << " - fdur: to ignore the frame duration correction (emission only)" << endl;
585  cout << " - cali: to ignore the calibration correction (emission only)" << endl;
586  cout << endl;
587 }
588 
589 // =============================================================================================================================================
590 // =============================================================================================================================================
591 // =============================================================================================================================================
592 // M A I N P R O G R A M
593 // =============================================================================================================================================
594 // =============================================================================================================================================
595 // =============================================================================================================================================
596 
597 int main(int argc, char** argv)
598 {
599  // ============================================================================================================
600  // MPI stuff
601  // ============================================================================================================
602  int mpi_rank = 0;
603  int mpi_size = 1;
604  #ifdef CASTOR_MPI
605  MPI_Init(&argc, &argv);
606  MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank);
607  MPI_Comm_size(MPI_COMM_WORLD, &mpi_size);
608  #endif
609 
610  // No argument, then show help
611  if (argc==1)
612  {
613  ShowHelp();
614  Exit(EXIT_SUCCESS);
615  }
616 
617  // ============================================================================================================
618  // Parameterized variables with their default values
619  // ============================================================================================================
620 
621  // --------------------------------------------------------------------------------
622  // Dimensions settings
623  // --------------------------------------------------------------------------------
624 
625  // Initialization of the voxel and field-of-view values in each spatial dimensions. default values depend of the scanner.
626  INTNB nb_voxX=-1, nb_voxY=-1, nb_voxZ=-1;
627  FLTNB fov_sizeX=-1., fov_sizeY=-1., fov_sizeZ=-1.;
628  FLTNB vox_sizeX=-1., vox_sizeY=-1., vox_sizeZ=-1.;
629  // Initialization offset values of the field-of-view in each spatial dimensions
630  FLTNB offsetX = 0., offsetY = 0., offsetZ = 0.;
631  FLTNB fov_out = 0.;
632  INTNB slice_out = 0;
633  // Output flip
634  string flip_out = "";
635 
636  // --------------------------------------------------------------------------------
637  // Dynamic settings
638  // --------------------------------------------------------------------------------
639 
640  // Frame list descriptor
641  string frame_list = "";
642  // Number of respiratory gates in the data. default : 1
643  int nb_resp_gates = 1;
644  // Number of cardiac gates in the data. default : 1
645  int nb_card_gates = 1;
646  // Path to file containing the respiratory/cardiac gate splitting of the data
647  string path_to_4D_data_splitting_file = "";
648  // String gathering the name of the used dynamic model applied to the frames/resp gates/card gates of the dynamic acquisition (default : none), corresponding file, and corresponding string gathering parameters
649  string dynamic_model_options = "";
650  // String gathering the name of the used deformation model for respiratory motion (default : none), corresponding file, and corresponding string gathering parameters
651  string resp_motion_options = "";
652  // String gathering the name of the used deformation model for cardiac motion (default : none), corresponding file, and corresponding string gathering parameters
653  string card_motion_options = "";
654  // String gathering the name of the used deformation model for both respiratory and cardiac motions (default : none), corresponding file, and corresponding string gathering parameters
655  string double_motion_options = "";
656  // String gathering the name of the used deformation model for involuntary motion (default : none), corresponding file, and corresponding string gathering parameters
657  string ipat_motion_options = "";
658  // Number of respiratory basis functions and associated file
659  int nb_resp_basis = 1;
660  string path_to_resp_basis_coef = "";
661  // Number of cardiac basis functions and associated file
662  int nb_card_basis = 1;
663  string path_to_card_basis_coef = "";
664  // Number of cardiac basis functions and associated file
665  string path_to_dynamic_quantification_file= "";
666 
667 
668  // --------------------------------------------------------------------------------
669  // Input settings
670  // --------------------------------------------------------------------------------
671 
672  // Number of bed positions
673  int nb_beds = 0;
674  // Vector (for bed positions) containing string which gather the path to the data filenames provided by the user. no default
675  vector<string> path_to_data_filename;
676  // Invert bed datafile names order (bed positions)
677  bool invert_datafile_bed_order_flag = false;
678  // Path to an image used as initialization. no default (uniform image is used in this case)
679  string path_to_initial_img = "";
680  // Path to an image used as initialization for the sensitivity image. no default (sensitivity image is computed in this case)
681  string path_to_sensitivity_img = "";
682  // Path to a normalization data file for sensitivity computation with list-mode data
683  vector<string> path_to_normalization_filename;
684  // Path to an image used for the attenuation. default : uniform image
685  string path_to_attenuation_img;
686  // Paths to additional images coming from -multimodal option
687  vector<string> path_to_multimodal_img;
688  // Paths to additional data coming from -additional-data option
689  vector<string> path_to_additional_data;
690  // Path to an image used as mask
691  string path_to_mask_img = "";
692  // Number of resp and card atn images for sensitivity image generation
693  int nb_atn_resp_imgs = 1;
694  int nb_atn_card_imgs = 1;
695  // Ignored corrections (by default, if present, there are applied)
696  string ignored_corrections = "";
697 
698  // --------------------------------------------------------------------------------
699  // Output settings
700  // --------------------------------------------------------------------------------
701 
702  // Output directory name.
703  string path_dout = "";
704  // Or root name
705  string path_fout = "";
706  // Iterations to be saved
707  string output_iterations = "";
708  // Merge output dynamic images on disk into one file or not
709  bool merge_dynamic_imgs_flag = false;
710  // Write scanner LUT generated by a geom file on disk
711  bool save_LUT_flag = false;
712  // Save the sensitivity image in histogram mode for each subset/iteration
713  bool save_sens_histo = false;
714  // Save the image after each subset
715  bool save_subset_image = false;
716  // Save the dynamic basis functions coefficients images (flag). default : no saving
717  bool save_dynamic_basis_coefficients_flag = false;
718  // Exit directly after computing the sensitivity
719  bool exit_after_sensitivity = false;
720  // Compute sensitivity with a histogram file as input
721  bool sensitivity_from_histogram = false;
722  // Precision for output number display
723  string onb_prec = "s,0";
724 
725  // --------------------------------------------------------------------------------
726  // Projector settings
727  // --------------------------------------------------------------------------------
728 
729  // String gathering the name of the projector for forward/backward projection with specific options (default: Native Siddon for both)
730  string options_projector = "incrementalSiddon";
731  string options_projectorF = "incrementalSiddon";
732  string options_projectorB = "incrementalSiddon";
733  string options_projector_common = "3.,1,1";
734  // Default projector computation strategy
735  int projector_computation_strategy = FIXED_LIST_COMPUTATION_STRATEGY;
736  // POI & TOF flags for the use of such information in the reconstruction
737  bool ignore_POI = false;
738  bool ignore_TOF = false;
739 
740  // --------------------------------------------------------------------------------
741  // Algorithm settings
742  // --------------------------------------------------------------------------------
743 
744  // Numbers of iterations and associated numbers of subsets (default : 1 for both)
745  string nb_iterations_subsets = "";
746  // Numbers of iterations to be skipped (default : 0)
747  string nb_skipped_iterations = "";
748  // String gathering the name of the optimizer with specific options (default: MLEM)
749  string options_optimizer = "MLEM";
750  // Boolean to say if we want to compute FOM in the data-space
751  bool optimizer_fom = false;
752  // Boolean to say if we want to compute image update basic statistics
753  bool optimizer_stat = false;
754  // String gathering the name of the penalty with specific options (default: no penalty)
755  string options_penalty = "";
756  // String with options for probabilistic algorithms (default: none)
757  string options_prob = "";
758  // Penalty strength
759  FLTNB penalty_beta = -1.;
760 
761 
762  // --------------------------------------------------------------------------------
763  // Image convolvers and processing modules
764  // --------------------------------------------------------------------------------
765 
766  // String vector gathering the name of the image convolvers with specific options (default: no image convolver)
767  vector<string> options_image_convolver;
768  // String vector gathering the name of the image processing modules with specific options (default: no image processing module)
769  vector<string> options_image_processing;
770 
771  // --------------------------------------------------------------------------------
772  // Computation settings
773  // --------------------------------------------------------------------------------
774 
775  // Using GPU (flag) ->NOTE : default : only CPU
776  bool gpu_flag = false;
777  // Number of threads
778  string nb_threads = "1";
779 
780  // --------------------------------------------------------------------------------
781  // Miscellaneous settings
782  // --------------------------------------------------------------------------------
783 
784  // General verbose level
785  int verbose_general = 1;
786  // Specific verbose levels
787  int verbose_algo = -1;
788  int verbose_opti = -1;
789  int verbose_proj = -1;
790  int verbose_conv = -1;
791  int verbose_proc = -1;
792  int verbose_scan = -1;
793  int verbose_data = -1;
794  int verbose_defo = -1;
795  int verbose_dyna = -1;
796  int verbose_sens = -1;
797  // Path to config directory
798  string path_to_config_dir = "";
799  // Initial seed for random number generator
800  int64_t random_generator_seed = -1;
801  int nb_extra_random_generators = 0;
802 
803  // ============================================================================================================
804  // Read command-line parameters
805  // ============================================================================================================
806 
807  // TODO : replace remaining atoi, atof, etc, by ConvertFromString()
808 
809  // Must manually increment the option index when an argument is needed after an option
810  for (int i=1; i<argc; i++)
811  {
812 
813  // Get the option as a string
814  string option = (string)argv[i];
815 
816  // --------------------------------------------------------------------------------
817  // Miscellaneous settings
818  // --------------------------------------------------------------------------------
819 
820  // Show help
821  if (option=="-h" || option=="--help" || option=="-help")
822  {
823  ShowHelp();
824  Exit(EXIT_SUCCESS);
825  }
826  // Specific help for integrated scanners (managed by scanner manager)
827  else if (option=="-help-scan")
828  {
829  if(sScannerManager::GetInstance()->ShowScannersDescription())
830  Cerr("***** castor-recon() -> An error occurred when trying to output the available scanners from the scanner repository !'" << endl;);
831  Exit(EXIT_SUCCESS);
832  }
833  // Specific help for RCP-GS algorithm settings
834  else if (option=="-help-prob")
835  {
836  // TODO generalize this for a family of probabilistic algorithms
837  iRCPGSAlgorithm* alg = new iRCPGSAlgorithm();
838  alg->ShowHelpSpecific();
839  delete alg;
840  Exit(EXIT_SUCCESS);
841  }
842  // Specific help for optimizer settings (managed by optimizer children)
843  else if (option=="-help-opti")
844  {
846  Exit(EXIT_SUCCESS);
847  }
848  // Specific help for penalty settings (managed by penalty children)
849  else if (option=="-help-pnlt")
850  {
852  Exit(EXIT_SUCCESS);
853  }
854  // Specific help for projector settings (managed by projector children)
855  else if (option=="-help-projm")
856  {
857  // Call specific showHelp function from vProjector children
859  // Call the static showHelp function from vProjector
861  Exit(EXIT_SUCCESS);
862  }
863  // Specific help for image convolver settings (managed by image convolver children)
864  else if (option=="-help-conv")
865  {
866  // Call specific showHelp function from vImageConvolver children
868  // Call the static showHelp function from oImageConvolverManager
870  Exit(EXIT_SUCCESS);
871  }
872  // Specific help for image processing settings (managed by image processing children)
873  else if (option=="-help-proc")
874  {
875  // Call specific showHelp function from vImageProcessingModule children
877  // Call the static showHelp function from oImageProcessingManager
879  Exit(EXIT_SUCCESS);
880  }
881  // Specific help for dynamic model (managed by dynamic model children)
882  else if (option=="-help-dynamic-model")
883  {
885  Exit(EXIT_SUCCESS);
886  }
887  // Specific help for image deformation settings (managed by projector children)
888  else if (option=="-help-motion-model")
889  {
891  Exit(EXIT_SUCCESS);
892  }
893  // Specific help for input settings (managed by main)
894  else if (option=="-help-in")
895  {
896  ShowHelpInput();
897  Exit(EXIT_SUCCESS);
898  }
899  // Specific help for output settings (managed by main)
900  else if (option=="-help-out")
901  {
902  ShowHelpOutput();
903  Exit(EXIT_SUCCESS);
904  }
905  // Specific help for dimensions settings (managed by main)
906  else if (option=="-help-dim")
907  {
909  Exit(EXIT_SUCCESS);
910  }
911  // Specific help for optimizer settings (managed by main)
912  else if (option=="-help-algo")
913  {
914  ShowHelpAlgo();
915  Exit(EXIT_SUCCESS);
916  }
917  // Specific help for projector settings (managed by main)
918  else if (option=="-help-proj")
919  {
920  ShowHelpProj();
921  Exit(EXIT_SUCCESS);
922  }
923  // Specific help for image processing settings (managed by main)
924  else if (option=="-help-imgp")
925  {
926  ShowHelpImgp();
927  Exit(EXIT_SUCCESS);
928  }
929  // Specific help for computation settings (managed by main)
930  else if (option=="-help-comp")
931  {
933  Exit(EXIT_SUCCESS);
934  }
935  // Specific help for miscellaneous settings (managed by main)
936  else if (option=="-help-misc")
937  {
939  Exit(EXIT_SUCCESS);
940  }
941  // Specific help for dynamic settings (managed by main)
942  else if (option=="-help-dynamic")
943  {
944  ShowHelpDynamic();
945  Exit(EXIT_SUCCESS);
946  }
947  // Specific help for correction settings (managed by main)
948  else if (option=="-help-corr")
949  {
951  Exit(EXIT_SUCCESS);
952  }
953  // General verbosity level
954  else if (option=="-vb")
955  {
956  if (i>=argc-1)
957  {
958  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
959  Exit(EXIT_FAILURE);
960  }
961  if (ConvertFromString(argv[i+1], &verbose_general))
962  {
963  Cerr("***** castor-recon() -> Exception when trying to read provided verbosity level '" << verbose_general << " for option: " << option << endl);
964  Exit(EXIT_FAILURE);
965  }
966  i++;
967  }
968  // Algorithm verbosity level
969  else if (option=="-vb-algo")
970  {
971  if (i>=argc-1)
972  {
973  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
974  Exit(EXIT_FAILURE);
975  }
976  if (ConvertFromString(argv[i+1], &verbose_algo))
977  {
978  Cerr("***** castor-recon() -> Exception when trying to read provided verbosity level '" << verbose_algo << " for option: " << option << endl);
979  Exit(EXIT_FAILURE);
980  }
981  i++;
982  }
983  // Optimizer verbosity level
984  else if (option=="-vb-opti")
985  {
986  if (i>=argc-1)
987  {
988  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
989  Exit(EXIT_FAILURE);
990  }
991  if (ConvertFromString(argv[i+1], &verbose_opti))
992  {
993  Cerr("***** castor-recon() -> Exception when trying to read provided verbosity level '" << verbose_opti << " for option: " << option << endl);
994  Exit(EXIT_FAILURE);
995  }
996  i++;
997  }
998  // Projector verbosity level
999  else if (option=="-vb-proj")
1000  {
1001  if (i>=argc-1)
1002  {
1003  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1004  Exit(EXIT_FAILURE);
1005  }
1006  if (ConvertFromString(argv[i+1], &verbose_proj))
1007  {
1008  Cerr("***** castor-recon() -> Exception when trying to read provided verbosity level '" << verbose_proj << " for option: " << option << endl);
1009  Exit(EXIT_FAILURE);
1010  }
1011  i++;
1012  }
1013  // Image convolver verbosity level
1014  else if (option=="-vb-conv")
1015  {
1016  if (i>=argc-1)
1017  {
1018  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1019  Exit(EXIT_FAILURE);
1020  }
1021  if (ConvertFromString(argv[i+1], &verbose_conv))
1022  {
1023  Cerr("***** castor-recon() -> Exception when trying to read provided verbosity level '" << verbose_conv << " for option: " << option << endl);
1024  Exit(EXIT_FAILURE);
1025  }
1026  i++;
1027  }
1028  // Image processing verbosity level
1029  else if (option=="-vb-proc")
1030  {
1031  if (i>=argc-1)
1032  {
1033  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1034  Exit(EXIT_FAILURE);
1035  }
1036  if (ConvertFromString(argv[i+1], &verbose_proc))
1037  {
1038  Cerr("***** castor-recon() -> Exception when trying to read provided verbosity level '" << verbose_proc << " for option: " << option << endl);
1039  Exit(EXIT_FAILURE);
1040  }
1041  i++;
1042  }
1043  // Scanner verbosity level
1044  else if (option=="-vb-scan")
1045  {
1046  if (i>=argc-1)
1047  {
1048  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1049  Exit(EXIT_FAILURE);
1050  }
1051  if (ConvertFromString(argv[i+1], &verbose_scan))
1052  {
1053  Cerr("***** castor-recon() -> Exception when trying to read provided verbosity level '" << verbose_scan << " for option: " << option << endl);
1054  Exit(EXIT_FAILURE);
1055  }
1056  i++;
1057  }
1058  // Data and image verbosity level
1059  else if (option=="-vb-data")
1060  {
1061  if (i>=argc-1)
1062  {
1063  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1064  Exit(EXIT_FAILURE);
1065  }
1066  if (ConvertFromString(argv[i+1], &verbose_data))
1067  {
1068  Cerr("***** castor-recon() -> Exception when trying to read provided verbosity level '" << verbose_data << " for option: " << option << endl);
1069  Exit(EXIT_FAILURE);
1070  }
1071  i++;
1072  }
1073  // Deformation verbosity level
1074  else if (option=="-vb-defo")
1075  {
1076  if (i>=argc-1)
1077  {
1078  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1079  Exit(EXIT_FAILURE);
1080  }
1081  if (ConvertFromString(argv[i+1], &verbose_defo))
1082  {
1083  Cerr("***** castor-recon() -> Exception when trying to read provided verbosity level '" << verbose_defo << " for option: " << option << endl);
1084  Exit(EXIT_FAILURE);
1085  }
1086  i++;
1087  }
1088  // Dynamic verbosity level
1089  else if (option=="-vb-dyna")
1090  {
1091  if (i>=argc-1)
1092  {
1093  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1094  Exit(EXIT_FAILURE);
1095  }
1096  if (ConvertFromString(argv[i+1], &verbose_dyna))
1097  {
1098  Cerr("***** castor-recon() -> Exception when trying to read provided verbosity level '" << verbose_dyna << " for option: " << option << endl);
1099  Exit(EXIT_FAILURE);
1100  }
1101  i++;
1102  }
1103  // Sensitivity verbosity level
1104  else if (option=="-vb-sens")
1105  {
1106  if (i>=argc-1)
1107  {
1108  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1109  Exit(EXIT_FAILURE);
1110  }
1111  if (ConvertFromString(argv[i+1], &verbose_sens))
1112  {
1113  Cerr("***** castor-recon() -> Exception when trying to read provided verbosity level '" << verbose_sens << " for option: " << option << endl);
1114  Exit(EXIT_FAILURE);
1115  }
1116  i++;
1117  }
1118  // RNG seed
1119  else if (option=="-rng-seed")
1120  {
1121  if (i>=argc-1)
1122  {
1123  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1124  Exit(EXIT_FAILURE);
1125  }
1126  if(ConvertFromString(argv[i+1], &random_generator_seed))
1127  {
1128  Cerr("***** castor-recon() -> Exception when trying to read provided number '" << random_generator_seed << " for option: " << option << endl);
1129  Exit(EXIT_FAILURE);
1130  }
1131  i++;
1132  }
1133  // number of extra RNG
1134  else if (option=="-rng-extra")
1135  {
1136  if (i>=argc-1)
1137  {
1138  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1139  Exit(EXIT_FAILURE);
1140  }
1141  if(ConvertFromString(argv[i+1], &nb_extra_random_generators))
1142  {
1143  Cerr("***** castor-recon() -> Exception when trying to read provided number '" << nb_extra_random_generators << " for option: " << option << endl);
1144  Exit(EXIT_FAILURE);
1145  }
1146  i++;
1147  }
1148  // Path to config directory
1149  else if (option=="-conf")
1150  {
1151  if (i>=argc-1)
1152  {
1153  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1154  Exit(EXIT_FAILURE);
1155  }
1156  path_to_config_dir = (string)argv[i+1];
1157  i++;
1158  }
1159 
1160  // --------------------------------------------------------------------------------
1161  // Dimensions settings
1162  // --------------------------------------------------------------------------------
1163 
1164  // Dimensions: number of voxels
1165  else if (option=="-dim")
1166  {
1167  if (i>=argc-1)
1168  {
1169  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1170  Exit(EXIT_FAILURE);
1171  }
1172  INTNB input[3];
1173  if (ReadStringOption(argv[i+1], input, 3, ",", option))
1174  {
1175  Cerr("***** castor-recon() -> Invalid argument " << argv[i+1] << " for option " << option << " !" << endl);
1176  Exit(EXIT_FAILURE);
1177  }
1178  nb_voxX = input[0];
1179  nb_voxY = input[1];
1180  nb_voxZ = input[2];
1181  i++;
1182  }
1183  // Dimensions: size of the field-of-view in mm
1184  else if (option=="-fov")
1185  {
1186  if (i>=argc-1)
1187  {
1188  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1189  Exit(EXIT_FAILURE);
1190  }
1191  FLTNB input[3];
1192  if (ReadStringOption(argv[i+1], input, 3, ",", option))
1193  {
1194  Cerr("***** castor-recon() -> Invalid argument " << argv[i+1] << " for option " << option << " !" << endl);
1195  Exit(EXIT_FAILURE);
1196  }
1197  fov_sizeX = input[0];
1198  fov_sizeY = input[1];
1199  fov_sizeZ = input[2];
1200  i++;
1201  }
1202  // Dimensions: size of the voxels in mm
1203  else if (option=="-vox")
1204  {
1205  if (i>=argc-1)
1206  {
1207  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1208  Exit(EXIT_FAILURE);
1209  }
1210  FLTNB input[3];
1211  if (ReadStringOption(argv[i+1], input, 3, ",", option))
1212  {
1213  Cerr("***** castor-recon() -> Invalid argument " << argv[i+1] << " for option " << option << " !" << endl);
1214  Exit(EXIT_FAILURE);
1215  }
1216  vox_sizeX = input[0];
1217  vox_sizeY = input[1];
1218  vox_sizeZ = input[2];
1219  i++;
1220  }
1221  // Dimensions: offset of the image in mm
1222  else if (option=="-off")
1223  {
1224  if (i>=argc-1)
1225  {
1226  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1227  Exit(EXIT_FAILURE);
1228  }
1229  FLTNB input[3];
1230  if (ReadStringOption(argv[i+1], input, 3, ",", option))
1231  {
1232  Cerr("***** castor-recon() -> Invalid argument " << argv[i+1] << " for option " << option << " !" << endl);
1233  Exit(EXIT_FAILURE);
1234  }
1235  offsetX = input[0];
1236  offsetY = input[1];
1237  offsetZ = input[2];
1238  i++;
1239  }
1240  // Size of the output transaxial FOV in percentage
1241  else if (option=="-fov-out")
1242  {
1243  if (i>=argc-1)
1244  {
1245  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1246  Exit(EXIT_FAILURE);
1247  }
1248  fov_out = atof(argv[i+1]);
1249  i++;
1250  }
1251  // Number of slices to be masked at output
1252  else if (option=="-slice-out")
1253  {
1254  if (i>=argc-1)
1255  {
1256  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1257  Exit(EXIT_FAILURE);
1258  }
1259  slice_out = ((INTNB)(atoi(argv[i+1])));
1260  i++;
1261  }
1262  // Output flip
1263  else if (option=="-flip-out")
1264  {
1265  if (i>=argc-1)
1266  {
1267  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1268  Exit(EXIT_FAILURE);
1269  }
1270  flip_out = (string)(argv[i+1]);
1271  i++;
1272  }
1273 
1274  // --------------------------------------------------------------------------------
1275  // Dynamic settings
1276  // --------------------------------------------------------------------------------
1277 
1278  // Dimensions: number of frames
1279  else if (option=="-frm") // TODO: more checks to be done in the option reading
1280  {
1281  if (i>=argc-1)
1282  {
1283  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1284  Exit(EXIT_FAILURE);
1285  }
1286  frame_list = (string)argv[i+1];
1287  i++;
1288  }
1289  // Dimensions: number of respiratory gates
1290  else if (option=="-g")
1291  {
1292  if (i>=argc-1)
1293  {
1294  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1295  Exit(EXIT_FAILURE);
1296  }
1297  // Path to the dynamic file
1298  path_to_4D_data_splitting_file = ((string)argv[i+1]);
1299  // Recover number of respiratory gates from file
1300  if (ReadDataASCIIFile(path_to_4D_data_splitting_file, "nb_respiratory_gates", &nb_resp_gates, 1, KEYWORD_OPTIONAL) == KEYWORD_OPTIONAL_ERROR)
1301  {
1302  Cerr("***** castor-recon() -> Error when trying to read the number of respiratory gates in the file " << path_to_4D_data_splitting_file << " for option " << option << endl);
1303  Exit(EXIT_FAILURE);
1304  }
1305  // Recover number of cardiac gates from file
1306  if (ReadDataASCIIFile(path_to_4D_data_splitting_file, "nb_cardiac_gates", &nb_card_gates, 1, KEYWORD_OPTIONAL) == KEYWORD_OPTIONAL_ERROR)
1307  {
1308  Cerr("***** castor-recon() -> Error when trying to read the number of cardiac gates in the file " << path_to_4D_data_splitting_file << " for option " << option << endl);
1309  Exit(EXIT_FAILURE);
1310  }
1311  // Check for wrong initialization
1312  if (nb_resp_gates<1 || nb_card_gates <1)
1313  {
1314  Cerr("***** castor-recon() -> Incorrect initialization of the number of gates for the option: " << option << ". This number should be >= 1" << endl);
1315  Exit(EXIT_FAILURE);
1316  }
1317  i++;
1318  }
1319  // Time basis functions
1320  /*else if (option=="-time-basis") // TODO: Deactivate this option - is already incorporated in the -dynamic-model
1321  {
1322  if (i>=argc-1)
1323  {
1324  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1325  Exit(EXIT_FAILURE);
1326  }
1327  string input = argv[i+1];
1328  size_t column_pos = input.find_first_of(":");
1329  if (column_pos==string::npos)
1330  {
1331  Cerr("***** castor-recon() -> Incorrect argument after option " << option << ", ':' sign is missing !" << endl);
1332  Exit(EXIT_FAILURE);
1333  }
1334  string str = input.substr(0, column_pos);
1335  nb_time_basis = atoi(str.c_str());
1336  path_to_time_basis_coef = input.substr(column_pos+1);
1337  i++;
1338  }
1339  // Respiratory basis functions
1340  else if (option=="-resp-basis")
1341  {
1342  if (i>=argc-1)
1343  {
1344  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1345  Exit(EXIT_FAILURE);
1346  }
1347  string input = argv[i+1];
1348  size_t column_pos = input.find_first_of(":");
1349  if (column_pos==string::npos)
1350  {
1351  Cerr("***** castor-recon() -> Incorrect argument after option " << option << ", ':' sign is missing !" << endl);
1352  Exit(EXIT_FAILURE);
1353  }
1354  string str = input.substr(0, column_pos);
1355  nb_resp_basis = atoi(str.c_str());
1356  path_to_resp_basis_coef = input.substr(column_pos+1);
1357  i++;
1358  }
1359  // Cardiac basis functions
1360  else if (option=="-card-basis")
1361  {
1362  if (i>=argc-1)
1363  {
1364  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1365  Exit(EXIT_FAILURE);
1366  }
1367  string input = argv[i+1];
1368  size_t column_pos = input.find_first_of(":");
1369  if (column_pos==string::npos)
1370  {
1371  Cerr("***** castor-recon() -> Incorrect argument after option " << option << ", ':' sign is missing !" << endl);
1372  Exit(EXIT_FAILURE);
1373  }
1374  string str = input.substr(0, column_pos);
1375  nb_card_basis = atoi(str.c_str());
1376  path_to_card_basis_coef = input.substr(column_pos+1);
1377  i++;
1378  } */
1379 
1380  // Dynamic model applied to the frames/respiratory gates/cardiac gates of the dynamic acquisition
1381  else if (option=="-dynamic-model")
1382  {
1383  if (i>=argc-1)
1384  {
1385  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1386  Exit(EXIT_FAILURE);
1387  }
1388  dynamic_model_options = (string)argv[i+1];
1389  i++;
1390  }
1391  // Data for respiratory motion correction based on deformation
1392  else if (option=="-rm")
1393  {
1394  if (i>=argc-1)
1395  {
1396  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1397  Exit(EXIT_FAILURE);
1398  }
1399  resp_motion_options = (string)argv[i+1];
1400  i++;
1401  }
1402  // Data for cardiac motion correction based on deformation
1403  else if (option=="-cm")
1404  {
1405  if (i>=argc-1)
1406  {
1407  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1408  Exit(EXIT_FAILURE);
1409  }
1410  card_motion_options = (string)argv[i+1];
1411  i++;
1412  }
1413  // Data for respiratory and cardiac motion corrections based on deformation
1414  /*
1415  else if (option=="-rcm")
1416  {
1417  if (i>=argc-1)
1418  {
1419  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1420  Exit(EXIT_FAILURE);
1421  }
1422  double_motion_options = (string)argv[i+1];
1423  i++;
1424  }*/
1425  // Data for involuntary motion correction based on deformation
1426  else if (option=="-im")
1427  {
1428  if (i>=argc-1)
1429  {
1430  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1431  Exit(EXIT_FAILURE);
1432  }
1433  ipat_motion_options = (string)argv[i+1];
1434  i++;
1435  }
1436  // Data for involuntary motion correction based on deformation
1437  else if (option=="-qdyn")
1438  {
1439  if (i>=argc-1)
1440  {
1441  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1442  Exit(EXIT_FAILURE);
1443  }
1444  path_to_dynamic_quantification_file = (string)argv[i+1];
1445  i++;
1446  }
1447 
1448  // --------------------------------------------------------------------------------
1449  // Input settings
1450  // --------------------------------------------------------------------------------
1451 
1452  // DataFiles
1453  else if (option=="-df") // This is a mandatory option
1454  {
1455  if (i>=argc-1)
1456  {
1457  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1458  Exit(EXIT_FAILURE);
1459  }
1460  string file_name = (string)argv[i+1];
1461  path_to_data_filename.push_back(file_name);
1462  nb_beds++;
1463  i++;
1464  }
1465  // Invert datafile order
1466  else if (option=="-df-inv")
1467  {
1468  invert_datafile_bed_order_flag = true;
1469  }
1470  // Image for the initialisation of the algorithm : What should we do in case of multiple beds ? or multiple frames ? TODO
1471  else if (option=="-img")
1472  {
1473  if (i>=argc-1)
1474  {
1475  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1476  Exit(EXIT_FAILURE);
1477  }
1478  path_to_initial_img = argv[i+1];
1479  i++;
1480  }
1481  // Sensitivity image
1482  else if (option=="-sens")
1483  {
1484  if (i>=argc-1)
1485  {
1486  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1487  Exit(EXIT_FAILURE);
1488  }
1489 
1490  path_to_sensitivity_img = argv[i+1];
1491  i++;
1492  }
1493  // Normalization data files
1494  else if (option=="-norm")
1495  {
1496  if (i>=argc-1)
1497  {
1498  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1499  Exit(EXIT_FAILURE);
1500  }
1501  string file_name = (string)argv[i+1];
1502  path_to_normalization_filename.push_back(file_name);
1503  i++;
1504  }
1505 
1506  // Image for the attenuation
1507  else if (option=="-atn")
1508  {
1509  if (i>=argc-1)
1510  {
1511  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1512  Exit(EXIT_FAILURE);
1513  }
1514 
1515  path_to_attenuation_img = (string)argv[i+1];
1516 
1517  if (path_to_attenuation_img != "") // parse
1518  {
1519  // Retrieve nb of gated images from header if required
1520  Intf_fields IF;
1521  IntfKeyInitFields(&IF);
1522  if(IntfReadHeader(path_to_attenuation_img, &IF, 0) )
1523  {
1524  Cerr("***** castor-recon() -> An error occurred while trying to read the interfile header of attenuation file " << path_to_attenuation_img << " !" << endl);
1525  Exit(EXIT_FAILURE);
1526  }
1527  nb_atn_resp_imgs = IF.nb_resp_gates;
1528  nb_atn_card_imgs = IF.nb_card_gates;
1529  }
1530  i++;
1531  }
1532  // Multimodal images
1533  else if (option=="-multimodal")
1534  {
1535  if (i>=argc-1)
1536  {
1537  Cerr("***** Argument missing for option: " << option << endl);
1538  Exit(EXIT_FAILURE);
1539  }
1540  string file_name = (string)argv[i+1];
1541  path_to_multimodal_img.push_back(file_name);
1542  i++;
1543  }
1544  // Additional images (sinogram size)
1545  else if (option=="-additional-data")
1546  {
1547  if (i>=argc-1)
1548  {
1549  Cerr("***** Argument missing for option: " << option << endl);
1550  Exit(EXIT_FAILURE);
1551  }
1552  string file_name = (string)argv[i+1];
1553  path_to_additional_data.push_back(file_name);
1554  i++;
1555  }
1556  // Mask image
1557  else if (option=="-mask")
1558  {
1559  if (i>=argc-1)
1560  {
1561  Cerr("***** Argument missing for option: " << option << endl);
1562  Exit(EXIT_FAILURE);
1563  }
1564 
1565  path_to_mask_img = argv[i+1];
1566  i++;
1567  }
1568 
1569  // --------------------------------------------------------------------------------
1570  // Output settings
1571  // --------------------------------------------------------------------------------
1572 
1573  // Name of the output directory
1574  else if (option=="-dout") // This is a mandatory option
1575  {
1576  if (i>=argc-1)
1577  {
1578  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1579  Exit(EXIT_FAILURE);
1580  }
1581  path_dout = argv[i+1];
1582  i++;
1583  }
1584  // Base name of the output files
1585  else if (option=="-fout") // This is a mandatory option
1586  {
1587  if (i>=argc-1)
1588  {
1589  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1590  Exit(EXIT_FAILURE);
1591  }
1592  path_fout = argv[i+1];
1593  i++;
1594  }
1595  // List of iterations to be outputed
1596  else if (option=="-oit")
1597  {
1598  if (i>=argc-1)
1599  {
1600  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1601  Exit(EXIT_FAILURE);
1602  }
1603  output_iterations = (string)argv[i+1];
1604  i++;
1605  }
1606  // Output number precision
1607  else if (option=="-onbp")
1608  {
1609  if (i>=argc-1)
1610  {
1611  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1612  Exit(EXIT_FAILURE);
1613  }
1614  onb_prec = argv[i+1];
1615  i++;
1616  }
1617  // Flag to say that we want to save time basis functions too
1618  else if (option=="-omd")
1619  {
1620  merge_dynamic_imgs_flag = true;
1621  }
1622  // Flag to say that we want to save time basis functions too
1623  else if (option=="-olut")
1624  {
1625  save_LUT_flag = true;
1626  }
1627  // Flag to say that we want to save the sensitivity image for each subset/iteration in histogram mode
1628  else if (option=="-osens")
1629  {
1630  save_sens_histo = true;
1631  }
1632  // Flag to say that we want to save the image after each subset
1633  else if (option=="-osub")
1634  {
1635  save_subset_image = true;
1636  }
1637  // Flag to say that we want to save time basis functions too
1638  else if (option=="-odyn")
1639  {
1640  save_dynamic_basis_coefficients_flag = true;
1641  }
1642  // Flag to say that we exit directly after computing and saving the sensitivity
1643  else if (option=="-sens-only")
1644  {
1645  exit_after_sensitivity = true;
1646  }
1647  // Flag to say that we still want to compute global sensitivity from the input histogram file
1648  else if (option=="-sens-histo")
1649  {
1650  sensitivity_from_histogram = true;
1651  }
1652 
1653  // --------------------------------------------------------------------------------
1654  // Algorithm settings
1655  // --------------------------------------------------------------------------------
1656 
1657  // List of iterations/subsets
1658  else if (option=="-it") // This is a mandatory option
1659  {
1660  if (i>=argc-1)
1661  {
1662  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1663  Exit(EXIT_FAILURE);
1664  }
1665  nb_iterations_subsets = (string)argv[i+1];
1666  i++;
1667  }
1668  // Skip first iterations (default : 0)
1669  else if (option=="-skip-it")
1670  {
1671  if (i>=argc-1)
1672  {
1673  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1674  Exit(EXIT_FAILURE);
1675  }
1676  nb_skipped_iterations = (string)argv[i+1];
1677  i++;
1678  }
1679  // Optimizer settings
1680  else if (option=="-opti")
1681  {
1682  if (i>=argc-1)
1683  {
1684  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1685  Exit(EXIT_FAILURE);
1686  }
1687  options_optimizer = (string)argv[i+1];
1688  i++;
1689  }
1690  // Optimizer FOM
1691  else if (option=="-opti-fom")
1692  {
1693  optimizer_fom = true;
1694  }
1695  // Optimizer image update stat
1696  else if (option=="-opti-stat")
1697  {
1698  optimizer_stat = true;
1699  }
1700  // Penalty settings
1701  else if (option=="-pnlt")
1702  {
1703  if (i>=argc-1)
1704  {
1705  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1706  Exit(EXIT_FAILURE);
1707  }
1708  options_penalty = (string)argv[i+1];
1709  i++;
1710  }
1711 
1712  // RCP-GS algorithm settings
1713  else if (option=="-prob")
1714  {
1715  if (i>=argc-1)
1716  {
1717  Cerr("***** Argument missing for option: " << option << endl);
1718  Exit(EXIT_FAILURE);
1719  }
1720  options_prob = (string)argv[i+1];
1721  i++;
1722  }
1723  // Penalty strength
1724  else if (option=="-pnlt-beta")
1725  {
1726  if (i>=argc-1)
1727  {
1728  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1729  Exit(EXIT_FAILURE);
1730  }
1731  penalty_beta = (FLTNB)atof(argv[i+1]);
1732  i++;
1733  }
1734  // Image convolver settings
1735  else if (option=="-conv")
1736  {
1737  if (i>=argc-1)
1738  {
1739  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1740  Exit(EXIT_FAILURE);
1741  }
1742  string convolver = (string)argv[i+1];
1743  options_image_convolver.push_back(convolver);
1744  i++;
1745  }
1746  // Image processing settings
1747  else if (option=="-proc")
1748  {
1749  if (i>=argc-1)
1750  {
1751  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1752  Exit(EXIT_FAILURE);
1753  }
1754  string module = (string)argv[i+1];
1755  options_image_processing.push_back(module);
1756  i++;
1757  }
1758 
1759  // --------------------------------------------------------------------------------
1760  // Projection settings
1761  // --------------------------------------------------------------------------------
1762 
1763  // Projector settings
1764  else if (option=="-proj")
1765  {
1766  if (i>=argc-1)
1767  {
1768  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1769  Exit(EXIT_FAILURE);
1770  }
1771  options_projectorF = (string)argv[i+1];
1772  options_projectorB = (string)argv[i+1];
1773  i++;
1774  }
1775  // Forward projector settings
1776  else if (option=="-projF")
1777  {
1778  if (i>=argc-1)
1779  {
1780  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1781  Exit(EXIT_FAILURE);
1782  }
1783  options_projectorF = (string)argv[i+1];
1784  i++;
1785  }
1786  // Backward projector settings
1787  else if (option=="-projB")
1788  {
1789  if (i>=argc-1)
1790  {
1791  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1792  Exit(EXIT_FAILURE);
1793  }
1794  options_projectorB = (string)argv[i+1];
1795  i++;
1796  }
1797  // Common projector settings
1798  else if (option=="-proj-common")
1799  {
1800  if (i>=argc-1)
1801  {
1802  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1803  Exit(EXIT_FAILURE);
1804  }
1805  options_projector_common = (string)argv[i+1];
1806  i++;
1807  }
1808  // Ignore TOF flag
1809  else if (option=="-ignore-TOF")
1810  {
1811  ignore_TOF = true;
1812  }
1813  // Ignore POI flag
1814  else if (option=="-ignore-POI")
1815  {
1816  ignore_POI = true;
1817  }
1818  // Projection line computation strategy
1819  else if (option=="-proj-comp")
1820  {
1821  if (i>=argc-1)
1822  {
1823  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1824  Exit(EXIT_FAILURE);
1825  }
1826  projector_computation_strategy = atoi(argv[i+1]);
1827  i++;
1828  }
1829 
1830  // --------------------------------------------------------------------------------
1831  // Quantification settings
1832  // --------------------------------------------------------------------------------
1833 
1834  // Corrections settings
1835  else if (option=="-ignore-corr")
1836  {
1837  if (i>=argc-1)
1838  {
1839  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1840  Exit(EXIT_FAILURE);
1841  }
1842  ignored_corrections = (string)argv[i+1];
1843  i++;
1844  }
1845 
1846  // --------------------------------------------------------------------------------
1847  // Computation settings
1848  // --------------------------------------------------------------------------------
1849 
1850  // Flag to say that we want to use the GPU
1851  #ifdef CASTOR_GPU
1852  else if (option=="-gpu")
1853  {
1854  gpu_flag = 1;
1855  }
1856  #endif
1857  // Number of threads
1858  #ifdef CASTOR_OMP
1859  else if (option=="-th")
1860  {
1861  if (i>=argc-1)
1862  {
1863  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1864  Exit(EXIT_FAILURE);
1865  }
1866  nb_threads = (string)argv[i+1];
1867  i++;
1868  }
1869  #else
1870  else if (option=="-th")
1871  {
1872  if (i>=argc-1)
1873  {
1874  Cerr("***** castor-recon() -> Argument missing for option: " << option << endl);
1875  Exit(EXIT_FAILURE);
1876  }
1877  Cerr("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << endl);
1878  Cerr("!!!!! castor-recon() -> Option -th is available only if the code is compiled using the CASTOR_OMP environment variable set to 1 !" << endl);
1879  Cerr("!!!!! The execution will continue BUT WITH ONLY ONE THREAD !" << endl);
1880  Cerr("!!!!! We strongly advice to compile CASToR with OpenMP !" << endl);
1881  Cerr("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" << endl);
1882  i++;
1883  }
1884  #endif
1885 
1886  // --------------------------------------------------------------------------------
1887  // Unknown option!
1888  // --------------------------------------------------------------------------------
1889 
1890  else
1891  {
1892  Cerr("***** castor-recon() -> Unknown option '" << option << "' !" << endl);
1893  Exit(EXIT_FAILURE);
1894  }
1895  }
1896 
1897  // Synchronize MPI processes
1898  #ifdef CASTOR_MPI
1899  MPI_Barrier(MPI_COMM_WORLD);
1900  #endif
1901 
1902  // Affect specific verbose leves if not set
1903  if (verbose_algo==-1) verbose_algo = verbose_general;
1904  if (verbose_opti==-1) verbose_opti = verbose_general;
1905  if (verbose_proj==-1) verbose_proj = verbose_general;
1906  if (verbose_conv==-1) verbose_conv = verbose_general;
1907  if (verbose_proc==-1) verbose_proc = verbose_general;
1908  if (verbose_scan==-1) verbose_scan = verbose_general;
1909  if (verbose_data==-1) verbose_data = verbose_general;
1910  if (verbose_defo==-1) verbose_defo = verbose_general;
1911  if (verbose_dyna==-1) verbose_dyna = verbose_general;
1912  if (verbose_sens==-1) verbose_sens = verbose_general;
1913 
1914  // ============================================================================================================
1915  // Some checks
1916  // ============================================================================================================
1917 
1918  // Data files
1919  if (nb_beds < 1)
1920  {
1921  Cerr("***** castor-recon() -> Please provide at least one data filename !" << endl);
1922  Exit(EXIT_FAILURE);
1923  }
1924  // Output files
1925  if (path_fout.empty() && path_dout.empty())
1926  {
1927  Cerr("***** castor-recon() -> Please provide an output option for output files (-fout or -dout) !" << endl);
1928  Exit(EXIT_FAILURE);
1929  }
1930  // Check that only one option has been provided
1931  if (!path_fout.empty() && !path_dout.empty())
1932  {
1933  Cerr("***** castor-recon() -> Please provide either output option -fout or -dout but not both !" << endl);
1934  Exit(EXIT_FAILURE);
1935  }
1936 
1937  // Check if gated reconstruction is enabled but no file describing the gating of the data has been provided
1938  // TODO: maybe do it in the dynamic data manager if possible to clean this main as much as possible
1939  if ( (nb_resp_gates>1 || nb_card_gates>1) && path_to_4D_data_splitting_file.empty() )
1940  {
1941  Cerr("***** castor-recon() -> gating is enabled, but no file describing the splitting of the data has been provided (-g option) !" << endl);
1942  Exit(EXIT_FAILURE);
1943  }
1944 
1945  // check options consistence if RCP-GS algorithm
1946  if (!options_prob.empty())
1947  {
1948  if (!options_image_convolver.empty())
1949  {
1950  Cerr("***** castor-recon() -> Image convolution option is not compatible with the RCP-GS algorithm !" << endl);
1951  Exit(EXIT_FAILURE);
1952  }
1953  // check dynamic options
1954  if (!frame_list.empty() || !path_to_4D_data_splitting_file.empty())
1955  {
1956  Cerr("***** castor-recon() -> Dynamic reconstruction is not compatible with the RCP-GS algorithm !" << endl);
1957  Exit(EXIT_FAILURE);
1958  }
1959  if (nb_extra_random_generators!=2)
1960  {
1961  Cerr("***** castor-recon() -> The number of random generators must be 2 for the RCP-GS algorithm!" << endl);
1962  Exit(EXIT_FAILURE);
1963  }
1964  if (!options_penalty.empty())
1965  {
1966  Cerr("***** castor-recon() -> Penalties are not compatible with the RCP-GS algorithm !" << endl);
1967  Exit(EXIT_FAILURE);
1968  }
1969  }
1970 
1971  // ============================================================================================================
1972  // Singletons initialization: create here all needed singletons
1973  // ============================================================================================================
1974 
1975  if (verbose_general>=5) Cout("----- Singletons initializations ... -----" << endl);
1976 
1977  // Get user endianness (interfile I/O)
1979 
1980  // ----------------------------------------------------------------------------------------
1981  // Create sOutputManager
1982  // ----------------------------------------------------------------------------------------
1983  sOutputManager* p_outputManager = sOutputManager::GetInstance();
1984  // Set verbose level
1985  p_outputManager->SetVerbose(verbose_general);
1986  // Set MPI rank
1987  p_outputManager->SetMPIRank(mpi_rank);
1988  // Set output dynamic image policy
1989  p_outputManager->SetMergeDynImagesFlag(merge_dynamic_imgs_flag);
1990  // Set datafile name(s) in order to be able to recover them from interfile classes
1991  p_outputManager->SetDataFileName(path_to_data_filename);
1992  // Set output number precision
1993  p_outputManager->SetOutNbPrec(onb_prec);
1994 
1995 
1996  // Set path to the config directory
1997  if (p_outputManager->CheckConfigDir(path_to_config_dir))
1998  {
1999  Cerr("***** castor-recon() -> A problem occurred while checking for the config directory path !" << endl);
2000  Exit(EXIT_FAILURE);
2001  }
2002  // Initialize output directory and base name
2003  if (p_outputManager->InitOutputDirectory(path_fout, path_dout))
2004  {
2005  Cerr("***** castor-recon() -> A problem occurred while initializing output directory !" << endl);
2006  Exit(EXIT_FAILURE);
2007  }
2008  // General call verbose
2009  #ifdef CASTOR_VERSION
2010  Cout("castor-recon() -> Launch reconstruction from CASToR version " << CASTOR_VERSION << "." << endl);
2011  #endif
2012  // Log command line
2013  if (p_outputManager->LogCommandLine(argc,argv))
2014  {
2015  Cerr("***** castor-recon() -> A problem occurred while logging command line arguments !" << endl);
2016  Exit(EXIT_FAILURE);
2017  }
2018 
2019  // ----------------------------------------------------------------------------------------
2020  // Create oImageDimensionsAndQuantification
2021  // ----------------------------------------------------------------------------------------
2022 
2023  // Have to create it and set the number of threads before the scanner manager is used to compute the LUT,
2024  // because some scanners use multi-threading for better efficiency while computing the LUT.
2025  // However, the dimensions must not be set here because if not provided in the command line, they will be
2026  // read from the scanner configuration file right below.
2027  oImageDimensionsAndQuantification* p_ImageDimensionsAndQuantification = new oImageDimensionsAndQuantification();
2028  if (p_ImageDimensionsAndQuantification->SetNbThreads(nb_threads))
2029  {
2030  Cerr("***** castor-recon() -> A problem occurred while setting the number of threads !" << endl);
2031  Exit(EXIT_FAILURE);
2032  }
2033 
2034  // ----------------------------------------------------------------------------------------
2035  // Create sScannerManager
2036  // ----------------------------------------------------------------------------------------
2037  sScannerManager* p_ScannerManager = sScannerManager::GetInstance();
2038  p_ScannerManager->SetVerbose(verbose_scan);
2039  p_ScannerManager->SetImageDimensionsAndQuantification(p_ImageDimensionsAndQuantification);
2040  p_ScannerManager->SetSaveLUTFlag(save_LUT_flag);
2041 
2042  if (verbose_general>=5) Cout("----- Geometry Initialization ... -----" << endl);
2043 
2044  // TODO: put all that stuff into only one function taking the path_to_data_filename[0] as the only parameter
2045 
2046  // Get system name from the dataFile
2047  string scanner_name = "";
2048  if (ReadDataASCIIFile(path_to_data_filename[0], "Scanner name", &scanner_name, 1, KEYWORD_MANDATORY))
2049  {
2050  Cerr("***** castor-recon() -> A problem occurred while trying to find the system name in the datafile header !" << endl);
2051  Exit(EXIT_FAILURE);
2052  }
2053  if (p_ScannerManager->FindScannerSystem(scanner_name) )
2054  {
2055  Cerr("***** castor-recon() -> A problem occurred while searching for scanner system !" << endl);
2056  Exit(EXIT_FAILURE);
2057  }
2058  if (p_ScannerManager->BuildScannerObject() )
2059  {
2060  Cerr("***** castor-recon() -> A problem occurred during scanner object construction ! !" << endl);
2061  Exit(EXIT_FAILURE);
2062  }
2063  if (p_ScannerManager->InstantiateScanner() )
2064  {
2065  Cerr("***** castor-recon() -> A problem occurred while creating Scanner object !" << endl);
2066  Exit(EXIT_FAILURE);
2067  }
2068  if (p_ScannerManager->GetGeometricInfoFromDataFile(path_to_data_filename[0]))
2069  {
2070  Cerr("***** castor-recon() -> A problem occurred while retrieving scanner fields from the datafile header !" << endl);
2071  Exit(EXIT_FAILURE);
2072  }
2073  if (p_ScannerManager->BuildLUT() )
2074  {
2075  Cerr("***** castor-recon() -> A problem occurred while generating/reading the LUT !" << endl);
2076  Exit(EXIT_FAILURE);
2077  }
2078  // Check the scanner manager parameters and initialize the scanner
2079  if (p_ScannerManager->CheckParameters())
2080  {
2081  Cerr("***** castor-recon() -> A problem occurred while checking scanner manager parameters !" << endl);
2082  Exit(EXIT_FAILURE);
2083  }
2084  if (p_ScannerManager->Initialize())
2085  {
2086  Cerr("***** castor-recon() -> A problem occurred while initializing scanner !" << endl);
2087  Exit(EXIT_FAILURE);
2088  }
2089 
2090  // If no number of voxels provided, then get the default ones from the scanner
2091  if (nb_voxX<=0 || nb_voxY<=0 || nb_voxZ<=0)
2092  {
2093  if (ReadDataASCIIFile(p_ScannerManager->GetPathToScannerFile(), "voxels number transaxial", &nb_voxX, 1, KEYWORD_MANDATORY))
2094  {
2095  Cerr("***** castor-recon() -> A problem occurred while reading for default number of transaxial voxels !" << endl);
2096  Exit(EXIT_FAILURE);
2097  }
2098  if (ReadDataASCIIFile(p_ScannerManager->GetPathToScannerFile(), "voxels number transaxial", &nb_voxY, 1, KEYWORD_MANDATORY))
2099  {
2100  Cerr("***** castor-recon() -> A problem occurred while reading for default number of transaxial voxels !" << endl);
2101  Exit(EXIT_FAILURE);
2102  }
2103  if (ReadDataASCIIFile(p_ScannerManager->GetPathToScannerFile(), "voxels number axial", &nb_voxZ, 1, KEYWORD_MANDATORY))
2104  {
2105  Cerr("***** castor-recon() -> A problem occurred while reading for default number of axial voxels !" << endl);
2106  Exit(EXIT_FAILURE);
2107  }
2108  }
2109  // If no FOV nor VOX size provided, then get the default one
2110  if ( (fov_sizeX<=0 || fov_sizeY<=0 || fov_sizeZ<=0) && (vox_sizeX<=0 || vox_sizeY<=0 || vox_sizeZ<=0) )
2111  {
2112  if (ReadDataASCIIFile(p_ScannerManager->GetPathToScannerFile(), "field of view transaxial", &fov_sizeX, 1, KEYWORD_MANDATORY))
2113  {
2114  Cerr("***** castor-recon() -> A problem occurred while reading for default transaxial FOV size !" << endl);
2115  Exit(EXIT_FAILURE);
2116  }
2117  if (ReadDataASCIIFile(p_ScannerManager->GetPathToScannerFile(), "field of view transaxial", &fov_sizeY, 1, KEYWORD_MANDATORY))
2118  {
2119  Cerr("***** castor-recon() -> A problem occurred while reading for default transaxial FOV size !" << endl);
2120  Exit(EXIT_FAILURE);
2121  }
2122  if (ReadDataASCIIFile(p_ScannerManager->GetPathToScannerFile(), "field of view axial", &fov_sizeZ, 1, KEYWORD_MANDATORY))
2123  {
2124  Cerr("***** castor-recon() -> A problem occurred while reading for default axial FOV size !" << endl);
2125  Exit(EXIT_FAILURE);
2126  }
2127  }
2128 
2129  if (verbose_general>=5) Cout("----- Geometry Initialization OK -----" << endl);
2130 
2131  // ----------------------------------------------------------------------------------------
2132  // Create oImageDimensionsAndQuantification
2133  // ----------------------------------------------------------------------------------------
2134 
2135  if (verbose_general>=5) Cout("----- Image dimensions initialization ... -----" << endl);
2136 
2137  p_ImageDimensionsAndQuantification->SetNbBeds(nb_beds);
2138  p_ImageDimensionsAndQuantification->SetNbVoxX(nb_voxX);
2139  p_ImageDimensionsAndQuantification->SetNbVoxY(nb_voxY);
2140  p_ImageDimensionsAndQuantification->SetNbVoxZ(nb_voxZ);
2141  p_ImageDimensionsAndQuantification->SetVoxSizeX(vox_sizeX);
2142  p_ImageDimensionsAndQuantification->SetVoxSizeY(vox_sizeY);
2143  p_ImageDimensionsAndQuantification->SetVoxSizeZ(vox_sizeZ);
2144  p_ImageDimensionsAndQuantification->SetFOVSizeX(fov_sizeX);
2145  p_ImageDimensionsAndQuantification->SetFOVSizeY(fov_sizeY);
2146  p_ImageDimensionsAndQuantification->SetFOVSizeZ(fov_sizeZ);
2147  p_ImageDimensionsAndQuantification->SetFOVOutMasking(fov_out,slice_out);
2148  p_ImageDimensionsAndQuantification->SetOffsetX(offsetX);
2149  p_ImageDimensionsAndQuantification->SetOffsetY(offsetY);
2150  p_ImageDimensionsAndQuantification->SetOffsetZ(offsetZ);
2151  p_ImageDimensionsAndQuantification->SetMPIRankAndSize(mpi_rank, mpi_size);
2152  p_ImageDimensionsAndQuantification->SetVerbose(verbose_data);
2153  p_ImageDimensionsAndQuantification->SetIgnoredCorrections(ignored_corrections);
2154  p_ImageDimensionsAndQuantification->SetFrames(frame_list);
2155  p_ImageDimensionsAndQuantification->SetNbMultiModalImages(path_to_multimodal_img.size());
2156  if (p_ImageDimensionsAndQuantification->SetFlipOut(flip_out))
2157  {
2158  Cerr("***** castor-recon() -> A problem occurred while setting the output flip option !" << endl);
2159  Exit(EXIT_FAILURE);
2160  }
2161  // TODO: Remove Respiratory gating, Cardiac gating and Dynamic
2162  if (resp_motion_options=="" && double_motion_options=="")
2163  {
2164  p_ImageDimensionsAndQuantification->SetNbRespGates(nb_resp_gates);
2165  p_ImageDimensionsAndQuantification->SetNbRespBasisFunctions(nb_resp_basis);
2166  p_ImageDimensionsAndQuantification->SetRespBasisFunctionsFile(path_to_resp_basis_coef);
2167  }
2168  else
2169  {
2170  if (path_to_resp_basis_coef!="")
2171  {
2172  Cerr("***** castor-recon() -> Cannot use both respiratory motion correction and respiratory basis functions, it has no sense !" << endl);
2173  Exit(EXIT_FAILURE);
2174  }
2175  // Set only one gate here because we correct for motion, so we reconstruct only one image
2176  p_ImageDimensionsAndQuantification->SetNbRespGates(1);
2177  }
2178  if (card_motion_options=="" && double_motion_options=="")
2179  {
2180  p_ImageDimensionsAndQuantification->SetNbCardGates(nb_card_gates);
2181  p_ImageDimensionsAndQuantification->SetNbCardBasisFunctions(nb_card_basis);
2182  p_ImageDimensionsAndQuantification->SetCardBasisFunctionsFile(path_to_card_basis_coef);
2183  }
2184  else
2185  {
2186  if (path_to_card_basis_coef!="")
2187  {
2188  Cerr("***** castor-recon() -> Cannot use both cardiac motion correction and cardiac basis functions, it has no sense !" << endl);
2189  Exit(EXIT_FAILURE);
2190  }
2191  // Set only one gate here because we correct for motion, so we reconstruct only one image
2192  p_ImageDimensionsAndQuantification->SetNbCardGates(1);
2193  }
2194  if (p_ImageDimensionsAndQuantification->CheckParameters())
2195  {
2196  Cerr("***** castor-recon() -> A problem occurred while checking image dimensions parameters !" << endl);
2197  Exit(EXIT_FAILURE);
2198  }
2199  if (p_ImageDimensionsAndQuantification->Initialize())
2200  {
2201  Cerr("***** castor-recon() -> A problem occurred while initializing image dimensions !" << endl);
2202  Exit(EXIT_FAILURE);
2203  }
2204  /* Initialization of DynamicDataManager class, related 4D data splitting management
2205  if (p_ImageDimensionsAndQuantification->InitDynamicData(path_to_4D_data_splitting_file,
2206  !resp_motion_options.empty(),
2207  !card_motion_options.empty(),
2208  !ipat_motion_options.empty(),
2209  nb_resp_gates,
2210  nb_card_gates) )
2211  {
2212  Cerr("***** castor-recon() -> A problem occurred while initializing Dynamic data manager's class !" << endl);
2213  Exit(EXIT_FAILURE);
2214  }
2215  // Get the number of events in the data from the header (in order to check consistency between
2216  // the number of events in the datafile and in the dynamic files, if any gating is enabled)
2217  int64_t nb_events = 0;
2218  ReadDataASCIIFile(path_to_data_filename[0], "Number of events", &nb_events, 1, KEYWORD_MANDATORY);
2219  // Check dynamic parameters
2220  if (p_ImageDimensionsAndQuantification->CheckDynamicParameters(nb_events) )
2221  {
2222  Cerr("***** castor-recon() -> A problem occurred while checking Dynamic data manager's parameters !" << endl);
2223  Exit(EXIT_FAILURE);
2224  }
2225  // Initialize dynamic specific quantitative factors
2226  if (p_ImageDimensionsAndQuantification->SetDynamicSpecificQuantificationFactors(path_to_dynamic_quantification_file) )
2227  {
2228  Cerr("***** castor-recon() -> A problem occurred while initializing specific dynamic quantification factors!" << endl);
2229  Exit(EXIT_FAILURE);
2230  }
2231  */
2232  if (verbose_general>=5) Cout("----- Image dimensions initialization OK -----" << endl);
2233 
2234  // ----------------------------------------------------------------------------------------
2235  // Create the image space
2236  // ----------------------------------------------------------------------------------------
2237 
2238  oImageSpace* p_ImageSpace = new oImageSpace();
2239  p_ImageSpace->SetImageDimensionsAndQuantification(p_ImageDimensionsAndQuantification);
2240  p_ImageSpace->SetVerbose(verbose_data);
2241 
2242  // ----------------------------------------------------------------------------------------
2243  // If mask image provided, load it using ImageSpace and store it into ImageDimensionsAndQuantification
2244  // ----------------------------------------------------------------------------------------
2245 
2246  if (!path_to_mask_img.empty())
2247  {
2248  if (p_ImageSpace->InitMaskImage(path_to_mask_img))
2249  {
2250  Cerr("The option for using a mask image is set, but the mask image is not provided or could not be loaded !" << endl);
2251  Exit(EXIT_FAILURE);
2252  }
2253  p_ImageDimensionsAndQuantification->ProcessAndSetMask(p_ImageSpace->mp_maskImage);
2254  p_ImageSpace->DeallocateMaskImage();
2255  }
2256 
2257 
2258  // ----------------------------------------------------------------------------------------
2259  // Random Number Generator initialization: (we first require to know the number of threads to use from p_ImageDimensionsAndQuantification)
2260  // ----------------------------------------------------------------------------------------
2261 
2262  if (verbose_general>=5) Cout("----- Random number generator initialization ... -----" << endl);
2263 
2264  sRandomNumberGenerator* p_RandomNumberGenerator = sRandomNumberGenerator::GetInstance();
2265  p_RandomNumberGenerator->SetVerbose(verbose_general);
2266  // Use a user-provided seed to initialize the RNG if one has been provided. Use random number otherwise.
2267  if (random_generator_seed>=0) p_RandomNumberGenerator->Initialize(random_generator_seed, p_ImageDimensionsAndQuantification->GetNbThreadsMax(), nb_extra_random_generators);
2268  else p_RandomNumberGenerator->Initialize(p_ImageDimensionsAndQuantification->GetNbThreadsMax(), nb_extra_random_generators);
2269 
2270  if (verbose_general >=5) Cout("----- Random number generator initialization OK -----" << endl);
2271 
2272  // ----------------------------------------------------------------------------------------
2273  // Create vDataFile
2274  // ----------------------------------------------------------------------------------------
2275 
2276  if (verbose_general>=5) Cout("----- DataFile initialization ... -----" << endl);
2277 
2278  vDataFile** p_DataFile = new vDataFile*[nb_beds];
2279 
2280  if (p_ScannerManager->GetScannerType() == SCANNER_PET)
2281  {
2282  // Create specific data file
2283  for (int i=0 ; i<nb_beds ; i++)
2284  {
2285  p_DataFile[i] = new iDataFilePET();
2286  (dynamic_cast<iDataFilePET*>(p_DataFile[i]))->SetIgnoreTOFFlag(ignore_TOF);
2287  }
2288  }
2289  else if (p_ScannerManager->GetScannerType() == SCANNER_SPECT_CONVERGENT)
2290  {
2291  // Create specific data file
2292  for (int i=0 ; i<nb_beds ; i++)
2293  {
2294  p_DataFile[i] = new iDataFileSPECT();
2295  }
2296  }
2297  else if (p_ScannerManager->GetScannerType() == SCANNER_CT)
2298  {
2299  // Create specific data file
2300  for (int i=0 ; i<nb_beds ; i++)
2301  {
2302  p_DataFile[i] = new iDataFileCT();
2303  }
2304  }
2305  // Unknown scanner
2306  else
2307  {
2308  Cerr("***** castor-recon() -> Unknown scanner type (" << p_ScannerManager->GetScannerType() << ") for datafile construction ! Abort." << endl);
2309  Exit(EXIT_FAILURE);
2310  }
2311 
2312  // Check that the number of supplied additional data is consistent with the number of datafiles corresponding to the number of bed positions
2313  if (path_to_additional_data.size()!=0 && path_to_additional_data.size()!=((size_t)nb_beds))
2314  {
2315  Cerr("***** castor-recon() -> There must be as many supplied additional data options as number of bed positions !" << endl);
2316  Exit(EXIT_FAILURE);
2317  }
2318 
2319  // Load raw data in memory and do other stuff if needed.
2320  for (int bed=0 ; bed<nb_beds ; bed++)
2321  {
2322  // If it is asked to revert the order of the bed positions, then we proceed here
2323  if (invert_datafile_bed_order_flag) p_DataFile[bed]->SetHeaderDataFileName(path_to_data_filename.at(nb_beds-1-bed));
2324  else p_DataFile[bed]->SetHeaderDataFileName(path_to_data_filename.at(bed));
2325  p_DataFile[bed]->SetBedIndex(bed);
2326  p_DataFile[bed]->SetVerbose(verbose_data);
2327  p_DataFile[bed]->SetImageDimensionsAndQuantification(p_ImageDimensionsAndQuantification);
2328  p_DataFile[bed]->SetIgnorePOIFlag(ignore_POI);
2329  if (p_DataFile[bed]->ReadInfoInHeader())
2330  {
2331  Cerr("***** castor-recon() -> A problem occurred during datafile header reading ! Abort." << endl);
2332  Exit(EXIT_FAILURE);
2333  }
2334  if (p_DataFile[bed]->CheckParameters())
2335  {
2336  Cerr("***** castor-recon() -> A problem occurred while checking datafile parameters ! Abort." << endl);
2337  Exit(EXIT_FAILURE);
2338  }
2339  if (p_DataFile[bed]->ComputeSizeEvent())
2340  {
2341  Cerr("***** castor-recon() -> A problem occurred in datafile initialization ! Abort." << endl);
2342  Exit(EXIT_FAILURE);
2343  }
2344  if (p_DataFile[bed]->InitializeMappedFile())
2345  {
2346  Cerr("***** castor-recon() -> A problem occurred in datafile initialization ! Abort." << endl);
2347  Exit(EXIT_FAILURE);
2348  }
2349  if (p_DataFile[bed]->PrepareDataFile())
2350  {
2351  Cerr("***** castor-recon() -> A problem occurred in datafile preparation ! Abort." << endl);
2352  Exit(EXIT_FAILURE);
2353  }
2354  if (path_to_additional_data.size()!=0 && p_DataFile[bed]->InitializeAdditionalData(path_to_additional_data[bed]))
2355  {
2356  Cerr("***** castor-recon() -> A problem occured during additional data initialization !" << endl);
2357  Exit(EXIT_FAILURE);
2358  }
2359  }
2360  // Check consistency between all datafiles; to do that we compare the first with all the others
2361  for (int bed=1; bed<nb_beds; bed++)
2362  {
2363  if (p_DataFile[0]->CheckConsistencyWithAnotherBedDataFile(p_DataFile[bed]))
2364  {
2365  int bed_index_problem = bed + 1;
2366  if (invert_datafile_bed_order_flag) bed_index_problem = nb_beds - bed;
2367  Cerr("***** castor-recon() -> A problem occurred while checking consistency between first bed and bed " << bed_index_problem << " !" << endl);
2368  Exit(EXIT_FAILURE);
2369  }
2370  }
2371  // And finally, deal with the multiple bed positions
2372  if (p_ImageDimensionsAndQuantification->DealWithBedPositions(p_DataFile))
2373  {
2374  Cerr("***** castor-recon() -> A problem occurred while dealing with the bed positions !" << endl);
2375  Exit(EXIT_FAILURE);
2376  }
2377 
2378  if (verbose_general>=5) Cout("----- DataFile initialization OK -----" << endl);
2379 
2380  // Initialization of DynamicDataManager class, related 4D data splitting management
2381  if (verbose_general>=5) Cout("----- Dynamic Data Manager initialization ... -----" << endl);
2382 
2383 
2384  if (p_ImageDimensionsAndQuantification->InitDynamicData(path_to_4D_data_splitting_file,
2385  !resp_motion_options.empty(),
2386  !card_motion_options.empty(),
2387  !ipat_motion_options.empty(),
2388  nb_resp_gates,
2389  nb_card_gates) )
2390  {
2391  Cerr("***** castor-recon() -> A problem occurred while initializing Dynamic data manager's class !" << endl);
2392  Exit(EXIT_FAILURE);
2393  }
2394  // Get the number of events in the data from the header (in order to check consistency between
2395  // the number of events in the datafile and in the dynamic files, if any gating is enabled)
2396  int64_t nb_events = 0;
2397  ReadDataASCIIFile(path_to_data_filename[0], "Number of events", &nb_events, 1, KEYWORD_MANDATORY);
2398  // Check dynamic parameters
2399  if (p_ImageDimensionsAndQuantification->CheckDynamicParameters(nb_events) )
2400  {
2401  Cerr("***** castor-recon() -> A problem occurred while checking Dynamic data manager's parameters !" << endl);
2402  Exit(EXIT_FAILURE);
2403  }
2404  // Initialize dynamic specific quantitative factors
2405  if (p_ImageDimensionsAndQuantification->SetDynamicSpecificQuantificationFactors(path_to_dynamic_quantification_file) )
2406  {
2407  Cerr("***** castor-recon() -> A problem occurred while initializing specific dynamic quantification factors!" << endl);
2408  Exit(EXIT_FAILURE);
2409  }
2410 
2411  if (verbose_general>=5) Cout("----- Dynamic Data Manager initialization OK -----" << endl);
2412 
2413  // ----------------------------------------------------------------------------------------
2414  // Create Projector Manager
2415  // ----------------------------------------------------------------------------------------
2416 
2417  // Verbose
2418  if (verbose_general>=5) Cout("----- Projector initialization ... -----" << endl);
2419  // Create object
2420  oProjectorManager* p_ProjectorManager = new oProjectorManager();
2421  // Set all parameters
2422  p_ProjectorManager->SetScanner(p_ScannerManager->GetScannerObject());
2423  p_ProjectorManager->SetImageDimensionsAndQuantification(p_ImageDimensionsAndQuantification);
2424  p_ProjectorManager->SetDataFile(p_DataFile[0]);
2425  p_ProjectorManager->SetComputationStrategy(projector_computation_strategy);
2426  p_ProjectorManager->SetOptionsForward(options_projectorF);
2427  p_ProjectorManager->SetOptionsBackward(options_projectorB);
2428  p_ProjectorManager->SetOptionsCommon(options_projector_common);
2429  p_ProjectorManager->SetVerbose(verbose_proj);
2430  // Check parameters
2431  if (p_ProjectorManager->CheckParameters())
2432  {
2433  Cerr("***** castor-recon() -> A problem occurred while checking projector manager's parameters !" << endl);
2434  Exit(EXIT_FAILURE);
2435  }
2436  // Initialize projector manager
2437  if (p_ProjectorManager->Initialize())
2438  {
2439  Cerr("***** castor-recon() -> A problem occurred while initializing projector manager !" << endl);
2440  Exit(EXIT_FAILURE);
2441  }
2442  // Check specific requirements for SPECT with attenuation correction
2443  if (p_ProjectorManager->CheckSPECTAttenuationCompatibility(path_to_attenuation_img))
2444  {
2445  Cerr("***** castor-recon() -> A problem occurred while checking projector's compatibility with SPECT and attenuation correction !" << endl);
2446  Exit(EXIT_FAILURE);
2447  }
2448  // Verbose
2449  if (verbose_general>=5) Cout("----- Projector initialization OK -----" << endl);
2450 
2451  // ----------------------------------------------------------------------------------------
2452  // Create Dynamic Model Manager
2453  // ----------------------------------------------------------------------------------------
2454 
2455  // Verbose
2456  if (verbose_general>=5) Cout("----- Dynamic model initialization (if any) ... -----" << endl);
2457  // Create object
2458  oDynamicModelManager* p_DynamicModelManager = new oDynamicModelManager();
2459  // Set all parameters
2460  p_DynamicModelManager->SetImageDimensionsAndQuantification(p_ImageDimensionsAndQuantification);
2461  p_DynamicModelManager->SetOptions(dynamic_model_options);
2462  p_DynamicModelManager->SetVerbose(verbose_dyna);
2463  p_DynamicModelManager->SetUseModelInReconstruction(true);
2464  // Check parameters
2465  if (p_DynamicModelManager->CheckParameters())
2466  {
2467  Cerr("***** castor-recon() -> A problem occurred while checking dynamic model manager's parameters !" << endl);
2468  Exit(EXIT_FAILURE);
2469  }
2470  // Initialize dynamic model manager
2471  int DynamicModelinitialisation = p_DynamicModelManager->Initialize();
2472  if (DynamicModelinitialisation ==1)
2473  {
2474  Cerr("***** castor-recon() -> A problem occurred while initializing dynamic model manager !" << endl);
2475  Exit(EXIT_FAILURE);
2476  }
2477  // Case of no parameters given -> meaning seting of diagonal basis fucntions on ImageDimensionsandQuantification
2478  else if (DynamicModelinitialisation ==2)
2479  {
2480  Cout( "----- Dynamic model: No parameters given - setting diagonal basis functions !" << endl);
2481  }
2482 
2483  // Verbose
2484  if (verbose_general>=5) Cout("----- Dynamic model initialization OK -----" << endl);
2485 
2486 
2487  // ----------------------------------------------------------------------------------------
2488  // Create Optimizer Manager
2489  // ----------------------------------------------------------------------------------------
2490 
2491  // Verbose
2492  if (verbose_general>=5) Cout("----- Optimizer initialization ... -----" << endl);
2493  // Create object
2494  oOptimizerManager* p_OptimizerManager = new oOptimizerManager();
2495  // Set all parameters
2496  p_OptimizerManager->SetImageDimensionsAndQuantification(p_ImageDimensionsAndQuantification);
2497  p_OptimizerManager->SetImageSpace(p_ImageSpace);
2498  p_OptimizerManager->SetDataMode(p_DataFile[0]->GetDataMode());
2499  p_OptimizerManager->SetDataType(p_DataFile[0]->GetDataType());
2500  p_OptimizerManager->SetDataSpec(p_DataFile[0]->GetDataSpec());
2501  p_OptimizerManager->SetDataFile(p_DataFile[0]);
2502  p_OptimizerManager->SetOptionsOptimizer(options_optimizer);
2503  p_OptimizerManager->SetOptimizerFOMFlag(optimizer_fom);
2504  p_OptimizerManager->SetOptimizerImageStatFlag(optimizer_stat);
2505  p_OptimizerManager->SetOptionsPenalty(options_penalty,penalty_beta);
2506  p_OptimizerManager->SetNbTOFBins(p_ProjectorManager->GetNbTOFBins());
2507  p_OptimizerManager->SetVerbose(verbose_opti);
2508  // Check parameters
2509  if (p_OptimizerManager->CheckParameters())
2510  {
2511  Cerr("***** castor-recon() -> A problem occurred while checking optimizer manager's parameters !" << endl);
2512  Exit(EXIT_FAILURE);
2513  }
2514  // Initialize optimizer manager
2515  if (p_OptimizerManager->Initialize())
2516  {
2517  Cerr("***** castor-recon() -> A problem occurred while initializing optimizer manager !" << endl);
2518  Exit(EXIT_FAILURE);
2519  }
2520  // Verbose
2521  if (verbose_general>=5) Cout("----- Optimizer initialization OK -----" << endl);
2522 
2523  // ----------------------------------------------------------------------------------------
2524  // Create Image Convolver Manager
2525  // ----------------------------------------------------------------------------------------
2526 
2527  // Verbose
2528  if (verbose_general>=5) Cout("----- Image Convolver initialization (if any) ... -----" << endl);
2529  // Create object
2530  oImageConvolverManager* p_ImageConvolverManager = new oImageConvolverManager();
2531  // Set all parameters
2532  p_ImageConvolverManager->SetVerbose(verbose_conv);
2533  p_ImageConvolverManager->SetImageDimensionsAndQuantification(p_ImageDimensionsAndQuantification);
2534  p_ImageConvolverManager->SetOptions(options_image_convolver);
2535  // Check parameters
2536  if (p_ImageConvolverManager->CheckParameters())
2537  {
2538  Cerr("***** castor-recon() -> A problem occurred while checking image convolver manager's parameters !" << endl);
2539  Exit(EXIT_FAILURE);
2540  }
2541  // Initialize image convolver manager
2542  if (p_ImageConvolverManager->Initialize())
2543  {
2544  Cerr("***** castor-recon() -> A problem occurred while initializing image convolver manager !" << endl);
2545  Exit(EXIT_FAILURE);
2546  }
2547  // Verbose
2548  if (verbose_general>=5) Cout("----- Image Convolver initialization OK -----" << endl);
2549 
2550  // ----------------------------------------------------------------------------------------
2551  // Create Image Processing Manager
2552  // ----------------------------------------------------------------------------------------
2553 
2554  // Verbose
2555  if (verbose_general>=5) Cout("----- Image Processing initialization (if any) ... -----" << endl);
2556  // Create object
2557  oImageProcessingManager* p_ImageProcessingManager = new oImageProcessingManager();
2558  // Set all parameters
2559  p_ImageProcessingManager->SetVerbose(verbose_proc);
2560  p_ImageProcessingManager->SetImageDimensionsAndQuantification(p_ImageDimensionsAndQuantification);
2561  p_ImageProcessingManager->SetOptions(options_image_processing);
2562  // Check parameters
2563  if (p_ImageProcessingManager->CheckParameters())
2564  {
2565  Cerr("***** castor-recon() -> A problem occurred while checking image processing manager's parameters !" << endl);
2566  Exit(EXIT_FAILURE);
2567  }
2568  // Initialize image processing manager
2569  if (p_ImageProcessingManager->Initialize())
2570  {
2571  Cerr("***** castor-recon() -> A problem occurred while initializing image processing manager !" << endl);
2572  Exit(EXIT_FAILURE);
2573  }
2574  // Verbose
2575  if (verbose_general>=5) Cout("----- Image Processing initialization OK -----" << endl);
2576 
2577 
2578  // ----------------------------------------------------------------------------------------
2579  // Create Deformation Manager
2580  // ----------------------------------------------------------------------------------------
2581 
2582  // Verbose
2583  if (verbose_general>=5) Cout("----- Image deformation initialization (if any) ... -----" << endl);
2584  // Create object
2585  oDeformationManager* p_DeformationManager = new oDeformationManager();
2586  // Set all parameters
2587  p_DeformationManager->SetImageDimensionsAndQuantification(p_ImageDimensionsAndQuantification);
2588  p_DeformationManager->SetDataMode(p_DataFile[0]->GetDataMode()); // required to know if sensitivity image deformation should be enabled
2589 
2590  if(resp_motion_options != "")
2591  {
2592  p_DeformationManager->SetOptions(resp_motion_options);
2593  p_DeformationManager->SetNbTransformations(nb_resp_gates);
2594  p_DeformationManager->SetMotionType(DEF_RESP_MOT);
2595  }
2596  else if (card_motion_options != "")
2597  {
2598  p_DeformationManager->SetOptions(card_motion_options);
2599  p_DeformationManager->SetNbTransformations(nb_card_gates);
2600  p_DeformationManager->SetMotionType(DEF_CARD_MOT);
2601  }
2602  else if (double_motion_options != "")
2603  {
2604  p_DeformationManager->SetOptions(double_motion_options);
2605  p_DeformationManager->SetNbTransformations(nb_resp_gates*nb_card_gates);
2606  p_DeformationManager->SetMotionType(DEF_DUAL_MOT);
2607  }
2608  else if (ipat_motion_options != "")
2609  {
2610  p_DeformationManager->SetOptions(ipat_motion_options);
2611  p_DeformationManager->SetNbTransformations(p_ImageDimensionsAndQuantification->GetNbIPatMotionSubsets() - 1);
2612  p_DeformationManager->SetMotionType(DEF_IPAT_MOT);
2613  }
2614  else
2615  p_DeformationManager->SetNbTransformations(0);
2616 
2617  p_DeformationManager->SetVerbose(verbose_defo);
2618  // Check parameters
2619  if (p_DeformationManager->CheckParameters())
2620  {
2621  Cerr("***** castor-recon() -> A problem occurred while checking image deformation manager's parameters !" << endl);
2622  Exit(EXIT_FAILURE);
2623  }
2624  // Initialize optimizer manager
2625  if (p_DeformationManager->Initialize())
2626  {
2627  Cerr("***** castor-recon() -> A problem occurred while initializing image deformation manager !" << endl);
2628  Exit(EXIT_FAILURE);
2629  }
2630  // Verbose
2631  if (verbose_general >=5) Cout("----- Image deformation initialization OK -----" << endl);
2632 
2633  // ============================================================================================================
2634  // Check for supported/implemented combinations of options, after creating managers/input data and before launching the algorithm
2635  // ============================================================================================================
2636 
2637  // ============================================================================================================
2638  // Algorithm initialization: create here sensitivity computation and launch algorithm
2639  // ============================================================================================================
2640 
2641  // --------------------------------------------------------------------------------------------
2642  // Compute sensitivity if a sensitivity image is not provided and one of the following conditions is met
2643  // 1. Input file is a list-mode file
2644  // 2. Input file is a histogram and the boolean sensitivity_from_histogram is true
2645  // --------------------------------------------------------------------------------------------
2646 
2647  // In histogram mode, the sensitivity has to be computed if the optimizer requires a global sensitivity
2648  if (p_DataFile[0]->GetDataMode()==MODE_HISTOGRAM && (p_OptimizerManager->GetNeedGlobalSensitivity() || !options_prob.empty())) sensitivity_from_histogram = true;
2649 
2650  if ( path_to_sensitivity_img.empty() && (p_DataFile[0]->GetDataMode()==MODE_LIST || sensitivity_from_histogram) )
2651  {
2652  // Verbose
2653  if (verbose_general>=5) Cout("----- Image Sensitivity generation initialization ... -----" << endl);
2654  // Create object
2655  oSensitivityGenerator* p_Sensitivity = new oSensitivityGenerator();
2656  // Set parameters
2657  p_Sensitivity->SetImageDimensionsAndQuantification(p_ImageDimensionsAndQuantification);
2658  p_Sensitivity->SetImageSpace(p_ImageSpace);
2659  p_Sensitivity->SetScanner(p_ScannerManager->GetScannerObject());
2660  p_Sensitivity->SetProjectorManager(p_ProjectorManager);
2661  p_Sensitivity->SetImageConvolverManager(p_ImageConvolverManager);
2662  p_Sensitivity->SetDeformationManager(p_DeformationManager);
2663  p_Sensitivity->SetGPUflag(gpu_flag);
2664  p_Sensitivity->SetPathToAttenuationImage(path_to_attenuation_img);
2665  p_Sensitivity->SetNumberOfAtnGateImages(nb_atn_resp_imgs, nb_atn_card_imgs);
2666  p_Sensitivity->SetPathToNormalizationFileName(path_to_normalization_filename,invert_datafile_bed_order_flag);
2667  p_Sensitivity->SetDataFile(p_DataFile);
2668  p_Sensitivity->SetComputeFromHistogramFlag(sensitivity_from_histogram);
2669  p_Sensitivity->SetVerbose(verbose_sens);
2670  // Check parameters
2671  if (p_Sensitivity->CheckParameters())
2672  {
2673  Cerr("***** castor-recon() -> A problem occurred while checking parameters of the sensitivity generator !" << endl);
2674  Exit(EXIT_FAILURE);
2675  }
2676  // Initialize the sensitivity generator
2677  if (p_Sensitivity->Initialize())
2678  {
2679  Cerr("***** castor-recon() -> A problem occurred while initializing the sensitivity generator !" << endl);
2680  Exit(EXIT_FAILURE);
2681  }
2682  // Set the sensitivity mode ON for the projector manager
2683  p_ProjectorManager->SetSensitivityModeOn();
2684  // Launch the computation
2685  if (p_Sensitivity->Launch())
2686  {
2687  Cerr("***** castor-recon() -> A problem occurred while computing the sensitivity !" << endl);
2688  Exit(EXIT_FAILURE);
2689  }
2690  // Set the sensitivity mode OFF for the projector manager
2691  p_ProjectorManager->SetSensitivityModeOff();
2692 
2693  // Get the path to the sensitivity image (will be given to the algorithm if input file is a list-mode or a global sensitivity is needed)
2694  if ( p_DataFile[0]->GetDataMode()==MODE_LIST || p_OptimizerManager->GetNeedGlobalSensitivity() || !options_prob.empty())
2695  path_to_sensitivity_img = p_Sensitivity->GetPathToSensitivityImage();
2696 
2697  else path_to_sensitivity_img = "";
2698  // Delete the generator
2699  delete p_Sensitivity;
2700  // Exit now if asked for
2701  if (exit_after_sensitivity)
2702  {
2703  if (verbose_general>=VERBOSE_LIGHT) Cout("castor-recon() -> Asked to exit after sensitivity computation." << endl);
2704  // Delete objects in the inverse order in which they were created
2705  delete p_ImageSpace;
2706  delete p_DeformationManager;
2707  delete p_DynamicModelManager;
2708  delete p_ImageProcessingManager;
2709  delete p_ImageConvolverManager;
2710  delete p_OptimizerManager;
2711  delete p_ProjectorManager;
2712  for (int i=0 ; i<nb_beds ; i++) delete p_DataFile[i];
2713  delete[] p_DataFile;
2714  delete p_ImageDimensionsAndQuantification;
2715  // And exit
2716  return 0;
2717  }
2718  }
2719 
2720  // ----------------------------------------------------------------------------------------
2721  // Create algorithm : currently only iterative optimization algorithms
2722  // ----------------------------------------------------------------------------------------
2723 
2724  // If the number of events in a datafile is below the number of threads for projections, then we must reduce this number of threads, otherwise
2725  // the datafile reading cannot work (and it has no sense anyway). This is done by the following function
2726  p_ImageDimensionsAndQuantification->CheckNumberOfProjectionThreadsConsistencyWithDataFileSize(p_DataFile);
2727 
2728  // Verbose
2729  if (verbose_general>=5) Cout("----- Iterative reconstruction algorithm initialization ... -----" << endl);
2730  // Create object
2731 
2732  vAlgorithm* p_Algorithm = NULL;
2733  string algorithm_options = "";
2734 
2735  // ----------------------------------------------------------------------------------------
2736  // Create sChronoManager
2737  // ----------------------------------------------------------------------------------------
2738  sChronoManager* p_ChronoManager = sChronoManager::GetInstance();
2739 
2740  if (!options_prob.empty())
2741  {
2742  if (verbose_general>=5) Cout("----- Profiling manager initialization ... -----" << endl);
2743 
2744  p_ChronoManager->SetNbThreads( p_ImageDimensionsAndQuantification->GetNbThreadsForProjection(),
2745  p_ImageDimensionsAndQuantification->GetNbThreadsForImageComputation() );
2746  p_ChronoManager->SetNbCustomSteps(10);
2747  p_ChronoManager->SetVerbose(verbose_general);
2748  if (p_ChronoManager->CheckParameters())
2749  {
2750  Cerr("***** castor-recon() -> A problem occured while checking parameters for the chrono manager !" << endl);
2751  Exit(EXIT_FAILURE);
2752  }
2753  if (p_ChronoManager->Initialize())
2754  {
2755  Cerr("***** castor-recon() -> A problem occured while initializing the chrono manager !" << endl);
2756  Exit(EXIT_FAILURE);
2757  }
2758 
2759  if (verbose_general>=5) Cout("----- Profiling manager initialization OK -----" << endl);
2760 
2761  // currently the only probabilistic algorithm, TODO implement a generalization for probabilistic algorithms
2762  p_Algorithm = new iRCPGSAlgorithm();
2763  algorithm_options = options_prob;
2764  }
2765  else if (!options_optimizer.empty())
2766  {
2767  // ----------------------------------------------------------------------------------------
2768  // Create sChronoManager
2769  // ----------------------------------------------------------------------------------------
2770 
2771  if (verbose_general>=5) Cout("----- Profiling manager initialization ... -----" << endl);
2772 
2773  sChronoManager* p_ChronoManager = sChronoManager::GetInstance();
2774  p_ChronoManager->SetNbThreads( p_ImageDimensionsAndQuantification->GetNbThreadsForProjection(),
2775  p_ImageDimensionsAndQuantification->GetNbThreadsForImageComputation() );
2776  p_ChronoManager->SetNbCustomSteps(1);
2777  p_ChronoManager->SetVerbose(verbose_general);
2778  if (p_ChronoManager->CheckParameters())
2779  {
2780  Cerr("***** castor-recon() -> A problem occured while checking parameters for the chrono manager !" << endl);
2781  Exit(EXIT_FAILURE);
2782  }
2783  if (p_ChronoManager->Initialize())
2784  {
2785  Cerr("***** castor-recon() -> A problem occured while initializing the chrono manager !" << endl);
2786  Exit(EXIT_FAILURE);
2787  }
2788 
2789  if (verbose_general>=5) Cout("----- Profiling manager initialization OK -----" << endl);
2790 
2791  p_Algorithm = new iIterativeAlgorithm();
2792 
2793  p_Algorithm->SetImageConvolverManager(p_ImageConvolverManager);
2794  p_Algorithm->SetImageProcessingManager(p_ImageProcessingManager);
2795  p_Algorithm->SetDynamicModelManager(p_DynamicModelManager);
2796  p_Algorithm->SetDeformationManager(p_DeformationManager);
2797  p_Algorithm->SetOptimizerManager(p_OptimizerManager);
2798  p_Algorithm->SetSaveDynamicBasisCoefficientImages(save_dynamic_basis_coefficients_flag);
2799  }
2800 
2801  // Set parameters
2802  p_Algorithm->SetImageDimensionsAndQuantification(p_ImageDimensionsAndQuantification);
2803  p_Algorithm->SetImageSpace(p_ImageSpace);
2804  p_Algorithm->SetProjectorManager(p_ProjectorManager);
2805  p_Algorithm->SetDataFile(p_DataFile);
2806  p_Algorithm->SetGPUflag(gpu_flag);
2807  p_Algorithm->SetVerbose(verbose_algo);
2808  p_Algorithm->SetNbBeds(nb_beds);
2809  p_Algorithm->SetPathInitImage(path_to_initial_img);
2810  p_Algorithm->SetPathToAttenuationImage(path_to_attenuation_img);
2811  p_Algorithm->SetPathToSensitivityImage(path_to_sensitivity_img);
2812  p_Algorithm->SetPathToMultiModalImage(path_to_multimodal_img);
2813  p_Algorithm->SetSaveSensitivityHistoFlag(save_sens_histo);
2814  p_Algorithm->SetSaveSubsetImageFlag(save_subset_image);
2815 
2816  if (p_Algorithm->SetNbIterationsAndSubsets(nb_iterations_subsets))
2817  {
2818  Cerr("***** castor-recon() -> Error while setting the numbers of iterations and subsets !" << endl);
2819  Exit(EXIT_FAILURE);
2820  }
2821 
2822  p_Algorithm->SetNbSkippedIterations(nb_skipped_iterations);
2823 
2824  if (p_Algorithm->SetOutputIterations(output_iterations))
2825  {
2826  Cerr("***** castor-recon() -> Error while setting the selected output iterations !" << endl);
2827  Exit(EXIT_FAILURE);
2828  }
2829  if (p_Algorithm->InitSpecificOptions(algorithm_options))
2830  {
2831  Cerr("***** Error while setting specific options for this algorithm !" << endl);
2832  Exit(EXIT_FAILURE);
2833  }
2834  if (p_Algorithm->Run())
2835  {
2836  Cerr("***** castor-recon() -> Error while performing the reconstruction" << endl);
2837  Exit(EXIT_FAILURE);
2838  }
2839 
2840  // Display profiling results
2841  p_ChronoManager->Display();
2842 
2843  // ============================================================================================================
2844  // End
2845  // ============================================================================================================
2846 
2847  // Delete objects in the inverse order in which they were created
2848  if (verbose_general>=5) Cout("----- Deleting CASToR objects ... -----" << endl);
2849  delete p_Algorithm;
2850  delete p_ImageSpace;
2851  delete p_DeformationManager;
2852  delete p_DynamicModelManager;
2853  delete p_ImageProcessingManager;
2854  delete p_ImageConvolverManager;
2855  delete p_OptimizerManager;
2856  delete p_ProjectorManager;
2857  for (int i=0 ; i<nb_beds ; i++) delete p_DataFile[i];
2858  delete[] p_DataFile;
2859  delete p_ImageDimensionsAndQuantification;
2860  if (verbose_general>=5) Cout("----- CASToR objects successfully deleted -----" << endl);
2861 
2862  // Ending
2863  if (verbose_general>=1) Cout(endl);
2864  #ifdef CASTOR_MPI
2865  MPI_Finalize();
2866  #endif
2867  return EXIT_SUCCESS;
2868 }
void SetIgnorePOIFlag(bool a_ignorePOIFlag)
void SetOptionsPenalty(const string &a_optionsPenalty, FLTNB a_penaltyStrength)
void ShowHelpDynamic()
This class is designed to be a mother virtual class for DataFile.
static sScannerManager * GetInstance()
Instanciate the singleton object and Initialize member variables if not already done, return a pointer to this object otherwise.
void SetGPUflag(bool a_flagGPU)
static sRandomNumberGenerator * GetInstance()
Instanciate the singleton object and Initialize member variables if not already done, return a pointer to this object otherwise.
#define MODE_HISTOGRAM
void SetNumberOfAtnGateImages(int a_nbAtnRespGateImages, int a_nbAtnCardGateImages)
virtual int InitSpecificOptions(string a_specificOptions)
static void ShowCommonHelp()
This function is used to print out some help about the use of options common to all projectors...
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.
void SetDynamicModelManager(oDynamicModelManager *ap_DynamicModelManager)
void SetSaveSubsetImageFlag(bool a_saveImageAfterSubsets)
int SetNbIterationsAndSubsets(const string &a_nbIterationsSubsets)
int InitMaskImage(const string &a_pathToImage)
void ShowHelpDynamicModel()
Show help about all implemented dynamic models.
#define Cerr(MESSAGE)
void ShowHelpDeformation()
Show help about all implemented deformations.
void ShowHelp()
Display main command line options for castor-proj.
Definition: castor-recon.cc:42
void SetOptionsCommon(const string &a_optionsCommon)
int Initialize()
A function used to initialize the manager and the projectors or system matrices it manages...
static void ShowCommonHelp()
This function does not take any parameter and is used to display some help about the syntax of the op...
int Initialize()
A public function used to initialize the sensitivity generator.
void SetImageConvolverManager(oImageConvolverManager *ap_ImageConvolverManager)
void SetPathToAttenuationImage(string a_pathToAttenuationImage)
void ShowHelpImgp()
Display command line options related to the Image Processing module for castor-recon.
int FindScannerSystem(string a_scannerName)
int CheckParameters()
Check validity of all parameters.
void SetImageDimensionsAndQuantification(oImageDimensionsAndQuantification *ap_ImageDimensionsAndQuantification)
void SetPathInitImage(string a_pathToInitialImage)
int BuildScannerObject()
Instantiate the specific scanner object related to the modality, and set verbosity of scanner object...
void SetImageDimensionsAndQuantification(oImageDimensionsAndQuantification *ap_ImageDimensionsAndQuantification)
string GetPathToSensitivityImage()
This function return the path to the sensitivity image.
void SetOptionsForward(const string &a_optionsForward)
int CheckParameters()
A function used to check the parameters settings.
void SetOptimizerManager(oOptimizerManager *ap_OptimizerManager)
This class is designed to manage the optimization part of an iterative reconstruction.
void CheckNumberOfProjectionThreadsConsistencyWithDataFileSize(vDataFile **a2p_DataFile)
void ShowHelpImageProcessingModule()
Show help about all implemented image processing modules.
void SetProjectorManager(oProjectorManager *ap_ProjectorManager)
void SetVerbose(int a_verboseLevel)
int Run()
Just call either the RunCPU or the RunGPU function as asked for.
void SetSensitivityModeOff()
Say that the projector will no longer be used to compute the global sensitivity.
void SetImageDimensionsAndQuantification(oImageDimensionsAndQuantification *ap_ImageDimensionsAndQuantification)
int Launch()
A public function used to launch the sensitivity generator (compute the sensitivity image) ...
int Initialize()
A function used to initialize the manager and all image processing modules it manages.
void Exit(int code)
void SetVerbose(int a_verboseLevel)
Set verbosity level.
void ShowHelpPenalty()
Show help about all implemented penalties.
int Initialize()
Set the dynamic model flag and instanciate/initialize model objects through the ParseOptionsAndInitia...
static sOutputManager * GetInstance()
Instanciate the singleton object and Initialize member variables if not already done, return a pointer to this object otherwise.
void SetNbCustomSteps(int a_nbCustomSteps)
void SetImageDimensionsAndQuantification(oImageDimensionsAndQuantification *ap_ImageDimensionsAndQuantification)
int Initialize()
A function used to initialize the manager and the optimizer it manages.
int CheckParameters()
Check if all parameters have been correctly initialized, and call the CheckParameters function of the...
void DeallocateMaskImage()
Free memory for the mask image.
void SetOptionsOptimizer(const string &a_optionsOptimizer)
int InstantiateScanner()
Instantiate scanner using the related function in the scanner classes.
int LogCommandLine(int argc, char **argv)
void SetPathToAttenuationImage(string a_pathToAttenuationImage)
void SetImageDimensionsAndQuantification(oImageDimensionsAndQuantification *ap_ImageDimensionsAndQuantification)
static sAddonManager * GetInstance()
void SetOptimizerFOMFlag(bool a_optimizerFOMFlag)
void SetDeformationManager(oDeformationManager *ap_DeformationManager)
#define FIXED_LIST_COMPUTATION_STRATEGY
int CheckConfigDir(const string &a_path)
int CheckParameters()
A function used to check the parameters settings.
#define SCANNER_SPECT_CONVERGENT
void SetImageConvolverManager(oImageConvolverManager *ap_ImageConvolverManager)
int BuildLUT()
Call the eponym function of the scanner class.
int GetNbIPatMotionSubsets()
call the eponym function from the oDynamicDataManager object
int Initialize()
A function used to initialize all that is needed.
Singleton class that manages output writing on disk (images, sinograms, etc). It also manages loggi...
void SetComputationStrategy(int a_computationStrategy)
void SetNbThreads(int a_nbThreadsForProjection, int a_nbThreadsForImageComputation)
void SetProjectorManager(oProjectorManager *ap_ProjectorManager)
void SetOptionsBackward(const string &a_optionsBackward)
This class is designed to manage the use of dynamic model in the reconstruction.
RCP-GS : Random Clustering Prior - Gibbs Sampler.
void SetDataFile(vDataFile *ap_DataFile)
int GetNbThreadsMax()
Get the maximum between the number of threads used for projections and image operations.
Singleton class that Instantiate and initialize the scanner object.
int Initialize(int a_nbThreads, int a_nbExtra)
Instantiate pseudo random number generators, one per thread by default, and additional extra ones if ...
void SetComputeFromHistogramFlag(bool a_computeFromHistogramFlag)
void SetSaveDynamicBasisCoefficientImages(bool a_saveDynamicBasisCoefficients)
int CheckParameters()
A function used to check the parameters settings.
void SetImageProcessingManager(oImageProcessingManager *ap_ImageProcessingManager)
void SetImageDimensionsAndQuantification(oImageDimensionsAndQuantification *ap_ImageDimensionsAndQuantification)
Inherit from vDataFile. Class that manages the reading of a SPECT input file (header + data)...
This class is designed to manage the different image convolvers and to apply them.
void SetImageDimensionsAndQuantification(oImageDimensionsAndQuantification *ap_ImageDimensionsAndQuantification)
void SetHeaderDataFileName(const string &a_headerFileName)
int CheckParameters()
A function used to check the parameters settings.
void SetUseModelInReconstruction(bool a_useModelInReconstruction)
void SetSensitivityModeOn()
Say that the projector will be used to compute the global sensitivity.
int InitDynamicData(string a_pathTo4DDataSplittingFile, int a_respMotionCorrectionFlag, int a_cardMotionCorrectionFlag, int a_invMotionCorrectionFlag, int a_nbRespGates, int a_nbCardGates)
void SetImageDimensionsAndQuantification(oImageDimensionsAndQuantification *ap_ImageDimensionsAndQuantification)
void ShowHelpMiscellaneous()
int main(int argc, char **argv)
void ShowHelpProjector()
Show help about all implemented projectors.
#define KEYWORD_MANDATORY
bool GetNeedGlobalSensitivity()
Get the boolean saying if the sensitivity has to be computed globally.
int CheckParameters()
A function used to check the parameters settings.
#define KEYWORD_OPTIONAL
void SetImageSpace(oImageSpace *ap_ImageSpace)
static void ShowCommonHelp()
This function does not take any parameter and is used to display some help about the syntax of the op...
void ShowHelpComputation()
int CheckParameters()
This function is used to check parameters after the latter have been all set using Set functions...
Singleton class that generate a thread-safe random generator number for openMP As singleton...
void IntfKeyInitFields(Intf_fields *ap_IF)
Init the file of an Interfile fields structure passed in parameter to their default values...
void SetIgnoredCorrections(const string &a_ignoredCorrectionsList)
int CheckParameters()
This function is used to check parameters after the latter have been all set using Set functions...
void SetFOVOutMasking(FLTNB a_fovOutPercent, INTNB a_nbSliceOutMask)
void SetSaveSensitivityHistoFlag(bool a_saveSensitivityHistoFlag)
int Initialize()
Initialization : .
void SetImageDimensionsAndQuantification(oImageDimensionsAndQuantification *ap_ID)
int Initialize()
Initialize all thread-safe buffers for profiling.
This class is designed to manage the image-based deformation part of the reconstruction.
int InitializeAdditionalData(const string &a_pathToAdditionalData)
Memory allocation and initialization for the additional data matrices.
void SetOptions(const string &a_options)
void SetPathToNormalizationFileName(vector< string > ap_pathToNormalizationFileName, bool a_inverseDataFileOrderFlag)
This class is designed to manage the different image processing modules and to apply them...
void SetPathToMultiModalImage(vector< string > a_pathToMultiModalImage)
This class is designed to manage the projection part of the reconstruction.
int GetNbTOFBins()
Get the number of TOF bins associated to the projector.
Interfile fields. This structure contains all the Interfile keys currently managed by CASToR Decl...
void ShowHelpOutput()
void SetBedIndex(int a_bedIndex)
This is the base class for reconstructions, containing a framework with iteration and data subset loo...
void GetUserEndianness()
Check user/host computer endianness and write it to the global variable User_Endianness.
int Initialize()
Set the flags for the different motion types and instanciate/initialize deformation objects through t...
void SetCardBasisFunctionsFile(const string &a_cardBasisFunctionsFile)
This class holds all the matrices in the image domain that can be used in the algorithm: image...
int GetNbThreadsForImageComputation()
Get the number of threads used for image operations.
int SetOutputIterations(const string &a_outputIterations)
int InitOutputDirectory(const string &a_pathFout, const string &a_pathDout)
int ConvertFromString(const string &a_str, string *a_result)
Copy the &#39;a_str&#39; string in the position pointed by &#39;a_result&#39;.
void ShowHelpSpecific()
Show help for the child algorithm.
int CheckParameters()
A public function used to check the parameters settings.
Inherit from vDataFile. Class that manages the reading of a CT input file (header + data)...
void SetOptions(vector< string > a_options)
void ShowHelpProj()
This class is designed to manage all dimensions and quantification related stuff. ...
int GetNbThreadsForProjection()
Get the number of threads used for projections.
void SetDataFile(vDataFile **a2p_DataFile)
void ShowHelpDimensions()
Display command line options related to image dimensions for castor-recon.
void SetImageSpace(oImageSpace *ap_ImageSpace)
void SetImageSpace(oImageSpace *ap_ImageSpace)
void SetVerbose(int a_verboseLevel)
void SetNbTransformations(int a_nbTransformations)
int CheckSPECTAttenuationCompatibility(const string &a_pathToAttenuationImage)
This class is designed to manage some profiling of the code.
void SetDataFileName(vector< string > ap_dataFileName)
void SetNbSkippedIterations(const string &a_skippedIterations)
Set the number of first iterations to be skipped.
int IntfReadHeader(const string &a_pathToHeaderFile, Intf_fields *ap_IntfFields, int vb)
Read an Interfile header.
void ShowHelpAlgo()
Display command line options related to the available algorithms. For iterative algorithms based on o...
void ShowHelpOptimizer()
Show help about all implemented optimizers.
void SetDeformationManager(oDeformationManager *ap_DeformationManager)
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...
void SetImageDimensionsAndQuantification(oImageDimensionsAndQuantification *ap_ImageDimensionsAndQuantification)
void SetImageDimensionsAndQuantification(oImageDimensionsAndQuantification *ap_ImageDimensionsAndQuantification)
Inherit from vDataFile. Class that manages the reading of a PET input file (header + data)...
int GetGeometricInfoFromDataFile(string a_pathToDataFilename)
void SetDataFile(vDataFile *ap_DataFile)
Set the data file in use.
#define Cout(MESSAGE)
void SetRespBasisFunctionsFile(const string &a_respBasisFunctionsFile)
static sChronoManager * GetInstance()
Instantiate the singleton if not already done, then return the pointer to its instance.
void SetVerbose(int a_verboseLevel)
This class is designed to manage the computation of the sensitivity image.
void SetVerbose(int a_verboseLevel)
void SetOptimizerImageStatFlag(bool a_optimizerImageStatFlag)
void ShowHelpInput()
void SetPathToSensitivityImage(string a_pathToSensitivityImage)
int Initialize()
A function used to initialize the manager and all image convolvers it manages.
#define KEYWORD_OPTIONAL_ERROR
int SetDynamicSpecificQuantificationFactors(const string &a_quantificationFile)
void ShowHelpCorrection()
Display command line options related to correction settings for castor-recon.
void ShowHelpImageConvolver()
Show help about all implemented image convolvers.
void Display()
Display the results of the duration buffers.