/* * highly inefficient computation of the imaginary part of complex * conjugate eigenvalues of a 3x3 non-symmetric matrix */ double gage_imaginary_part_eigenvalues( gage_t *M ) { double A, B, C, scale, frob, m[9], _eval[3]; double beta, gamma; int roots; frob = ELL_3M_FROB(M); scale = frob > 10 ? 10.0/frob : 1.0; ELL_3M_SCALE(m, scale, M); /* ** from gordon with mathematica; these are the coefficients of the ** cubic polynomial in x: det(x*I - M). The full cubic is ** x^3 + A*x^2 + B*x + C. */ A = -m[0] - m[4] - m[8]; B = m[0]*m[4] - m[3]*m[1] + m[0]*m[8] - m[6]*m[2] + m[4]*m[8] - m[7]*m[5]; C = (m[6]*m[4] - m[3]*m[7])*m[2] + (m[0]*m[7] - m[6]*m[1])*m[5] + (m[3]*m[1] - m[0]*m[4])*m[8]; roots = ell_cubic(_eval, A, B, C, AIR_TRUE); if ( roots != ell_cubic_root_single ) return 0.; /* 2 complex conjuguate eigenvalues */ beta = A + _eval[0]; gamma = -C/_eval[0]; return sqrt( 4.*gamma - beta*beta ); }
/* ******** ell_3m_eigenvalues_d() ** ** finds eigenvalues of given matrix. ** ** returns information about the roots according to ellCubeRoot enum, ** see header for ellCubic for details. ** ** given matrix is NOT modified ** ** This does NOT use biff ** ** Doing the frobenius normalization proved successfull in avoiding the ** the creating of NaN eigenvalues when the coefficients of the matrix ** were really large (> 50000). Also, when the matrix norm was really ** small, the comparison to "epsilon" in ell_cubic mistook three separate ** roots for a single and a double, with this matrix in particular: ** 1.7421892 0.0137642 0.0152975 ** 0.0137642 1.7565432 -0.0062296 ** 0.0152975 -0.0062296 1.7700019 ** (actually, this is prior to tenEigensolve's isotropic removal) ** ** HEY: tenEigensolve_d and tenEigensolve_f start by removing the ** isotropic part of the tensor. It may be that that smarts should ** be migrated here, but GLK is uncertain how it would change the ** handling of non-symmetric matrices. */ int ell_3m_eigenvalues_d(double _eval[3], const double _m[9], const int newton) { double A, B, C, scale, frob, m[9], eval[3]; int roots; frob = ELL_3M_FROB(_m); scale = frob ? 1.0/frob : 1.0; ELL_3M_SCALE(m, scale, _m); /* printf("!%s: m = %g %g %g; %g %g %g; %g %g %g\n", "ell_3m_eigenvalues_d", m[0], m[1], m[2], m[3], m[4], m[5], m[6], m[7], m[8]); */ /* ** from gordon with mathematica; these are the coefficients of the ** cubic polynomial in x: det(x*I - M). The full cubic is ** x^3 + A*x^2 + B*x + C. */ A = -m[0] - m[4] - m[8]; B = m[0]*m[4] - m[3]*m[1] + m[0]*m[8] - m[6]*m[2] + m[4]*m[8] - m[7]*m[5]; C = (m[6]*m[4] - m[3]*m[7])*m[2] + (m[0]*m[7] - m[6]*m[1])*m[5] + (m[3]*m[1] - m[0]*m[4])*m[8]; /* printf("!%s: A B C = %g %g %g\n", "ell_3m_eigenvalues_d", A, B, C); */ roots = ell_cubic(eval, A, B, C, newton); /* no longer need to sort here */ ELL_3V_SCALE(_eval, 1.0/scale, eval); return roots; }
void _gageVecAnswer(gageContext *ctx, gagePerVolume *pvl) { char me[]="_gageVecAnswer"; double cmag, tmpMat[9], mgevec[9], mgeval[3]; double symm[9], asym[9], tran[9], eval[3], tmpVec[3], norm; gage_t *vecAns, *normAns, *jacAns, *curlAns, *hesAns, *curlGradAns, *helGradAns, *dirHelDirAns, *curlnormgradAns; /* int asw; */ vecAns = pvl->directAnswer[gageVecVector]; normAns = pvl->directAnswer[gageVecNormalized]; jacAns = pvl->directAnswer[gageVecJacobian]; curlAns = pvl->directAnswer[gageVecCurl]; hesAns = pvl->directAnswer[gageVecHessian]; curlGradAns = pvl->directAnswer[gageVecCurlGradient]; curlnormgradAns = pvl->directAnswer[gageVecCurlNormGrad]; helGradAns = pvl->directAnswer[gageVecHelGradient]; dirHelDirAns = pvl->directAnswer[gageVecDirHelDeriv]; if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecVector)) { /* done if doV */ if (ctx->verbose) { fprintf(stderr, "vec = "); ell_3v_PRINT(stderr, vecAns); } } /* done if doV if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecVector{0,1,2})) { } */ if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecLength)) { pvl->directAnswer[gageVecLength][0] = AIR_CAST(gage_t, ELL_3V_LEN(vecAns)); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecNormalized)) { if (pvl->directAnswer[gageVecLength][0]) { ELL_3V_SCALE_TT(normAns, gage_t, 1.0/pvl->directAnswer[gageVecLength][0], vecAns); } else { ELL_3V_COPY(normAns, gageZeroNormal); } } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecJacobian)) { /* done if doD1 */ /* 0:dv_x/dx 1:dv_x/dy 2:dv_x/dz 3:dv_y/dx 4:dv_y/dy 5:dv_y/dz 6:dv_z/dx 7:dv_z/dy 8:dv_z/dz */ if (ctx->verbose) { fprintf(stderr, "%s: jac = \n", me); ell_3m_PRINT(stderr, jacAns); } } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecDivergence)) { pvl->directAnswer[gageVecDivergence][0] = jacAns[0] + jacAns[4] + jacAns[8]; if (ctx->verbose) { fprintf(stderr, "%s: div = %g + %g + %g = %g\n", me, jacAns[0], jacAns[4], jacAns[8], pvl->directAnswer[gageVecDivergence][0]); } } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecCurl)) { ELL_3V_SET(curlAns, jacAns[7] - jacAns[5], jacAns[2] - jacAns[6], jacAns[3] - jacAns[1]); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecCurlNorm)) { pvl->directAnswer[gageVecCurlNorm][0] = AIR_CAST(gage_t, ELL_3V_LEN(curlAns)); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecHelicity)) { pvl->directAnswer[gageVecHelicity][0] = ELL_3V_DOT(vecAns, curlAns); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecNormHelicity)) { cmag = ELL_3V_LEN(curlAns); pvl->directAnswer[gageVecNormHelicity][0] = AIR_CAST(gage_t, cmag ? ELL_3V_DOT(normAns, curlAns)/cmag : 0); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecLambda2)) { ELL_3M_TRANSPOSE(tran, jacAns); /* symmetric part */ ELL_3M_SCALE_ADD2(symm, 0.5, jacAns, 0.5, tran); /* antisymmetric part */ ELL_3M_SCALE_ADD2(asym, 0.5, jacAns, -0.5, tran); /* square symmetric part */ ELL_3M_MUL(tmpMat, symm, symm); ELL_3M_COPY(symm, tmpMat); /* square antisymmetric part */ ELL_3M_MUL(tmpMat, asym, asym); /* sum of both */ ELL_3M_ADD2(symm, symm, tmpMat); /* get eigenvalues in sorted order */ /* asw = */ ell_3m_eigenvalues_d(eval, symm, AIR_TRUE); pvl->directAnswer[gageVecLambda2][0] = AIR_CAST(gage_t, eval[1]); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecImaginaryPart)) { pvl->directAnswer[gageVecImaginaryPart][0] = AIR_CAST(gage_t, gage_imaginary_part_eigenvalues(jacAns)); } /* 2nd order vector derivative continued */ if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecHessian)) { /* done if doD2 */ /* the ordering is induced by the scalar hessian computation : 0:d2v_x/dxdx 1:d2v_x/dxdy 2:d2v_x/dxdz 3:d2v_x/dydx 4:d2v_x/dydy 5:d2v_x/dydz 6:d2v_x/dzdx 7:d2v_x/dzdy 8:d2v_x/dzdz 9:d2v_y/dxdx [...] [...] 24:dv2_z/dzdx 25:d2v_z/dzdy 26:d2v_z/dzdz */ if (ctx->verbose) { fprintf(stderr, "%s: hes = \n", me); ell_3m_PRINT(stderr, hesAns); /* ?? */ } } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecDivGradient)) { pvl->directAnswer[gageVecDivGradient][0] = hesAns[0] + hesAns[12] + hesAns[24]; pvl->directAnswer[gageVecDivGradient][1] = hesAns[1] + hesAns[13] + hesAns[25]; pvl->directAnswer[gageVecDivGradient][2] = hesAns[2] + hesAns[14] + hesAns[26]; } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecCurlGradient)) { pvl->directAnswer[gageVecCurlGradient][0] = hesAns[21]-hesAns[15]; pvl->directAnswer[gageVecCurlGradient][1] = hesAns[22]-hesAns[16]; pvl->directAnswer[gageVecCurlGradient][2] = hesAns[23]-hesAns[17]; pvl->directAnswer[gageVecCurlGradient][3] = hesAns[ 6]-hesAns[18]; pvl->directAnswer[gageVecCurlGradient][4] = hesAns[ 7]-hesAns[19]; pvl->directAnswer[gageVecCurlGradient][5] = hesAns[ 8]-hesAns[20]; pvl->directAnswer[gageVecCurlGradient][6] = hesAns[ 9]-hesAns[ 1]; pvl->directAnswer[gageVecCurlGradient][7] = hesAns[10]-hesAns[ 2]; pvl->directAnswer[gageVecCurlGradient][8] = hesAns[11]-hesAns[ 3]; } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecCurlNormGrad)) { norm = 1./ELL_3V_LEN(curlAns); tmpVec[0] = hesAns[21] - hesAns[15]; tmpVec[1] = hesAns[ 6] - hesAns[18]; tmpVec[2] = hesAns[ 9] - hesAns[ 3]; pvl->directAnswer[gageVecCurlNormGrad][0]= AIR_CAST(gage_t, norm*ELL_3V_DOT(tmpVec, curlAns)); tmpVec[0] = hesAns[22] - hesAns[16]; tmpVec[1] = hesAns[ 7] - hesAns[19]; tmpVec[2] = hesAns[10] - hesAns[ 4]; pvl->directAnswer[gageVecCurlNormGrad][1]= AIR_CAST(gage_t, norm*ELL_3V_DOT(tmpVec, curlAns)); tmpVec[0] = hesAns[23] - hesAns[17]; tmpVec[1] = hesAns[ 8] - hesAns[20]; tmpVec[2] = hesAns[11] - hesAns[ 5]; pvl->directAnswer[gageVecCurlNormGrad][2]= AIR_CAST(gage_t, norm*ELL_3V_DOT(tmpVec, curlAns)); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecNCurlNormGrad)) { norm = 1./ELL_3V_LEN(curlnormgradAns); ELL_3V_SCALE_TT(pvl->directAnswer[gageVecNCurlNormGrad], gage_t, norm, pvl->directAnswer[gageVecCurlNormGrad]); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecHelGradient)) { pvl->directAnswer[gageVecHelGradient][0] = jacAns[0]*curlAns[0]+ jacAns[3]*curlAns[1]+ jacAns[6]*curlAns[2]+ curlGradAns[0]*vecAns[0]+ curlGradAns[3]*vecAns[1]+ curlGradAns[6]*vecAns[2]; pvl->directAnswer[gageVecHelGradient][1] = jacAns[1]*curlAns[0]+ jacAns[4]*curlAns[1]+ jacAns[7]*curlAns[2]+ curlGradAns[1]*vecAns[0]+ curlGradAns[4]*vecAns[1]+ curlGradAns[7]*vecAns[2]; pvl->directAnswer[gageVecHelGradient][0] = jacAns[2]*curlAns[0]+ jacAns[5]*curlAns[1]+ jacAns[8]*curlAns[2]+ curlGradAns[2]*vecAns[0]+ curlGradAns[5]*vecAns[1]+ curlGradAns[8]*vecAns[2]; } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecDirHelDeriv)) { pvl->directAnswer[gageVecDirHelDeriv][0] = ELL_3V_DOT(normAns, helGradAns); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecProjHelGradient)) { pvl->directAnswer[gageVecDirHelDeriv][0] = helGradAns[0]-dirHelDirAns[0]*normAns[0]; pvl->directAnswer[gageVecDirHelDeriv][1] = helGradAns[1]-dirHelDirAns[0]*normAns[1]; pvl->directAnswer[gageVecDirHelDeriv][2] = helGradAns[2]-dirHelDirAns[0]*normAns[2]; } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecGradient0)) { ELL_3V_SET(pvl->directAnswer[gageVecGradient0], jacAns[0], jacAns[1], jacAns[2]); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecGradient1)) { ELL_3V_SET(pvl->directAnswer[gageVecGradient1], jacAns[3], jacAns[4], jacAns[5]); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecGradient2)) { ELL_3V_SET(pvl->directAnswer[gageVecGradient2], jacAns[6], jacAns[7], jacAns[8]); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecMultiGrad)) { ELL_3M_IDENTITY_SET(pvl->directAnswer[gageVecMultiGrad]); ELL_3MV_OUTER_ADD(pvl->directAnswer[gageVecMultiGrad], pvl->directAnswer[gageVecGradient0], pvl->directAnswer[gageVecGradient0]); ELL_3MV_OUTER_ADD(pvl->directAnswer[gageVecMultiGrad], pvl->directAnswer[gageVecGradient1], pvl->directAnswer[gageVecGradient1]); ELL_3MV_OUTER_ADD(pvl->directAnswer[gageVecMultiGrad], pvl->directAnswer[gageVecGradient2], pvl->directAnswer[gageVecGradient2]); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecMGFrob)) { pvl->directAnswer[gageVecMGFrob][0] = AIR_CAST(gage_t, ELL_3M_FROB(pvl->directAnswer[gageVecMultiGrad])); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecMGEval)) { ELL_3M_COPY(tmpMat, pvl->directAnswer[gageVecMultiGrad]); /* HEY: look at the return value for root multiplicity? */ ell_3m_eigensolve_d(mgeval, mgevec, tmpMat, AIR_TRUE); ELL_3V_COPY_TT(pvl->directAnswer[gageVecMGEval], gage_t, mgeval); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageVecMGEvec)) { ELL_3M_COPY_TT(pvl->directAnswer[gageVecMGEvec], gage_t, mgevec); } return; }
void _gageSclAnswer (gageContext *ctx, gagePerVolume *pvl) { char me[]="_gageSclAnswer"; double gmag=0, *hess, *norm, *gvec, *gten, *k1, *k2, curv=0, sHess[9]={0,0,0,0,0,0,0,0,0}; double tmpMat[9], tmpVec[3], hevec[9], heval[3]; double len, gp1[3], gp2[3], *nPerp, ncTen[9], nProj[9]={0,0,0,0,0,0,0,0,0}; double alpha = 0.5; double beta = 0.5; double gamma = 5; double cc = 1e-6; #define FD_MEDIAN_MAX 16 int fd, nidx, xi, yi, zi; double *fw, iv3wght[2*FD_MEDIAN_MAX*FD_MEDIAN_MAX*FD_MEDIAN_MAX], wghtSum, wght; /* convenience pointers for work below */ hess = pvl->directAnswer[gageSclHessian]; gvec = pvl->directAnswer[gageSclGradVec]; norm = pvl->directAnswer[gageSclNormal]; nPerp = pvl->directAnswer[gageSclNPerp]; gten = pvl->directAnswer[gageSclGeomTens]; k1 = pvl->directAnswer[gageSclK1]; k2 = pvl->directAnswer[gageSclK2]; if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclValue)) { /* done if doV */ if (ctx->verbose) { fprintf(stderr, "%s: val = % 15.7f\n", me, (double)(pvl->directAnswer[gageSclValue][0])); } } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclGradVec)) { /* done if doD1 */ if (ctx->verbose) { fprintf(stderr, "%s: gvec = ", me); ell_3v_print_d(stderr, gvec); } } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclGradMag)) { /* this is the true value of gradient magnitude */ gmag = pvl->directAnswer[gageSclGradMag][0] = sqrt(ELL_3V_DOT(gvec, gvec)); } /* NB: it would seem that gageParmGradMagMin is completely ignored ... */ if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclNormal)) { if (gmag) { ELL_3V_SCALE(norm, 1/gmag, gvec); /* polishing ... len = sqrt(ELL_3V_DOT(norm, norm)); ELL_3V_SCALE(norm, 1/len, norm); */ } else { ELL_3V_COPY(norm, gageZeroNormal); } } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclNPerp)) { /* nPerp = I - outer(norm, norm) */ /* NB: this sets both nPerp and nProj */ ELL_3MV_OUTER(nProj, norm, norm); ELL_3M_SCALE(nPerp, -1, nProj); nPerp[0] += 1; nPerp[4] += 1; nPerp[8] += 1; } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclHessian)) { /* done if doD2 */ if (ctx->verbose) { fprintf(stderr, "%s: hess = \n", me); ell_3m_print_d(stderr, hess); } } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclLaplacian)) { pvl->directAnswer[gageSclLaplacian][0] = hess[0] + hess[4] + hess[8]; if (ctx->verbose) { fprintf(stderr, "%s: lapl = %g + %g + %g = %g\n", me, hess[0], hess[4], hess[8], pvl->directAnswer[gageSclLaplacian][0]); } } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclHessFrob)) { pvl->directAnswer[gageSclHessFrob][0] = ELL_3M_FROB(hess); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclHessEval)) { /* HEY: look at the return value for root multiplicity? */ ell_3m_eigensolve_d(heval, hevec, hess, AIR_TRUE); ELL_3V_COPY(pvl->directAnswer[gageSclHessEval], heval); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclHessEvec)) { ELL_3M_COPY(pvl->directAnswer[gageSclHessEvec], hevec); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclHessRidgeness)) { double A, B, S; if (heval[1] >0 || heval[2]>0) { pvl->directAnswer[gageSclHessRidgeness][0] = 0; } else if (AIR_ABS(heval[1])<1e-10 || AIR_ABS(heval[2])<1e-10) { pvl->directAnswer[gageSclHessRidgeness][0] = 0; } else { double *ans; A = AIR_ABS(heval[1])/AIR_ABS(heval[2]); B = AIR_ABS(heval[0])/sqrt(AIR_ABS(heval[1]*heval[2])); S = sqrt(heval[0]*heval[0] + heval[1]*heval[1] + heval[2]*heval[2]); ans = pvl->directAnswer[gageSclHessRidgeness]; ans[0] = (1-exp(-A*A/(2*alpha*alpha))) * exp(-B*B/(2*beta*beta)) * (1-exp(-S*S/(2*gamma*gamma))) * exp(-2*cc*cc/(AIR_ABS(heval[1])*heval[2]*heval[2])); } } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclHessValleyness)) { double A, B, S; if (heval[0] <0 || heval[1]<0) { pvl->directAnswer[gageSclHessValleyness][0] = 0; } else if (AIR_ABS(heval[0])<1e-10 || AIR_ABS(heval[1])<1e-10) { pvl->directAnswer[gageSclHessValleyness][0] = 0; } else { double *ans; A = AIR_ABS(heval[1])/AIR_ABS(heval[0]); B = AIR_ABS(heval[2])/sqrt(AIR_ABS(heval[1]*heval[0])); S = sqrt(heval[0]*heval[0] + heval[1]*heval[1] + heval[2]*heval[2]); ans = pvl->directAnswer[gageSclHessValleyness]; ans[0] = (1-exp(-A*A/(2*alpha*alpha))) * exp(-B*B/(2*beta*beta)) * (1-exp(-S*S/(2*gamma*gamma))) * exp(-2*cc*cc/(AIR_ABS(heval[1])*heval[0]*heval[0])); } } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclHessMode)) { pvl->directAnswer[gageSclHessMode][0] = airMode3_d(heval); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageScl2ndDD)) { ELL_3MV_MUL(tmpVec, hess, norm); pvl->directAnswer[gageScl2ndDD][0] = ELL_3V_DOT(norm, tmpVec); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclGeomTens)) { if (gmag > ctx->parm.gradMagCurvMin) { /* parm.curvNormalSide applied here to determine the sense of the normal when doing all curvature calculations */ ELL_3M_SCALE(sHess, -(ctx->parm.curvNormalSide)/gmag, hess); /* gten = nPerp * sHess * nPerp */ ELL_3M_MUL(tmpMat, sHess, nPerp); ELL_3M_MUL(gten, nPerp, tmpMat); if (ctx->verbose) { fprintf(stderr, "%s: gten: \n", me); ell_3m_print_d(stderr, gten); ELL_3MV_MUL(tmpVec, gten, norm); len = ELL_3V_LEN(tmpVec); fprintf(stderr, "%s: should be small: %30.15f\n", me, (double)len); ell_3v_perp_d(gp1, norm); ELL_3MV_MUL(tmpVec, gten, gp1); len = ELL_3V_LEN(tmpVec); fprintf(stderr, "%s: should be bigger: %30.15f\n", me, (double)len); ELL_3V_CROSS(gp2, gp1, norm); ELL_3MV_MUL(tmpVec, gten, gp2); len = ELL_3V_LEN(tmpVec); fprintf(stderr, "%s: should (also) be bigger: %30.15f\n", me, (double)len); } } else { ELL_3M_ZERO_SET(gten); } } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclTotalCurv)) { curv = pvl->directAnswer[gageSclTotalCurv][0] = ELL_3M_FROB(gten); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclShapeTrace)) { pvl->directAnswer[gageSclShapeTrace][0] = (curv ? ELL_3M_TRACE(gten)/curv : 0); } if ( (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclK1)) || (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclK2)) ){ double T, N, D; T = ELL_3M_TRACE(gten); N = curv; D = 2*N*N - T*T; /* if (D < -0.0000001) { fprintf(stderr, "%s: %g %g\n", me, T, N); fprintf(stderr, "%s: !!! D curv determinant % 22.10f < 0.0\n", me, D); fprintf(stderr, "%s: gten: \n", me); ell_3m_print_d(stderr, gten); } */ D = AIR_MAX(D, 0); D = sqrt(D); k1[0] = 0.5*(T + D); k2[0] = 0.5*(T - D); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclMeanCurv)) { pvl->directAnswer[gageSclMeanCurv][0] = (*k1 + *k2)/2; } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclGaussCurv)) { pvl->directAnswer[gageSclGaussCurv][0] = (*k1)*(*k2); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclShapeIndex)) { pvl->directAnswer[gageSclShapeIndex][0] = -(2/AIR_PI)*atan2(*k1 + *k2, *k1 - *k2); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclCurvDir1)) { /* HEY: this only works when K1, K2, 0 are all well mutually distinct, since these are the eigenvalues of the geometry tensor, and this code assumes that the eigenspaces are all one-dimensional */ ELL_3M_COPY(tmpMat, gten); ELL_3M_DIAG_SET(tmpMat, gten[0] - *k1, gten[4]- *k1, gten[8] - *k1); ell_3m_1d_nullspace_d(tmpVec, tmpMat); ELL_3V_COPY(pvl->directAnswer[gageSclCurvDir1], tmpVec); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclCurvDir2)) { /* HEY: this only works when K1, K2, 0 are all well mutually distinct, since these are the eigenvalues of the geometry tensor, and this code assumes that the eigenspaces are all one-dimensional */ ELL_3M_COPY(tmpMat, gten); ELL_3M_DIAG_SET(tmpMat, gten[0] - *k2, gten[4] - *k2, gten[8] - *k2); ell_3m_1d_nullspace_d(tmpVec, tmpMat); ELL_3V_COPY(pvl->directAnswer[gageSclCurvDir2], tmpVec); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclFlowlineCurv)) { if (gmag >= ctx->parm.gradMagCurvMin) { /* because of the gageSclGeomTens prerequisite, sHess, nPerp, and nProj are all already set */ /* ncTen = nPerp * sHess * nProj */ ELL_3M_MUL(tmpMat, sHess, nProj); ELL_3M_MUL(ncTen, nPerp, tmpMat); } else { ELL_3M_ZERO_SET(ncTen); } /* there used to be a wrong extra sqrt() here */ pvl->directAnswer[gageSclFlowlineCurv][0] = ELL_3M_FROB(ncTen); } if (GAGE_QUERY_ITEM_TEST(pvl->query, gageSclMedian)) { /* this item is currently a complete oddball in that it does not benefit from anything done in the "filter" stage, which is in fact a waste of time if the query consists only of this item */ fd = 2*ctx->radius; if (fd > FD_MEDIAN_MAX) { fprintf(stderr, "%s: PANIC: current filter diameter = %d " "> FD_MEDIAN_MAX = %d\n", me, fd, FD_MEDIAN_MAX); exit(1); } fw = ctx->fw + fd*3*gageKernel00; /* HEY: this needs some optimization help */ wghtSum = 0; nidx = 0; for (xi=0; xi<fd; xi++) { for (yi=0; yi<fd; yi++) { for (zi=0; zi<fd; zi++) { iv3wght[0 + 2*nidx] = pvl->iv3[nidx]; iv3wght[1 + 2*nidx] = fw[xi + 0*fd]*fw[yi + 1*fd]*fw[zi + 2*fd]; wghtSum += iv3wght[1 + 2*nidx]; nidx++; } } } qsort(iv3wght, fd*fd*fd, 2*sizeof(double), nrrdValCompare[nrrdTypeDouble]); wght = 0; for (nidx=0; nidx<fd*fd*fd; nidx++) { wght += iv3wght[1 + 2*nidx]; if (wght > wghtSum/2) { break; } } pvl->directAnswer[gageSclMedian][0] = iv3wght[0 + 2*nidx]; } return; }
int main(int argc, char *argv[]) { float angleA_f, axisA_f[3], angleB_f, axisB_f[3], qA_f[4], qB_f[4], qC_f[4], mat3A_f[9], mat4A_f[16], mat3B_f[9], mat4B_f[16], mat3C_f[9], mat4C_f[16], pntA_f[4], pntB_f[4], pntC_f[4]; double angleA_d, axisA_d[3], angleB_d, axisB_d[3], qA_d[4], qB_d[4], qC_d[4], mat3A_d[9], mat4A_d[16], mat3B_d[9], mat4B_d[16], mat3C_d[9], mat4C_d[16], pntA_d[4], pntB_d[4], pntC_d[4]; int I, N; double tmp, det, frob; me = argv[0]; N = 100000; AIR_UNUSED(pntA_d); AIR_UNUSED(pntB_d); AIR_UNUSED(pntC_d); AIR_UNUSED(mat4C_d); AIR_UNUSED(mat3C_d); AIR_UNUSED(mat4B_d); AIR_UNUSED(mat3B_d); AIR_UNUSED(mat4A_d); AIR_UNUSED(mat3A_d); AIR_UNUSED(qC_d); AIR_UNUSED(qB_d); AIR_UNUSED(qA_d); AIR_UNUSED(axisB_d); AIR_UNUSED(angleB_d); AIR_UNUSED(axisA_d); AIR_UNUSED(angleA_d); AIR_UNUSED(argc); for (I=0; I<N; I++) { /* make a rotation (as a quaternion) */ ELL_3V_SET(axisA_f, 2*airDrandMT()-1, 2*airDrandMT()-1, 2*airDrandMT()-1); ELL_3V_NORM(axisA_f, axisA_f, tmp); /* yea, not uniform, so what */ angleA_f = AIR_PI*(2*airDrandMT()-1); ell_aa_to_q_f(qA_f, angleA_f, axisA_f); /* convert to AA and back, and back */ angleB_f = ell_q_to_aa_f(axisB_f, qA_f); if (ELL_3V_DOT(axisB_f, axisA_f) < 0) { ELL_3V_SCALE(axisB_f, -1, axisB_f); angleB_f *= -1; } ELL_3V_SUB(axisA_f, axisA_f, axisB_f); printf(" aa -> q -> aa error: %g, %g\n", CA + AIR_ABS(angleA_f - angleB_f), CA + ELL_3V_LEN(axisA_f)); /* convert to 3m and back, and back */ ell_q_to_3m_f(mat3A_f, qA_f); ell_3m_to_q_f(qB_f, mat3A_f); if (ELL_4V_DOT(qA_f, qB_f) < 0) { ELL_4V_SCALE(qB_f, -1, qB_f); } ELL_4V_SUB(qC_f, qA_f, qB_f); ELL_Q_TO_3M(mat3B_f, qA_f); ELL_3M_SUB(mat3C_f, mat3B_f, mat3A_f); printf(" q -> 3m -> q error: %g, %g\n", CA + ELL_4V_LEN(qC_f), CA + ELL_3M_FROB(mat3C_f)); /* convert to 4m and back, and back */ ell_q_to_4m_f(mat4A_f, qA_f); ell_4m_to_q_f(qB_f, mat4A_f); if (ELL_4V_DOT(qA_f, qB_f) < 0) { ELL_4V_SCALE(qB_f, -1, qB_f); } ELL_4V_SUB(qC_f, qA_f, qB_f); ELL_Q_TO_4M(mat4B_f, qA_f); ELL_4M_SUB(mat4C_f, mat4B_f, mat4A_f); printf(" q -> 4m -> q error: %g, %g\n", CA + ELL_4V_LEN(qC_f), CA + ELL_4M_FROB(mat4C_f)); /* make a point that we'll rotate */ ELL_3V_SET(pntA_f, 2*airDrandMT()-1, 2*airDrandMT()-1, 2*airDrandMT()-1); /* effect rotation in two different ways, and compare results */ ELL_3MV_MUL(pntB_f, mat3A_f, pntA_f); ell_q_3v_rotate_f(pntC_f, qA_f, pntA_f); ELL_3V_SUB(pntA_f, pntB_f, pntC_f); printf(" rotation error = %g\n", CA + ELL_3V_LEN(pntA_f)); /* mix up inversion with conversion */ ell_3m_inv_f(mat3C_f, mat3A_f); ell_3m_to_q_f(qB_f, mat3C_f); ell_q_mul_f(qC_f, qA_f, qB_f); if (ELL_4V_DOT(qA_f, qC_f) < 0) { ELL_4V_SCALE(qC_f, -1, qC_f); } printf(" inv mul = %g %g %g %g\n", qC_f[0], CA + qC_f[1], CA + qC_f[2], CA + qC_f[3]); ell_q_inv_f(qC_f, qB_f); ELL_4V_SUB(qC_f, qB_f, qB_f); printf(" inv diff = %g %g %g %g\n", CA + qC_f[0], CA + qC_f[1], CA + qC_f[2], CA + qC_f[3]); /* exp and log */ ell_q_log_f(qC_f, qA_f); ell_q_log_f(qB_f, qC_f); ell_q_exp_f(qC_f, qB_f); ell_q_exp_f(qB_f, qC_f); ELL_4V_SUB(qC_f, qB_f, qA_f); printf(" exp/log diff = %g %g %g %g\n", CA + qC_f[0], CA + qC_f[1], CA + qC_f[2], CA + qC_f[3]); /* pow, not very exhaustive */ ell_q_to_3m_f(mat3A_f, qA_f); ell_3m_post_mul_f(mat3A_f, mat3A_f); ell_3m_post_mul_f(mat3A_f, mat3A_f); ell_q_pow_f(qB_f, qA_f, 4); ell_q_to_3m_f(mat3B_f, qB_f); ELL_3M_SUB(mat3B_f, mat3B_f, mat3A_f); printf(" pow diff = %g\n", CA + ELL_3M_FROB(mat3B_f)); if (ELL_3M_FROB(mat3B_f) > 2) { printf(" start q = %g %g %g %g\n", qA_f[0], qA_f[1], qA_f[2], qA_f[3]); angleA_f = ell_q_to_aa_f(axisA_f, qA_f); printf(" --> aa = %g (%g %g %g)\n", angleA_f, axisA_f[0], axisA_f[1], axisA_f[2]); printf(" q^3 = %g %g %g %g\n", qB_f[0], qB_f[1], qB_f[2], qB_f[3]); angleA_f = ell_q_to_aa_f(axisA_f, qB_f); printf(" --> aa = %g (%g %g %g)\n", angleA_f, axisA_f[0], axisA_f[1], axisA_f[2]); exit(1); } /* make sure it looks like a rotation matrix */ ell_q_to_3m_f(mat3A_f, qA_f); det = ELL_3M_DET(mat3A_f); frob = ELL_3M_FROB(mat3A_f); ELL_3M_TRANSPOSE(mat3B_f, mat3A_f); ell_3m_inv_f(mat3C_f, mat3A_f); ELL_3M_SUB(mat3C_f, mat3B_f, mat3C_f); printf(" det = %g; size = %g; err = %g\n", det, frob*frob/3, CA + ELL_3M_FROB(mat3C_f)); } exit(0); }