CASToR  3.0
Tomographic Reconstruction (PET/SPECT/CT)
iOptimizerBSREM.cc
Go to the documentation of this file.
1 /*
2 This file is part of CASToR.
3 
4  CASToR is free software: you can redistribute it and/or modify it under the
5  terms of the GNU General Public License as published by the Free Software
6  Foundation, either version 3 of the License, or (at your option) any later
7  version.
8 
9  CASToR is distributed in the hope that it will be useful, but WITHOUT ANY
10  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12  details.
13 
14  You should have received a copy of the GNU General Public License along with
15  CASToR (in file GNU_GPL.TXT). If not, see <http://www.gnu.org/licenses/>.
16 
17 Copyright 2017-2019 all CASToR contributors listed below:
18 
19  --> Didier BENOIT, Claude COMTAT, Marina FILIPOVIC, Thibaut MERLIN, Mael MILLARDET, Simon STUTE, Valentin VIELZEUF
20 
21 This is CASToR version 3.0.
22 */
23 
30 #include "iOptimizerBSREM.hh"
31 #include "sOutputManager.hh"
32 
33 // =====================================================================
34 // ---------------------------------------------------------------------
35 // ---------------------------------------------------------------------
36 // =====================================================================
37 
39 {
40  // ---------------------------
41  // Mandatory member parameters
42  // ---------------------------
43 
44  // Initial value at 1
45  m_initialValue = 1.;
46  // Only one backward image for BSREM
48  // BSREM accepts penalties, which must have a derivative order of 1 minimum
50  // BSREM is only compatible with histogram data
53  // BSREM is only compatible with emission data
56  // BSREM needs the global sensitivity which is computed at the beginning of the reconstruction process.
57  // In Ahn & Fessler 2003, it is clearly explained that the algorithm cannot use a scale function that
58  // changes over subsets, otherwise the convergence to "the desired optimum point" is not guaranteed.
60 
61  // --------------------------
62  // Specific member parameters
63  // --------------------------
64 
65  m_minimumImageValue = -1.;
66  m_maximumImageValue = -1.;
71  m_relaxationFactor = -1.;
72 }
73 
74 // =====================================================================
75 // ---------------------------------------------------------------------
76 // ---------------------------------------------------------------------
77 // =====================================================================
78 
80 {
81  // Delete the penalty image
83  {
84  // Loop over time basis functions
86  {
88  {
89  // Loop over respiratory basis functions
91  {
92  if (m4p_firstDerivativePenaltyImage[tbf][rbf])
93  {
94  free(m4p_firstDerivativePenaltyImage[tbf][rbf]);
95  }
96  }
98  }
99  }
101  }
102 }
103 
104 // =====================================================================
105 // ---------------------------------------------------------------------
106 // ---------------------------------------------------------------------
107 // =====================================================================
108 
110 {
111  cout << "This optimizer is the Block Sequential Regularized Expectation Maximization (BSREM) algorithm from S. Ahn and" << endl;
112  cout << "J. Fessler, IEEE TMI, May 2003, vol. 22, pp. 613-626. Its abbreviated name in this paper is BSREM-II." << endl;
113  cout << "This algorithm is the only one to have proven convergence using subsets. Its implementation is entirely based" << endl;
114  cout << "on the reference paper. It may have numerical problems when a full field-of-view is used, because of the sharp" << endl;
115  cout << "sensitivity loss at the edges of the cylindrical field-of-view. As it is simply based on the gradient, penalty" << endl;
116  cout << "terms must have a derivative order of at least one. Without penalty, it reduces to OSEM but where the sensitivity" << endl;
117  cout << "is not dependent on the current subset. This is a requirement of the algorithm, explaining why it starts by" << endl;
118  cout << "computing the global sensitivity before going through iterations. The algorithm is restricted to histograms." << endl;
119  cout << "The following options can be used:" << endl;
120  cout << " initial image value: to set the uniform voxel value for the initial image" << endl;
121  cout << " minimum image value: to set the minimum allowed image value (parameter 't' in the reference paper)" << endl;
122  cout << " maximum image value: to set the maximum allowed image value (parameter 'U' in the reference paper)" << endl;
123  cout << " relaxation factor type: type of relaxation factors (can be one of the following: 'classic')" << endl;
124  cout << "Relaxation factors of type 'classic' correspond to what was proposed in the reference paper in equation (31)." << endl;
125  cout << "This equation gives: alpha_n = alpha_0 / (gamma * iter_num + 1)" << endl;
126  cout << "The iteration number 'iter_num' is supposed to start at 0 so that for the first iteration, alpha_0 is used." << endl;
127  cout << "This parameter can be provided using the following keyword: 'relaxation factor classic initial value'." << endl;
128  cout << "The 'gamma' parameter can be provided using the following keyword: 'relaxation factor classic step size'." << endl;
129 }
130 
131 // =====================================================================
132 // ---------------------------------------------------------------------
133 // ---------------------------------------------------------------------
134 // =====================================================================
135 
136 int iOptimizerBSREM::ReadConfigurationFile(const string& a_configurationFile)
137 {
138  string key_word = "";
139  string buffer = "";
140 
141  // Read the initial image value option
142  key_word = "initial image value";
143  if (ReadDataASCIIFile(a_configurationFile, key_word, &m_initialValue, 1, KEYWORD_MANDATORY))
144  {
145  Cerr("***** iOptimizerBSREM::ReadConfigurationFile() -> Failed to get the '" << key_word << "' keyword !" << endl);
146  return 1;
147  }
148  // Read the minimum image value option
149  key_word = "minimum image value";
150  if (ReadDataASCIIFile(a_configurationFile, key_word, &m_minimumImageValue, 1, KEYWORD_MANDATORY))
151  {
152  Cerr("***** iOptimizerBSREM::ReadConfigurationFile() -> Failed to get the '" << key_word << "' keyword !" << endl);
153  return 1;
154  }
155  // Read the maximum image value option
156  key_word = "maximum image value";
157  if (ReadDataASCIIFile(a_configurationFile, key_word, &m_maximumImageValue, 1, KEYWORD_MANDATORY))
158  {
159  Cerr("***** iOptimizerBSREM::ReadConfigurationFile() -> Failed to get the '" << key_word << "' keyword !" << endl);
160  return 1;
161  }
162  if (m_maximumImageValue<0.) m_maximumImageValue = numeric_limits<FLTNB>::infinity();
163  // Read the relaxation factors type option
164  key_word = "relaxation factor type";
165  if (ReadDataASCIIFile(a_configurationFile, key_word, &buffer, 1, KEYWORD_MANDATORY))
166  {
167  Cerr("***** iOptimizerBSREM::ReadConfigurationFile() -> Failed to get the '" << key_word << "' keyword !" << endl);
168  return 1;
169  }
170  if (buffer == "classic")
171  {
173  // Read the relaxation factors initial value option
174  key_word = "relaxation factor classic initial value";
175  if (ReadDataASCIIFile(a_configurationFile, key_word, &m_relaxationFactorInitialValue, 1, KEYWORD_MANDATORY))
176  {
177  Cerr("***** iOptimizerBSREM::ReadConfigurationFile() -> Failed to get the '" << key_word << "' keyword !" << endl);
178  return 1;
179  }
180  // Read the relaxation factors step size
181  key_word = "relaxation factor classic step size";
182  if (ReadDataASCIIFile(a_configurationFile, key_word, &m_relaxationFactorStepSize, 1, KEYWORD_MANDATORY))
183  {
184  Cerr("***** iOptimizerBSREM::ReadConfigurationFile() -> Failed to get the '" << key_word << "' keyword !" << endl);
185  return 1;
186  }
187  }
188  else
189  {
190  Cerr("***** iOptimizerBSREM::ReadConfigurationFile() -> Provided type of the relaxation factors (" << buffer << ") is not recognized" << endl);
191  return 1;
192  }
193  // Normal end
194  return 0;
195 }
196 
197 // =====================================================================
198 // ---------------------------------------------------------------------
199 // ---------------------------------------------------------------------
200 // =====================================================================
201 
202 int iOptimizerBSREM::ReadOptionsList(const string& a_optionsList)
203 {
204  // For the moment, as there is only the classic relaxation parameter type, let the possibility to read the parameters from a list.
205 
206  // There are 5 floating point variables as options
207  const int nb_options = 5;
208  FLTNB options[nb_options];
209  // Read them
210  if (ReadStringOption(a_optionsList, options, nb_options, ",", "BSREM configuration"))
211  {
212  Cerr("***** iOptimizerBSREM::ReadOptionsList() -> Failed to correctly read the list of options !" << endl
213  << " Note: if you are not using the classic relaxation, you must for now use the configuration file" << endl);
214  return 1;
215  }
216  // Affect options
217  m_initialValue = options[0];
218  m_minimumImageValue = options[1];
219  m_maximumImageValue = options[2];
221  m_relaxationFactorInitialValue = options[3];
222  m_relaxationFactorStepSize = options[4];
223  // Normal end
224  return 0;
225 }
226 
227 // =====================================================================
228 // ---------------------------------------------------------------------
229 // ---------------------------------------------------------------------
230 // =====================================================================
231 
233 {
234  // Check relaxation factors type
236  {
237  Cerr("***** iOptimizerBSREM::CheckSpecificParameters() -> Should provide a relaxation factor type !" << endl);
238  return 1;
239  }
240  // Check that initial image value is strictly positive
241  if (m_initialValue<=0.)
242  {
243  Cerr("***** iOptimizerBSREM::CheckSpecificParameters() -> Provided initial image value (" << m_initialValue << ") must be strictly positive !" << endl);
244  return 1;
245  }
246  // Check that the minimum image value is strictly positive
247  if (m_minimumImageValue<=0.)
248  {
249  Cerr("***** iOptimizerBSREM::CheckSpecificParameters() -> Provided minimum image value (" << m_minimumImageValue << ") must be strictly positive ! !" << endl);
250  return 1;
251  }
252  // Check that the maximum image value is superior to the min image value
254  {
255  Cerr("***** iOptimizerBSREM::CheckSpecificParameters() -> Provided maximum image value (" << m_maximumImageValue << ") must be positive and superior to twice the minimum image value !" << endl);
256  return 1;
257  }
258  // Check parameters for the relaxation factor
260  {
261  // Check that the relaxation factors initial value is strictly positive
263  {
264  Cerr("***** iOptimizerBSREM::CheckSpecificParameters() -> Provided relaxation factors initial value (" << m_relaxationFactorInitialValue << ") must be strictly positive ! !" << endl);
265  return 1;
266  }
267  // Check that the relaxation factors step size is strictly positive
269  {
270  Cerr("***** iOptimizerBSREM::CheckSpecificParameters() -> Provided relaxation factors step size (" << m_relaxationFactorInitialValue << ") must be strictly positive ! !" << endl);
271  return 1;
272  }
273  }
274  // Normal end
275  return 0;
276 }
277 
278 // =====================================================================
279 // ---------------------------------------------------------------------
280 // ---------------------------------------------------------------------
281 // =====================================================================
282 
284 {
285  // Allocate and create the penalty image
287  // Loop over time basis functions
288  for (int tbf=0; tbf<mp_ImageDimensionsAndQuantification->GetNbTimeBasisFunctions(); tbf++)
289  {
291  // Loop over respiratory basis functions
292  for (int rbf=0; rbf<mp_ImageDimensionsAndQuantification->GetNbRespBasisFunctions(); rbf++)
293  {
295  // Loop over cardiac basis functions
296  for (int cbf=0; cbf<mp_ImageDimensionsAndQuantification->GetNbCardBasisFunctions(); cbf++)
297  {
298  //Get a pointer to a newly allocated image
299  m4p_firstDerivativePenaltyImage[tbf][rbf][cbf] = mp_ImageSpace -> AllocateMiscellaneousImage();
300  // Initialize to 0, in case the penalty is not used
301  for (INTNB v=0; v<mp_ImageDimensionsAndQuantification->GetNbVoxXYZ(); v++) m4p_firstDerivativePenaltyImage[tbf][rbf][cbf][v] = 0.;
302  }
303  }
304  }
305  // Verbose
307  {
308  Cout("iOptimizerBSREM::InitializeSpecific() -> Use the BSREM optimizer" << endl);
310  {
311  Cout(" --> Initial image value: " << m_initialValue << endl);
312  Cout(" --> Minimum image value: " << m_minimumImageValue << endl);
313  Cout(" --> Maximum image value: " << m_maximumImageValue << endl);
315  {
316  Cout(" --> Relaxation factors type: classic" << endl);
317  Cout(" --> Relaxation factors initial value: " << m_relaxationFactorInitialValue << endl);
318  Cout(" --> Relaxation factors step size: " << m_relaxationFactorStepSize << endl);
319  }
320  else
321  {
322  Cerr("***** iOptimizerBSREM::InitializeSpecific() -> Provided relaxation factors type (" << m_relaxationFactorType << ") is not recognized !" << endl);
323  return 1;
324  }
325  }
326  }
327  // Normal end
328  return 0;
329 }
330 
331 // =====================================================================
332 // ---------------------------------------------------------------------
333 // ---------------------------------------------------------------------
334 // =====================================================================
335 
337 {
338  // ==========================================================================================
339  // If no penalty, then exit (the penalty image term has been initialized to 0)
340  if (mp_Penalty==NULL) return 0;
341  // Set the number of threads
342  #ifdef CASTOR_OMP
344  #endif
345  // Verbose
346  if (m_verbose>=1) Cout("iOptimizerBSREM::PreImageUpdateSpecificStep() -> Compute penalty term" << endl);
347  // ==========================================================================================
348  // Global precomputation step if needed by the penalty
350  {
351  Cerr("***** iOptimizerBSREM::PreImageUpdateSpecificStep() -> A problem occurred while computing the penalty pre-processing step !" << endl);
352  return 1;
353  }
354  // ==========================================================================================
355  // Loop over time basis functions
356  for (int tbf=0; tbf<mp_ImageDimensionsAndQuantification->GetNbTimeBasisFunctions(); tbf++)
357  {
358  // Loop over respiratory basis functions
359  for (int rbf=0; rbf<mp_ImageDimensionsAndQuantification->GetNbRespBasisFunctions(); rbf++)
360  {
361  // Loop over cardiac basis functions
362  for (int cbf=0; cbf<mp_ImageDimensionsAndQuantification->GetNbCardBasisFunctions(); cbf++)
363  {
364  // In order to detect problems in the multi-threaded loop
365  bool problem = false;
366  // Voxel index
367  INTNB v;
368  // Multi-threading over voxels
369  #pragma omp parallel for private(v) schedule(guided)
371  {
372  // Get the thread index
373  int th = 0;
374  #ifdef CASTOR_OMP
375  th = omp_get_thread_num();
376  #endif
377  // Local precomputation step if needed by the penalty
378  if (mp_Penalty->LocalPreProcessingStep(tbf,rbf,cbf,v,th))
379  {
380  Cerr("***** iOptimizerBSREM::PreImageUpdateSpecificStep() -> A problem occurred while computing the penalty local pre-processing step for voxel " << v << " !" << endl);
381  problem = true;
382  }
383  // Compute the penalty term at first order
384  m4p_firstDerivativePenaltyImage[tbf][rbf][cbf][v] = mp_Penalty->ComputeFirstDerivative(tbf,rbf,cbf,v,th);
385  }
386  // Check for problems
387  if (problem)
388  {
389  Cerr("***** iOptimizerBSREM::PreImageUpdateSpecificStep() -> A problem occurred inside the multi-threaded loop, stop now !" << endl);
390  return 1;
391  }
392  }
393  }
394  }
395  // ==========================================================================================
396  // Update the relaxation factor and the number of subsets if we are in a new loop
397  if (m_currentSubset == 0)
398  {
400  {
402  if (m_verbose>=2) Cout(" --> Relaxation factor for this iteration: " << m_relaxationFactor << endl);
403  }
404  else
405  {
406  Cerr("***** iOptimizerBSREM::PostDataUpdateSpecificStep -> Unknown relaxation factors type (" << m_relaxationFactorType << ") !" << endl);
407  return 1;
408  }
409  }
410  // Normal end
411  return 0;
412 }
413 
414 // =====================================================================
415 // ---------------------------------------------------------------------
416 // ---------------------------------------------------------------------
417 // =====================================================================
418 
419 int iOptimizerBSREM::SensitivitySpecificOperations( FLTNB a_data, FLTNB a_forwardModel, FLTNB* ap_weight,
420  FLTNB a_multiplicativeCorrections, FLTNB a_additiveCorrections, FLTNB a_blankValue,
421  FLTNB a_quantificationFactor, oProjectionLine* ap_Line )
422 {
423  // Line weight here is simply 1 or any other value. It will actually not be used
424  *ap_weight = 1.;
425  // That's all
426  return 0;
427 }
428 
429 // =====================================================================
430 // ---------------------------------------------------------------------
431 // ---------------------------------------------------------------------
432 // =====================================================================
433 
434 int iOptimizerBSREM::DataSpaceSpecificOperations( FLTNB a_data, FLTNB a_forwardModel, FLTNB* ap_backwardValues,
435  FLTNB a_multiplicativeCorrections, FLTNB a_additiveCorrections, FLTNB a_blankValue,
436  FLTNB a_quantificationFactor, oProjectionLine* ap_Line )
437 {
438  // Compute numerator
439  FLTNB numerator = a_data - a_forwardModel;
440  // Check if the denominator is zero
441  if (a_forwardModel==0.) *ap_backwardValues = 0.;
442  // Update backward values
443  else *ap_backwardValues = numerator / a_forwardModel;
444  // That's all
445  return 0;
446 }
447 
448 // =====================================================================
449 // ---------------------------------------------------------------------
450 // ---------------------------------------------------------------------
451 // =====================================================================
452 
453 int iOptimizerBSREM::ImageSpaceSpecificOperations( FLTNB a_currentImageValue, FLTNB* ap_newImageValue,
454  FLTNB a_sensitivity, FLTNB* ap_correctionValues,
455  INTNB a_voxel, int a_tbf, int a_rbf, int a_cbf )
456 {
457  // Note: This algorithm is sensitive to precision of computations, so everything is performed in HPFLTNB.
458 
459  // Check if correction values (backward matrix) is zero, this means that no data are contributing to the update of this voxel.
460  // In this case, we do not update the voxel value only based on penalty, because it quickly causes numerical problems.
461  if (*ap_correctionValues==0.) return 0;
462 
463  // ===== Implementation of BSREM-I algorithm
464 
465  // Scale penalty with respect to the number of subsets to get correct balance between likelihood and penalty
466  HPFLTNB scaled_penalty = ((HPFLTNB)(m4p_firstDerivativePenaltyImage[a_tbf][a_rbf][a_cbf][a_voxel])) / ((HPFLTNB)(mp_nbSubsets[m_currentIteration]));
467  // Additive update factor without the image scaling (equation (21) in the reference paper)
468  HPFLTNB image_update_factor = m_relaxationFactor * (((HPFLTNB)(*ap_correctionValues))-scaled_penalty) / ((HPFLTNB)a_sensitivity);
469  // Image scaling of the update factor depends on image value (equation (22) in the reference paper)
470  if (a_currentImageValue<=m_maximumImageValue/2.) image_update_factor *= ((HPFLTNB)a_currentImageValue);
471  else image_update_factor *= (m_maximumImageValue-((HPFLTNB)a_currentImageValue));
472  // Update the image
473  *ap_newImageValue = ((HPFLTNB)a_currentImageValue) + image_update_factor;
474 
475  // ===== Up to here, this is the BSREM-I algorithm.
476  // Then, the two following lines implement the BSREM-II algorithm (equation (23) and footnote (9) in the reference paper).
477 
478  // Check if the new image value is lower than 0
479  if (*ap_newImageValue < 0.) *ap_newImageValue = m_minimumImageValue;
480  // Check if the new image value is higher than the max image value
481  if (*ap_newImageValue > m_maximumImageValue) *ap_newImageValue = m_maximumImageValue - m_minimumImageValue;
482 
483  // End
484  return 0;
485 }
486 
487 // =====================================================================
488 // ---------------------------------------------------------------------
489 // ---------------------------------------------------------------------
490 // =====================================================================
void ShowHelpSpecific()
A function used to show help about the child optimizer.
iOptimizerBSREM()
The constructor of iOptimizerBSREM.
int m_requiredPenaltyDerivativesOrder
Definition: vOptimizer.hh:697
int ImageSpaceSpecificOperations(FLTNB a_currentImageValue, FLTNB *ap_newImageValue, FLTNB a_sensitivity, FLTNB *ap_correctionValues, INTNB a_voxel, int a_tbf=-1, int a_rbf=-1, int a_cbf=-1)
This function performs the image update step specific to the optimizer.
int GetNbCardBasisFunctions()
Get the number of cardiac basis functions.
#define FLTNB
Definition: gVariables.hh:81
int ReadOptionsList(const string &a_optionsList)
A function used to read options from a list of options.
#define BSREM_RELAXATION_CLASSIC
FLTNB m_initialValue
Definition: vOptimizer.hh:663
bool m_listmodeCompatibility
Definition: vOptimizer.hh:664
HPFLTNB m_relaxationFactorStepSize
#define HPFLTNB
Definition: gVariables.hh:83
HPFLTNB m_maximumImageValue
HPFLTNB m_relaxationFactorInitialValue
int ReadConfigurationFile(const string &a_configurationFile)
A function used to read options from a configuration file.
#define VERBOSE_DETAIL
oImageDimensionsAndQuantification * mp_ImageDimensionsAndQuantification
Definition: vOptimizer.hh:669
virtual int LocalPreProcessingStep(int a_tbf, int a_rbf, int a_cbf, INTNB a_voxel, int a_th)
A public function computing a local pre-processing step for the penalty.
Definition: vPenalty.cc:149
int GetNbTimeBasisFunctions()
Get the number of time basis functions.
int CheckSpecificParameters()
A private function used to check the parameters settings specific to the child optimizer.
Declaration of class iOptimizerBSREM.
FLTNB **** m4p_firstDerivativePenaltyImage
int InitializeSpecific()
This function is used to initialize specific stuff to the child optimizer.
#define Cerr(MESSAGE)
bool m_needGlobalSensitivity
Definition: vOptimizer.hh:699
bool m_emissionCompatibility
Definition: vOptimizer.hh:666
int SensitivitySpecificOperations(FLTNB a_data, FLTNB a_forwardModel, FLTNB *ap_weight, FLTNB a_multiplicativeCorrections, FLTNB a_additiveCorrections, FLTNB a_blankValue, FLTNB a_quantificationFactor, oProjectionLine *ap_Line)
This function compute the weight associated to the provided event (for sensitivity computation) ...
int m_nbBackwardImages
Definition: vOptimizer.hh:659
virtual int GlobalPreProcessingStep()
A public function computing a global pre-processing step for the penalty.
Definition: vPenalty.cc:138
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...
Definition: gOptions.cc:129
bool m_histogramCompatibility
Definition: vOptimizer.hh:665
#define VERBOSE_NORMAL
#define BSREM_NOT_DEFINED
HPFLTNB m_minimumImageValue
int m_currentSubset
Definition: vOptimizer.hh:679
#define KEYWORD_MANDATORY
Definition: gOptions.hh:47
HPFLTNB m_relaxationFactor
#define INTNB
Definition: gVariables.hh:92
~iOptimizerBSREM()
The destructor of iOptimizerBSREM.
bool m_transmissionCompatibility
Definition: vOptimizer.hh:667
This class is designed to generically described any iterative optimizer.
Definition: vOptimizer.hh:59
This class is designed to manage and store system matrix elements associated to a vEvent...
vPenalty * mp_Penalty
Definition: vOptimizer.hh:698
int m_currentIteration
Definition: vOptimizer.hh:678
Declaration of class sOutputManager.
oImageSpace * mp_ImageSpace
Definition: vOptimizer.hh:670
int GetNbThreadsForImageComputation()
Get the number of threads used for image operations.
INTNB GetNbVoxXYZ()
Get the total number of voxels.
int PreImageUpdateSpecificStep()
A private function used to compute the penalty term of the BSREM algorithm.
int DataSpaceSpecificOperations(FLTNB a_data, FLTNB a_forwardModel, FLTNB *ap_backwardValues, FLTNB a_multiplicativeCorrections, FLTNB a_additiveCorrections, FLTNB a_blankValue, FLTNB a_quantificationFactor, oProjectionLine *ap_Line)
This function performs the data space operations specific to the optimizer (computes the values to be...
int * mp_nbSubsets
Definition: vOptimizer.hh:677
#define Cout(MESSAGE)
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.
Definition: gOptions.cc:50
int GetNbRespBasisFunctions()
Get the number of respiratory basis functions.
virtual FLTNB ComputeFirstDerivative(int a_tbf, int a_rbf, int a_cbf, INTNB a_voxel, int a_th)=0
A public function computing the derivative of the penalty.