Skip to content

Commit 3a8dae7

Browse files
committed
Directional Stats Unit tests now passing
1 parent cc7a950 commit 3a8dae7

12 files changed

Lines changed: 39671 additions & 108 deletions
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
qu
2+
10
3+
0.92934656 -0.36858946 0.0081792902 0.019746415
4+
0.93205625 -0.3620477 0.012823511 -0.0053116297
5+
0.92983103 -0.36758989 0.016257482 -0.0052523925
6+
0.93061996 -0.36583757 0.010389386 -0.0012097559
7+
0.92853022 -0.37113327 -0.0051697767 0.0080596395
8+
0.92621905 -0.37646216 -0.0033933693 -0.019568495
9+
0.92438912 -0.38072789 0.02168753 0.0089833615
10+
0.92300296 -0.38422647 -0.002270041 0.020744085
11+
0.92018086 -0.39103976 -0.018711079 -0.0022371865
12+
0.91371483 -0.40632781 0.0044282493 -0.0018341328

Data/EbsdTestFiles/quats_wxyz_29791.csv

Lines changed: 29793 additions & 0 deletions
Large diffs are not rendered by default.

Data/EbsdTestFiles/quats_wxyz_9260.csv

Lines changed: 9263 additions & 0 deletions
Large diffs are not rendered by default.

Source/EbsdLib/Core/DirectionalStats.cpp

Lines changed: 97 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -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

8786
template <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>>>
129127
T 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

210213
void 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
{

Source/EbsdLib/Core/DirectionalStats.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ namespace ebsdlib
1313
{
1414
class EbsdLib_EXPORT DirectionalStats
1515
{
16-
public:
16+
public:
1717
DirectionalStats(const std::string& DSType, LaueOps::Pointer laueOps);
1818
virtual ~DirectionalStats();
1919

@@ -80,7 +80,7 @@ class EbsdLib_EXPORT DirectionalStats
8080
return m_XQuats.size();
8181
}
8282

83-
private:
83+
private:
8484
int NumEM_ = 0;
8585
int NumIter_ = 0;
8686
std::string DStype = "";
@@ -94,4 +94,4 @@ class EbsdLib_EXPORT DirectionalStats
9494

9595
LaueOps::Pointer m_LaueOps;
9696
};
97-
}
97+
} // namespace ebsdlib

Source/EbsdLib/Core/EbsdLibConstants.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -289,8 +289,8 @@ inline constexpr double BP[12] = {
289289

290290
} // namespace LambertParametersType
291291

292-
// Add some shortened namespace alias
293-
// Condense some of the namespaces to same some typing later on.
292+
// Add shortened namespace alias
293+
// Condense namespaces to save some typing later on.
294294
namespace LPs = LambertParametersType;
295295

296296
} // namespace ebsdlib

0 commit comments

Comments
 (0)