template <typename F> GpuQmrCs<F>::GpuQmrCs (const OpenCL::StubPool& pool, const std::vector<cl::CommandQueue>& queues, const DDAParams<ftype>& ddaParams, GpuMatVec<ftype>& matVec, csize_t maxIter, OpenCL::VectorAccounting& accounting) : GpuIterativeSolver<F> (pool, queues, ddaParams, matVec, 50000, maxIter, accounting), varsVec (pool, 1, accounting, "vars"), vars (varsVec.pointer ()), tmpVec2_ (pool, queues, g (), accounting, "tmpVec2"), tmpVec3_ (pool, queues, g (), accounting, "tmpVec3"), tmpVec4_ (pool, queues, g (), accounting, "tmpVec4") { this->Avecbuffer ().setToZero (queues); this->rvec ().setToZero (queues); this->xvec ().setToZero (queues); this->tmpVec1 ().setToZero (queues); tmpVec2 ().setToZero (queues); tmpVec3 ().setToZero (queues); tmpVec4 ().setToZero (queues); }
int SVD(Mat3d & F, Mat3d & U, Vec3d & Sigma, Mat3d & V, double singularValue_eps, int modifiedSVD) { // The code handles the following special situations: //--------------------------------------------------------- // 1. det(V) == -1 // - multiply the first column of V by -1 //--------------------------------------------------------- // 2. An entry of Sigma is near zero //--------------------------------------------------------- // (if modifiedSVD == 1) : // 3. negative determinant (Tet is inverted in solid mechanics). // - check if det(U) == -1 // - If yes, then negate the minimal element of Sigma // and the corresponding column of U //--------------------------------------------------------- // form F^T F and do eigendecomposition Mat3d normalEq = trans(F) * F; Vec3d eigenValues; Vec3d eigenVectors[3]; eigen_sym(normalEq, eigenValues, eigenVectors); V.set(eigenVectors[0][0], eigenVectors[1][0], eigenVectors[2][0], eigenVectors[0][1], eigenVectors[1][1], eigenVectors[2][1], eigenVectors[0][2], eigenVectors[1][2], eigenVectors[2][2]); /* printf("--- original V ---\n"); V.print(); printf("--- eigenValues ---\n"); printf("%G %G %G\n", eigenValues[0], eigenValues[1], eigenValues[2]); */ // Handle situation: // 1. det(V) == -1 // - multiply the first column of V by -1 if (det(V) < 0.0) { // convert V into a rotation (multiply column 1 by -1) V[0][0] *= -1.0; V[1][0] *= -1.0; V[2][0] *= -1.0; } Sigma[0] = (eigenValues[0] > 0.0) ? sqrt(eigenValues[0]) : 0.0; Sigma[1] = (eigenValues[1] > 0.0) ? sqrt(eigenValues[1]) : 0.0; Sigma[2] = (eigenValues[2] > 0.0) ? sqrt(eigenValues[2]) : 0.0; //printf("--- Sigma ---\n"); //printf("%G %G %G\n", Sigma[0][0], Sigma[1][1], Sigma[2][2]); // compute inverse of singular values // also check if singular values are close to zero Vec3d SigmaInverse; SigmaInverse[0] = (Sigma[0] > singularValue_eps) ? (1.0 / Sigma[0]) : 0.0; SigmaInverse[1] = (Sigma[1] > singularValue_eps) ? (1.0 / Sigma[1]) : 0.0; SigmaInverse[2] = (Sigma[2] > singularValue_eps) ? (1.0 / Sigma[2]) : 0.0; // compute U using the formula: // U = F * V * diag(SigmaInverse) U = F * V; U.multiplyDiagRight(SigmaInverse); // In theory, U is now orthonormal, U^T U = U U^T = I .. it may be a rotation or a reflection, depending on F. // But in practice, if singular values are small or zero, it may not be orthonormal, so we need to fix it. // Handle situation: // 2. An entry of Sigma is near zero // --------------------------------------------------------- /* printf("--- SigmaInverse ---\n"); SigmaInverse.print(); printf(" --- U ---\n"); U.print(); */ if ((Sigma[0] < singularValue_eps) && (Sigma[1] < singularValue_eps) && (Sigma[2] < singularValue_eps)) { // extreme case, all singular values are small, material has collapsed almost to a point // see [Irving 04], p. 4 U.set(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0); } else { // handle the case where two singular values are small, but the third one is not // handle it by computing two (arbitrary) vectors orthogonal to the eigenvector for the large singular value int done = 0; for(int dim=0; dim<3; dim++) { int dimA = dim; int dimB = (dim + 1) % 3; int dimC = (dim + 2) % 3; if ((Sigma[dimB] < singularValue_eps) && (Sigma[dimC] < singularValue_eps)) { // only the column dimA can be trusted, columns dimB and dimC correspond to tiny singular values Vec3d tmpVec1(U[0][dimA], U[1][dimA], U[2][dimA]); // column dimA Vec3d tmpVec2; tmpVec2 = tmpVec1.findOrthonormalVector(); Vec3d tmpVec3 = norm(cross(tmpVec1, tmpVec2)); U[0][dimB] = tmpVec2[0]; U[1][dimB] = tmpVec2[1]; U[2][dimB] = tmpVec2[2]; U[0][dimC] = tmpVec3[0]; U[1][dimC] = tmpVec3[1]; U[2][dimC] = tmpVec3[2]; if (det(U) < 0.0) { U[0][dimB] *= -1.0; U[1][dimB] *= -1.0; U[2][dimB] *= -1.0; } done = 1; break; // out of for } } // handle the case where one singular value is small, but the other two are not // handle it by computing the cross product of the two eigenvectors for the two large singular values if (!done) { for(int dim=0; dim<3; dim++) { int dimA = dim; int dimB = (dim + 1) % 3; int dimC = (dim + 2) % 3; if (Sigma[dimA] < singularValue_eps) { // columns dimB and dimC are both good, but column dimA corresponds to a tiny singular value Vec3d tmpVec1(U[0][dimB], U[1][dimB], U[2][dimB]); // column dimB Vec3d tmpVec2(U[0][dimC], U[1][dimC], U[2][dimC]); // column dimC Vec3d tmpVec3 = norm(cross(tmpVec1, tmpVec2)); U[0][dimA] = tmpVec3[0]; U[1][dimA] = tmpVec3[1]; U[2][dimA] = tmpVec3[2]; if (det(U) < 0.0) { U[0][dimA] *= -1.0; U[1][dimA] *= -1.0; U[2][dimA] *= -1.0; } done = 1; break; // out of for } } } if ((!done) && (modifiedSVD == 1)) { // Handle situation: // 3. negative determinant (Tet is inverted in solid mechanics) // - check if det(U) == -1 // - If yes, then negate the minimal element of Sigma // and the corresponding column of U double detU = det(U); if (detU < 0.0) { // negative determinant // find the smallest singular value (they are all non-negative) int smallestSingularValueIndex = 0; for(int dim=1; dim<3; dim++) if (Sigma[dim] < Sigma[smallestSingularValueIndex]) smallestSingularValueIndex = dim; // negate the smallest singular value Sigma[smallestSingularValueIndex] *= -1.0; U[0][smallestSingularValueIndex] *= -1.0; U[1][smallestSingularValueIndex] *= -1.0; U[2][smallestSingularValueIndex] *= -1.0; } } } /* printf("U = \n"); U.print(); printf("Sigma = \n"); Sigma.print(); printf("V = \n"); V.print(); */ return 0; }
GcmJointTildeInfo<S_V,S_M,D_V,D_M,P_V,P_M,Q_V,Q_M>::GcmJointTildeInfo( const GpmsaComputerModelOptions& gcmOptionsObj, const GcmExperimentInfo<S_V,S_M,D_V,D_M,P_V,P_M>& e, const GcmJointInfo<S_V,S_M,D_V,D_M,P_V,P_M,Q_V,Q_M>& jj) : m_env (jj.m_env), m_Bmat_tilde (m_env,e.m_y_space.map(),jj.m_Bmat_rank), m_Bmat_tilde_rank (0), m_vu_tilde_space (m_env, "vu_tilde_", jj.m_Bmat_rank, NULL), // rr0 check m_Lbmat (m_env,m_vu_tilde_space.map(),jj.m_Bmat_with_permut->numCols()), // rr0 check m_Btildet_Wy_Btilde (m_vu_tilde_space.zeroVector()), m_Btildet_Wy_Btilde_inv(m_vu_tilde_space.zeroVector()), m_Zvec_tilde_hat_vu (m_vu_tilde_space.zeroVector()), m_a_y_modifier_tilde (0), m_b_y_modifier_tilde (0) { std::set<unsigned int> tmpSet; tmpSet.insert(m_env.subId()); //****************************************************************************** // Tilde situation: form 'm_Bmat_tilde' // Tilde situation: form 'm_vu_tilde_space' // Tilde situation: form 'm_Lbmat' //****************************************************************************** if (jj.m_Bmat_with_permut->numRowsGlobal() >= jj.m_Bmat_with_permut->numCols()) { D_M matbU(m_env,e.m_y_space.map(),jj.m_vu_size); // same as m_Bmat matbU = jj.m_Bmat_with_permut->svdMatU(); unsigned int buMatRank = matbU.rank(0.,1.e-8 ); // todo: should be an option unsigned int buMatRank14 = matbU.rank(0.,1.e-14); if (m_env.subDisplayFile()) { *m_env.subDisplayFile() << "In GcmJointTildeInfo<S_V,S_M,D_V,D_M,P_V,P_M,Q_V,Q_M>::constructor()" << ": matbU.numRowsLocal() = " << matbU.numRowsLocal() << ", matbU.numCols() = " << matbU.numCols() << ", matbU.rank(0.,1.e-8) = " << buMatRank << ", matbU.rank(0.,1.e-14) = " << buMatRank14 << std::endl; } if (m_env.checkingLevel() >= 1) { D_M matbUcheck(jj.m_vu_space.zeroVector()); D_V vecI(e.m_y_space.zeroVector()); D_V vecJ(e.m_y_space.zeroVector()); for (unsigned int i = 0; i < matbU.numCols(); ++i) { matbU.getColumn(i,vecI); for (unsigned int j = i; j < matbU.numCols(); ++j) { matbU.getColumn(j,vecJ); matbUcheck(i,j) = scalarProduct(vecI,vecJ); } } matbUcheck.setPrintHorizontally(false); if (m_env.subDisplayFile()) { *m_env.subDisplayFile() << "In GcmJointTildeInfo<S_V,S_M,D_V,D_M,P_V,P_M,Q_V,Q_M>::constructor()" << ": m_Bmat_with_permut->numRowsLocal() = " << jj.m_Bmat_with_permut->numRowsLocal() << ", m_Bmat_with_permut->numCols() = " << jj.m_Bmat_with_permut->numCols() << ", m_Bmat_rank = " << jj.m_Bmat_rank << ", matbU.numRowsLocal() = " << matbU.numRowsLocal() << ", matbU.numCols() = " << matbU.numCols() << ", buMatrank(0.,1.e-8) = " << buMatRank << ", buMatrank(0.,1.e-14) = " << buMatRank14 << ", matbUcheck.numRowsLocal() = " << matbUcheck.numRowsLocal() << ", matbUcheck.numCols() = " << matbUcheck.numCols() << ", matbUcheck =\n" << matbUcheck << std::endl; } } D_V vecbJ(e.m_y_space.zeroVector()); for (unsigned int j = 0; j < jj.m_Bmat_rank; ++j) { matbU.getColumn(j,vecbJ); m_Bmat_tilde.setColumn(j,vecbJ); } if (gcmOptionsObj.m_ov.m_dataOutputAllowedSet.find(m_env.subId()) != gcmOptionsObj.m_ov.m_dataOutputAllowedSet.end()) { m_Bmat_tilde.subWriteContents("Btilde", "Btilde1", "m", tmpSet); } if (m_env.subDisplayFile()) { *m_env.subDisplayFile() << "In GcmJointTildeInfo<S_V,S_M,D_V,D_M,P_V,P_M,Q_V,Q_M>::constructor()" << ": m_Bmat_tilde computed (1)" << std::endl; } } else { D_M Bmat_t(m_env,jj.m_vu_space.map(),e.m_paper_n_y); // same as m_Bmat^T Bmat_t.fillWithTranspose(0,0,*jj.m_Bmat_with_permut,true,true); D_M matbV(e.m_y_space.zeroVector()); matbV = Bmat_t.svdMatV(); unsigned int bvMatRank = matbV.rank(0.,1.e-8); // todo: should be an option unsigned int bvMatRank14 = matbV.rank(0.,1.e-14); if (m_env.subDisplayFile()) { *m_env.subDisplayFile() << "In GcmJointTildeInfo<S_V,S_M,D_V,D_M,P_V,P_M,Q_V,Q_M>::constructor()" << ": matbV.numRowsLocal() = " << matbV.numRowsLocal() << ", matbV.numCols() = " << matbV.numCols() << ", matbV.rank(0.,1.e-8) = " << bvMatRank << ", matbV.rank(0.,1.e-14) = " << bvMatRank14 << std::endl; } if (m_env.checkingLevel() >= 1) { D_M matbVcheck(e.m_y_space.zeroVector()); D_V vecI(e.m_y_space.zeroVector()); D_V vecJ(e.m_y_space.zeroVector()); for (unsigned int i = 0; i < matbV.numCols(); ++i) { matbV.getColumn(i,vecI); for (unsigned int j = i; j < matbV.numCols(); ++j) { matbV.getColumn(j,vecJ); matbVcheck(i,j) = scalarProduct(vecI,vecJ); } } matbVcheck.setPrintHorizontally(false); if (m_env.subDisplayFile()) { *m_env.subDisplayFile() << "In GcmJointTildeInfo<S_V,S_M,D_V,D_M,P_V,P_M,Q_V,Q_M>::constructor()" << ": m_Bmat_with_permut->numRowsLocal() = " << jj.m_Bmat_with_permut->numRowsLocal() << ", m_Bmat_with_permut->numCols() = " << jj.m_Bmat_with_permut->numCols() << ", m_Bmat_rank = " << jj.m_Bmat_rank << ", matbV.numRowsLocal() = " << matbV.numRowsLocal() << ", matbV.numCols() = " << matbV.numCols() << ", bvMatrank(0.,1.e-8) = " << bvMatRank << ", bvMatrank(0.,1.e-14) = " << bvMatRank14 << ", matbVcheck.numRowsLocal() = " << matbVcheck.numRowsLocal() << ", matbVcheck.numCols() = " << matbVcheck.numCols() << ", matbVcheck =\n" << matbVcheck << std::endl; } } D_V vecbJ(e.m_y_space.zeroVector()); for (unsigned int j = 0; j < jj.m_Bmat_rank; ++j) { matbV.getColumn(j,vecbJ); m_Bmat_tilde.setColumn(j,vecbJ); } if (gcmOptionsObj.m_ov.m_dataOutputAllowedSet.find(m_env.subId()) != gcmOptionsObj.m_ov.m_dataOutputAllowedSet.end()) { m_Bmat_tilde.subWriteContents("Btilde", "Btilde2", "m", tmpSet); } if (m_env.subDisplayFile()) { *m_env.subDisplayFile() << "In GcmJointTildeInfo<S_V,S_M,D_V,D_M,P_V,P_M,Q_V,Q_M>::constructor()" << ": m_Bmat_tilde computed (2)" << std::endl; } } if (m_env.subDisplayFile()) { *m_env.subDisplayFile() << "In GcmJointTildeInfo<S_V,S_M,D_V,D_M,P_V,P_M,Q_V,Q_M>::constructor()" << ": finished forming 'm_Bmat_tilde'" << ", m_Bmat_tilde.numRowsLocal() = " << m_Bmat_tilde.numRowsLocal() << ", m_Bmat_tilde.numCols() = " << m_Bmat_tilde.numCols() << std::endl; } m_Bmat_tilde.svdSolve(*jj.m_Bmat_with_permut,m_Lbmat); if (gcmOptionsObj.m_ov.m_dataOutputAllowedSet.find(m_env.subId()) != gcmOptionsObj.m_ov.m_dataOutputAllowedSet.end()) { m_Lbmat.subWriteContents("Lbmat", "Lbmat", "m", tmpSet); } if (m_env.subDisplayFile()) { *m_env.subDisplayFile() << "In GcmJointTildeInfo<S_V,S_M,D_V,D_M,P_V,P_M,Q_V,Q_M>::constructor()" << ": m_Lbmat_tilde computed" << std::endl; } //******************************************************************************** // Form 'Btilde^T' matrix //******************************************************************************** D_M Btildet(m_env,m_vu_tilde_space.map(),e.m_paper_n_y); Btildet.fillWithTranspose(0,0,m_Bmat_tilde,true,true); if (m_env.checkingLevel() >= 1) { // Check transpose operation D_M Btildett(m_env,e.m_y_space.map(),m_vu_tilde_space.dimGlobal()); Btildett.fillWithTranspose(0,0,Btildet,true,true); Btildett -= m_Bmat_tilde; double btDiffNorm = Btildett.normFrob(); if (m_env.subDisplayFile()) { *m_env.subDisplayFile() << "In GcmJointTildeInfo<S_V,S_M,D_V,D_M,P_V,P_M,Q_V,Q_M>::constructor()" << ": ||Btildett - Btilde||_2 = " << btDiffNorm << std::endl; } } //******************************************************************************** // Compute 'Btilde' rank //******************************************************************************** double bTildeRank14 = 0.; if (m_Bmat_tilde.numRowsGlobal() >= m_Bmat_tilde.numCols()) { m_Bmat_tilde_rank = m_Bmat_tilde.rank(0.,1.e-8 ); // todo: should be an option bTildeRank14 = m_Bmat_tilde.rank(0.,1.e-14); } else { m_Bmat_tilde_rank = Btildet.rank(0.,1.e-8 ); // todo: should be an option bTildeRank14 = Btildet.rank(0.,1.e-14); } if (m_env.subDisplayFile()) { *m_env.subDisplayFile() << "In GcmJointTildeInfo<S_V,S_M,D_V,D_M,P_V,P_M,Q_V,Q_M>::constructor()" << ": m_Bmat_tilde.numRowsLocal() = " << m_Bmat_tilde.numRowsLocal() << ", m_Bmat_tilde.numCols() = " << m_Bmat_tilde.numCols() << ", m_Bmat_tilde.rank(0.,1.e-8) = " << m_Bmat_tilde_rank << ", m_Bmat_tilde.rank(0.,1.e-14) = " << bTildeRank14 << std::endl; } queso_require_equal_to_msg(m_Bmat_tilde_rank, std::min(m_Bmat_tilde.numRowsGlobal(),m_Bmat_tilde.numCols()), "'m_Bmat_tilde' does not have a proper rank"); //****************************************************************************** // Tilde situation: compute 'Btilde^T W_y Btilde' matrix, and its inverse //****************************************************************************** m_Btildet_Wy_Btilde = Btildet * (*e.m_Wy * m_Bmat_tilde); // todo: add 1.e-4 to diagonal if (m_env.subDisplayFile()) { *m_env.subDisplayFile() << "In GcmJointTildeInfo<S_V,S_M,D_V,D_M,P_V,P_M,Q_V,Q_M>::constructor()" << ": finished computing 'm_Btildet_Wy_Btilde'" << std::endl; } if (gcmOptionsObj.m_ov.m_dataOutputAllowedSet.find(m_env.subId()) != gcmOptionsObj.m_ov.m_dataOutputAllowedSet.end()) { m_Btildet_Wy_Btilde.subWriteContents("Btildet_Wy_Btilde", "Btildet_Wy_Btilde", "m", tmpSet); } if (m_env.subDisplayFile()) { *m_env.subDisplayFile() << "In GcmJointTildeInfo<S_V,S_M,D_V,D_M,P_V,P_M,Q_V,Q_M>::constructor()" << ": m_Btildet_Wy_Btilde computed" << std::endl; } double btildetWyBtildeLnDeterminant = m_Btildet_Wy_Btilde.lnDeterminant(); unsigned int btildetWyBtildeRank = m_Btildet_Wy_Btilde.rank(0.,1.e-8 ); // todo: should be an option unsigned int btildetWyBtildeRank14 = m_Btildet_Wy_Btilde.rank(0.,1.e-14); if (m_env.subDisplayFile()) { *m_env.subDisplayFile() << "In GcmJointTildeInfo<S_V,S_M,D_V,D_M,P_V,P_M,Q_V,Q_M>::constructor()" << ": m_Btildet_Wy_Btilde.numRowsLocal() = " << m_Btildet_Wy_Btilde.numRowsLocal() << ", m_Btildet_Wy_Btilde.numCols() = " << m_Btildet_Wy_Btilde.numCols() << ", m_Btildet_Wy_Btilde.lnDeterminant() = " << btildetWyBtildeLnDeterminant << ": m_Btildet_Wy_Btilde.rank(0.,1.e-8) = " << btildetWyBtildeRank << ": m_Btildet_Wy_Btilde.rank(0.,1.e-14) = " << btildetWyBtildeRank14 << std::endl; } m_Btildet_Wy_Btilde_inv = m_Btildet_Wy_Btilde.inverse(); // todo: add 1.e-6 to diagonal if (m_env.subDisplayFile()) { *m_env.subDisplayFile() << "In GcmJointTildeInfo<S_V,S_M,D_V,D_M,P_V,P_M,Q_V,Q_M>::constructor()" << ": finished computing 'm_Btildet_Wy_Btilde_inv'" << ", m_Btildet_Wy_Btilde_inv.lnDeterminant() = " << m_Btildet_Wy_Btilde_inv.lnDeterminant() << std::endl; } if (gcmOptionsObj.m_ov.m_dataOutputAllowedSet.find(m_env.subId()) != gcmOptionsObj.m_ov.m_dataOutputAllowedSet.end()) { m_Btildet_Wy_Btilde_inv.subWriteContents("Btildet_Wy_Btilde_inv", "Btildet_Wy_Btilde_inv", "m", tmpSet); } if (m_env.subDisplayFile()) { *m_env.subDisplayFile() << "In GcmJointTildeInfo<S_V,S_M,D_V,D_M,P_V,P_M,Q_V,Q_M>::constructor()" << ": m_Btildet_Wy_Btilde_inv computed" << std::endl; } double btildetWyBtildeInvLnDeterminant = m_Btildet_Wy_Btilde_inv.lnDeterminant(); unsigned int btildetWyBtildeInvRank = m_Btildet_Wy_Btilde_inv.rank(0.,1.e-8 ); // todo: should be an option unsigned int btildetWyBtildeInvRank14 = m_Btildet_Wy_Btilde_inv.rank(0.,1.e-14); if (m_env.subDisplayFile()) { *m_env.subDisplayFile() << "In GcmJointTildeInfo<S_V,S_M,D_V,D_M,P_V,P_M,Q_V,Q_M>::constructor()" << ": m_Btildet_Wy_Btilde_inv.numRowsLocal() = " << m_Btildet_Wy_Btilde_inv.numRowsLocal() << ", m_Btildet_Wy_Btilde_inv.numCols() = " << m_Btildet_Wy_Btilde_inv.numCols() << ": m_Btildet_Wy_Btilde_inv.lnDeterminant() = " << btildetWyBtildeInvLnDeterminant << ": m_Btildet_Wy_Btilde_inv.rank(0.,1.e-8) = " << btildetWyBtildeInvRank << ": m_Btildet_Wy_Btilde_inv.rank(0.,1.e-14) = " << btildetWyBtildeInvRank14 << std::endl; } //******************************************************************************** // Compute 'tilde' exponent modifiers //******************************************************************************** m_a_y_modifier_tilde = ((double) (e.m_paper_n_y - m_Bmat_tilde_rank)) / 2.; if (m_env.subDisplayFile()) { *m_env.subDisplayFile() << "In GcmJointTildeInfo<S_V,S_M,D_V,D_M,P_V,P_M,Q_V,Q_M>::constructor()" << ": m_a_y_modifier_tilde = " << m_a_y_modifier_tilde << std::endl; } D_V yVec_transformed(e.m_experimentStorage.yVec_transformed()); if (m_env.subDisplayFile()) { *m_env.subDisplayFile() << "In GcmJointTildeInfo<S_V,S_M,D_V,D_M,P_V,P_M,Q_V,Q_M>::constructor()" << ": m_Zvec_tilde_hat_vu.sizeLocal() = " << m_Zvec_tilde_hat_vu.sizeLocal() << ", m_Btildet_Wy_Btilde_inv.numRowsLocal() = " << m_Btildet_Wy_Btilde_inv.numRowsLocal() << ", m_Btildet_Wy_Btilde_inv.numCols() = " << m_Btildet_Wy_Btilde_inv.numCols() << ", Btildet.numRowsLocal() = " << Btildet.numRowsLocal() << ", Btildet.numCols() = " << Btildet.numCols() << ", m_Wy->numRowsLocal() = " << e.m_Wy->numRowsLocal() << ", m_Wy->numCols() = " << e.m_Wy->numCols() << ", yVec_transformed.sizeLocal() = " << yVec_transformed.sizeLocal() << std::endl; } m_Zvec_tilde_hat_vu = m_Btildet_Wy_Btilde_inv * (Btildet * (*e.m_Wy * yVec_transformed)); D_V tmpVec2(yVec_transformed - (m_Bmat_tilde * m_Zvec_tilde_hat_vu)); tmpVec2 = *e.m_Wy * tmpVec2; m_b_y_modifier_tilde = scalarProduct(yVec_transformed,tmpVec2) / 2.; if (m_env.subDisplayFile()) { *m_env.subDisplayFile() << "In GcmJointTildeInfo<S_V,S_M,D_V,D_M,P_V,P_M,Q_V,Q_M>::constructor()" << ": m_b_y_modifier_tilde = " << m_b_y_modifier_tilde << std::endl; } if (m_env.subDisplayFile()) { *m_env.subDisplayFile() << "In GcmJointTildeInfo<S_V,S_M,D_V,D_M,P_V,P_M,Q_V,Q_M>::constructor()" << ": finished computing 'tilde' exponent modifiers" << std::endl; } }
int ReducedStVKCubatureForceModel::ModifiedSVD(Mat3d & F, Mat3d & U, Vec3d & Fhat, Mat3d & V) const { // The code handles the following necessary special situations (see the code below) : //--------------------------------------------------------- // 1. det(V) == -1 // - simply multiply a column of V by -1 //--------------------------------------------------------- // 2. An entry of Fhat is near zero //--------------------------------------------------------- // 3. Tet is inverted. // - check if det(U) == -1 // - If yes, then negate the minimal element of Fhat // and the corresponding column of U //--------------------------------------------------------- double modifiedSVD_singularValue_eps = 1e-8; // form F^T F and do eigendecomposition Mat3d normalEq = trans(F) * F; Vec3d eigenValues; Vec3d eigenVectors[3]; // note that normalEq is changed after calling eigen_sym eigen_sym(normalEq, eigenValues, eigenVectors); V.set(eigenVectors[0][0], eigenVectors[1][0], eigenVectors[2][0], eigenVectors[0][1], eigenVectors[1][1], eigenVectors[2][1], eigenVectors[0][2], eigenVectors[1][2], eigenVectors[2][2]); /* printf("--- original V ---\n"); V.print(); printf("--- eigenValues ---\n"); printf("%G %G %G\n", eigenValues[0], eigenValues[1], eigenValues[2]); */ // Handle situation: // 1. det(V) == -1 // - simply multiply a column of V by -1 if (det(V) < 0.0) { // convert V into a rotation (multiply column 1 by -1) V[0][0] *= -1.0; V[1][0] *= -1.0; V[2][0] *= -1.0; } Fhat[0] = (eigenValues[0] > 0.0) ? sqrt(eigenValues[0]) : 0.0; Fhat[1] = (eigenValues[1] > 0.0) ? sqrt(eigenValues[1]) : 0.0; Fhat[2] = (eigenValues[2] > 0.0) ? sqrt(eigenValues[2]) : 0.0; //printf("--- Fhat ---\n"); //printf("%G %G %G\n", Fhat[0][0], Fhat[1][1], Fhat[2][2]); // compute inverse of singular values // also check if singular values are close to zero Vec3d FhatInverse; FhatInverse[0] = (Fhat[0] > modifiedSVD_singularValue_eps) ? (1.0 / Fhat[0]) : 0.0; FhatInverse[1] = (Fhat[1] > modifiedSVD_singularValue_eps) ? (1.0 / Fhat[1]) : 0.0; FhatInverse[2] = (Fhat[2] > modifiedSVD_singularValue_eps) ? (1.0 / Fhat[2]) : 0.0; // compute U using the formula: // U = F * V * diag(FhatInverse) U = F * V; U.multiplyDiagRight(FhatInverse); // In theory, U is now orthonormal, U^T U = U U^T = I .. it may be a rotation or a reflection, depending on F. // But in practice, if singular values are small or zero, it may not be orthonormal, so we need to fix it. // Handle situation: // 2. An entry of Fhat is near zero // --------------------------------------------------------- /* printf("--- FhatInverse ---\n"); FhatInverse.print(); printf(" --- U ---\n"); U.print(); */ if ((Fhat[0] < modifiedSVD_singularValue_eps) && (Fhat[1] < modifiedSVD_singularValue_eps) && (Fhat[2] < modifiedSVD_singularValue_eps)) { // extreme case, material has collapsed almost to a point // see [Irving 04], p. 4 U.set(1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0); } else { int done = 0; for(int dim=0; dim<3; dim++) { int dimA = dim; int dimB = (dim + 1) % 3; int dimC = (dim + 2) % 3; if ((Fhat[dimB] < modifiedSVD_singularValue_eps) && (Fhat[dimC] < modifiedSVD_singularValue_eps)) { // only the column dimA can be trusted, columns dimB and dimC correspond to tiny singular values Vec3d tmpVec1(U[0][dimA], U[1][dimA], U[2][dimA]); // column dimA Vec3d tmpVec2; FindOrthonormalVector(tmpVec1, tmpVec2); Vec3d tmpVec3 = norm(cross(tmpVec1, tmpVec2)); U[0][dimB] = tmpVec2[0]; U[1][dimB] = tmpVec2[1]; U[2][dimB] = tmpVec2[2]; U[0][dimC] = tmpVec3[0]; U[1][dimC] = tmpVec3[1]; U[2][dimC] = tmpVec3[2]; if (det(U) < 0.0) { U[0][dimB] *= -1.0; U[1][dimB] *= -1.0; U[2][dimB] *= -1.0; } done = 1; break; // out of for } } if (!done) { for(int dim=0; dim<3; dim++) { int dimA = dim; int dimB = (dim + 1) % 3; int dimC = (dim + 2) % 3; if (Fhat[dimA] < modifiedSVD_singularValue_eps) { // columns dimB and dimC are both good, but column dimA corresponds to a tiny singular value Vec3d tmpVec1(U[0][dimB], U[1][dimB], U[2][dimB]); // column dimB Vec3d tmpVec2(U[0][dimC], U[1][dimC], U[2][dimC]); // column dimC Vec3d tmpVec3 = norm(cross(tmpVec1, tmpVec2)); U[0][dimA] = tmpVec3[0]; U[1][dimA] = tmpVec3[1]; U[2][dimA] = tmpVec3[2]; if (det(U) < 0.0) { U[0][dimA] *= -1.0; U[1][dimA] *= -1.0; U[2][dimA] *= -1.0; } done = 1; break; // out of for } } } if (!done) { // Handle situation: // 3. Tet is inverted. // - check if det(U) == -1 // - If yes, then negate the minimal element of Fhat // and the corresponding column of U double detU = det(U); if (detU < 0.0) { // tet is inverted // find smallest singular value (they are all non-negative) int smallestSingularValueIndex = 0; for(int dim=1; dim<3; dim++) if (Fhat[dim] < Fhat[smallestSingularValueIndex]) smallestSingularValueIndex = dim; // negate smallest singular value Fhat[smallestSingularValueIndex] *= -1.0; U[0][smallestSingularValueIndex] *= -1.0; U[1][smallestSingularValueIndex] *= -1.0; U[2][smallestSingularValueIndex] *= -1.0; } } } /* printf("U = \n"); U.print(); printf("Fhat = \n"); Fhat.print(); printf("V = \n"); V.print(); */ return 0; }