ANIMA  4.0
animaStaniszCompartment.cxx
Go to the documentation of this file.
2 
4 #include <animaMCMConstants.h>
5 
6 namespace anima
7 {
8 
9 void StaniszCompartment::UpdateSignals(double smallDelta, double bigDelta, double gradientStrength)
10 {
11  if ((std::abs(smallDelta - m_CurrentSmallDelta) < 1.0e-6) &&
12  (std::abs(bigDelta - m_CurrentBigDelta)) &&
13  (std::abs(gradientStrength - m_CurrentGradientStrength) < 1.0e-6) &&
14  (!m_ModifiedParameters))
15  return;
16 
17  double alpha = anima::DiffusionGyromagneticRatio * smallDelta * gradientStrength;
18  double tissueRadius = this->GetTissueRadius();
19  double axialDiff = this->GetAxialDiffusivity();
20  double alphaRs = alpha * tissueRadius;
21  double alphaRsSquare = alphaRs * alphaRs;
22  double deltaDiff = bigDelta - smallDelta / 3.0;
23 
24  m_FirstSummation = 0.0;
25  m_SecondSummation = 0.0;
26  m_ThirdSummation = 0.0;
27  m_FourthSummation = 0.0;
28  for (unsigned int n = 1;n <= m_MaximumNumberOfSumElements;++n)
29  {
30  double npiSquare = n * M_PI * n * M_PI;
31  double expInternalValue = npiSquare * deltaDiff * axialDiff / (tissueRadius * tissueRadius);
32  double denomValue = alphaRsSquare - npiSquare;
33 
34  double internalTermCos = std::exp(- expInternalValue);
35  if (internalTermCos == 0)
36  continue;
37 
38  double internalTermSin = internalTermCos;
39 
40  if (n % 2 == 0)
41  {
42  internalTermCos *= 1.0 - std::cos(alphaRs);
43  internalTermSin *= std::sin(alphaRs);
44  }
45  else
46  {
47  internalTermCos *= 1.0 + std::cos(alphaRs);
48  internalTermSin *= - std::sin(alphaRs);
49  }
50 
51  internalTermCos /= denomValue * denomValue;
52  internalTermSin /= denomValue * denomValue;
53 
54  m_FirstSummation += internalTermCos;
55  m_SecondSummation += internalTermCos * n * n;
56  m_ThirdSummation += internalTermSin;
57  m_FourthSummation += internalTermCos / denomValue;
58  }
59 
60  m_CurrentSmallDelta = smallDelta;
61  m_CurrentBigDelta = bigDelta;
62  m_CurrentGradientStrength = gradientStrength;
63  m_ModifiedParameters = false;
64 }
65 
66 double StaniszCompartment::GetFourierTransformedDiffusionProfile(double smallDelta, double bigDelta, double gradientStrength, const Vector3DType &gradient)
67 {
68  this->UpdateSignals(smallDelta, bigDelta, gradientStrength);
69 
70  double alpha = anima::DiffusionGyromagneticRatio * smallDelta * gradientStrength;
71  double alphaRs = alpha * this->GetTissueRadius();
72  double alphaRsSquare = alphaRs * alphaRs;
73 
74  double signalValue = 4.0 * alphaRsSquare * m_FirstSummation;
75 
76  if (alphaRs < 1.0e-8)
77  signalValue += 1.0 - alphaRsSquare / 12.0;
78  else
79  signalValue += 2.0 * (1.0 - std::cos(alphaRs)) / alphaRsSquare;
80 
81  return signalValue;
82 }
83 
84 StaniszCompartment::ListType &StaniszCompartment::GetSignalAttenuationJacobian(double smallDelta, double bigDelta, double gradientStrength, const Vector3DType &gradient)
85 {
86  this->UpdateSignals(smallDelta, bigDelta, gradientStrength);
87 
89 
90  double tissueRadius = this->GetTissueRadius();
91  double axialDiff = this->GetAxialDiffusivity();
92  double alpha = anima::DiffusionGyromagneticRatio * smallDelta * gradientStrength;
93  double alphaRs = alpha * tissueRadius;
94  double alphaRsSquare = alphaRs * alphaRs;
95  double piSquare = M_PI * M_PI;
96  double bValue = anima::GetBValueFromAcquisitionParameters(smallDelta, bigDelta, gradientStrength);
97 
98  // Derivative w.r.t. R_S
99  unsigned int pos = 0;
100 
101  if (m_EstimateTissueRadius)
102  {
103  if (alphaRs < 1.0e-8)
104  m_JacobianVector[pos] = - alphaRsSquare / (6.0 * tissueRadius);
105  else
106  m_JacobianVector[pos] = 2.0 * (alphaRs * std::sin(alphaRs) - 2.0 * (1.0 - std::cos(alphaRs))) / (alphaRsSquare * tissueRadius);
107 
108  m_JacobianVector[pos] += 8.0 * alpha * alphaRs * m_FirstSummation;
109  m_JacobianVector[pos] += 8.0 * piSquare * bValue * axialDiff * m_SecondSummation / tissueRadius;
110  m_JacobianVector[pos] += 4.0 * alpha * alphaRsSquare * m_ThirdSummation;
111  m_JacobianVector[pos] -= 16.0 * alpha * alphaRs * alphaRsSquare * m_FourthSummation;
112 
113  ++pos;
114  }
115 
116  if (m_EstimateAxialDiffusivity)
117  {
118  // Derivative w.r.t. D_I
119  m_JacobianVector[pos] = - 4.0 * bValue * piSquare * m_SecondSummation;
120  }
121 
122  return m_JacobianVector;
123 }
124 
126 {
127  // Compute equivalent isotropic term for default delta values and gradient strength
128  double bValue = 1000.0;
131 
132  double alpha = anima::DiffusionGyromagneticRatio * anima::DiffusionSmallDelta * gradientStrength;
133  double alphaRs = alpha * this->GetTissueRadius();
134  double alphaRsSquare = alphaRs * alphaRs;
135  double signalValue = 4.0 * alphaRsSquare * m_FirstSummation;
136 
137  if (alphaRs < 1.0e-8)
138  signalValue += 1.0 - alphaRsSquare / 12.0;
139  else
140  signalValue += 2.0 * (1.0 - std::cos(alphaRs)) / alphaRsSquare;
141 
142  double equivalentGaussianDiffusivity = - std::log(signalValue) / bValue;
143 
144  double resVal = - 1.5 * std::log(2.0 * M_PI * equivalentGaussianDiffusivity);
145 
146  resVal -= sample.squared_magnitude() / (2.0 * equivalentGaussianDiffusivity);
147 
148  return resVal;
149 }
150 
152 {
153  if (num != this->GetTissueRadius())
154  {
155  m_ModifiedParameters = true;
156  this->Superclass::SetTissueRadius(num);
157  }
158 }
159 
161 {
162  if (num != this->GetAxialDiffusivity())
163  {
164  m_ModifiedParameters = true;
166  }
167 }
168 
170 {
171  if (params.size() != this->GetNumberOfParameters())
172  return;
173 
174  unsigned int pos = 0;
175  if (m_EstimateTissueRadius)
176  {
177  this->SetTissueRadius(params[pos]);
178  ++pos;
179  }
180 
181  if (m_EstimateAxialDiffusivity)
182  this->SetAxialDiffusivity(params[pos]);
183 }
184 
186 {
188 
189  unsigned int pos = 0;
190  if (m_EstimateTissueRadius)
191  {
192  m_ParametersVector[pos] = this->GetTissueRadius();
193  ++pos;
194  }
195 
196  if (m_EstimateAxialDiffusivity)
198 
199  return m_ParametersVector;
200 }
201 
203 {
205 
206  unsigned int pos = 0;
207  if (m_EstimateTissueRadius)
208  {
210  ++pos;
211  }
212 
213  if (m_EstimateAxialDiffusivity)
215 
217 }
218 
220 {
222 
223  unsigned int pos = 0;
224  if (m_EstimateTissueRadius)
225  {
227  ++pos;
228  }
229 
230  if (m_EstimateAxialDiffusivity)
232 
234 }
235 
237 {
238  if (m_EstimateAxialDiffusivity == arg)
239  return;
240 
241  m_EstimateAxialDiffusivity = arg;
242  m_ChangedConstraints = true;
243 }
244 
246 {
247  if (m_EstimateTissueRadius == arg)
248  return;
249 
250  m_EstimateTissueRadius = arg;
251  m_ChangedConstraints = true;
252 }
253 
255 {
256  if (compartmentVector.GetSize() != this->GetCompartmentSize())
257  itkExceptionMacro("The input vector size does not match the size of the compartment");
258 
259  this->SetTissueRadius(compartmentVector[0]);
260  this->SetAxialDiffusivity(compartmentVector[1]);
261 
262  m_ModifiedParameters = false;
263 }
264 
266 {
267  return 2;
268 }
269 
271 {
272  if (!m_ChangedConstraints)
273  return m_NumberOfParameters;
274 
275  m_NumberOfParameters = 2;
276 
277  if (!m_EstimateTissueRadius)
278  --m_NumberOfParameters;
279 
280  if (!m_EstimateAxialDiffusivity)
281  --m_NumberOfParameters;
282 
283  m_ChangedConstraints = false;
284  return m_NumberOfParameters;
285 }
286 
288 {
289  if (m_CompartmentVector.GetSize() != this->GetCompartmentSize())
290  m_CompartmentVector.SetSize(this->GetCompartmentSize());
291 
294 
295  return m_CompartmentVector;
296 }
297 
299 {
300  return 0.0;
301 }
302 
303 } //end namespace anima
virtual ListType & GetParametersAsVector() ITK_OVERRIDE
double GetGradientStrengthFromBValue(double bValue, double smallDelta, double bigDelta)
Given b-value in s/mm^2 and deltas in s, computes gradient strength in T/mm.
ModelOutputVectorType & GetCompartmentVector() ITK_OVERRIDE
Get compartment overall description vector, mainly for writing, should be self-contained.
unsigned int GetNumberOfParameters() ITK_OVERRIDE
Number of optimized parameters: smaller than total number of parameters.
std::vector< double > ListType
virtual void SetAxialDiffusivity(double num)
ListType m_ParametersLowerBoundsVector
Vector holding current parameters lower bounds.
virtual ListType & GetSignalAttenuationJacobian(double smallDelta, double bigDelta, double gradientStrength, const Vector3DType &gradient) ITK_OVERRIDE
virtual void SetTissueRadius(double num)
virtual ListType & GetParameterLowerBounds() ITK_OVERRIDE
void SetAxialDiffusivity(double num) ITK_OVERRIDE
void UpdateSignals(double smallDelta, double bigDelta, double gradientStrength)
virtual double GetAxialDiffusivity()
virtual double GetLogDiffusionProfile(const Vector3DType &sample) ITK_OVERRIDE
ListType m_ParametersVector
Vector holding current parameters vector.
const double DiffusionBigDelta
Default big delta value (classical values)
double GetBValueFromAcquisitionParameters(double smallDelta, double bigDelta, double gradientStrength)
Given gyromagnetic ratio in rad/s/T, gradient strength in T/mm and deltas in s, computes b-value in s...
const double DiffusionSmallDelta
Default small delta value (classical values)
const double MCMTissueRadiusUpperBound
Tissue radius upper bound (in Stanisz for now)
double GetApparentFractionalAnisotropy() ITK_OVERRIDE
Superclass::ModelOutputVectorType ModelOutputVectorType
void SetTissueRadius(double num) ITK_OVERRIDE
unsigned int GetCompartmentSize() ITK_OVERRIDE
Number of parameters to describe the model, these parameters will be self-contained, i.e. include fixed parameters for example.
const double DiffusionGyromagneticRatio
Gyromagnetic ratio (in rad/s/T), from Nelson, J., Nuclear Magnetic Resonance Spectroscopy, Prentice Hall, Londres, 2003.
Superclass::Vector3DType Vector3DType
ListType m_ParametersUpperBoundsVector
Vector holding current parameters upper bounds.
void SetCompartmentVector(ModelOutputVectorType &compartmentVector) ITK_OVERRIDE
Set compartment overall description vector, for setting automatically the individual parameters when ...
ListType m_JacobianVector
Vector holding current jacobian value.
virtual ListType & GetParameterUpperBounds() ITK_OVERRIDE
const double MCMDiffusivityUpperBound
Diffusivity upper bound.
const double MCMTissueRadiusLowerBound
Tissue radius lower bound (in Stanisz for now)
const double MCMDiffusivityLowerBound
Diffusivity lower bound for estimation.
virtual double GetTissueRadius()
virtual double GetFourierTransformedDiffusionProfile(double smallDelta, double bigDelta, double gradientStrength, const Vector3DType &gradient) ITK_OVERRIDE
ModelOutputVectorType m_CompartmentVector
Vector to hold working value of compartment vector.
virtual void SetParametersFromVector(const ListType &params) ITK_OVERRIDE
Various methods for optimization parameters setting and getting.