CASToR  3.0
Tomographic Reconstruction (PET/SPECT/CT)
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-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 "iOptimizerLandweber.hh"
31 #include "sOutputManager.hh"
32 
33 // =====================================================================
34 // ---------------------------------------------------------------------
35 // ---------------------------------------------------------------------
36 // =====================================================================
37 
39 {
40  // ---------------------------
41  // Mandatory member parameters
42  // ---------------------------
43 
44  // Initial value at 0
45  m_initialValue = 0.;
46  // Only one backward image for Landweber
48  // Landweber is not compatible with listmode data
50  // Landweber is compatible with histogram data only
52  // Landweber is compatible with both emission and transmission data
55 
56  // --------------------------
57  // Specific member parameters
58  // --------------------------
59 
60  // The custom relaxation parameter
61  m_relaxationFactor = -1.;
62  // Non-negativity constraint
64 }
65 
66 // =====================================================================
67 // ---------------------------------------------------------------------
68 // ---------------------------------------------------------------------
69 // =====================================================================
70 
72 {
73 }
74 
75 // =====================================================================
76 // ---------------------------------------------------------------------
77 // ---------------------------------------------------------------------
78 // =====================================================================
79 
81 {
82  cout << "This optimizer implements the standard Landweber algorithm for least-squares optimization." << endl;
83  cout << "With transmission data, it uses the log-converted model to derive the update." << endl;
84  cout << "Be aware that the relaxation parameter is not automatically set, so it often requires some" << endl;
85  cout << "trials and errors to find an optimal setting. Also, remember that this algorithm is particularly" << endl;
86  cout << "slow to converge." << endl;
87  cout << "The following options can be used (in this particular order when provided as a list):" << endl;
88  cout << " initial image value: to set the uniform voxel value for the initial image" << endl;
89  cout << " relaxation factor: to set the relaxation factor applied to the update" << endl;
90  cout << " non-negativity constraint: 0 if no constraint or 1 in order to apply the constraint during the image update" << endl;
91 }
92 
93 // =====================================================================
94 // ---------------------------------------------------------------------
95 // ---------------------------------------------------------------------
96 // =====================================================================
97 
98 int iOptimizerLandweber::ReadConfigurationFile(const string& a_configurationFile)
99 {
100  string key_word = "";
101  // Read the initial image value option
102  key_word = "initial image value";
103  if (ReadDataASCIIFile(a_configurationFile, key_word, &m_initialValue, 1, KEYWORD_MANDATORY))
104  {
105  Cerr("***** iOptimizerLandweber::ReadConfigurationFile() -> Failed to get the '" << key_word << "' keyword !" << endl);
106  return 1;
107  }
108  // Read the relaxation factor option
109  key_word = "relaxation factor";
110  if (ReadDataASCIIFile(a_configurationFile, key_word, &m_relaxationFactor, 1, KEYWORD_MANDATORY))
111  {
112  Cerr("***** iOptimizerLandweber::ReadConfigurationFile() -> Failed to get the '" << key_word << "' keyword !" << endl);
113  return 1;
114  }
115  // Read the non-negativity constraint option
116  key_word = "non-negativity constraint";
117  if (ReadDataASCIIFile(a_configurationFile, key_word, &m_nonNegativityConstraint, 1, KEYWORD_MANDATORY))
118  {
119  Cerr("***** iOptimizerMLTR::ReadConfigurationFile() -> Failed to get the '" << key_word << "' keyword !" << endl);
120  return 1;
121  }
122  // Normal end
123  return 0;
124 }
125 
126 // =====================================================================
127 // ---------------------------------------------------------------------
128 // ---------------------------------------------------------------------
129 // =====================================================================
130 
131 int iOptimizerLandweber::ReadOptionsList(const string& a_optionsList)
132 {
133  // There are 3 floating point variables as options
134  const int nb_options = 3;
135  FLTNB options[nb_options];
136  // Read them
137  if (ReadStringOption(a_optionsList, options, nb_options, ",", "Landweber configuration"))
138  {
139  Cerr("***** iOptimizerLandweber::ReadOptionsList() -> Failed to correctly read the list of options !" << endl);
140  return 1;
141  }
142  // Affect options
143  m_initialValue = options[0];
144  m_relaxationFactor = options[1];
145  if (options[2]==0.) m_nonNegativityConstraint = false;
146  else m_nonNegativityConstraint = true;
147  // Normal end
148  return 0;
149 }
150 
151 // =====================================================================
152 // ---------------------------------------------------------------------
153 // ---------------------------------------------------------------------
154 // =====================================================================
155 
157 {
158  // Check that relaxation factor value is strictly positive
159  if (m_relaxationFactor<=0.)
160  {
161  Cerr("***** iOptimizerLandweber->CheckSpecificParameters() -> Provided relaxation factor (" << m_relaxationFactor << ") must be strictly positive !" << endl);
162  return 1;
163  }
164  // Normal end
165  return 0;
166 }
167 
168 // =====================================================================
169 // ---------------------------------------------------------------------
170 // ---------------------------------------------------------------------
171 // =====================================================================
172 
174 {
175  // Verbose
177  {
178  Cout("iOptimizerLandweber::InitializeSpecific() -> Use the Landweber algorithm" << endl);
180  {
181  Cout(" --> Initial image value: " << m_initialValue << endl);
182  Cout(" --> Relaxation factor: " << m_relaxationFactor << endl);
183  if (m_nonNegativityConstraint) Cout(" --> Apply a non-negativity constraint during image update" << endl);
184  }
185  }
186  // Normal end
187  return 0;
188 }
189 
190 // =====================================================================
191 // ---------------------------------------------------------------------
192 // ---------------------------------------------------------------------
193 // =====================================================================
194 
195 int iOptimizerLandweber::SensitivitySpecificOperations( FLTNB a_data, FLTNB a_forwardModel, FLTNB* ap_weight,
196  FLTNB a_multiplicativeCorrections, FLTNB a_additiveCorrections, FLTNB a_blankValue,
197  FLTNB a_quantificationFactor, oProjectionLine* ap_Line )
198 {
199  // Line weight here is simply 1
200  *ap_weight = 1.;
201  // That's all
202  return 0;
203 }
204 
205 // =====================================================================
206 // ---------------------------------------------------------------------
207 // ---------------------------------------------------------------------
208 // =====================================================================
209 
210 int iOptimizerLandweber::DataSpaceSpecificOperations( FLTNB a_data, FLTNB a_forwardModel, FLTNB* ap_backwardValues,
211  FLTNB a_multiplicativeCorrections, FLTNB a_additiveCorrections, FLTNB a_blankValue,
212  FLTNB a_quantificationFactor, oProjectionLine* ap_Line )
213 {
214  // Case for emission tomography
216  {
217  // Simply subtract the model from the data
218  *ap_backwardValues = (a_data - a_forwardModel);
219  }
220  // Case for transmission tomography
221  else if (m_dataSpec==SPEC_TRANSMISSION)
222  {
223  // Subtract scatters
224  a_data -= a_additiveCorrections;
225  a_forwardModel -= a_additiveCorrections;
226  // Safely ignore this data if data or model is less than 1 (set backward value to 0 and return)
227  if (a_data<1. || a_forwardModel<1.) *ap_backwardValues = 0.;
228  // Otherwise, proceed to subtraction of log converted data and model
229  *ap_backwardValues = log( a_forwardModel / a_data );
230  }
231  // That's all
232  return 0;
233 }
234 
235 // =====================================================================
236 // ---------------------------------------------------------------------
237 // ---------------------------------------------------------------------
238 // =====================================================================
239 
240 int iOptimizerLandweber::ImageSpaceSpecificOperations( FLTNB a_currentImageValue, FLTNB* ap_newImageValue,
241  FLTNB a_sensitivity, FLTNB* ap_correctionValues,
242  INTNB a_voxel, int a_tbf, int a_rbf, int a_cbf )
243 {
244  // Compute image update factor
245  FLTNB image_update_factor = *ap_correctionValues * m_relaxationFactor / a_sensitivity;
246  // Update image
247  *ap_newImageValue = a_currentImageValue + image_update_factor;
248  // Apply non-negativity constraint if asked for
249  if (m_nonNegativityConstraint && *ap_newImageValue<0.) *ap_newImageValue = 0.;
250  // End
251  return 0;
252 }
253 
254 // =====================================================================
255 // ---------------------------------------------------------------------
256 // ---------------------------------------------------------------------
257 // =====================================================================
int ReadOptionsList(const string &a_optionsList)
A function used to read options from a list of options.
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 perform the image update step specific to the optimizer.
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
FLTNB m_initialValue
Definition: vOptimizer.hh:663
bool m_listmodeCompatibility
Definition: vOptimizer.hh:664
#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:673
int InitializeSpecific()
This function is used to initialize specific stuff to the child optimizer.
#define Cerr(MESSAGE)
bool m_emissionCompatibility
Definition: vOptimizer.hh:666
int CheckSpecificParameters()
A private function used to check the parameters settings specific to the child optimizer.
int m_nbBackwardImages
Definition: vOptimizer.hh:659
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 KEYWORD_MANDATORY
Definition: gOptions.hh:47
#define SPEC_TRANSMISSION
Definition: vDataFile.hh:92
#define INTNB
Definition: gVariables.hh:92
Declaration of class iOptimizerLandweber.
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...
iOptimizerLandweber()
The constructor of iOptimizerLandweber.
Declaration of class sOutputManager.
#define SPEC_EMISSION
Definition: vDataFile.hh:90
#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 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...