Temperary commit

-- works on SPE1 but not SPE9
-- if number of perforations are increased to 3 in SPE1 the same error
as in SPE9 occur.
This commit is contained in:
Tor Harald Sandve 2016-08-25 15:25:01 +02:00
parent 4bdf74eb11
commit 190076f5da
4 changed files with 419 additions and 62 deletions

View File

@ -220,10 +220,10 @@ namespace detail {
int nc,
int np,
const std::vector<double> pv,
LinearisedBlackoilResidual residual)
std::vector<double> residual_well)
{
const int nw = residual.well_flux_eq.size() / np;
assert(nw * np == int(residual.well_flux_eq.size()));
const int nw = residual_well.size() / np;
assert(nw * np == int(residual_well.size()));
// Do the global reductions
#if HAVE_MPI
@ -257,7 +257,7 @@ namespace detail {
if (idx < np) {
maxNormWell[idx] = 0.0;
for ( int w = 0; w < nw; ++w ) {
maxNormWell[idx] = std::max(maxNormWell[idx], std::abs(residual_.well_flux_eq.value()[nw*idx + w]));
maxNormWell[idx] = std::max(maxNormWell[idx], std::abs(residual_well[nw*idx + w]));
}
}
}
@ -282,7 +282,7 @@ namespace detail {
if (idx < np) {
maxNormWell[idx] = 0.0;
for ( int w = 0; w < nw; ++w ) {
maxNormWell[idx] = std::max(maxNormWell[idx], std::abs(residual.well_flux_eq.value()[nw*idx + w]));
maxNormWell[idx] = std::max(maxNormWell[idx], std::abs(residual_well[nw*idx + w]));
}
}
}

View File

@ -116,6 +116,12 @@ namespace Opm {
typedef typename GET_PROP_TYPE(TypeTag, Indices) BlackoilIndices;
typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw;
typedef typename GET_PROP_TYPE(TypeTag, MaterialLawParams) MaterialLawParams;
typedef double Scalar;
typedef Dune::FieldVector<Scalar, 3 > VectorBlockType;
typedef Dune::FieldMatrix<Scalar, 3, 3 > MatrixBlockType;
typedef Dune::BCRSMatrix <MatrixBlockType> Mat;
typedef Dune::BlockVector<VectorBlockType> BVector;
//typedef typename SolutionVector :: value_type PrimaryVariables ;
// --------- Public methods ---------
@ -175,9 +181,7 @@ namespace Opm {
{
const double gravity = detail::getGravity(geo_.gravity(), UgGridHelpers::dimensions(grid_));
const V depth = Opm::AutoDiffGrid::cellCentroidsZToEigen(grid_);
well_model_.init(&fluid_, &active_, &phaseCondition_, &vfp_properties_, gravity, depth);
wellModel().setWellsActive( localWellsActive() );
global_nc_ = Opm::AutoDiffGrid::numCells(grid_);
}
@ -229,7 +233,7 @@ namespace Opm {
const bool must_solve = (iteration < nonlinear_solver.minIter()) || (!converged);
if (must_solve) {
// enable single precision for solvers when dt is smaller then 20 days
residual_.singlePrecision = (unit::convert::to(dt, unit::day) < 20.) ;
//residual_.singlePrecision = (unit::convert::to(dt, unit::day) < 20.) ;
// Compute the nonlinear update.
V dx = solveJacobianSystem();
@ -283,10 +287,22 @@ namespace Opm {
// -------- Mass balance equations --------
assembleMassBalanceEq(timer, iterationIdx, reservoir_state);
// -------- Well equations ----------
double dt = timer.currentStepLength();
IterationReport iter_report = wellModel().assemble(ebosSimulator_, iterationIdx, dt, well_state, residual_);
typedef double Scalar;
typedef Dune::FieldVector<Scalar, 3 > VectorBlockType;
typedef Dune::FieldMatrix<Scalar, 3, 3 > MatrixBlockType;
typedef Dune::BCRSMatrix <MatrixBlockType> Mat;
typedef Dune::BlockVector<VectorBlockType> BVector;
typedef Dune::MatrixAdapter<Mat,BVector,BVector> Operator;
auto& ebosJac = ebosSimulator_.model().linearizer().matrix();
auto& ebosResid = ebosSimulator_.model().linearizer().residual();
convertResults2(ebosResid, ebosJac);
wellModel().addRhs(ebosResid, ebosJac);
return iter_report;
}
@ -392,7 +408,82 @@ namespace Opm {
/// r is the residual.
V solveJacobianSystem() const
{
return linsolver_.computeNewtonIncrement(residual_);
typedef double Scalar;
typedef Dune::FieldVector<Scalar, 3 > VectorBlockType;
typedef Dune::FieldMatrix<Scalar, 3, 3 > MatrixBlockType;
typedef Dune::BCRSMatrix <MatrixBlockType> Mat;
typedef Dune::BlockVector<VectorBlockType> BVector;
typedef Dune::MatrixAdapter<Mat,BVector,BVector> Operator;
auto& ebosJac = ebosSimulator_.model().linearizer().matrix();
auto& ebosResid = ebosSimulator_.model().linearizer().residual();
Operator opA(ebosJac);
const double relax = 0.9;
typedef Dune::SeqILU0<Mat, BVector, BVector> SeqPreconditioner;
SeqPreconditioner precond(opA.getmat(), relax);
std::cout << "hei" << std::endl;
Dune::SeqScalarProduct<BVector> sp;
wellModel().apply(ebosJac, ebosResid);
Dune::BiCGSTABSolver<BVector> linsolve(opA, sp, precond,
0.001,
100,
false);
const int np = numPhases();
const int nc = AutoDiffGrid::numCells(grid_);
// std::cout << "ebosResid" << std::endl;
// for( int p=0; p<np; ++p) {
// for (int cell = 0 ; cell < 1; ++cell) {
// std::cout << ebosResid[cell][p] << std::endl;
// }
// }
std::cout << "hei2" << std::endl;
// Solve system.
Dune::InverseOperatorResult result;
BVector x(ebosJac.M());
x = 0.0;
std::cout << "start" << std::endl;
linsolve.apply(x, ebosResid, result);
std::cout << "end" << std::endl;
const int nw = wellModel().wells().number_of_wells;
BVector xw(nw);
wellModel().recoverVariable(x, xw);
// convert to V;
V dx( (nc + nw) * np);
for( int p=0; p<np; ++p) {
for (int i = 0; i < nc; ++i) {
int idx = i + nc*ebosCompToFlowPhaseIdx(p);
dx(idx) = x[i][p];
}
for (int w = 0; w < nw; ++w) {
int idx = w + nw*p + nc*np;
dx(idx) = xw[w][flowPhaseToEbosCompIdx(p)];
}
}
V dx2 = linsolver_.computeNewtonIncrement(residual_);
std::cout << "------dx------- " << std::endl;
std::cout << dx << std::endl;
std::cout << "------dx2------- " << std::endl;
std::cout << dx2 << std::endl;
//return dx;
return dx;
}
/// Apply an update to the primary variables, chopped if appropriate.
@ -665,35 +756,45 @@ namespace Opm {
std::vector<double> maxNormWell(np);
Eigen::Array<V::Scalar, Eigen::Dynamic, Eigen::Dynamic> B(nc, np);
Eigen::Array<V::Scalar, Eigen::Dynamic, Eigen::Dynamic> R(nc, np);
Eigen::Array<V::Scalar, Eigen::Dynamic, Eigen::Dynamic> R2(nc, np);
Eigen::Array<V::Scalar, Eigen::Dynamic, Eigen::Dynamic> tempV(nc, np);
auto ebosResid = ebosSimulator_.model().linearizer().residual();
for ( int idx = 0; idx < np; ++idx )
{
V b(nc);
V r(nc);
for (int cell_idx = 0; cell_idx < nc; ++cell_idx) {
const auto& intQuants = *(ebosSimulator_.model().cachedIntensiveQuantities(cell_idx, /*timeIdx=*/0));
const auto& fs = intQuants.fluidState();
int ebosPhaseIdx = flowPhaseToEbosPhaseIdx(idx);
int ebosCompIdx = flowPhaseToEbosCompIdx(idx);
b[cell_idx] = 1 / fs.invB(ebosPhaseIdx).value;
r[cell_idx] = ebosResid[cell_idx][ebosCompIdx];
}
R2.col(idx) = r;
B.col(idx) = b;
}
for ( int idx = 0; idx < np; ++idx )
{
//const ADB& tempB = rq_[idx].b;
//B.col(idx) = 1./tempB.value();
R.col(idx) = residual_.material_balance_eq[idx].value();
tempV.col(idx) = R.col(idx).abs()/pv;
std::cout << "------R------- " << idx << std::endl;
std::cout << R.col(idx)[0] << std::endl;
std::cout << "------R2------- " << idx << std::endl;
std::cout << R2.col(idx)[0] << std::endl;
}
std::vector<double> pv_vector (geo_.poreVolume().data(), geo_.poreVolume().data() + geo_.poreVolume().size());
const double pvSum = detail::convergenceReduction(B, tempV, R,
const double pvSum = detail::convergenceReduction(B, tempV, R2,
R_sum, maxCoeff, B_avg, maxNormWell,
nc, np, pv_vector, residual_);
nc, np, pv_vector, wellModel().residual());
std::vector<double> CNV(np);
std::vector<double> mass_balance_residual(np);
@ -1006,13 +1107,11 @@ namespace Opm {
}
public:
/*
int ebosCompToFlowPhaseIdx( const int compIdx ) const
{
const int compToPhase[ 3 ] = { Oil, Water, Gas };
return compToPhase[ compIdx ];
}
*/
int flowToEbosPvIdx( const int flowPv ) const
{
@ -1032,6 +1131,7 @@ namespace Opm {
private:
void convertResults(const Simulator& simulator)
{
@ -1136,6 +1236,52 @@ namespace Opm {
std::move(adbJacs[eqIdx]));
}
}
void convertResults2(BVector& ebosResid, Mat& ebosJac) const
{
const int numPhases = wells().number_of_phases;
const int numCells = ebosJac.N();
const int cols = ebosJac.M();
assert( numCells == cols );
// write the right-hand-side values from the ebosJac into the objects
// allocated above.
const auto endrow = ebosJac.end();
for( int cellIdx = 0; cellIdx < numCells; ++cellIdx )
{
const double cellVolume = ebosSimulator_.model().dofTotalVolume(cellIdx);
auto& cellRes = ebosResid[ cellIdx ];
for( int flowPhaseIdx = 0; flowPhaseIdx < numPhases; ++flowPhaseIdx )
{
const double refDens = FluidSystem::referenceDensity( flowPhaseToEbosPhaseIdx( flowPhaseIdx ), 0 );
cellRes[ flowPhaseToEbosCompIdx( flowPhaseIdx ) ] /= refDens;
cellRes[ flowPhaseToEbosCompIdx( flowPhaseIdx ) ] *= cellVolume;
}
}
for( auto row = ebosJac.begin(); row != endrow; ++row )
{
const int rowIdx = row.index();
const double cellVolume = ebosSimulator_.model().dofTotalVolume(rowIdx);
// translate the Jacobian of the residual from the format used by ebos to
// the one expected by flow
const auto endcol = row->end();
for( auto col = row->begin(); col != endcol; ++col )
{
for( int flowPhaseIdx = 0; flowPhaseIdx < numPhases; ++flowPhaseIdx )
{
const double refDens = FluidSystem::referenceDensity( flowPhaseToEbosPhaseIdx( flowPhaseIdx ), 0 );
for( int pvIdx=0; pvIdx<numPhases; ++pvIdx )
{
(*col)[flowPhaseToEbosCompIdx(flowPhaseIdx)][flowToEbosPvIdx(pvIdx)] /= refDens;
(*col)[flowPhaseToEbosCompIdx(flowPhaseIdx)][flowToEbosPvIdx(pvIdx)] *= cellVolume;
}
}
}
}
}
int flowPhaseToEbosPhaseIdx( const int phaseIdx ) const
{

View File

@ -85,9 +85,16 @@ namespace Opm
for (int eq = 0; eq < num_eq; ++eq) {
jacs[eq].reserve(num_eq - 1);
const std::vector<M>& Je = eqs[eq].derivative();
Sp Bb;
const M& B = Je[n];
B.toSparse(Bb);
//std::cout << "B eigen" << std::endl;
//std::cout << Bb << std::endl;
// Update right hand side.
vals[eq] = eqs[eq].value().matrix() - B * Dibn;
//std::cout << "vals " << eq << std::endl;
//std::cout << vals[eq][0] << std::endl;
}
for (int var = 0; var < num_eq; ++var) {
if (var == n) {
@ -149,6 +156,11 @@ namespace Opm
V equation_value = equation.value();
ADB eq_coll = collapseJacs(ADB::function(std::move(equation_value), std::move(C_jacs)));
const M& C = eq_coll.derivative()[0];
typedef Eigen::SparseMatrix<double> Sp;
Sp Cc;
C.toSparse(Cc);
//std::cout << "C eigen" << std::endl;
//std::cout << Cc <<std::endl;
// Use sparse LU to solve the block submatrices
typedef Eigen::SparseMatrix<double> Sp;

View File

@ -47,9 +47,12 @@
#include <opm/autodiff/WellDensitySegmented.hpp>
#include <opm/autodiff/BlackoilDetails.hpp>
#include <opm/autodiff/BlackoilModelParameters.hpp>
#include <opm/autodiff/NewtonIterationBlackoilInterleaved.cpp>
#include<dune/common/fmatrix.hh>
#include<dune/istl/bcrsmatrix.hh>
#include<dune/istl/matrixmatrix.hh>
#include <opm/material/densead/Math.hpp>
#include <opm/material/densead/Evaluation.hpp>
@ -110,6 +113,11 @@ namespace Opm {
using Vector = ADB::V;
using V = ADB::V;
typedef ADB::M M;
typedef double Scalar;
typedef Dune::FieldVector<Scalar, 3 > VectorBlockType;
typedef Dune::FieldMatrix<Scalar, 3, 3 > MatrixBlockType;
typedef Dune::BCRSMatrix <MatrixBlockType> Mat;
typedef Dune::BlockVector<VectorBlockType> BVector;
// copied from BlackoilModelBase
@ -138,6 +146,10 @@ namespace Opm {
, param_(param)
, terminal_output_(terminal_output)
, pv_(pv)
//, resWell(wells_->number_of_wells)
//, duneD( Mat(2, 2, 3, 0.4, Mat::implicit))
//, duneB( Mat(300, 2, 6, 0.4, Mat::implicit))
//, duneC( Mat(2, 300, 6, 0.4, Mat::implicit))
{
}
@ -163,21 +175,140 @@ namespace Opm {
return iter_report;
}
//wellModel().extractWellPerfProperties(state, rq_, mob_perfcells, b_perfcells);
if (param_.solve_welleq_initially_ && iterationIdx == 0) {
// solve the well equations as a pre-processing step
iter_report = solveWellEq(ebosSimulator, dt, well_state);
}
std::vector<ADB> cq_s;
computeWellFluxDense(ebosSimulator, cq_s, 4);
int nw = wells_->number_of_wells;
int nc = numCells();
Mat duneD (nw, nw, 9, 0.4, Mat::implicit);
Mat duneB (nc, nw, 9, 0.4, Mat::implicit);
Mat duneC (nw, nc, 9, 0.4, Mat::implicit);
Mat duneA (nc, nc, 9, 0.4, Mat::implicit);
BVector rhs(nc);
computeWellFluxDense(ebosSimulator, cq_s, 4, duneA, duneB, duneC, duneD, rhs);
//std::cout << cq_s[0] << std::endl;
//std::cout << cq_s[1] << std::endl;
//std::cout << cq_s[2] << std::endl;
updatePerfPhaseRatesAndPressures(cq_s, well_state);
addWellFluxEq(cq_s, dt, 4, residual);
addWellContributionToMassBalanceEq(cq_s, residual);
addWellContributionToMassBalanceEq(cq_s,residual);
addWellFluxEq(cq_s, dt, 4, residual, duneD);
//std::cout << residual.well_flux_eq << std::endl;
duneA.compress();
duneB.compress();
duneC.compress();
duneD.compress();
//std::cout << "B" << std::endl;
//print(duneB);
//std::cout << "C" << std::endl;
//print(duneC);
//print(duneD);
V resWellEigen = residual.well_flux_eq.value();
const int np = numPhases();
BVector resWell(nw);
for (int i = 0; i < nw; ++i){
for( int p = 0; p < np; ++p ) {
int idx = i + p * nw;
resWell[i][flowPhaseToEbosCompIdx(p)] = resWellEigen(idx);
}
}
resWell_ = resWell;
rhs_ = rhs;
duneB_ = duneB;
duneC_ = duneC;
localInvert(duneD);
invDuneD_ = duneD;
duneA_ = duneA;
if (param_.compute_well_potentials_) {
//wellModel().computeWellPotentials(mob_perfcells, b_perfcells, state0, well_state);
}
return iter_report;
}
void localInvert(Mat& istlA) const {
for (auto row = istlA.begin(), rowend = istlA.end(); row != rowend; ++row ) {
for (auto col = row->begin(), colend = row->end(); col != colend; ++col ) {
//std::cout << (*col) << std::endl;
(*col).invert();
}
}
}
void print(Mat& istlA) const {
for (auto row = istlA.begin(), rowend = istlA.end(); row != rowend; ++row ) {
for (auto col = row->begin(), colend = row->end(); col != colend; ++col ) {
std::cout << (*col) << std::endl;
}
}
}
void addRhs(BVector& x, Mat& jac) const {
assert(x.size() == rhs.size());
x += rhs_;
jac += duneA_;
}
void apply( Mat& A,
BVector& res) const {
Mat BmultinvD;
Mat duneA;
Dune::matMultMat(BmultinvD, duneB_ , invDuneD_);
Dune::matMultMat(duneA, BmultinvD, duneC_);
A -= duneA;
BmultinvD.mmv(resWell_, res);
}
void recoverVariable(const BVector& x, BVector& xw) const {
BVector resWell = resWell_;
duneC_.mmv(x, resWell);
invDuneD_.mv(resWell, xw);
}
void addDuneMatrix(Eigen::SparseMatrix<double, Eigen::RowMajor> eigen, Mat& dune, int p1, int p2) {
//Mat dune( eigen.rows(), eigen.cols(), eigen.nonZeros(), 0.4,Mat::implicit) ;
const int* ia = eigen.outerIndexPtr();
const int* ja = eigen.innerIndexPtr();
for (int row = 0; row < eigen.rows(); ++row) {
dune.entry(ia[row],ja[row])[p1][p2] = eigen.coeff(ia[row] ,ja[row]);
}
}
int flowPhaseToEbosCompIdx( const int phaseIdx ) const
{
const int phaseToComp[ 3 ] = { FluidSystem::waterCompIdx, FluidSystem::oilCompIdx, FluidSystem::gasCompIdx };
return phaseToComp[ phaseIdx ];
}
int flowToEbosPvIdx( const int flowPv ) const
{
const int flowToEbos[ 3 ] = {
BlackoilIndices::pressureSwitchIdx,
BlackoilIndices::waterSaturationIdx,
BlackoilIndices::compositionSwitchIdx
};
return flowToEbos[ flowPv ];
}
int ebosCompToFlowPhaseIdx( const int compIdx ) const
{
const int compToPhase[ 3 ] = { Oil, Water, Gas };
return compToPhase[ compIdx ];
}
@ -193,7 +324,7 @@ namespace Opm {
phase_condition_ = pc_arg;
vfp_properties_ = vfp_properties_arg;
gravity_ = gravity_arg;
perf_cell_depth_ = subset(depth_arg, wellOps().well_cells);
perf_cell_depth_ = subset(depth_arg, wellOps().well_cells);
}
const WellOps& wellOps() const
@ -429,14 +560,9 @@ namespace Opm {
addWellFluxEq(std::vector<ADB> cq_s,
const double dt,
const int numBlocks,
LinearisedBlackoilResidual& residual)
LinearisedBlackoilResidual& residual,
Mat& duneD)
{
if( !localWellsActive() )
{
// If there are no wells in the subdomain of the proces then
// cq_s has zero size and will cause a segmentation fault below.
return;
}
const int np = wells().number_of_phases;
const int nw = wells().number_of_wells;
@ -458,13 +584,14 @@ namespace Opm {
// res -= cq_s[perf*np + p];
//}
res_vec[w] = res;
for (int i = 0; i < np; ++i) {
duneD.entry(w,w)[flowPhaseToEbosCompIdx(p)][flowToEbosPvIdx(i)] += res.derivatives[i+3];
}
}
ADB tmp = convertToADBWell(res_vec, numBlocks);
qs += superset(tmp,Span(nw,1,p*nw), nw*np);
}
//std::cout << residual_.well_flux_eq << std::endl;
//wellModel().convertToADB(res_vec, well_cells, nc, well_id, nw, numBlocks);
//ADB qs = state.qs;
@ -474,7 +601,6 @@ namespace Opm {
}
residual.well_flux_eq = qs;
//std::cout << "etter Ebos" << residual_.well_flux_eq << std::endl;
}
@ -521,7 +647,12 @@ namespace Opm {
void
computeWellFluxDense(const Simulator& ebosSimulator,
std::vector<ADB>& cq_s,
const int numBlocks) const
const int numBlocks,
Mat& duneA,
Mat& duneB,
Mat& duneC,
Mat& duneD,
BVector& rhs) const
{
if( ! localWellsActive() ) return ;
const int np = wells().number_of_phases;
@ -668,10 +799,22 @@ namespace Opm {
EvalWell cqt_is = cqt_i/volumeRatio;
//std::cout << "volrat " << volumeRatio << " " << volrat_perf_[perf] << std::endl;
for (int phase = 0; phase < np; ++phase) {
cq_s_dense[phase][perf] = cmix_s[phase] * cqt_is; // * b_perfcells_dense[phase];
cq_s_dense[phase][perf] = cmix_s[phase] * cqt_is; // * b_perfcells_dense[phase];
}
}
for (int p1 = 0; p1 < np; ++p1) {
EvalWell tmp = cq_s_dense[p1][perf];
for (int p2 = 0; p2 < np; ++p2) {
duneC.entry(w, cell_idx)[flowPhaseToEbosCompIdx(p1)][flowToEbosPvIdx(p2)] -= tmp.derivatives[p2];
duneB.entry(cell_idx, w)[flowPhaseToEbosCompIdx(p1)][flowToEbosPvIdx(p2)] -= tmp.derivatives[p2+3];
duneA.entry(cell_idx, cell_idx)[flowPhaseToEbosCompIdx(p1)][flowToEbosPvIdx(p2)] -= tmp.derivatives[p2];
duneD.entry(w, w)[flowPhaseToEbosCompIdx(p1)][flowToEbosPvIdx(p2)] -= tmp.derivatives[p2+3];
}
rhs[cell_idx][flowPhaseToEbosCompIdx(p1)] -= tmp.value;
}
}
}
cq_s.resize(np, ADB::null());
for (int phase = 0; phase < np; ++phase) {
@ -700,10 +843,31 @@ namespace Opm {
bool converged;
do {
// bhp and Q for the wells
computeWellFluxDense(ebosSimulator, cq_s, 1);
int nw = wells().number_of_wells;
int nc = numCells();
Mat duneDlo( nw, nw, 9, 0.4,Mat::implicit);
Mat duneBlo( nc, nw, 9, 0.4, Mat::implicit);
Mat duneClo( nw, nc, 9, 0.4, Mat::implicit);
Mat duneAlo( nc, nc, 9, 0.4, Mat::implicit);
BVector rhslo(nc);
computeWellFluxDense(ebosSimulator, cq_s, 1, duneAlo, duneBlo, duneClo, duneDlo, rhslo);
updatePerfPhaseRatesAndPressures(cq_s, well_state);
addWellFluxEq(cq_s, dt, 1, residual);
converged = getWellConvergence(ebosSimulator, it, residual);
addWellFluxEq(cq_s, dt, 1, residual, duneDlo);
V resWellEigen = residual.well_flux_eq.value();
//std::cout << "resWellEigen " << resWellEigen << std::endl;
BVector resWell(nw);
for (int i = 0; i < nw; ++i){
for( int p = 0; p < np; ++p ) {
int idx = i + p * nw;
resWell[i][flowPhaseToEbosCompIdx(p)] = resWellEigen(idx);
}
}
duneDlo.compress();
//print(duneDlo);
localInvert(duneDlo);
resWell_ = resWell;
converged = getWellConvergence(ebosSimulator, it);
if (converged) {
break;
@ -712,20 +876,46 @@ namespace Opm {
++it;
if( localWellsActive() )
{
std::vector<ADB> eqs;
eqs.reserve(1);
eqs.push_back(residual.well_flux_eq);
//eqs.push_back(residual_.well_eq);
ADB total_residual = vertcatCollapseJacs(eqs);
const std::vector<M>& Jn = total_residual.derivative();
typedef Eigen::SparseMatrix<double> Sp;
Sp Jn0;
Jn[0].toSparse(Jn0);
const Eigen::SparseLU< Sp > solver(Jn0);
ADB::V total_residual_v = total_residual.value();
const Eigen::VectorXd& dx = solver.solve(total_residual_v.matrix());
// std::vector<ADB> eqs;
// eqs.reserve(1);
// eqs.push_back(residual.well_flux_eq);
// //eqs.push_back(residual_.well_eq);
// ADB total_residual = vertcatCollapseJacs(eqs);
// const std::vector<M>& Jn = total_residual.derivative();
// typedef Eigen::SparseMatrix<double> Sp;
// Sp Jn0;
// Jn[0].toSparse(Jn0);
// std::cout << Jn0 << std::endl;
// const Eigen::SparseLU< Sp > solver(Jn0);
// ADB::V total_residual_v = total_residual.value();
// std::cout << "tot res " <<total_residual_v << std::endl;
// const Eigen::VectorXd& dx = solver.solve(total_residual_v.matrix());
BVector dx_new (nw);
duneDlo.mv(resWell_, dx_new);
// std::cout << "hei" << std::endl;
// Sp eye(nw*np,nw*np);
// eye.setIdentity();
// Sp invD = solver.solve(eye);
// std::cout << invD << std::endl;
// print(duneDlo);
V dx_new_eigen(np*nw);
for( int p=0; p<np; ++p) {
for (int w = 0; w < nw; ++w) {
int idx = w + nw*p;
dx_new_eigen(idx) = dx_new[w][flowPhaseToEbosCompIdx(p)];
}
}
// std::cout << "new " <<dx_new_eigen << std::endl;
// std::cout << "old " <<dx << std::endl;
assert(dx.size() == total_residual_v.size());
updateWellState(dx.array(), well_state);
updateWellState(dx_new_eigen.array(), well_state);
updateWellControls(well_state);
setWellVariables(well_state);
}
@ -740,11 +930,24 @@ namespace Opm {
return IterationReport{failed, converged, linear_iters, it};
}
std::vector<double> residual() {
const int np = numPhases();
const int nw = wells().number_of_wells;
std::vector<double> res(np*nw);
for( int p=0; p<np; ++p) {
for (int i = 0; i < nw; ++i) {
int idx = i + nw*p;
res[idx] = resWell_[i][flowPhaseToEbosCompIdx(p)];
}
}
return res;
}
template <typename Simulator>
bool getWellConvergence(Simulator& ebosSimulator,
const int iteration,
const LinearisedBlackoilResidual& residual)
const int iteration)
{
const int np = numPhases();
const int nc = numCells();
@ -773,7 +976,7 @@ namespace Opm {
B.col(idx) = b;
}
detail::convergenceReduction(B, tempV, R, R_sum, maxCoeff, B_avg, maxNormWell, nc, np, pv_, residual);
detail::convergenceReduction(B, tempV, R, R_sum, maxCoeff, B_avg, maxNormWell, nc, np, pv_, residual());
std::vector<double> well_flux_residual(np);
bool converged_Well = true;
@ -1533,16 +1736,6 @@ namespace Opm {
return flowToEbos[ phaseIdx ];
}
int flowToEbosPvIdx( const int flowPv ) const
{
const int flowToEbos[ 3 ] = {
BlackoilIndices::pressureSwitchIdx,
BlackoilIndices::waterSaturationIdx,
BlackoilIndices::compositionSwitchIdx
};
return flowToEbos[ flowPv ];
}
/// upate the dynamic lists related to economic limits
template<class WellState>
void
@ -1698,6 +1891,12 @@ namespace Opm {
std::vector<EvalWell> wellVariables_;
std::vector<double> F0_;
const std::vector<double>& pv_;
Mat duneA_;
Mat duneB_;
Mat duneC_;
Mat invDuneD_;
BVector resWell_;
BVector rhs_;
// protected methods
EvalWell getBhp(const int wellIdx) const {