DMRITool  v0.1.1-139-g860d86b4
Diffusion MRI Tool
itkSpecialFunctionGenerator.hxx
Go to the documentation of this file.
1 
18 #ifndef __itkSpecialFunctionGenerator_hxx
19 #define __itkSpecialFunctionGenerator_hxx
20 
21 
23 #include <gsl/gsl_sf_gamma.h>
24 #include <gsl/gsl_sf_laguerre.h>
25 #include <gsl/gsl_sf_bessel.h>
26 #include <gsl/gsl_sf_hyperg.h>
27 #include "utl.h"
28 #include <tr1/cmath>
29 
32 
35 
36 namespace utl
37 {
38 
39 double
40 Hyperg1F1(double a, double b, double x)
41 {
42  // Handle possible underflows with a Kummer transformation
43  // if(x>=-500.0)
44  // return gsl_sf_hyperg_1F1(a,b,x);
45  // else
46  // return std::exp(x)*gsl_sf_hyperg_1F1(b-a,b,-x);
47  return std::tr1::conf_hyperg(a,b,x);
48 }
49 
50 template < class T >
51 T
52 Lagurre (const int n, const double a, const T x )
53 {
54  if (n==1)
55  return gsl_sf_laguerre_1 (a,x);
56  else if (n==2)
57  return gsl_sf_laguerre_2 (a,x);
58  else if (n==3)
59  return gsl_sf_laguerre_3 (a,x);
60  else
61  return gsl_sf_laguerre_n(n,a,x);
62 }
63 
64 double
65 Gamma(const double x)
66 {
67  utlException(std::fabs(x)<1e-8, "wrong input x, x=0");
68 
69  if (utl::IsInt(2*x) && x>0)
70  return GammaHalfInteger(x);
71  else
72  return gsl_sf_gamma(x);
73 }
74 
75 double
76 GammaLower ( const double s, const double x )
77 {
78  double gamma_whole = Gamma(s);
79  double gamma_upper = gsl_sf_gamma_inc(s,x);
80  return gamma_whole - gamma_upper;
81 }
82 
83 double
84 BesselJa(const double a, const double x)
85 {
86  int int_a = int(a);
87  int int_2a = int(2.0*a);
88  if (std::abs(int_a-a)<1e-8) // integer
89  {
90  return BesselJInteger(int_a, x);
91  }
92  else if (std::abs(int_2a-2.0*a)<1e-8) // half of an intger
93  {
94  utlException (a<0, "the parameter a should be positive in this routine. \
95  Note: a can be negative in theory... \n\
96  When a is an integer, J_a(x)=(-1)^a J_{-a}(x); When a is not an integer, J_a(x) and J_{-a}(x) are linearly independent.");
97  // j_l(x) = \sqrt(\pi / (2x)) J_{l+0.5}(x)
98  return std::sqrt(2.0*x/M_PI) * gsl_sf_bessel_jl(int(a-0.5),x);
99  }
100  else // use std::tr1::cyl_bessel_j for non-negative order.
101  utlException(true, "a should be an integer or a half of an integer!");
102  return 0;
103 }
104 
105 double
106 BesselJInteger(const int n, const double x)
107 {
108  if (n<0)
109  return (n%2?(-1):1)*BesselJInteger(-n,x);
110  if (n==0)
111  return gsl_sf_bessel_J0(x);
112  else if (n==1)
113  return gsl_sf_bessel_J1(x);
114  else
115  return gsl_sf_bessel_Jn(n, x);
116 }
117 
118 double
119 BesselJIntegerPrime(const int n, const double x)
120 {
121  if (n==0)
122  return -BesselJInteger(1,x);
123  else
124  return 0.5*(BesselJInteger(n-1,x) - BesselJInteger(n+1,x));
125 }
126 
127 // template<class T>
128 // NDArray<T,1>
129 // GetRotatedSHCoefficients(const NDArray<T,1>& shInput, const NDArray<T,2>& rotationMatrix)
130 // {
131 // typedef NDArray<double,2> MatrixDouble;
132 // typedef NDArray<double,1> VectorDouble;
133 // static utl_shared_ptr<MatrixDouble > gradt3 = utl::ReadGrad<double>(3, DIRECTION_NODUPLICATE, CARTESIAN_TO_CARTESIAN);
134 // // static int rank = utl::DimToRankSH(shInput.size());
135 // static int rank = 10;
136 // static utl_shared_ptr< MatrixDouble> shMatrix = utl::ComputeSHMatrix(rank, *gradt3, CARTESIAN_TO_SPHERICAL);
137 // static std::vector< MatrixDouble > shMatrixInv(rank/2);
138 // static bool isFirstTime = true;
139 // if (isFirstTime)
140 // {
141 // for ( int l = 2; l <= rank; l += 2 )
142 // {
143 // MatrixDouble shMatrixL = shMatrix->GetNColumns(utl::RankToDimSH(l-2), 2*l+1);
144 // utl::PInverseMatrix(shMatrixL, shMatrixInv[l/2-1]);
145 // }
146 // isFirstTime = false;
147 // }
148 
149 // int rankReal = utl::DimToRankSH(shInput.Size());
150 // if (rankReal>rank)
151 // {
152 // rank = rankReal;
153 // shMatrix = utl::ComputeSHMatrix(rank, *gradt3, CARTESIAN_TO_SPHERICAL);
154 // shMatrixInv = std::vector<MatrixDouble >(rank/2);
155 // for ( int l = 2; l <= rank; l += 2 )
156 // {
157 // MatrixDouble shMatrixL = shMatrix->GetNColumns(utl::RankToDimSH(l-2), 2*l+1);
158 // utl::PInverseMatrix(shMatrixL, shMatrixInv[l/2-1]);
159 // }
160 // }
161 
162 // // MatrixDouble gradt3Rotated = (rotationMatrix.GetTranspose() * gradt3->GetTranspose()).GetTranspose();
163 // MatrixDouble gradt3Rotated = (*gradt3) * rotationMatrix;
164 // utl_shared_ptr<MatrixDouble > shMatrixRotated = utl::ComputeSHMatrix(rankReal, gradt3Rotated,CARTESIAN_TO_SPHERICAL);
165 // VectorDouble shRotated(shInput);
166 // MatrixDouble tmp;
167 // for ( int l = 2; l <= rankReal; l += 2 )
168 // {
169 // int colstart = utl::RankToDimSH(l-2);
170 // tmp = shMatrixRotated->GetNColumns(colstart, 2*l+1);
171 // VectorDouble sfValueRotatedL = tmp* shInput.GetSubVector(utl::GetRange(colstart, colstart+2*l+1));
172 // VectorDouble shRotatedL = shMatrixInv[l/2-1]*sfValueRotatedL;
173 // shRotated.SetSubVector(utl::GetRange(colstart, colstart+shRotatedL.Size()), shRotatedL);
174 // }
175 // return shRotated;
176 // }
177 
178 template < class T >
179 utl_shared_ptr<utl::NDArray<T,1> >
180 GetSymmetricTensorSHCoef ( const T b, const T e1, const T e2, const int lMax, const T theta, const T phi )
181 {
182  utlException(!utl::IsInt(0.5*lMax), "lMax should be even, lMax="<<lMax);
183  utlException(e1<e2-1e-10, "e1 should be more than e2, e1="<<e1 << ", e2="<<e2);
184 
185  typedef utl::NDArray<T, 1> VectorType;
186  typedef utl_shared_ptr<VectorType> VectorPointer;
187 
188  // utlPrintVar6(true, b, e1, e2, lMax, theta, phi);
189  VectorPointer coef_vec (new VectorType(utl::RankToDimSH(lMax),T(0.0)));
190  double a = (e1 - e2)*b;
191  double expbe2 = itk::lutExpValue(-b*e2);
192 
193  for ( int l = 0; l <= lMax; l += 2 )
194  {
195  double A = utl::GetExpLegendreCoef(a,l, &itk::lutExpValue);
196  if (std::fabs(theta)<1e-10)
197  {
198  int jj = utl::GetIndexSHj(l,0);
199  (*coef_vec)[jj] = 4.0*M_PI/(2.0*l+1.0) * expbe2 * A * std::sqrt(1+2*l)/(2*utl::SQRTPI);
200  }
201  else
202  {
203  for ( int m = -l; m <= l; m += 1 )
204  {
205  int jj = utl::GetIndexSHj(l,m);
206  (*coef_vec)[jj] = 4.0*M_PI/(2.0*l+1.0) * expbe2 * A * itk::SphericalHarmonicsGenerator<double>::RealSH(l,m,theta, phi);
207  }
208  }
209  }
210  return coef_vec;
211 } // ----- end of method SpecialFunctions<T>::<method> -----
212 
213 template < class T >
214 std::vector< std::vector<T> >
215 GetSymmetricTensorSHCoefDerivative ( const T b, const T e1, const T e2, const int lMax, const T theta, const T phi )
216 {
217  utlException(!utl::IsInt(0.5*lMax), "lMax should be even, lMax="<<lMax);
218  utlException(e1<e2-1e-10, "e1 should be more than e2, e1="<<e1 << ", e2="<<e2);
219 
220  std::vector<std::vector<T> > coef(2);
221  coef[0] = std::vector<T>(utl::RankToDimSH(lMax),0.0);
222  coef[1] = std::vector<T>(utl::RankToDimSH(lMax),0.0);
223 
224  double a = (e1 - e2)*b;
225  double expbe2 = itk::lutExpValue(-b*e2);
226 
227  for ( int l = 0; l <= lMax; l += 2 )
228  {
229  double A = utl::GetExpLegendreCoef(a,l, &itk::lutExpValue);
230  double dA = GetExpLegendreCoefDerivative(a,l);
231  for ( int m = -l; m <= l; m += 1 )
232  {
233  int jj = utl::GetIndexSHj(l,m);
234  coef[0][jj] = 4.0*M_PI/(2.0*l+1.0) * expbe2 * b * dA * itk::SphericalHarmonicsGenerator<double>::RealSH(l,m,theta, phi);
235  coef[1][jj] = 4.0*M_PI/(2.0*l+1.0) * expbe2 * (-b) * (A + dA);
236  }
237  }
238  return coef;
239 } // ----- end of method SpecialFunctions<T>::<method> -----
240 
241 
242 inline double
243 GetExpProductLegendreCoef(const double a, const double b, const int l )
244 {
245  if (!utl::IsInt(0.5*l))
246  return 0;
247 
248  if (a==b)
249  return l==0? itk::lutExpValue(-b) : 0;
250  else
252 }
253 
254 template < class T >
255 utl_shared_ptr<utl::NDArray<T,1> >
256 ComputeDWISHCoefficientsForGPDCylinder(const T radius, const T diffusivity, const T deltaBig, const T deltaSmall, const T qq, const int lMax, const T theta, const T phi)
257 {
258  double tau = deltaBig - deltaSmall/3.0;
259  double q_norm = qq*2.0*M_PI;
260  double a = tau*q_norm*q_norm*diffusivity;
261 
262  typedef utl::NDArray<double, 1> VectorType;
263  typedef utl_shared_ptr<VectorType> VectorPointer;
264  const int m_max = 60;
265  const VectorType besselJZeros(utl::BesselJPrimeZerosOrder1,m_max);
266  VectorType beta_m = besselJZeros / radius;
267  // utl::PrintUtlVector(besselJZeros, "zeros");
268  // utl::PrintUtlVector(beta_m, "beta_m");
269 
270  double sum_orth=0.0;
271  // utlPrintVar4(true, diffusivity, deltaBig, deltaSmall, radius);
272  for ( int m = 0; m < m_max; ++m )
273  {
274  double dam = diffusivity*beta_m[m]*beta_m[m];
275  double numerator = 2.0*dam*deltaSmall -2
276  + 2.0*itk::lutExpValue(-dam*deltaSmall)
277  + 2.0*itk::lutExpValue(-dam*deltaBig)
278  - itk::lutExpValue(-dam*(deltaBig - deltaSmall))
279  - itk::lutExpValue(-dam*(deltaBig + deltaSmall));
280  double beta_m2 = beta_m[m]*beta_m[m];
281  double denominator = dam*dam*beta_m2 * (radius*radius*beta_m2 - 1);
282  // utlPrintVar2(true, numerator, denominator);
283  sum_orth += numerator/denominator;
284  }
285 
286  // utlPrintVar3(true, q_norm, deltaSmall, sum_orth);
287  double b = 2.0* q_norm*q_norm/(deltaSmall*deltaSmall) * sum_orth;
288 
289  VectorPointer coef_vec(new VectorType(utl::RankToDimSH(lMax),0.0));
290  for ( int l = 0; l <= lMax ; l+=2 )
291  {
292  double A = utl::GetExpProductLegendreCoef(a, b, l);
293  // utlPrintVar4(true, a, b, l, A);
294  if (std::fabs(theta)<1e-10)
295  {
296  int jj = utl::GetIndexSHj(l,0);
297  (*coef_vec)[jj] = 4.0*M_PI/(2.0*l+1.0) * A * std::sqrt(1+2*l)/(2*utl::SQRTPI);
298  }
299  else
300  {
301  for ( int m = -l; m <= l; m += 1 )
302  {
303  int jj = utl::GetIndexSHj(l,m);
304  (*coef_vec)[jj] = 4.0*M_PI/(2.0*l+1.0) * A * itk::SphericalHarmonicsGenerator<double>::RealSH(l,m,theta, phi);
305  }
306  }
307  }
308 
309  // utl::PrintUtlVector(*coef_vec,"coef_vec");
310  return coef_vec;
311 }
312 
313 
314 template < class T >
315 double
317 {
318  utlException(axis.Size()!=3, "wrong size of axis");
319  utlException(std::fabs(axis.GetSquaredTwoNorm()-1)>1e-10, "axis should have unit norm");
320 
321  const double normZ = 2.0*std::sqrt(M_PI/5.0);
322 
323  // only l=2 is used.
324  int N = utl::RankToDimSH(2);
325  utl::NDArray<T,1> shCoef2(N);
326  for ( int i = 0; i < N; ++i )
327  shCoef2[i] = shCoef[i];
328 
329  typedef itk::SHCoefficientsRotation<double> SHRotationFilterType;
330  SHRotationFilterType::Pointer shRotateFilter = SHRotationFilterType::GetInstance();
331 
332  // assume rank and Initialize have been set to the global instance.
333  utlSAException(shRotateFilter->GetMaxRank()<2)
334  (shRotateFilter->GetMaxRank()).msg("need to set large rank");
335 
336  utl::NDArray<T,1> zAxis(3,0.0), shCoefRot;
337  zAxis[2]=1.0;
338  utl::NDArray<T,2> matRot(3,3);
339  utl::RotationMatrixFromVectors(axis, zAxis, matRot);
340 
341  shCoefRot = shRotateFilter->GetRotatedSHCoefficients(shCoef2, matRot);
342  double sh20 = shCoefRot[utl::GetIndexSHj(2,0)];
343 
344  return normZ * sh20;
345 }
346 
347 double
348 ComputeOrientationalOrderFromSymmetricTensor(const double e1, const double e2, const double phi)
349 {
350  double diff = e1-e2;
351  if (utl::IsSame(diff,0.0, 1e-10))
352  return 0;
353 
354  double sqrtdiff = std::sqrt(diff);
355  double sqrte2 = std::sqrt(e2);
356  double oo = ( sqrtdiff*(2.*e1+e2) - 3.*e1*sqrte2*std::atan(sqrtdiff/sqrte2) ) / (2.0* diff*sqrtdiff);
357 
358  if (utl::IsSame(phi, 0.0, 1e-10))
359  return oo;
360  else
361  return oo*(1.0+3.*std::cos(2.*phi))/4.0;
362 }
363 
364 
365 }
366 
367 
368 #endif
static PreciseType RealSH(const int l, const int m, const PreciseType theta, const PreciseType phi)
NDArray is a N-Dimensional array class (row-major, c version)
Definition: utlFunctors.h:131
Created "03-26-2014.
NDArray<T,1> is a vector class which uses blas mkl.
Definition: utlVector.h:36
double BesselJIntegerPrime(const int n, const double x)
void RotationMatrixFromVectors(const VectorType &from, const VectorType &to, MatrixType &mat)
helper functions specifically used in dmritool
double GetExpLegendreCoefDerivative(const double a, const int l, Func1To1 expF=&std::exp)
Definition: utlMath.h:1042
int GetIndexSHj(const int l, const int m)
Definition: utlDMRI.h:204
double ComputeOrientationalOrderFromSymmetricTensor(const double e1, const double e2, const double phi=0)
double GammaLower(const double s, const double x)
#define utlException(cond, expout)
Definition: utlCoreMacro.h:548
double GetExpLegendreCoef(const double a, const int l, Func1To1 expF=&std::exp)
Definition: utlMath.h:919
NDArray<T,2> is a row-major matrix.
Definition: utlMatrix.h:37
double GetExpProductLegendreCoef(const double a, const double b, const int l)
double Hyperg1F1(double a, double b, double x)
T abs(const T x)
template version of the fabs function
#define M_PI
Definition: utlCoreMacro.h:57
double GetSquaredTwoNorm() const
Definition: utlNDArray.h:1017
Definition: utl.h:90
bool IsInt(const std::string &input, const double epss=1e-10)
Definition: utlCore.h:792
T Lagurre(const int n, const double a, const T x)
#define utlSAException(expr)
Definition: utlCoreMacro.h:543
rotate SH coefficient vector by a given rotation matrix.
int RankToDimSH(const int shRank)
Definition: utlDMRI.h:193
utl_shared_ptr< utl::NDArray< T, 1 > > ComputeDWISHCoefficientsForGPDCylinder(const T radius, const T diffusivity, const T deltaBig, const T deltaSmall, const T qq, const int lMax, const T theta=0, const T phi=0)
double BesselJInteger(const int n, const double x)
bool IsSame(const T &value, const T &v0, const double eps=1e-10)
Definition: utlCore.h:1337
double GammaHalfInteger(const double x)
Definition: utlMath.h:887
std::vector< std::vector< T > > GetSymmetricTensorSHCoefDerivative(const T b, const T e1, const T e2, const int lMax, const T theta=0, const T phi=0)
get the derivatives of the SH coefficients with respect to (e1, e2) in the symmetric tensor with eige...
static constexpr double SQRTPI
Definition: utlConstants.h:41
double lutExpValue(const double x)
double ComputeOrientationalOrderFromSHCoefficients(const utl::NDArray< T, 1 > &shCoef, const utl::NDArray< T, 1 > &axis)
SizeType Size() const
Definition: utlNDArray.h:321
static const double BesselJPrimeZerosOrder1[60]
Definition: utlMath.h:66
double BesselJa(const double a, const double x)
bessel_Ja : Regular Cylindrical Bessel Function
utl_shared_ptr< utl::NDArray< T, 1 > > GetSymmetricTensorSHCoef(const T b, const T e1, const T e2, const int lMax, const T theta=0, const T phi=0)
get the SH coefficients from the symmetric tensor with eigenvalues (e1,e2,e2), e1>e2, and (theta,phi) is the angular direction of the e1 axis.
double Gamma(const double x)
gamma function.