7 #include <boost/math/special_functions/legendre.hpp> 14 if (std::abs(bValue - m_CurrentBValue) < 1.0e-6 &&
anima::ComputeNorm(gradient - m_CurrentGradient) < 1.0e-6 && !m_ModifiedParameters)
42 m_IntraAxonalSignal = 0;
43 m_IntraAngleDerivative = 0;
44 m_IntraKappaDerivative = 0;
45 m_IntraAxialDerivative = 0;
46 double x = bValue * dpara;
48 for (
unsigned int i = 0;i < m_WatsonSHCoefficients.size();++i)
50 double coefVal = m_WatsonSHCoefficients[i];
51 double sqrtVal = std::sqrt((4.0 * i + 1.0) / (4.0 * M_PI));
52 double legendreVal = boost::math::legendre_p(2 * i, innerProd);
54 double xPowVal = std::pow(-x, (
double)i);
55 double cVal = xPowVal * kummerVal;
58 m_IntraAxonalSignal += coefVal * sqrtVal * legendreVal * cVal;
61 double coefDerivVal = m_WatsonSHCoefficientDerivatives[i];
62 double legendreDerivVal = boost::math::legendre_p_prime(2 * i, innerProd);
64 double cDerivVal = 0.0;
65 if (m_EstimateAxialDiffusivity)
69 cDerivVal += xPowVal * i * kummerVal / x;
72 m_IntraAngleDerivative += coefVal * sqrtVal * legendreDerivVal * cVal;
73 m_IntraKappaDerivative += coefDerivVal * sqrtVal * legendreVal * cVal;
74 m_IntraAxialDerivative += coefVal * sqrtVal * legendreVal * cDerivVal;
77 m_IntraAxonalSignal /= 2.0;
78 m_IntraAngleDerivative /= 2.0;
79 m_IntraKappaDerivative /= 2.0;
80 m_IntraAxialDerivative /= 2.0;
83 double appAxialDiff = dpara * (1.0 - nuic * (1.0 - m_Tau1));
84 double appRadialDiff = dpara * (1.0 - nuic * (1.0 + m_Tau1) / 2.0);
86 m_ExtraAxonalSignal = std::exp(-bValue * (appRadialDiff + (appAxialDiff - appRadialDiff) * innerProd * innerProd));
88 m_CurrentBValue = bValue;
89 m_CurrentGradient = gradient;
90 m_ModifiedParameters =
false;
98 double signal = (1.0 - nuec) * m_IntraAxonalSignal + nuec * m_ExtraAxonalSignal;
104 itkExceptionMacro(
"As of now, derivative is not functional for NODDI, please use bobyqa optimizer");
121 double extraAngleDerivative = -bValue * dpara * nuic * (3.0 * m_Tau1 - 1.0) * innerProd * m_ExtraAxonalSignal;
126 double innerProdThetaDeriv = (gradient[0] * std::cos(phi) + gradient[1] * std::sin(phi)) * std::cos(theta) - gradient[2] * std::sin(theta);
129 double intraThetaDerivative = m_IntraAngleDerivative * innerProdThetaDeriv;
132 double extraThetaDerivative = extraAngleDerivative * innerProdThetaDeriv;
134 m_JacobianVector[0] = (nuic * intraThetaDerivative + (1.0 - nuic) * extraThetaDerivative);
139 double innerProdPhiDeriv = std::sin(theta) * (gradient[1] * std::cos(phi) - gradient[0] * std::sin(phi));
142 double intraPhiDerivative = m_IntraAngleDerivative * innerProdPhiDeriv;
145 double extraPhiDerivative = extraAngleDerivative * innerProdPhiDeriv;
147 m_JacobianVector[1] = (nuic * intraPhiDerivative + (1.0 - nuic) * extraPhiDerivative);
152 unsigned int pos = 2;
154 if (m_EstimateOrientationConcentration)
157 double extraKappaDerivative = bValue * dpara * nuic * m_Tau1Deriv * (1.0 - 3.0 * innerProd * innerProd) * m_ExtraAxonalSignal / 2.0;
159 m_JacobianVector[pos] = (nuic * m_IntraKappaDerivative + (1.0 - nuic) * extraKappaDerivative);
166 double tmpVal = 1.0 + m_Tau1 - (3.0 * m_Tau1 - 1.0) * innerProd * innerProd;
167 if (m_EstimateExtraAxonalFraction)
169 double extraNuicDeriv = bValue * dpara * tmpVal * m_ExtraAxonalSignal / 2.0;
171 m_JacobianVector[pos] = - (m_IntraAxonalSignal - m_ExtraAxonalSignal + (1.0 - nuic) * extraNuicDeriv);
175 if (m_EstimateAxialDiffusivity)
180 m_JacobianVector[pos] = bValue * (nuic * m_IntraAxialDerivative - (1.0 - nuic) * m_ExtraAxonalSignal * (1.0 - nuic * tmpVal / 2.0));
196 double appAxialDiff = axialDiff * (1.0 - intraFraction * (1.0 - m_Tau1));
197 double appRadialDiff = axialDiff * (1.0 - intraFraction * (1.0 + m_Tau1) / 2.0);
204 double resVal = - 1.5 * std::log(2.0 * M_PI) - 0.5 * std::log(appAxialDiff) - std::log(appRadialDiff);
205 resVal -= (sample.squared_magnitude() - (1.0 - appRadialDiff / appAxialDiff) * innerProd * innerProd) / (2.0 * appRadialDiff);
214 m_ModifiedParameters =
true;
223 m_ModifiedParameters =
true;
232 m_ModifiedParameters =
true;
233 m_ModifiedConcentration =
true;
242 m_ModifiedParameters =
true;
251 m_ModifiedParameters =
true;
264 unsigned int pos = 2;
265 if (m_EstimateOrientationConcentration)
271 if (m_EstimateExtraAxonalFraction)
277 if (m_EstimateAxialDiffusivity)
288 unsigned int pos = 2;
289 if (m_EstimateOrientationConcentration)
295 if (m_EstimateExtraAxonalFraction)
301 if (m_EstimateAxialDiffusivity)
313 if (m_EstimateAxialDiffusivity)
326 unsigned int pos = 2;
328 if (m_EstimateOrientationConcentration)
334 if (m_EstimateExtraAxonalFraction)
340 if (m_EstimateAxialDiffusivity)
348 if (m_EstimateOrientationConcentration == arg)
351 m_EstimateOrientationConcentration = arg;
352 m_ChangedConstraints =
true;
357 if (m_EstimateAxialDiffusivity == arg)
360 m_EstimateAxialDiffusivity = arg;
361 m_ChangedConstraints =
true;
366 if (m_EstimateExtraAxonalFraction == arg)
369 m_EstimateExtraAxonalFraction = arg;
370 m_ChangedConstraints =
true;
376 itkExceptionMacro(
"The input vector size does not match the size of the compartment");
381 compartmentOrientation[i] = compartmentVector[i];
391 double odi = compartmentVector[currentPos];
402 m_ModifiedParameters =
false;
403 m_ModifiedConcentration =
false;
413 if (!m_ChangedConstraints)
414 return m_NumberOfParameters;
416 m_NumberOfParameters = 2;
418 if (m_EstimateOrientationConcentration)
419 ++m_NumberOfParameters;
421 if (m_EstimateAxialDiffusivity)
422 ++m_NumberOfParameters;
424 if (m_EstimateExtraAxonalFraction)
425 ++m_NumberOfParameters;
427 m_ChangedConstraints =
false;
428 return m_NumberOfParameters;
466 double appAxialDiff = axialDiff * (1.0 - intraFraction * (1.0 - m_Tau1));
467 double appRadialDiff = axialDiff * (1.0 - intraFraction * (1.0 + m_Tau1) / 2.0);
480 m_DiffusionTensor(i,j) += compartmentOrientation[i] * compartmentOrientation[j] * (appAxialDiff - appRadialDiff);
490 if (!m_ModifiedConcentration)
495 m_Tau1 = (1.0 / dawsonValue - 1.0) / (2.0 * kappa);
496 m_Tau1Deriv = (1.0 - (1.0 - dawsonValue * (2.0 * kappa - 1.0)) / (2.0 * dawsonValue * dawsonValue)) / (2.0 * kappa * kappa);
499 m_ModifiedConcentration =
false;
506 double l1 = axialDiff * (1.0 - intraFraction * (1.0 - m_Tau1));
507 double l2 = axialDiff * (1.0 - intraFraction * (1.0 + m_Tau1) / 2.0);
510 double numFA = std::sqrt ((l1 - l2) * (l1 - l2) + (l2 - l3) * (l2 - l3) + (l3 - l1) * (l3 - l1));
511 double denomFA = std::sqrt (l1 * l1 + l2 * l2 + l3 * l3);
515 fa = std::sqrt(0.5) * (numFA / denomFA);
const double MCMZeroLowerBound
Default zero lower bound (in case we want something else than zero one day)
void SetOrientationPhi(double num) ITK_OVERRIDE
std::vector< double > ListType
void TransformSphericalToCartesianCoordinates(const VectorType &v, VectorType &resVec)
virtual void SetAxialDiffusivity(double num)
ListType m_ParametersLowerBoundsVector
Vector holding current parameters lower bounds.
void SetOrientationConcentration(double num) ITK_OVERRIDE
void UpdateKappaValues()
Update quantities that depend on kappa.
const double MCMAzimuthAngleUpperBound
Azimuth angle upper bound.
void SetEstimateOrientationConcentration(bool arg)
void SetCompartmentVector(ModelOutputVectorType &compartmentVector) ITK_OVERRIDE
Set compartment overall description vector, for setting automatically the individual parameters when ...
virtual double GetOrientationPhi()
ModelOutputVectorType & GetCompartmentVector() ITK_OVERRIDE
Get compartment overall description vector, mainly for writing, should be self-contained.
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 MCMFractionUpperBound
Fraction upper bound (intra/extra axonal)
void SetEstimateAxialDiffusivity(bool arg)
const Matrix3DType & GetDiffusionTensor() ITK_OVERRIDE
Get compartment as a 3D tensor (default behavior: throw exception if not supported by the compartment...
virtual double GetFourierTransformedDiffusionProfile(double smallDelta, double bigDelta, double gradientStrength, const Vector3DType &gradient) ITK_OVERRIDE
virtual double GetAxialDiffusivity()
double ComputeNorm(const VectorType &v)
ListType m_ParametersVector
Vector holding current parameters vector.
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...
virtual double GetOrientationTheta()
const double MCMPolarAngleUpperBound
Polar angle upper bound (used in tensor for now)
virtual void SetOrientationConcentration(double num)
double GetApparentFractionalAnisotropy() ITK_OVERRIDE
Superclass::Vector3DType Vector3DType
virtual void SetExtraAxonalFraction(double num)
void SetAxialDiffusivity(double num) ITK_OVERRIDE
virtual double GetExtraAxonalFraction()
virtual ListType & GetParameterLowerBounds() ITK_OVERRIDE
virtual double GetLogDiffusionProfile(const Vector3DType &sample) ITK_OVERRIDE
virtual void SetOrientationTheta(double num)
ListType m_ParametersUpperBoundsVector
Vector holding current parameters upper bounds.
Superclass::ModelOutputVectorType ModelOutputVectorType
ListType m_JacobianVector
Vector holding current jacobian value.
void GetStandardWatsonSHCoefficients(const ScalarType k, std::vector< ScalarType > &coefficients, std::vector< ScalarType > &derivatives)
const double MCMConcentrationUpperBound
Concentration upper bound (used in NODDI and DDI)
const double MCMDiffusivityUpperBound
Diffusivity upper bound.
virtual void SetParametersFromVector(const ListType ¶ms) ITK_OVERRIDE
Various methods for optimization parameters setting and getting.
double ComputeScalarProduct(const VectorType &v1, const VectorType &v2, const unsigned int NDimension)
virtual void SetOrientationPhi(double num)
virtual ListType & GetParameterUpperBounds() ITK_OVERRIDE
const double MCMDiffusivityLowerBound
Diffusivity lower bound for estimation.
virtual ListType & GetParametersAsVector() ITK_OVERRIDE
Superclass::Matrix3DType Matrix3DType
double GetKummerFunctionValue(const double &x, const double &a, const double &b, const unsigned int maxIter, const double tol)
Computes the confluent hypergeometric function 1F1 also known as the Kummer function M...
Matrix3DType m_DiffusionTensor
Matrix to hold working value of diffusion tensor approximation to the model.
unsigned int GetNumberOfParameters() ITK_OVERRIDE
Number of optimized parameters: smaller than total number of parameters.
virtual ListType & GetSignalAttenuationJacobian(double smallDelta, double bigDelta, double gradientStrength, const Vector3DType &gradient) ITK_OVERRIDE
void TransformCartesianToSphericalCoordinates(const VectorType &v, VectorType &resVec)
ModelOutputVectorType m_CompartmentVector
Vector to hold working value of compartment vector.
void UpdateSignals(double bValue, const Vector3DType &gradient)
Compute intra- and extra-axonal signals and useful signals for derivatives.
void SetExtraAxonalFraction(double num) ITK_OVERRIDE
static const unsigned int m_SpaceDimension
void SetOrientationTheta(double num) ITK_OVERRIDE
virtual double GetOrientationConcentration()
void SetEstimateExtraAxonalFraction(bool arg)
double EvaluateDawsonIntegral(const double x, const bool scaled)