CollOfScalar EquelleRuntimeCPU::solveForUpdate(const CollOfScalar& residual) const { Eigen::SparseMatrix<double, Eigen::RowMajor> matr = residual.derivative()[0]; CollOfScalar::V du = CollOfScalar::V::Zero(residual.size()); Opm::time::StopWatch clock; clock.start(); // solve(n, # nonzero values ("val"), ptr to col indices // ("col_ind"), ptr to row locations in val array ("row_ind") // (these two may be swapped, not sure about the naming convention // here...), array of actual values ("val") (I guess... '*sa'...), // rhs, solution) Opm::LinearSolverInterface::LinearSolverReport rep = linsolver_.solve(matr.rows(), matr.nonZeros(), matr.outerIndexPtr(), matr.innerIndexPtr(), matr.valuePtr(), residual.value().data(), du.data()); if (verbose_ > 2) { std::cout << " solveForUpdate: Linear solver took: " << clock.secsSinceLast() << " seconds." << std::endl; } if (!rep.converged) { OPM_THROW(std::runtime_error, "Linear solver convergence failure."); } return du; }
/// This function is not provided by AutoDiffBlock, so we must add it here. inline CollOfScalar sqrt(const CollOfScalar& x) { // d(sqrt(x))/dy = 1/(2*sqrt(x)) * dx/dy const auto& xjac = x.derivative(); if (xjac.empty()) { return CollOfScalar(sqrt(x.value())); } const int num_blocks = xjac.size(); std::vector<CollOfScalar::M> jac(num_blocks); const auto sqrt_x = sqrt(x.value()); const CollOfScalar::M one_over_two_sqrt_x((0.5/sqrt_x).matrix().asDiagonal()); for (int block = 0; block < num_blocks; ++block) { jac[block] = one_over_two_sqrt_x * xjac[block]; } return CollOfScalar::ADB::function(sqrt_x, jac); }
CollOfScalar EquelleRuntimeCUDA::newtonSolve(const ResidualFunctor& rescomp, const CollOfScalar& u_initialguess) { Opm::time::StopWatch clock; clock.start(); // Set up Newton loop. // Define the primary variable CollOfScalar u = CollOfScalar(u_initialguess, true); if (verbose_ > 2) { output("Initial u", u); output(" newtonSolve: norm (initial u)", twoNorm(u)); } CollOfScalar residual = rescomp(u); if (verbose_ > 2) { output("Initial residual", residual); output(" newtonSolve: norm (initial residual)", twoNorm(residual)); } int iter = 0; // Debugging output not specified in Equelle. if (verbose_ > 1) { std::cout << " newtonSolve: iter = " << iter << " (max = " << max_iter_ << "), norm(residual) = " << twoNorm(residual) << " (tol = " << abs_res_tol_ << ")" << std::endl; } CollOfScalar du; // Execute newton loop until residual is small or we have used too many iterations. while ( (twoNorm(residual) > abs_res_tol_) && (iter < max_iter_) ) { if ( solver_.getSolver() == CPU ) { du = serialSolveForUpdate(residual); } else { // Solve linear equations for du, apply update. du = solver_.solve(residual.derivative(), residual.value(), verbose_); } // du is a constant, hence, u is still a primary variable with an identity // matrix as its derivative. u = u - du; // Recompute residual. residual = rescomp(u); if (verbose_ > 2) { // Debugging output not specified in Equelle. output("u", u); output(" newtonSolve: norm(u)", twoNorm(u)); output("residual", residual); output(" newtonSolve: norm(residual)", twoNorm(residual)); } ++iter; // Debugging output not specified in Equelle. if (verbose_ > 1) { std::cout << " newtonSolve: iter = " << iter << " (max = " << max_iter_ << "), norm(residual) = " << twoNorm(residual) << " (tol = " << abs_res_tol_ << ")" << std::endl; } } if (verbose_ > 0) { if (twoNorm(residual) > abs_res_tol_) { std::cout << "Newton solver failed to converge in " << max_iter_ << " iterations" << std::endl; } else { std::cout << "Newton solver converged in " << iter << " iterations" << std::endl; } } if (verbose_ > 1) { std::cout << "Newton solver took: " << clock.secsSinceLast() << " seconds." << std::endl; } return CollOfScalar(u.value()); }