Foam::label Foam::quadraticFitSnGradData::calcFit ( const List<point>& C, const label faci ) { vector idir(1,0,0); vector jdir(0,1,0); vector kdir(0,0,1); findFaceDirs(idir, jdir, kdir, mesh(), faci); scalarList wts(C.size(), scalar(1)); wts[0] = centralWeight_; wts[1] = centralWeight_; point p0 = mesh().faceCentres()[faci]; scalar scale = 0; // calculate the matrix of the polynomial components scalarRectangularMatrix B(C.size(), minSize_, scalar(0)); for(label ip = 0; ip < C.size(); ip++) { const point& p = C[ip]; scalar px = (p - p0)&idir; scalar py = (p - p0)&jdir; #ifdef SPHERICAL_GEOMETRY scalar pz = mag(p) - mag(p0); #else scalar pz = (p - p0)&kdir; #endif if (ip == 0) scale = max(max(mag(px), mag(py)), mag(pz)); px /= scale; py /= scale; pz /= scale; label is = 0; B[ip][is++] = wts[0]*wts[ip]; B[ip][is++] = wts[0]*wts[ip]*px; B[ip][is++] = wts[ip]*sqr(px); if (dim_ >= 2) { B[ip][is++] = wts[ip]*py; B[ip][is++] = wts[ip]*px*py; B[ip][is++] = wts[ip]*sqr(py); } if (dim_ == 3) { B[ip][is++] = wts[ip]*pz; B[ip][is++] = wts[ip]*px*pz; //B[ip][is++] = wts[ip]*py*pz; B[ip][is++] = wts[ip]*sqr(pz); } } // Set the fit label stencilSize = C.size(); fit_[faci].setSize(stencilSize); scalarList singVals(minSize_); label nSVDzeros = 0; const scalar& deltaCoeff = mesh().deltaCoeffs()[faci]; bool goodFit = false; for(int iIt = 0; iIt < 10 && !goodFit; iIt++) { SVD svd(B, SMALL); scalar fit0 = wts[0]*wts[0]*svd.VSinvUt()[1][0]/scale; scalar fit1 = wts[0]*wts[1]*svd.VSinvUt()[1][1]/scale; goodFit = fit0 < 0 && fit1 > 0 && mag(fit0 + deltaCoeff) < 0.5*deltaCoeff && mag(fit1 - deltaCoeff) < 0.5*deltaCoeff; if (goodFit) { fit_[faci][0] = fit0; fit_[faci][1] = fit1; for(label i = 2; i < stencilSize; i++) { fit_[faci][i] = wts[0]*wts[i]*svd.VSinvUt()[1][i]/scale; } singVals = svd.S(); nSVDzeros = svd.nZeros(); } else // (not good fit so increase weight in the centre and for linear) { wts[0] *= 10; wts[1] *= 10; for(label i = 0; i < B.n(); i++) { B[i][0] *= 10; B[i][1] *= 10; } for(label j = 0; j < B.m(); j++) { B[0][j] *= 10; B[1][j] *= 10; } } } if (goodFit) { // remove the uncorrected snGradScheme coefficients fit_[faci][0] += deltaCoeff; fit_[faci][1] -= deltaCoeff; } else { Pout<< "quadratifFitSnGradData could not fit face " << faci << " fit_[faci][0] = " << fit_[faci][0] << " fit_[faci][1] = " << fit_[faci][1] << " deltaCoeff = " << deltaCoeff << endl; fit_[faci] = 0; } return minSize_ - nSVDzeros; }
IGL_INLINE void igl::min_quad_dense_precompute( const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& A, const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& Aeq, const bool use_lu_decomposition, Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& S) { typedef Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> Mat; // This threshold seems to matter a lot but I'm not sure how to // set it const T treshold = igl::FLOAT_EPS; //const T treshold = igl::DOUBLE_EPS; const int n = A.rows(); assert(A.cols() == n); const int m = Aeq.rows(); assert(Aeq.cols() == n); // Lagrange multipliers method: Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> LM(n + m, n + m); LM.block(0, 0, n, n) = A; LM.block(0, n, n, m) = Aeq.transpose(); LM.block(n, 0, m, n) = Aeq; LM.block(n, n, m, m).setZero(); Mat LMpinv; if(use_lu_decomposition) { // if LM is close to singular, use at your own risk :) LMpinv = LM.inverse(); }else { // use SVD typedef Eigen::Matrix<T, Eigen::Dynamic, 1> Vec; Vec singValues; Eigen::JacobiSVD<Mat> svd; svd.compute(LM, Eigen::ComputeFullU | Eigen::ComputeFullV ); const Mat& u = svd.matrixU(); const Mat& v = svd.matrixV(); const Vec& singVals = svd.singularValues(); Vec pi_singVals(n + m); int zeroed = 0; for (int i=0; i<n + m; i++) { T sv = singVals(i, 0); assert(sv >= 0); // printf("sv: %lg ? %lg\n",(double) sv,(double)treshold); if (sv > treshold) pi_singVals(i, 0) = T(1) / sv; else { pi_singVals(i, 0) = T(0); zeroed++; } } printf("min_quad_dense_precompute: %i singular values zeroed (threshold = %e)\n", zeroed, treshold); Eigen::DiagonalMatrix<T, Eigen::Dynamic> pi_diag(pi_singVals); LMpinv = v * pi_diag * u.transpose(); } S = LMpinv.block(0, 0, n, n + m); //// debug: //mlinit(&g_pEngine); // //mlsetmatrix(&g_pEngine, "A", A); //mlsetmatrix(&g_pEngine, "Aeq", Aeq); //mlsetmatrix(&g_pEngine, "LM", LM); //mlsetmatrix(&g_pEngine, "u", u); //mlsetmatrix(&g_pEngine, "v", v); //MatrixXd svMat = singVals; //mlsetmatrix(&g_pEngine, "singVals", svMat); //mlsetmatrix(&g_pEngine, "LMpinv", LMpinv); //mlsetmatrix(&g_pEngine, "S", S); //int hu = 1; }
int main( int argc, char* argv[] ) { El::Environment env( argc, argv ); El::mpi::Comm comm = El::mpi::COMM_WORLD; const int commRank = El::mpi::Rank( comm ); try { typedef double Real; typedef El::Complex<Real> Scalar; El::Timer timer; const El::Int n1 = El::Input("--n1","first grid dimension",30); const El::Int n2 = El::Input("--n2","second grid dimension",30); const El::Int n3 = El::Input("--n3","third grid dimension",30); const Real omega = El::Input("--omega","angular frequency",Real(18)); const Real damping = El::Input("--damping","damping parameter",Real(7)); const bool selInv = El::Input("--selInv","selectively invert?",false); const bool intraPiv = El::Input("--intraPiv","frontal pivoting?",false); const bool natural = El::Input("--natural","analytic partitions?",true); const bool sequential = El::Input ("--sequential","sequential partitions?",true); const int numDistSeps = El::Input ("--numDistSeps", "number of separators to try per distributed partition",1); const int numSeqSeps = El::Input ("--numSeqSeps", "number of separators to try per sequential partition",1); const int cutoff = El::Input("--cutoff","cutoff for nested dissection",128); const bool print = El::Input("--print","print matrix?",false); const bool display = El::Input("--display","display matrix?",false); El::ProcessInput(); const El::Grid grid(comm); El::DistSparseMatrix<Scalar> A(grid); Scalar dampedOmega( omega, damping ); El::Helmholtz( A, n1, n2, n3, dampedOmega*dampedOmega ); const El::Int N = A.Height(); if( display ) El::Display( A, "A" ); if( print ) El::Print( A, "A" ); if( commRank == 0 ) El::Output("Generating random vector x and forming y := A x"); timer.Start(); El::DistMultiVec<Scalar> x( N, 1, grid ), y( N, 1, grid ); El::MakeUniform( x ); El::Zero( y ); El::Multiply( El::NORMAL, Scalar(1), A, x, Scalar(0), y ); const Real yOrigNorm = El::FrobeniusNorm( y ); El::mpi::Barrier(comm); if( commRank == 0 ) El::Output(timer.Stop()," seconds"); El::BisectCtrl ctrl; ctrl.sequential = sequential; ctrl.numSeqSeps = numSeqSeps; ctrl.numDistSeps = numDistSeps; ctrl.cutoff = cutoff; El::DistSparseLDLFactorization<Scalar> sparseLDLFact; const bool hermitian = false; if( commRank == 0 ) El::Output("Running analysis..."); timer.Start(); if( natural ) { sparseLDLFact.Initialize3DGridGraph ( n1, n2, n3, A, hermitian, ctrl ); } else { sparseLDLFact.Initialize( A, hermitian, ctrl ); } El::mpi::Barrier(comm); if( commRank == 0 ) El::Output(timer.Stop()," seconds"); auto& front = sparseLDLFact.Front(); auto& info = sparseLDLFact.NodeInfo(); const El::Int rootSepSize = info.size; if( commRank == 0 ) El::Output(rootSepSize," vertices in root separator\n"); if( commRank == 0 ) El::Output("Running LDL factorization..."); El::mpi::Barrier(comm); timer.Start(); El::LDLFrontType type; if( intraPiv ) type = selInv ? El::LDL_INTRAPIV_SELINV_2D : El::LDL_INTRAPIV_2D; else type = selInv ? El::LDL_SELINV_2D : El::LDL_2D; sparseLDLFact.Factor( type ); El::mpi::Barrier(comm); if( commRank == 0 ) El::Output(timer.Stop()," seconds"); if( info.child != nullptr && info.child->onLeft ) { if( commRank == 0 ) El::Output ("Computing SVD of connectivity of second separator to " "the root separator..."); timer.Start(); const auto& FL = front.child->L2D; const El::Grid& grid = FL.Grid(); const El::Int height = FL.Height(); const El::Int width = FL.Width(); auto B = FL( El::IR(width,height), El::IR(0,width) ); El::DistMatrix<Real,El::VR,El::STAR> singVals_VR_STAR( grid ); El::SVD( B, singVals_VR_STAR ); El::DistMatrix<Real,El::CIRC,El::CIRC> singVals( singVals_VR_STAR ); El::mpi::Barrier( grid.Comm() ); const Real twoNorm = El::MaxNorm( singVals_VR_STAR ); const El::Int minDim = singVals_VR_STAR.Height(); if( grid.Rank() == singVals.Root() ) { El::Output (" two-norm is ",twoNorm," (took ",timer.Stop()," seconds)"); for( Real tol=1e-1; tol>=Real(1e-10); tol/=10 ) { El::Int numRank = minDim; for( El::Int j=0; j<minDim; ++j ) { if( singVals.GetLocal(j,0) <= twoNorm*tol ) { numRank = j; break; } } El::Output(" rank (",tol,")=",numRank,"/",minDim); } } } if( commRank == 0 ) El::Output ("Computing SVD of the largest off-diagonal block of " "numerical Green's function on root separator..."); { timer.Start(); const auto& FL = front.L2D; const El::Grid& grid = FL.Grid(); const El::Int lHalf = rootSepSize/2; const El::Int uHalf = rootSepSize - lHalf; if( commRank == 0 ) El::Output("lower half=",lHalf,", upper half=",uHalf); auto offDiagBlock = FL( El::IR(lHalf,rootSepSize), El::IR(0,lHalf) ); El::DistMatrix<Real,El::VR,El::STAR> singVals_VR_STAR( grid ); El::SVD( offDiagBlock, singVals_VR_STAR ); El::DistMatrix<Real,El::CIRC,El::CIRC> singVals( singVals_VR_STAR ); El::mpi::Barrier( grid.Comm() ); const Real twoNorm = El::MaxNorm( singVals_VR_STAR ); if( grid.Rank() == singVals.Root() ) { El::Output(timer.Stop()," seconds"); for( Real tol=1e-1; tol>=Real(1e-10); tol/=10 ) { El::Int numRank = lHalf; for( El::Int j=0; j<lHalf; ++j ) { if( singVals.GetLocal(j,0) <= twoNorm*tol ) { numRank = j; break; } } El::Output(" rank (",tol,")=",numRank,"/",lHalf); } } } if( commRank == 0 ) El::Output("Solving against y..."); timer.Start(); sparseLDLFact.Solve( y ); El::mpi::Barrier(comm); if( commRank == 0 ) El::Output(timer.Stop()," seconds"); if( commRank == 0 ) El::Output("Checking error in computed solution..."); const Real xNorm = El::FrobeniusNorm( x ); const Real yNorm = El::FrobeniusNorm( y ); y -= x; const Real errorNorm = El::FrobeniusNorm( y ); if( commRank == 0 ) El::Output ("|| x ||_2 = ",xNorm,"\n", "|| xComp ||_2 = ",yNorm,"\n", "|| A x ||_2 = ",yOrigNorm,"\n", "|| error ||_2 / || x ||_2 = ",errorNorm/xNorm,"\n", "|| error ||_2 / || A x ||_2 = ",errorNorm/yOrigNorm); } catch( std::exception& e ) { El::ReportException(e); } return 0; }