Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
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;
}
Ejemplo n.º 3
0
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;
}