CASToR  2.0
Tomographic Reconstruction (PET/SPECT/CT)
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
iOptimizerLandweber.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-2018 all CASToR contributors listed below:
18 
19  --> current contributors: Thibaut MERLIN, Simon STUTE, Didier BENOIT, Claude COMTAT, Marina FILIPOVIC, Mael MILLARDET
20  --> past contributors: Valentin VIELZEUF
21 
22 This is CASToR version 2.0.
23 */
24 
31 #include "iOptimizerLandweber.hh"
32 #include "sOutputManager.hh"
33 
34 // =====================================================================
35 // ---------------------------------------------------------------------
36 // ---------------------------------------------------------------------
37 // =====================================================================
38 
40 {
41  // ---------------------------
42  // Mandatory member parameters
43  // ---------------------------
44 
45  // Initial value at 0
46  m_initialValue = 0.;
47  // Only one backward image for Landweber
49  // Landweber does not accept penalties
50  //m_penaltyEnergyFunctionDerivativesOrder = 0;
51  // Landweber is not compatible with listmode data
53  // Landweber is compatible with histogram data only
55  // Landweber is compatible with both emission and transmission data
58 
59  // --------------------------
60  // Specific member parameters
61  // --------------------------
62 
63  // The custom relaxation parameter
64  m_relaxationFactor = -1.;
65  // Non-negativity constraint
67 }
68 
69 // =====================================================================
70 // ---------------------------------------------------------------------
71 // ---------------------------------------------------------------------
72 // =====================================================================
73 
75 {
76 }
77 
78 // =====================================================================
79 // ---------------------------------------------------------------------
80 // ---------------------------------------------------------------------
81 // =====================================================================
82 
84 {
85  cout << "This optimizer implements the standard Landweber algorithm for least-squares optimization." << endl;
86  cout << "With transmission data, it uses the log-converted model to derive the update." << endl;
87  cout << "Be aware that the relaxation parameter is not automatically set, so it often requires some" << endl;
88  cout << "trials and errors to find an optimal setting. Also, remember that this algorithm is particularly" << endl;
89  cout << "slow to converge." << endl;
90  cout << "The following options can be used (in this particular order when provided as a list):" << endl;
91  cout << " initial image value: to set the uniform voxel value for the initial image" << endl;
92  cout << " relaxation factor: to set the relaxation factor applied to the update" << endl;
93  cout << " non-negativity constraint: 0 if no constraint or 1 in order to apply the constraint during the image update" << endl;
94 }
95 
96 // =====================================================================
97 // ---------------------------------------------------------------------
98 // ---------------------------------------------------------------------
99 // =====================================================================
100 
101 int iOptimizerLandweber::ReadConfigurationFile(const string& a_configurationFile)
102 {
103  string key_word = "";
104  // Read the initial image value option
105  key_word = "initial image value";
106  if (ReadDataASCIIFile(a_configurationFile, key_word, &m_initialValue, 1, KEYWORD_MANDATORY))
107  {
108  Cerr("***** iOptimizerLandweber::ReadConfigurationFile() -> Failed to get the '" << key_word << "' keyword !" << endl);
109  return 1;
110  }
111  // Read the relaxation factor option
112  key_word = "relaxation factor";
113  if (ReadDataASCIIFile(a_configurationFile, key_word, &m_relaxationFactor, 1, KEYWORD_MANDATORY))
114  {
115  Cerr("***** iOptimizerLandweber::ReadConfigurationFile() -> Failed to get the '" << key_word << "' keyword !" << endl);
116  return 1;
117  }
118  // Read the non-negativity constraint option
119  key_word = "non-negativity constraint";
120  if (ReadDataASCIIFile(a_configurationFile, key_word, &m_nonNegativityConstraint, 1, KEYWORD_MANDATORY))
121  {
122  Cerr("***** iOptimizerMLTR::ReadConfigurationFile() -> Failed to get the '" << key_word << "' keyword !" << endl);
123  return 1;
124  }
125  // Normal end
126  return 0;
127 }
128 
129 // =====================================================================
130 // ---------------------------------------------------------------------
131 // ---------------------------------------------------------------------
132 // =====================================================================
133 
134 int iOptimizerLandweber::ReadOptionsList(const string& a_optionsList)
135 {
136  // There are 3 floating point variables as options
137  const int nb_options = 3;
138  FLTNB options[nb_options];
139 
140  // Read them
141  if (ReadStringOption(a_optionsList, options, nb_options, ",", "Landweber configuration"))
142  {
143  Cerr("***** iOptimizerLandweber::ReadOptionsList() -> Failed to correctly read the list of options !" << endl);
144  return 1;
145  }
146  // Affect options
147  m_initialValue = options[0];
148  m_relaxationFactor = options[1];
149  if (options[2]==0.) m_nonNegativityConstraint = false;
150  else m_nonNegativityConstraint = true;
151  // Normal end
152  return 0;
153 }
154 
155 // =====================================================================
156 // ---------------------------------------------------------------------
157 // ---------------------------------------------------------------------
158 // =====================================================================
159 
161 {
162  // Check that relaxation factor value is strictly positive
163  if (m_relaxationFactor<=0.)
164  {
165  Cerr("***** iOptimizerLandweber->CheckSpecificParameters() -> Provided relaxation factor (" << m_relaxationFactor << ") must be strictly positive !" << endl);
166  return 1;
167  }
168  // Normal end
169  return 0;
170 }
171 
172 // =====================================================================
173 // ---------------------------------------------------------------------
174 // ---------------------------------------------------------------------
175 // =====================================================================
176 
178 {
179  // Verbose
181  {
182  Cout("iOptimizerLandweber::InitializeSpecific() -> Use the Landweber algorithm" << endl);
184  {
185  Cout(" --> Initial image value: " << m_initialValue << endl);
186  Cout(" --> Relaxation factor: " << m_relaxationFactor << endl);
187  if (m_nonNegativityConstraint) Cout(" --> Apply a non-negativity constraint during image update" << endl);
188  }
189  }
190  // Normal end
191  return 0;
192 }
193 
194 // =====================================================================
195 // ---------------------------------------------------------------------
196 // ---------------------------------------------------------------------
197 // =====================================================================
198 
199 int iOptimizerLandweber::SensitivitySpecificOperations( FLTNB a_data, FLTNB a_forwardModel, FLTNB* ap_weight,
200  FLTNB a_multiplicativeCorrections, FLTNB a_additiveCorrections, FLTNB a_blankValue,
201  FLTNB a_quantificationFactor, oProjectionLine* ap_Line )
202 {
203  // Line weight here is simply 1
204  *ap_weight = 1.;
205  // That's all
206  return 0;
207 }
208 
209 // =====================================================================
210 // ---------------------------------------------------------------------
211 // ---------------------------------------------------------------------
212 // =====================================================================
213 
214 int iOptimizerLandweber::DataSpaceSpecificOperations( FLTNB a_data, FLTNB a_forwardModel, FLTNB* ap_backwardValues,
215  FLTNB a_multiplicativeCorrections, FLTNB a_additiveCorrections, FLTNB a_blankValue,
216  FLTNB a_quantificationFactor, oProjectionLine* ap_Line )
217 {
218  // Case for emission tomography
220  {
221  // Simply subtract the model from the data
222  *ap_backwardValues = (a_data - a_forwardModel);
223  }
224  // Case for transmission tomography
225  else if (m_dataSpec==SPEC_TRANSMISSION)
226  {
227  // Subtract scatters
228  a_data -= a_additiveCorrections;
229  a_forwardModel -= a_additiveCorrections;
230  // Truncate both if less than 1
231  if (a_data<1.) a_data = 1.;
232  if (a_forwardModel<1.) a_forwardModel = 1.;
233  *ap_backwardValues = log( a_forwardModel / a_data );
234  }
235  // That's all
236  return 0;
237 }
238 
239 // =====================================================================
240 // ---------------------------------------------------------------------
241 // ---------------------------------------------------------------------
242 // =====================================================================
243 
244 int iOptimizerLandweber::ImageSpaceSpecificOperations( FLTNB a_currentImageValue, FLTNB* ap_newImageValue,
245  FLTNB a_sensitivity, FLTNB* ap_correctionValues, INTNB a_voxel )
246 {
247  // Compute image update factor
248  FLTNB image_update_factor = *ap_correctionValues * m_relaxationFactor / a_sensitivity;
249  // Update image
250  *ap_newImageValue = a_currentImageValue + image_update_factor;
251  // Apply non-negativity constraint if asked for
252  if (m_nonNegativityConstraint && *ap_newImageValue<0.) *ap_newImageValue = 0.;
253  // End
254  return 0;
255 }
256 
257 // =====================================================================
258 // ---------------------------------------------------------------------
259 // ---------------------------------------------------------------------
260 // =====================================================================
int ReadOptionsList(const string &a_optionsList)
A function used to read options from a list of options.
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) ...
void ShowHelpSpecific()
A function used to show help about the child optimizer.
#define FLTNB
Definition: gVariables.hh:81
int ImageSpaceSpecificOperations(FLTNB a_currentImageValue, FLTNB *ap_newImageValue, FLTNB a_sensitivity, FLTNB *ap_correctionValues, INTNB a_voxel)
This function perform the image update step specific to the optimizer.
FLTNB m_initialValue
Definition: vOptimizer.hh:619
bool m_listmodeCompatibility
Definition: vOptimizer.hh:620
#define VERBOSE_DETAIL
int ReadConfigurationFile(const string &a_configurationFile)
A function used to read options from a configuration file.
~iOptimizerLandweber()
The destructor of iOptimizerLandweber.
int m_dataSpec
Definition: vOptimizer.hh:629
int InitializeSpecific()
This function is used to initialize specific stuff to the child optimizer.
#define Cerr(MESSAGE)
bool m_emissionCompatibility
Definition: vOptimizer.hh:622
int CheckSpecificParameters()
A private function used to check the parameters settings specific to the child optimizer.
int m_nbBackwardImages
Definition: vOptimizer.hh:615
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:123
bool m_histogramCompatibility
Definition: vOptimizer.hh:621
#define VERBOSE_NORMAL
#define KEYWORD_MANDATORY
Definition: gOptions.hh:48
#define SPEC_TRANSMISSION
Definition: vDataFile.hh:93
#define INTNB
Definition: gVariables.hh:92
Declaration of class iOptimizerLandweber.
bool m_transmissionCompatibility
Definition: vOptimizer.hh:623
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...
iOptimizerLandweber()
The constructor of iOptimizerLandweber.
Declaration of class sOutputManager.
#define SPEC_EMISSION
Definition: vDataFile.hh:91
#define Cout(MESSAGE)
int ReadStringOption(const string &a_input, T *ap_return, int a_nbElts, const string &sep, const string &a_option)
Parse the 'a_input' string corresponding to the 'a_option' into 'a_nbElts' elements, using the 'sep' separator. The results are returned in the templated 'ap_return' dynamic templated array. Call "ConvertFromString()" to perform the correct conversion depending on the type of the data to convert.
Definition: gOptions.cc:62
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...