@@ -79,9 +79,8 @@ T BesselI0(T x) noexcept
7979
8080 const T y = T (3.75 ) / ax;
8181 const T bx = std::exp (ax) / std::sqrt (ax);
82- const T a = q1 + y * (q2 + y * (q3 + y * (q4 + y * (q5 + y * (q6 + y * (q7 + y * (q8 + y * 19 )))))));
82+ const T a = q1 + y * (q2 + y * (q3 + y * (q4 + y * (q5 + y * (q6 + y * (q7 + y * (q8 + y * q9 )))))));
8383 return a * bx;
84-
8584}
8685
8786template <class T , typename = std::enable_if_t <std::is_floating_point_v<T>>>
@@ -114,12 +113,11 @@ T BesselI1(T x) noexcept
114113 return x * (P1 + y * (P2 + y * (P3 + y * (P4 + y * (P5 + y * (P6 + y * P7))))));
115114 }
116115
117- const T y = T (3.75 ) / ax;
118- const T bx = std::exp (ax) / std::sqrt (ax);
119- const T a = Q1 + y * (Q2 + y * (Q3 + y * (Q4 + y * (Q5 + y * (Q6 + y * (Q7 + y * (Q8 + y * Q9)))))));
120- // As in the provided Fortran, this branch does not apply sign(x).
121- return a * bx;
122-
116+ const T y = T (3.75 ) / ax;
117+ const T bx = std::exp (ax) / std::sqrt (ax);
118+ const T a = Q1 + y * (Q2 + y * (Q3 + y * (Q4 + y * (Q5 + y * (Q6 + y * (Q7 + y * (Q8 + y * Q9)))))));
119+ // As in the provided Fortran, this branch does not apply sign(x).
120+ return a * bx;
123121}
124122
125123// Assumes templated BesselI0<T> and BesselI1<T> are available.
@@ -129,15 +127,18 @@ template <class T, typename = std::enable_if_t<std::is_floating_point_v<T>>>
129127T BesselIn (T x, int N) noexcept
130128{
131129 // Special cases
132- if (N == 0 ) {
130+ if (N == 0 )
131+ {
133132 return BesselI0 (x);
134- }
135- if (N == 1 ) {
133+ }
134+ if (N == 1 )
135+ {
136136 return BesselI1 (x);
137- }
138- if (x == T (0 )) {
137+ }
138+ if (x == T (0 ))
139+ {
139140 return T (0 );
140- }
141+ }
141142
142143 // Constants (mirroring Fortran)
143144 constexpr int iacc = 40 ;
@@ -165,9 +166,10 @@ T BesselIn(T x, int N) noexcept
165166 bip *= bigni;
166167 bessi *= bigni;
167168 }
168- if (j == N) {
169+ if (j == N)
170+ {
169171 bessi = bip;
170- }
172+ }
171173 }
172174
173175 // Normalize using I0(x)
@@ -200,19 +202,21 @@ double r8_uniform_01(uint32_t& seed)
200202 int32_t s = static_cast <int32_t >(seed);
201203 const int32_t k = s / 127773 ;
202204 s = (16807 * (s - k * 127773 )) - (k * 2836 );
203- if (s < 0 ) {
205+ if (s < 0 )
206+ {
204207 s += 2147483647 ;
205- }
208+ }
206209 seed = static_cast <uint32_t >(s);
207210 return static_cast <double >(s) * 4.656612875e-10 ;
208211}
209212
210213void r8vec_uniform_01 (int m, uint32_t & seed, std::vector<double >& r)
211214{
212215 r.resize (m);
213- for (int i = 0 ; i < m; ++i) {
216+ for (int i = 0 ; i < m; ++i)
217+ {
214218 r[i] = r8_uniform_01 (seed);
215- }
219+ }
216220}
217221
218222// Faithful port of the Fortran r8vec_normal_01
@@ -232,9 +236,10 @@ void r8vec_normal_01(int n, uint32_t& seed, double* x)
232236 if (x_hi_index - x_lo_index + 1 == 1 )
233237 {
234238 double r1 = r8_uniform_01 (seed);
235- if (r1 <= 0.0 ) {
239+ if (r1 <= 0.0 )
240+ {
236241 r1 = std::numeric_limits<double >::min ();
237- }
242+ }
238243 double r2 = r8_uniform_01 (seed);
239244 x[x_hi_index] = std::sqrt (-2.0 * std::log (r1)) * std::cos (2.0 * r8_pi * r2);
240245 return ;
@@ -387,6 +392,12 @@ void DirectionalStats::EMforDS(uint32_t& seed, QuatD& muhat, double& kappahat, b
387392 const int numEm = this ->NumEM_ ;
388393 const int numIter = this ->NumIter_ ;
389394
395+ if (verbose)
396+ {
397+ std::printf (" Starting EMforDS routine\n " );
398+ std::printf (" N=%d, Pmdims=%d, NumEM=%d, NumIter=%d\n " , N, pmdims, numEm, numIter);
399+ }
400+
390401 // initialize some auxiliary arrays
391402 std::vector<QuatD> muAll (numEm); //
392403 std::vector<double > kappaAll (numEm, 0.0 );
@@ -408,9 +419,42 @@ void DirectionalStats::EMforDS(uint32_t& seed, QuatD& muhat, double& kappahat, b
408419 std::vector<double > q (numIter, 0.0 );
409420 std::vector<double > l (numIter, 0.0 );
410421
422+ if (verbose)
423+ {
424+ std::printf (" \n starting iteration %4d\n " , init + 1 );
425+ std::printf (" Initial guess for Mu (wxyz): %12.8f %12.8f %12.8f %12.8f\n " , mu.w (), mu.x (), mu.y (), mu.z ());
426+ std::printf (" Initial guess for Kappa : %12.8f\n " , kappa);
427+
428+ if (init == 0 )
429+ {
430+ // Print first 3 Xquats for diagnostic comparison
431+ std::printf (" First 3 Xquats (wxyz):\n " );
432+ for (int d = 0 ; d < 3 && d < N; ++d)
433+ {
434+ QuatD xq = m_XQuats[d];
435+ std::printf (" [%d] %20.16f %20.16f %20.16f %20.16f\n " , d, xq.w (), xq.x (), xq.y (), xq.z ());
436+ }
437+
438+ // Print logCp(30) diagnostic
439+ double testC = this ->logCp_ (30.0 );
440+ std::printf (" logCp(30) = %20.16f\n " , testC);
441+
442+ // Print first 3 density values for j=0 (identity symmetry op)
443+ QuatD PmMu0 = mu * m_LaueOps->getQuatSymOp (0 );
444+ std::printf (" PmMu0 (wxyz): %20.16f %20.16f %20.16f %20.16f\n " , PmMu0.w (), PmMu0.x (), PmMu0.y (), PmMu0.z ());
445+ std::vector<double > dens0 = this ->Density_ (PmMu0, kappa, testC);
446+ for (int d = 0 ; d < 3 && d < N; ++d)
447+ {
448+ double dp = PmMu0.dotProduct (m_XQuats[d]);
449+ std::printf (" density[%d] = %20.16e dot=%20.16f\n " , d, dens0[d], dp);
450+ }
451+ }
452+ }
453+
411454 // and here we go with the EM iteration...
412455 // we use quaternion multiplication throughout instead of the matrix version in the Matlab version
413456 // quaternion multiplication has been verified against the 4x4 matrix multiplication of the Matlab code on 01/02/15
457+ double Qi = 0.0 , Li = 0.0 ; // persist across inner iterations (Fortran INOUT semantics)
414458 for (int i = 0 ; i < numIter; ++i)
415459 {
416460 // E-step
@@ -420,11 +464,32 @@ void DirectionalStats::EMforDS(uint32_t& seed, QuatD& muhat, double& kappahat, b
420464 std::array<double , 5 > muKa = this ->Mstep_ (r, N, pmdims);
421465
422466 // Q and Likelihood
423- double Qi = 0.0 , Li = 0.0 ;
424467 this ->getQandL_ (muKa, r, Qi, Li);
425468 q[i] = Qi;
426469 l[i] = Li;
427470
471+ if (verbose)
472+ {
473+ std::printf (" inner loop : %4d\n " , i + 1 );
474+ std::printf (" Li : %16.8f\n " , Li);
475+ std::printf (" Qi : %16.8f\n " , Qi);
476+ std::printf (" Current guess for MuKa (wxyz,kappa): %12.8f %12.8f %12.8f %12.8f %12.8f\n " , muKa[3 ], muKa[0 ], muKa[1 ], muKa[2 ], muKa[4 ]);
477+
478+ if (init == 0 && i == 0 )
479+ {
480+ // Print diagnostic R matrix stats
481+ double rSum = 0.0 ;
482+ for (size_t ri = 0 ; ri < r.size (); ++ri)
483+ rSum += r[ri];
484+ std::printf (" R total sum: %20.16f (expected ~%d)\n " , rSum, N);
485+ // Print first 3 R values for j=0
486+ for (int d = 0 ; d < 3 && d < N; ++d)
487+ {
488+ std::printf (" R[%d,0] = %20.16e\n " , d, r[d]);
489+ }
490+ }
491+ }
492+
428493 // Persist latest params for this init
429494 // MuKa is [x,y,z,w,kappa] matching QuatD(x,y,z,w) constructor
430495 muAll[init] = QuatD (muKa[0 ], muKa[1 ], muKa[2 ], muKa[3 ]);
@@ -438,6 +503,10 @@ void DirectionalStats::EMforDS(uint32_t& seed, QuatD& muhat, double& kappahat, b
438503 // Convergence: |Q(i) - Q(i-1)| < 0.01
439504 if (i >= 1 && std::fabs (q[i] - q[i - 1 ]) < 0.01 )
440505 {
506+ if (verbose)
507+ {
508+ std::printf (" Exiting inner loop : %4d\n " , i + 1 );
509+ }
441510 break ;
442511 }
443512 }
@@ -457,6 +526,11 @@ void DirectionalStats::EMforDS(uint32_t& seed, QuatD& muhat, double& kappahat, b
457526 }
458527 }
459528
529+ if (verbose)
530+ {
531+ std::printf (" best fit init: %d\n " , dd + 1 );
532+ }
533+
460534 // Recover Mu for best init
461535 QuatD mu = muAll[dd];
462536 mu.positiveOrientation ();
@@ -710,7 +784,6 @@ std::array<double, 5> DirectionalStats::Mstep_(const std::vector<double>& R, int
710784 }
711785
712786 y_scalar = nGamma / static_cast <double >(N);
713-
714787 }
715788 else if (this ->DStype == " WAT" )
716789 {
0 commit comments