CASToR  3.2
Tomographic Reconstruction (PET/SPECT/CT)
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);
218  // Provide configuration file if any (child specific function)
219  if (file_options_optimizer!="" && mp_Optimizer->ReadConfigurationFile(file_options_optimizer))
220  {
221  Cerr("***** oOptimizerManager::ParseOptionsAndInitializeOptimizerAndPenalty() -> A problem occurred while reading and checking optimizer's configuration file !" << endl);
222  return 1;
223  }
224  // Provide options if any (child specific function)
225  if (list_options_optimizer!="" && mp_Optimizer->ReadOptionsList(list_options_optimizer))
226  {
227  Cerr("***** oOptimizerManager::ParseOptionsAndInitializeOptimizerAndPenalty() -> A problem occurred while parsing and reading optimizer's options !" << endl);
228  return 1;
229  }
230  // Check parameters (mother generic function that will call the child specific function at the end)
232  {
233  Cerr("***** oOptimizerManager::ParseOptionsAndInitializeOptimizerAndPenalty() -> A problem occurred while checking optimizer parameters !" << endl);
234  return 1;
235  }
236 
237  // ---------------------------------------------------------------------------------------------------
238  // Manage penalty options
239  // ---------------------------------------------------------------------------------------------------
240 
241  string name_penalty = "";
242  string list_options_penalty = "";
243  string file_options_penalty = "";
244 
245  // This is for the automatic initialization of the penalty
246  typedef vPenalty *(*maker_penalty) ();
247 
248  // ______________________________________________________________________________
249  // Get the penalty name in the options and isolate the real penalty's options
250 
251  // Do we have some penalty provided ?
252  if (m_optionsPenalty!="")
253  {
254 
255  // Otherwise, check if the optimizer accepts penalties
257  {
258  Cerr("***** oOptimizerManager::ParseOptionsAndInitializeOptimizerAndPenalty() -> Penalty provided while the selected optimizer does not accept penalties !" << endl);
259  Cerr(" Remove penalty or change for another optimizer that accepts penalties." << endl);
260  return 1;
261  }
262  // Search for a colon ":", this indicates that a configuration file is provided after the penalty name
263  colon = m_optionsPenalty.find_first_of(":");
264  comma = m_optionsPenalty.find_first_of(",");
265  // Case 1: we have a colon
266  if (colon!=string::npos)
267  {
268  // Get the penalty name before the colon
269  name_penalty = m_optionsPenalty.substr(0,colon);
270  // Get the configuration file after the colon
271  file_options_penalty = m_optionsPenalty.substr(colon+1);
272  // List of options is empty
273  list_options_penalty = "";
274  }
275  // Case 2: we have a comma
276  else if (comma!=string::npos)
277  {
278  // Get the penalty name before the first comma
279  name_penalty = m_optionsPenalty.substr(0,comma);
280  // Get the list of options after the first comma
281  list_options_penalty = m_optionsPenalty.substr(comma+1);
282  // Configuration file is empty
283  file_options_penalty = "";
284  }
285  // Case 3: no colon and no comma (a single penalty name)
286  else
287  {
288  // Get the penalty name
289  name_penalty = m_optionsPenalty;
290  // List of options is empty
291  list_options_penalty = "";
292  // Build the default configuration file
293  sOutputManager* p_output_manager = sOutputManager::GetInstance();
294  file_options_penalty = p_output_manager->GetPathToConfigDir() + "/optimizer/" + name_penalty + ".conf";
295  }
296  // ______________________________________________________________________________
297  // Construct and initialize the penalty
298  // Get penalty's list from addon manager
299  std::map <string,maker_penalty> list_penalty = sAddonManager::GetInstance()->mp_listOfPenalties;
300  // Create the penalty
301  if (list_penalty[name_penalty]) mp_Penalty = list_penalty[name_penalty]();
302  else
303  {
304  Cerr("***** oOptimizerManager::ParseOptionsAndInitializeOptimizerAndPenalty() -> Penalty '" << name_penalty << "' does not exist !" << endl);
305  return 1;
306  }
307  // Set parameters
308  mp_Penalty->SetPenaltyID(name_penalty);
315  // Provide configuration file if any
316  if (file_options_penalty!="" && mp_Penalty->ReadConfigurationFile(file_options_penalty))
317  {
318  Cerr("***** oOptimizerManager::ParseOptionsAndInitializeOptimizerAndPenalty() -> A problem occurred while reading and checking penalty's configuration file !" << endl);
319  return 1;
320  }
321  // Provide options if any
322  if (list_options_penalty!="" && mp_Penalty->ReadOptionsList(list_options_penalty))
323  {
324  Cerr("***** oOptimizerManager::ParseOptionsAndInitializeOptimizerAndPenalty() -> A problem occurred while parsing and reading penalty's options !" << endl);
325  return 1;
326  }
327  // Check parameters
329  {
330  Cerr("***** oOptimizerManager::ParseOptionsAndInitializeOptimizerAndPenalty() -> A problem occurred while checking penalty parameters !" << endl);
331  return 1;
332  }
333  // Initialize the penalty
334  if (mp_Penalty->Initialize())
335  {
336  Cerr("***** oOptimizerManager::ParseOptionsAndInitializeOptimizerAndPenalty() -> A problem occurred while initializing the penalty !" << endl);
337  return 1;
338  }
339  // Check that the derivatives order of the penalty is compatible with the optimizer
341  {
342  Cerr("***** oOptimizerManager::ParseOptionsAndInitializeOptimizerAndPenalty() -> Derivatives order allowed by chosen penalty is not compatible with the order required by the optimizer !" << endl);
343  return 1;
344  }
345  }
346 
347  // ---------------------------------------------------------------------------------------------------
348  // Finally initialize the optimizer (mother generic function that will call the child specific function at the end)
349  // ---------------------------------------------------------------------------------------------------
350  if (mp_Optimizer->Initialize())
351  {
352  Cerr("***** oOptimizerManager::ParseOptionsAndInitializeOptimizerAndPenalty() -> A problem occurred while initializing the optimizer !" << endl);
353  return 1;
354  }
355 
356  // Normal end
357  return 0;
358 }
359 
360 // =====================================================================
361 // ---------------------------------------------------------------------
362 // ---------------------------------------------------------------------
363 // =====================================================================
364 
366 {
367  // Simply call the homonymous function from the vOptimizer
369  {
370  Cerr("***** oOptimizerManager::PreDataUpdateStep() -> A problem occurred while applying the pre-data-update step to the optimizer !" << endl);
371  return 1;
372  }
373  // Normal end
374  return 0;
375 }
376 
377 // =====================================================================
378 // ---------------------------------------------------------------------
379 // ---------------------------------------------------------------------
380 // =====================================================================
381 
383 {
384  // Simply call the homonymous function from the vOptimizer
386  {
387  Cerr("***** oOptimizerManager::PreImageUpdateStep() -> A problem occurred while applying the pre-image-update step to the optimizer !" << endl);
388  return 1;
389  }
390  // Normal end
391  return 0;
392 }
393 
394 // =====================================================================
395 // ---------------------------------------------------------------------
396 // ---------------------------------------------------------------------
397 // =====================================================================
398 
400  int a_bed, int a_timeFrame, int a_respGate, int a_cardGate,
401  int a_thread)
402 {
403  // ---------------------------------------------------------------------------------
404  // Deal with all multiplicative correction factors to be included in the projections
405  // ---------------------------------------------------------------------------------
406 
407  // Compute the global multiplicative correction factor
408  FLTNB multiplicative_correction = ap_Event->GetMultiplicativeCorrections() * mp_ImageDimensionsAndQuantification->GetQuantificationFactor(a_bed,a_timeFrame, a_respGate, a_cardGate);
409 
410  // Do nothing if the multiplicative correction factor is null or negative
411  if (multiplicative_correction<=0.) return 0;
412 
413  // With transmission data, we include a correction factor to convert the default
414  // mm-1 unit of CASToR into cm-1 which is the standard attenuation unit in physics
415  // (this means that the image is reconstructed in cm-1)
416  if (m_dataSpec==SPEC_TRANSMISSION) multiplicative_correction *= 10.;
417 
418  // Set the multiplicative correction to the oProjectionLine so that it is part of the system matrix and automatically applied
419  ap_Line->SetMultiplicativeCorrection(multiplicative_correction);
420 
421  // Set the current attenuation image for SPECT attenuation correction
422  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);
423 
424  // --------------------------------------------------------------------------------
425  // Decompose the data update step into 4 steps mandatory steps and 3 optional steps
426  // --------------------------------------------------------------------------------
427 
428  // Mandatory 1: Compute model (forward-projection + additive background)
429  if (mp_Optimizer->DataStep1ForwardProjectModel( ap_Line, ap_Event, a_bed, a_timeFrame, a_respGate, a_cardGate, a_thread ))
430  {
431  Cerr("***** oOptimizerManager::DataUpdateStep() -> An error occurred while forward projecting !" << endl);
432  return 1;
433  }
434 
435  // Optional 1: Do what is done in the child optimizer
436  if (mp_Optimizer->DataStep2Optional( ap_Line, ap_Event, a_bed, a_timeFrame, a_respGate, a_cardGate, a_thread ))
437  {
438  Cerr("***** oOptimizerManager::DataUpdateStep() -> An error occurred while performing optional step 1 !" << endl);
439  return 1;
440  }
441 
442  // Mandatory 2: Compute sensitivity in histogram mode
444  && mp_Optimizer->DataStep3BackwardProjectSensitivity( ap_Line, ap_Event, a_bed, a_timeFrame, a_respGate, a_cardGate, a_thread ))
445  {
446  Cerr("***** oOptimizerManager::DataUpdateStep() -> An error occurred while backward projecting the sensitivity !" << endl);
447  return 1;
448  }
449 
450  // Optional 2: Do what is done in the child optimizer
451  if (mp_Optimizer->DataStep4Optional( ap_Line, ap_Event, a_bed, a_timeFrame, a_respGate, a_cardGate, a_thread ))
452  {
453  Cerr("***** oOptimizerManager::DataUpdateStep() -> An error occurred while performing optional step 2 !" << endl);
454  return 1;
455  }
456 
457  // Mandatory 3: Compute the correction terms
458  if (mp_Optimizer->DataStep5ComputeCorrections( ap_Line, ap_Event, a_bed, a_timeFrame, a_respGate, a_cardGate, a_thread ))
459  {
460  Cerr("***** oOptimizerManager::DataUpdateStep() -> An error occurred while computing correction terms !" << endl);
461  return 1;
462  }
463 
464  // Optional 3: Do what is done in the child optimizer
465  if (mp_Optimizer->DataStep6Optional( ap_Line, ap_Event, a_bed, a_timeFrame, a_respGate, a_cardGate, a_thread ))
466  {
467  Cerr("***** oOptimizerManager::DataUpdateStep() -> An error occurred while performing optional step 3 !" << endl);
468  return 1;
469  }
470 
471  // Mandatory 4: Backproject correction terms
472  if (mp_Optimizer->DataStep7BackwardProjectCorrections( ap_Line, ap_Event, a_bed, a_timeFrame, a_respGate, a_cardGate, a_thread ))
473  {
474  Cerr("***** oOptimizerManager::DataUpdateStep() -> An error occurred while backward projecting the correction !" << endl);
475  return 1;
476  }
477 
478  // Compute FOM is asked for
479  if (m_optimizerFOMFlag && mp_Optimizer->DataStep8ComputeFOM( ap_Line, ap_Event, a_timeFrame, a_respGate, a_cardGate, a_thread ))
480  {
481  Cerr("***** oOptimizerManager::DataUpdateStep() -> An error occurred while computing FOMs !" << endl);
482  return 1;
483  }
484 
485  // End
486  return 0;
487 }
488 
489 // =====================================================================
490 // ---------------------------------------------------------------------
491 // ---------------------------------------------------------------------
492 // =====================================================================
493 
495 {
496  // Verbose
497  if (m_verbose>=2) Cout("oOptimizerManager::ImageUpdateStep() -> Proceed to image update" << endl);
498  // Update visited voxels
500  {
501  Cerr("***** oOptimizerManager::ImageUpdateStep() -> Problem while updating visited voxels !" << endl);
502  return 1;
503  }
504  // Image update step
506  {
507  Cerr("***** oOptimizerManager::ImageUpdateStep() -> Problem while updating image space !" << endl);
508  return 1;
509  }
510  // End
511  return 0;
512 }
513 
514 // =====================================================================
515 // ---------------------------------------------------------------------
516 // ---------------------------------------------------------------------
517 // =====================================================================
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)
void SetDataFile(vDataFile *ap_DataFile)
Set the image space in use.
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 SetDataFile(vDataFile *ap_DataFile)
Set the data file in use.
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