CASToR  3.2
Tomographic Reconstruction (PET/SPECT/CT)
code/src/optimizer/oOptimizerManager.cc
Go to the documentation of this file.
1 
8 #include "oOptimizerManager.hh"
9 #include "sOutputManager.hh"
10 #include "sAddonManager.hh"
11 
12 // =====================================================================
13 // ---------------------------------------------------------------------
14 // ---------------------------------------------------------------------
15 // =====================================================================
16 
18 {
19  // Image dimensions
21  // Image space
22  mp_ImageSpace = NULL;
23  // Data mode
25  // Data type
27  // Data spec
29  // Number of TOF bins
30  m_nbTOFBins = 0;
31  // Optimizer and penalty options
32  m_optionsOptimizer = "";
33  m_optionsPenalty = "";
34  m_penaltyStrength = -1.;
35  // Optimizer and penalty
36  mp_Optimizer = NULL;
37  mp_Penalty = NULL;
38  // Verbosity
39  m_verbose = 0;
40  // Optimizer FOM computation, and image update stat flags
41  m_optimizerFOMFlag = false;
43 }
44 
45 // =====================================================================
46 // ---------------------------------------------------------------------
47 // ---------------------------------------------------------------------
48 // =====================================================================
49 
51 {
52  if (mp_Optimizer) delete(mp_Optimizer);
53  if (mp_Penalty) delete(mp_Penalty);
54 }
55 
56 // =====================================================================
57 // ---------------------------------------------------------------------
58 // ---------------------------------------------------------------------
59 // =====================================================================
60 
62 {
63  // Check image dimensions
65  {
66  Cerr("***** oOptimizerManager::CheckParameters() -> No image dimensions provided !" << endl);
67  return 1;
68  }
69  // Check image space
70  if (mp_ImageSpace==NULL)
71  {
72  Cerr("***** oOptimizerManager::CheckParameters() -> No image space provided !" << endl);
73  return 1;
74  }
75  // Check data mode
77  {
78  Cerr("***** oOptimizerManager::CheckParameters() -> No or meaningless data mode provided !" << endl);
79  return 1;
80  }
81  // Check data type
83  {
84  Cerr("***** oOptimizerManager::CheckParameters() -> No or meaningless data type provided !" << endl);
85  return 1;
86  }
87  // Check data spec
89  {
90  Cerr("***** oOptimizerManager::CheckParameters() -> No or meaningless data specificity provided (emission or transmission) !" << endl);
91  return 1;
92  }
93  // Check optimizer options
94  if (m_optionsOptimizer=="")
95  {
96  Cerr("***** oOptimizerManager::CheckParameters() -> No optimizer options provided !" << endl);
97  return 1;
98  }
99  // Check verbosity
100  if (m_verbose<0)
101  {
102  Cerr("***** oOptimizerManager::CheckParameters() -> Wrong verbosity level provided !" << endl);
103  return 1;
104  }
105  // Normal end
106  return 0;
107 }
108 
109 // =====================================================================
110 // ---------------------------------------------------------------------
111 // ---------------------------------------------------------------------
112 // =====================================================================
113 
115 {
116  // Verbose
117  if (m_verbose>=1) Cout("oOptimizerManager::Initialize() -> Initialize optimizer and penalty" << endl);
118 
119  // Parse projector options and initialize them
121  {
122  Cerr("***** oOptimizerManager::Initialize() -> A problem occurred while parsing optimizer options and initializing it !" << endl);
123  return 1;
124  }
125 
126  // Normal end
127  return 0;
128 }
129 
130 // =====================================================================
131 // ---------------------------------------------------------------------
132 // ---------------------------------------------------------------------
133 // =====================================================================
134 
136 {
137  // ---------------------------------------------------------------------------------------------------
138  // Manage optimizer options
139  // ---------------------------------------------------------------------------------------------------
140 
141  string name_optimizer = "";
142  string list_options_optimizer = "";
143  string file_options_optimizer = "";
144 
145  // This is for the automatic initialization of the optimizer and penalty
146  typedef vOptimizer *(*maker_optimizer) ();
147 
148  // ______________________________________________________________________________
149  // Get the optimizer name in the options and isolate the real optimizer's options
150 
151  // First check emptyness of the options
152  if (m_optionsOptimizer=="")
153  {
154  Cerr("***** oOptimizerManager::ParseOptionsAndInitializeOptimizerAndPenalty() -> No optimizer provided !" << endl);
155  return 1;
156  }
157 
158  // Search for a colon ":", this indicates that a configuration file is provided after the optimizer name
159  size_t colon = m_optionsOptimizer.find_first_of(":");
160  size_t comma = m_optionsOptimizer.find_first_of(",");
161 
162  // Case 1: we have a colon
163  if (colon!=string::npos)
164  {
165  // Get the optimizer name before the colon
166  name_optimizer = m_optionsOptimizer.substr(0,colon);
167  // Get the configuration file after the colon
168  file_options_optimizer = m_optionsOptimizer.substr(colon+1);
169  // List of options is empty
170  list_options_optimizer = "";
171  }
172  // Case 2: we have a comma
173  else if (comma!=string::npos)
174  {
175  // Get the optimizer name before the first comma
176  name_optimizer = m_optionsOptimizer.substr(0,comma);
177  // Get the list of options after the first comma
178  list_options_optimizer = m_optionsOptimizer.substr(comma+1);
179  // Configuration file is empty
180  file_options_optimizer = "";
181  }
182  // Case 3: no colon and no comma (a single optimizer name)
183  else
184  {
185  // Get the optimizer name
186  name_optimizer = m_optionsOptimizer;
187  // List of options is empty
188  list_options_optimizer = "";
189  // Build the default configuration file
190  sOutputManager* p_output_manager = sOutputManager::GetInstance();
191  file_options_optimizer = p_output_manager->GetPathToConfigDir() + "/optimizer/" + name_optimizer + ".conf";
192  }
193 
194  // ______________________________________________________________________________
195  // Construct and initialize the optimizer
196 
197  // Get optimizer's listfrom addon manager
198  std::map <string,maker_optimizer> list_optimizer = sAddonManager::GetInstance()->mp_listOfOptimizers;
199  // Create the optimizer
200  if (list_optimizer[name_optimizer]) mp_Optimizer = list_optimizer[name_optimizer]();
201  else
202  {
203  Cerr("***** oOptimizerManager::ParseOptionsAndInitializeOptimizerAndPenalty() -> Optimizer '" << name_optimizer << "' does not exist !" << endl);
204  return 1;
205  }
206  // Set parameters
207  mp_Optimizer->SetOptimizerID(name_optimizer);
217  // Provide configuration file if any (child specific function)
218  if (file_options_optimizer!="" && mp_Optimizer->ReadConfigurationFile(file_options_optimizer))
219  {
220  Cerr("***** oOptimizerManager::ParseOptionsAndInitializeOptimizerAndPenalty() -> A problem occurred while reading and checking optimizer's configuration file !" << endl);
221  return 1;
222  }
223  // Provide options if any (child specific function)
224  if (list_options_optimizer!="" && mp_Optimizer->ReadOptionsList(list_options_optimizer))
225  {
226  Cerr("***** oOptimizerManager::ParseOptionsAndInitializeOptimizerAndPenalty() -> A problem occurred while parsing and reading optimizer's options !" << endl);
227  return 1;
228  }
229  // Check parameters (mother generic function that will call the child specific function at the end)
231  {
232  Cerr("***** oOptimizerManager::ParseOptionsAndInitializeOptimizerAndPenalty() -> A problem occurred while checking optimizer parameters !" << endl);
233  return 1;
234  }
235 
236  // ---------------------------------------------------------------------------------------------------
237  // Manage penalty options
238  // ---------------------------------------------------------------------------------------------------
239 
240  string name_penalty = "";
241  string list_options_penalty = "";
242  string file_options_penalty = "";
243 
244  // This is for the automatic initialization of the penalty
245  typedef vPenalty *(*maker_penalty) ();
246 
247  // ______________________________________________________________________________
248  // Get the penalty name in the options and isolate the real penalty's options
249 
250  // Do we have some penalty provided ?
251  if (m_optionsPenalty!="")
252  {
253 
254  // Otherwise, check if the optimizer accepts penalties
256  {
257  Cerr("***** oOptimizerManager::ParseOptionsAndInitializeOptimizerAndPenalty() -> Penalty provided while the selected optimizer does not accept penalties !" << endl);
258  Cerr(" Remove penalty or change for another optimizer that accepts penalties." << endl);
259  return 1;
260  }
261  // Search for a colon ":", this indicates that a configuration file is provided after the penalty name
262  colon = m_optionsPenalty.find_first_of(":");
263  comma = m_optionsPenalty.find_first_of(",");
264  // Case 1: we have a colon
265  if (colon!=string::npos)
266  {
267  // Get the penalty name before the colon
268  name_penalty = m_optionsPenalty.substr(0,colon);
269  // Get the configuration file after the colon
270  file_options_penalty = m_optionsPenalty.substr(colon+1);
271  // List of options is empty
272  list_options_penalty = "";
273  }
274  // Case 2: we have a comma
275  else if (comma!=string::npos)
276  {
277  // Get the penalty name before the first comma
278  name_penalty = m_optionsPenalty.substr(0,comma);
279  // Get the list of options after the first comma
280  list_options_penalty = m_optionsPenalty.substr(comma+1);
281  // Configuration file is empty
282  file_options_penalty = "";
283  }
284  // Case 3: no colon and no comma (a single penalty name)
285  else
286  {
287  // Get the penalty name
288  name_penalty = m_optionsPenalty;
289  // List of options is empty
290  list_options_penalty = "";
291  // Build the default configuration file
292  sOutputManager* p_output_manager = sOutputManager::GetInstance();
293  file_options_penalty = p_output_manager->GetPathToConfigDir() + "/optimizer/" + name_penalty + ".conf";
294  }
295  // ______________________________________________________________________________
296  // Construct and initialize the penalty
297  // Get penalty's list from addon manager
298  std::map <string,maker_penalty> list_penalty = sAddonManager::GetInstance()->mp_listOfPenalties;
299  // Create the penalty
300  if (list_penalty[name_penalty]) mp_Penalty = list_penalty[name_penalty]();
301  else
302  {
303  Cerr("***** oOptimizerManager::ParseOptionsAndInitializeOptimizerAndPenalty() -> Penalty '" << name_penalty << "' does not exist !" << endl);
304  return 1;
305  }
306  // Set parameters
307  mp_Penalty->SetPenaltyID(name_penalty);
313  // Provide configuration file if any
314  if (file_options_penalty!="" && mp_Penalty->ReadConfigurationFile(file_options_penalty))
315  {
316  Cerr("***** oOptimizerManager::ParseOptionsAndInitializeOptimizerAndPenalty() -> A problem occurred while reading and checking penalty's configuration file !" << endl);
317  return 1;
318  }
319  // Provide options if any
320  if (list_options_penalty!="" && mp_Penalty->ReadOptionsList(list_options_penalty))
321  {
322  Cerr("***** oOptimizerManager::ParseOptionsAndInitializeOptimizerAndPenalty() -> A problem occurred while parsing and reading penalty's options !" << endl);
323  return 1;
324  }
325  // Check parameters
327  {
328  Cerr("***** oOptimizerManager::ParseOptionsAndInitializeOptimizerAndPenalty() -> A problem occurred while checking penalty parameters !" << endl);
329  return 1;
330  }
331  // Initialize the penalty
332  if (mp_Penalty->Initialize())
333  {
334  Cerr("***** oOptimizerManager::ParseOptionsAndInitializeOptimizerAndPenalty() -> A problem occurred while initializing the penalty !" << endl);
335  return 1;
336  }
337  // Check that the derivatives order of the penalty is compatible with the optimizer
339  {
340  Cerr("***** oOptimizerManager::ParseOptionsAndInitializeOptimizerAndPenalty() -> Derivatives order allowed by chosen penalty is not compatible with the order required by the optimizer !" << endl);
341  return 1;
342  }
343  }
344 
345  // ---------------------------------------------------------------------------------------------------
346  // Finally initialize the optimizer (mother generic function that will call the child specific function at the end)
347  // ---------------------------------------------------------------------------------------------------
348  if (mp_Optimizer->Initialize())
349  {
350  Cerr("***** oOptimizerManager::ParseOptionsAndInitializeOptimizerAndPenalty() -> A problem occurred while initializing the optimizer !" << endl);
351  return 1;
352  }
353 
354  // Normal end
355  return 0;
356 }
357 
358 // =====================================================================
359 // ---------------------------------------------------------------------
360 // ---------------------------------------------------------------------
361 // =====================================================================
362 
364 {
365  // Simply call the homonymous function from the vOptimizer
367  {
368  Cerr("***** oOptimizerManager::PreDataUpdateStep() -> A problem occurred while applying the pre-data-update step to the optimizer !" << endl);
369  return 1;
370  }
371  // Normal end
372  return 0;
373 }
374 
375 // =====================================================================
376 // ---------------------------------------------------------------------
377 // ---------------------------------------------------------------------
378 // =====================================================================
379 
381 {
382  // Simply call the homonymous function from the vOptimizer
384  {
385  Cerr("***** oOptimizerManager::PreImageUpdateStep() -> A problem occurred while applying the pre-image-update step to the optimizer !" << endl);
386  return 1;
387  }
388  // Normal end
389  return 0;
390 }
391 
392 // =====================================================================
393 // ---------------------------------------------------------------------
394 // ---------------------------------------------------------------------
395 // =====================================================================
396 
398  int a_bed, int a_timeFrame, int a_respGate, int a_cardGate,
399  int a_thread)
400 {
401  // ---------------------------------------------------------------------------------
402  // Deal with all multiplicative correction factors to be included in the projections
403  // ---------------------------------------------------------------------------------
404 
405  // Compute the global multiplicative correction factor
406  FLTNB multiplicative_correction = ap_Event->GetMultiplicativeCorrections() * mp_ImageDimensionsAndQuantification->GetQuantificationFactor(a_bed,a_timeFrame, a_respGate, a_cardGate);
407 
408  // Do nothing if the multiplicative correction factor is null or negative
409  if (multiplicative_correction<=0.) return 0;
410 
411  // With transmission data, we include a correction factor to convert the default
412  // mm-1 unit of CASToR into cm-1 which is the standard attenuation unit in physics
413  // (this means that the image is reconstructed in cm-1)
414  if (m_dataSpec==SPEC_TRANSMISSION) multiplicative_correction *= 10.;
415 
416  // Set the multiplicative correction to the oProjectionLine so that it is part of the system matrix and automatically applied
417  ap_Line->SetMultiplicativeCorrection(multiplicative_correction);
418 
419  // Set the current attenuation image for SPECT attenuation correction
420  if (m_dataType==TYPE_SPECT && mp_ImageSpace->m4p_attenuation!=NULL) mp_Optimizer->SetAttenuationImage(mp_ImageSpace->m4p_attenuation[a_timeFrame][a_respGate][a_cardGate], a_thread);
421 
422  // --------------------------------------------------------------------------------
423  // Decompose the data update step into 4 steps mandatory steps and 3 optional steps
424  // --------------------------------------------------------------------------------
425 
426  // Mandatory 1: Compute model (forward-projection + additive background)
427  if (mp_Optimizer->DataStep1ForwardProjectModel( ap_Line, ap_Event, a_bed, a_timeFrame, a_respGate, a_cardGate, a_thread ))
428  {
429  Cerr("***** oOptimizerManager::DataUpdateStep() -> An error occurred while forward projecting !" << endl);
430  return 1;
431  }
432 
433  // Optional 1: Do what is done in the child optimizer
434  if (mp_Optimizer->DataStep2Optional( ap_Line, ap_Event, a_bed, a_timeFrame, a_respGate, a_cardGate, a_thread ))
435  {
436  Cerr("***** oOptimizerManager::DataUpdateStep() -> An error occurred while performing optional step 1 !" << endl);
437  return 1;
438  }
439 
440  // Mandatory 2: Compute sensitivity in histogram mode
442  && mp_Optimizer->DataStep3BackwardProjectSensitivity( ap_Line, ap_Event, a_bed, a_timeFrame, a_respGate, a_cardGate, a_thread ))
443  {
444  Cerr("***** oOptimizerManager::DataUpdateStep() -> An error occurred while backward projecting the sensitivity !" << endl);
445  return 1;
446  }
447 
448  // Optional 2: Do what is done in the child optimizer
449  if (mp_Optimizer->DataStep4Optional( ap_Line, ap_Event, a_bed, a_timeFrame, a_respGate, a_cardGate, a_thread ))
450  {
451  Cerr("***** oOptimizerManager::DataUpdateStep() -> An error occurred while performing optional step 2 !" << endl);
452  return 1;
453  }
454 
455  // Mandatory 3: Compute the correction terms
456  if (mp_Optimizer->DataStep5ComputeCorrections( ap_Line, ap_Event, a_bed, a_timeFrame, a_respGate, a_cardGate, a_thread ))
457  {
458  Cerr("***** oOptimizerManager::DataUpdateStep() -> An error occurred while computing correction terms !" << endl);
459  return 1;
460  }
461 
462  // Optional 3: Do what is done in the child optimizer
463  if (mp_Optimizer->DataStep6Optional( ap_Line, ap_Event, a_bed, a_timeFrame, a_respGate, a_cardGate, a_thread ))
464  {
465  Cerr("***** oOptimizerManager::DataUpdateStep() -> An error occurred while performing optional step 3 !" << endl);
466  return 1;
467  }
468 
469  // Mandatory 4: Backproject correction terms
470  if (mp_Optimizer->DataStep7BackwardProjectCorrections( ap_Line, ap_Event, a_bed, a_timeFrame, a_respGate, a_cardGate, a_thread ))
471  {
472  Cerr("***** oOptimizerManager::DataUpdateStep() -> An error occurred while backward projecting the correction !" << endl);
473  return 1;
474  }
475 
476  // Compute FOM is asked for
477  if (m_optimizerFOMFlag && mp_Optimizer->DataStep8ComputeFOM( ap_Line, ap_Event, a_timeFrame, a_respGate, a_cardGate, a_thread ))
478  {
479  Cerr("***** oOptimizerManager::DataUpdateStep() -> An error occurred while computing FOMs !" << endl);
480  return 1;
481  }
482 
483  // End
484  return 0;
485 }
486 
487 // =====================================================================
488 // ---------------------------------------------------------------------
489 // ---------------------------------------------------------------------
490 // =====================================================================
491 
493 {
494  // Verbose
495  if (m_verbose>=2) Cout("oOptimizerManager::ImageUpdateStep() -> Proceed to image update" << endl);
496  // Update visited voxels
498  {
499  Cerr("***** oOptimizerManager::ImageUpdateStep() -> Problem while updating visited voxels !" << endl);
500  return 1;
501  }
502  // Image update step
504  {
505  Cerr("***** oOptimizerManager::ImageUpdateStep() -> Problem while updating image space !" << endl);
506  return 1;
507  }
508  // End
509  return 0;
510 }
511 
512 // =====================================================================
513 // ---------------------------------------------------------------------
514 // ---------------------------------------------------------------------
515 // =====================================================================
virtual int ReadConfigurationFile(const string &a_configurationFile)=0
void SetPenaltyID(const string &a_penaltyID)
virtual int ReadOptionsList(const string &a_optionsList)=0
#define MODE_HISTOGRAM
bool GetNeedGlobalSensitivity()
Get the boolean saying if the sensitivity has to be computed globally for all data channels and not p...
#define Cerr(MESSAGE)
void SetImageDimensionsAndQuantification(oImageDimensionsAndQuantification *ap_ImageDimensionsAndQuantification)
virtual int DataStep2Optional(oProjectionLine *ap_Line, vEvent *ap_Event, int a_bed, int a_timeFrame, int a_respGate, int a_cardGate, int a_thread)
void SetImageDimensionsAndQuantification(oImageDimensionsAndQuantification *ap_ImageDimensionsAndQuantification)
int PreImageUpdateStep()
A function that simply calls the eponym function from the vOptimizer.
void SetVerbose(int a_verbose)
void SetMultiplicativeCorrection(FLTNB a_multiplicativeCorrection)
virtual int ImageUpdateStep()
A public function used to perform the image update step of the optimizer.
void SetDataType(int a_dataType)
virtual FLTNB GetMultiplicativeCorrections()=0
This is a pure virtual function implemented in the child classes.
static sOutputManager * GetInstance()
Instanciate the singleton object and Initialize member variables if not already done, return a pointer to this object otherwise.
int PreDataUpdateStep()
A public function used to do stuff that need to be done at the beginning of a subset (before the data...
int Initialize()
A function used to initialize the manager and the optimizer it manages.
int DataUpdateStep(oProjectionLine *ap_Line, vEvent *ap_Event, int a_bed, int a_timeFrame, int a_respGate, int a_cardGate, int a_thread)
int Initialize()
A public function used to initialize the penalty.
static sAddonManager * GetInstance()
void SetFOMFlag(bool a_optimizerFOMFlag)
void SetImageSpace(oImageSpace *ap_ImageSpace)
virtual int DataStep6Optional(oProjectionLine *ap_Line, vEvent *ap_Event, int a_bed, int a_timeFrame, int a_respGate, int a_cardGate, int a_thread)
int GetRequiredPenaltyDerivativesOrder()
Get the penalty derivative order needed for this algorithm.
std::map< string, maker_optimizer > mp_listOfOptimizers
bool GetAcceptPenalty()
Get the boolean saying if the optimizer accepts penalties.
void SetAttenuationImage(FLTNB *ap_attenuationImage, int a_thread)
Singleton class that manages output writing on disk (images, sinograms, etc). It also manages loggi...
const string & GetPathToConfigDir()
Return the path to the CASTOR config directory.
virtual int DataStep3BackwardProjectSensitivity(oProjectionLine *ap_Line, vEvent *ap_Event, int a_bed, int a_timeFrame, int a_respGate, int a_cardGate, int a_thread)
std::map< string, maker_penalty > mp_listOfPenalties
int PreDataUpdateStep()
A function that simply calls the eponym function from the vOptimizer.
void SetOptimizerID(const string &a_optimizerID)
virtual int DataStep1ForwardProjectModel(oProjectionLine *ap_Line, vEvent *ap_Event, int a_bed, int a_timeFrame, int a_respGate, int a_cardGate, int a_thread)
void SetDataMode(int a_dataMode)
FLTNB GetQuantificationFactor(int a_bed, int a_frame, int a_respGate, int a_cardGate)
This class is designed to generically described any penalty applied to MAP algorithms.
virtual int DataStep8ComputeFOM(oProjectionLine *ap_Line, vEvent *ap_Event, int a_timeFrame, int a_respGate, int a_cardGate, int a_thread)
void SetNbTOFBins(int a_nbTOFBins)
int CheckParameters()
A function used to check the parameters settings.
void SetVerbose(int a_verbose)
int GetPenaltyDerivativesOrder()
Get the penalty deratives order.
#define SPEC_TRANSMISSION
void SetPenaltyStrength(FLTNB a_penaltyStrength)
int CheckParameters()
A public function used to check the parameters settings.
int PreImageUpdateStep()
A public function used to do stuff that need to be done between the loop over events and the image up...
This class is designed to generically described any iterative optimizer.
This class is designed to manage and store system matrix elements associated to a vEvent...
~oOptimizerManager()
The destructor of oOptimizerManager.
void SetImageStatFlag(bool a_optimizerImageStatFlag)
int Initialize()
A public function used to initialize the optimizer.
virtual int DataStep4Optional(oProjectionLine *ap_Line, vEvent *ap_Event, int a_bed, int a_timeFrame, int a_respGate, int a_cardGate, int a_thread)
Mother class for the Event objects.
virtual int DataStep5ComputeCorrections(oProjectionLine *ap_Line, vEvent *ap_Event, int a_bed, int a_timeFrame, int a_respGate, int a_cardGate, int a_thread)
int ImageUpdateStep()
A function dedicated to the update step in the image space (performed after the loop on events) ...
oOptimizerManager()
The constructor of oOptimizerManager.
int UpdateVisitedVoxels()
A public function used to update the &#39;visited&#39; voxels after each subset.
void SetImageSpace(oImageSpace *ap_ImageSpace)
virtual int ReadConfigurationFile(const string &a_configurationFile)=0
void SetDataSpec(int a_dataSpec)
virtual int DataStep7BackwardProjectCorrections(oProjectionLine *ap_Line, vEvent *ap_Event, int a_bed, int a_timeFrame, int a_respGate, int a_cardGate, int a_thread)
void SetPenalty(vPenalty *ap_penalty)
#define Cout(MESSAGE)
int CheckParameters()
A public function used to check the parameters settings.
oImageDimensionsAndQuantification * mp_ImageDimensionsAndQuantification
virtual int ReadOptionsList(const string &a_optionsList)=0