/// Solve the linear system Ax = b, with A being the /// combined derivative matrix of the residual and b /// being the residual itself. /// \param[in] residual residual object containing A and b. /// \return the solution x NewtonIterationBlackoilInterleaved::SolutionVector NewtonIterationBlackoilInterleaved::computeNewtonIncrement(const LinearisedBlackoilResidual& residual) const { // Build the vector of equations. const int np = residual.material_balance_eq.size(); std::vector<ADB> eqs; eqs.reserve(np + 2); for (int phase = 0; phase < np; ++phase) { eqs.push_back(residual.material_balance_eq[phase]); } // check if wells are present const bool hasWells = residual.well_flux_eq.size() > 0 ; std::vector<ADB> elim_eqs; if( hasWells ) { eqs.push_back(residual.well_flux_eq); eqs.push_back(residual.well_eq); // Eliminate the well-related unknowns, and corresponding equations. elim_eqs.reserve(2); elim_eqs.push_back(eqs[np]); eqs = eliminateVariable(eqs, np); // Eliminate well flux unknowns. elim_eqs.push_back(eqs[np]); eqs = eliminateVariable(eqs, np); // Eliminate well bhp unknowns. assert(int(eqs.size()) == np); } // Scale material balance equations. const double matbalscale[3] = { 1.1169, 1.0031, 0.0031 }; // HACK hardcoded instead of computed. for (int phase = 0; phase < np; ++phase) { eqs[phase] = eqs[phase] * matbalscale[phase]; } // Form modified system. Eigen::SparseMatrix<double, Eigen::RowMajor> A; V b; formEllipticSystem(np, eqs, A, b); // Create ISTL matrix with interleaved rows and columns (block structured). Mat istlA; formInterleavedSystem(eqs, A, istlA); // Solve reduced system. SolutionVector dx(SolutionVector::Zero(b.size())); // Right hand side. const int size = istlA.N(); Vector istlb(size); for (int i = 0; i < size; ++i) { istlb[i][0] = b(i); istlb[i][1] = b(size + i); istlb[i][2] = b(2*size + i); } // System solution Vector x(istlA.M()); x = 0.0; Dune::InverseOperatorResult result; // Parallel version is deactivated until we figure out how to do it properly. #if HAVE_MPI if (parallelInformation_.type() == typeid(ParallelISTLInformation)) { typedef Dune::OwnerOverlapCopyCommunication<int,int> Comm; const ParallelISTLInformation& info = boost::any_cast<const ParallelISTLInformation&>( parallelInformation_); Comm istlComm(info.communicator()); info.copyValuesTo(istlComm.indexSet(), istlComm.remoteIndices(), size, np); // Construct operator, scalar product and vectors needed. typedef Dune::OverlappingSchwarzOperator<Mat,Vector,Vector,Comm> Operator; Operator opA(istlA, istlComm); constructPreconditionerAndSolve<Dune::SolverCategory::overlapping>(opA, x, istlb, istlComm, result); } else #endif { // Construct operator, scalar product and vectors needed. typedef Dune::MatrixAdapter<Mat,Vector,Vector> Operator; Operator opA(istlA); Dune::Amg::SequentialInformation info; constructPreconditionerAndSolve(opA, x, istlb, info, result); } // store number of iterations iterations_ = result.iterations; // Check for failure of linear solver. if (!result.converged) { OPM_THROW(LinearSolverProblem, "Convergence failure for linear solver."); } // Copy solver output to dx. for (int i = 0; i < size; ++i) { dx(i) = x[i][0]; dx(size + i) = x[i][1]; dx(2*size + i) = x[i][2]; } if ( hasWells ) { // Compute full solution using the eliminated equations. // Recovery in inverse order of elimination. dx = recoverVariable(elim_eqs[1], dx, np); dx = recoverVariable(elim_eqs[0], dx, np); } return dx; }
/// Solve the linear system Ax = b, with A being the /// combined derivative matrix of the residual and b /// being the residual itself. /// \param[in] residual residual object containing A and b. /// \return the solution x NewtonIterationBlackoilCPR::SolutionVector NewtonIterationBlackoilCPR::computeNewtonIncrement(const LinearisedBlackoilResidual& residual) const { // Build the vector of equations. const int np = residual.material_balance_eq.size(); std::vector<ADB> eqs; eqs.reserve(np + 2); for (int phase = 0; phase < np; ++phase) { eqs.push_back(residual.material_balance_eq[phase]); } // check if wells are present const bool hasWells = residual.well_flux_eq.size() > 0 ; std::vector<ADB> elim_eqs; if( hasWells ) { eqs.push_back(residual.well_flux_eq); eqs.push_back(residual.well_eq); // Eliminate the well-related unknowns, and corresponding equations. elim_eqs.reserve(2); elim_eqs.push_back(eqs[np]); eqs = eliminateVariable(eqs, np); // Eliminate well flux unknowns. elim_eqs.push_back(eqs[np]); eqs = eliminateVariable(eqs, np); // Eliminate well bhp unknowns. assert(int(eqs.size()) == np); } // Scale material balance equations. for (int phase = 0; phase < np; ++phase) { eqs[phase] = eqs[phase] * residual.matbalscale[phase]; } // Add material balance equations (or other manipulations) to // form pressure equation in top left of full system. Eigen::SparseMatrix<double, Eigen::RowMajor> A; V b; formEllipticSystem(np, eqs, A, b); // Scale pressure equation. const double pscale = 200*unit::barsa; const int nc = residual.material_balance_eq[0].size(); A.topRows(nc) *= pscale; b.topRows(nc) *= pscale; // Solve reduced system. SolutionVector dx(SolutionVector::Zero(b.size())); // Create ISTL matrix. DuneMatrix istlA( A ); // Create ISTL matrix for elliptic part. DuneMatrix istlAe( A.topLeftCorner(nc, nc) ); // Right hand side. Vector istlb(istlA.N()); std::copy_n(b.data(), istlb.size(), istlb.begin()); // System solution Vector x(istlA.M()); x = 0.0; Dune::InverseOperatorResult result; #if HAVE_MPI if(parallelInformation_.type()==typeid(ParallelISTLInformation)) { typedef Dune::OwnerOverlapCopyCommunication<int,int> Comm; const ParallelISTLInformation& info = boost::any_cast<const ParallelISTLInformation&>( parallelInformation_); Comm istlComm(info.communicator()); Comm istlAeComm(info.communicator()); info.copyValuesTo(istlAeComm.indexSet(), istlAeComm.remoteIndices()); info.copyValuesTo(istlComm.indexSet(), istlComm.remoteIndices(), istlAe.N(), istlA.N()/istlAe.N()); // Construct operator, scalar product and vectors needed. typedef Dune::OverlappingSchwarzOperator<Mat,Vector,Vector,Comm> Operator; Operator opA(istlA, istlComm); constructPreconditionerAndSolve<Dune::SolverCategory::overlapping>(opA, istlAe, x, istlb, istlComm, istlAeComm, result); } else #endif { // Construct operator, scalar product and vectors needed. typedef Dune::MatrixAdapter<Mat,Vector,Vector> Operator; Operator opA(istlA); Dune::Amg::SequentialInformation info; constructPreconditionerAndSolve(opA, istlAe, x, istlb, info, info, result); } // store number of iterations iterations_ = result.iterations; // Check for failure of linear solver. if (!result.converged && !linear_solver_ignoreconvergencefailure_) { OPM_THROW(LinearSolverProblem, "Convergence failure for linear solver."); } // Copy solver output to dx. std::copy(x.begin(), x.end(), dx.data()); if ( hasWells ) { // Compute full solution using the eliminated equations. // Recovery in inverse order of elimination. dx = recoverVariable(elim_eqs[1], dx, np); dx = recoverVariable(elim_eqs[0], dx, np); } return dx; }