template <class F> boost::shared_ptr<std::vector<std::complex<F> > > CpuIterativeSolver<F>::getResult (UNUSED std::ostream& log, UNUSED Core::ProfilingDataPtr prof) { std::vector<ctype>& pvec = tmpVec1 (); std::vector<ctype>& xvec = this->xvec (); g ().multMat (matVec ().cc ().cc_sqrt (), xvec, pvec); return boost::make_shared<std::vector<std::complex<F> > > (pvec); }
template <class F> F CpuIterativeSolver<F>::initGeneral (const std::vector<ctype>& einc, std::ostream& log, const std::vector<ctype>& start, UNUSED Core::ProfilingDataPtr prof) { std::vector<ctype>& pvec = tmpVec1 (); for (int j = 0; j < 3; j++) for (uint32_t i = g ().nvCount (); i < g ().vecStride (); i++) pvec[i + j * g ().vecStride ()] = 0; g ().multMat (matVec ().cc ().cc_sqrt (), einc, pvec); ftype temp = LinAlg::norm (pvec); this->residScale = 1 / temp; ftype inprodR = 0.0 / 0.0; if (start.size () != 0) { std::vector<ctype>& xvec = this->xvec (); g ().multMatInv (matVec ().cc ().cc_sqrt (), start, xvec); // xvec = start / cc_sqrt std::vector<ctype>& Avecbuffer = this->Avecbuffer (); matVec ().apply (xvec, Avecbuffer, false); std::vector<ctype>& rvec = this->rvec (); LinAlg::linComb (Avecbuffer, ctype (-1), pvec, rvec); inprodR = LinAlg::norm (rvec); log << "Use loaded start value" << std::endl; } else { std::vector<ctype>& Avecbuffer = this->Avecbuffer (); matVec ().apply (pvec, Avecbuffer, false); std::vector<ctype>& rvec = this->rvec (); LinAlg::linComb (Avecbuffer, ctype (-1), pvec, rvec); inprodR = LinAlg::norm (rvec); log << "temp = " << temp << ", inprodR = " << inprodR << std::endl; std::vector<ctype>& xvec = this->xvec (); if (temp < inprodR) { log << "Use 0" << std::endl; LinAlg::fill<ctype> (xvec, 0); swap (rvec, pvec); inprodR = temp; } else { log << "Use pvec" << std::endl; swap (xvec, pvec); } } log << "|r_0|^2: " << temp << std::endl; return inprodR; }
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; }
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; }