ANIMA  4.0
animaMultiCompartmentModel.cxx
Go to the documentation of this file.
2 #include <animaMCMConstants.h>
3 
4 namespace anima
5 {
6 
8 {
9  m_OptimizeWeights = true;
10  m_CommonDiffusivityParameters = false;
11  m_CommonConcentrationParameters = false;
12  m_CommonExtraAxonalFractionParameters = false;
13  m_NegativeWeightBounds = false;
14 
15  m_NumberOfIsotropicCompartments = 0;
16 }
17 
19 {
20 }
21 
22 itk::LightObject::Pointer MultiCompartmentModel::InternalClone() const
23 {
24  itk::LightObject::Pointer outputValue = Superclass::InternalClone();
25 
26  Self *mcm = dynamic_cast <Self *> (outputValue.GetPointer());
27  for (unsigned int i = 0;i < m_Compartments.size();++i)
28  {
29  BaseCompartmentPointer tmpCompartment = dynamic_cast <anima::BaseCompartment *> (m_Compartments[i]->Clone().GetPointer());
30  mcm->AddCompartment(m_CompartmentWeights[i],tmpCompartment);
31  }
32 
33  mcm->SetOptimizeWeights(m_OptimizeWeights);
34  mcm->SetCommonDiffusivityParameters(m_CommonDiffusivityParameters);
35  mcm->SetCommonConcentrationParameters(m_CommonConcentrationParameters);
36  mcm->SetCommonExtraAxonalFractionParameters(m_CommonExtraAxonalFractionParameters);
37 
38  return outputValue;
39 }
40 
41 void MultiCompartmentModel::AddCompartment(double weight, BaseCompartment *compartment)
42 {
43  unsigned int pos = 0;
44 
45  for (pos = m_Compartments.size();pos > 0;--pos)
46  {
47  if (m_Compartments[pos - 1]->GetCompartmentType() <= compartment->GetCompartmentType())
48  break;
49  }
50 
51  m_Compartments.insert(m_Compartments.begin() + pos, compartment);
52  m_CompartmentWeights.insert(m_CompartmentWeights.begin() + pos, weight);
53 
54  DiffusionModelCompartmentType compType = compartment->GetCompartmentType();
55 
56  if ((compType == anima::FreeWater)||(compType == anima::StationaryWater)||
57  (compType == anima::IsotropicRestrictedWater)||(compType == anima::Stanisz))
58  ++m_NumberOfIsotropicCompartments;
59 }
60 
62 {
63  if (i > this->GetNumberOfCompartments())
64  return ITK_NULLPTR;
65 
66  return m_Compartments[i];
67 }
68 
70 {
71  unsigned int vectorSize = 0;
72  for (unsigned int i = 0;i < m_Compartments.size();++i)
73  vectorSize += m_Compartments[i]->GetNumberOfParameters();
74 
75  unsigned int numWeightsToOptimize = this->GetNumberOfOptimizedWeights();
76 
77  vectorSize += numWeightsToOptimize;
78 
79  m_ParametersVector.resize(vectorSize);
80 
81  unsigned int pos = 0;
82  // Not accounting for optimize weights with common compartment weights, and no free water
83  // In that case, weights are not optimized
84  for (unsigned int i = 0;i < numWeightsToOptimize;++i)
85  m_ParametersVector[i] = m_CompartmentWeights[i];
86 
87  pos += numWeightsToOptimize;
88 
89  for (unsigned int i = 0;i < m_Compartments.size();++i)
90  {
91  m_WorkVector = m_Compartments[i]->GetParametersAsVector();
92 
93  for (unsigned int j = 0;j < m_WorkVector.size();++j)
94  m_ParametersVector[pos + j] = m_WorkVector[j];
95 
96  pos += m_WorkVector.size();
97  }
98 
99  return m_ParametersVector;
100 }
101 
103 {
104  if (i >= m_CompartmentWeights.size())
105  itkExceptionMacro("Trying to access an unreferenced weight index");
106 
107  return m_CompartmentWeights[i];
108 }
109 
111 {
112  if (weights.size() != m_CompartmentWeights.size())
113  itkExceptionMacro("Compartment weights sizes differ in set");
114 
115  for (unsigned int i = 0;i < weights.size();++i)
116  m_CompartmentWeights[i] = weights[i];
117 }
118 
120 {
121  unsigned int pos = 0;
122  unsigned int numCompartments = this->GetNumberOfCompartments();
123  unsigned int numWeightsToOptimize = this->GetNumberOfOptimizedWeights();
124 
125  // Set compartment fractions if optimized
126  for (unsigned int i = 0;i < numWeightsToOptimize;++i)
127  m_CompartmentWeights[i] = params[i];
128 
129  pos = numWeightsToOptimize;
130 
131  for (unsigned int i = 0;i < numCompartments;++i)
132  {
133  unsigned int tmpCompartmentSize = m_Compartments[i]->GetNumberOfParameters();
134 
135  // Set compartment parameters
136  m_WorkVector.resize(tmpCompartmentSize);
137  std::copy(params.begin() + pos,params.begin() + pos + tmpCompartmentSize,m_WorkVector.begin());
138 
139  m_Compartments[i]->SetParametersFromVector(m_WorkVector);
140 
141  if (i > m_NumberOfIsotropicCompartments)
142  {
143  if (m_CommonDiffusivityParameters)
144  {
145  m_Compartments[i]->SetAxialDiffusivity(m_Compartments[m_NumberOfIsotropicCompartments]->GetAxialDiffusivity());
146  m_Compartments[i]->SetRadialDiffusivity1(m_Compartments[m_NumberOfIsotropicCompartments]->GetRadialDiffusivity1());
147  m_Compartments[i]->SetRadialDiffusivity2(m_Compartments[m_NumberOfIsotropicCompartments]->GetRadialDiffusivity2());
148  }
149 
150  if (m_CommonConcentrationParameters)
151  m_Compartments[i]->SetOrientationConcentration(m_Compartments[m_NumberOfIsotropicCompartments]->GetOrientationConcentration());
152 
153  if (m_CommonExtraAxonalFractionParameters)
154  m_Compartments[i]->SetExtraAxonalFraction(m_Compartments[m_NumberOfIsotropicCompartments]->GetExtraAxonalFraction());
155  }
156 
157  pos += tmpCompartmentSize;
158  }
159 }
160 
162 {
163  if (m_ModelVector.GetSize() != this->GetSize())
164  m_ModelVector.SetSize(this->GetSize());
165  m_ModelVector.Fill(0.0);
166 
167  unsigned int numCompartments = this->GetNumberOfCompartments();
168 
169  for (unsigned int i = 0;i < numCompartments;++i)
170  m_ModelVector[i] = m_CompartmentWeights[i];
171 
172  unsigned int pos = numCompartments;
173  ModelOutputVectorType tmpParams;
174 
175  for (unsigned int i = 0;i < numCompartments;++i)
176  {
177  if (m_CompartmentWeights[i] != 0.0)
178  {
179  tmpParams = m_Compartments[i]->GetCompartmentVector();
180  for (unsigned int j = 0;j < m_Compartments[i]->GetCompartmentSize();++j)
181  m_ModelVector[pos + j] = tmpParams[j];
182  }
183 
184  pos += m_Compartments[i]->GetCompartmentSize();
185  }
186 
187  return m_ModelVector;
188 }
189 
190 void MultiCompartmentModel::SetModelVector(const itk::VariableLengthVector <float> &mcmVec)
191 {
192  unsigned int numCompartments = this->GetNumberOfCompartments();
193 
194  for (unsigned int i = 0;i < numCompartments;++i)
195  m_CompartmentWeights[i] = mcmVec[i];
196 
197  unsigned int pos = numCompartments;
198 
199  for (unsigned int i = 0;i < numCompartments;++i)
200  {
201  unsigned int compartmentSize = m_Compartments[i]->GetCompartmentSize();
202  ModelOutputVectorType inputVector(compartmentSize);
203  for (unsigned int j = 0;j < compartmentSize;++j)
204  inputVector[j] = mcmVec[pos + j];
205 
206  m_Compartments[i]->SetCompartmentVector(inputVector);
207  pos += compartmentSize;
208  }
209 }
210 
212 {
213  unsigned int numCompartments = this->GetNumberOfCompartments();
214 
215  for (unsigned int i = 0;i < numCompartments;++i)
216  m_CompartmentWeights[i] = mcmVec[i];
217 
218  unsigned int pos = numCompartments;
219 
220  for (unsigned int i = 0;i < numCompartments;++i)
221  {
222  unsigned int compartmentSize = m_Compartments[i]->GetCompartmentSize();
223  ModelOutputVectorType inputVector(compartmentSize);
224  for (unsigned int j = 0;j < compartmentSize;++j)
225  inputVector[j] = mcmVec[pos + j];
226 
227  m_Compartments[i]->SetCompartmentVector(inputVector);
228  pos += compartmentSize;
229  }
230 }
231 
232 double MultiCompartmentModel::GetPredictedSignal(double smallDelta, double bigDelta, double gradientStrength, const Vector3DType &gradient)
233 {
234  double ftDiffusionProfile = 0;
235 
236  for (unsigned int i = 0;i < m_Compartments.size();++i)
237  {
238  if (m_CompartmentWeights[i] != 0.0)
239  ftDiffusionProfile += m_CompartmentWeights[i] * m_Compartments[i]->GetFourierTransformedDiffusionProfile(smallDelta, bigDelta, gradientStrength, gradient);
240  }
241 
242  return ftDiffusionProfile;
243 }
244 
245 MultiCompartmentModel::ListType &MultiCompartmentModel::GetSignalJacobian(double smallDelta, double bigDelta, double gradientStrength, const Vector3DType &gradient)
246 {
247  unsigned int jacobianSize = 0;
248  for (unsigned int i = 0;i < m_Compartments.size();++i)
249  jacobianSize += m_Compartments[i]->GetNumberOfParameters();
250 
251  unsigned int numWeightsToOptimize = this->GetNumberOfOptimizedWeights();
252  jacobianSize += numWeightsToOptimize;
253 
254  m_JacobianVector.resize(jacobianSize);
255  std::fill(m_JacobianVector.begin(), m_JacobianVector.end(), 0.0);
256 
257  unsigned int pos = 0;
258  // Not accounting for optimize weights with common compartment weights, and no free water
259  // In that case, weights are not optimized
260  for (unsigned int i = 0;i < numWeightsToOptimize;++i)
261  m_JacobianVector[i] = - m_Compartments[i]->GetFourierTransformedDiffusionProfile(smallDelta, bigDelta, gradientStrength, gradient);
262 
263  pos += numWeightsToOptimize;
264 
265  for (unsigned int i = 0;i < m_Compartments.size();++i)
266  {
267  m_WorkVector = m_Compartments[i]->GetSignalAttenuationJacobian(smallDelta, bigDelta, gradientStrength, gradient);
268 
269  for (unsigned int j = 0;j < m_WorkVector.size();++j)
270  m_JacobianVector[pos + j] -= m_CompartmentWeights[i] * m_WorkVector[j];
271 
272  pos += m_WorkVector.size();
273  }
274 
275  return m_JacobianVector;
276 }
277 
279 {
280  double resVal = 0;
281 
282  for (unsigned int i = 0;i < m_Compartments.size();++i)
283  {
284  if (m_CompartmentWeights[i] != 0.0)
285  resVal += m_CompartmentWeights[i] * std::exp(m_Compartments[i]->GetLogDiffusionProfile(sample));
286  }
287 
288  return resVal;
289 }
290 
292 {
293  unsigned int vectorSize = 0;
294  for (unsigned int i = 0;i < m_Compartments.size();++i)
295  vectorSize += m_Compartments[i]->GetNumberOfParameters();
296 
297  unsigned int numWeightsToOptimize = this->GetNumberOfOptimizedWeights();
298  vectorSize += numWeightsToOptimize;
299 
300  m_ParametersLowerBoundsVector.resize(vectorSize);
301 
302  unsigned int pos = 0;
303  // Lower bound of weights is 0
304  if (!m_NegativeWeightBounds)
305  {
306  for (unsigned int i = 0;i < numWeightsToOptimize;++i)
307  m_ParametersLowerBoundsVector[i] = anima::MCMZeroLowerBound;
308  }
309  else
310  {
311  for (unsigned int i = 0;i < numWeightsToOptimize;++i)
312  m_ParametersLowerBoundsVector[i] = - anima::MCMFractionUpperBound;
313  }
314 
315  pos += numWeightsToOptimize;
316 
317  for (unsigned int i = 0;i < m_Compartments.size();++i)
318  {
319  m_WorkVector = m_Compartments[i]->GetParameterLowerBounds();
320  for (unsigned int j = 0;j < m_WorkVector.size();++j)
321  m_ParametersLowerBoundsVector[pos + j] = m_WorkVector[j];
322 
323  pos += m_WorkVector.size();
324  }
325 
326  return m_ParametersLowerBoundsVector;
327 }
328 
330 {
331  unsigned int vectorSize = 0;
332  for (unsigned int i = 0;i < m_Compartments.size();++i)
333  vectorSize += m_Compartments[i]->GetNumberOfParameters();
334 
335  unsigned int numWeightsToOptimize = this->GetNumberOfOptimizedWeights();
336 
337  vectorSize += numWeightsToOptimize;
338  m_ParametersUpperBoundsVector.resize(vectorSize);
339 
340  unsigned int pos = 0;
341  // Upper bound of weights is 1
342  if (!m_NegativeWeightBounds)
343  {
344  for (unsigned int i = 0;i < numWeightsToOptimize;++i)
345  m_ParametersUpperBoundsVector[i] = anima::MCMCompartmentsFractionUpperBound;
346  }
347  else
348  {
349  for (unsigned int i = 0;i < numWeightsToOptimize;++i)
350  m_ParametersUpperBoundsVector[i] = - anima::MCMZeroLowerBound;
351  }
352 
353  pos += numWeightsToOptimize;
354 
355  for (unsigned int i = 0;i < m_Compartments.size();++i)
356  {
357  m_WorkVector = m_Compartments[i]->GetParameterUpperBounds();
358  for (unsigned int j = 0;j < m_WorkVector.size();++j)
359  m_ParametersUpperBoundsVector[pos + j] = m_WorkVector[j];
360 
361  pos += m_WorkVector.size();
362  }
363 
364  return m_ParametersUpperBoundsVector;
365 }
366 
368 {
369  int numWeightsToOptimize = 0;
370  if (m_OptimizeWeights)
371  numWeightsToOptimize = m_Compartments.size();
372 
373  return numWeightsToOptimize;
374 }
375 
377 {
378  unsigned int numParams = 0;
379 
380  for (unsigned int i = 0;i < m_Compartments.size();++i)
381  numParams += m_Compartments[i]->GetNumberOfParameters();
382 
383  numParams += this->GetNumberOfOptimizedWeights();
384 
385  return numParams;
386 }
387 
389 {
390  // Weights
391  unsigned int numParams = m_Compartments.size();
392 
393  // Add individual compartments sizes
394  for (unsigned int i = 0;i < m_Compartments.size();++i)
395  numParams += m_Compartments[i]->GetCompartmentSize();
396 
397  return numParams;
398 }
399 
400 void MultiCompartmentModel::Reorient(vnl_matrix <double> &orientationMatrix, bool affineTransform)
401 {
402  for (unsigned int i = 0;i < m_Compartments.size();++i)
403  m_Compartments[i]->Reorient(orientationMatrix,affineTransform);
404 }
405 
406 } // end namespace anima
BaseCompartment::Pointer BaseCompartmentPointer
const double MCMZeroLowerBound
Default zero lower bound (in case we want something else than zero one day)
BaseCompartment * GetCompartment(unsigned int i)
ListType & GetSignalJacobian(double smallDelta, double bigDelta, double gradientStrength, const Vector3DType &gradient)
unsigned int GetNumberOfParameters()
Number of parameters to be optimized.
double GetDiffusionProfile(Vector3DType &sample)
void SetCompartmentWeights(const ListType &weights)
void SetParametersFromVector(ListType &params)
BaseCompartment::ListType ListType
const double MCMFractionUpperBound
Fraction upper bound (intra/extra axonal)
unsigned int GetNumberOfOptimizedWeights()
Number of weights that are optimized.
itk::LightObject::Pointer InternalClone() const ITK_OVERRIDE
DiffusionModelCompartmentType
void SetModelVector(const itk::VariableLengthVector< float > &mcmVec)
const double MCMCompartmentsFractionUpperBound
Compartment fractions upper bound (B0 times weight)
BaseCompartment::Vector3DType Vector3DType
virtual DiffusionModelCompartmentType GetCompartmentType()=0
Utility function to return compartment type without needing dynamic casts.
MultiCompartmentModel: holds several diffusion compartments, ordered by type It also handles weights ...
void AddCompartment(double weight, BaseCompartment *compartment)
ModelOutputVectorType & GetModelVector()
double GetPredictedSignal(double smallDelta, double bigDelta, double gradientStrength, const Vector3DType &gradient)
void Reorient(vnl_matrix< double > &orientationMatrix, bool affineTransform)
Re-orient the MCM using the provided transform, the flag precises if the transform id rigid or affine...
BaseCompartment::ModelOutputVectorType ModelOutputVectorType
unsigned int GetSize()
Number of parameters to have a self-contained description of the MCM.