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