From b50fb730edf2cb51990191656005a00b1c79bd8e Mon Sep 17 00:00:00 2001 From: hnil Date: Wed, 29 Apr 2020 12:55:04 +0200 Subject: [PATCH 01/93] inital blackoil version where classes intended to change for sequential will be replaced by inheretence --- CMakeLists.txt | 19 +++- flow/flow_blackoil_dunecpr_noflex.cpp | 98 +++++++++++++++++++ flow/flow_blackoil_dunecpr_seq.cpp | 132 ++++++++++++++++++++++++++ 3 files changed, 248 insertions(+), 1 deletion(-) create mode 100644 flow/flow_blackoil_dunecpr_noflex.cpp create mode 100644 flow/flow_blackoil_dunecpr_seq.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a7993d86c04..47f32ada710 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,7 +89,7 @@ include ("${project}-prereqs") # our way of specifying cuda source files never worked for CMake # version < 3.8. Hence we deactivate cuda for these versions. # We use "CMAKE_VERSION VERSION_GREATER 3.7.9" instead of -# CMAKE_VERSION VERSION_GREATER_EQUAL 3.8, because of backwards +# CMAKE_VERSION VERSION_GREATER_EQUAL 3.8, because of backwarsd # compatibility to cmake 3.6 and lower. if(NOT CMAKE_DISABLE_FIND_PACKAGE_CUDA AND CMAKE_VERSION VERSION_GREATER 3.7.9) @@ -283,6 +283,23 @@ opm_add_test(flow_blackoil_dunecpr DEPENDS opmsimulators LIBRARIES opmsimulators) +opm_add_test(flow_blackoil_dunecpr_noflex + ONLY_COMPILE + DEFAULT_ENABLE_IF ${FLOW_VARIANTS_DEFAULT_ENABLE_IF} + SOURCES flow/flow_blackoil_dunecpr_noflex.cpp + EXE_NAME flow_blackoil_dunecpr_noflex + DEPENDS "opmsimulators" + LIBRARIES "opmsimulators") + +opm_add_test(flow_blackoil_dunecpr_seq + ONLY_COMPILE + DEFAULT_ENABLE_IF ${FLOW_VARIANTS_DEFAULT_ENABLE_IF} + SOURCES flow/flow_blackoil_dunecpr_seq.cpp + EXE_NAME flow_blackoil_dunecpr_seq + DEPENDS "opmsimulators" + LIBRARIES "opmsimulators") + + opm_add_test(flow_onephase ONLY_COMPILE DEFAULT_ENABLE_IF ${FLOW_VARIANTS_DEFAULT_ENABLE_IF} diff --git a/flow/flow_blackoil_dunecpr_noflex.cpp b/flow/flow_blackoil_dunecpr_noflex.cpp new file mode 100644 index 00000000000..2c42b65ac94 --- /dev/null +++ b/flow/flow_blackoil_dunecpr_noflex.cpp @@ -0,0 +1,98 @@ +/* + Copyright 2013, 2014, 2015, 2019 SINTEF Digital, Mathematics and Cybernetics. + Copyright 2014 Dr. Blatt - HPC-Simulation-Software & Services + Copyright 2015, 2017 IRIS AS + + This file is part of the Open Porous Media project (OPM). + + OPM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OPM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with OPM. If not, see . +*/ +#include "config.h" + +#include +#include + + +BEGIN_PROPERTIES +NEW_TYPE_TAG(EclFlowProblemSimple, INHERITS_FROM(EclFlowProblem)); +NEW_PROP_TAG(FluidState); +//SET_TYPE_PROP(EclBaseProblem, Problem, Opm::EclProblem); +SET_PROP(EclFlowProblemSimple, FluidState) + { + private: + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + enum { enableTemperature = GET_PROP_VALUE(TypeTag, EnableTemperature) }; + enum { enableSolvent = GET_PROP_VALUE(TypeTag, EnableSolvent) }; + enum { enableEnergy = GET_PROP_VALUE(TypeTag, EnableEnergy) }; + enum { numPhases = GET_PROP_VALUE(TypeTag, NumPhases) }; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, Evaluation) Evaluation; + static const bool compositionSwitchEnabled = Indices::gasEnabled; + + public: +//typedef Opm::BlackOilFluidSystemSimple type; + typedef Opm::BlackOilFluidState type; +}; + +SET_BOOL_PROP(EclFlowProblemSimple, MatrixAddWellContributions, true); +SET_INT_PROP(EclFlowProblemSimple, LinearSolverVerbosity,0); +SET_SCALAR_PROP(EclFlowProblemSimple, LinearSolverReduction, 1e-2); +SET_INT_PROP(EclFlowProblemSimple, LinearSolverMaxIter, 100); +SET_BOOL_PROP(EclFlowProblemSimple, UseAmg, true);//probably not used +SET_BOOL_PROP(EclFlowProblemSimple, UseCpr, true); +SET_INT_PROP(EclFlowProblemSimple, CprMaxEllIter, 1); +SET_INT_PROP(EclFlowProblemSimple, CprEllSolvetype, 3); +SET_INT_PROP(EclFlowProblemSimple, CprReuseSetup, 3); +SET_INT_PROP(EclFlowProblemSimple, CprSolverVerbose, 0); +SET_STRING_PROP(EclFlowProblemSimple, LinearSolverConfiguration, "ilu0"); +SET_STRING_PROP(EclFlowProblemSimple, SystemStrategy, "quasiimpes"); +END_PROPERTIES + +namespace Opm { + namespace Properties { + + SET_PROP(EclFlowProblemSimple, FluidSystem) + { + private: + //typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, Evaluation) Evaluation; + + public: + typedef Opm::BlackOilFluidSystem type; + }; + //NEW_TYPE_TAG(EclFlowProblem, INHERITS_FROM(BlackOilModel, EclBaseProblem)); + SET_TYPE_PROP(EclFlowProblemSimple, IntensiveQuantities, Opm::BlackOilIntensiveQuantities); + //SET_TYPE_PROP(EclFlowProblemSimple, LinearSolverBackend, Opm::ISTLSolverEbos); + //SET_TAG_PROP(EclFlowProblemSimple, LinearSolverSplice, ParallelBiCGStabLinearSolver); + //SET_TYPE_PROP(EclFlowProblemSimple, LinearSolverBackend, Opm::Linear::ParallelBiCGStabSolverBackend);//not work + //SET_TYPE_PROP(EclFlowProblemSimple, LinearSolverBackend, Opm::Linear::SuperLUBackend)//not work + //SET_TAG_PROP(EclFlowProblem, FluidState, Opm::BlackOilFluidState); + SET_TYPE_PROP(EclFlowProblemSimple, LinearSolverBackend, Opm::ISTLSolverEbos); + SET_BOOL_PROP(EclFlowProblemSimple, EnableStorageCache, true); + SET_BOOL_PROP(EclFlowProblemSimple, EnableIntensiveQuantityCache, true); + + //SET_INT_PROP(EclFlowProblemSimple, NumWellAdjoint, 1); + //SET_BOOL_PROP(EclFlowProblem, EnableStorageCache, true); + //SET_BOOL_PROP(EclFlowProblem, EnableIntensiveQuantityCache, true); + } +} + +int main(int argc, char** argv) +{ + using TypeTag = TTAG(EclFlowProblemSimple); + auto mainObject = Opm::Main(argc, argv); + return mainObject.runStatic(); +} diff --git a/flow/flow_blackoil_dunecpr_seq.cpp b/flow/flow_blackoil_dunecpr_seq.cpp new file mode 100644 index 00000000000..94c6ed4bd46 --- /dev/null +++ b/flow/flow_blackoil_dunecpr_seq.cpp @@ -0,0 +1,132 @@ +/* + Copyright 2013, 2014, 2015, 2019 SINTEF Digital, Mathematics and Cybernetics. + Copyright 2014 Dr. Blatt - HPC-Simulation-Software & Services + Copyright 2015, 2017 IRIS AS + + This file is part of the Open Porous Media project (OPM). + + OPM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OPM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with OPM. If not, see . +*/ +#include "config.h" + +#include +#include + +BEGIN_PROPERTIES +NEW_TYPE_TAG(EclFlowProblemSimple, INHERITS_FROM(EclFlowProblem)); +NEW_PROP_TAG(FluidState); +//SET_TYPE_PROP(EclBaseProblem, Problem, Opm::EclProblem); +SET_PROP(EclFlowProblemSimple, FluidState) + { + private: + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + enum { enableTemperature = GET_PROP_VALUE(TypeTag, EnableTemperature) }; + enum { enableSolvent = GET_PROP_VALUE(TypeTag, EnableSolvent) }; + enum { enableEnergy = GET_PROP_VALUE(TypeTag, EnableEnergy) }; + enum { numPhases = GET_PROP_VALUE(TypeTag, NumPhases) }; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, Evaluation) Evaluation; + static const bool compositionSwitchEnabled = Indices::gasEnabled; + + public: +//typedef Opm::BlackOilFluidSystemSimple type; + typedef Opm::BlackOilFluidState type; +}; + +SET_BOOL_PROP(EclFlowProblemSimple, MatrixAddWellContributions, true); +SET_INT_PROP(EclFlowProblemSimple, LinearSolverVerbosity,0); +SET_SCALAR_PROP(EclFlowProblemSimple, LinearSolverReduction, 1e-2); +SET_INT_PROP(EclFlowProblemSimple, LinearSolverMaxIter, 100); +SET_BOOL_PROP(EclFlowProblemSimple, UseAmg, true);//probably not used +SET_BOOL_PROP(EclFlowProblemSimple, UseCpr, true); +SET_INT_PROP(EclFlowProblemSimple, CprMaxEllIter, 1); +SET_INT_PROP(EclFlowProblemSimple, CprEllSolvetype, 3); +SET_INT_PROP(EclFlowProblemSimple, CprReuseSetup, 3); +SET_INT_PROP(EclFlowProblemSimple, CprSolverVerbose, 0); +SET_STRING_PROP(EclFlowProblemSimple, LinearSolverConfiguration, "ilu0"); +//SET_STRING_PROP(EclFlowProblemSimple, LinearSolverConfiguration, "file"); +SET_STRING_PROP(EclFlowProblemSimple, SystemStrategy, "quasiimpes"); +END_PROPERTIES + +namespace Opm { + template + class EclTransExtensiveQuantitiesSeq : public EclTransExtensiveQuantities + {}; + + // template + // BlackOilIntensiveQuantitiesSeq : public BlackOilIntensiveQuantities + // {}; + + // template + // BlackOilPrimaryVariablesSeq : public BlackOilPrimaryVariables + // {}; + +template +struct EclTransFluxModuleSeq +{ + typedef EclTransIntensiveQuantities FluxIntensiveQuantities; + typedef EclTransExtensiveQuantitiesSeq FluxExtensiveQuantities; + typedef EclTransBaseProblem FluxBaseProblem; + + /*! + * \brief Register all run-time parameters for the flux module. + */ + static void registerParameters() + { } +}; +} + + +namespace Opm { + namespace Properties { + + SET_PROP(EclFlowProblemSimple, FluidSystem) + { + private: + //typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, Evaluation) Evaluation; + + public: + typedef Opm::BlackOilFluidSystem type; + }; + //NEW_TYPE_TAG(EclFlowProblem, INHERITS_FROM(BlackOilModel, EclBaseProblem)); + // template + // BlackOilIntensiveQuantitiesSeq : public BlackOilIntensiveQuantities + // {}; + SET_TYPE_PROP(EclFlowProblemSimple, PrimaryVariables, Opm::BlackOilPrimaryVariables); + SET_TYPE_PROP(EclFlowProblemSimple, IntensiveQuantities, Opm::BlackOilIntensiveQuantities); + SET_TYPE_PROP(EclFlowProblemSimple, FluxModule, Opm::EclTransFluxModuleSeq); + //SET_TYPE_PROP(EclFlowProblemSimple, LinearSolverBackend, Opm::ISTLSolverEbos); + //SET_TAG_PROP(EclFlowProblemSimple, LinearSolverSplice, ParallelBiCGStabLinearSolver); + //SET_TYPE_PROP(EclFlowProblemSimple, LinearSolverBackend, Opm::Linear::ParallelBiCGStabSolverBackend);//not work + //SET_TYPE_PROP(EclFlowProblemSimple, LinearSolverBackend, Opm::Linear::SuperLUBackend)//not work + //SET_TAG_PROP(EclFlowProblem, FluidState, Opm::BlackOilFluidState); + SET_TYPE_PROP(EclFlowProblemSimple, LinearSolverBackend, Opm::ISTLSolverEbosFlexible); + SET_BOOL_PROP(EclFlowProblemSimple, EnableStorageCache, true); + SET_BOOL_PROP(EclFlowProblemSimple, EnableIntensiveQuantityCache, true); + + //SET_INT_PROP(EclFlowProblemSimple, NumWellAdjoint, 1); + //SET_BOOL_PROP(EclFlowProblem, EnableStorageCache, true); + //SET_BOOL_PROP(EclFlowProblem, EnableIntensiveQuantityCache, true); + } +} + +int main(int argc, char** argv) +{ + using TypeTag = TTAG(EclFlowProblemSimple); + auto mainObject = Opm::Main(argc, argv); + return mainObject.runStatic(); +} From 9f15a192a161a9fd4a21f43e5fefac9975d8fdfb Mon Sep 17 00:00:00 2001 From: hnil Date: Fri, 5 Jun 2020 11:11:26 +0200 Subject: [PATCH 02/93] Introduced linearization type --- opm/simulators/flow/BlackoilModelEbos.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/opm/simulators/flow/BlackoilModelEbos.hpp b/opm/simulators/flow/BlackoilModelEbos.hpp index f58751ee120..4e992741d2e 100644 --- a/opm/simulators/flow/BlackoilModelEbos.hpp +++ b/opm/simulators/flow/BlackoilModelEbos.hpp @@ -372,7 +372,8 @@ namespace Opm { // -------- Mass balance equations -------- ebosSimulator_.model().newtonMethod().setIterationIndex(iterationIdx); ebosSimulator_.problem().beginIteration(); - ebosSimulator_.model().linearizer().linearizeDomain(); + //use default linearization + ebosSimulator_.model().linearizer().linearizeDomain(/*LinearizationType*/ LinearizationType()); ebosSimulator_.problem().endIteration(); return wellModel().lastReport(); From 847fce0e9fa27971787b36debea2ebde1aca7853 Mon Sep 17 00:00:00 2001 From: hnil Date: Fri, 5 Jun 2020 22:54:05 +0200 Subject: [PATCH 03/93] Draft of sequential --- opm/simulators/flow/BlackoilModelEbos.hpp | 57 +++++++++++++------ opm/simulators/flow/NonlinearSolverEbos.hpp | 21 ++++++- .../timestepping/AdaptiveTimeSteppingEbos.hpp | 2 +- 3 files changed, 59 insertions(+), 21 deletions(-) diff --git a/opm/simulators/flow/BlackoilModelEbos.hpp b/opm/simulators/flow/BlackoilModelEbos.hpp index 4e992741d2e..18389ec16c7 100644 --- a/opm/simulators/flow/BlackoilModelEbos.hpp +++ b/opm/simulators/flow/BlackoilModelEbos.hpp @@ -339,6 +339,7 @@ namespace Opm { // Apply the update, with considering model-dependent limitations and // chopping of the update. + // NB !! should be set model().linearizer().constraintsMap(); updateSolution(x); report.update_time += perfTimer.stop(); @@ -373,7 +374,7 @@ namespace Opm { ebosSimulator_.model().newtonMethod().setIterationIndex(iterationIdx); ebosSimulator_.problem().beginIteration(); //use default linearization - ebosSimulator_.model().linearizer().linearizeDomain(/*LinearizationType*/ LinearizationType()); + ebosSimulator_.model().linearizer().linearizeDomain(); ebosSimulator_.problem().endIteration(); return wellModel().lastReport(); @@ -474,25 +475,45 @@ namespace Opm { /// r is the residual. void solveJacobianSystem(BVector& x) { + if(ebosSimulator_.model().linearizer().getLinearizationType().type == Opm::LinearizationType::pressure){ + OPM_THROW(Opm::NumericalIssue, "Not implemented!"); + /* + auto& ebosJac = ebosSimulator_.model().linearizer().jacobian(); + auto& ebosResid = ebosSimulator_.model().linearizer().residual(); + + // set initial guess + x = 0.0; + auto& ebosSolver = ebosSimulator_.model().newtonMethod().linearSolver(); + PressureMatrixType mat; + auto weights = ebosSolver.getTrueImpesWeights(); + auto pmat = makePressureMatrix(weights,matrix) + auto prhs = makePressureRhs(weights,matrix) + FlexibleSolver pSolver(matrix); + psolver.apply(prhs,dp); + for(size_t i=0; i < x.size(); ++i){ + x[i][pinx]=dp[i]; + } + */ + }else{ + auto& ebosJac = ebosSimulator_.model().linearizer().jacobian(); + auto& ebosResid = ebosSimulator_.model().linearizer().residual(); - auto& ebosJac = ebosSimulator_.model().linearizer().jacobian(); - auto& ebosResid = ebosSimulator_.model().linearizer().residual(); - - // set initial guess - x = 0.0; + // set initial guess + x = 0.0; - auto& ebosSolver = ebosSimulator_.model().newtonMethod().linearSolver(); - Dune::Timer perfTimer; - perfTimer.start(); - ebosSolver.prepare(ebosJac, ebosResid); - linear_solve_setup_time_ = perfTimer.stop(); - ebosSolver.setResidual(ebosResid); - // actually, the error needs to be calculated after setResidual in order to - // account for parallelization properly. since the residual of ECFV - // discretizations does not need to be synchronized across processes to be - // consistent, this is not relevant for OPM-flow... - ebosSolver.setMatrix(ebosJac); - ebosSolver.solve(x); + auto& ebosSolver = ebosSimulator_.model().newtonMethod().linearSolver(); + Dune::Timer perfTimer; + perfTimer.start(); + ebosSolver.prepare(ebosJac, ebosResid); + linear_solve_setup_time_ = perfTimer.stop(); + ebosSolver.setResidual(ebosResid); + // actually, the error needs to be calculated after setResidual in order to + // account for parallelization properly. since the residual of ECFV + // discretizations does not need to be synchronized across processes to be + // consistent, this is not relevant for OPM-flow... + ebosSolver.setMatrix(ebosJac); + ebosSolver.solve(x); + } } diff --git a/opm/simulators/flow/NonlinearSolverEbos.hpp b/opm/simulators/flow/NonlinearSolverEbos.hpp index d4fc5736ff3..e51a82af70d 100644 --- a/opm/simulators/flow/NonlinearSolverEbos.hpp +++ b/opm/simulators/flow/NonlinearSolverEbos.hpp @@ -26,7 +26,7 @@ #include #include #include - +#include #include #include @@ -147,8 +147,25 @@ namespace Opm { } } + SimulatorReportSingle stepSequential(const SimulatorTimerInterface& timer){ + LinearizationType linearizationType; + linearizationType.type = Opm::LinearizationType::pressure; + model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); + this->stepDefault(timer); + linearizationType.type = Opm::LinearizationType::seqtransport; + model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); + this->stepDefault(timer); + } + + SimulatorReportSingle stepFull(const SimulatorTimerInterface& timer){ + LinearizationType linearizationType;// use default + model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); + this->stepDefault(timer); + } + - SimulatorReportSingle step(const SimulatorTimerInterface& timer) + + SimulatorReportSingle stepDefault(const SimulatorTimerInterface& timer) { SimulatorReportSingle report; report.global_time = timer.simulationTimeElapsed(); diff --git a/opm/simulators/timestepping/AdaptiveTimeSteppingEbos.hpp b/opm/simulators/timestepping/AdaptiveTimeSteppingEbos.hpp index 4e9e5b9cec8..a6f88b53674 100644 --- a/opm/simulators/timestepping/AdaptiveTimeSteppingEbos.hpp +++ b/opm/simulators/timestepping/AdaptiveTimeSteppingEbos.hpp @@ -239,7 +239,7 @@ namespace Opm { SimulatorReportSingle substepReport; std::string causeOfFailure = ""; try { - substepReport = solver.step(substepTimer); + substepReport = solver.stepFull(substepTimer); if (solverVerbose_) { // report number of linear iterations OpmLog::debug("Overall linear iterations used: " + std::to_string(substepReport.total_linear_iterations)); From 9d6e023dcf77d1666b282cb3abd71a2cb9514c05 Mon Sep 17 00:00:00 2001 From: hnil Date: Sat, 6 Jun 2020 22:17:30 +0200 Subject: [PATCH 04/93] Draft of pressure update for sequential --- opm/simulators/flow/BlackoilModelEbos.hpp | 43 +++++++++++++++-------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/opm/simulators/flow/BlackoilModelEbos.hpp b/opm/simulators/flow/BlackoilModelEbos.hpp index 18389ec16c7..e44d5be2c18 100644 --- a/opm/simulators/flow/BlackoilModelEbos.hpp +++ b/opm/simulators/flow/BlackoilModelEbos.hpp @@ -476,24 +476,37 @@ namespace Opm { void solveJacobianSystem(BVector& x) { if(ebosSimulator_.model().linearizer().getLinearizationType().type == Opm::LinearizationType::pressure){ - OPM_THROW(Opm::NumericalIssue, "Not implemented!"); - /* + OPM_THROW(Opm::NumericalIssue, "Not implemented!"); auto& ebosJac = ebosSimulator_.model().linearizer().jacobian(); auto& ebosResid = ebosSimulator_.model().linearizer().residual(); - + // NB when tested the linear solver an the martrix could be part of linearizer + using PressureMatrixType = Dune::BCRSMatrix< Dune::FieldMatrix>; + using PressureVectorType = Dune::BlockVector>; + int pressureVarIndex=1; + // true impes case could add case with trivial weighs i equations is modifind with weights + // this would make a newton based method if derivative of the weights are takein into account + PressureVectorType weights(x.size()); + ElementContext elemCtx(ebosSimulator_); + Opm::Amg::getTrueImpesWeights(pressureVarIndex, + weights, + ebsSimulator_.vanguard().gridView(), + elemCtx, simulator_.model(), + ThreadManager::threadId()); + PresssureMatrixType pmatrix = + PressureHelper::makePressureMatrix( + ebosJac, + weights, + pressureVarIndex); + PressureVectorType rhs(ebosResid.size(),0); + PressureHelper::moveToPressure(ebosResid,rhs); + boost::property_tree::ptree prm; + boost::property_tree::read_json("pressuresolver.json", prm); + Dune::FlexibleSolver pressureSolver(pmatrix,prm); + PressureVectorType xp(x.size(),0); + pressureSolver.apply(rhs, xp); + x=0; + PressureHelper::moveToBlock(xp, x, pressureVarIndex); // set initial guess - x = 0.0; - auto& ebosSolver = ebosSimulator_.model().newtonMethod().linearSolver(); - PressureMatrixType mat; - auto weights = ebosSolver.getTrueImpesWeights(); - auto pmat = makePressureMatrix(weights,matrix) - auto prhs = makePressureRhs(weights,matrix) - FlexibleSolver pSolver(matrix); - psolver.apply(prhs,dp); - for(size_t i=0; i < x.size(); ++i){ - x[i][pinx]=dp[i]; - } - */ }else{ auto& ebosJac = ebosSimulator_.model().linearizer().jacobian(); auto& ebosResid = ebosSimulator_.model().linearizer().residual(); From 45b9f838cb3084ca214d197c471a32132907d767 Mon Sep 17 00:00:00 2001 From: hnil Date: Sat, 6 Jun 2020 23:26:30 +0200 Subject: [PATCH 05/93] pressure draft almost ok --- opm/simulators/flow/BlackoilModelEbos.hpp | 32 ++++--- opm/simulators/flow/PressureMatrixHelper.hpp | 94 ++++++++++++++++++++ 2 files changed, 113 insertions(+), 13 deletions(-) create mode 100644 opm/simulators/flow/PressureMatrixHelper.hpp diff --git a/opm/simulators/flow/BlackoilModelEbos.hpp b/opm/simulators/flow/BlackoilModelEbos.hpp index e44d5be2c18..c568f2cdd01 100644 --- a/opm/simulators/flow/BlackoilModelEbos.hpp +++ b/opm/simulators/flow/BlackoilModelEbos.hpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -119,7 +120,7 @@ namespace Opm { typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw; typedef typename GET_PROP_TYPE(TypeTag, MaterialLawParams) MaterialLawParams; - + typedef double Scalar; static const int numEq = Indices::numEq; static const int contiSolventEqIdx = Indices::contiSolventEqIdx; @@ -485,27 +486,32 @@ namespace Opm { int pressureVarIndex=1; // true impes case could add case with trivial weighs i equations is modifind with weights // this would make a newton based method if derivative of the weights are takein into account - PressureVectorType weights(x.size()); + BVector weights(x.size()); ElementContext elemCtx(ebosSimulator_); + typedef typename GET_PROP_TYPE(TypeTag, ThreadManager) ThreadManager; Opm::Amg::getTrueImpesWeights(pressureVarIndex, weights, - ebsSimulator_.vanguard().gridView(), - elemCtx, simulator_.model(), + ebosSimulator_.vanguard().gridView(), + elemCtx, ebosSimulator_.model(), ThreadManager::threadId()); - PresssureMatrixType pmatrix = - PressureHelper::makePressureMatrix( - ebosJac, - weights, - pressureVarIndex); + PressureMatrixType pmatrix = + PressureHelper::makePressureMatrix( + ebosJac.istlMatrix(), + pressureVarIndex, + weights); PressureVectorType rhs(ebosResid.size(),0); - PressureHelper::moveToPressure(ebosResid,rhs); + PressureHelper::moveToPressureEqn(ebosResid, rhs, weights); boost::property_tree::ptree prm; boost::property_tree::read_json("pressuresolver.json", prm); - Dune::FlexibleSolver pressureSolver(pmatrix,prm); + std::function weightsCalculator; + Dune::FlexibleSolver pressureSolver(prm,pmatrix,weightsCalculator,comm); PressureVectorType xp(x.size(),0); - pressureSolver.apply(rhs, xp); + Dune::InverseOperatorResult res; + pressureSolver.apply(rhs, xp, res); x=0; - PressureHelper::moveToBlock(xp, x, pressureVarIndex); + PressureHelper::movePressureToBlock(x, xp, pressureVarIndex); // set initial guess }else{ auto& ebosJac = ebosSimulator_.model().linearizer().jacobian(); diff --git a/opm/simulators/flow/PressureMatrixHelper.hpp b/opm/simulators/flow/PressureMatrixHelper.hpp new file mode 100644 index 00000000000..fd53f32d8c1 --- /dev/null +++ b/opm/simulators/flow/PressureMatrixHelper.hpp @@ -0,0 +1,94 @@ +/* + Copyright 2019 SINTEF Digital, Mathematics and Cybernetics. + + This file is part of the Open Porous Media project (OPM). + + OPM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OPM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with OPM. If not, see . +*/ + +#ifndef OPM_PRESSURMATRIXHELPER_HEADER_INCLUDED +#define OPM_PRESSURMATRIXHELPER_HEADER_INCLUDED + +namespace Opm{ + namespace PressureHelper{ + // this make pressure equations or jacobi of pressure equation + // it is identical to the cpr PressureTransferPolicy.hpp placed not in a linear solver setting + template + PressureMatrixType makePressureMatrix(const MatrixType& fineLevelMatrix, + int pressureVarIndex, + const PressureVectorType& weights) + { + PressureMatrixType pressureMatrix(fineLevelMatrix.N(), fineLevelMatrix.M(), PressureMatrixType::row_wise); + auto createIter = pressureMatrix.createbegin(); + + for (const auto& row : fineLevelMatrix) { + for (auto col = row.begin(), cend = row.end(); col != cend; ++col) { + createIter.insert(col.index()); + } + ++createIter; + } + makePressureMatrixEntries(pressureMatrix,fineLevelMatrix,pressureVarIndex, weights); + return pressureMatrix; + } + template + void makePressureMatrixEntries(PressureMatrixType& pmatrix, + const MatrixType& fineMatrix, + const int pressure_var_index, + const BlockVectorType& weights){ + pmatrix = 0; + auto rowCoarse = pmatrix.begin(); + for (auto row = fineMatrix.begin(), rowEnd = fineMatrix.end(); row != rowEnd; ++row, ++rowCoarse) { + assert(row.index() == rowCoarse.index()); + auto entryCoarse = rowCoarse->begin(); + for (auto entry = row->begin(), entryEnd = row->end(); entry != entryEnd; ++entry, ++entryCoarse) { + assert(entry.index() == entryCoarse.index()); + double matrix_el = 0; + const auto& bw = weights[row.index()]; + for (size_t i = 0; i < bw.size(); ++i) { + matrix_el += (*entry)[i][pressure_var_index] * bw[i]; + } + (*entryCoarse) = matrix_el; + } + } + assert(rowCoarse == pmatrix.end()); + } + + template + void moveToPressureEqn(const BlockVectorType& fine,PressureVectorType& rhs,const BlockVectorType& weights) + { + // Set coarse vector to zero + rhs = 0; + auto end = fine.end(), begin = fine.begin(); + + for (auto block = begin; block != end; ++block) { + const auto& bw = weights[block.index()]; + double rhs_el = 0.0; + for (size_t i = 0; i < block->size(); ++i) { + rhs_el += (*block)[i] * bw[i]; + } + rhs[block - begin] = rhs_el; + } + } + template + void movePressureToBlock(BlockVectorType& fine,const PressureVectorType& lhs,int pressure_var_index) + { + auto end = fine.end(), begin = fine.begin(); + for (auto block = begin; block != end; ++block) { + (*block)[pressure_var_index] = lhs[block - begin]; + } + } + } +} + +#endif From c2d6c65e758be1db253467027da08e72dab25cd6 Mon Sep 17 00:00:00 2001 From: hnil Date: Sun, 7 Jun 2020 20:51:02 +0200 Subject: [PATCH 06/93] sequential pressure solver compile --- opm/simulators/flow/BlackoilModelEbos.hpp | 24 +++++++-- opm/simulators/flow/PressureMatrixHelper.hpp | 55 ++++++++++++-------- 2 files changed, 53 insertions(+), 26 deletions(-) diff --git a/opm/simulators/flow/BlackoilModelEbos.hpp b/opm/simulators/flow/BlackoilModelEbos.hpp index c568f2cdd01..fe1f89d501d 100644 --- a/opm/simulators/flow/BlackoilModelEbos.hpp +++ b/opm/simulators/flow/BlackoilModelEbos.hpp @@ -496,8 +496,9 @@ namespace Opm { ThreadManager::threadId()); PressureMatrixType pmatrix = PressureHelper::makePressureMatrix( + PressureVectorType>( ebosJac.istlMatrix(), pressureVarIndex, weights); @@ -505,8 +506,25 @@ namespace Opm { PressureHelper::moveToPressureEqn(ebosResid, rhs, weights); boost::property_tree::ptree prm; boost::property_tree::read_json("pressuresolver.json", prm); - std::function weightsCalculator; - Dune::FlexibleSolver pressureSolver(prm,pmatrix,weightsCalculator,comm); + std::any parallelInformation; + extractParallelGridInformationToISTL(ebosSimulator_.vanguard().grid(), parallelInformation); +#if HAVE_MPI + using Communication = Dune::OwnerOverlapCopyCommunication; + Communication comm; + if (parallelInformation_.type() == typeid(ParallelISTLInformation)) { + // Parallel case. + const ParallelISTLInformation* parinfo = std::any_cast(¶llelInformation_); + assert(parinfo); + comm = Communication(parinfo->communicator()); + } +#else + using Communication = Dune::Amg::SequentialInformation; // Dummy type + Communication comm; +#endif + + + std::function weightsCalculator;// dummy + Dune::FlexibleSolver pressureSolver(prm,pmatrix, weightsCalculator, comm); PressureVectorType xp(x.size(),0); Dune::InverseOperatorResult res; pressureSolver.apply(rhs, xp, res); diff --git a/opm/simulators/flow/PressureMatrixHelper.hpp b/opm/simulators/flow/PressureMatrixHelper.hpp index fd53f32d8c1..470ab4d455e 100644 --- a/opm/simulators/flow/PressureMatrixHelper.hpp +++ b/opm/simulators/flow/PressureMatrixHelper.hpp @@ -24,28 +24,11 @@ namespace Opm{ namespace PressureHelper{ // this make pressure equations or jacobi of pressure equation // it is identical to the cpr PressureTransferPolicy.hpp placed not in a linear solver setting - template - PressureMatrixType makePressureMatrix(const MatrixType& fineLevelMatrix, - int pressureVarIndex, - const PressureVectorType& weights) - { - PressureMatrixType pressureMatrix(fineLevelMatrix.N(), fineLevelMatrix.M(), PressureMatrixType::row_wise); - auto createIter = pressureMatrix.createbegin(); - - for (const auto& row : fineLevelMatrix) { - for (auto col = row.begin(), cend = row.end(); col != cend; ++col) { - createIter.insert(col.index()); - } - ++createIter; - } - makePressureMatrixEntries(pressureMatrix,fineLevelMatrix,pressureVarIndex, weights); - return pressureMatrix; - } - template + template void makePressureMatrixEntries(PressureMatrixType& pmatrix, const MatrixType& fineMatrix, const int pressure_var_index, - const BlockVectorType& weights){ + const VectorType& weights){ pmatrix = 0; auto rowCoarse = pmatrix.begin(); for (auto row = fineMatrix.begin(), rowEnd = fineMatrix.end(); row != rowEnd; ++row, ++rowCoarse) { @@ -64,8 +47,34 @@ namespace Opm{ assert(rowCoarse == pmatrix.end()); } - template - void moveToPressureEqn(const BlockVectorType& fine,PressureVectorType& rhs,const BlockVectorType& weights) + + + + template + PressureMatrixType makePressureMatrix(const MatrixType& fineLevelMatrix, + int pressureVarIndex, + const VectorType& weights) + { + PressureMatrixType pressureMatrix(fineLevelMatrix.N(), fineLevelMatrix.M(), PressureMatrixType::row_wise); + auto createIter = pressureMatrix.createbegin(); + + for (const auto& row : fineLevelMatrix) { + for (auto col = row.begin(), cend = row.end(); col != cend; ++col) { + createIter.insert(col.index()); + } + ++createIter; + } + makePressureMatrixEntries + (pressureMatrix,fineLevelMatrix,pressureVarIndex, weights); + return pressureMatrix; + } + template + void moveToPressureEqn(const VectorType& fine,PressureVectorType& rhs,const VectorType& weights) { // Set coarse vector to zero rhs = 0; @@ -80,8 +89,8 @@ namespace Opm{ rhs[block - begin] = rhs_el; } } - template - void movePressureToBlock(BlockVectorType& fine,const PressureVectorType& lhs,int pressure_var_index) + template + void movePressureToBlock(VectorType& fine,const PressureVectorType& lhs,int pressure_var_index) { auto end = fine.end(), begin = fine.begin(); for (auto block = begin; block != end; ++block) { From 3055f175b37099d82100ef1363528f62692555bb Mon Sep 17 00:00:00 2001 From: hnil Date: Mon, 8 Jun 2020 18:23:08 +0200 Subject: [PATCH 07/93] draft of new flux calculations --- ebos/eclfluxmoduleseq.hh | 543 +++++++++++++++++++++++++++++ ebos/totalfluxupwind.hh | 84 +++++ flow/flow_blackoil_dunecpr_seq.cpp | 10 +- 3 files changed, 632 insertions(+), 5 deletions(-) create mode 100644 ebos/eclfluxmoduleseq.hh create mode 100644 ebos/totalfluxupwind.hh diff --git a/ebos/eclfluxmoduleseq.hh b/ebos/eclfluxmoduleseq.hh new file mode 100644 index 00000000000..093a9b7413a --- /dev/null +++ b/ebos/eclfluxmoduleseq.hh @@ -0,0 +1,543 @@ +// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +// vi: set et ts=4 sw=4 sts=4: +/* + This file is part of the Open Porous Media project (OPM). + + OPM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + OPM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with OPM. If not, see . + + Consult the COPYING file in the top-level source directory of this + module for the precise wording of the license and the list of + copyright holders. +*/ +/*! + * \file + * + * \brief This file contains the flux module which is used for ECL problems + * + * This approach to fluxes is very specific to two-point flux approximation and applies + * what the Eclipse Technical Description calls the "NEWTRAN" transmissibility approach. + */ +#ifndef EWOMS_ECL_FLUX_MODULE_SEQ_HH +#define EWOMS_ECL_FLUX_MODULE_SEQ_HH +#include "eclfluxmodule.hh" +/* +#include +#include +#include + +#include +#include + +#include +#include +*/ + +namespace Opm { + + +// template +// class EclTransIntensiveQuantities; + +// template +// class EclTransExtensiveQuantities; + +// template +// class EclTransBaseProblem; + +/*! + * \ingroup EclBlackOilSimulator + * \brief Specifies a flux module which uses ECL transmissibilities. + */ + +// template +// struct EclTransFluxModule +// { +// typedef EclTransIntensiveQuantities FluxIntensiveQuantities; +// typedef EclTransExtensiveQuantities FluxExtensiveQuantities; +// typedef EclTransBaseProblem FluxBaseProblem; + +// /*! +// * \brief Register all run-time parameters for the flux module. +// */ +// static void registerParameters() +// { } +// }; + +/*! + * \ingroup EclBlackOilSimulator + * \brief Provides the defaults for the parameters required by the + * transmissibility based volume flux calculation. + */ +/* +template +class EclTransBaseProblem +{ }; +*/ +/*! + * \ingroup EclBlackOilSimulator + * \brief Provides the intensive quantities for the ECL flux module + */ + +// template +// class EclTransIntensiveQuantities +// { +// typedef typename GET_PROP_TYPE(TypeTag, ElementContext) ElementContext; +// protected: +// void update_(const ElementContext& elemCtx OPM_UNUSED, unsigned dofIdx OPM_UNUSED, unsigned timeIdx OPM_UNUSED) +// { } +// }; + +/*! + * \ingroup EclBlackOilSimulator + * \brief Provides the ECL flux module + */ + +template +class EclTransExtensiveQuantitiesSeq +{ + typedef typename GET_PROP_TYPE(TypeTag, ExtensiveQuantities) Implementation; + + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + typedef typename GET_PROP_TYPE(TypeTag, ElementContext) ElementContext; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, Evaluation) Evaluation; + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw; + + enum { dimWorld = GridView::dimensionworld }; + enum { gasPhaseIdx = FluidSystem::gasPhaseIdx }; + enum { numPhases = FluidSystem::numPhases }; + enum { enableSolvent = GET_PROP_VALUE(TypeTag, EnableSolvent) }; + enum { enableEnergy = GET_PROP_VALUE(TypeTag, EnableEnergy) }; + + typedef Opm::MathToolbox Toolbox; + typedef Dune::FieldVector DimVector; + typedef Dune::FieldVector EvalDimVector; + typedef Dune::FieldMatrix DimMatrix; + +public: + /*! + * \brief Return the intrinsic permeability tensor at a face [m^2] + */ + const DimMatrix& intrinsicPermeability() const + { + throw std::invalid_argument("The ECL transmissibility module does not provide an explicit intrinsic permeability"); + } + + /*! + * \brief Return the pressure potential gradient of a fluid phase at the + * face's integration point [Pa/m] + * + * \param phaseIdx The index of the fluid phase + */ + const EvalDimVector& potentialGrad(unsigned phaseIdx OPM_UNUSED) const + { + throw std::invalid_argument("The ECL transmissibility module does not provide explicit potential gradients"); + } + + /*! + * \brief Return the gravity corrected pressure difference between the interior and + * the exterior of a face. + * + * \param phaseIdx The index of the fluid phase + */ + const Evaluation& pressureDifference(unsigned phaseIdx) const + { return pressureDifference_[phaseIdx]; } + + /*! + * \brief Return the filter velocity of a fluid phase at the face's integration point + * [m/s] + * + * \param phaseIdx The index of the fluid phase + */ + const EvalDimVector& filterVelocity(unsigned phaseIdx OPM_UNUSED) const + { + throw std::invalid_argument("The ECL transmissibility module does not provide explicit filter velocities"); + } + + /*! + * \brief Return the volume flux of a fluid phase at the face's integration point + * \f$[m^3/s / m^2]\f$ + * + * This is the fluid volume of a phase per second and per square meter of face + * area. + * + * \param phaseIdx The index of the fluid phase + */ + const Evaluation& volumeFlux(unsigned phaseIdx) const + { // could be used to check in the fully implicit cas + Scalar control = volumeFlux_[phaseIdx]; + Scalar fmob =1; + Scalar mobT =1; + + + + } + +protected: + /*! + * \brief Returns the local index of the degree of freedom in which is + * in upstream direction. + * + * i.e., the DOF which exhibits a higher effective pressure for + * the given phase. + */ + unsigned upstreamIndex_(unsigned phaseIdx) const + { + assert(0 <= phaseIdx && phaseIdx < numPhases); + + return upIdx_[phaseIdx]; + } + + /*! + * \brief Returns the local index of the degree of freedom in which is + * in downstream direction. + * + * i.e., the DOF which exhibits a lower effective pressure for the + * given phase. + */ + unsigned downstreamIndex_(unsigned phaseIdx) const + { + assert(0 <= phaseIdx && phaseIdx < numPhases); + + return dnIdx_[phaseIdx]; + } + + void updateSolvent(const ElementContext& elemCtx, unsigned scvfIdx, unsigned timeIdx) + { asImp_().updateVolumeFluxTrans(elemCtx, scvfIdx, timeIdx); } + + void updatePolymer(const ElementContext& elemCtx, unsigned scvfIdx, unsigned timeIdx) + { asImp_().updateShearMultipliers(elemCtx, scvfIdx, timeIdx); } + + /*! + * \brief Update the required gradients for interior faces + */ + void calculateGradients_(const ElementContext& elemCtx, unsigned scvfIdx, unsigned timeIdx) + { + Opm::Valgrind::SetUndefined(*this); + + const auto& problem = elemCtx.problem(); + const auto& stencil = elemCtx.stencil(timeIdx); + const auto& scvf = stencil.interiorFace(scvfIdx); + + interiorDofIdx_ = scvf.interiorIndex(); + exteriorDofIdx_ = scvf.exteriorIndex(); + assert(interiorDofIdx_ != exteriorDofIdx_); + + unsigned I = stencil.globalSpaceIndex(interiorDofIdx_); + unsigned J = stencil.globalSpaceIndex(exteriorDofIdx_); + + Scalar trans = problem.transmissibility(elemCtx, interiorDofIdx_, exteriorDofIdx_); + Scalar faceArea = scvf.area(); + Scalar thpres = problem.thresholdPressure(I, J); + + // estimate the gravity correction: for performance reasons we use a simplified + // approach for this flux module that assumes that gravity is constant and always + // acts into the downwards direction. (i.e., no centrifuge experiments, sorry.) + Scalar g = elemCtx.problem().gravity()[dimWorld - 1]; + + const auto& intQuantsIn = elemCtx.intensiveQuantities(interiorDofIdx_, timeIdx); + const auto& intQuantsEx = elemCtx.intensiveQuantities(exteriorDofIdx_, timeIdx); + + // this is quite hacky because the dune grid interface does not provide a + // cellCenterDepth() method (so we ask the problem to provide it). The "good" + // solution would be to take the Z coordinate of the element centroids, but since + // ECL seems to like to be inconsistent on that front, it needs to be done like + // here... + Scalar zIn = problem.dofCenterDepth(elemCtx, interiorDofIdx_, timeIdx); + Scalar zEx = problem.dofCenterDepth(elemCtx, exteriorDofIdx_, timeIdx); + + // the distances from the DOF's depths. (i.e., the additional depth of the + // exterior DOF) + Scalar distZ = zIn - zEx; + totalFlux_ = 0.0; + for (unsigned phaseIdx=0; phaseIdx < numPhases; phaseIdx++) { + if (!FluidSystem::phaseIsActive(phaseIdx)) + continue; + + // check shortcut: if the mobility of the phase is zero in the interior as + // well as the exterior DOF, we can skip looking at the phase. + if (intQuantsIn.mobility(phaseIdx) <= 0.0 && + intQuantsEx.mobility(phaseIdx) <= 0.0) + { + upIdx_[phaseIdx] = interiorDofIdx_; + dnIdx_[phaseIdx] = exteriorDofIdx_; + pressureDifference_[phaseIdx] = 0.0; + volumeFlux_[phaseIdx] = 0.0; + continue; + } + + // do the gravity correction: compute the hydrostatic pressure for the + // external at the depth of the internal one + const Evaluation& rhoIn = intQuantsIn.fluidState().density(phaseIdx); + Scalar rhoEx = Toolbox::value(intQuantsEx.fluidState().density(phaseIdx)); + Evaluation rhoAvg = (rhoIn + rhoEx)/2; + + const Evaluation& pressureInterior = intQuantsIn.fluidState().pressure(phaseIdx); + Evaluation pressureExterior = Toolbox::value(intQuantsEx.fluidState().pressure(phaseIdx)); + pressureExterior += rhoAvg*(distZ*g); + + pressureDifference_[phaseIdx] = pressureExterior - pressureInterior; + + // decide the upstream index for the phase. for this we make sure that the + // degree of freedom which is regarded upstream if both pressures are equal + // is always the same: if the pressure is equal, the DOF with the lower + // global index is regarded to be the upstream one. + if (pressureDifference_[phaseIdx] > 0.0) { + upIdx_[phaseIdx] = exteriorDofIdx_; + dnIdx_[phaseIdx] = interiorDofIdx_; + } + else if (pressureDifference_[phaseIdx] < 0.0) { + upIdx_[phaseIdx] = interiorDofIdx_; + dnIdx_[phaseIdx] = exteriorDofIdx_; + } + else { + // if the pressure difference is zero, we chose the DOF which has the + // larger volume associated to it as upstream DOF + Scalar Vin = elemCtx.dofVolume(interiorDofIdx_, /*timeIdx=*/0); + Scalar Vex = elemCtx.dofVolume(exteriorDofIdx_, /*timeIdx=*/0); + if (Vin > Vex) { + upIdx_[phaseIdx] = interiorDofIdx_; + dnIdx_[phaseIdx] = exteriorDofIdx_; + } + else if (Vin < Vex) { + upIdx_[phaseIdx] = exteriorDofIdx_; + dnIdx_[phaseIdx] = interiorDofIdx_; + } + else { + assert(Vin == Vex); + // if the volumes are also equal, we pick the DOF which exhibits the + // smaller global index + if (I < J) { + upIdx_[phaseIdx] = interiorDofIdx_; + dnIdx_[phaseIdx] = exteriorDofIdx_; + } + else { + upIdx_[phaseIdx] = exteriorDofIdx_; + dnIdx_[phaseIdx] = interiorDofIdx_; + } + } + } + + // apply the threshold pressure for the intersection. note that the concept + // of threshold pressure is a quite big hack that only makes sense for ECL + // datasets. (and even there, its physical justification is quite + // questionable IMO.) + if (std::abs(Toolbox::value(pressureDifference_[phaseIdx])) > thpres) { + if (pressureDifference_[phaseIdx] < 0.0) + pressureDifference_[phaseIdx] += thpres; + else + pressureDifference_[phaseIdx] -= thpres; + } + else { + pressureDifference_[phaseIdx] = 0.0; + volumeFlux_[phaseIdx] = 0.0; + continue; + } + + // this is slightly hacky because in the automatic differentiation case, it + // only works for the element centered finite volume method. for ebos this + // does not matter, though. + unsigned upstreamIdx = upstreamIndex_(phaseIdx); + const auto& up = elemCtx.intensiveQuantities(upstreamIdx, timeIdx); + + // TODO: should the rock compaction transmissibility multiplier be upstreamed + // or averaged? all fluids should see the same compaction?! + const Evaluation& transMult = + problem.template rockCompTransMultiplier(up, stencil.globalSpaceIndex(upstreamIdx)); + + if (upstreamIdx == interiorDofIdx_) + volumeFlux_[phaseIdx] = + pressureDifference_[phaseIdx]*up.mobility(phaseIdx)*transMult*(-trans/faceArea); + else + volumeFlux_[phaseIdx] = + pressureDifference_[phaseIdx]*(Toolbox::value(up.mobility(phaseIdx))*Toolbox::value(transMult)*(-trans/faceArea)); + + totalFlux_ += volumeFlux_[phaseIdx]; + } + // use the sequential type even in fully implicit + calculateGradientsSeq_(elemCtx, scvfIdx, timeIdx); + } + + /*! + * \brief Update the required gradients for interior faces + */ + void calculateGradientsSeq_(const ElementContext& elemCtx, unsigned scvfIdx, unsigned timeIdx) + { + Opm::Valgrind::SetUndefined(*this); + + const auto& problem = elemCtx.problem(); + const auto& stencil = elemCtx.stencil(timeIdx); + const auto& scvf = stencil.interiorFace(scvfIdx); + + interiorDofIdx_ = scvf.interiorIndex(); + exteriorDofIdx_ = scvf.exteriorIndex(); + assert(interiorDofIdx_ != exteriorDofIdx_); + + unsigned I = stencil.globalSpaceIndex(interiorDofIdx_); + unsigned J = stencil.globalSpaceIndex(exteriorDofIdx_); + + Scalar trans = problem.transmissibility(elemCtx, interiorDofIdx_, exteriorDofIdx_); + Scalar faceArea = scvf.area(); + + // estimate the gravity correction: for performance reasons we use a simplified + // approach for this flux module that assumes that gravity is constant and always + // acts into the downwards direction. (i.e., no centrifuge experiments, sorry.) + Scalar g = elemCtx.problem().gravity()[dimWorld - 1]; + + const auto& intQuantsIn = elemCtx.intensiveQuantities(interiorDofIdx_, timeIdx); + const auto& intQuantsEx = elemCtx.intensiveQuantities(exteriorDofIdx_, timeIdx); + + // { + // // if used only for sequential scalar is ok + // const Scalar& transMult1 = + // problem.template + // rockCompTransMultiplier(intQuantsIn, stencil.globalSpaceIndex(interiorDofIdx_)); + + // const Scalar& transMult2 = + // problem.template + // rockCompTransMultiplier(intQuantsIn, stencil.globalSpaceIndex(exteriorDofIdx_)); + // Scalar transM = 1.0/(1.0/transMult1 + 1.0/transMult2); + // trans *= transM; + // } + + // this is quite hacky because the dune grid interface does not provide a + // cellCenterDepth() method (so we ask the problem to provide it). The "good" + // solution would be to take the Z coordinate of the element centroids, but since + // ECL seems to like to be inconsistent on that front, it needs to be done like + // here... + Scalar zIn = problem.dofCenterDepth(elemCtx, interiorDofIdx_, timeIdx); + Scalar zEx = problem.dofCenterDepth(elemCtx, exteriorDofIdx_, timeIdx); + + // the distances from the DOF's depths. (i.e., the additional depth of the + // exterior DOF) + Scalar distZ = zIn - zEx; + + Evaluation mob1[numPhases]; + Evaluation mob2[numPhases]; + Evaluation headDiff[numPhases]; + for (unsigned phaseIdx=0; phaseIdx < numPhases; phaseIdx++) { + if (!FluidSystem::phaseIsActive(phaseIdx)) + continue; + + // check shortcut: if the mobility of the phase is zero in the interior as + // well as the exterior DOF, we can skip looking at the phase. + // if (intQuantsIn.mobility(phaseIdx) <= 0.0 && + // intQuantsEx.mobility(phaseIdx) <= 0.0) + // { + // upIdx_[phaseIdx] = interiorDofIdx_; + // dnIdx_[phaseIdx] = exteriorDofIdx_; + // pressureDifference_[phaseIdx] = 0.0; + // volumeFlux_[phaseIdx] = 0.0; + // continue; + // } + + // do the gravity correction: compute the hydrostatic pressure for the + // external at the depth of the internal one + const Evaluation& rhoIn = intQuantsIn.fluidState().density(phaseIdx); + Scalar rhoEx = Toolbox::value(intQuantsEx.fluidState().density(phaseIdx)); + Evaluation rhoAvg = (rhoIn + rhoEx)/2; + + headDiff2[phaseIdx] = rhoAvg*(distZ*g); + mob1[phaseIdx] = intQuantsIn.mobility(phaseIdx); + mob2[phaseIdx] = Toolbox::value(intQuantsEx.mobility(phaseIdx)); + } + Evaluation ST1 = intQuantsIn.totalSaturation(); + Evaluation ST2 = Toolbox::value(intQuantsEx.totalSaturation(phaseIdx)); + + std::array upwind; + connectionMultiPhaseUpwind(upwind, + headDiff_, + mob1, + mob2, + trans, + totalFlux_); + + Evaluation fmob[numPhases];//upwind weighted total saturation + Evaluation fst[numPhases];// upwindweighted total saturation + Evaluation mobT = 0; + for (unsigned phaseIdx=0; phaseIdx < numPhases; phaseIdx++) { + if (!FluidSystem::phaseIsActive(phaseIdx)) + continue; + if(upwind[phaseIdx] > 0){ + assert(upIdx_[phaseIdx_] == interieorDofIdx_); + upIdx_[phaseIdx] = interiorDofIdx_; + dnIdx_[phaseIdx] = exteriorDofIdx_; + fmob[phaseIdx] = mob1[phaseIdx]; + fst[phaseIdx] = ST1; + }else{ + assert(upIdx_[phaseIdx_] == exteriorDofIdx_); + upIdx_[phaseIdx] = exteriorDofIdx_; + dnIdx_[phaseIdx] = interiorDofIdx_; + fmob[phaseIdx] = mob2[phaseIdx]; + fst[phaseIdx] = ST1; + } + mobT += fmob[phaseIdx]; + } + if(linearizationType.type == Opm::LinearizationType::seqtransport){ + //needed? where should volumeFlux_ should probably be a scalar + volumeFlux_ = Toolbox::value(volumeFlux_); + } + + + for (unsigned phaseIdx=0; phaseIdx < numPhases; phaseIdx++) { + if (!FluidSystem::phaseIsActive(phaseIdx)) + continue; + mobG = 0; + for (unsigned phaseIdx1=0; phaseIdx1 < numPhases; phaseIdx1++) { + if( phaseIdx ~= phaseIdx1 ){ + mobG = mobG + fmob*(headDiff_[phaseIdx] - headDiff_[phaseIdx1]); + } + } + Evaluation pFlux = (1.0./mobT) * (totalFlux_ + trans * mobG); + assert(pFlux == volumeFlux_[phaseIdx]); // for testing code in fully implit mode + volumeFlux_[phaseIdx] = fst[phaseIdx] * mobTinv * (totalFlux_ + trans * fmob); + } + } + + + /*! + * \brief Update the volumetric fluxes for all fluid phases on the interior faces of the context + */ + void calculateFluxes_(const ElementContext& elemCtx OPM_UNUSED, unsigned scvfIdx OPM_UNUSED, unsigned timeIdx OPM_UNUSED) + { } + + void calculateBoundaryFluxes_(const ElementContext& elemCtx OPM_UNUSED, unsigned scvfIdx OPM_UNUSED, unsigned timeIdx OPM_UNUSED) + {} + +private: + Implementation& asImp_() + { return *static_cast(this); } + + const Implementation& asImp_() const + { return *static_cast(this); } + + // the volumetric flux of all phases [m^3/s] + Evaluation volumeFlux_[numPhases]; + Evaluation totalFlux_; + + // the difference in effective pressure between the exterior and the interior degree + // of freedom [Pa] + Evaluation pressureDifference_[numPhases]; + + // the local indices of the interior and exterior degrees of freedom + unsigned short interiorDofIdx_; + unsigned short exteriorDofIdx_; + short upIdx_[numPhases]; + short dnIdx_[numPhases]; +}; + +} // namespace Opm + +#endif diff --git a/ebos/totalfluxupwind.hh b/ebos/totalfluxupwind.hh new file mode 100644 index 00000000000..c92de6d996d --- /dev/null +++ b/ebos/totalfluxupwind.hh @@ -0,0 +1,84 @@ +/* + Copyright 2015, 2016 SINTEF ICT, Applied Mathematics. + Copyright 2016 Statoil AS. + This file is part of the Open Porous Media project (OPM). + OPM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + OPM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + You should have received a copy of the GNU General Public License + along with OPM. If not, see . +*/ + + +#include +#include +#include + + +namespace Opm +{ + + template + VectorType connectionMultiPhaseUpwind(IntVectorType& upwind, + const VectorType& head_diff, + const VectorType& mob1, + const VectorType& mob2, + const Scalar transmissibility, + const Scalar flux) + { + // Based on the paper "Upstream Differencing for Multiphase Flow in Reservoir Simulation", + // by Yann Brenier and Jérôme Jaffré, + // SIAM J. Numer. Anal., 28(3), 685–696. + // DOI:10.1137/0728036 + // + // Notation is based on this paper, except q -> flux, t -> transmissibility. + + enum { NumPhases = 3 }; // TODO: remove this restriction. + + // Get and sort the g values (also called "weights" in the paper) for this connection. + using ValueAndIndex = std::pair; + std::array g; + for (int phase_idx = 0; phase_idx < NumPhases; ++phase_idx) { + g[phase_idx] = ValueAndIndex(head_diff[phase_idx], phase_idx); + } + std::sort(g.begin(), g.end()); + + // Compute theta and r. + // Paper notation: subscript l -> ell (for read/searchability) + // Note that since we index phases from 0, r is one less than in the paper. + std::array theta; + int r = -1; + for (int ell = 0; ell < NumPhases; ++ell) { + theta[ell] = flux; + for (int j = 0; j < NumPhases; ++j) { + if (j < ell) { + theta[ell] += transmissibility * (g[ell].first - g[j].first) * mob2[g[j].second]; + } + if (j > ell) { + theta[ell] += transmissibility * (g[ell].first - g[j].first) * mob1[g[j].second]; + } + } + if (theta[ell] <= 0.0) { + r = ell; + } else { + break; // r is correct, no need to continue + } + } + + // Set upwind array and return. + //std::array upwind; + for (int ell = 0; ell < NumPhases; ++ell) { + const int phase_idx = g[ell].second; + upwind[phase_idx] = ell > r ? 1.0 : -1.0; + } + //return upwind; + + } + + +} // namespace Opm diff --git a/flow/flow_blackoil_dunecpr_seq.cpp b/flow/flow_blackoil_dunecpr_seq.cpp index 94c6ed4bd46..c8f8c7c8092 100644 --- a/flow/flow_blackoil_dunecpr_seq.cpp +++ b/flow/flow_blackoil_dunecpr_seq.cpp @@ -21,8 +21,8 @@ #include "config.h" #include -#include - +#include +#include BEGIN_PROPERTIES NEW_TYPE_TAG(EclFlowProblemSimple, INHERITS_FROM(EclFlowProblem)); NEW_PROP_TAG(FluidState); @@ -61,9 +61,9 @@ SET_STRING_PROP(EclFlowProblemSimple, SystemStrategy, "quasiimpes"); END_PROPERTIES namespace Opm { - template - class EclTransExtensiveQuantitiesSeq : public EclTransExtensiveQuantities - {}; + //template + //class EclTransExtensiveQuantitiesSeq : public EclTransExtensiveQuantitise + //{}; // template // BlackOilIntensiveQuantitiesSeq : public BlackOilIntensiveQuantities From 67730ceec6f535c9804456201b117b6366472e38 Mon Sep 17 00:00:00 2001 From: hnil Date: Mon, 8 Jun 2020 18:43:55 +0200 Subject: [PATCH 08/93] draft sequential implicit --- opm/simulators/flow/NonlinearSolverEbos.hpp | 25 ++++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/opm/simulators/flow/NonlinearSolverEbos.hpp b/opm/simulators/flow/NonlinearSolverEbos.hpp index e51a82af70d..b20d9c92be6 100644 --- a/opm/simulators/flow/NonlinearSolverEbos.hpp +++ b/opm/simulators/flow/NonlinearSolverEbos.hpp @@ -149,12 +149,25 @@ namespace Opm { SimulatorReportSingle stepSequential(const SimulatorTimerInterface& timer){ LinearizationType linearizationType; - linearizationType.type = Opm::LinearizationType::pressure; - model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); - this->stepDefault(timer); - linearizationType.type = Opm::LinearizationType::seqtransport; - model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); - this->stepDefault(timer); + bool converged = false; + SimulatorReportSingle reportpre; + SimulatorReportSingle reportseq; + while(not converged){ + linearizationType.type = Opm::LinearizationType::pressure; + model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); + SimulatorReportSingle lreportpre = this->stepDefault(timer); + linearizationType.type = Opm::LinearizationType::seqtransport; + model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); + SimulatorReportSingle lreportseq = this->stepDefault(timer); + reportpre += lreportpre; + reportseq += lreportseq; + // for no not seq implicit + converged = true; + } + SimulatorReportSingle report; + //todo fill this report correctly + return report; + } SimulatorReportSingle stepFull(const SimulatorTimerInterface& timer){ From ed0dee7b8372b6e1c0962c31c29c7f7697eaf36e Mon Sep 17 00:00:00 2001 From: hnil Date: Mon, 8 Jun 2020 22:04:00 +0200 Subject: [PATCH 09/93] fixed forgotten return of report --- opm/simulators/flow/NonlinearSolverEbos.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/opm/simulators/flow/NonlinearSolverEbos.hpp b/opm/simulators/flow/NonlinearSolverEbos.hpp index b20d9c92be6..3695ac34cdf 100644 --- a/opm/simulators/flow/NonlinearSolverEbos.hpp +++ b/opm/simulators/flow/NonlinearSolverEbos.hpp @@ -173,7 +173,8 @@ namespace Opm { SimulatorReportSingle stepFull(const SimulatorTimerInterface& timer){ LinearizationType linearizationType;// use default model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); - this->stepDefault(timer); + SimulatorReportSingle report = this->stepDefault(timer); + return report; } From 92ca7f9d9c6f54a10e9c1b4339d477c770392b74 Mon Sep 17 00:00:00 2001 From: hnil Date: Tue, 9 Jun 2020 13:12:27 +0200 Subject: [PATCH 10/93] compiling version of new eclfluxmodule --- ebos/eclfluxmoduleseq.hh | 170 ++++++++++++++++++++++++----- ebos/totalfluxupwind.hh | 6 +- flow/flow_blackoil_dunecpr_seq.cpp | 2 +- 3 files changed, 146 insertions(+), 32 deletions(-) diff --git a/ebos/eclfluxmoduleseq.hh b/ebos/eclfluxmoduleseq.hh index 093a9b7413a..5f7e6ab38bf 100644 --- a/ebos/eclfluxmoduleseq.hh +++ b/ebos/eclfluxmoduleseq.hh @@ -42,7 +42,7 @@ #include #include */ - +#include "totalfluxupwind.hh" namespace Opm { @@ -176,13 +176,8 @@ public: * \param phaseIdx The index of the fluid phase */ const Evaluation& volumeFlux(unsigned phaseIdx) const - { // could be used to check in the fully implicit cas - Scalar control = volumeFlux_[phaseIdx]; - Scalar fmob =1; - Scalar mobT =1; - - - + { + return volumeFlux_[phaseIdx]; } protected: @@ -375,8 +370,10 @@ protected: */ void calculateGradientsSeq_(const ElementContext& elemCtx, unsigned scvfIdx, unsigned timeIdx) { + //NB a bit hacky + LinearizationType linearizationType = elemCtx.simulator().model().linearizer().getLinearizationType(); Opm::Valgrind::SetUndefined(*this); - + const auto& problem = elemCtx.problem(); const auto& stencil = elemCtx.stencil(timeIdx); const auto& scvf = stencil.interiorFace(scvfIdx); @@ -385,11 +382,11 @@ protected: exteriorDofIdx_ = scvf.exteriorIndex(); assert(interiorDofIdx_ != exteriorDofIdx_); - unsigned I = stencil.globalSpaceIndex(interiorDofIdx_); - unsigned J = stencil.globalSpaceIndex(exteriorDofIdx_); + //unsigned I = stencil.globalSpaceIndex(interiorDofIdx_); + //unsigned J = stencil.globalSpaceIndex(exteriorDofIdx_); - Scalar trans = problem.transmissibility(elemCtx, interiorDofIdx_, exteriorDofIdx_); - Scalar faceArea = scvf.area(); + Evaluation trans = problem.transmissibility(elemCtx, interiorDofIdx_, exteriorDofIdx_); + Scalar faceArea = scvf.area();//NB check definition of flux // estimate the gravity correction: for performance reasons we use a simplified // approach for this flux module that assumes that gravity is constant and always @@ -449,20 +446,20 @@ protected: Scalar rhoEx = Toolbox::value(intQuantsEx.fluidState().density(phaseIdx)); Evaluation rhoAvg = (rhoIn + rhoEx)/2; - headDiff2[phaseIdx] = rhoAvg*(distZ*g); + headDiff[phaseIdx] = rhoAvg*(distZ*g); mob1[phaseIdx] = intQuantsIn.mobility(phaseIdx); mob2[phaseIdx] = Toolbox::value(intQuantsEx.mobility(phaseIdx)); } - Evaluation ST1 = intQuantsIn.totalSaturation(); - Evaluation ST2 = Toolbox::value(intQuantsEx.totalSaturation(phaseIdx)); + Evaluation ST1 = intQuantsIn.fluidState().totalSaturation(); + Evaluation ST2 = Toolbox::value(intQuantsEx.fluidState().totalSaturation()); - std::array upwind; + std::array upwind; connectionMultiPhaseUpwind(upwind, - headDiff_, + headDiff, mob1, mob2, trans, - totalFlux_); + totalFlux_);//NB! taken from the object it self.. Evaluation fmob[numPhases];//upwind weighted total saturation Evaluation fst[numPhases];// upwindweighted total saturation @@ -471,13 +468,17 @@ protected: if (!FluidSystem::phaseIsActive(phaseIdx)) continue; if(upwind[phaseIdx] > 0){ - assert(upIdx_[phaseIdx_] == interieorDofIdx_); + if(linearizationType.type == Opm::LinearizationType::implicit){ + assert(upIdx_[phaseIdx] == interiorDofIdx_);//NB test for implicit + } upIdx_[phaseIdx] = interiorDofIdx_; dnIdx_[phaseIdx] = exteriorDofIdx_; fmob[phaseIdx] = mob1[phaseIdx]; fst[phaseIdx] = ST1; }else{ - assert(upIdx_[phaseIdx_] == exteriorDofIdx_); + if(linearizationType.type == Opm::LinearizationType::implicit){ + assert(upIdx_[phaseIdx] == exteriorDofIdx_);//NB test for implicit + } upIdx_[phaseIdx] = exteriorDofIdx_; dnIdx_[phaseIdx] = interiorDofIdx_; fmob[phaseIdx] = mob2[phaseIdx]; @@ -487,26 +488,139 @@ protected: } if(linearizationType.type == Opm::LinearizationType::seqtransport){ //needed? where should volumeFlux_ should probably be a scalar - volumeFlux_ = Toolbox::value(volumeFlux_); + totalFlux_ = Toolbox::value(totalFlux_); } for (unsigned phaseIdx=0; phaseIdx < numPhases; phaseIdx++) { if (!FluidSystem::phaseIsActive(phaseIdx)) continue; - mobG = 0; + Evaluation mobG = 0; for (unsigned phaseIdx1=0; phaseIdx1 < numPhases; phaseIdx1++) { - if( phaseIdx ~= phaseIdx1 ){ - mobG = mobG + fmob*(headDiff_[phaseIdx] - headDiff_[phaseIdx1]); + if( not(phaseIdx == phaseIdx1) ){ + mobG = mobG + fmob[phaseIdx]*(headDiff[phaseIdx] - headDiff[phaseIdx1]); } } - Evaluation pFlux = (1.0./mobT) * (totalFlux_ + trans * mobG); - assert(pFlux == volumeFlux_[phaseIdx]); // for testing code in fully implit mode - volumeFlux_[phaseIdx] = fst[phaseIdx] * mobTinv * (totalFlux_ + trans * fmob); + Evaluation pFlux = (1.0/mobT) * (totalFlux_ + trans * mobG); + if(linearizationType.type == Opm::LinearizationType::implicit){ + assert(pFlux == volumeFlux_[phaseIdx]); // for testing code in fully implit mode + } + volumeFlux_[phaseIdx] = fst[phaseIdx] * pFlux; } } + /*! + * \brief Update the required gradients for boundary faces + */ + template + void calculateBoundaryGradients_(const ElementContext& elemCtx, + unsigned scvfIdx, + unsigned timeIdx, + const FluidState& exFluidState) + { + const auto& problem = elemCtx.problem(); + + bool enableBoundaryMassFlux = problem.nonTrivialBoundaryConditions(); + if (!enableBoundaryMassFlux) + return; + + const auto& stencil = elemCtx.stencil(timeIdx); + const auto& scvf = stencil.boundaryFace(scvfIdx); + + interiorDofIdx_ = scvf.interiorIndex(); + + Scalar trans = problem.transmissibilityBoundary(elemCtx, scvfIdx); + Scalar faceArea = scvf.area(); + + // estimate the gravity correction: for performance reasons we use a simplified + // approach for this flux module that assumes that gravity is constant and always + // acts into the downwards direction. (i.e., no centrifuge experiments, sorry.) + Scalar g = elemCtx.problem().gravity()[dimWorld - 1]; + + const auto& intQuantsIn = elemCtx.intensiveQuantities(interiorDofIdx_, timeIdx); + + // this is quite hacky because the dune grid interface does not provide a + // cellCenterDepth() method (so we ask the problem to provide it). The "good" + // solution would be to take the Z coordinate of the element centroids, but since + // ECL seems to like to be inconsistent on that front, it needs to be done like + // here... + Scalar zIn = problem.dofCenterDepth(elemCtx, interiorDofIdx_, timeIdx); + Scalar zEx = scvf.integrationPos()[dimWorld - 1]; + + // the distances from the DOF's depths. (i.e., the additional depth of the + // exterior DOF) + Scalar distZ = zIn - zEx; + + for (unsigned phaseIdx=0; phaseIdx < numPhases; phaseIdx++) { + if (!FluidSystem::phaseIsActive(phaseIdx)) + continue; + + // do the gravity correction: compute the hydrostatic pressure for the + // integration position + const Evaluation& rhoIn = intQuantsIn.fluidState().density(phaseIdx); + const auto& rhoEx = exFluidState.density(phaseIdx); + Evaluation rhoAvg = (rhoIn + rhoEx)/2; + + const Evaluation& pressureInterior = intQuantsIn.fluidState().pressure(phaseIdx); + Evaluation pressureExterior = exFluidState.pressure(phaseIdx); + pressureExterior += rhoAvg*(distZ*g); + + pressureDifference_[phaseIdx] = pressureExterior - pressureInterior; + + // decide the upstream index for the phase. for this we make sure that the + // degree of freedom which is regarded upstream if both pressures are equal + // is always the same: if the pressure is equal, the DOF with the lower + // global index is regarded to be the upstream one. + if (pressureDifference_[phaseIdx] > 0.0) { + upIdx_[phaseIdx] = -1; + dnIdx_[phaseIdx] = interiorDofIdx_; + } + else { + upIdx_[phaseIdx] = interiorDofIdx_; + dnIdx_[phaseIdx] = -1; + } + + Evaluation transModified = trans; + + short upstreamIdx = upstreamIndex_(phaseIdx); + if (upstreamIdx == interiorDofIdx_) { + + // this is slightly hacky because in the automatic differentiation case, it + // only works for the element centered finite volume method. for ebos this + // does not matter, though. + const auto& up = elemCtx.intensiveQuantities(upstreamIdx, timeIdx); + + // deal with water induced rock compaction + transModified *= problem.template rockCompTransMultiplier(up, stencil.globalSpaceIndex(upstreamIdx)); + + volumeFlux_[phaseIdx] = + pressureDifference_[phaseIdx]*up.mobility(phaseIdx)*(-transModified/faceArea); + + if (enableSolvent && phaseIdx == gasPhaseIdx) + asImp_().setSolventVolumeFlux( pressureDifference_[phaseIdx]*up.solventMobility()*(-transModified/faceArea)); + } + else { + // compute the phase mobility using the material law parameters of the + // interior element. TODO: this could probably be done more efficiently + const auto& matParams = + elemCtx.problem().materialLawParams(elemCtx, + interiorDofIdx_, + /*timeIdx=*/0); + typename FluidState::Scalar kr[numPhases]; + MaterialLaw::relativePermeabilities(kr, matParams, exFluidState); + + const auto& mob = kr[phaseIdx]/exFluidState.viscosity(phaseIdx); + volumeFlux_[phaseIdx] = + pressureDifference_[phaseIdx]*mob*(-transModified/faceArea); + + // Solvent inflow is not yet supported + if (enableSolvent && phaseIdx == gasPhaseIdx) + asImp_().setSolventVolumeFlux(0.0); + } + } + } + /*! * \brief Update the volumetric fluxes for all fluid phases on the interior faces of the context */ diff --git a/ebos/totalfluxupwind.hh b/ebos/totalfluxupwind.hh index c92de6d996d..783a795c455 100644 --- a/ebos/totalfluxupwind.hh +++ b/ebos/totalfluxupwind.hh @@ -15,7 +15,7 @@ */ -#include +//#include #include #include @@ -23,8 +23,8 @@ namespace Opm { - template - VectorType connectionMultiPhaseUpwind(IntVectorType& upwind, + template + void connectionMultiPhaseUpwind(IntVectorType& upwind, const VectorType& head_diff, const VectorType& mob1, const VectorType& mob2, diff --git a/flow/flow_blackoil_dunecpr_seq.cpp b/flow/flow_blackoil_dunecpr_seq.cpp index c8f8c7c8092..200ae61134f 100644 --- a/flow/flow_blackoil_dunecpr_seq.cpp +++ b/flow/flow_blackoil_dunecpr_seq.cpp @@ -22,7 +22,7 @@ #include #include -#include +#include BEGIN_PROPERTIES NEW_TYPE_TAG(EclFlowProblemSimple, INHERITS_FROM(EclFlowProblem)); NEW_PROP_TAG(FluidState); From 3c20d36facc620b631f721494acbbfa0b02a2194 Mon Sep 17 00:00:00 2001 From: hnil Date: Tue, 9 Jun 2020 20:12:40 +0200 Subject: [PATCH 11/93] added cappilary contribution and made checking better --- ebos/eclfluxmoduleseq.hh | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/ebos/eclfluxmoduleseq.hh b/ebos/eclfluxmoduleseq.hh index 5f7e6ab38bf..61bfb4bb7de 100644 --- a/ebos/eclfluxmoduleseq.hh +++ b/ebos/eclfluxmoduleseq.hh @@ -387,7 +387,7 @@ protected: Evaluation trans = problem.transmissibility(elemCtx, interiorDofIdx_, exteriorDofIdx_); Scalar faceArea = scvf.area();//NB check definition of flux - + trans /= faceArea; // all calculations here is done for pr area // estimate the gravity correction: for performance reasons we use a simplified // approach for this flux module that assumes that gravity is constant and always // acts into the downwards direction. (i.e., no centrifuge experiments, sorry.) @@ -444,9 +444,14 @@ protected: // external at the depth of the internal one const Evaluation& rhoIn = intQuantsIn.fluidState().density(phaseIdx); Scalar rhoEx = Toolbox::value(intQuantsEx.fluidState().density(phaseIdx)); - Evaluation rhoAvg = (rhoIn + rhoEx)/2; - + Evaluation rhoAvg = (rhoIn + rhoEx)/2; headDiff[phaseIdx] = rhoAvg*(distZ*g); + + // also add capillary part + const Evaluation& pcIn = intQuantsIn.fluidState().pc(phaseIdx); + Scalar pcEx = Toolbox::value(intQuantsEx.fluidState().pc(phaseIdx)); + headDiff[phaseIdx] -= (pcIn-pcEx); + mob1[phaseIdx] = intQuantsIn.mobility(phaseIdx); mob2[phaseIdx] = Toolbox::value(intQuantsEx.mobility(phaseIdx)); } @@ -468,16 +473,20 @@ protected: if (!FluidSystem::phaseIsActive(phaseIdx)) continue; if(upwind[phaseIdx] > 0){ - if(linearizationType.type == Opm::LinearizationType::implicit){ - assert(upIdx_[phaseIdx] == interiorDofIdx_);//NB test for implicit + if(linearizationType.type == Opm::LinearizationType::implicit){ + if(not(pressureDifference_[phaseIdx] == 0.0)){ + assert(upIdx_[phaseIdx] == interiorDofIdx_);//NB test for implicit + } } upIdx_[phaseIdx] = interiorDofIdx_; dnIdx_[phaseIdx] = exteriorDofIdx_; fmob[phaseIdx] = mob1[phaseIdx]; fst[phaseIdx] = ST1; }else{ - if(linearizationType.type == Opm::LinearizationType::implicit){ - assert(upIdx_[phaseIdx] == exteriorDofIdx_);//NB test for implicit + if(linearizationType.type == Opm::LinearizationType::implicit){ + if(not(pressureDifference_[phaseIdx] == 0.0)){ + assert(upIdx_[phaseIdx] == exteriorDofIdx_);//NB test for implicit + } } upIdx_[phaseIdx] = exteriorDofIdx_; dnIdx_[phaseIdx] = interiorDofIdx_; @@ -501,7 +510,7 @@ protected: mobG = mobG + fmob[phaseIdx]*(headDiff[phaseIdx] - headDiff[phaseIdx1]); } } - Evaluation pFlux = (1.0/mobT) * (totalFlux_ + trans * mobG); + Evaluation pFlux = fmob[phaseIdx]*(1.0/mobT) * (totalFlux_ + trans * mobG); if(linearizationType.type == Opm::LinearizationType::implicit){ assert(pFlux == volumeFlux_[phaseIdx]); // for testing code in fully implit mode } From b6b40f111937dc4997def5d88aa249b7e4ce7b57 Mon Sep 17 00:00:00 2001 From: hnil Date: Tue, 9 Jun 2020 20:47:24 +0200 Subject: [PATCH 12/93] seems to be correct with for test without capillary and gravity --- ebos/eclfluxmoduleseq.hh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ebos/eclfluxmoduleseq.hh b/ebos/eclfluxmoduleseq.hh index 61bfb4bb7de..b2ad85cfd72 100644 --- a/ebos/eclfluxmoduleseq.hh +++ b/ebos/eclfluxmoduleseq.hh @@ -450,7 +450,7 @@ protected: // also add capillary part const Evaluation& pcIn = intQuantsIn.fluidState().pc(phaseIdx); Scalar pcEx = Toolbox::value(intQuantsEx.fluidState().pc(phaseIdx)); - headDiff[phaseIdx] -= (pcIn-pcEx); + headDiff[phaseIdx] += (pcIn-pcEx); mob1[phaseIdx] = intQuantsIn.mobility(phaseIdx); mob2[phaseIdx] = Toolbox::value(intQuantsEx.mobility(phaseIdx)); @@ -507,12 +507,12 @@ protected: Evaluation mobG = 0; for (unsigned phaseIdx1=0; phaseIdx1 < numPhases; phaseIdx1++) { if( not(phaseIdx == phaseIdx1) ){ - mobG = mobG + fmob[phaseIdx]*(headDiff[phaseIdx] - headDiff[phaseIdx1]); + mobG = mobG + fmob[phaseIdx1]*(headDiff[phaseIdx] - headDiff[phaseIdx1]); } } Evaluation pFlux = fmob[phaseIdx]*(1.0/mobT) * (totalFlux_ + trans * mobG); if(linearizationType.type == Opm::LinearizationType::implicit){ - assert(pFlux == volumeFlux_[phaseIdx]); // for testing code in fully implit mode + assert(Toolbox::isSame(pFlux,volumeFlux_[phaseIdx],1e-6)); // for testing code in fully implit mode } volumeFlux_[phaseIdx] = fst[phaseIdx] * pFlux; } From 039450acb4c5e84d3172339541520041fde41020 Mon Sep 17 00:00:00 2001 From: hnil Date: Wed, 10 Jun 2020 15:57:43 +0200 Subject: [PATCH 13/93] added pressure and total saturation to eclproblem. better checking of flux module --- ebos/eclfluxmoduleseq.hh | 5 +++- ebos/eclproblem.hh | 61 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/ebos/eclfluxmoduleseq.hh b/ebos/eclfluxmoduleseq.hh index b2ad85cfd72..42c5b631812 100644 --- a/ebos/eclfluxmoduleseq.hh +++ b/ebos/eclfluxmoduleseq.hh @@ -475,6 +475,7 @@ protected: if(upwind[phaseIdx] > 0){ if(linearizationType.type == Opm::LinearizationType::implicit){ if(not(pressureDifference_[phaseIdx] == 0.0)){ + // check faild in non significant flow assert(upIdx_[phaseIdx] == interiorDofIdx_);//NB test for implicit } } @@ -485,6 +486,7 @@ protected: }else{ if(linearizationType.type == Opm::LinearizationType::implicit){ if(not(pressureDifference_[phaseIdx] == 0.0)){ + // check faild in non significant flow assert(upIdx_[phaseIdx] == exteriorDofIdx_);//NB test for implicit } } @@ -511,7 +513,8 @@ protected: } } Evaluation pFlux = fmob[phaseIdx]*(1.0/mobT) * (totalFlux_ + trans * mobG); - if(linearizationType.type == Opm::LinearizationType::implicit){ + if(linearizationType.type == Opm::LinearizationType::implicit){ + // Does this test derivatives?? assert(Toolbox::isSame(pFlux,volumeFlux_[phaseIdx],1e-6)); // for testing code in fully implit mode } volumeFlux_[phaseIdx] = fst[phaseIdx] * pFlux; diff --git a/ebos/eclproblem.hh b/ebos/eclproblem.hh index ae4241c0ec4..d4bfa0ce2cb 100644 --- a/ebos/eclproblem.hh +++ b/ebos/eclproblem.hh @@ -689,7 +689,9 @@ public: lastRv_.resize(numDof, 0.0); maxOilSaturation_.resize(numDof, 0.0); } - + pressure_.resize(numDof, 0.0); + totalSaturation_.resize(numDof, 1.0); + updateElementDepths_(); readRockParameters_(); readMaterialParameters_(); @@ -905,6 +907,7 @@ public: // used when ROCKCOMP is activated const bool invalidateFromMaxWaterSat = updateMaxWaterSaturation_(); const bool invalidateFromMinPressure = updateMinPressure_(); + updatePressure_();//update stored pressure in case of sequential do not need to recalculate chach invalidateIntensiveQuantities = invalidateFromMaxWaterSat || invalidateFromMinPressure; if (invalidateIntensiveQuantities) @@ -1760,7 +1763,21 @@ public: return minOilPressure_[globalDofIdx]; } - + /*! + * \brief Returns an element's pressure of the oil phase that was at the begining + * of the timestep need for sequential + * + */ + Scalar pressure(unsigned globalDofIdx,unsigned phaseIndex) const + { + // phase index is unused for now will give warning in compilation + return pressure_[globalDofIdx]; + } + Scalar totalSaturation(unsigned globalDofIdx) const + { + return totalSaturation_[globalDofIdx]; + } + /*! * \brief Returns a reference to the ECL well manager used by the problem. * @@ -1908,7 +1925,13 @@ public: return overburdenPressure_[elementIdx]; } - + /*! + * \brief update pressure and totalSaturation + * update copy of pressure and total saturation for sequential solve + */ + bool updatePressure(){ + this->updatePressure_(); + } private: void checkDeckCompatibility_() const @@ -2171,6 +2194,36 @@ private: return true; } + bool updatePressure_() + { + + ElementContext elemCtx(this->simulator()); + const auto& vanguard = this->simulator().vanguard(); + auto elemIt = vanguard.gridView().template begin(); + const auto& elemEndIt = vanguard.gridView().template end(); + for (; elemIt != elemEndIt; ++elemIt) { + const Element& elem = *elemIt; + + elemCtx.updatePrimaryStencil(elem); + elemCtx.updatePrimaryIntensiveQuantities(/*timeIdx=*/0); + + unsigned compressedDofIdx = elemCtx.globalSpaceIndex(/*spaceIdx=*/0, /*timeIdx=*/0); + const auto& iq = elemCtx.intensiveQuantities(/*spaceIdx=*/0, /*timeIdx=*/0); + const auto& fs = iq.fluidState(); + + if (FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)) { + pressure_[compressedDofIdx] = Opm::getValue(fs.pressure(oilPhaseIdx)); + }else if( FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)){ + pressure_[compressedDofIdx] = Opm::getValue(fs.pressure(gasPhaseIdx)); + }else{ + pressure_[compressedDofIdx] = Opm::getValue(fs.pressure(waterPhaseIdx)); + } + totalSaturation_[compressedDofIdx] = Opm::getValue(fs.totalSaturation()); + } + + return true; + } + void readRockParameters_() { const auto& simulator = this->simulator(); @@ -3077,6 +3130,8 @@ private: std::vector maxWaterSaturation_; std::vector overburdenPressure_; std::vector minOilPressure_; + std::vector pressure_; + std::vector totalSaturation_; std::vector rockCompPoroMult_; std::vector rockCompTransMult_; From 59807d76847f0543396bfb1b4788907675032580 Mon Sep 17 00:00:00 2001 From: hnil Date: Wed, 10 Jun 2020 15:58:26 +0200 Subject: [PATCH 14/93] added pressure as type to convergenceReport --- opm/simulators/timestepping/ConvergenceReport.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opm/simulators/timestepping/ConvergenceReport.hpp b/opm/simulators/timestepping/ConvergenceReport.hpp index 2e0ee3157d8..7b173d31068 100644 --- a/opm/simulators/timestepping/ConvergenceReport.hpp +++ b/opm/simulators/timestepping/ConvergenceReport.hpp @@ -48,7 +48,7 @@ namespace Opm class ReservoirFailure { public: - enum struct Type { Invalid, MassBalance, Cnv }; + enum struct Type { Invalid, MassBalance, Cnv , Pressure}; ReservoirFailure(Type t, Severity s, int phase) : type_(t), severity_(s), phase_(phase) { From f249701849317350fc474356ac858c1781a1f54b Mon Sep 17 00:00:00 2001 From: hnil Date: Wed, 10 Jun 2020 15:59:03 +0200 Subject: [PATCH 15/93] added update of varibles in case timestepping is changed from step to step adde pure pressure step --- opm/simulators/flow/NonlinearSolverEbos.hpp | 31 +++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/opm/simulators/flow/NonlinearSolverEbos.hpp b/opm/simulators/flow/NonlinearSolverEbos.hpp index 3695ac34cdf..336ce8b8683 100644 --- a/opm/simulators/flow/NonlinearSolverEbos.hpp +++ b/opm/simulators/flow/NonlinearSolverEbos.hpp @@ -147,17 +147,27 @@ namespace Opm { } } + + SimulatorReportSingle stepSequential(const SimulatorTimerInterface& timer){ LinearizationType linearizationType; bool converged = false; SimulatorReportSingle reportpre; SimulatorReportSingle reportseq; while(not converged){ + // do pressure step linearizationType.type = Opm::LinearizationType::pressure; + model_->ebosSimulator().problem().updatePressure();//update pressure ans ST model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); + model_->updateSolution();// should conver to the new solution time SimulatorReportSingle lreportpre = this->stepDefault(timer); + + // do transport step + model_->ebosSimulator().problem().updatePressure();//update pressure ans ST linearizationType.type = Opm::LinearizationType::seqtransport; model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); + + model_->updateSolution(); SimulatorReportSingle lreportseq = this->stepDefault(timer); reportpre += lreportpre; reportseq += lreportseq; @@ -170,9 +180,30 @@ namespace Opm { } + SimulatorReportSingle stepPressure(const SimulatorTimerInterface& timer){ + LinearizationType linearizationType; + bool converged = false; + SimulatorReportSingle reportpre; + // do pressure step + linearizationType.type = Opm::LinearizationType::pressure; + model_->ebosSimulator().problem().updatePressure();//update pressure ans ST + model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); + model_->updateSolution();// should conver to the new solution time + SimulatorReportSingle lreportpre = this->stepDefault(timer); + SimulatorReportSingle report = lreportpre; + //todo fill this report correctly + return report; + + } + + + SimulatorReportSingle stepFull(const SimulatorTimerInterface& timer){ LinearizationType linearizationType;// use default model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); + // incase previous step was not fully implicit + model_->ebosSimulator().problem().updatePressure();//update pressure ans ST + model_->updateSolution(); SimulatorReportSingle report = this->stepDefault(timer); return report; } From 542ad82ebcae22d11c7b2cb8e9ce1faba26028ea Mon Sep 17 00:00:00 2001 From: hnil Date: Wed, 10 Jun 2020 16:00:11 +0200 Subject: [PATCH 16/93] added pressure convergence criteria --- opm/simulators/flow/BlackoilModelEbos.hpp | 71 +++++++++++++++++++---- 1 file changed, 61 insertions(+), 10 deletions(-) diff --git a/opm/simulators/flow/BlackoilModelEbos.hpp b/opm/simulators/flow/BlackoilModelEbos.hpp index fe1f89d501d..012617127ec 100644 --- a/opm/simulators/flow/BlackoilModelEbos.hpp +++ b/opm/simulators/flow/BlackoilModelEbos.hpp @@ -207,7 +207,7 @@ namespace Opm { ebosSimulator_.setTimeStepSize(timer.currentStepLength()); ebosSimulator_.problem().beginTimeStep(); - unsigned numDof = ebosSimulator_.model().numGridDof(); + unsigned numDof = ebosSimulator_.model().numGridDof(); wasSwitched_.resize(numDof); std::fill(wasSwitched_.begin(), wasSwitched_.end(), false); @@ -486,14 +486,7 @@ namespace Opm { int pressureVarIndex=1; // true impes case could add case with trivial weighs i equations is modifind with weights // this would make a newton based method if derivative of the weights are takein into account - BVector weights(x.size()); - ElementContext elemCtx(ebosSimulator_); - typedef typename GET_PROP_TYPE(TypeTag, ThreadManager) ThreadManager; - Opm::Amg::getTrueImpesWeights(pressureVarIndex, - weights, - ebosSimulator_.vanguard().gridView(), - elemCtx, ebosSimulator_.model(), - ThreadManager::threadId()); + BVector weights = this->getPressureWeights(pressureVarIndex); PressureMatrixType pmatrix = PressureHelper::makePressureMatrixupdateSolution(); + } /// Apply an update to the primary variables. void updateSolution(const BVector& dx) @@ -862,6 +859,54 @@ namespace Opm { return report; } + BVector getPressureWeights(int pressureVarIndex){ + size_t nocells = ebosSimulator_.model().linearizer().residual().size(); + BVector weights(nocells); + ElementContext elemCtx(ebosSimulator_); + typedef typename GET_PROP_TYPE(TypeTag, ThreadManager) ThreadManager; + Opm::Amg::getTrueImpesWeights(pressureVarIndex, + weights, + ebosSimulator_.vanguard().gridView(), + elemCtx, ebosSimulator_.model(), + ThreadManager::threadId()); + return weights; + + } + + ConvergenceReport getPressureConvergence(const int iteration) + { + //should be globaly defined + int pressureVarIndex = 1; + BVector weights = this->getPressureWeights(pressureVarIndex); + const auto& ebosResid = ebosSimulator_.model().linearizer().residual(); + double norm=0.0; + for(size_t i = 0; i< weights.size(); i++){ + auto& wb = weights[i]; + auto& resb= ebosResid[i]; + double lnorm=0.0; + for(int j = 0; j< wb.size(); j++){ + lnorm += wb[j]*resb[j]; + } + norm = std::max(lnorm,norm); + } + std::ostringstream ss; + ss << "Iteration " << iteration << "Norm of pressure equation " << norm; + OpmLog::info(ss.str()); + // NB need better convergence criteria + const double tol_cnv = param_.tolerance_cnv_; + bool converged = norm < tol_cnv; + ConvergenceReport report; + + if(not(converged)){ + ConvergenceReport::ReservoirFailure rv( + ConvergenceReport::ReservoirFailure::Type::Pressure, + ConvergenceReport::Severity::Normal, -1); + report.setReservoirFailed(rv); + } + //report.converged = converged; + return report; + } + /// Compute convergence based on total mass balance (tol_mb) and maximum /// residual mass balance (tol_cnv). /// \param[in] timer simulation timer @@ -874,6 +919,12 @@ namespace Opm { // Get convergence reports for reservoir and wells. std::vector B_avg(numEq, 0.0); auto report = getReservoirConvergence(timer.currentStepLength(), iteration, B_avg, residual_norms); + + // overwrite the convergence report if it is a pressure solve + if(ebosSimulator_.model().linearizer().getLinearizationType().type == Opm::LinearizationType::pressure){ + report = getPressureConvergence(iteration); + } + report += wellModel().getWellConvergence(B_avg); return report; From 51e34ffdb317bd8bc1fb0a46968f7426872fe5eb Mon Sep 17 00:00:00 2001 From: hnil Date: Wed, 10 Jun 2020 23:03:04 +0200 Subject: [PATCH 17/93] added storage of totalflux fixed recusive error --- ebos/eclfluxmoduleseq.hh | 26 ++++++++---- ebos/eclproblem.hh | 52 ++++++++++++++++++++--- opm/simulators/flow/BlackoilModelEbos.hpp | 2 +- 3 files changed, 66 insertions(+), 14 deletions(-) diff --git a/ebos/eclfluxmoduleseq.hh b/ebos/eclfluxmoduleseq.hh index 42c5b631812..bad83a9ddd4 100644 --- a/ebos/eclfluxmoduleseq.hh +++ b/ebos/eclfluxmoduleseq.hh @@ -180,6 +180,12 @@ public: return volumeFlux_[phaseIdx]; } + const Evaluation& totalFlux() const + { + return totalFlux_; + } + + protected: /*! * \brief Returns the local index of the degree of freedom in which is @@ -457,6 +463,15 @@ protected: } Evaluation ST1 = intQuantsIn.fluidState().totalSaturation(); Evaluation ST2 = Toolbox::value(intQuantsEx.fluidState().totalSaturation()); + Evaluation totalflux; + if(linearizationType.type == Opm::LinearizationType::seqtransport){ + unsigned gIdx = elemCtx.globalSpaceIndex(/*spaceIdx=*/0, /*timeIdx=*/0); + //const auto& problem = elemCtx.problem(); + double flux = problem.totalFlux(gIdx, scvfIdx); + totalflux = flux; + }else{ + totalflux = totalFlux_; + } std::array upwind; connectionMultiPhaseUpwind(upwind, @@ -464,7 +479,7 @@ protected: mob1, mob2, trans, - totalFlux_);//NB! taken from the object it self.. + totalflux);//NB! taken from the object it self.. Evaluation fmob[numPhases];//upwind weighted total saturation Evaluation fst[numPhases];// upwindweighted total saturation @@ -497,12 +512,7 @@ protected: } mobT += fmob[phaseIdx]; } - if(linearizationType.type == Opm::LinearizationType::seqtransport){ - //needed? where should volumeFlux_ should probably be a scalar - totalFlux_ = Toolbox::value(totalFlux_); - } - - + for (unsigned phaseIdx=0; phaseIdx < numPhases; phaseIdx++) { if (!FluidSystem::phaseIsActive(phaseIdx)) continue; @@ -512,7 +522,7 @@ protected: mobG = mobG + fmob[phaseIdx1]*(headDiff[phaseIdx] - headDiff[phaseIdx1]); } } - Evaluation pFlux = fmob[phaseIdx]*(1.0/mobT) * (totalFlux_ + trans * mobG); + Evaluation pFlux = fmob[phaseIdx]*(1.0/mobT) * (totalflux + trans * mobG); if(linearizationType.type == Opm::LinearizationType::implicit){ // Does this test derivatives?? assert(Toolbox::isSame(pFlux,volumeFlux_[phaseIdx],1e-6)); // for testing code in fully implit mode diff --git a/ebos/eclproblem.hh b/ebos/eclproblem.hh index d4bfa0ce2cb..33670ffebc0 100644 --- a/ebos/eclproblem.hh +++ b/ebos/eclproblem.hh @@ -907,7 +907,7 @@ public: // used when ROCKCOMP is activated const bool invalidateFromMaxWaterSat = updateMaxWaterSaturation_(); const bool invalidateFromMinPressure = updateMinPressure_(); - updatePressure_();//update stored pressure in case of sequential do not need to recalculate chach + updatePressure();//update stored pressure in case of sequential do not need to recalculate chach invalidateIntensiveQuantities = invalidateFromMaxWaterSat || invalidateFromMinPressure; if (invalidateIntensiveQuantities) @@ -1777,7 +1777,13 @@ public: { return totalSaturation_[globalDofIdx]; } - + + Scalar totalFlux(unsigned globalIndex,unsigned loc_index) const{ + //unsigned globalIndx = elemCtx.globalSpaceIndex(/*spaceIdx=*/0, /*timeIdx=*/0); + //for (unsigned scvfIdx = 0; scvfIdx < numInteriorFaces; scvfIdx++) { + return totalFlux_[globalIndex][loc_index]; + } + /*! * \brief Returns a reference to the ECL well manager used by the problem. * @@ -1931,6 +1937,7 @@ public: */ bool updatePressure(){ this->updatePressure_(); + this->updateFluxes_(); } private: @@ -2195,8 +2202,7 @@ private: } bool updatePressure_() - { - + { ElementContext elemCtx(this->simulator()); const auto& vanguard = this->simulator().vanguard(); auto elemIt = vanguard.gridView().template begin(); @@ -2883,7 +2889,7 @@ private: { Opm::ConditionalStorage thermalHalfTrans; Scalar transmissibility; - }; + }; // update the prefetch friendly data object void updatePffDofData_() @@ -2909,6 +2915,41 @@ private: pffDofData_.update(distFn); } + + + void updateFluxes_(){ + const auto& vanguard = this->simulator().vanguard(); + unsigned numElems = vanguard.gridView().size(/*codim=*/0); + totalFlux_.resize(numElems); + ElementContext elemCtx(this->simulator()); + auto elemIt = vanguard.gridView().template begin(); + const auto& elemEndIt = vanguard.gridView().template end(); + for (; elemIt != elemEndIt; ++elemIt) { + const Element& elem = *elemIt; + + //elemCtx.updatePrimaryStencil(elem); + //elemCtx.updatePrimaryIntensiveQuantities(/*timeIdx=*/0); + elemCtx.updateStencil(elem); + elemCtx.updateAllIntensiveQuantities(); + elemCtx.updateAllExtensiveQuantities(); + unsigned compressedDofIdx = elemCtx.globalSpaceIndex(/*spaceIdx=*/0, /*timeIdx=*/0); + //const auto& stencil = elemCtx.stencil(timeIdx); + size_t numInteriorFaces = elemCtx.numInteriorFaces(/*timeIdx*/ 0); + totalFlux_[compressedDofIdx].resize(numInteriorFaces); + for (unsigned scvfIdx = 0; scvfIdx < numInteriorFaces; scvfIdx++) { + /* + const auto& face = stencil.interiorFace(scvfIdx); + unsigned i = face.interiorIndex(); + unsigned j = face.exteriorIndex(); + */ + const auto& extQuants = elemCtx.extensiveQuantities(scvfIdx, /*timeIdx*/ 0); + // this is what I want + const auto& totalflux = extQuants.totalFlux(); + totalFlux_[compressedDofIdx][scvfIdx] = Toolbox::value(totalflux); + } + } + } + void readBoundaryConditions_() { nonTrivialBoundaryConditions_ = false; @@ -3132,6 +3173,7 @@ private: std::vector minOilPressure_; std::vector pressure_; std::vector totalSaturation_; + std::vector< std::vector > totalFlux_; std::vector rockCompPoroMult_; std::vector rockCompTransMult_; diff --git a/opm/simulators/flow/BlackoilModelEbos.hpp b/opm/simulators/flow/BlackoilModelEbos.hpp index 012617127ec..6e4fb0581f4 100644 --- a/opm/simulators/flow/BlackoilModelEbos.hpp +++ b/opm/simulators/flow/BlackoilModelEbos.hpp @@ -549,7 +549,7 @@ namespace Opm { void updateSolution(){ unsigned numDof = ebosSimulator_.model().numGridDof(); BVector dx(numDof,0); - this->updateSolution(); + this->updateSolution(dx); } /// Apply an update to the primary variables. From fde90a6cca64c98151b1de4607a7c70dc8992abd Mon Sep 17 00:00:00 2001 From: hnil Date: Thu, 11 Jun 2020 07:20:46 +0200 Subject: [PATCH 18/93] added totalFlux for compatibility, need to remove all calles in flow... --- ebos/eclfluxmodule.hh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ebos/eclfluxmodule.hh b/ebos/eclfluxmodule.hh index eb8f7d37248..30ae119675b 100644 --- a/ebos/eclfluxmodule.hh +++ b/ebos/eclfluxmodule.hh @@ -171,6 +171,10 @@ public: const Evaluation& volumeFlux(unsigned phaseIdx) const { return volumeFlux_[phaseIdx]; } + const Evaluation& totalFlux() const{ + throw std::invalid_argument("The ECL transmissibility module does not provide totalflux: see totalfluxupwind.hh"); + } + protected: /*! * \brief Returns the local index of the degree of freedom in which is From aa2c87b7db6f158a13c2f80c533bc5c29ebf453d Mon Sep 17 00:00:00 2001 From: hnil Date: Thu, 11 Jun 2020 09:26:25 +0200 Subject: [PATCH 19/93] added SimulationType --- .../flow/BlackoilModelParametersEbos.hpp | 6 +- opm/simulators/flow/NonlinearSolverEbos.hpp | 178 +++++++++--------- .../timestepping/AdaptiveTimeSteppingEbos.hpp | 2 +- 3 files changed, 100 insertions(+), 86 deletions(-) diff --git a/opm/simulators/flow/BlackoilModelParametersEbos.hpp b/opm/simulators/flow/BlackoilModelParametersEbos.hpp index c006de576d4..5d89f21489e 100644 --- a/opm/simulators/flow/BlackoilModelParametersEbos.hpp +++ b/opm/simulators/flow/BlackoilModelParametersEbos.hpp @@ -22,7 +22,8 @@ #include #include - +#include +#include #include namespace Opm::Properties { @@ -46,6 +47,7 @@ NEW_PROP_TAG(UpdateEquationsScaling); NEW_PROP_TAG(UseUpdateStabilization); NEW_PROP_TAG(MatrixAddWellContributions); NEW_PROP_TAG(EnableWellOperabilityCheck); +NEW_PROP_TAG(SimulationType); // parameters for multisegment wells NEW_PROP_TAG(TolerancePressureMsWells); @@ -84,6 +86,7 @@ SET_INT_PROP(FlowModelParameters, MaxInnerIterWells, 50); SET_INT_PROP(FlowModelParameters, StrictInnerIterMsWells, 40); SET_SCALAR_PROP(FlowModelParameters, RegularizationFactorMsw, 1); SET_BOOL_PROP(FlowModelParameters, EnableWellOperabilityCheck, true); +SET_STRING_PROP(FlowModelParameters, SimulationType, "implicit"); SET_SCALAR_PROP(FlowModelParameters, RelaxedFlowTolInnerIterMsw, 1); SET_SCALAR_PROP(FlowModelParameters, RelaxedPressureTolInnerIterMsw, 0.5e5); @@ -245,6 +248,7 @@ namespace Opm EWOMS_REGISTER_PARAM(TypeTag, bool, UseUpdateStabilization, "Try to detect and correct oscillations or stagnation during the Newton method"); EWOMS_REGISTER_PARAM(TypeTag, bool, MatrixAddWellContributions, "Explicitly specify the influences of wells between cells in the Jacobian and preconditioner matrices"); EWOMS_REGISTER_PARAM(TypeTag, bool, EnableWellOperabilityCheck, "Enable the well operability checking"); + EWOMS_REGISTER_PARAM(TypeTag, std::string, SimulationType, "Define simulation type: default implicit"); } }; } // namespace Opm diff --git a/opm/simulators/flow/NonlinearSolverEbos.hpp b/opm/simulators/flow/NonlinearSolverEbos.hpp index 336ce8b8683..0046785a36c 100644 --- a/opm/simulators/flow/NonlinearSolverEbos.hpp +++ b/opm/simulators/flow/NonlinearSolverEbos.hpp @@ -20,7 +20,7 @@ #ifndef OPM_NON_LINEAR_SOLVER_EBOS_HPP #define OPM_NON_LINEAR_SOLVER_EBOS_HPP - +#include #include #include #include @@ -37,7 +37,6 @@ namespace Opm::Properties { NEW_TYPE_TAG(FlowNonLinearSolver); - NEW_PROP_TAG(NewtonMaxRelax); NEW_PROP_TAG(FlowNewtonMaxIterations); NEW_PROP_TAG(FlowNewtonMinIterations); @@ -179,90 +178,22 @@ namespace Opm { return report; } - - SimulatorReportSingle stepPressure(const SimulatorTimerInterface& timer){ - LinearizationType linearizationType; - bool converged = false; - SimulatorReportSingle reportpre; - // do pressure step - linearizationType.type = Opm::LinearizationType::pressure; - model_->ebosSimulator().problem().updatePressure();//update pressure ans ST - model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); - model_->updateSolution();// should conver to the new solution time - SimulatorReportSingle lreportpre = this->stepDefault(timer); - SimulatorReportSingle report = lreportpre; - //todo fill this report correctly - return report; - - } - - - - SimulatorReportSingle stepFull(const SimulatorTimerInterface& timer){ - LinearizationType linearizationType;// use default - model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); - // incase previous step was not fully implicit - model_->ebosSimulator().problem().updatePressure();//update pressure ans ST - model_->updateSolution(); - SimulatorReportSingle report = this->stepDefault(timer); - return report; - } - - - - SimulatorReportSingle stepDefault(const SimulatorTimerInterface& timer) - { - SimulatorReportSingle report; - report.global_time = timer.simulationTimeElapsed(); - report.timestep_length = timer.currentStepLength(); - - // Do model-specific once-per-step calculations. - model_->prepareStep(timer); - - int iteration = 0; - - // Let the model do one nonlinear iteration. - - // Set up for main solver loop. - bool converged = false; - - // ---------- Main nonlinear solver loop ---------- - do { - try { - // Do the nonlinear step. If we are in a converged state, the - // model will usually do an early return without an expensive - // solve, unless the minIter() count has not been reached yet. - auto iterReport = model_->nonlinearIteration(iteration, timer, *this); - iterReport.global_time = timer.simulationTimeElapsed(); - report += iterReport; - report.converged = iterReport.converged; - - converged = report.converged; - iteration += 1; - } - catch (...) { - // if an iteration fails during a time step, all previous iterations - // count as a failure as well - failureReport_ = report; - failureReport_ += model_->failureReport(); - throw; - } - } - while ( (!converged && (iteration <= maxIter())) || (iteration <= minIter())); - - if (!converged) { - failureReport_ = report; - - std::string msg = "Solver convergence failure - Failed to complete a time step within " + std::to_string(maxIter()) + " iterations."; - OPM_THROW_NOLOG(Opm::TooManyIterations, msg); + SimulatorReportSingle step(const SimulatorTimerInterface& timer){ + std::string simulationtype = EWOMS_GET_PARAM(TypeTag, std::string, SimulationType); + if(simulationtype == "implicit"){ + this->stepFull(timer); + }else if(simulationtype == "pressure"){ + this->stepPressure(timer); + }else if(simulationtype == "seqtransport"){ + this->stepSequential(timer); + }else if(simulationtype == "seqtransport"){ + this->stepSequential(timer); + }else{ + OPM_THROW(std::runtime_error, "No such simulation type"); } - - // Do model-specific post-step actions. - model_->afterStep(timer); - report.converged = true; - return report; + } - + /// return the statistics if the step() method failed const SimulatorReportSingle& failureReport() const { return failureReport_; } @@ -412,6 +343,85 @@ namespace Opm { { param_ = param; } private: + SimulatorReportSingle stepFull(const SimulatorTimerInterface& timer){ + LinearizationType linearizationType;// use default + model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); + // incase previous step was not fully implicit + model_->ebosSimulator().problem().updatePressure();//update pressure ans ST + model_->updateSolution(); + SimulatorReportSingle report = this->stepDefault(timer); + return report; + } + + SimulatorReportSingle stepPressure(const SimulatorTimerInterface& timer){ + LinearizationType linearizationType; + bool converged = false; + SimulatorReportSingle reportpre; + // do pressure step + linearizationType.type = Opm::LinearizationType::pressure; + model_->ebosSimulator().problem().updatePressure();//update pressure ans ST + model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); + model_->updateSolution();// should conver to the new solution time + SimulatorReportSingle lreportpre = this->stepDefault(timer); + SimulatorReportSingle report = lreportpre; + //todo fill this report correctly + return report; + + } + + SimulatorReportSingle stepDefault(const SimulatorTimerInterface& timer) + { + SimulatorReportSingle report; + report.global_time = timer.simulationTimeElapsed(); + report.timestep_length = timer.currentStepLength(); + + // Do model-specific once-per-step calculations. + model_->prepareStep(timer); + + int iteration = 0; + + // Let the model do one nonlinear iteration. + + // Set up for main solver loop. + bool converged = false; + + // ---------- Main nonlinear solver loop ---------- + do { + try { + // Do the nonlinear step. If we are in a converged state, the + // model will usually do an early return without an expensive + // solve, unless the minIter() count has not been reached yet. + auto iterReport = model_->nonlinearIteration(iteration, timer, *this); + iterReport.global_time = timer.simulationTimeElapsed(); + report += iterReport; + report.converged = iterReport.converged; + + converged = report.converged; + iteration += 1; + } + catch (...) { + // if an iteration fails during a time step, all previous iterations + // count as a failure as well + failureReport_ = report; + failureReport_ += model_->failureReport(); + throw; + } + } + while ( (!converged && (iteration <= maxIter())) || (iteration <= minIter())); + + if (!converged) { + failureReport_ = report; + + std::string msg = "Solver convergence failure - Failed to complete a time step within " + std::to_string(maxIter()) + " iterations."; + OPM_THROW_NOLOG(Opm::TooManyIterations, msg); + } + + // Do model-specific post-step actions. + model_->afterStep(timer); + report.converged = true; + return report; + } + // --------- Data members --------- SimulatorReportSingle failureReport_; SolverParameters param_; diff --git a/opm/simulators/timestepping/AdaptiveTimeSteppingEbos.hpp b/opm/simulators/timestepping/AdaptiveTimeSteppingEbos.hpp index a6f88b53674..4e9e5b9cec8 100644 --- a/opm/simulators/timestepping/AdaptiveTimeSteppingEbos.hpp +++ b/opm/simulators/timestepping/AdaptiveTimeSteppingEbos.hpp @@ -239,7 +239,7 @@ namespace Opm { SimulatorReportSingle substepReport; std::string causeOfFailure = ""; try { - substepReport = solver.stepFull(substepTimer); + substepReport = solver.step(substepTimer); if (solverVerbose_) { // report number of linear iterations OpmLog::debug("Overall linear iterations used: " + std::to_string(substepReport.total_linear_iterations)); From e5007f0adf370a2011d7487a40e927ff137ddd53 Mon Sep 17 00:00:00 2001 From: hnil Date: Thu, 11 Jun 2020 11:53:41 +0200 Subject: [PATCH 20/93] made pressure 3 vector --- ebos/eclproblem.hh | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/ebos/eclproblem.hh b/ebos/eclproblem.hh index 33670ffebc0..585d80fc7d3 100644 --- a/ebos/eclproblem.hh +++ b/ebos/eclproblem.hh @@ -689,7 +689,7 @@ public: lastRv_.resize(numDof, 0.0); maxOilSaturation_.resize(numDof, 0.0); } - pressure_.resize(numDof, 0.0); + pressure_.resize(numDof); totalSaturation_.resize(numDof, 1.0); updateElementDepths_(); @@ -1771,7 +1771,7 @@ public: Scalar pressure(unsigned globalDofIdx,unsigned phaseIndex) const { // phase index is unused for now will give warning in compilation - return pressure_[globalDofIdx]; + return pressure_[globalDofIdx][phaseIndex]; } Scalar totalSaturation(unsigned globalDofIdx) const { @@ -1936,8 +1936,12 @@ public: * update copy of pressure and total saturation for sequential solve */ bool updatePressure(){ - this->updatePressure_(); - this->updateFluxes_(); + LinearizationType linearizationType = this->simulator().model().linearizer().getLinearizationType(); + // maybe use simulation type instead + if(not(linearizationType.type == Opm::LinearizationType::implicit)){ + this->updatePressure_(); + this->updateFluxes_(); + } } private: @@ -2218,11 +2222,11 @@ private: const auto& fs = iq.fluidState(); if (FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)) { - pressure_[compressedDofIdx] = Opm::getValue(fs.pressure(oilPhaseIdx)); + pressure_[compressedDofIdx][oilPhaseIdx] = Opm::getValue(fs.pressure(oilPhaseIdx)); }else if( FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)){ - pressure_[compressedDofIdx] = Opm::getValue(fs.pressure(gasPhaseIdx)); + pressure_[compressedDofIdx][gasPhaseIdx] = Opm::getValue(fs.pressure(gasPhaseIdx)); }else{ - pressure_[compressedDofIdx] = Opm::getValue(fs.pressure(waterPhaseIdx)); + pressure_[compressedDofIdx][waterPhaseIdx] = Opm::getValue(fs.pressure(waterPhaseIdx)); } totalSaturation_[compressedDofIdx] = Opm::getValue(fs.totalSaturation()); } @@ -3171,7 +3175,7 @@ private: std::vector maxWaterSaturation_; std::vector overburdenPressure_; std::vector minOilPressure_; - std::vector pressure_; + std::vector< Dune::FieldVector > pressure_; std::vector totalSaturation_; std::vector< std::vector > totalFlux_; From a2ef74a88bc12382e2965d7f90126f446baa262e Mon Sep 17 00:00:00 2001 From: hnil Date: Thu, 11 Jun 2020 13:43:51 +0200 Subject: [PATCH 21/93] fixed missin report in step --- opm/simulators/flow/NonlinearSolverEbos.hpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/opm/simulators/flow/NonlinearSolverEbos.hpp b/opm/simulators/flow/NonlinearSolverEbos.hpp index 0046785a36c..87d9e1cda6c 100644 --- a/opm/simulators/flow/NonlinearSolverEbos.hpp +++ b/opm/simulators/flow/NonlinearSolverEbos.hpp @@ -180,18 +180,19 @@ namespace Opm { } SimulatorReportSingle step(const SimulatorTimerInterface& timer){ std::string simulationtype = EWOMS_GET_PARAM(TypeTag, std::string, SimulationType); + SimulatorReportSingle report; if(simulationtype == "implicit"){ - this->stepFull(timer); + report = this->stepFull(timer); }else if(simulationtype == "pressure"){ - this->stepPressure(timer); + report = this->stepPressure(timer); }else if(simulationtype == "seqtransport"){ - this->stepSequential(timer); + report = this->stepSequential(timer); }else if(simulationtype == "seqtransport"){ - this->stepSequential(timer); + report = this->stepSequential(timer); }else{ OPM_THROW(std::runtime_error, "No such simulation type"); } - + return report; } /// return the statistics if the step() method failed From 0f0410e089d3e3416f2e556265e43f6423d2a3a1 Mon Sep 17 00:00:00 2001 From: hnil Date: Thu, 11 Jun 2020 13:55:53 +0200 Subject: [PATCH 22/93] fixed upwind of ST and a whitespace in text --- ebos/eclfluxmoduleseq.hh | 2 +- opm/simulators/flow/BlackoilModelEbos.hpp | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/ebos/eclfluxmoduleseq.hh b/ebos/eclfluxmoduleseq.hh index bad83a9ddd4..3d08cc66508 100644 --- a/ebos/eclfluxmoduleseq.hh +++ b/ebos/eclfluxmoduleseq.hh @@ -508,7 +508,7 @@ protected: upIdx_[phaseIdx] = exteriorDofIdx_; dnIdx_[phaseIdx] = interiorDofIdx_; fmob[phaseIdx] = mob2[phaseIdx]; - fst[phaseIdx] = ST1; + fst[phaseIdx] = ST2; } mobT += fmob[phaseIdx]; } diff --git a/opm/simulators/flow/BlackoilModelEbos.hpp b/opm/simulators/flow/BlackoilModelEbos.hpp index 6e4fb0581f4..58a543b974e 100644 --- a/opm/simulators/flow/BlackoilModelEbos.hpp +++ b/opm/simulators/flow/BlackoilModelEbos.hpp @@ -477,7 +477,6 @@ namespace Opm { void solveJacobianSystem(BVector& x) { if(ebosSimulator_.model().linearizer().getLinearizationType().type == Opm::LinearizationType::pressure){ - OPM_THROW(Opm::NumericalIssue, "Not implemented!"); auto& ebosJac = ebosSimulator_.model().linearizer().jacobian(); auto& ebosResid = ebosSimulator_.model().linearizer().residual(); // NB when tested the linear solver an the martrix could be part of linearizer @@ -890,7 +889,7 @@ namespace Opm { norm = std::max(lnorm,norm); } std::ostringstream ss; - ss << "Iteration " << iteration << "Norm of pressure equation " << norm; + ss << "Iteration " << iteration << " Norm of pressure equation " << norm; OpmLog::info(ss.str()); // NB need better convergence criteria const double tol_cnv = param_.tolerance_cnv_; From d1a877ca096791b50f175e8897fc8b397956a5dd Mon Sep 17 00:00:00 2001 From: hnil Date: Fri, 12 Jun 2020 11:26:35 +0200 Subject: [PATCH 23/93] added writing of pressure system, fixed solving of pressure --- ebos/eclproblem.hh | 3 +++ opm/simulators/flow/BlackoilModelEbos.hpp | 18 ++++++++++++------ opm/simulators/flow/NonlinearSolverEbos.hpp | 1 - .../linalg/WriteSystemMatrixHelper.hpp | 8 +++++--- 4 files changed, 20 insertions(+), 10 deletions(-) diff --git a/ebos/eclproblem.hh b/ebos/eclproblem.hh index 585d80fc7d3..48d8b123497 100644 --- a/ebos/eclproblem.hh +++ b/ebos/eclproblem.hh @@ -1938,10 +1938,13 @@ public: bool updatePressure(){ LinearizationType linearizationType = this->simulator().model().linearizer().getLinearizationType(); // maybe use simulation type instead + bool updated = false; if(not(linearizationType.type == Opm::LinearizationType::implicit)){ this->updatePressure_(); this->updateFluxes_(); + updated = true; } + return updated; } private: diff --git a/opm/simulators/flow/BlackoilModelEbos.hpp b/opm/simulators/flow/BlackoilModelEbos.hpp index 58a543b974e..4a22490aed8 100644 --- a/opm/simulators/flow/BlackoilModelEbos.hpp +++ b/opm/simulators/flow/BlackoilModelEbos.hpp @@ -502,24 +502,30 @@ namespace Opm { extractParallelGridInformationToISTL(ebosSimulator_.vanguard().grid(), parallelInformation); #if HAVE_MPI using Communication = Dune::OwnerOverlapCopyCommunication; - Communication comm; + std::unique_ptr comm; if (parallelInformation_.type() == typeid(ParallelISTLInformation)) { // Parallel case. const ParallelISTLInformation* parinfo = std::any_cast(¶llelInformation_); assert(parinfo); - comm = Communication(parinfo->communicator()); + comm.reset(new Communication(parinfo->communicator())); } #else using Communication = Dune::Amg::SequentialInformation; // Dummy type - Communication comm; + std::unique_ptr comm; #endif std::function weightsCalculator;// dummy - Dune::FlexibleSolver pressureSolver(prm,pmatrix, weightsCalculator, comm); + Dune::FlexibleSolver pressureSolver(prm,pmatrix, weightsCalculator, *comm); PressureVectorType xp(x.size(),0); Dune::InverseOperatorResult res; - pressureSolver.apply(rhs, xp, res); + pressureSolver.apply(xp,rhs, res); + Opm::Helper::writeSystem(this->ebosSimulator_, //simulator is only used to get names + pmatrix, + rhs, + comm.get(), + std::string("pressure_") + ); x=0; PressureHelper::movePressureToBlock(x, xp, pressureVarIndex); // set initial guess @@ -883,7 +889,7 @@ namespace Opm { auto& wb = weights[i]; auto& resb= ebosResid[i]; double lnorm=0.0; - for(int j = 0; j< wb.size(); j++){ + for(size_t j = 0; j< wb.size(); j++){ lnorm += wb[j]*resb[j]; } norm = std::max(lnorm,norm); diff --git a/opm/simulators/flow/NonlinearSolverEbos.hpp b/opm/simulators/flow/NonlinearSolverEbos.hpp index 87d9e1cda6c..9fc3ecc3af0 100644 --- a/opm/simulators/flow/NonlinearSolverEbos.hpp +++ b/opm/simulators/flow/NonlinearSolverEbos.hpp @@ -356,7 +356,6 @@ namespace Opm { SimulatorReportSingle stepPressure(const SimulatorTimerInterface& timer){ LinearizationType linearizationType; - bool converged = false; SimulatorReportSingle reportpre; // do pressure step linearizationType.type = Opm::LinearizationType::pressure; diff --git a/opm/simulators/linalg/WriteSystemMatrixHelper.hpp b/opm/simulators/linalg/WriteSystemMatrixHelper.hpp index 22772bc9a0a..ccfbc2fb611 100644 --- a/opm/simulators/linalg/WriteSystemMatrixHelper.hpp +++ b/opm/simulators/linalg/WriteSystemMatrixHelper.hpp @@ -32,7 +32,9 @@ namespace Helper void writeSystem(const SimulatorType& simulator, const MatrixType& matrix, const VectorType& rhs, - [[maybe_unused]] const Communicator* comm) + [[maybe_unused]] const Communicator* comm, + std::string ename = std::string("") + ) { std::string dir = simulator.problem().outputDir(); if (dir == ".") { @@ -57,7 +59,7 @@ namespace Helper fs::path full_path = output_dir / output_file; std::string prefix = full_path.string(); { - std::string filename = prefix + "matrix_istl"; + std::string filename = prefix + ename + "matrix_istl"; #if HAVE_MPI if (comm != nullptr) { // comm is not set in serial runs Dune::storeMatrixMarket(matrix, filename, *comm, true); @@ -68,7 +70,7 @@ namespace Helper } } { - std::string filename = prefix + "rhs_istl"; + std::string filename = prefix + ename + "rhs_istl"; #if HAVE_MPI if (comm != nullptr) { // comm is not set in serial runs Dune::storeMatrixMarket(rhs, filename, *comm, true); From 73142e509289eb8c0795d29748134fead50bb722 Mon Sep 17 00:00:00 2001 From: hnil Date: Fri, 12 Jun 2020 14:40:44 +0200 Subject: [PATCH 24/93] fixed cmake file with new system --- CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 47f32ada710..1b01990c2ba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -287,6 +287,7 @@ opm_add_test(flow_blackoil_dunecpr_noflex ONLY_COMPILE DEFAULT_ENABLE_IF ${FLOW_VARIANTS_DEFAULT_ENABLE_IF} SOURCES flow/flow_blackoil_dunecpr_noflex.cpp + $ EXE_NAME flow_blackoil_dunecpr_noflex DEPENDS "opmsimulators" LIBRARIES "opmsimulators") @@ -295,6 +296,7 @@ opm_add_test(flow_blackoil_dunecpr_seq ONLY_COMPILE DEFAULT_ENABLE_IF ${FLOW_VARIANTS_DEFAULT_ENABLE_IF} SOURCES flow/flow_blackoil_dunecpr_seq.cpp + $ EXE_NAME flow_blackoil_dunecpr_seq DEPENDS "opmsimulators" LIBRARIES "opmsimulators") From 417a7e7f75922796c72098b6bf25144335458cba Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Fri, 12 Jun 2020 14:50:19 +0200 Subject: [PATCH 25/93] fixing the parallel compilation related to parallelInformation_ --- opm/simulators/flow/BlackoilModelEbos.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/opm/simulators/flow/BlackoilModelEbos.hpp b/opm/simulators/flow/BlackoilModelEbos.hpp index 4a22490aed8..62d976958fb 100644 --- a/opm/simulators/flow/BlackoilModelEbos.hpp +++ b/opm/simulators/flow/BlackoilModelEbos.hpp @@ -503,9 +503,9 @@ namespace Opm { #if HAVE_MPI using Communication = Dune::OwnerOverlapCopyCommunication; std::unique_ptr comm; - if (parallelInformation_.type() == typeid(ParallelISTLInformation)) { + if (parallelInformation.type() == typeid(ParallelISTLInformation)) { // Parallel case. - const ParallelISTLInformation* parinfo = std::any_cast(¶llelInformation_); + const ParallelISTLInformation* parinfo = std::any_cast(¶llelInformation); assert(parinfo); comm.reset(new Communication(parinfo->communicator())); } From 9e9b46df76591e51c0cd195567ec714cfabc11f4 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Fri, 12 Jun 2020 10:01:20 +0200 Subject: [PATCH 26/93] adding assembleControlEqSeqTrans to StandardWell --- opm/simulators/wells/StandardWell.hpp | 3 +++ opm/simulators/wells/StandardWell_impl.hpp | 26 +++++++++++++++++++++- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/opm/simulators/wells/StandardWell.hpp b/opm/simulators/wells/StandardWell.hpp index cd39f62c113..92d50616215 100644 --- a/opm/simulators/wells/StandardWell.hpp +++ b/opm/simulators/wells/StandardWell.hpp @@ -545,6 +545,9 @@ namespace Opm const SummaryState& summary_state, DeferredLogger& deferred_logger) const; + // assembling the control equation for sequential transport solution + void assembleControlEqSeqTrans(const WellState& well_state); + }; } diff --git a/opm/simulators/wells/StandardWell_impl.hpp b/opm/simulators/wells/StandardWell_impl.hpp index 584ba98b0d0..ffd884b89d7 100644 --- a/opm/simulators/wells/StandardWell_impl.hpp +++ b/opm/simulators/wells/StandardWell_impl.hpp @@ -778,8 +778,12 @@ namespace Opm const auto& summaryState = ebosSimulator.vanguard().summaryState(); const Opm::Schedule& schedule = ebosSimulator.vanguard().schedule(); - assembleControlEq(well_state, schedule, summaryState, deferred_logger); + if(ebosSimulator.model().linearizer().getLinearizationType().type == Opm::LinearizationType::seqtransport) { + assembleControlEqSeqTrans(well_state); + } else { + assembleControlEq(well_state, schedule, summaryState, deferred_logger); + } // do the local inversion of D. try { @@ -794,6 +798,26 @@ namespace Opm + + template + void + StandardWell::assembleControlEqSeqTrans(const WellState& /* well_state */) + { + // TODO: we can get the current bhp value from well_state + // If the primary variables are well synchronized, they should have the same value. + EvalWell control_eq(numWellEq_ + numEq, 0.0); + const EvalWell& bhp = getBhp(); + control_eq = bhp - bhp.value(); + resWell_[0][Bhp] = control_eq.value(); + for (int pv_idx = 0; pv_idx < numWellEq_; ++pv_idx) { + invDuneD_[0][0][Bhp][pv_idx] = control_eq.derivative(pv_idx + numEq); + } + } + + + + + template void StandardWell::assembleControlEq(const WellState& well_state, From 995cbe1c41fed45cffe6f702f8f7de039720d579 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Fri, 12 Jun 2020 12:03:28 +0200 Subject: [PATCH 27/93] calculate the perforation reservoir rates and total reservoir rates. --- opm/simulators/wells/StandardWell.hpp | 26 +++++++-- opm/simulators/wells/StandardWell_impl.hpp | 58 +++++++++++---------- opm/simulators/wells/WellInterface.hpp | 6 +++ opm/simulators/wells/WellInterface_impl.hpp | 4 ++ 4 files changed, 64 insertions(+), 30 deletions(-) diff --git a/opm/simulators/wells/StandardWell.hpp b/opm/simulators/wells/StandardWell.hpp index 92d50616215..6b8b3396450 100644 --- a/opm/simulators/wells/StandardWell.hpp +++ b/opm/simulators/wells/StandardWell.hpp @@ -369,15 +369,35 @@ namespace Opm void computeWellConnectionPressures(const Simulator& ebosSimulator, const WellState& well_state); + struct PerfRates { + // surface perforation rates + std::vector cq_s; + // reservoir perforation rates + std::vector cq_r; + // reservor perfration total rates + EvalWell cq_r_t; + + double perf_dis_gas_rate; + + double perf_vap_oil_rate; + + PerfRates(int num_components, int num_welleq) + : cq_s(num_components, {num_welleq + numEq, 0.}) + , cq_r(num_components, {num_welleq + numEq, 0.}) + , cq_r_t(num_welleq + numEq, 0.) + , perf_dis_gas_rate(0.) + , perf_vap_oil_rate(0.) + { + } + }; + void computePerfRate(const IntensiveQuantities& intQuants, const std::vector& mob, const EvalWell& bhp, const double Tw, const int perf, const bool allow_cf, - std::vector& cq_s, - double& perf_dis_gas_rate, - double& perf_vap_oil_rate, + PerfRates& perf_rates, Opm::DeferredLogger& deferred_logger) const; void computeWellRatesWithBhp(const Simulator& ebosSimulator, diff --git a/opm/simulators/wells/StandardWell_impl.hpp b/opm/simulators/wells/StandardWell_impl.hpp index ffd884b89d7..f3d26a2e613 100644 --- a/opm/simulators/wells/StandardWell_impl.hpp +++ b/opm/simulators/wells/StandardWell_impl.hpp @@ -350,11 +350,12 @@ namespace Opm const double Tw, const int perf, const bool allow_cf, - std::vector& cq_s, - double& perf_dis_gas_rate, - double& perf_vap_oil_rate, + PerfRates& perf_rates, Opm::DeferredLogger& deferred_logger) const { + auto& cq_s = perf_rates.cq_s; + auto& cq_r = perf_rates.cq_r; + auto& cq_r_t = perf_rates.cq_r_t; const auto& fs = intQuants.fluidState(); const EvalWell pressure = extendEval(getPerfCellPressure(fs)); @@ -393,7 +394,9 @@ namespace Opm // compute component volumetric rates at standard conditions for (int componentIdx = 0; componentIdx < num_components_; ++componentIdx) { const EvalWell cq_p = - Tw * (mob[componentIdx] * drawdown); - cq_s[componentIdx] = b_perfcells_dense[componentIdx] * cq_p; + perf_rates.cq_s[componentIdx] = b_perfcells_dense[componentIdx] * cq_p; + perf_rates.cq_r[componentIdx] = cq_p; + perf_rates.cq_r_t += cq_p; } if (FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx) && FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)) { @@ -404,13 +407,13 @@ namespace Opm const EvalWell dis_gas = rs * cq_sOil; const EvalWell vap_oil = rv * cq_sGas; - cq_s[gasCompIdx] += dis_gas; + perf_rates.cq_s[gasCompIdx] += dis_gas; cq_s[oilCompIdx] += vap_oil; // recording the perforation solution gas rate and solution oil rates if (this->isProducer()) { - perf_dis_gas_rate = dis_gas.value(); - perf_vap_oil_rate = vap_oil.value(); + perf_rates.perf_dis_gas_rate = dis_gas.value(); + perf_rates.perf_vap_oil_rate = vap_oil.value(); } } @@ -424,8 +427,11 @@ namespace Opm EvalWell total_mob_dense = mob[0]; for (int componentIdx = 1; componentIdx < num_components_; ++componentIdx) { total_mob_dense += mob[componentIdx]; + cq_r[componentIdx] = - Tw * (mob[componentIdx] * drawdown); + cq_r_t += cq_r[componentIdx]; } + // TODO: cqt_i should be same with cq_r_t, there is some repeated computation here // injection perforations total volume rates const EvalWell cqt_i = - Tw * (total_mob_dense * drawdown); @@ -499,10 +505,10 @@ namespace Opm const double d = 1.0 - rv.value() * rs.value(); // vaporized oil into gas // rv * q_gr * b_g = rv * (q_gs - rs * q_os) / d - perf_vap_oil_rate = rv.value() * (cq_s[gasCompIdx].value() - rs.value() * cq_s[oilCompIdx].value()) / d; + perf_rates.perf_vap_oil_rate = rv.value() * (cq_s[gasCompIdx].value() - rs.value() * cq_s[oilCompIdx].value()) / d; // dissolved of gas in oil // rs * q_or * b_o = rs * (q_os - rv * q_gs) / d - perf_dis_gas_rate = rs.value() * (cq_s[oilCompIdx].value() - rv.value() * cq_s[gasCompIdx].value()) / d; + perf_rates.perf_dis_gas_rate = rs.value() * (cq_s[oilCompIdx].value() - rv.value() * cq_s[gasCompIdx].value()) / d; } } } @@ -580,34 +586,35 @@ namespace Opm std::vector mob(num_components_, {numWellEq_ + numEq, 0.}); getMobility(ebosSimulator, perf, mob, deferred_logger); - std::vector cq_s(num_components_, {numWellEq_ + numEq, 0.}); - double perf_dis_gas_rate = 0.; - double perf_vap_oil_rate = 0.; + PerfRates perf_rates(num_components_, numWellEq_); double trans_mult = ebosSimulator.problem().template rockCompTransMultiplier(intQuants, cell_idx); const double Tw = well_index_[perf] * trans_mult; computePerfRate(intQuants, mob, bhp, Tw, perf, allow_cf, - cq_s, perf_dis_gas_rate, perf_vap_oil_rate, deferred_logger); + perf_rates, deferred_logger); // better way to do here is that use the cq_s and then replace the cq_s_water here? if (has_polymer && this->has_polymermw && this->isInjector()) { - handleInjectivityRateAndEquations(intQuants, well_state, perf, cq_s, deferred_logger); + // TODO: we strictly, we probably should handle cq_r here too + handleInjectivityRateAndEquations(intQuants, well_state, perf, perf_rates.cq_s, deferred_logger); } // updating the solution gas rate and solution oil rate if (this->isProducer()) { - well_state.wellDissolvedGasRates()[index_of_well_] += perf_dis_gas_rate; - well_state.wellVaporizedOilRates()[index_of_well_] += perf_vap_oil_rate; + well_state.wellDissolvedGasRates()[index_of_well_] += perf_rates.perf_dis_gas_rate; + well_state.wellVaporizedOilRates()[index_of_well_] += perf_rates.perf_vap_oil_rate; } if (has_energy) { connectionRates_[perf][contiEnergyEqIdx] = 0.0; } + const auto& cq_s = perf_rates.cq_s; for (int componentIdx = 0; componentIdx < num_components_; ++componentIdx) { // the cq_s entering mass balance equations need to consider the efficiency factors. const EvalWell cq_s_effective = cq_s[componentIdx] * well_efficiency_factor_; connectionRates_[perf][componentIdx] = Base::restrictEval(cq_s_effective); + this->conResRates_[perf][componentIdx] = this->restrictEval(perf_rates.cq_r[componentIdx] * well_efficiency_factor_); // subtract sum of phase fluxes in the well equations. resWell_[0][componentIdx] += cq_s_effective.value(); @@ -630,6 +637,8 @@ namespace Opm well_state.perfPhaseRates()[(first_perf_ + perf) * np + ebosCompIdxToFlowCompIdx(componentIdx)] = cq_s[componentIdx].value(); } } + this->conTotalResRates_[perf] = this->restrictEval(perf_rates.cq_r_t * well_efficiency_factor_); + if (has_energy) { auto fs = intQuants.fluidState(); @@ -2471,14 +2480,12 @@ namespace Opm double trans_mult = ebosSimulator.problem().template rockCompTransMultiplier(intQuants, cell_idx); const double Tw = well_index_[perf] * trans_mult; - std::vector cq_s(num_components_, {numWellEq_ + numEq, 0.}); - double perf_dis_gas_rate = 0.; - double perf_vap_oil_rate = 0.; + PerfRates perf_rates(num_components_, numWellEq_); computePerfRate(intQuants, mob, EvalWell(numWellEq_ + numEq, bhp), Tw, perf, allow_cf, - cq_s, perf_dis_gas_rate, perf_vap_oil_rate, deferred_logger); + perf_rates, deferred_logger); for(int p = 0; p < np; ++p) { - well_flux[ebosCompIdxToFlowCompIdx(p)] += cq_s[p].value(); + well_flux[ebosCompIdxToFlowCompIdx(p)] += perf_rates.cq_s[p].value(); } } } @@ -2854,13 +2861,10 @@ namespace Opm const bool allow_cf = getAllowCrossFlow() || openCrossFlowAvoidSingularity(ebos_simulator); const EvalWell& bhp = getBhp(); - std::vector cq_s(num_components_, {numWellEq_ + numEq, 0.}); - double perf_dis_gas_rate = 0.; - double perf_vap_oil_rate = 0.; + PerfRates perf_rates(num_components_, numWellEq_); double trans_mult = ebos_simulator.problem().template rockCompTransMultiplier(int_quant, cell_idx); const double Tw = well_index_[perf] * trans_mult; - computePerfRate(int_quant, mob, bhp, Tw, perf, allow_cf, - cq_s, perf_dis_gas_rate, perf_vap_oil_rate, deferred_logger); + computePerfRate(int_quant, mob, bhp, Tw, perf, allow_cf, perf_rates, deferred_logger); // TODO: make area a member const double area = 2 * M_PI * perf_rep_radius_[perf] * perf_length_[perf]; const auto& material_law_manager = ebos_simulator.problem().materialLawManager(); @@ -2872,7 +2876,7 @@ namespace Opm // guard against zero porosity and no water const EvalWell denom = Opm::max( (area * poro * (sw - swcr)), 1e-12); const unsigned waterCompIdx = Indices::canonicalToActiveComponentIndex(FluidSystem::waterCompIdx); - EvalWell water_velocity = cq_s[waterCompIdx] / denom * extendEval(int_quant.fluidState().invB(FluidSystem::waterPhaseIdx)); + EvalWell water_velocity = perf_rates.cq_s[waterCompIdx] / denom * extendEval(int_quant.fluidState().invB(FluidSystem::waterPhaseIdx)); if (PolymerModule::hasShrate()) { // the equation for the water velocity conversion for the wells and reservoir are from different version diff --git a/opm/simulators/wells/WellInterface.hpp b/opm/simulators/wells/WellInterface.hpp index 308c052873a..e7643ae7550 100644 --- a/opm/simulators/wells/WellInterface.hpp +++ b/opm/simulators/wells/WellInterface.hpp @@ -374,6 +374,12 @@ namespace Opm std::vector connectionRates_; + // rates under reservoir condtion for each phase/component? + // RateVector is based on Dune::FieldVector + std::vector conResRates_; + + std::vector conTotalResRates_; + bool wellIsStopped_; double wsolvent_; diff --git a/opm/simulators/wells/WellInterface_impl.hpp b/opm/simulators/wells/WellInterface_impl.hpp index 42db8a60def..b351644441e 100644 --- a/opm/simulators/wells/WellInterface_impl.hpp +++ b/opm/simulators/wells/WellInterface_impl.hpp @@ -90,6 +90,10 @@ namespace Opm connectionRates_.resize(number_of_perforations_); + conResRates_.resize(number_of_perforations_); + + conTotalResRates_.resize(number_of_perforations_); + well_productivity_index_logger_counter_ = 0; wellIsStopped_ = false; From 9a3d9f6af73406d53901cb6f0418f9d3fa7e2c45 Mon Sep 17 00:00:00 2001 From: hnil Date: Fri, 12 Jun 2020 22:42:08 +0200 Subject: [PATCH 28/93] fixed some convergence criteria for sequential, some sequential simulations run --- opm/simulators/flow/NonlinearSolverEbos.hpp | 35 ++++++++++++++++----- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/opm/simulators/flow/NonlinearSolverEbos.hpp b/opm/simulators/flow/NonlinearSolverEbos.hpp index 9fc3ecc3af0..4c66ef0db61 100644 --- a/opm/simulators/flow/NonlinearSolverEbos.hpp +++ b/opm/simulators/flow/NonlinearSolverEbos.hpp @@ -148,12 +148,14 @@ namespace Opm { - SimulatorReportSingle stepSequential(const SimulatorTimerInterface& timer){ + SimulatorReportSingle stepSequential(const SimulatorTimerInterface& timer,bool implicit){ LinearizationType linearizationType; bool converged = false; SimulatorReportSingle reportpre; SimulatorReportSingle reportseq; - while(not converged){ + int seqiterations = 0; + int maxseqiterations = 10; + while(not(converged) && (seqiterations < maxseqiterations) ){ // do pressure step linearizationType.type = Opm::LinearizationType::pressure; model_->ebosSimulator().problem().updatePressure();//update pressure ans ST @@ -171,9 +173,26 @@ namespace Opm { reportpre += lreportpre; reportseq += lreportseq; // for no not seq implicit - converged = true; + if(implicit){ + // for now do full implicit solve + linearizationType.type = Opm::LinearizationType::pressure; + model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); + + model_->updateSolution(); + SimulatorReportSingle lreportsim = this->stepDefault(timer); + converged = lreportsim.converged; + }else{ + converged = true; + } + std::cout << "Sequantial iteration " << seqiterations << std::endl; + seqiterations += 1; } SimulatorReportSingle report; + if(not(converged)){ + report.converged = false; + }else{ + report.converged = true; + } //todo fill this report correctly return report; @@ -185,12 +204,12 @@ namespace Opm { report = this->stepFull(timer); }else if(simulationtype == "pressure"){ report = this->stepPressure(timer); - }else if(simulationtype == "seqtransport"){ - report = this->stepSequential(timer); - }else if(simulationtype == "seqtransport"){ - report = this->stepSequential(timer); + }else if(simulationtype == "seq"){ + report = this->stepSequential(timer,false); + }else if(simulationtype == "fimseq"){ + report = this->stepSequential(timer,true); }else{ - OPM_THROW(std::runtime_error, "No such simulation type"); + OPM_THROW(std::logic_error, "No such simulation type valid is: implicit, pressure, seq, fimseq "); } return report; } From 8ade2cd4ce4d592786391c23d0b5396113dc3c5e Mon Sep 17 00:00:00 2001 From: hnil Date: Wed, 17 Jun 2020 10:24:02 +0200 Subject: [PATCH 29/93] Working code we separate blackoil quantities --- ebos/eclblackoilintensivequantities.hh | 493 ++++++++++++++ ebos/eclblackoilnewtonmethod.hh | 324 +++++++++ ebos/eclblackoilprimaryvariables.hh | 761 ++++++++++++++++++++++ ebos/eclnewtonmethodseq.hh | 245 +++++++ flow/flow_blackoil_dunecpr_seq.cpp | 10 +- opm/simulators/flow/BlackoilModelEbos.hpp | 6 +- 6 files changed, 1836 insertions(+), 3 deletions(-) create mode 100644 ebos/eclblackoilintensivequantities.hh create mode 100644 ebos/eclblackoilnewtonmethod.hh create mode 100644 ebos/eclblackoilprimaryvariables.hh create mode 100644 ebos/eclnewtonmethodseq.hh diff --git a/ebos/eclblackoilintensivequantities.hh b/ebos/eclblackoilintensivequantities.hh new file mode 100644 index 00000000000..9f763b3d427 --- /dev/null +++ b/ebos/eclblackoilintensivequantities.hh @@ -0,0 +1,493 @@ +// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +// vi: set et ts=4 sw=4 sts=4: +/* + This file is part of the Open Porous Media project (OPM). + + OPM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + OPM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with OPM. If not, see . + + Consult the COPYING file in the top-level source directory of this + module for the precise wording of the license and the list of + copyright holders. +*/ +/*! + * \file + * + * \copydoc Opm::BlackOilIntensiveQuantities + */ +#ifndef EWOMS_ECL_BLACK_OIL_INTENSIVE_QUANTITIES_HH +#define EWOMS_ECL_BLACK_OIL_INTENSIVE_QUANTITIES_HH +#include +namespace Opm { +/*! + * \ingroup BlackOilModel + * \ingroup IntensiveQuantities + * + * \brief Contains the quantities which are are constant within a + * finite volume in the black-oil model. + */ +template +class EclBlackOilIntensiveQuantities + : public GET_PROP_TYPE(TypeTag, DiscIntensiveQuantities) + , public GET_PROP_TYPE(TypeTag, FluxModule)::FluxIntensiveQuantities + , public BlackOilSolventIntensiveQuantities + , public BlackOilPolymerIntensiveQuantities + , public BlackOilFoamIntensiveQuantities + , public BlackOilBrineIntensiveQuantities + , public BlackOilEnergyIntensiveQuantities +{ + typedef typename GET_PROP_TYPE(TypeTag, DiscIntensiveQuantities) ParentType; + typedef typename GET_PROP_TYPE(TypeTag, IntensiveQuantities) Implementation; + + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, Evaluation) Evaluation; + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw; + typedef typename GET_PROP_TYPE(TypeTag, ElementContext) ElementContext; + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; + typedef typename GET_PROP_TYPE(TypeTag, FluxModule) FluxModule; + + enum { numEq = GET_PROP_VALUE(TypeTag, NumEq) }; + enum { enableSolvent = GET_PROP_VALUE(TypeTag, EnableSolvent) }; + enum { enablePolymer = GET_PROP_VALUE(TypeTag, EnablePolymer) }; + enum { enableFoam = GET_PROP_VALUE(TypeTag, EnableFoam) }; + enum { enableBrine = GET_PROP_VALUE(TypeTag, EnableBrine) }; + enum { enableTemperature = GET_PROP_VALUE(TypeTag, EnableTemperature) }; + enum { enableEnergy = GET_PROP_VALUE(TypeTag, EnableEnergy) }; + enum { numPhases = GET_PROP_VALUE(TypeTag, NumPhases) }; + enum { numComponents = GET_PROP_VALUE(TypeTag, NumComponents) }; + enum { waterCompIdx = FluidSystem::waterCompIdx }; + enum { oilCompIdx = FluidSystem::oilCompIdx }; + enum { gasCompIdx = FluidSystem::gasCompIdx }; + enum { waterPhaseIdx = FluidSystem::waterPhaseIdx }; + enum { oilPhaseIdx = FluidSystem::oilPhaseIdx }; + enum { gasPhaseIdx = FluidSystem::gasPhaseIdx }; + enum { dimWorld = GridView::dimensionworld }; + enum { compositionSwitchIdx = Indices::compositionSwitchIdx }; + + static const bool compositionSwitchEnabled = Indices::gasEnabled; + static const bool waterEnabled = Indices::waterEnabled; + + typedef Opm::MathToolbox Toolbox; + typedef Dune::FieldMatrix DimMatrix; + typedef typename FluxModule::FluxIntensiveQuantities FluxIntensiveQuantities; + typedef Opm::BlackOilFluidState FluidState; + +public: + EclBlackOilIntensiveQuantities() + { + if (compositionSwitchEnabled) { + fluidState_.setRs(0.0); + fluidState_.setRv(0.0); + } + } + + EclBlackOilIntensiveQuantities(const EclBlackOilIntensiveQuantities& other) = default; + + EclBlackOilIntensiveQuantities& operator=(const EclBlackOilIntensiveQuantities& other) = default; + + /*! + * \copydoc IntensiveQuantities::update + */ + void update(const ElementContext& elemCtx, unsigned dofIdx, unsigned timeIdx) + { + ParentType::update(elemCtx, dofIdx, timeIdx); + + const auto linearizationType = elemCtx.linearizationType(); + const auto& problem = elemCtx.problem(); + const auto& priVars = elemCtx.primaryVars(dofIdx, timeIdx); + + asImp_().updateTemperature_(elemCtx, dofIdx, timeIdx); + + unsigned globalSpaceIdx = elemCtx.globalSpaceIndex(dofIdx, timeIdx); + unsigned pvtRegionIdx = priVars.pvtRegionIndex(); + fluidState_.setPvtRegionIndex(pvtRegionIdx); + + asImp_().updateSaltConcentration_(elemCtx, dofIdx, timeIdx); + + // extract the water and the gas saturations for convenience + Evaluation Sw = 0.0; + if (waterEnabled) { + if (priVars.primaryVarsMeaning() == PrimaryVariables::OnePhase_p) { + Sw = 1.0; + } else { + Sw = priVars.makeEvaluation(Indices::waterSaturationIdx, timeIdx, linearizationType); + } + } + Evaluation Sg = 0.0; + if (compositionSwitchEnabled) + { + if (priVars.primaryVarsMeaning() == PrimaryVariables::Sw_po_Sg) { + // -> threephase case + assert( priVars.primaryVarsMeaning() != PrimaryVariables::OnePhase_p ); + Sg = priVars.makeEvaluation(Indices::compositionSwitchIdx, timeIdx); + } else if (priVars.primaryVarsMeaning() == PrimaryVariables::Sw_pg_Rv) { + // -> gas-water case + Sg = 1.0 - Sw; + + // deal with solvent + if (enableSolvent) + Sg -= priVars.makeEvaluation(Indices::solventSaturationIdx, timeIdx, linearizationType); + } + else + { + assert(priVars.primaryVarsMeaning() == PrimaryVariables::Sw_po_Rs); + // -> oil-water case + Sg = 0.0; + } + } + + Opm::Valgrind::CheckDefined(Sg); + Opm::Valgrind::CheckDefined(Sw); + + Evaluation So = 1.0 - Sw - Sg; + + // deal with solvent + if (enableSolvent) + So -= priVars.makeEvaluation(Indices::solventSaturationIdx, timeIdx, linearizationType); + + if (FluidSystem::phaseIsActive(waterPhaseIdx)){ + fluidState_.setSaturation(waterPhaseIdx, Sw); + } + if (FluidSystem::phaseIsActive(gasPhaseIdx)){ + fluidState_.setSaturation(gasPhaseIdx, Sg); + } + if (FluidSystem::phaseIsActive(oilPhaseIdx)){ + fluidState_.setSaturation(oilPhaseIdx, So); + } + asImp_().solventPreSatFuncUpdate_(elemCtx, dofIdx, timeIdx); + + // now we compute all phase pressures + Evaluation pC[numPhases]; + const auto& materialParams = problem.materialLawParams(elemCtx, dofIdx, timeIdx); + MaterialLaw::capillaryPressures(pC, materialParams, fluidState_); + + // NB which index is correct!! + if (FluidSystem::phaseIsActive(waterPhaseIdx)){ + fluidState_.setPc(waterPhaseIdx, pC[waterPhaseIdx]); + } + if (FluidSystem::phaseIsActive(gasPhaseIdx)){ + fluidState_.setPc(gasPhaseIdx, pC[gasPhaseIdx]); + } + if (FluidSystem::phaseIsActive(oilPhaseIdx)){ + fluidState_.setPc(oilPhaseIdx, pC[oilPhaseIdx]); + } + + // oil is the reference phase for pressure + Evaluation ST = 1.0; + if (linearizationType.type == Opm::LinearizationType::seqtransport) { + ST = priVars.makeEvaluation(Indices::pressureSwitchIdx, timeIdx, linearizationType); + assert(ST<2);// debug to be sure no pressure is pressent + assert(timeIdx==0 || ST == 1);// for pure sequential with multiple steps this is always true. + + }else if (linearizationType.type == Opm::LinearizationType::pressure) { + // we are doing sequation pressure where ST may not be 1 any more + if(timeIdx == 1){//pressure solves try to make new value i.e. timeIdx==0 so that ST==1; + ST = elemCtx.problem().totalSaturation(globalSpaceIdx); + } + } + fluidState_.setTotalSaturation(ST); + if (priVars.primaryVarsMeaning() == PrimaryVariables::Sw_pg_Rv) { + Evaluation pg; + if (linearizationType.type == Opm::LinearizationType::seqtransport) { + pg = Toolbox::value( + elemCtx.problem().pressure(globalSpaceIdx, + gasPhaseIdx)); // get current value assuem this is not updated + } else { + pg = priVars.makeEvaluation(Indices::pressureSwitchIdx, timeIdx, linearizationType); + assert(pg>2.0);//enure not ST is present + } + for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + if (FluidSystem::phaseIsActive(phaseIdx)) + fluidState_.setPressure(phaseIdx, pg + (pC[phaseIdx] - pC[gasPhaseIdx])); + } else { + Evaluation po; + if (linearizationType.type == Opm::LinearizationType::seqtransport) { + // get current value assume this is never updated + po = Toolbox::value(elemCtx.problem().pressure(globalSpaceIdx, oilPhaseIdx)); + } else { + po = priVars.makeEvaluation(Indices::pressureSwitchIdx, timeIdx, linearizationType); + assert(po>2.0);//enure not ST is present + } + for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + if (FluidSystem::phaseIsActive(phaseIdx)) + fluidState_.setPressure(phaseIdx, po + (pC[phaseIdx] - pC[oilPhaseIdx])); + } + + // calculate relative permeabilities. note that we store the result into the + // mobility_ class attribute. the division by the phase viscosity happens later. + MaterialLaw::relativePermeabilities(mobility_, materialParams, fluidState_); + Opm::Valgrind::CheckDefined(mobility_); + + // update the Saturation functions for the blackoil solvent module. + asImp_().solventPostSatFuncUpdate_(elemCtx, dofIdx, timeIdx); + + Evaluation SoMax = 0.0; + if (FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)) { + SoMax = Opm::max(fluidState_.saturation(oilPhaseIdx), + elemCtx.problem().maxOilSaturation(globalSpaceIdx)); + } + + // take the meaning of the switiching primary variable into account for the gas + // and oil phase compositions + if (priVars.primaryVarsMeaning() == PrimaryVariables::Sw_po_Sg) { + // in the threephase case, gas and oil phases are potentially present, i.e., + // we use the compositions of the gas-saturated oil and oil-saturated gas. + if (FluidSystem::enableDissolvedGas()) { + Scalar RsMax = elemCtx.problem().maxGasDissolutionFactor(timeIdx, globalSpaceIdx); + const Evaluation& RsSat = + FluidSystem::saturatedDissolutionFactor(fluidState_, + oilPhaseIdx, + pvtRegionIdx, + SoMax); + fluidState_.setRs(Opm::min(RsMax, RsSat)); + } + else if (compositionSwitchEnabled) + fluidState_.setRs(0.0); + + if (FluidSystem::enableVaporizedOil()) { + Scalar RvMax = elemCtx.problem().maxOilVaporizationFactor(timeIdx, globalSpaceIdx); + const Evaluation& RvSat = + FluidSystem::saturatedDissolutionFactor(fluidState_, + gasPhaseIdx, + pvtRegionIdx, + SoMax); + fluidState_.setRv(Opm::min(RvMax, RvSat)); + } + else if (compositionSwitchEnabled) + fluidState_.setRv(0.0); + } + else if (priVars.primaryVarsMeaning() == PrimaryVariables::Sw_po_Rs) { + // if the switching variable is the mole fraction of the gas component in the + Scalar RsMax = elemCtx.problem().maxGasDissolutionFactor(timeIdx, globalSpaceIdx); + + // oil phase, we can directly set the composition of the oil phase + const auto& Rs = priVars.makeEvaluation(Indices::compositionSwitchIdx, timeIdx, linearizationType); + fluidState_.setRs(Opm::min(RsMax, Rs)); + + if (FluidSystem::enableVaporizedOil()) { + // the gas phase is not present, but we need to compute its "composition" + // for the gravity correction anyway + Scalar RvMax = elemCtx.problem().maxOilVaporizationFactor(timeIdx, globalSpaceIdx); + const auto& RvSat = + FluidSystem::saturatedDissolutionFactor(fluidState_, + gasPhaseIdx, + pvtRegionIdx, + SoMax); + + fluidState_.setRv(Opm::min(RvMax, RvSat)); + } + else + fluidState_.setRv(0.0); + } + else if (priVars.primaryVarsMeaning() == PrimaryVariables::Sw_pg_Rv) { + const auto& Rv = priVars.makeEvaluation(Indices::compositionSwitchIdx, timeIdx, linearizationType); + fluidState_.setRv(Rv); + + if (FluidSystem::enableDissolvedGas()) { + // the oil phase is not present, but we need to compute its "composition" for + // the gravity correction anyway + Scalar RsMax = elemCtx.problem().maxGasDissolutionFactor(timeIdx, globalSpaceIdx); + const auto& RsSat = + FluidSystem::saturatedDissolutionFactor(fluidState_, + oilPhaseIdx, + pvtRegionIdx, + SoMax); + + fluidState_.setRs(Opm::min(RsMax, RsSat)); + } else { + fluidState_.setRs(0.0); + } + } else { + assert(priVars.primaryVarsMeaning() == PrimaryVariables::OnePhase_p); + } + + typename FluidSystem::template ParameterCache paramCache; + paramCache.setRegionIndex(pvtRegionIdx); + if(FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)){ + paramCache.setMaxOilSat(SoMax); + } + paramCache.updateAll(fluidState_); + + // compute the phase densities and transform the phase permeabilities into mobilities + for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { + if (!FluidSystem::phaseIsActive(phaseIdx)) + continue; + + const auto& b = FluidSystem::inverseFormationVolumeFactor(fluidState_, phaseIdx, pvtRegionIdx); + fluidState_.setInvB(phaseIdx, b); + + const auto& mu = FluidSystem::viscosity(fluidState_, paramCache, phaseIdx); + mobility_[phaseIdx] /= mu; + } + Opm::Valgrind::CheckDefined(mobility_); + + // calculate the phase densities + Evaluation rho; + if (FluidSystem::phaseIsActive(waterPhaseIdx)) { + rho = fluidState_.invB(waterPhaseIdx); + rho *= FluidSystem::referenceDensity(waterPhaseIdx, pvtRegionIdx); + fluidState_.setDensity(waterPhaseIdx, rho); + } + + if (FluidSystem::phaseIsActive(gasPhaseIdx)) { + rho = fluidState_.invB(gasPhaseIdx); + rho *= FluidSystem::referenceDensity(gasPhaseIdx, pvtRegionIdx); + if (FluidSystem::enableVaporizedOil()) { + rho += + fluidState_.invB(gasPhaseIdx) * + fluidState_.Rv() * + FluidSystem::referenceDensity(oilPhaseIdx, pvtRegionIdx); + } + fluidState_.setDensity(gasPhaseIdx, rho); + } + + if (FluidSystem::phaseIsActive(oilPhaseIdx)) { + rho = fluidState_.invB(oilPhaseIdx); + rho *= FluidSystem::referenceDensity(oilPhaseIdx, pvtRegionIdx); + if (FluidSystem::enableDissolvedGas()) { + rho += + fluidState_.invB(oilPhaseIdx) * + fluidState_.Rs() * + FluidSystem::referenceDensity(gasPhaseIdx, pvtRegionIdx); + } + fluidState_.setDensity(oilPhaseIdx, rho); + } + + // retrieve the porosity from the problem + referencePorosity_ = problem.porosity(elemCtx, dofIdx, timeIdx); + porosity_ = referencePorosity_; + + // the porosity must be modified by the compressibility of the + // rock... + Scalar rockCompressibility = problem.rockCompressibility(elemCtx, dofIdx, timeIdx); + if (rockCompressibility > 0.0) { + Scalar rockRefPressure = problem.rockReferencePressure(elemCtx, dofIdx, timeIdx); + Evaluation x; + if (FluidSystem::phaseIsActive(oilPhaseIdx)) { + x = rockCompressibility*(fluidState_.pressure(oilPhaseIdx) - rockRefPressure); + } else if (FluidSystem::phaseIsActive(waterPhaseIdx)){ + } else { + x = rockCompressibility*(fluidState_.pressure(gasPhaseIdx) - rockRefPressure); + } + porosity_ *= 1.0 + x + 0.5*x*x; + } + + // deal with water induced rock compaction + porosity_ *= problem.template rockCompPoroMultiplier(*this, globalSpaceIdx); + + // this line is doing things for sequential simulation to avoid modifying storage term. + porosity_ *= ST; + + asImp_().solventPvtUpdate_(elemCtx, dofIdx, timeIdx); + asImp_().polymerPropertiesUpdate_(elemCtx, dofIdx, timeIdx); + asImp_().updateEnergyQuantities_(elemCtx, dofIdx, timeIdx, paramCache); + asImp_().foamPropertiesUpdate_(elemCtx, dofIdx, timeIdx); + + // update the quantities which are required by the chosen + // velocity model + // TODO: use the focus time here + FluxIntensiveQuantities::update_(elemCtx, dofIdx, timeIdx); + +#ifndef NDEBUG + // some safety checks in debug mode + for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) { + if (!FluidSystem::phaseIsActive(phaseIdx)) + continue; + + assert(Opm::isfinite(fluidState_.density(phaseIdx))); + assert(Opm::isfinite(fluidState_.saturation(phaseIdx))); + assert(Opm::isfinite(fluidState_.temperature(phaseIdx))); + assert(Opm::isfinite(fluidState_.pressure(phaseIdx))); + assert(Opm::isfinite(fluidState_.invB(phaseIdx))); + } + assert(Opm::isfinite(fluidState_.Rs())); + assert(Opm::isfinite(fluidState_.Rv())); +#endif + } + + /*! + * \copydoc ImmiscibleIntensiveQuantities::fluidState + */ + const FluidState& fluidState() const + { return fluidState_; } + + /*! + * \copydoc ImmiscibleIntensiveQuantities::mobility + */ + const Evaluation& mobility(unsigned phaseIdx) const + { return mobility_[phaseIdx]; } + + /*! + * \copydoc ImmiscibleIntensiveQuantities::porosity + */ + const Evaluation& porosity() const + { return porosity_; } + + /*! + * \brief Returns the index of the PVT region used to calculate the thermodynamic + * quantities. + * + * This allows to specify different Pressure-Volume-Temperature (PVT) relations in + * different parts of the spatial domain. Note that this concept should be seen as a + * work-around of the fact that the black-oil model does not capture the + * thermodynamics well enough. (Because there is, err, only a single real world with + * in which all substances follow the same physical laws and hence the same + * thermodynamics.) Anyway: Since the ECL file format uses multiple PVT regions, we + * support it as well in our black-oil model. (Note that, if it is not explicitly + * specified, the PVT region index is 0.) + */ + auto pvtRegionIndex() const + -> decltype(std::declval().pvtRegionIndex()) + { return fluidState_.pvtRegionIndex(); } + + /*! + * \copydoc ImmiscibleIntensiveQuantities::relativePermeability + */ + Evaluation relativePermeability(unsigned phaseIdx) const + { + // warning: slow + return fluidState_.viscosity(phaseIdx)*mobility(phaseIdx); + } + + /*! + * \brief Returns the porosity of the rock at reference conditions. + * + * I.e., the porosity of rock which is not perturbed by pressure and temperature + * changes. + */ + Scalar referencePorosity() const + { return referencePorosity_; } + +private: + friend BlackOilSolventIntensiveQuantities; + friend BlackOilPolymerIntensiveQuantities; + friend BlackOilEnergyIntensiveQuantities; + friend BlackOilFoamIntensiveQuantities; + friend BlackOilBrineIntensiveQuantities; + + + Implementation& asImp_() + { return *static_cast(this); } + + FluidState fluidState_; + Scalar referencePorosity_; + Evaluation porosity_; + Evaluation mobility_[numPhases]; +}; + +} // namespace Opm + +#endif diff --git a/ebos/eclblackoilnewtonmethod.hh b/ebos/eclblackoilnewtonmethod.hh new file mode 100644 index 00000000000..957bedffac4 --- /dev/null +++ b/ebos/eclblackoilnewtonmethod.hh @@ -0,0 +1,324 @@ +// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +// vi: set et ts=4 sw=4 sts=4: +/* + This file is part of the Open Porous Media project (OPM). + + OPM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + OPM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with OPM. If not, see . + + Consult the COPYING file in the top-level source directory of this + module for the precise wording of the license and the list of + copyright holders. +*/ +/*! + * \file + * + * \copydoc Opm::BlackOilNewtonMethod + */ +#ifndef EWOMS_ECL_BLACK_OIL_NEWTON_METHOD_HH +#define EWOMS_ECL_BLACK_OIL_NEWTON_METHOD_HH + +#include + +namespace Opm { + +/*! + * \ingroup BlackOilModel + * + * \brief A newton solver which is specific to the black oil model. + */ +template +class EclBlackOilNewtonMethod : public GET_PROP_TYPE(TypeTag, DiscNewtonMethod) +{ + typedef typename GET_PROP_TYPE(TypeTag, DiscNewtonMethod) ParentType; + typedef typename GET_PROP_TYPE(TypeTag, Simulator) Simulator; + typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; + typedef typename GET_PROP_TYPE(TypeTag, GlobalEqVector) GlobalEqVector; + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, EqVector) EqVector; + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, Linearizer) Linearizer; + + static const unsigned numEq = GET_PROP_VALUE(TypeTag, NumEq); + +public: + EclBlackOilNewtonMethod(Simulator& simulator) : ParentType(simulator) + { + priVarOscilationThreshold_ = EWOMS_GET_PARAM(TypeTag, Scalar, PriVarOscilationThreshold); + dpMaxRel_ = EWOMS_GET_PARAM(TypeTag, Scalar, DpMaxRel); + dsMax_ = EWOMS_GET_PARAM(TypeTag, Scalar, DsMax); + projectSaturations_ = EWOMS_GET_PARAM(TypeTag, bool, ProjectSaturations); + } + + /*! + * \copydoc NewtonMethod::finishInit() + */ + void finishInit() + { + ParentType::finishInit(); + + wasSwitched_.resize(this->model().numTotalDof()); + std::fill(wasSwitched_.begin(), wasSwitched_.end(), false); + } + + /*! + * \brief Register all run-time parameters for the immiscible model. + */ + static void registerParameters() + { + ParentType::registerParameters(); + + EWOMS_REGISTER_PARAM(TypeTag, Scalar, DpMaxRel, "Maximum relative change of pressure in a single iteration"); + EWOMS_REGISTER_PARAM(TypeTag, Scalar, DsMax, "Maximum absolute change of any saturation in a single iteration"); + EWOMS_REGISTER_PARAM(TypeTag, Scalar, PriVarOscilationThreshold, + "The threshold value for the primary variable switching conditions after its meaning has switched to hinder oscilations"); + EWOMS_REGISTER_PARAM(TypeTag,bool, ProjectSaturations, "Option for doing saturation projection"); + } + + /*! + * \brief Returns the number of degrees of freedom for which the + * interpretation has changed for the most recent iteration. + */ + unsigned numPriVarsSwitched() const + { return numPriVarsSwitched_; } + +protected: + friend NewtonMethod; + friend ParentType; + + /*! + * \copydoc FvBaseNewtonMethod::beginIteration_ + */ + void beginIteration_() + { + numPriVarsSwitched_ = 0; + ParentType::beginIteration_(); + } + + /*! + * \copydoc FvBaseNewtonMethod::endIteration_ + */ + void endIteration_(SolutionVector& uCurrentIter, + const SolutionVector& uLastIter) + { +#if HAVE_MPI + // in the MPI enabled case we need to add up the number of DOF + // for which the interpretation changed over all processes. + int localSwitched = numPriVarsSwitched_; + MPI_Allreduce(&localSwitched, + &numPriVarsSwitched_, + /*num=*/1, + MPI_INT, + MPI_SUM, + MPI_COMM_WORLD); +#endif // HAVE_MPI + + this->simulator_.model().newtonMethod().endIterMsg() + << ", num switched=" << numPriVarsSwitched_; + + ParentType::endIteration_(uCurrentIter, uLastIter); + } + +public: + void update_(SolutionVector& nextSolution, + const SolutionVector& currentSolution, + const GlobalEqVector& solutionUpdate, + const GlobalEqVector& currentResidual) + { + const auto& comm = this->simulator_.gridView().comm(); + + int succeeded; + try { + ParentType::update_(nextSolution, + currentSolution, + solutionUpdate, + currentResidual); + succeeded = 1; + } + catch (...) { + std::cout << "Newton update threw an exception on rank " + << comm.rank() << "\n"; + succeeded = 0; + } + succeeded = comm.min(succeeded); + + if (!succeeded) + throw Opm::NumericalIssue("A process did not succeed in adapting the primary variables"); + + numPriVarsSwitched_ = comm.sum(numPriVarsSwitched_); + } + +protected: + /*! + * \copydoc FvBaseNewtonMethod::updatePrimaryVariables_ + */ + void updatePrimaryVariables_(unsigned globalDofIdx, + PrimaryVariables& nextValue, + const PrimaryVariables& currentValue, + const EqVector& update, + const EqVector& currentResidual) + { + static constexpr bool enableSolvent = Indices::solventSaturationIdx >= 0; + static constexpr bool enablePolymer = Indices::polymerConcentrationIdx >= 0; + static constexpr bool enablePolymerWeight = Indices::polymerMoleWeightIdx >= 0; + static constexpr bool enableEnergy = Indices::temperatureIdx >= 0; + static constexpr bool enableFoam = Indices::foamConcentrationIdx >= 0; + static constexpr bool enableBrine = Indices::saltConcentrationIdx >= 0; + + currentValue.checkDefined(); + Opm::Valgrind::CheckDefined(update); + Opm::Valgrind::CheckDefined(currentResidual); + + // saturation delta for each phase + Scalar deltaSw = 0.0; + Scalar deltaSo = 0.0; + Scalar deltaSg = 0.0; + Scalar deltaSs = 0.0; + + if (Indices::waterEnabled) { + deltaSw = update[Indices::waterSaturationIdx]; + deltaSo = -deltaSw; + } + + if (Indices::gasEnabled && currentValue.primaryVarsMeaning() == PrimaryVariables::Sw_po_Sg) { + deltaSg = update[Indices::compositionSwitchIdx]; + deltaSo -= deltaSg; + } + + if (enableSolvent) { + deltaSs = update[Indices::solventSaturationIdx]; + deltaSo -= deltaSs; + } + + // maximum saturation delta + Scalar maxSatDelta = std::max(std::abs(deltaSg), std::abs(deltaSo)); + maxSatDelta = std::max(maxSatDelta, std::abs(deltaSw)); + maxSatDelta = std::max(maxSatDelta, std::abs(deltaSs)); + + // scaling factor for saturation deltas to make sure that none of them exceeds + // the specified threshold value. + Scalar satAlpha = 1.0; + if (maxSatDelta > dsMax_) + satAlpha = dsMax_/maxSatDelta; + + for (int pvIdx = 0; pvIdx < int(numEq); ++pvIdx) { + // calculate the update of the current primary variable. For the black-oil + // model we limit the pressure delta relative to the pressure's current + // absolute value (Default: 30%) and saturation deltas to an absolute change + // (Default: 20%). Further, we ensure that the R factors, solvent + // "saturation" and polymer concentration do not become negative after the + // update. + Scalar delta = update[pvIdx]; + + // limit pressure delta + if (pvIdx == Indices::pressureSwitchIdx) { + LinearizationType linearizationType = this->model().linearizer().getLinearizationType(); + if (linearizationType.type == Opm::LinearizationType::seqtransport) { + // TODO: set max update of ST + } else { + if (std::abs(delta) > dpMaxRel_*currentValue[pvIdx]) + delta = Opm::signum(delta)*dpMaxRel_*currentValue[pvIdx]; + } + } + // water saturation delta + else if (pvIdx == Indices::waterSaturationIdx) + delta *= satAlpha; + else if (pvIdx == Indices::compositionSwitchIdx) { + // the switching primary variable for composition is tricky because the + // "reasonable" value ranges it exhibits vary widely depending on its + // interpretation since it can represent Sg, Rs or Rv. For now, we only + // limit saturation deltas and ensure that the R factors do not become + // negative. + if (currentValue.primaryVarsMeaning() == PrimaryVariables::Sw_po_Sg) + delta *= satAlpha; + else { + if (delta > currentValue[Indices::compositionSwitchIdx]) + delta = currentValue[Indices::compositionSwitchIdx]; + } + } + else if (enableSolvent && pvIdx == Indices::solventSaturationIdx) + // solvent saturation updates are also subject to the Appleyard chop + delta *= satAlpha; + else if (enablePolymerWeight && pvIdx == Indices::polymerMoleWeightIdx) { + const double sign = delta >= 0. ? 1. : -1.; + // maximum change of polymer molecular weight, the unit is MDa. + // applying this limit to stabilize the simulation. The value itself is still experimental. + const double maxMolarWeightChange = 100.0; + delta = sign * std::min(std::abs(delta), maxMolarWeightChange); + delta *= satAlpha; + } + + // do the actual update + nextValue[pvIdx] = currentValue[pvIdx] - delta; + + // keep the solvent saturation between 0 and 1 + if (enableSolvent && pvIdx == Indices::solventSaturationIdx) + nextValue[pvIdx] = std::min(std::max(nextValue[pvIdx], 0.0), 1.0); + + // keep the polymer concentration above 0 + if (enablePolymer && pvIdx == Indices::polymerConcentrationIdx) + nextValue[pvIdx] = std::max(nextValue[pvIdx], 0.0); + + if (enablePolymerWeight && pvIdx == Indices::polymerMoleWeightIdx) { + nextValue[pvIdx] = std::max(nextValue[pvIdx], 0.0); + const double polymerConcentration = nextValue[Indices::polymerConcentrationIdx]; + if (polymerConcentration < 1.e-10) + nextValue[pvIdx] = 0.0; + } + + // keep the foam concentration above 0 + if (enableFoam && pvIdx == Indices::foamConcentrationIdx) + nextValue[pvIdx] = std::max(nextValue[pvIdx], 0.0); + + // keep the salt concentration above 0 + if (enableBrine && pvIdx == Indices::saltConcentrationIdx) + nextValue[pvIdx] = std::max(nextValue[pvIdx], 0.0); + + // keep the temperature above 100 and below 1000 Kelvin + if (enableEnergy && pvIdx == Indices::temperatureIdx) + nextValue[pvIdx] = std::max(std::min(nextValue[pvIdx], 1000.0), 100.0); + } + + // switch the new primary variables to something which is physically meaningful. + // use a threshold value after a switch to make it harder to switch back + // immediately. + if (wasSwitched_[globalDofIdx]) + wasSwitched_[globalDofIdx] = nextValue.adaptPrimaryVariables(this->problem(), globalDofIdx, priVarOscilationThreshold_); + else + wasSwitched_[globalDofIdx] = nextValue.adaptPrimaryVariables(this->problem(), globalDofIdx); + + if (wasSwitched_[globalDofIdx]) + ++ numPriVarsSwitched_; + if(projectSaturations_){ + nextValue.chopAndNormalizeSaturations(); + } + + nextValue.checkDefined(); + } + +private: + int numPriVarsSwitched_; + + Scalar priVarOscilationThreshold_; + Scalar dpMaxRel_; + Scalar dsMax_; + bool projectSaturations_; + + // keep track of cells where the primary variable meaning has changed + // to detect and hinder oscillations + std::vector wasSwitched_; +}; +} // namespace Opm + +#endif diff --git a/ebos/eclblackoilprimaryvariables.hh b/ebos/eclblackoilprimaryvariables.hh new file mode 100644 index 00000000000..eedbf93ec24 --- /dev/null +++ b/ebos/eclblackoilprimaryvariables.hh @@ -0,0 +1,761 @@ +// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +// vi: set et ts=4 sw=4 sts=4: +/* + This file is part of the Open Porous Media project (OPM). + + OPM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + OPM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with OPM. If not, see . + + Consult the COPYING file in the top-level source directory of this + module for the precise wording of the license and the list of + copyright holders. +*/ +/*! + * \file + * + * \copydoc Opm::BlackOilPrimaryVariables + */ +#ifndef EWOMS_ECL_BLACK_OIL_PRIMARY_VARIABLES_HH +#define EWOMS_ECL_BLACK_OIL_PRIMARY_VARIABLES_HH + +#include +namespace Opm{ +/*! + * \ingroup BlackOilModel + * + * \brief Represents the primary variables used by the black-oil model. + */ +template +class EclBlackOilPrimaryVariables : public FvBasePrimaryVariables +{ + typedef FvBasePrimaryVariables ParentType; + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) Implementation; + + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, Evaluation) Evaluation; + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw; + typedef typename GET_PROP_TYPE(TypeTag, MaterialLawParams) MaterialLawParams; + + // number of equations + enum { numEq = GET_PROP_VALUE(TypeTag, NumEq) }; + + // primary variable indices + enum { waterSaturationIdx = Indices::waterSaturationIdx }; + enum { pressureSwitchIdx = Indices::pressureSwitchIdx }; + enum { compositionSwitchIdx = Indices::compositionSwitchIdx }; + + static const bool compositionSwitchEnabled = Indices::gasEnabled; + static const bool waterEnabled = Indices::waterEnabled; + + // phase indices from the fluid system + enum { numPhases = GET_PROP_VALUE(TypeTag, NumPhases) }; + enum { gasPhaseIdx = FluidSystem::gasPhaseIdx }; + enum { waterPhaseIdx = FluidSystem::waterPhaseIdx }; + enum { oilPhaseIdx = FluidSystem::oilPhaseIdx }; + + // component indices from the fluid system + enum { numComponents = GET_PROP_VALUE(TypeTag, NumComponents) }; + enum { enableSolvent = GET_PROP_VALUE(TypeTag, EnableSolvent) }; + enum { enablePolymer = GET_PROP_VALUE(TypeTag, EnablePolymer) }; + enum { enableFoam = GET_PROP_VALUE(TypeTag, EnableFoam) }; + enum { enableBrine = GET_PROP_VALUE(TypeTag, EnableBrine) }; + enum { enableEnergy = GET_PROP_VALUE(TypeTag, EnableEnergy) }; + enum { gasCompIdx = FluidSystem::gasCompIdx }; + enum { waterCompIdx = FluidSystem::waterCompIdx }; + enum { oilCompIdx = FluidSystem::oilCompIdx }; + + typedef typename Opm::MathToolbox Toolbox; + typedef Dune::FieldVector ComponentVector; + typedef BlackOilSolventModule SolventModule; + typedef BlackOilPolymerModule PolymerModule; + typedef BlackOilEnergyModule EnergyModule; + typedef BlackOilFoamModule FoamModule; + typedef BlackOilBrineModule BrineModule; + + static_assert(numPhases == 3, "The black-oil model assumes three phases!"); + static_assert(numComponents == 3, "The black-oil model assumes three components!"); + +public: + enum PrimaryVarsMeaning { + Sw_po_Sg, // threephase case + Sw_po_Rs, // water + oil case + Sw_pg_Rv, // water + gas case + OnePhase_p, // onephase case + }; + + EclBlackOilPrimaryVariables() + : ParentType() + { + Opm::Valgrind::SetUndefined(*this); + pvtRegionIdx_ = 0; + } + + /*! + * \copydoc ImmisciblePrimaryVariables::ImmisciblePrimaryVariables(Scalar) + */ + EclBlackOilPrimaryVariables(Scalar value) + : ParentType(value) + { + Opm::Valgrind::SetUndefined(primaryVarsMeaning_); + pvtRegionIdx_ = 0; + } + + /*! + * \copydoc ImmisciblePrimaryVariables::ImmisciblePrimaryVariables(const ImmisciblePrimaryVariables& ) + */ + EclBlackOilPrimaryVariables(const EclBlackOilPrimaryVariables& value) = default; + + /*! + * \brief Set the index of the region which should be used for PVT properties. + * + * The concept of PVT regions is a hack to work around the fact that the + * pseudo-components used by the black oil model (i.e., oil, gas and water) change + * their composition within the spatial domain. We implement them because, the ECL + * file format mandates them. + */ + void setPvtRegionIndex(unsigned value) + { pvtRegionIdx_ = static_cast(value); } + + /*! + * \brief Return the index of the region which should be used for PVT properties. + */ + unsigned pvtRegionIndex() const + { return pvtRegionIdx_; } + + /*! + * \brief Return the interpretation which should be applied to the switching primary + * variables. + */ + PrimaryVarsMeaning primaryVarsMeaning() const + { return primaryVarsMeaning_; } + + /*! + * \brief Set the interpretation which should be applied to the switching primary + * variables. + */ + void setPrimaryVarsMeaning(PrimaryVarsMeaning newMeaning) + { primaryVarsMeaning_ = newMeaning; } + + /*! + * \copydoc ImmisciblePrimaryVariables::assignMassConservative + */ + template + void assignMassConservative(const FluidState& fluidState, + const MaterialLawParams& matParams, + bool isInEquilibrium = false) + { + typedef typename std::remove_reference::type ConstEvaluation; + typedef typename std::remove_const::type FsEvaluation; + typedef typename Opm::MathToolbox FsToolbox; + +#ifndef NDEBUG + // make sure the temperature is the same in all fluid phases + for (unsigned phaseIdx = 1; phaseIdx < numPhases; ++phaseIdx) { + Opm::Valgrind::CheckDefined(fluidState.temperature(0)); + Opm::Valgrind::CheckDefined(fluidState.temperature(phaseIdx)); + + assert(fluidState.temperature(0) == fluidState.temperature(phaseIdx)); + } +#endif // NDEBUG + + // for the equilibrium case, we don't need complicated + // computations. + if (isInEquilibrium) { + assignNaive(fluidState); + return; + } + + // If your compiler bails out here, you're probably not using a suitable black + // oil fluid system. + typename FluidSystem::template ParameterCache paramCache; + paramCache.setRegionIndex(pvtRegionIdx_); + paramCache.setMaxOilSat(FsToolbox::value(fluidState.saturation(oilPhaseIdx))); + + // create a mutable fluid state with well defined densities based on the input + typedef Opm::NcpFlash NcpFlash; + typedef Opm::CompositionalFluidState FlashFluidState; + FlashFluidState fsFlash; + fsFlash.setTemperature(FsToolbox::value(fluidState.temperature(/*phaseIdx=*/0))); + for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { + fsFlash.setPressure(phaseIdx, FsToolbox::value(fluidState.pressure(phaseIdx))); + fsFlash.setSaturation(phaseIdx, FsToolbox::value(fluidState.saturation(phaseIdx))); + for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) + fsFlash.setMoleFraction(phaseIdx, compIdx, FsToolbox::value(fluidState.moleFraction(phaseIdx, compIdx))); + } + + paramCache.updateAll(fsFlash); + for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { + if (!FluidSystem::phaseIsActive(phaseIdx)) + continue; + + Scalar rho = FluidSystem::template density(fsFlash, paramCache, phaseIdx); + fsFlash.setDensity(phaseIdx, rho); + } + + // calculate the "global molarities" + ComponentVector globalMolarities(0.0); + for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) { + for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { + if (!FluidSystem::phaseIsActive(phaseIdx)) + continue; + + globalMolarities[compIdx] += + fsFlash.saturation(phaseIdx) * fsFlash.molarity(phaseIdx, compIdx); + } + } + + // use a flash calculation to calculate a fluid state in + // thermodynamic equilibrium + + // run the flash calculation + NcpFlash::template solve(fsFlash, matParams, paramCache, globalMolarities); + + // use the result to assign the primary variables + assignNaive(fsFlash); + } + + /*! + * \copydoc ImmisciblePrimaryVariables::assignNaive + */ + template + void assignNaive(const FluidState& fluidState) + { + typedef typename std::remove_reference::type ConstEvaluation; + typedef typename std::remove_const::type FsEvaluation; + typedef typename Opm::MathToolbox FsToolbox; + + bool gasPresent = FluidSystem::phaseIsActive(gasPhaseIdx)?(fluidState.saturation(gasPhaseIdx) > 0.0):false; + bool oilPresent = FluidSystem::phaseIsActive(oilPhaseIdx)?(fluidState.saturation(oilPhaseIdx) > 0.0):false; + static const Scalar thresholdWaterFilledCell = 1.0 - 1e-6; + bool onlyWater = FluidSystem::phaseIsActive(waterPhaseIdx)?(fluidState.saturation(waterPhaseIdx) > thresholdWaterFilledCell):false; + + // deal with the primary variables for the energy extension + EnergyModule::assignPrimaryVars(*this, fluidState); + + // determine the meaning of the primary variables + if (FluidSystem::numActivePhases() == 1) { + primaryVarsMeaning_ = OnePhase_p; + } + else if ((gasPresent && oilPresent) || (onlyWater && FluidSystem::phaseIsActive(oilPhaseIdx))) { + // gas and oil: both hydrocarbon phases are in equilibrium (i.e., saturated + // with the "protagonist" component of the other phase.) + primaryVarsMeaning_ = Sw_po_Sg; + } + else if (oilPresent) { + // only oil: if dissolved gas is enabled, we need to consider the oil phase + // composition, if it is disabled, the gas component must stick to its phase + if (FluidSystem::enableDissolvedGas()) + primaryVarsMeaning_ = Sw_po_Rs; + else + primaryVarsMeaning_ = Sw_po_Sg; + } + else { + assert(gasPresent); + // only gas: if vaporized oil is enabled, we need to consider the gas phase + // composition, if it is disabled, the oil component must stick to its phase + if (FluidSystem::enableVaporizedOil()) + primaryVarsMeaning_ = Sw_pg_Rv; + else + primaryVarsMeaning_ = Sw_po_Sg; + } + + // assign the actual primary variables + if (primaryVarsMeaning() == OnePhase_p) { + if (waterEnabled) { + (*this)[waterSaturationIdx] = FsToolbox::value(fluidState.saturation(waterPhaseIdx)); + (*this)[pressureSwitchIdx] = FsToolbox::value(fluidState.pressure(waterPhaseIdx)); + } else { + throw std::logic_error("For single-phase runs, only pure water is presently allowed."); + } + + } + else if (primaryVarsMeaning() == Sw_po_Sg) { + if (waterEnabled) + (*this)[waterSaturationIdx] = FsToolbox::value(fluidState.saturation(waterPhaseIdx)); + (*this)[pressureSwitchIdx] = FsToolbox::value(fluidState.pressure(oilPhaseIdx)); + if( compositionSwitchEnabled ) + (*this)[compositionSwitchIdx] = FsToolbox::value(fluidState.saturation(gasPhaseIdx)); + } + else if (primaryVarsMeaning() == Sw_po_Rs) { + const auto& Rs = Opm::BlackOil::getRs_(fluidState, pvtRegionIdx_); + + if (waterEnabled) + (*this)[waterSaturationIdx] = FsToolbox::value(fluidState.saturation(waterPhaseIdx)); + (*this)[pressureSwitchIdx] = FsToolbox::value(fluidState.pressure(oilPhaseIdx)); + if( compositionSwitchEnabled ) + (*this)[compositionSwitchIdx] = Rs; + } + else { + assert(primaryVarsMeaning() == Sw_pg_Rv); + + const auto& Rv = Opm::BlackOil::getRv_(fluidState, pvtRegionIdx_); + if (waterEnabled) + (*this)[waterSaturationIdx] = FsToolbox::value(fluidState.saturation(waterPhaseIdx)); + + (*this)[pressureSwitchIdx] = FsToolbox::value(fluidState.pressure(gasPhaseIdx)); + if( compositionSwitchEnabled ) + (*this)[compositionSwitchIdx] = Rv; + } + + checkDefined(); + } + + /*! + * \brief Adapt the interpretation of the switching variables to be physically + * meaningful. + * + * If the meaning of the primary variables changes, their values are also adapted in a + * meaningful manner. (e.g. if the gas phase appears and the composition switching + * variable changes its meaning from the gas dissolution factor Rs to the gas + * saturation Sg, the value for this variable is set to zero.) + * A Scalar eps can be passed to make the switching condition more strict. + * Useful for avoiding ocsilation in the primaryVarsMeaning. + * + * \return true Iff the interpretation of one of the switching variables was changed + */ + bool adaptPrimaryVariables(const Problem& problem, unsigned globalDofIdx, Scalar eps = 0.0) + { + const LinearizationType linearizationType = problem.simulator().model().linearizer().getLinearizationType(); + static const Scalar thresholdWaterFilledCell = 1.0 - eps; + + // this function accesses quite a few black-oil specific low-level functions + // directly for better performance (instead of going the canonical way through + // the IntensiveQuantities). The reason is that most intensive quantities are not + // required to be able to decide if the primary variables needs to be switched or + // not, so it would be a waste to compute them. + if (primaryVarsMeaning() == OnePhase_p){ + return false; + } + Scalar Sw = 0.0; + if (waterEnabled) + Sw = (*this)[Indices::waterSaturationIdx]; + + if (primaryVarsMeaning() == Sw_po_Sg) { + + // special case for cells with almost only water + if (Sw >= thresholdWaterFilledCell) { + + // make sure water saturations does not exceed 1.0 + if (waterEnabled) + (*this)[Indices::waterSaturationIdx] = 1.0; + // the hydrocarbon gas saturation is set to 0.0 + if (compositionSwitchEnabled) + (*this)[Indices::compositionSwitchIdx] = 0.0; + + return false; + } + + // phase equilibrium, i.e., both hydrocarbon phases are present. + Scalar Sg = 0.0; + if (compositionSwitchEnabled) + Sg = (*this)[Indices::compositionSwitchIdx]; + + Scalar So = 1.0 - Sw - Sg - solventSaturation_(); + + Scalar So2 = 1.0 - Sw - solventSaturation_(); + if (Sg < -eps && So2 > 0.0 && FluidSystem::enableDissolvedGas()) { + // the hydrocarbon gas phase disappeared and some oil phase is left, + // i.e., switch the primary variables to { Sw, po, Rs }. + // + // by a "lucky" coincidence the pressure switching variable already + // represents the oil phase pressure, so we do not need to change + // this. For the gas dissolution factor, we use the low-level blackoil + // PVT objects to calculate the mole fraction of gas saturated oil. + Scalar po; + if (linearizationType.type == Opm::LinearizationType::seqtransport) { + // This should be the oil pressure + po = problem.pressure(globalDofIdx, oilPhaseIdx); + } else { + po = (*this)[Indices::pressureSwitchIdx]; + assert(po>2.0); + } + Scalar T = asImp_().temperature_(); + Scalar SoMax = problem.maxOilSaturation(globalDofIdx); + Scalar RsMax = problem.maxGasDissolutionFactor(/*timeIdx=*/0, globalDofIdx); + Scalar RsSat = FluidSystem::oilPvt().saturatedGasDissolutionFactor(pvtRegionIdx_, + T, + po, + So2, + SoMax); + + setPrimaryVarsMeaning(Sw_po_Rs); + if (compositionSwitchEnabled) + (*this)[Indices::compositionSwitchIdx] = + std::min(RsMax, RsSat); + return true; + } + + Scalar Sg2 = 1.0 - Sw - solventSaturation_(); + if (So < -eps && Sg2 > 0.0 && FluidSystem::enableVaporizedOil()) { + // the oil phase disappeared and some hydrocarbon gas phase is still + // present, i.e., switch the primary variables to { Sw, pg, Rv }. + Scalar po; + if (linearizationType.type == Opm::LinearizationType::seqtransport) { + po = problem.pressure(globalDofIdx, oilPhaseIdx); + } else { + po = (*this)[Indices::pressureSwitchIdx]; + assert(po>2.0); + } + // we only have the oil pressure readily available, but we need the gas + // pressure, i.e. we must determine capillary pressure + Scalar pC[numPhases] = { 0.0 }; + const MaterialLawParams& matParams = problem.materialLawParams(globalDofIdx); + computeCapillaryPressures_(pC, /*So=*/0.0, Sg2 + solventSaturation_(), Sw, matParams); + Scalar pg = po + (pC[gasPhaseIdx] - pC[oilPhaseIdx]); + + // we start at the Rv value that corresponds to that of oil-saturated + // hydrocarbon gas + Scalar T = asImp_().temperature_(); + Scalar SoMax = problem.maxOilSaturation(globalDofIdx); + Scalar RvMax = problem.maxOilVaporizationFactor(/*timeIdx=*/0, globalDofIdx); + Scalar RvSat = + FluidSystem::gasPvt().saturatedOilVaporizationFactor(pvtRegionIdx_, + T, + pg, + Scalar(0), + SoMax); + setPrimaryVarsMeaning(Sw_pg_Rv); + if (not(linearizationType.type == Opm::LinearizationType::seqtransport)) { + (*this)[Indices::pressureSwitchIdx] = pg; + } + if (compositionSwitchEnabled) + (*this)[Indices::compositionSwitchIdx] = std::min(RvMax, RvSat); + + return true; + } + + return false; + } + else if (primaryVarsMeaning() == Sw_po_Rs) { + assert(compositionSwitchEnabled); + + // special case for cells with almost only water + if (Sw >= thresholdWaterFilledCell) { + // switch back to phase equilibrium mode if the oil phase vanishes (i.e., + // the water-only case) + setPrimaryVarsMeaning(Sw_po_Sg); + if (waterEnabled) + (*this)[Indices::waterSaturationIdx] = 1.0; // water saturation + + (*this)[Indices::compositionSwitchIdx] = 0.0; // hydrocarbon gas saturation + + return true; + } + + // Only the oil and the water phases are present. The hydrocarbon gas phase + // appears as soon as more of the gas component is present in the oil phase + // than what saturated oil can hold. + Scalar T = asImp_().temperature_(); + Scalar po; + if (linearizationType.type == Opm::LinearizationType::seqtransport) { + po = problem.pressure(globalDofIdx, oilPhaseIdx); + } else { + po = (*this)[Indices::pressureSwitchIdx]; + assert(po>2.0); + } + Scalar So = 1.0 - Sw - solventSaturation_(); + Scalar SoMax = std::max(So, problem.maxOilSaturation(globalDofIdx)); + Scalar RsMax = problem.maxGasDissolutionFactor(/*timeIdx=*/0, globalDofIdx); + Scalar RsSat = + FluidSystem::oilPvt().saturatedGasDissolutionFactor(pvtRegionIdx_, + T, + po, + So, + SoMax); + + Scalar Rs = (*this)[Indices::compositionSwitchIdx]; + if (Rs > std::min(RsMax, RsSat*(1.0 + eps))) { + // the gas phase appears, i.e., switch the primary variables to { Sw, po, + // Sg }. + setPrimaryVarsMeaning(Sw_po_Sg); + (*this)[Indices::compositionSwitchIdx] = 0.0; // hydrocarbon gas saturation + + return true; + } + + return false; + } + else { + assert(primaryVarsMeaning() == Sw_pg_Rv); + assert(compositionSwitchEnabled); + + Scalar pg; + if (linearizationType.type == Opm::LinearizationType::seqtransport) { + // This should be the gas pressure + pg = problem.pressure(globalDofIdx, gasPhaseIdx); + } else { + pg = (*this)[Indices::pressureSwitchIdx]; + assert(pg>2.0); + } + Scalar Sg = 1.0 - Sw - solventSaturation_(); + + // special case for cells with almost only water + if (Sw >= thresholdWaterFilledCell) { + // switch to phase equilibrium mode because the hydrocarbon gas phase + // disappears. here we need the capillary pressures to calculate the oil + // phase pressure using the gas phase pressure + Scalar pC[numPhases] = { 0.0 }; + const MaterialLawParams& matParams = problem.materialLawParams(globalDofIdx); + computeCapillaryPressures_(pC, + /*So=*/0.0, + /*Sg=*/Sg + solventSaturation_(), + Sw, + matParams); + Scalar po = pg + (pC[oilPhaseIdx] - pC[gasPhaseIdx]); + + setPrimaryVarsMeaning(Sw_po_Sg); + if (waterEnabled) + (*this)[Indices::waterSaturationIdx] = 1.0; + if(not(linearizationType.type == Opm::LinearizationType::seqtransport)){ + (*this)[Indices::pressureSwitchIdx] = po; + } + (*this)[Indices::compositionSwitchIdx] = 0.0; // hydrocarbon gas saturation + + return true; + } + + // Only the gas and the water phases are present. The oil phase appears as + // soon as more of the oil component is present in the hydrocarbon gas phase + // than what saturated gas contains. Note that we use the blackoil specific + // low-level PVT objects here for performance reasons. + Scalar T = asImp_().temperature_(); + Scalar SoMax = problem.maxOilSaturation(globalDofIdx); + Scalar RvMax = problem.maxOilVaporizationFactor(/*timeIdx=*/0, globalDofIdx); + Scalar RvSat = + FluidSystem::gasPvt().saturatedOilVaporizationFactor(pvtRegionIdx_, + T, + pg, + /*So=*/Scalar(0.0), + SoMax); + + Scalar Rv = (*this)[Indices::compositionSwitchIdx]; + if (Rv > std::min(RvMax, RvSat*(1.0 + eps))) { + // switch to phase equilibrium mode because the oil phase appears. here + // we also need the capillary pressures to calculate the oil phase + // pressure using the gas phase pressure + Scalar pC[numPhases] = { 0.0 }; + const MaterialLawParams& matParams = problem.materialLawParams(globalDofIdx); + computeCapillaryPressures_(pC, + /*So=*/0.0, + /*Sg=*/Sg + solventSaturation_(), + Sw, + matParams); + Scalar po = pg + (pC[oilPhaseIdx] - pC[gasPhaseIdx]); + + setPrimaryVarsMeaning(Sw_po_Sg); + if (not(linearizationType.type == Opm::LinearizationType::seqtransport)) { + (*this)[Indices::pressureSwitchIdx] = po; + } + (*this)[Indices::compositionSwitchIdx] = Sg; // hydrocarbon gas saturation + + return true; + } + + return false; + } + + assert(false); + return false; + } + + bool chopAndNormalizeSaturations(){ + if (primaryVarsMeaning() == OnePhase_p){ + return false; + } + Scalar Sw = 0.0; + if (waterEnabled) + Sw = (*this)[Indices::waterSaturationIdx]; + + if (primaryVarsMeaning() == Sw_po_Sg) { + Scalar Sg = 0.0; + if (compositionSwitchEnabled) + Sg = (*this)[Indices::compositionSwitchIdx]; + Scalar Ssol = 0.0; + if (enableSolvent) + Ssol =(*this) [Indices::solventSaturationIdx]; + + Scalar So = 1.0 - Sw - Sg - Ssol; + Sw = std::min(std::max(Sw,0.0),1.0); + So = std::min(std::max(So,0.0),1.0); + Sg = std::min(std::max(Sg,0.0),1.0); + Ssol = std::min(std::max(Ssol,0.0),1.0); + + Scalar St = Sw + So + Sg + Ssol; + Sw = Sw/St; + Sg = Sg/St; + Ssol = Ssol/St; + assert(St>0.5); + if (waterEnabled) + (*this)[Indices::waterSaturationIdx]= Sw; + if (compositionSwitchEnabled) + (*this)[Indices::compositionSwitchIdx] = Sg; + if (enableSolvent) + (*this)[Indices::solventSaturationIdx] = Ssol; + return not(St==1); + + }else if (primaryVarsMeaning() == Sw_po_Rs) { + Scalar Ssol = 0.0; + if (enableSolvent) + Ssol = (*this)[Indices::solventSaturationIdx]; + Scalar So = 1.0 - Sw - Ssol; + Sw = std::min(std::max(Sw,0.0),1.0); + So = std::min(std::max(So,0.0),1.0); + Ssol = std::min(std::max(Ssol,0.0),1.0); + //Sg = 0.0; + Scalar St = Sw + So + Ssol; + assert(St>0.5); + Sw=Sw/St; + Ssol=Ssol/St; + if (waterEnabled) + (*this)[Indices::waterSaturationIdx]= Sw; + if (enableSolvent) + (*this)[Indices::solventSaturationIdx] = Ssol; + return not(St==1); + }else{ + assert(primaryVarsMeaning() == Sw_pg_Rv); + assert(compositionSwitchEnabled); + Scalar Ssol=0.0; + if (enableSolvent) + Ssol = (*this)[Indices::solventSaturationIdx]; + Scalar Sg = 1.0 - Sw - Ssol; + //So = 0.0; + Sw = std::min(std::max(Sw,0.0),1.0); + Sg = std::min(std::max(Sg,0.0),1.0); + Ssol = std::min(std::max(Ssol,0.0),1.0); + Scalar St = Sw + Sg + Ssol; + assert(St>0.5); + Sw=Sw/St; + Ssol=Ssol/St; + if (waterEnabled) + (*this)[Indices::waterSaturationIdx]= Sw; + if (enableSolvent) + (*this)[Indices::solventSaturationIdx] = Ssol; + return not(St==1); + } + assert(false); + } + + EclBlackOilPrimaryVariables& operator=(const EclBlackOilPrimaryVariables& other) = default; + EclBlackOilPrimaryVariables& operator=(Scalar value) + { + for (unsigned i = 0; i < numEq; ++i) + (*this)[i] = value; + + return *this; + } + + /*! + * \brief Instruct valgrind to check the definedness of all attributes of this class. + * + * We cannot simply check the definedness of the whole object because there might be + * "alignedness holes" in the memory layout which are caused by the pseudo primary + * variables. + */ + void checkDefined() const + { +#ifndef NDEBUG + // check the "real" primary variables + for (unsigned i = 0; i < this->size(); ++i) + Opm::Valgrind::CheckDefined((*this)[i]); + + // check the "pseudo" primary variables + Opm::Valgrind::CheckDefined(primaryVarsMeaning_); + Opm::Valgrind::CheckDefined(pvtRegionIdx_); +#endif // NDEBUG + } + +private: + Implementation& asImp_() + { return *static_cast(this); } + + const Implementation& asImp_() const + { return *static_cast(this); } + + Scalar solventSaturation_() const + { + if (!enableSolvent) + return 0.0; + + return (*this)[Indices::solventSaturationIdx]; + } + + Scalar polymerConcentration_() const + { + if (!enablePolymer) + return 0.0; + + return (*this)[Indices::polymerConcentrationIdx]; + } + + Scalar foamConcentration_() const + { + if (!enableFoam) + return 0.0; + + return (*this)[Indices::foamConcentrationIdx]; + } + + Scalar saltConcentration_() const + { + if (!enableBrine) + return 0.0; + + return (*this)[Indices::saltConcentrationIdx]; + } + + Scalar temperature_() const + { + if (!enableEnergy) + return FluidSystem::reservoirTemperature(); + + return (*this)[Indices::temperatureIdx]; + } + + template + void computeCapillaryPressures_(Container& result, + Scalar So, + Scalar Sg, + Scalar Sw, + const MaterialLawParams& matParams) const + { + typedef Opm::SimpleModularFluidState SatOnlyFluidState; + SatOnlyFluidState fluidState; + fluidState.setSaturation(waterPhaseIdx, Sw); + fluidState.setSaturation(oilPhaseIdx, So); + fluidState.setSaturation(gasPhaseIdx, Sg); + + MaterialLaw::capillaryPressures(result, matParams, fluidState); + } + + PrimaryVarsMeaning primaryVarsMeaning_; + unsigned short pvtRegionIdx_; +}; + + +} // namespace Opm + +#endif diff --git a/ebos/eclnewtonmethodseq.hh b/ebos/eclnewtonmethodseq.hh new file mode 100644 index 00000000000..83385e75f0f --- /dev/null +++ b/ebos/eclnewtonmethodseq.hh @@ -0,0 +1,245 @@ +// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +// vi: set et ts=4 sw=4 sts=4: +/* + This file is part of the Open Porous Media project (OPM). + + OPM is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + OPM is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with OPM. If not, see . + + Consult the COPYING file in the top-level source directory of this + module for the precise wording of the license and the list of + copyright holders. +*/ +/*! + * \file + * + * \copydoc Opm::EclNewtonMethod + */ +#ifndef EWOMS_ECL_NEWTON_METHOD_SEQ_HH +#define EWOMS_ECL_NEWTON_METHOD_SEQ_HH + +#include +#include +#include + + +#include + +namespace Opm { + +/*! + * \brief A newton solver which is ebos specific. + */ +template +class EclNewtonMethodSeq : public EclBlackOilNewtonMethod +{ + typedef EclBlackOilNewtonMethod ParentType; + typedef typename GET_PROP_TYPE(TypeTag, DiscNewtonMethod) DiscNewtonMethod; + + typedef typename GET_PROP_TYPE(TypeTag, Simulator) Simulator; + typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; + typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; + typedef typename GET_PROP_TYPE(TypeTag, GlobalEqVector) GlobalEqVector; + typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; + typedef typename GET_PROP_TYPE(TypeTag, EqVector) EqVector; + typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; + typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; + typedef typename GET_PROP_TYPE(TypeTag, Linearizer) Linearizer; + typedef typename GET_PROP_TYPE(TypeTag, ElementContext) ElementContext; + + static const unsigned numEq = GET_PROP_VALUE(TypeTag, NumEq); + + static constexpr int contiSolventEqIdx = Indices::contiSolventEqIdx; + static constexpr int contiPolymerEqIdx = Indices::contiPolymerEqIdx; + static constexpr int contiEnergyEqIdx = Indices::contiEnergyEqIdx; + + friend NewtonMethod; + friend DiscNewtonMethod; + friend ParentType; + +public: + EclNewtonMethodSeq(Simulator& simulator) : ParentType(simulator) + { + errorPvFraction_ = 1.0; + relaxedMaxPvFraction_ = EWOMS_GET_PARAM(TypeTag, Scalar, EclNewtonRelaxedVolumeFraction); + + sumTolerance_ = 0.0; // this gets determined in the error calculation proceedure + relaxedTolerance_ = EWOMS_GET_PARAM(TypeTag, Scalar, EclNewtonRelaxedTolerance); + + numStrictIterations_ = EWOMS_GET_PARAM(TypeTag, int, EclNewtonStrictIterations); + } + + /*! + * \brief Register all run-time parameters for the Newton method. + */ + static void registerParameters() + { + ParentType::registerParameters(); + + EWOMS_REGISTER_PARAM(TypeTag, Scalar, EclNewtonSumTolerance, + "The maximum error tolerated by the Newton" + "method for considering a solution to be " + "converged"); + EWOMS_REGISTER_PARAM(TypeTag, int, EclNewtonStrictIterations, + "The number of Newton iterations where the" + " volumetric error is considered."); + EWOMS_REGISTER_PARAM(TypeTag, Scalar, EclNewtonRelaxedVolumeFraction, + "The fraction of the pore volume of the reservoir " + "where the volumetric error may be voilated during " + "strict Newton iterations."); + EWOMS_REGISTER_PARAM(TypeTag, Scalar, EclNewtonSumToleranceExponent, + "The the exponent used to scale the sum tolerance by " + "the total pore volume of the reservoir."); + EWOMS_REGISTER_PARAM(TypeTag, Scalar, EclNewtonRelaxedTolerance, + "The maximum error which the volumetric residual " + "may exhibit if it is in a 'relaxed' " + "region during a strict iteration."); + } + + /*! + * \brief Returns true if the error of the solution is below the + * tolerance. + */ + bool converged() const + { + if (errorPvFraction_ < relaxedMaxPvFraction_) + return (this->error_ < relaxedTolerance_ && errorSum_ < sumTolerance_) ; + else if (this->numIterations() > numStrictIterations_) + return (this->error_ < relaxedTolerance_ && errorSum_ < sumTolerance_) ; + + return this->error_ <= this->tolerance() && errorSum_ <= sumTolerance_; + } + + void preSolve_(const SolutionVector& currentSolution OPM_UNUSED, + const GlobalEqVector& currentResidual) + { + const auto& constraintsMap = this->model().linearizer().constraintsMap(); + this->lastError_ = this->error_; + Scalar newtonMaxError = EWOMS_GET_PARAM(TypeTag, Scalar, NewtonMaxError); + + // calculate the error as the maximum weighted tolerance of + // the solution's residual + this->error_ = 0.0; + Dune::FieldVector componentSumError; + std::fill(componentSumError.begin(), componentSumError.end(), 0.0); + Scalar sumPv = 0.0; + errorPvFraction_ = 0.0; + const Scalar dt = this->simulator_.timeStepSize(); + for (unsigned dofIdx = 0; dofIdx < currentResidual.size(); ++dofIdx) { + // do not consider auxiliary DOFs for the error + if (dofIdx >= this->model().numGridDof() + || this->model().dofTotalVolume(dofIdx) <= 0.0) + continue; + + if (!this->model().isLocalDof(dofIdx)) + continue; + + // also do not consider DOFs which are constraint + if (this->enableConstraints_()) { + if (constraintsMap.count(dofIdx) > 0) + continue; + } + + const auto& r = currentResidual[dofIdx]; + Scalar pvValue = + this->simulator_.problem().referencePorosity(dofIdx, /*timeIdx=*/0) + * this->model().dofTotalVolume(dofIdx); + sumPv += pvValue; + bool cnvViolated = false; + + Scalar dofVolume = this->model().dofTotalVolume(dofIdx); + + for (unsigned eqIdx = 0; eqIdx < r.size(); ++eqIdx) { + Scalar tmpError = r[eqIdx] * dt * this->model().eqWeight(dofIdx, eqIdx) / pvValue; + Scalar tmpError2 = r[eqIdx] * this->model().eqWeight(dofIdx, eqIdx); + + // in the case of a volumetric formulation, the residual in the above is + // per cubic meter + if (GET_PROP_VALUE(TypeTag, UseVolumetricResidual)) { + tmpError *= dofVolume; + tmpError2 *= dofVolume; + } + + this->error_ = Opm::max(std::abs(tmpError), this->error_); + + if (std::abs(tmpError) > this->tolerance_) + cnvViolated = true; + + componentSumError[eqIdx] += std::abs(tmpError2); + } + if (cnvViolated) + errorPvFraction_ += pvValue; + } + + // take the other processes into account + this->error_ = this->comm_.max(this->error_); + componentSumError = this->comm_.sum(componentSumError); + sumPv = this->comm_.sum(sumPv); + errorPvFraction_ = this->comm_.sum(errorPvFraction_); + + componentSumError /= sumPv; + componentSumError *= dt; + + errorPvFraction_ /= sumPv; + + errorSum_ = 0; + for (unsigned eqIdx = 0; eqIdx < numEq; ++eqIdx) + errorSum_ = std::max(std::abs(componentSumError[eqIdx]), errorSum_); + + // scale the tolerance for the total error with the pore volume. by default, the + // exponent is 1/3, i.e., cubic root. + Scalar x = EWOMS_GET_PARAM(TypeTag, Scalar, EclNewtonSumTolerance); + Scalar y = EWOMS_GET_PARAM(TypeTag, Scalar, EclNewtonSumToleranceExponent); + sumTolerance_ = x*std::pow(sumPv, y); + + this->endIterMsg() << " (max: " << this->tolerance_ << ", violated for " << errorPvFraction_*100 << "% of the pore volume), aggegate error: " << errorSum_ << " (max: " << sumTolerance_ << ")"; + + // make sure that the error never grows beyond the maximum + // allowed one + if (this->error_ > newtonMaxError) + throw Opm::NumericalIssue("Newton: Error "+std::to_string(double(this->error_)) + +" is larger than maximum allowed error of " + +std::to_string(double(newtonMaxError))); + + // make sure that the error never grows beyond the maximum + // allowed one + if (errorSum_ > newtonMaxError) + throw Opm::NumericalIssue("Newton: Sum of the error "+std::to_string(double(errorSum_)) + +" is larger than maximum allowed error of " + +std::to_string(double(newtonMaxError))); + } + + void endIteration_(SolutionVector& nextSolution, + const SolutionVector& currentSolution) + { + ParentType::endIteration_(nextSolution, currentSolution); + OpmLog::debug( "Newton iteration " + std::to_string(this->numIterations_) + "" + + " error: " + std::to_string(double(this->error_)) + + this->endIterMsg().str()); + this->endIterMsg().str(""); + } + +private: + Scalar errorPvFraction_; + Scalar errorSum_; + + Scalar relaxedTolerance_; + Scalar relaxedMaxPvFraction_; + + Scalar sumTolerance_; + + int numStrictIterations_; +}; +} // namespace Opm + +#endif diff --git a/flow/flow_blackoil_dunecpr_seq.cpp b/flow/flow_blackoil_dunecpr_seq.cpp index 200ae61134f..2b86e6356c9 100644 --- a/flow/flow_blackoil_dunecpr_seq.cpp +++ b/flow/flow_blackoil_dunecpr_seq.cpp @@ -23,6 +23,11 @@ #include #include #include +#include +#include +#include +#include + BEGIN_PROPERTIES NEW_TYPE_TAG(EclFlowProblemSimple, INHERITS_FROM(EclFlowProblem)); NEW_PROP_TAG(FluidState); @@ -106,9 +111,10 @@ namespace Opm { // template // BlackOilIntensiveQuantitiesSeq : public BlackOilIntensiveQuantities // {}; - SET_TYPE_PROP(EclFlowProblemSimple, PrimaryVariables, Opm::BlackOilPrimaryVariables); - SET_TYPE_PROP(EclFlowProblemSimple, IntensiveQuantities, Opm::BlackOilIntensiveQuantities); + SET_TYPE_PROP(EclFlowProblemSimple, PrimaryVariables, Opm::EclBlackOilPrimaryVariables); + SET_TYPE_PROP(EclFlowProblemSimple, IntensiveQuantities, Opm::EclBlackOilIntensiveQuantities); SET_TYPE_PROP(EclFlowProblemSimple, FluxModule, Opm::EclTransFluxModuleSeq); + SET_TYPE_PROP(EclFlowProblemSimple, NewtonMethod, Opm::EclNewtonMethodSeq); //SET_TYPE_PROP(EclFlowProblemSimple, LinearSolverBackend, Opm::ISTLSolverEbos); //SET_TAG_PROP(EclFlowProblemSimple, LinearSolverSplice, ParallelBiCGStabLinearSolver); //SET_TYPE_PROP(EclFlowProblemSimple, LinearSolverBackend, Opm::Linear::ParallelBiCGStabSolverBackend);//not work diff --git a/opm/simulators/flow/BlackoilModelEbos.hpp b/opm/simulators/flow/BlackoilModelEbos.hpp index 62d976958fb..9cc824a02b4 100644 --- a/opm/simulators/flow/BlackoilModelEbos.hpp +++ b/opm/simulators/flow/BlackoilModelEbos.hpp @@ -497,7 +497,11 @@ namespace Opm { PressureVectorType rhs(ebosResid.size(),0); PressureHelper::moveToPressureEqn(ebosResid, rhs, weights); boost::property_tree::ptree prm; - boost::property_tree::read_json("pressuresolver.json", prm); + try{ + boost::property_tree::read_json("pressuresolver.json", prm); + }catch(...){ + OPM_THROW(std::logic_error,"Configuration file pressuresolver.json not pressent"); + } std::any parallelInformation; extractParallelGridInformationToISTL(ebosSimulator_.vanguard().grid(), parallelInformation); #if HAVE_MPI From 98dc50156133a8192b552bdaf6850de835c0484b Mon Sep 17 00:00:00 2001 From: hnil Date: Sat, 20 Jun 2020 20:00:01 +0200 Subject: [PATCH 30/93] quite much work for the sequential --- ebos/eclblackoilintensivequantities.hh | 11 +++- ebos/eclblackoilprimaryvariables.hh | 69 ++++++++++++++++----- opm/simulators/flow/BlackoilModelEbos.hpp | 13 ++-- opm/simulators/flow/NonlinearSolverEbos.hpp | 18 ++++-- 4 files changed, 85 insertions(+), 26 deletions(-) diff --git a/ebos/eclblackoilintensivequantities.hh b/ebos/eclblackoilintensivequantities.hh index 9f763b3d427..06f98816fe9 100644 --- a/ebos/eclblackoilintensivequantities.hh +++ b/ebos/eclblackoilintensivequantities.hh @@ -28,6 +28,7 @@ #ifndef EWOMS_ECL_BLACK_OIL_INTENSIVE_QUANTITIES_HH #define EWOMS_ECL_BLACK_OIL_INTENSIVE_QUANTITIES_HH #include +//#include "eclblackoilprimaryvariabels.hh" namespace Opm { /*! * \ingroup BlackOilModel @@ -104,10 +105,16 @@ public: void update(const ElementContext& elemCtx, unsigned dofIdx, unsigned timeIdx) { ParentType::update(elemCtx, dofIdx, timeIdx); - - const auto linearizationType = elemCtx.linearizationType(); const auto& problem = elemCtx.problem(); const auto& priVars = elemCtx.primaryVars(dofIdx, timeIdx); + + const auto linearizationType = elemCtx.linearizationType(); + if(not(linearizationType.type == LinearizationType::seqtransport)){ + assert(priVars.simulationType() == PrimaryVariables::SimulationType::Implicit); + }else{ + assert(priVars.simulationType() == PrimaryVariables::SimulationType::Seq); + } + asImp_().updateTemperature_(elemCtx, dofIdx, timeIdx); diff --git a/ebos/eclblackoilprimaryvariables.hh b/ebos/eclblackoilprimaryvariables.hh index eedbf93ec24..ea06e28de1f 100644 --- a/ebos/eclblackoilprimaryvariables.hh +++ b/ebos/eclblackoilprimaryvariables.hh @@ -96,10 +96,16 @@ public: OnePhase_p, // onephase case }; + enum SimulationType { + Implicit, + Seq + }; + EclBlackOilPrimaryVariables() : ParentType() { Opm::Valgrind::SetUndefined(*this); + simulationType_ = SimulationType::Implicit; pvtRegionIdx_ = 0; } @@ -110,6 +116,7 @@ public: : ParentType(value) { Opm::Valgrind::SetUndefined(primaryVarsMeaning_); + Opm::Valgrind::SetUndefined(simulationType_); pvtRegionIdx_ = 0; } @@ -142,6 +149,9 @@ public: PrimaryVarsMeaning primaryVarsMeaning() const { return primaryVarsMeaning_; } + SimulationType simulationType() const + { return simulationType_; } + /*! * \brief Set the interpretation which should be applied to the switching primary * variables. @@ -149,6 +159,11 @@ public: void setPrimaryVarsMeaning(PrimaryVarsMeaning newMeaning) { primaryVarsMeaning_ = newMeaning; } + /* + void setSimulaiontType(SimulationType simulationType) + { simulaionType_ = simulationType; } + */ + /*! * \copydoc ImmisciblePrimaryVariables::assignMassConservative */ @@ -160,7 +175,6 @@ public: typedef typename std::remove_reference::type ConstEvaluation; typedef typename std::remove_const::type FsEvaluation; typedef typename Opm::MathToolbox FsToolbox; - #ifndef NDEBUG // make sure the temperature is the same in all fluid phases for (unsigned phaseIdx = 1; phaseIdx < numPhases; ++phaseIdx) { @@ -339,6 +353,33 @@ public: if (primaryVarsMeaning() == OnePhase_p){ return false; } + Scalar pressure=-1; + Scalar totalsaturation; + if(simulationType_ == SimulationType::Implicit){ + pressure = (*this)[Indices::pressureSwitchIdx]; + totalsaturation = problem.totalSaturation(globalDofIdx); + }else if (simulationType_ == SimulationType::Seq){ + if(primaryVarsMeaning() == Sw_po_Sg){ + pressure = problem.pressure(globalDofIdx, oilPhaseIdx); + }else if(primaryVarsMeaning() == Sw_po_Rs){ + pressure = problem.pressure(globalDofIdx, oilPhaseIdx); + }else if(primaryVarsMeaning() == Sw_pg_Rv){ + pressure = problem.pressure(globalDofIdx, gasPhaseIdx); + }else{ + assert(false); + } + totalsaturation = (*this)[Indices::pressureSwitchIdx]; + }else{ + assert(false); + } + if(linearizationType.type == LinearizationType::seqtransport){ + (*this)[Indices::pressureSwitchIdx] = totalsaturation; + this->simulationType_ = SimulationType::Seq; + }else{ + (*this)[Indices::pressureSwitchIdx] = pressure; + simulationType_ = SimulationType::Implicit; + } + Scalar Sw = 0.0; if (waterEnabled) Sw = (*this)[Indices::waterSaturationIdx]; @@ -375,12 +416,11 @@ public: // this. For the gas dissolution factor, we use the low-level blackoil // PVT objects to calculate the mole fraction of gas saturated oil. Scalar po; - if (linearizationType.type == Opm::LinearizationType::seqtransport) { - // This should be the oil pressure - po = problem.pressure(globalDofIdx, oilPhaseIdx); - } else { + if (simulationType_ == SimulationType::Implicit){ po = (*this)[Indices::pressureSwitchIdx]; assert(po>2.0); + }else{ + po = problem.pressure(globalDofIdx, oilPhaseIdx); } Scalar T = asImp_().temperature_(); Scalar SoMax = problem.maxOilSaturation(globalDofIdx); @@ -403,11 +443,11 @@ public: // the oil phase disappeared and some hydrocarbon gas phase is still // present, i.e., switch the primary variables to { Sw, pg, Rv }. Scalar po; - if (linearizationType.type == Opm::LinearizationType::seqtransport) { - po = problem.pressure(globalDofIdx, oilPhaseIdx); - } else { + if (simulationType_ == SimulationType::Implicit){ po = (*this)[Indices::pressureSwitchIdx]; assert(po>2.0); + }else{ + po = problem.pressure(globalDofIdx, oilPhaseIdx); } // we only have the oil pressure readily available, but we need the gas // pressure, i.e. we must determine capillary pressure @@ -460,11 +500,11 @@ public: // than what saturated oil can hold. Scalar T = asImp_().temperature_(); Scalar po; - if (linearizationType.type == Opm::LinearizationType::seqtransport) { - po = problem.pressure(globalDofIdx, oilPhaseIdx); - } else { + if (simulationType_ == SimulationType::Implicit) { po = (*this)[Indices::pressureSwitchIdx]; assert(po>2.0); + } else { + po = problem.pressure(globalDofIdx, oilPhaseIdx); } Scalar So = 1.0 - Sw - solventSaturation_(); Scalar SoMax = std::max(So, problem.maxOilSaturation(globalDofIdx)); @@ -493,12 +533,12 @@ public: assert(compositionSwitchEnabled); Scalar pg; - if (linearizationType.type == Opm::LinearizationType::seqtransport) { + if (simulationType_ == SimulationType::Implicit) { // This should be the gas pressure - pg = problem.pressure(globalDofIdx, gasPhaseIdx); - } else { pg = (*this)[Indices::pressureSwitchIdx]; assert(pg>2.0); + } else { + pg = problem.pressure(globalDofIdx, gasPhaseIdx); } Scalar Sg = 1.0 - Sw - solventSaturation_(); @@ -752,6 +792,7 @@ private: } PrimaryVarsMeaning primaryVarsMeaning_; + SimulationType simulationType_; unsigned short pvtRegionIdx_; }; diff --git a/opm/simulators/flow/BlackoilModelEbos.hpp b/opm/simulators/flow/BlackoilModelEbos.hpp index 9cc824a02b4..363675536b1 100644 --- a/opm/simulators/flow/BlackoilModelEbos.hpp +++ b/opm/simulators/flow/BlackoilModelEbos.hpp @@ -190,12 +190,17 @@ namespace Opm { /// Called once before each time step. /// \param[in] timer simulation timer - void prepareStep(const SimulatorTimerInterface& timer) + void prepareStep(const SimulatorTimerInterface& timer, bool next = true) { // update the solution variables in ebos - if ( timer.lastStepFailed() ) { - ebosSimulator_.model().updateFailed(); - } else { + if(next){ + if ( timer.lastStepFailed() ) { + ebosSimulator_.model().updateFailed(); + this->updateSolution(); + } else { + ebosSimulator_.model().advanceTimeLevel(); + } + }else{ ebosSimulator_.model().advanceTimeLevel(); } diff --git a/opm/simulators/flow/NonlinearSolverEbos.hpp b/opm/simulators/flow/NonlinearSolverEbos.hpp index 4c66ef0db61..0dcf4d2790a 100644 --- a/opm/simulators/flow/NonlinearSolverEbos.hpp +++ b/opm/simulators/flow/NonlinearSolverEbos.hpp @@ -146,7 +146,6 @@ namespace Opm { } } - SimulatorReportSingle stepSequential(const SimulatorTimerInterface& timer,bool implicit){ LinearizationType linearizationType; @@ -155,13 +154,18 @@ namespace Opm { SimulatorReportSingle reportseq; int seqiterations = 0; int maxseqiterations = 10; + // should probalby store for trying onse more + //auto solutionOld = this->model().solution(/*timeIdx=*/0); + bool first= true; while(not(converged) && (seqiterations < maxseqiterations) ){ // do pressure step linearizationType.type = Opm::LinearizationType::pressure; + model_->updateSolution(); model_->ebosSimulator().problem().updatePressure();//update pressure ans ST model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); model_->updateSolution();// should conver to the new solution time - SimulatorReportSingle lreportpre = this->stepDefault(timer); + SimulatorReportSingle lreportpre = this->stepDefault(timer, /*next*/first); + first=false; // do transport step model_->ebosSimulator().problem().updatePressure();//update pressure ans ST @@ -169,7 +173,7 @@ namespace Opm { model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); model_->updateSolution(); - SimulatorReportSingle lreportseq = this->stepDefault(timer); + SimulatorReportSingle lreportseq = this->stepDefault(timer,/*next*/false); reportpre += lreportpre; reportseq += lreportseq; // for no not seq implicit @@ -179,7 +183,7 @@ namespace Opm { model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); model_->updateSolution(); - SimulatorReportSingle lreportsim = this->stepDefault(timer); + SimulatorReportSingle lreportsim = this->stepDefault(timer,/*next*/false); converged = lreportsim.converged; }else{ converged = true; @@ -388,14 +392,16 @@ namespace Opm { } - SimulatorReportSingle stepDefault(const SimulatorTimerInterface& timer) + SimulatorReportSingle stepDefault(const SimulatorTimerInterface& timer,bool next = true) { SimulatorReportSingle report; report.global_time = timer.simulationTimeElapsed(); report.timestep_length = timer.currentStepLength(); // Do model-specific once-per-step calculations. - model_->prepareStep(timer); + + model_->prepareStep(timer, next); + int iteration = 0; From 98283df6cbc334a8856e6b4ce372137aa699344a Mon Sep 17 00:00:00 2001 From: hnil Date: Sat, 20 Jun 2020 21:52:46 +0200 Subject: [PATCH 31/93] Seems like a lot of thing go through --- ebos/eclblackoilintensivequantities.hh | 6 ++-- opm/simulators/flow/BlackoilModelEbos.hpp | 14 ++++++-- opm/simulators/flow/NonlinearSolverEbos.hpp | 36 +++++++++++++++------ 3 files changed, 42 insertions(+), 14 deletions(-) diff --git a/ebos/eclblackoilintensivequantities.hh b/ebos/eclblackoilintensivequantities.hh index 06f98816fe9..eedf495fa7f 100644 --- a/ebos/eclblackoilintensivequantities.hh +++ b/ebos/eclblackoilintensivequantities.hh @@ -196,7 +196,7 @@ public: Evaluation ST = 1.0; if (linearizationType.type == Opm::LinearizationType::seqtransport) { ST = priVars.makeEvaluation(Indices::pressureSwitchIdx, timeIdx, linearizationType); - assert(ST<2);// debug to be sure no pressure is pressent + //assert(ST<2);// debug to be sure no pressure is pressent assert(timeIdx==0 || ST == 1);// for pure sequential with multiple steps this is always true. }else if (linearizationType.type == Opm::LinearizationType::pressure) { @@ -214,7 +214,7 @@ public: gasPhaseIdx)); // get current value assuem this is not updated } else { pg = priVars.makeEvaluation(Indices::pressureSwitchIdx, timeIdx, linearizationType); - assert(pg>2.0);//enure not ST is present + //assert(pg>2.0);//enure not ST is present } for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) if (FluidSystem::phaseIsActive(phaseIdx)) @@ -226,7 +226,7 @@ public: po = Toolbox::value(elemCtx.problem().pressure(globalSpaceIdx, oilPhaseIdx)); } else { po = priVars.makeEvaluation(Indices::pressureSwitchIdx, timeIdx, linearizationType); - assert(po>2.0);//enure not ST is present + //assert(po>2.0);//enure not ST is present } for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) if (FluidSystem::phaseIsActive(phaseIdx)) diff --git a/opm/simulators/flow/BlackoilModelEbos.hpp b/opm/simulators/flow/BlackoilModelEbos.hpp index 363675536b1..7601a31695c 100644 --- a/opm/simulators/flow/BlackoilModelEbos.hpp +++ b/opm/simulators/flow/BlackoilModelEbos.hpp @@ -563,8 +563,18 @@ namespace Opm { void updateSolution(){ unsigned numDof = ebosSimulator_.model().numGridDof(); BVector dx(numDof,0); - this->updateSolution(dx); - } + this->updateSolution(dx); + // for(unsigned timeidx; timeidx< 2; ++timidx){ + // SolutionVector& sol = model().solution(/*historyIdx=*/timeidx); + // size_t numGridDof = ebosSimulator_.model().numGridDof(); + // for (unsigned dofIdx = 0; dofIdx < numGridDof; ++dofIdx) { + // sol[dofIdx].adaptPrimaryVariable(ebosSimulator_.problem(),dofIdx); + // } + // ebosSimulator_.model().invalidateIntensiveQuantitiesCache(/*timeIdx=*/0); + // } + + + } /// Apply an update to the primary variables. void updateSolution(const BVector& dx) diff --git a/opm/simulators/flow/NonlinearSolverEbos.hpp b/opm/simulators/flow/NonlinearSolverEbos.hpp index 0dcf4d2790a..cf503be314b 100644 --- a/opm/simulators/flow/NonlinearSolverEbos.hpp +++ b/opm/simulators/flow/NonlinearSolverEbos.hpp @@ -155,16 +155,20 @@ namespace Opm { int seqiterations = 0; int maxseqiterations = 10; // should probalby store for trying onse more - //auto solutionOld = this->model().solution(/*timeIdx=*/0); + auto solutionOld = model_->ebosSimulator().model().solution(/*timeIdx=*/0); bool first= true; while(not(converged) && (seqiterations < maxseqiterations) ){ // do pressure step + if(seqiterations>0){ + auto& prevsol = model_->ebosSimulator().model().solution(/*timeIdx=*/1); + prevsol=solutionOld; + } linearizationType.type = Opm::LinearizationType::pressure; model_->updateSolution(); model_->ebosSimulator().problem().updatePressure();//update pressure ans ST model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); model_->updateSolution();// should conver to the new solution time - SimulatorReportSingle lreportpre = this->stepDefault(timer, /*next*/first); + SimulatorReportSingle lreportpre = this->stepDefault(timer, /*next*/first, false); first=false; // do transport step @@ -173,17 +177,27 @@ namespace Opm { model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); model_->updateSolution(); - SimulatorReportSingle lreportseq = this->stepDefault(timer,/*next*/false); reportpre += lreportpre; - reportseq += lreportseq; + try{ + SimulatorReportSingle lreportseq = this->stepDefault(timer,/*next*/false, false); + reportseq += lreportseq; + }catch (...){ + //set the prevois value to the staring point + auto& prevsol = model_->ebosSimulator().model().solution(/*timeIdx=*/1); + prevsol=solutionOld; + throw; + } + // for no not seq implicit if(implicit){ // for now do full implicit solve + auto& prevsol = model_->ebosSimulator().model().solution(/*timeIdx=*/1); + prevsol=solutionOld; linearizationType.type = Opm::LinearizationType::pressure; model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); model_->updateSolution(); - SimulatorReportSingle lreportsim = this->stepDefault(timer,/*next*/false); + SimulatorReportSingle lreportsim = this->stepDefault(timer,/*next*/false, false); converged = lreportsim.converged; }else{ converged = true; @@ -195,6 +209,7 @@ namespace Opm { if(not(converged)){ report.converged = false; }else{ + model_->afterStep(timer); report.converged = true; } //todo fill this report correctly @@ -373,7 +388,7 @@ namespace Opm { // incase previous step was not fully implicit model_->ebosSimulator().problem().updatePressure();//update pressure ans ST model_->updateSolution(); - SimulatorReportSingle report = this->stepDefault(timer); + SimulatorReportSingle report = this->stepDefault(timer,true,true); return report; } @@ -385,14 +400,15 @@ namespace Opm { model_->ebosSimulator().problem().updatePressure();//update pressure ans ST model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); model_->updateSolution();// should conver to the new solution time - SimulatorReportSingle lreportpre = this->stepDefault(timer); + SimulatorReportSingle lreportpre = this->stepDefault(timer,true,true); SimulatorReportSingle report = lreportpre; //todo fill this report correctly return report; } - SimulatorReportSingle stepDefault(const SimulatorTimerInterface& timer,bool next = true) + //SimulatorReportSingle stepDefault(const SimulatorTimerInterface& timer,bool next = true, bool end) + SimulatorReportSingle stepDefault(const SimulatorTimerInterface& timer,bool next, bool endstep) { SimulatorReportSingle report; report.global_time = timer.simulationTimeElapsed(); @@ -442,7 +458,9 @@ namespace Opm { } // Do model-specific post-step actions. - model_->afterStep(timer); + if(endstep){ + model_->afterStep(timer); + } report.converged = true; return report; } From 19474413489051ae1ad1874fe0799d36d33e7e4e Mon Sep 17 00:00:00 2001 From: hnil Date: Sun, 21 Jun 2020 11:31:01 +0200 Subject: [PATCH 32/93] fixed timestepping for zero error --- opm/simulators/timestepping/TimeStepControl.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/opm/simulators/timestepping/TimeStepControl.cpp b/opm/simulators/timestepping/TimeStepControl.cpp index 9ff748c3bff..d0c50b57f3a 100644 --- a/opm/simulators/timestepping/TimeStepControl.cpp +++ b/opm/simulators/timestepping/TimeStepControl.cpp @@ -136,7 +136,10 @@ namespace Opm errors_[ 2 ] = error; for( int i=0; i<2; ++i ) { assert(std::isfinite(errors_[i])); - assert(errors_[i]>0); + //assert(errors_[i]>0); + if(errors_[i]==0){ + return dt*10; + } } if( error > tol_ ) From 263f6884d200ecb34f43d7ba6e9716a8fab35290 Mon Sep 17 00:00:00 2001 From: hnil Date: Sun, 21 Jun 2020 11:32:14 +0200 Subject: [PATCH 33/93] tried to make less updates to prepeare for iterations --- opm/simulators/flow/BlackoilModelEbos.hpp | 3 ++- opm/simulators/flow/NonlinearSolverEbos.hpp | 8 ++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/opm/simulators/flow/BlackoilModelEbos.hpp b/opm/simulators/flow/BlackoilModelEbos.hpp index 7601a31695c..8e375c28fcf 100644 --- a/opm/simulators/flow/BlackoilModelEbos.hpp +++ b/opm/simulators/flow/BlackoilModelEbos.hpp @@ -201,7 +201,8 @@ namespace Opm { ebosSimulator_.model().advanceTimeLevel(); } }else{ - ebosSimulator_.model().advanceTimeLevel(); + return; + //ebosSimulator_.model().advanceTimeLevel(); } // set the timestep size and episode index for ebos explicitly. ebos needs to diff --git a/opm/simulators/flow/NonlinearSolverEbos.hpp b/opm/simulators/flow/NonlinearSolverEbos.hpp index cf503be314b..6100889e6a2 100644 --- a/opm/simulators/flow/NonlinearSolverEbos.hpp +++ b/opm/simulators/flow/NonlinearSolverEbos.hpp @@ -179,12 +179,16 @@ namespace Opm { model_->updateSolution(); reportpre += lreportpre; try{ + model_->ebosSimulator().model().advanceTimeLevel(); + //model_->ebosSimulator().problem().beginTimeStep(); SimulatorReportSingle lreportseq = this->stepDefault(timer,/*next*/false, false); reportseq += lreportseq; }catch (...){ //set the prevois value to the staring point auto& prevsol = model_->ebosSimulator().model().solution(/*timeIdx=*/1); - prevsol=solutionOld; + prevsol = solutionOld; + auto& currsol = model_->ebosSimulator().model().solution(/*timeIdx=*/0); + currsol = solutionOld; throw; } @@ -193,7 +197,7 @@ namespace Opm { // for now do full implicit solve auto& prevsol = model_->ebosSimulator().model().solution(/*timeIdx=*/1); prevsol=solutionOld; - linearizationType.type = Opm::LinearizationType::pressure; + linearizationType.type = Opm::LinearizationType::implicit; model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); model_->updateSolution(); From 20bde8417b2b1fe9e0dbcd2d30ea63ecd9c771c0 Mon Sep 17 00:00:00 2001 From: hnil Date: Sun, 21 Jun 2020 12:10:26 +0200 Subject: [PATCH 34/93] explitly disable storagechace when implicite sequential: NB give different results with and without storagecach --- opm/simulators/flow/NonlinearSolverEbos.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/opm/simulators/flow/NonlinearSolverEbos.hpp b/opm/simulators/flow/NonlinearSolverEbos.hpp index 6100889e6a2..0942224d389 100644 --- a/opm/simulators/flow/NonlinearSolverEbos.hpp +++ b/opm/simulators/flow/NonlinearSolverEbos.hpp @@ -195,14 +195,19 @@ namespace Opm { // for no not seq implicit if(implicit){ // for now do full implicit solve + //NB storagecache need to be invalidated + bool storagecache = EWOMS_GET_PARAM(TypeTag, bool, EnableStorageCache); + model_->ebosSimulator().model().setEnableStorageCache(false); auto& prevsol = model_->ebosSimulator().model().solution(/*timeIdx=*/1); prevsol=solutionOld; linearizationType.type = Opm::LinearizationType::implicit; model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); model_->updateSolution(); + //NB her only the convergenceshould be checked SimulatorReportSingle lreportsim = this->stepDefault(timer,/*next*/false, false); converged = lreportsim.converged; + //model_->ebosSimulator().model().setEnableStorageCache(storagecache); }else{ converged = true; } From 0968361662e6df6db3bf2964df69acacb6679401 Mon Sep 17 00:00:00 2001 From: hnil Date: Mon, 22 Jun 2020 18:57:48 +0200 Subject: [PATCH 35/93] fixed sign --- ebos/eclfluxmoduleseq.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ebos/eclfluxmoduleseq.hh b/ebos/eclfluxmoduleseq.hh index 3d08cc66508..8f4ded5685f 100644 --- a/ebos/eclfluxmoduleseq.hh +++ b/ebos/eclfluxmoduleseq.hh @@ -451,7 +451,7 @@ protected: const Evaluation& rhoIn = intQuantsIn.fluidState().density(phaseIdx); Scalar rhoEx = Toolbox::value(intQuantsEx.fluidState().density(phaseIdx)); Evaluation rhoAvg = (rhoIn + rhoEx)/2; - headDiff[phaseIdx] = rhoAvg*(distZ*g); + headDiff[phaseIdx] = -1.0*rhoAvg*(distZ*g); // also add capillary part const Evaluation& pcIn = intQuantsIn.fluidState().pc(phaseIdx); From 3fefe860f319db6877028a1661bb9e7379b70880 Mon Sep 17 00:00:00 2001 From: hnil Date: Tue, 23 Jun 2020 09:43:03 +0200 Subject: [PATCH 36/93] fixed unincial --- ebos/eclblackoilprimaryvariables.hh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ebos/eclblackoilprimaryvariables.hh b/ebos/eclblackoilprimaryvariables.hh index ea06e28de1f..dc321708eb3 100644 --- a/ebos/eclblackoilprimaryvariables.hh +++ b/ebos/eclblackoilprimaryvariables.hh @@ -353,8 +353,8 @@ public: if (primaryVarsMeaning() == OnePhase_p){ return false; } - Scalar pressure=-1; - Scalar totalsaturation; + Scalar pressure=-1.0; + Scalar totalsaturation=-1.0; if(simulationType_ == SimulationType::Implicit){ pressure = (*this)[Indices::pressureSwitchIdx]; totalsaturation = problem.totalSaturation(globalDofIdx); From 21d006f725a755f6fcff2d9b65392b24bcb96e02 Mon Sep 17 00:00:00 2001 From: hnil Date: Tue, 23 Jun 2020 13:37:37 +0200 Subject: [PATCH 37/93] Try to fix the well part --- opm/simulators/flow/NonlinearSolverEbos.hpp | 3 + opm/simulators/wells/StandardWell_impl.hpp | 191 +++++++++++++++++++- 2 files changed, 191 insertions(+), 3 deletions(-) diff --git a/opm/simulators/flow/NonlinearSolverEbos.hpp b/opm/simulators/flow/NonlinearSolverEbos.hpp index 0942224d389..1eab166ff3c 100644 --- a/opm/simulators/flow/NonlinearSolverEbos.hpp +++ b/opm/simulators/flow/NonlinearSolverEbos.hpp @@ -182,6 +182,8 @@ namespace Opm { model_->ebosSimulator().model().advanceTimeLevel(); //model_->ebosSimulator().problem().beginTimeStep(); SimulatorReportSingle lreportseq = this->stepDefault(timer,/*next*/false, false); + // hopefully do not change any thing only update well quantities + model_->wellModel().assemble(0,ebosSimulator_.timeStepSize()); reportseq += lreportseq; }catch (...){ //set the prevois value to the staring point @@ -211,6 +213,7 @@ namespace Opm { }else{ converged = true; } + std::cout << "Sequantial iteration " << seqiterations << std::endl; seqiterations += 1; } diff --git a/opm/simulators/wells/StandardWell_impl.hpp b/opm/simulators/wells/StandardWell_impl.hpp index f3d26a2e613..6d710ea0271 100644 --- a/opm/simulators/wells/StandardWell_impl.hpp +++ b/opm/simulators/wells/StandardWell_impl.hpp @@ -351,8 +351,11 @@ namespace Opm const int perf, const bool allow_cf, PerfRates& perf_rates, - Opm::DeferredLogger& deferred_logger) const + Opm::DeferredLogger& deferred_logger, + LinearizationType linearizatonType) const { + //LinearizationType linearizatonType = ebosSimulator().linearizer().getLinarizationType(); + if(not(linearizationType == LinearizationType::Seq){ auto& cq_s = perf_rates.cq_s; auto& cq_r = perf_rates.cq_r; auto& cq_r_t = perf_rates.cq_r_t; @@ -424,8 +427,8 @@ namespace Opm } // Using total mobilities - EvalWell total_mob_dense = mob[0]; - for (int componentIdx = 1; componentIdx < num_components_; ++componentIdx) { + EvalWell total_mob_dense = 0; + for (int componentIdx = 0; componentIdx < num_components_; ++componentIdx) { total_mob_dense += mob[componentIdx]; cq_r[componentIdx] = - Tw * (mob[componentIdx] * drawdown); cq_r_t += cq_r[componentIdx]; @@ -3194,10 +3197,192 @@ namespace Opm } } } + } + + auto cq_s_tmp = perf_rates.cq_s; + if(not(linearizationType.type == LinearizationType::Seq)){ + perf_rates.cq_r_t = well_state.perfTotalResRate(index_of_well_ + perf); + } + computePerfRateNew(intQuants,mob,/*bhp,Tw,*/perf,allow_cf,perf_rates,deferred_logger); + if(not(linearizationType.type == LinearizationType::Seq)){ + for(int i = 0; i < cq_s_tmp.size(); ++i){ + isSame(cq_s_tmp[i],perf_rates.cq_s[i],1e-6); + } + } } + template + void + StandardWell:: + computePerfRateNew(const IntensiveQuantities& intQuants, + const std::vector& mob, + //const EvalWell& bhp, + //const double Tw, + const int perf, + const bool allow_cf, + PerfRates& perf_rates, + Opm::DeferredLogger& deferred_logger) const + { + auto& cq_s = perf_rates.cq_s; + const auto& cq_r = perf_rates.cq_r; + const auto& cq_r_t = perf_rates.cq_r_t; + + const auto& fs = intQuants.fluidState(); + const EvalWell pressure = extendEval(getPerfCellPressure(fs)); + const EvalWell rs = extendEval(fs.Rs()); + const EvalWell rv = extendEval(fs.Rv()); + std::vector b_perfcells_dense(num_components_, EvalWell{numWellEq_ + numEq, 0.0}); + for (unsigned phaseIdx = 0; phaseIdx < FluidSystem::numPhases; ++phaseIdx) { + if (!FluidSystem::phaseIsActive(phaseIdx)) { + continue; + } + + const unsigned compIdx = Indices::canonicalToActiveComponentIndex(FluidSystem::solventComponentIndex(phaseIdx)); + b_perfcells_dense[compIdx] = extendEval(fs.invB(phaseIdx)); + } + if (has_solvent) { + b_perfcells_dense[contiSolventEqIdx] = extendEval(intQuants.solventInverseFormationVolumeFactor()); + } + + + if (this->has_polymermw && this->isInjector()) { + const int pskin_index = Bhp + 1 + number_of_perforations_ + perf; + const EvalWell& skin_pressure = primary_variables_evaluation_[pskin_index]; + drawdown += skin_pressure; + } + + // producing perforations + if ( cq_r_t < 0 ) { + //Do nothing if crossflow is not allowed + if (!allow_cf && this->isInjector()) { + return; + } + + EvalWell mobt = 0.0; + for (int componentIdx = 0; componentIdx < num_components_; ++componentIdx) { + mobt += mob[componentIdx]; + } + // compute component volumetric rates at standard conditions + for (int componentIdx = 0; componentIdx < num_components_; ++componentIdx) { + const EvalWell cq_p = mob[componentIdx]/mobt * cq_r_t; + perf_rates.cq_s[componentIdx] = b_perfcells_dense[componentIdx] * cq_p; + } + + if (FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx) && FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)) { + const unsigned oilCompIdx = Indices::canonicalToActiveComponentIndex(FluidSystem::oilCompIdx); + const unsigned gasCompIdx = Indices::canonicalToActiveComponentIndex(FluidSystem::gasCompIdx); + const EvalWell cq_sOil = cq_s[oilCompIdx]; + const EvalWell cq_sGas = cq_s[gasCompIdx]; + const EvalWell dis_gas = rs * cq_sOil; + const EvalWell vap_oil = rv * cq_sGas; + + perf_rates.cq_s[gasCompIdx] += dis_gas; + cq_s[oilCompIdx] += vap_oil; + + // recording the perforation solution gas rate and solution oil rates + if (this->isProducer()) { + perf_rates.perf_dis_gas_rate = dis_gas.value(); + perf_rates.perf_vap_oil_rate = vap_oil.value(); + } + } + + } else { + //Do nothing if crossflow is not allowed + if (!allow_cf && this->isProducer()) { + return; + } + + // // Using total mobilities + // EvalWell total_mob_dense = + // for (int componentIdx = 0; componentIdx < num_components_; ++componentIdx) { + // total_mob_dense += mob[componentIdx]; + // cq_r[componentIdx] = - Tw * (mob[componentIdx] * drawdown); + // cq_r_t += cq_r[componentIdx]; + // } + // TODO: cqt_i should be same with cq_r_t, there is some repeated computation here + // injection perforations total volume rates + const EvalWell cqt_i = cq_r_t; + + // surface volume fraction of fluids within wellbore + std::vector cmix_s(num_components_, EvalWell{numWellEq_ + numEq}); + for (int componentIdx = 0; componentIdx < num_components_; ++componentIdx) { + cmix_s[componentIdx] = wellSurfaceVolumeFraction(componentIdx); + } + + // compute volume ratio between connection at standard conditions + EvalWell volumeRatio(numWellEq_ + numEq, 0.); + if (FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx)) { + const unsigned waterCompIdx = Indices::canonicalToActiveComponentIndex(FluidSystem::waterCompIdx); + volumeRatio += cmix_s[waterCompIdx] / b_perfcells_dense[waterCompIdx]; + } + + if (has_solvent) { + volumeRatio += cmix_s[contiSolventEqIdx] / b_perfcells_dense[contiSolventEqIdx]; + } + + if (FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx) && FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)) { + const unsigned oilCompIdx = Indices::canonicalToActiveComponentIndex(FluidSystem::oilCompIdx); + const unsigned gasCompIdx = Indices::canonicalToActiveComponentIndex(FluidSystem::gasCompIdx); + // Incorporate RS/RV factors if both oil and gas active + const EvalWell d = EvalWell(numWellEq_ + numEq, 1.0) - rv * rs; + + if (d.value() == 0.0) { + OPM_DEFLOG_THROW(Opm::NumericalIssue, "Zero d value obtained for well " << name() << " during flux calcuation" + << " with rs " << rs << " and rv " << rv, deferred_logger); + } + + const EvalWell tmp_oil = (cmix_s[oilCompIdx] - rv * cmix_s[gasCompIdx]) / d; + //std::cout << "tmp_oil " <isProducer()) { + if (FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx) && FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)) { + const unsigned oilCompIdx = Indices::canonicalToActiveComponentIndex(FluidSystem::oilCompIdx); + const unsigned gasCompIdx = Indices::canonicalToActiveComponentIndex(FluidSystem::gasCompIdx); + // TODO: the formulations here remain to be tested with cases with strong crossflow through production wells + // s means standard condition, r means reservoir condition + // q_os = q_or * b_o + rv * q_gr * b_g + // q_gs = q_gr * g_g + rs * q_or * b_o + // d = 1.0 - rs * rv + // q_or = 1 / (b_o * d) * (q_os - rv * q_gs) + // q_gr = 1 / (b_g * d) * (q_gs - rs * q_os) + + const double d = 1.0 - rv.value() * rs.value(); + // vaporized oil into gas + // rv * q_gr * b_g = rv * (q_gs - rs * q_os) / d + perf_rates.perf_vap_oil_rate = rv.value() * (cq_s[gasCompIdx].value() - rs.value() * cq_s[oilCompIdx].value()) / d; + // dissolved of gas in oil + // rs * q_or * b_o = rs * (q_os - rv * q_gs) / d + perf_rates.perf_dis_gas_rate = rs.value() * (cq_s[oilCompIdx].value() - rv.value() * cq_s[gasCompIdx].value()) / d; + } + } + } + } template From 9b7df50b5f2945f93e7cc62e3e748b3756838bae Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Tue, 23 Jun 2020 12:13:25 +0200 Subject: [PATCH 38/93] adding perfTotalResRates to WellStateFullyImplicitBlackoil --- opm/simulators/wells/StandardWell_impl.hpp | 1 + .../wells/WellStateFullyImplicitBlackoil.hpp | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/opm/simulators/wells/StandardWell_impl.hpp b/opm/simulators/wells/StandardWell_impl.hpp index 6d710ea0271..9e0922c0048 100644 --- a/opm/simulators/wells/StandardWell_impl.hpp +++ b/opm/simulators/wells/StandardWell_impl.hpp @@ -641,6 +641,7 @@ namespace Opm } } this->conTotalResRates_[perf] = this->restrictEval(perf_rates.cq_r_t * well_efficiency_factor_); + well_state.perfTotalResRates()[first_perf_ + perf] = perf_rates.cq_r_t.value(); if (has_energy) { diff --git a/opm/simulators/wells/WellStateFullyImplicitBlackoil.hpp b/opm/simulators/wells/WellStateFullyImplicitBlackoil.hpp index fa48668c3ad..e99dd3dd7ee 100644 --- a/opm/simulators/wells/WellStateFullyImplicitBlackoil.hpp +++ b/opm/simulators/wells/WellStateFullyImplicitBlackoil.hpp @@ -123,6 +123,8 @@ namespace Opm perfphaserates_.clear(); perfphaserates_.resize(nperf * np, 0.0); + perf_total_res_rates_.assign(nperf * np, 0.0); + // these are only used to monitor the injectivity perf_water_throughput_.clear(); perf_water_throughput_.resize(nperf, 0.0); @@ -142,6 +144,8 @@ namespace Opm if (wells_ecl[w].getStatus() == Well::Status::OPEN) { for (int p = 0; p < np; ++p) { perfphaserates_[np*perf + p] = wellRates()[np*w + p] / double(num_perf_this_well); + // TODO: probably not good for gas rates + perf_total_res_rates_[np*perf + p] = perfphaserates_[np*perf + p]; } } perfPress()[perf] = cellPressures[well_perf_data[w][perf-connpos].cell_index]; @@ -220,6 +224,7 @@ namespace Opm perf_phase_idx < (connpos + num_perf_this_well)*np; ++perf_phase_idx, ++old_perf_phase_idx ) { perfPhaseRates()[ perf_phase_idx ] = prevState->perfPhaseRates()[ old_perf_phase_idx ]; + perfTotalResRates()[ perf_phase_idx ] = prevState->perfTotalResRates()[ old_perf_phase_idx ]; } } else { for (int perf = connpos; perf < connpos + num_perf_this_well; ++perf) { @@ -321,6 +326,10 @@ namespace Opm std::vector& perfPhaseRates() { return perfphaserates_; } const std::vector& perfPhaseRates() const { return perfphaserates_; } + std::vector& perfTotalResRates() { return perf_total_res_rates_; } + const std::vector& perfTotalResRates() const { return perf_total_res_rates_; } + + /// One current control per injecting well. std::vector& currentInjectionControls() { return current_injection_controls_; } const std::vector& currentInjectionControls() const { return current_injection_controls_; } @@ -1088,6 +1097,10 @@ namespace Opm // iterate over all perforations of a given well // for (int perf = first_perf_index_[well_index]; perf < first_perf_index_[well_index+1]; ++perf) std::vector first_perf_index_; + + // perforation total reservoir volume rates + std::vector perf_total_res_rates_; + std::vector current_injection_controls_; std::vector current_production_controls_; From df134c12be471f2df3eaa89638f118483ed35243 Mon Sep 17 00:00:00 2001 From: hnil Date: Tue, 23 Jun 2020 16:30:04 +0200 Subject: [PATCH 39/93] added possibility to solve wells --- opm/simulators/wells/BlackoilWellModel.hpp | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/opm/simulators/wells/BlackoilWellModel.hpp b/opm/simulators/wells/BlackoilWellModel.hpp index 38cb97647a1..e12849accc5 100644 --- a/opm/simulators/wells/BlackoilWellModel.hpp +++ b/opm/simulators/wells/BlackoilWellModel.hpp @@ -162,6 +162,28 @@ namespace Opm { ebosSimulator_.timeStepSize()); } + void solveWells(double dt){ + last_report_ = SimulatorReportSingle(); + if ( ! wellsActive() ) { + return; + } + bool converged; + int exception_thrown = 0; + Opm::DeferredLogger local_deferredLogger; + try{ + updatePerforationIntensiveQuantities(); + std::vector< Scalar > B_avg(numComponents(), Scalar() ); + computeAverageFormationFactor(B_avg); + updatePerforationIntensiveQuantities(); + last_report_ = solveWellEq(B_avg, dt, local_deferredLogger); + } catch (std::exception& e) { + exception_thrown = 1; + } + logAndCheckForExceptionsAndThrow(local_deferredLogger, exception_thrown, "assemble() failed.", terminal_output_); + + last_report_.converged = true; + } + void endIteration() { } From 82105055e427aa643078525bd8db94dda95c6691 Mon Sep 17 00:00:00 2001 From: hnil Date: Tue, 23 Jun 2020 16:30:36 +0200 Subject: [PATCH 40/93] added solving of wells --- opm/simulators/flow/NonlinearSolverEbos.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/opm/simulators/flow/NonlinearSolverEbos.hpp b/opm/simulators/flow/NonlinearSolverEbos.hpp index 1eab166ff3c..f93c8ce68f1 100644 --- a/opm/simulators/flow/NonlinearSolverEbos.hpp +++ b/opm/simulators/flow/NonlinearSolverEbos.hpp @@ -183,7 +183,7 @@ namespace Opm { //model_->ebosSimulator().problem().beginTimeStep(); SimulatorReportSingle lreportseq = this->stepDefault(timer,/*next*/false, false); // hopefully do not change any thing only update well quantities - model_->wellModel().assemble(0,ebosSimulator_.timeStepSize()); + model_->wellModel().solveWells(model_->ebosSimulator().timeStepSize()); reportseq += lreportseq; }catch (...){ //set the prevois value to the staring point @@ -198,7 +198,7 @@ namespace Opm { if(implicit){ // for now do full implicit solve //NB storagecache need to be invalidated - bool storagecache = EWOMS_GET_PARAM(TypeTag, bool, EnableStorageCache); + //bool storagecache = EWOMS_GET_PARAM(TypeTag, bool, EnableStorageCache); model_->ebosSimulator().model().setEnableStorageCache(false); auto& prevsol = model_->ebosSimulator().model().solution(/*timeIdx=*/1); prevsol=solutionOld; @@ -209,6 +209,7 @@ namespace Opm { //NB her only the convergenceshould be checked SimulatorReportSingle lreportsim = this->stepDefault(timer,/*next*/false, false); converged = lreportsim.converged; + // if this used one probably have to invalidate the storage cache //model_->ebosSimulator().model().setEnableStorageCache(storagecache); }else{ converged = true; From 50410c793b84aa5e4a0738cb164575a6bd9ad8d5 Mon Sep 17 00:00:00 2001 From: hnil Date: Tue, 23 Jun 2020 16:49:12 +0200 Subject: [PATCH 41/93] tried to make minimal change for using wellstate --- opm/simulators/wells/StandardWell.hpp | 17 +++++-- opm/simulators/wells/StandardWell_impl.hpp | 59 +++++++++++----------- 2 files changed, 43 insertions(+), 33 deletions(-) diff --git a/opm/simulators/wells/StandardWell.hpp b/opm/simulators/wells/StandardWell.hpp index 6b8b3396450..fe845ed019d 100644 --- a/opm/simulators/wells/StandardWell.hpp +++ b/opm/simulators/wells/StandardWell.hpp @@ -34,7 +34,7 @@ #include #include #include - +#include #include #include @@ -390,15 +390,26 @@ namespace Opm { } }; - + + void computePerfRateSeq(const IntensiveQuantities& intQuants, + const std::vector& mob, + //const EvalWell& bhp, + //const double Tw, + //const int perf, + const bool allow_cf, + PerfRates& perf_rates, + Opm::DeferredLogger& deferred_logger) const; + void computePerfRate(const IntensiveQuantities& intQuants, const std::vector& mob, const EvalWell& bhp, + const WellState& well_state, const double Tw, const int perf, const bool allow_cf, PerfRates& perf_rates, - Opm::DeferredLogger& deferred_logger) const; + Opm::DeferredLogger& deferred_logger, + const Opm::LinearizationType& linearizatonType) const; void computeWellRatesWithBhp(const Simulator& ebosSimulator, const double& bhp, diff --git a/opm/simulators/wells/StandardWell_impl.hpp b/opm/simulators/wells/StandardWell_impl.hpp index 9e0922c0048..24c9eb2adf6 100644 --- a/opm/simulators/wells/StandardWell_impl.hpp +++ b/opm/simulators/wells/StandardWell_impl.hpp @@ -23,6 +23,7 @@ #include #include #include +// #include namespace Opm { @@ -347,15 +348,16 @@ namespace Opm computePerfRate(const IntensiveQuantities& intQuants, const std::vector& mob, const EvalWell& bhp, + const WellState& well_state, const double Tw, const int perf, const bool allow_cf, PerfRates& perf_rates, Opm::DeferredLogger& deferred_logger, - LinearizationType linearizatonType) const + const Opm::LinearizationType& linearizationType) const { //LinearizationType linearizatonType = ebosSimulator().linearizer().getLinarizationType(); - if(not(linearizationType == LinearizationType::Seq){ + if(not(linearizationType.type == Opm::LinearizationType::seqtransport)){ auto& cq_s = perf_rates.cq_s; auto& cq_r = perf_rates.cq_r; auto& cq_r_t = perf_rates.cq_r_t; @@ -427,7 +429,7 @@ namespace Opm } // Using total mobilities - EvalWell total_mob_dense = 0; + EvalWell total_mob_dense =mob[0]* 0.0; for (int componentIdx = 0; componentIdx < num_components_; ++componentIdx) { total_mob_dense += mob[componentIdx]; cq_r[componentIdx] = - Tw * (mob[componentIdx] * drawdown); @@ -592,8 +594,9 @@ namespace Opm PerfRates perf_rates(num_components_, numWellEq_); double trans_mult = ebosSimulator.problem().template rockCompTransMultiplier(intQuants, cell_idx); const double Tw = well_index_[perf] * trans_mult; - computePerfRate(intQuants, mob, bhp, Tw, perf, allow_cf, - perf_rates, deferred_logger); + const LinearizationType& linearizationType = ebosSimulator.model().linearizer().getLinearizationType(); + computePerfRate(intQuants, mob, bhp, well_state, Tw, perf, allow_cf, + perf_rates, deferred_logger, linearizationType); // better way to do here is that use the cq_s and then replace the cq_s_water here? if (has_polymer && this->has_polymermw && this->isInjector()) { @@ -2485,7 +2488,7 @@ namespace Opm const double Tw = well_index_[perf] * trans_mult; PerfRates perf_rates(num_components_, numWellEq_); - computePerfRate(intQuants, mob, EvalWell(numWellEq_ + numEq, bhp), Tw, perf, allow_cf, + computePerfRate(intQuants, mob, EvalWell(numWellEq_ + numEq, bhp), well_state, Tw, perf, allow_cf, perf_rates, deferred_logger); for(int p = 0; p < np; ++p) { @@ -2868,7 +2871,8 @@ namespace Opm PerfRates perf_rates(num_components_, numWellEq_); double trans_mult = ebos_simulator.problem().template rockCompTransMultiplier(int_quant, cell_idx); const double Tw = well_index_[perf] * trans_mult; - computePerfRate(int_quant, mob, bhp, Tw, perf, allow_cf, perf_rates, deferred_logger); + LinearizationType linearizationType = ebos_simulator.model().linearizer().getLinearizationType(); + computePerfRate(int_quant, mob, bhp, well_state, Tw, perf, allow_cf, perf_rates, deferred_logger, linearizationType); // TODO: make area a member const double area = 2 * M_PI * perf_rep_radius_[perf] * perf_length_[perf]; const auto& material_law_manager = ebos_simulator.problem().materialLawManager(); @@ -3201,13 +3205,14 @@ namespace Opm } auto cq_s_tmp = perf_rates.cq_s; - if(not(linearizationType.type == LinearizationType::Seq)){ - perf_rates.cq_r_t = well_state.perfTotalResRate(index_of_well_ + perf); + if(not(linearizationType.type == Opm::LinearizationType::seqtransport)){ + perf_rates.cq_r_t = well_state.perfTotalResRates()[first_perf_ + perf]; } - computePerfRateNew(intQuants,mob,/*bhp,Tw,*/perf,allow_cf,perf_rates,deferred_logger); - if(not(linearizationType.type == LinearizationType::Seq)){ + computePerfRateSeq(intQuants,mob,/*bhp,Tw,perf,*/allow_cf,perf_rates,deferred_logger); + if(not(linearizationType.type == Opm::LinearizationType::seqtransport)){ for(int i = 0; i < cq_s_tmp.size(); ++i){ - isSame(cq_s_tmp[i],perf_rates.cq_s[i],1e-6); + typedef Opm::MathToolbox Toolbox; + assert(Toolbox::isSame(cq_s_tmp[i],perf_rates.cq_s[i],1e-6)); } } } @@ -3216,23 +3221,24 @@ namespace Opm template void StandardWell:: - computePerfRateNew(const IntensiveQuantities& intQuants, - const std::vector& mob, + computePerfRateSeq(const IntensiveQuantities& intQuants, + const std::vector& mob, //const EvalWell& bhp, //const double Tw, - const int perf, - const bool allow_cf, - PerfRates& perf_rates, - Opm::DeferredLogger& deferred_logger) const + //const int perf, + const bool allow_cf, + PerfRates& perf_rates, + Opm::DeferredLogger& deferred_logger) const { auto& cq_s = perf_rates.cq_s; - const auto& cq_r = perf_rates.cq_r; + //const auto& cq_r = perf_rates.cq_r; const auto& cq_r_t = perf_rates.cq_r_t; const auto& fs = intQuants.fluidState(); const EvalWell pressure = extendEval(getPerfCellPressure(fs)); const EvalWell rs = extendEval(fs.Rs()); const EvalWell rv = extendEval(fs.Rv()); + const EvalWell ST = extendEval(fs.totalSaturation()); std::vector b_perfcells_dense(num_components_, EvalWell{numWellEq_ + numEq, 0.0}); for (unsigned phaseIdx = 0; phaseIdx < FluidSystem::numPhases; ++phaseIdx) { if (!FluidSystem::phaseIsActive(phaseIdx)) { @@ -3246,27 +3252,21 @@ namespace Opm b_perfcells_dense[contiSolventEqIdx] = extendEval(intQuants.solventInverseFormationVolumeFactor()); } - - if (this->has_polymermw && this->isInjector()) { - const int pskin_index = Bhp + 1 + number_of_perforations_ + perf; - const EvalWell& skin_pressure = primary_variables_evaluation_[pskin_index]; - drawdown += skin_pressure; - } - - // producing perforations + // producing perforations if ( cq_r_t < 0 ) { //Do nothing if crossflow is not allowed if (!allow_cf && this->isInjector()) { return; } - EvalWell mobt = 0.0; + EvalWell mobt = mob[0]*0.0; for (int componentIdx = 0; componentIdx < num_components_; ++componentIdx) { mobt += mob[componentIdx]; } // compute component volumetric rates at standard conditions for (int componentIdx = 0; componentIdx < num_components_; ++componentIdx) { - const EvalWell cq_p = mob[componentIdx]/mobt * cq_r_t; + // do upwinding of total saturation and mobility and totalmobility + const EvalWell cq_p = ST*mob[componentIdx]/mobt * cq_r_t; perf_rates.cq_s[componentIdx] = b_perfcells_dense[componentIdx] * cq_p; } @@ -3876,7 +3876,6 @@ namespace Opm ->bhp(controls.vfp_table_number, rates[Water], rates[Oil], rates[Gas], controls.thp_limit) - dp; }; - // Make the flo() function. auto flo_type = table.getFloType(); auto flo = [flo_type](const std::vector& rates) { return detail::getFlo(rates[Water], rates[Oil], rates[Gas], flo_type); From e9d67491f6a9e2e2d0e6d38fc7f6ec67b0cb1305 Mon Sep 17 00:00:00 2001 From: hnil Date: Tue, 23 Jun 2020 17:00:06 +0200 Subject: [PATCH 42/93] compile again --- opm/simulators/wells/StandardWell_impl.hpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/opm/simulators/wells/StandardWell_impl.hpp b/opm/simulators/wells/StandardWell_impl.hpp index 24c9eb2adf6..d72c15a6302 100644 --- a/opm/simulators/wells/StandardWell_impl.hpp +++ b/opm/simulators/wells/StandardWell_impl.hpp @@ -2488,8 +2488,10 @@ namespace Opm const double Tw = well_index_[perf] * trans_mult; PerfRates perf_rates(num_components_, numWellEq_); + const LinearizationType& linearizationType = ebosSimulator.model().linearizer().getLinearizationType(); + const WellState& well_state = ebosSimulator.problem().wellModel().wellState(); computePerfRate(intQuants, mob, EvalWell(numWellEq_ + numEq, bhp), well_state, Tw, perf, allow_cf, - perf_rates, deferred_logger); + perf_rates, deferred_logger, linearizationType); for(int p = 0; p < np; ++p) { well_flux[ebosCompIdxToFlowCompIdx(p)] += perf_rates.cq_s[p].value(); @@ -2872,6 +2874,7 @@ namespace Opm double trans_mult = ebos_simulator.problem().template rockCompTransMultiplier(int_quant, cell_idx); const double Tw = well_index_[perf] * trans_mult; LinearizationType linearizationType = ebos_simulator.model().linearizer().getLinearizationType(); + const WellState& well_state = ebos_simulator.problem().wellModel().wellState(); computePerfRate(int_quant, mob, bhp, well_state, Tw, perf, allow_cf, perf_rates, deferred_logger, linearizationType); // TODO: make area a member const double area = 2 * M_PI * perf_rep_radius_[perf] * perf_length_[perf]; @@ -3210,7 +3213,7 @@ namespace Opm } computePerfRateSeq(intQuants,mob,/*bhp,Tw,perf,*/allow_cf,perf_rates,deferred_logger); if(not(linearizationType.type == Opm::LinearizationType::seqtransport)){ - for(int i = 0; i < cq_s_tmp.size(); ++i){ + for(size_t i = 0; i < cq_s_tmp.size(); ++i){ typedef Opm::MathToolbox Toolbox; assert(Toolbox::isSame(cq_s_tmp[i],perf_rates.cq_s[i],1e-6)); } From 9ad2c97daa2fd92917bbbb0fd1e2a41e630ea4dd Mon Sep 17 00:00:00 2001 From: hnil Date: Wed, 24 Jun 2020 09:35:58 +0200 Subject: [PATCH 43/93] some fixes --- opm/simulators/wells/StandardWell_impl.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/opm/simulators/wells/StandardWell_impl.hpp b/opm/simulators/wells/StandardWell_impl.hpp index d72c15a6302..01eb95470f3 100644 --- a/opm/simulators/wells/StandardWell_impl.hpp +++ b/opm/simulators/wells/StandardWell_impl.hpp @@ -3208,11 +3208,11 @@ namespace Opm } auto cq_s_tmp = perf_rates.cq_s; - if(not(linearizationType.type == Opm::LinearizationType::seqtransport)){ - perf_rates.cq_r_t = well_state.perfTotalResRates()[first_perf_ + perf]; + if(linearizationType.type == Opm::LinearizationType::seqtransport){ + perf_rates.cq_r_t = well_state.perfTotalResRates()[first_perf_ + perf]; } - computePerfRateSeq(intQuants,mob,/*bhp,Tw,perf,*/allow_cf,perf_rates,deferred_logger); - if(not(linearizationType.type == Opm::LinearizationType::seqtransport)){ + computePerfRateSeq(intQuants,mob,/*bhp,Tw,perf,*/allow_cf,perf_rates,deferred_logger); + if(not(linearizationType.type == Opm::LinearizationType::seqtransport)){ for(size_t i = 0; i < cq_s_tmp.size(); ++i){ typedef Opm::MathToolbox Toolbox; assert(Toolbox::isSame(cq_s_tmp[i],perf_rates.cq_s[i],1e-6)); From c9af1fbc07a16c8db43151b49da78e76b4f70d2b Mon Sep 17 00:00:00 2001 From: hnil Date: Wed, 24 Jun 2020 09:51:57 +0200 Subject: [PATCH 44/93] Force ST to be 1 at start of sequential step --- ebos/eclblackoilintensivequantities.hh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ebos/eclblackoilintensivequantities.hh b/ebos/eclblackoilintensivequantities.hh index eedf495fa7f..d2f9cb947bd 100644 --- a/ebos/eclblackoilintensivequantities.hh +++ b/ebos/eclblackoilintensivequantities.hh @@ -197,7 +197,10 @@ public: if (linearizationType.type == Opm::LinearizationType::seqtransport) { ST = priVars.makeEvaluation(Indices::pressureSwitchIdx, timeIdx, linearizationType); //assert(ST<2);// debug to be sure no pressure is pressent - assert(timeIdx==0 || ST == 1);// for pure sequential with multiple steps this is always true. + //assert(timeIdx==0 || ST == 1);// for pure sequential with multiple steps this is always true. + if(timeIdx == 1){ + ST = 1.0; + } }else if (linearizationType.type == Opm::LinearizationType::pressure) { // we are doing sequation pressure where ST may not be 1 any more From 49d237cfe4934019a9822483ebb2e2d0a93ec87e Mon Sep 17 00:00:00 2001 From: hnil Date: Wed, 24 Jun 2020 09:53:47 +0200 Subject: [PATCH 45/93] tried to clean up the stepping --- ebos/eclproblem.hh | 47 ++++++++++++++++++--- opm/simulators/flow/NonlinearSolverEbos.hpp | 37 +++++++++------- 2 files changed, 62 insertions(+), 22 deletions(-) diff --git a/ebos/eclproblem.hh b/ebos/eclproblem.hh index 48d8b123497..af04d726b6b 100644 --- a/ebos/eclproblem.hh +++ b/ebos/eclproblem.hh @@ -907,7 +907,8 @@ public: // used when ROCKCOMP is activated const bool invalidateFromMaxWaterSat = updateMaxWaterSaturation_(); const bool invalidateFromMinPressure = updateMinPressure_(); - updatePressure();//update stored pressure in case of sequential do not need to recalculate chach + this->updatePressureAndFluxes();//update stored pressure in case of sequential do not need to recalculate chach + this->updateTotalSaturation(); invalidateIntensiveQuantities = invalidateFromMaxWaterSat || invalidateFromMinPressure; if (invalidateIntensiveQuantities) @@ -1778,6 +1779,12 @@ public: return totalSaturation_[globalDofIdx]; } + void totalSaturationOne(){ + for(auto& v : totalSaturation_){ + v=1.0; + } + } + Scalar totalFlux(unsigned globalIndex,unsigned loc_index) const{ //unsigned globalIndx = elemCtx.globalSpaceIndex(/*spaceIdx=*/0, /*timeIdx=*/0); //for (unsigned scvfIdx = 0; scvfIdx < numInteriorFaces; scvfIdx++) { @@ -1935,17 +1942,27 @@ public: * \brief update pressure and totalSaturation * update copy of pressure and total saturation for sequential solve */ - bool updatePressure(){ - LinearizationType linearizationType = this->simulator().model().linearizer().getLinearizationType(); + bool updatePressureAndFluxes(){ // maybe use simulation type instead + std::string simulationtype = EWOMS_GET_PARAM(TypeTag, std::string, SimulationType); bool updated = false; - if(not(linearizationType.type == Opm::LinearizationType::implicit)){ - this->updatePressure_(); + if(not(simulationtype == "implicit")){ + this->updatePressure_(); this->updateFluxes_(); updated = true; } return updated; } + bool updateTotalSaturation(){ + std::string simulationtype = EWOMS_GET_PARAM(TypeTag, std::string, SimulationType); + // maybe use simulation type instead + bool updated = false; + if(not(simulationtype == "implicit")){ + this->updateTotalSaturation_(); + updated = true; + } + return updated; + } private: void checkDeckCompatibility_() const @@ -2231,12 +2248,30 @@ private: }else{ pressure_[compressedDofIdx][waterPhaseIdx] = Opm::getValue(fs.pressure(waterPhaseIdx)); } - totalSaturation_[compressedDofIdx] = Opm::getValue(fs.totalSaturation()); } return true; } + bool updateTotalSaturation_() + { + ElementContext elemCtx(this->simulator()); + const auto& vanguard = this->simulator().vanguard(); + auto elemIt = vanguard.gridView().template begin(); + const auto& elemEndIt = vanguard.gridView().template end(); + for (; elemIt != elemEndIt; ++elemIt) { + const Element& elem = *elemIt; + elemCtx.updatePrimaryStencil(elem); + elemCtx.updatePrimaryIntensiveQuantities(/*timeIdx=*/0); + unsigned compressedDofIdx = elemCtx.globalSpaceIndex(/*spaceIdx=*/0, /*timeIdx=*/0); + const auto& iq = elemCtx.intensiveQuantities(/*spaceIdx=*/0, /*timeIdx=*/0); + const auto& fs = iq.fluidState(); + totalSaturation_[compressedDofIdx] = Opm::getValue(fs.totalSaturation()); + } + return true; + } + + void readRockParameters_() { const auto& simulator = this->simulator(); diff --git a/opm/simulators/flow/NonlinearSolverEbos.hpp b/opm/simulators/flow/NonlinearSolverEbos.hpp index f93c8ce68f1..58173421ffb 100644 --- a/opm/simulators/flow/NonlinearSolverEbos.hpp +++ b/opm/simulators/flow/NonlinearSolverEbos.hpp @@ -161,20 +161,18 @@ namespace Opm { // do pressure step if(seqiterations>0){ auto& prevsol = model_->ebosSimulator().model().solution(/*timeIdx=*/1); + model_->ebosSimulator().model().invalidateIntensiveQuantitiesCache(/*timeIdx=*/1); + //NB is the storag cach allso invalidated?? prevsol=solutionOld; } - linearizationType.type = Opm::LinearizationType::pressure; - model_->updateSolution(); - model_->ebosSimulator().problem().updatePressure();//update pressure ans ST + linearizationType.type = Opm::LinearizationType::pressure; model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); - model_->updateSolution();// should conver to the new solution time + model_->updateSolution(); SimulatorReportSingle lreportpre = this->stepDefault(timer, /*next*/first, false); first=false; - // do transport step - model_->ebosSimulator().problem().updatePressure();//update pressure ans ST - linearizationType.type = Opm::LinearizationType::seqtransport; - model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); + model_->ebosSimulator().problem().updatePressureAndFluxes();//update pressure ans ST + linearizationType.type = Opm::LinearizationType::seqtransport; model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); model_->updateSolution(); reportpre += lreportpre; @@ -183,7 +181,7 @@ namespace Opm { //model_->ebosSimulator().problem().beginTimeStep(); SimulatorReportSingle lreportseq = this->stepDefault(timer,/*next*/false, false); // hopefully do not change any thing only update well quantities - model_->wellModel().solveWells(model_->ebosSimulator().timeStepSize()); + //model_->wellModel().solveWells(model_->ebosSimulator().timeStepSize()); reportseq += lreportseq; }catch (...){ //set the prevois value to the staring point @@ -202,15 +200,21 @@ namespace Opm { model_->ebosSimulator().model().setEnableStorageCache(false); auto& prevsol = model_->ebosSimulator().model().solution(/*timeIdx=*/1); prevsol=solutionOld; + model_->ebosSimulator().model().invalidateIntensiveQuantitiesCache(/*timeIdx=*/1); + model_->ebosSimulator().model().invalidateIntensiveQuantitiesCache(/*timeIdx=*/0); linearizationType.type = Opm::LinearizationType::implicit; - model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); - + model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); model_->updateSolution(); + //NB her only the convergenceshould be checked - SimulatorReportSingle lreportsim = this->stepDefault(timer,/*next*/false, false); - converged = lreportsim.converged; + //SimulatorReportSingle lreportsim = this->stepDefault(timer,/*next*/false, false); + std::vector residual_norms; + auto asreport = model_->assembleReservoir(timer, seqiterations); + auto convrep = model_->getConvergence(timer, seqiterations,residual_norms); + converged = convrep.converged(); // if this used one probably have to invalidate the storage cache - //model_->ebosSimulator().model().setEnableStorageCache(storagecache); + //model_->ebosSimulator().model().setEnableStorageCache(storagecache); + model_->ebosSimulator().problem().totalSaturationOne(); }else{ converged = true; } @@ -225,6 +229,7 @@ namespace Opm { model_->afterStep(timer); report.converged = true; } + model_->updateSolution(); //todo fill this report correctly return report; @@ -399,7 +404,7 @@ namespace Opm { LinearizationType linearizationType;// use default model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); // incase previous step was not fully implicit - model_->ebosSimulator().problem().updatePressure();//update pressure ans ST + model_->ebosSimulator().problem().updatePressureAndFluxes();//update pressure ans ST model_->updateSolution(); SimulatorReportSingle report = this->stepDefault(timer,true,true); return report; @@ -410,7 +415,7 @@ namespace Opm { SimulatorReportSingle reportpre; // do pressure step linearizationType.type = Opm::LinearizationType::pressure; - model_->ebosSimulator().problem().updatePressure();//update pressure ans ST + model_->ebosSimulator().problem().updatePressureAndFluxes();//update pressure ans ST model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); model_->updateSolution();// should conver to the new solution time SimulatorReportSingle lreportpre = this->stepDefault(timer,true,true); From 434dc6a96735c6df4b1782e9950782a4c3a85498 Mon Sep 17 00:00:00 2001 From: hnil Date: Thu, 25 Jun 2020 11:56:52 +0200 Subject: [PATCH 46/93] added writout of saturation, fixed bug in total saturation update --- ebos/eclproblem.hh | 42 ++++++++++++++++++++- opm/simulators/flow/NonlinearSolverEbos.hpp | 5 ++- 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/ebos/eclproblem.hh b/ebos/eclproblem.hh index af04d726b6b..5d8cb845e0c 100644 --- a/ebos/eclproblem.hh +++ b/ebos/eclproblem.hh @@ -908,7 +908,7 @@ public: const bool invalidateFromMaxWaterSat = updateMaxWaterSaturation_(); const bool invalidateFromMinPressure = updateMinPressure_(); this->updatePressureAndFluxes();//update stored pressure in case of sequential do not need to recalculate chach - this->updateTotalSaturation(); + //this->updateTotalSaturation(); invalidateIntensiveQuantities = invalidateFromMaxWaterSat || invalidateFromMinPressure; if (invalidateIntensiveQuantities) @@ -993,7 +993,7 @@ public: bool isSubStep = !EWOMS_GET_PARAM(TypeTag, bool, EnableWriteAllSolutions) && !this->simulator().episodeWillBeOver(); eclWriter_->evalSummaryState(isSubStep); - + this->writeExtra(); auto& schedule = simulator.vanguard().schedule(); auto& ecl_state = simulator.vanguard().eclState(); int episodeIdx = simulator.episodeIndex(); @@ -1005,6 +1005,43 @@ public: simulator.vanguard().summaryState()); } + + void writeExtra(){ + std::string dir = this->simulator().problem().outputDir(); + if (dir == ".") { + dir = ""; + } else if (!dir.empty() && dir.back() != '/') { + dir += "/"; + } + namespace fs = Opm::filesystem; + fs::path output_dir(dir); + fs::path subdir("extra_out"); + output_dir = output_dir / subdir; + if (!(fs::exists(output_dir))) { + fs::create_directory(output_dir); + } + std::ostringstream oss; + oss << "totalsat_" << this->simulator().episodeIndex() << "_time_"; + oss << std::setprecision(15) << std::setw(12) << std::setfill('0') << this->simulator().time() << "_"; + std::string output_file(oss.str()); + fs::path full_path = output_dir / output_file; + std::string prefix = full_path.string() + ".txt"; + { +#if HAVE_MPI + //std::string filename = prefix + ename + "matrix_istl"; +#endif + std::ofstream file(prefix.c_str()); + std::string simulationType = EWOMS_GET_PARAM(TypeTag, std::string, SimulationType); + if(simulationType == "seq"){ + Opm::LinearizationType linearizationType = this->simulator().model().linearizer().getLinearizationType(); + assert(linearizationType.type == Opm::LinearizationType::seqtransport); + } + for(const auto& v : totalSaturation_){ + file << v << std::endl; + } + } + } + /*! * \brief Called by the simulator after the end of an episode. */ @@ -1021,6 +1058,7 @@ public: simulator.setFinished(true); return; } + // Combine and return. // .. if we're not yet done, start the next episode (report step) simulator.startNextEpisode(timeMap.getTimeStepLength(episodeIdx + 1)); diff --git a/opm/simulators/flow/NonlinearSolverEbos.hpp b/opm/simulators/flow/NonlinearSolverEbos.hpp index 58173421ffb..d36481fd0ac 100644 --- a/opm/simulators/flow/NonlinearSolverEbos.hpp +++ b/opm/simulators/flow/NonlinearSolverEbos.hpp @@ -226,10 +226,11 @@ namespace Opm { if(not(converged)){ report.converged = false; }else{ + model_->updateSolution(); + model_->ebosSimulator().problem().updateTotalSaturation(); model_->afterStep(timer); report.converged = true; - } - model_->updateSolution(); + } //todo fill this report correctly return report; From 59ca45caea40e75c43249eb22e5c92136cb9fea1 Mon Sep 17 00:00:00 2001 From: hnil Date: Thu, 25 Jun 2020 14:24:02 +0200 Subject: [PATCH 47/93] added reseting of totalsaturation --- ebos/eclproblem.hh | 10 ++++++++++ opm/simulators/flow/NonlinearSolverEbos.hpp | 12 +++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/ebos/eclproblem.hh b/ebos/eclproblem.hh index 5d8cb845e0c..4d733d74979 100644 --- a/ebos/eclproblem.hh +++ b/ebos/eclproblem.hh @@ -1817,6 +1817,16 @@ public: return totalSaturation_[globalDofIdx]; } + const std::vector& getTotalSaturation() const + { + return totalSaturation_; + } + + void setTotalSaturation(std::vector totSat) + { + totalSaturation_ = totSat; + } + void totalSaturationOne(){ for(auto& v : totalSaturation_){ v=1.0; diff --git a/opm/simulators/flow/NonlinearSolverEbos.hpp b/opm/simulators/flow/NonlinearSolverEbos.hpp index d36481fd0ac..07babe64ff9 100644 --- a/opm/simulators/flow/NonlinearSolverEbos.hpp +++ b/opm/simulators/flow/NonlinearSolverEbos.hpp @@ -156,6 +156,7 @@ namespace Opm { int maxseqiterations = 10; // should probalby store for trying onse more auto solutionOld = model_->ebosSimulator().model().solution(/*timeIdx=*/0); + auto oldTotalSaturation = model_->ebosSimulator().problem.getTotalSaturation(); bool first= true; while(not(converged) && (seqiterations < maxseqiterations) ){ // do pressure step @@ -172,7 +173,8 @@ namespace Opm { first=false; // do transport step model_->ebosSimulator().problem().updatePressureAndFluxes();//update pressure ans ST - linearizationType.type = Opm::LinearizationType::seqtransport; model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); + linearizationType.type = Opm::LinearizationType::seqtransport; + model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); model_->updateSolution(); reportpre += lreportpre; @@ -189,6 +191,10 @@ namespace Opm { prevsol = solutionOld; auto& currsol = model_->ebosSimulator().model().solution(/*timeIdx=*/0); currsol = solutionOld; + // set back totalSaturation pressure and fluxes + model_->ebosSimulator().problem.setTotalSaturation(oldTotalSaturation); + // total pressure fluxes should be updated in the pressure solve anyway + throw; } @@ -213,13 +219,13 @@ namespace Opm { auto convrep = model_->getConvergence(timer, seqiterations,residual_norms); converged = convrep.converged(); // if this used one probably have to invalidate the storage cache - //model_->ebosSimulator().model().setEnableStorageCache(storagecache); + //model_->ebosSimulator().model().setEnableStorageCache(storagecache); model_->ebosSimulator().problem().totalSaturationOne(); }else{ converged = true; } - std::cout << "Sequantial iteration " << seqiterations << std::endl; + std::cout << "Sequantial fullimplicit iteration " << seqiterations << std::endl; seqiterations += 1; } SimulatorReportSingle report; From a5b3843433f5dbdd4355f54e64d647a2ec8be956 Mon Sep 17 00:00:00 2001 From: hnil Date: Thu, 25 Jun 2020 17:59:53 +0200 Subject: [PATCH 48/93] make safer total saturation update if failed --- opm/simulators/flow/NonlinearSolverEbos.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/opm/simulators/flow/NonlinearSolverEbos.hpp b/opm/simulators/flow/NonlinearSolverEbos.hpp index 07babe64ff9..96c1f41332f 100644 --- a/opm/simulators/flow/NonlinearSolverEbos.hpp +++ b/opm/simulators/flow/NonlinearSolverEbos.hpp @@ -156,7 +156,7 @@ namespace Opm { int maxseqiterations = 10; // should probalby store for trying onse more auto solutionOld = model_->ebosSimulator().model().solution(/*timeIdx=*/0); - auto oldTotalSaturation = model_->ebosSimulator().problem.getTotalSaturation(); + auto oldTotalSaturation = model_->ebosSimulator().problem().getTotalSaturation(); bool first= true; while(not(converged) && (seqiterations < maxseqiterations) ){ // do pressure step @@ -192,7 +192,7 @@ namespace Opm { auto& currsol = model_->ebosSimulator().model().solution(/*timeIdx=*/0); currsol = solutionOld; // set back totalSaturation pressure and fluxes - model_->ebosSimulator().problem.setTotalSaturation(oldTotalSaturation); + model_->ebosSimulator().problem().setTotalSaturation(oldTotalSaturation); // total pressure fluxes should be updated in the pressure solve anyway throw; From 0c9edda2605d3ac01ed135e1b576784d661ec9a9 Mon Sep 17 00:00:00 2001 From: hnil Date: Thu, 25 Jun 2020 18:01:15 +0200 Subject: [PATCH 49/93] renameing for easier search after totalSaturation --- ebos/eclblackoilintensivequantities.hh | 24 +++++++++++----------- ebos/eclfluxmoduleseq.hh | 8 ++++---- opm/simulators/wells/StandardWell_impl.hpp | 4 ++-- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/ebos/eclblackoilintensivequantities.hh b/ebos/eclblackoilintensivequantities.hh index d2f9cb947bd..dc2969c24dc 100644 --- a/ebos/eclblackoilintensivequantities.hh +++ b/ebos/eclblackoilintensivequantities.hh @@ -193,22 +193,22 @@ public: } // oil is the reference phase for pressure - Evaluation ST = 1.0; + Evaluation totalSaturation = 1.0; if (linearizationType.type == Opm::LinearizationType::seqtransport) { - ST = priVars.makeEvaluation(Indices::pressureSwitchIdx, timeIdx, linearizationType); - //assert(ST<2);// debug to be sure no pressure is pressent - //assert(timeIdx==0 || ST == 1);// for pure sequential with multiple steps this is always true. + totalSaturation = priVars.makeEvaluation(Indices::pressureSwitchIdx, timeIdx, linearizationType); + //assert(totalSaturation<2);// debug to be sure no pressure is pressent + //assert(timeIdx==0 || totalSaturation == 1);// for pure sequential with multiple steps this is always true. if(timeIdx == 1){ - ST = 1.0; + totalSaturation = 1.0; } }else if (linearizationType.type == Opm::LinearizationType::pressure) { - // we are doing sequation pressure where ST may not be 1 any more - if(timeIdx == 1){//pressure solves try to make new value i.e. timeIdx==0 so that ST==1; - ST = elemCtx.problem().totalSaturation(globalSpaceIdx); + // we are doing sequation pressure where totalSaturation may not be 1 any more + if(timeIdx == 1){//pressure solves try to make new value i.e. timeIdx==0 so that totalSaturation==1; + totalSaturation = elemCtx.problem().totalSaturation(globalSpaceIdx); } } - fluidState_.setTotalSaturation(ST); + fluidState_.setTotalSaturation(totalSaturation); if (priVars.primaryVarsMeaning() == PrimaryVariables::Sw_pg_Rv) { Evaluation pg; if (linearizationType.type == Opm::LinearizationType::seqtransport) { @@ -217,7 +217,7 @@ public: gasPhaseIdx)); // get current value assuem this is not updated } else { pg = priVars.makeEvaluation(Indices::pressureSwitchIdx, timeIdx, linearizationType); - //assert(pg>2.0);//enure not ST is present + //assert(pg>2.0);//enure not totalSaturation is present } for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) if (FluidSystem::phaseIsActive(phaseIdx)) @@ -229,7 +229,7 @@ public: po = Toolbox::value(elemCtx.problem().pressure(globalSpaceIdx, oilPhaseIdx)); } else { po = priVars.makeEvaluation(Indices::pressureSwitchIdx, timeIdx, linearizationType); - //assert(po>2.0);//enure not ST is present + //assert(po>2.0);//enure not totalSaturation is present } for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) if (FluidSystem::phaseIsActive(phaseIdx)) @@ -399,7 +399,7 @@ public: porosity_ *= problem.template rockCompPoroMultiplier(*this, globalSpaceIdx); // this line is doing things for sequential simulation to avoid modifying storage term. - porosity_ *= ST; + porosity_ *= totalSaturation; asImp_().solventPvtUpdate_(elemCtx, dofIdx, timeIdx); asImp_().polymerPropertiesUpdate_(elemCtx, dofIdx, timeIdx); diff --git a/ebos/eclfluxmoduleseq.hh b/ebos/eclfluxmoduleseq.hh index 8f4ded5685f..4a73c4a2bfd 100644 --- a/ebos/eclfluxmoduleseq.hh +++ b/ebos/eclfluxmoduleseq.hh @@ -461,8 +461,8 @@ protected: mob1[phaseIdx] = intQuantsIn.mobility(phaseIdx); mob2[phaseIdx] = Toolbox::value(intQuantsEx.mobility(phaseIdx)); } - Evaluation ST1 = intQuantsIn.fluidState().totalSaturation(); - Evaluation ST2 = Toolbox::value(intQuantsEx.fluidState().totalSaturation()); + Evaluation totalSaturation1 = intQuantsIn.fluidState().totalSaturation(); + Evaluation totalSaturation2 = Toolbox::value(intQuantsEx.fluidState().totalSaturation()); Evaluation totalflux; if(linearizationType.type == Opm::LinearizationType::seqtransport){ unsigned gIdx = elemCtx.globalSpaceIndex(/*spaceIdx=*/0, /*timeIdx=*/0); @@ -497,7 +497,7 @@ protected: upIdx_[phaseIdx] = interiorDofIdx_; dnIdx_[phaseIdx] = exteriorDofIdx_; fmob[phaseIdx] = mob1[phaseIdx]; - fst[phaseIdx] = ST1; + fst[phaseIdx] = totalSaturation1; }else{ if(linearizationType.type == Opm::LinearizationType::implicit){ if(not(pressureDifference_[phaseIdx] == 0.0)){ @@ -508,7 +508,7 @@ protected: upIdx_[phaseIdx] = exteriorDofIdx_; dnIdx_[phaseIdx] = interiorDofIdx_; fmob[phaseIdx] = mob2[phaseIdx]; - fst[phaseIdx] = ST2; + fst[phaseIdx] = totalSaturation2; } mobT += fmob[phaseIdx]; } diff --git a/opm/simulators/wells/StandardWell_impl.hpp b/opm/simulators/wells/StandardWell_impl.hpp index 01eb95470f3..90ffb065883 100644 --- a/opm/simulators/wells/StandardWell_impl.hpp +++ b/opm/simulators/wells/StandardWell_impl.hpp @@ -3241,7 +3241,7 @@ namespace Opm const EvalWell pressure = extendEval(getPerfCellPressure(fs)); const EvalWell rs = extendEval(fs.Rs()); const EvalWell rv = extendEval(fs.Rv()); - const EvalWell ST = extendEval(fs.totalSaturation()); + const EvalWell totalSaturation = extendEval(fs.totalSaturation()); std::vector b_perfcells_dense(num_components_, EvalWell{numWellEq_ + numEq, 0.0}); for (unsigned phaseIdx = 0; phaseIdx < FluidSystem::numPhases; ++phaseIdx) { if (!FluidSystem::phaseIsActive(phaseIdx)) { @@ -3269,7 +3269,7 @@ namespace Opm // compute component volumetric rates at standard conditions for (int componentIdx = 0; componentIdx < num_components_; ++componentIdx) { // do upwinding of total saturation and mobility and totalmobility - const EvalWell cq_p = ST*mob[componentIdx]/mobt * cq_r_t; + const EvalWell cq_p = totalSaturation*mob[componentIdx]/mobt * cq_r_t; perf_rates.cq_s[componentIdx] = b_perfcells_dense[componentIdx] * cq_p; } From 8780d52126d6e9e5ac0a069c6df2db5838632382 Mon Sep 17 00:00:00 2001 From: hnil Date: Fri, 26 Jun 2020 09:06:31 +0200 Subject: [PATCH 50/93] using previous well state for flux cacluation in sequential --- opm/simulators/flow/NonlinearSolverEbos.hpp | 1 + opm/simulators/wells/BlackoilWellModel.hpp | 3 +++ opm/simulators/wells/BlackoilWellModel_impl.hpp | 7 ++++++- opm/simulators/wells/StandardWell_impl.hpp | 15 ++++++++------- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/opm/simulators/flow/NonlinearSolverEbos.hpp b/opm/simulators/flow/NonlinearSolverEbos.hpp index 96c1f41332f..f5a7dede45e 100644 --- a/opm/simulators/flow/NonlinearSolverEbos.hpp +++ b/opm/simulators/flow/NonlinearSolverEbos.hpp @@ -172,6 +172,7 @@ namespace Opm { SimulatorReportSingle lreportpre = this->stepDefault(timer, /*next*/first, false); first=false; // do transport step + model_->ebosSimulator().problem().wellModel().endTimeStep();// shouldupdate previous state NB do wee need to store it if transportstep fails? model_->ebosSimulator().problem().updatePressureAndFluxes();//update pressure ans ST linearizationType.type = Opm::LinearizationType::seqtransport; model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); diff --git a/opm/simulators/wells/BlackoilWellModel.hpp b/opm/simulators/wells/BlackoilWellModel.hpp index e12849accc5..7a473dcc846 100644 --- a/opm/simulators/wells/BlackoilWellModel.hpp +++ b/opm/simulators/wells/BlackoilWellModel.hpp @@ -264,6 +264,9 @@ namespace Opm { // return the internal well state const WellState& wellState() const; + // return the internal well state + const WellState& prevWellState() const; + const SimulatorReportSingle& lastReport() const; void addWellContributions(SparseMatrixAdapter& jacobian) const diff --git a/opm/simulators/wells/BlackoilWellModel_impl.hpp b/opm/simulators/wells/BlackoilWellModel_impl.hpp index 94bdb9326c0..86e354266e7 100644 --- a/opm/simulators/wells/BlackoilWellModel_impl.hpp +++ b/opm/simulators/wells/BlackoilWellModel_impl.hpp @@ -144,7 +144,6 @@ namespace Opm { } } - /// Return true if any well has a THP constraint. template bool @@ -1395,6 +1394,12 @@ namespace Opm { BlackoilWellModel:: wellState() const { return well_state_; } + template + const typename BlackoilWellModel::WellState& + BlackoilWellModel:: + prevWellState() const { return previous_well_state_; } + + template const typename BlackoilWellModel::WellState& BlackoilWellModel:: diff --git a/opm/simulators/wells/StandardWell_impl.hpp b/opm/simulators/wells/StandardWell_impl.hpp index 90ffb065883..2ec5ace07d5 100644 --- a/opm/simulators/wells/StandardWell_impl.hpp +++ b/opm/simulators/wells/StandardWell_impl.hpp @@ -348,7 +348,7 @@ namespace Opm computePerfRate(const IntensiveQuantities& intQuants, const std::vector& mob, const EvalWell& bhp, - const WellState& well_state, + const WellState& prev_well_state, const double Tw, const int perf, const bool allow_cf, @@ -595,7 +595,8 @@ namespace Opm double trans_mult = ebosSimulator.problem().template rockCompTransMultiplier(intQuants, cell_idx); const double Tw = well_index_[perf] * trans_mult; const LinearizationType& linearizationType = ebosSimulator.model().linearizer().getLinearizationType(); - computePerfRate(intQuants, mob, bhp, well_state, Tw, perf, allow_cf, + const WellState& prev_well_state = ebosSimulator.problem().wellModel().prevWellState(); + computePerfRate(intQuants, mob, bhp, prev_well_state, Tw, perf, allow_cf, perf_rates, deferred_logger, linearizationType); // better way to do here is that use the cq_s and then replace the cq_s_water here? @@ -2489,8 +2490,8 @@ namespace Opm PerfRates perf_rates(num_components_, numWellEq_); const LinearizationType& linearizationType = ebosSimulator.model().linearizer().getLinearizationType(); - const WellState& well_state = ebosSimulator.problem().wellModel().wellState(); - computePerfRate(intQuants, mob, EvalWell(numWellEq_ + numEq, bhp), well_state, Tw, perf, allow_cf, + const WellState& prev_well_state = ebosSimulator.problem().wellModel().prevWellState(); + computePerfRate(intQuants, mob, EvalWell(numWellEq_ + numEq, bhp), prev_well_state, Tw, perf, allow_cf, perf_rates, deferred_logger, linearizationType); for(int p = 0; p < np; ++p) { @@ -2874,8 +2875,8 @@ namespace Opm double trans_mult = ebos_simulator.problem().template rockCompTransMultiplier(int_quant, cell_idx); const double Tw = well_index_[perf] * trans_mult; LinearizationType linearizationType = ebos_simulator.model().linearizer().getLinearizationType(); - const WellState& well_state = ebos_simulator.problem().wellModel().wellState(); - computePerfRate(int_quant, mob, bhp, well_state, Tw, perf, allow_cf, perf_rates, deferred_logger, linearizationType); + const WellState& prev_well_state = ebos_simulator.problem().wellModel().prevWellState(); + computePerfRate(int_quant, mob, bhp, prev_well_state, Tw, perf, allow_cf, perf_rates, deferred_logger, linearizationType); // TODO: make area a member const double area = 2 * M_PI * perf_rep_radius_[perf] * perf_length_[perf]; const auto& material_law_manager = ebos_simulator.problem().materialLawManager(); @@ -3209,7 +3210,7 @@ namespace Opm auto cq_s_tmp = perf_rates.cq_s; if(linearizationType.type == Opm::LinearizationType::seqtransport){ - perf_rates.cq_r_t = well_state.perfTotalResRates()[first_perf_ + perf]; + perf_rates.cq_r_t = prev_well_state.perfTotalResRates()[first_perf_ + perf]; } computePerfRateSeq(intQuants,mob,/*bhp,Tw,perf,*/allow_cf,perf_rates,deferred_logger); if(not(linearizationType.type == Opm::LinearizationType::seqtransport)){ From 79bb58fe4c9ffaf690744598b75c17f57ed11e6a Mon Sep 17 00:00:00 2001 From: hnil Date: Fri, 26 Jun 2020 09:13:07 +0200 Subject: [PATCH 51/93] hopefully a working version --- ebos/eclblackoilintensivequantities.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ebos/eclblackoilintensivequantities.hh b/ebos/eclblackoilintensivequantities.hh index dc2969c24dc..99b3fffa87a 100644 --- a/ebos/eclblackoilintensivequantities.hh +++ b/ebos/eclblackoilintensivequantities.hh @@ -199,7 +199,7 @@ public: //assert(totalSaturation<2);// debug to be sure no pressure is pressent //assert(timeIdx==0 || totalSaturation == 1);// for pure sequential with multiple steps this is always true. if(timeIdx == 1){ - totalSaturation = 1.0; + totalSaturation = elemCtx.problem().totalSaturation(globalSpaceIdx); } }else if (linearizationType.type == Opm::LinearizationType::pressure) { From fb9c2bbeb84ac6b5d359f3df36d2594077b3728e Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Fri, 26 Jun 2020 15:17:29 +0200 Subject: [PATCH 52/93] fixing compilation after the rebasing. --- CMakeLists.txt | 2 +- ebos/eclproblem.hh | 44 +++++++++++------------ opm/simulators/flow/BlackoilModelEbos.hpp | 2 +- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 1b01990c2ba..6909e05fda7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -89,7 +89,7 @@ include ("${project}-prereqs") # our way of specifying cuda source files never worked for CMake # version < 3.8. Hence we deactivate cuda for these versions. # We use "CMAKE_VERSION VERSION_GREATER 3.7.9" instead of -# CMAKE_VERSION VERSION_GREATER_EQUAL 3.8, because of backwarsd +# CMAKE_VERSION VERSION_GREATER_EQUAL 3.8, because of backwards # compatibility to cmake 3.6 and lower. if(NOT CMAKE_DISABLE_FIND_PACKAGE_CUDA AND CMAKE_VERSION VERSION_GREATER 3.7.9) diff --git a/ebos/eclproblem.hh b/ebos/eclproblem.hh index 4d733d74979..07041576069 100644 --- a/ebos/eclproblem.hh +++ b/ebos/eclproblem.hh @@ -691,7 +691,7 @@ public: } pressure_.resize(numDof); totalSaturation_.resize(numDof, 1.0); - + updateElementDepths_(); readRockParameters_(); readMaterialParameters_(); @@ -1026,7 +1026,7 @@ public: std::string output_file(oss.str()); fs::path full_path = output_dir / output_file; std::string prefix = full_path.string() + ".txt"; - { + { #if HAVE_MPI //std::string filename = prefix + ename + "matrix_istl"; #endif @@ -1038,10 +1038,10 @@ public: } for(const auto& v : totalSaturation_){ file << v << std::endl; - } + } } } - + /*! * \brief Called by the simulator after the end of an episode. */ @@ -1804,7 +1804,7 @@ public: /*! * \brief Returns an element's pressure of the oil phase that was at the begining - * of the timestep need for sequential + * of the timestep need for sequential * */ Scalar pressure(unsigned globalDofIdx,unsigned phaseIndex) const @@ -1822,17 +1822,17 @@ public: return totalSaturation_; } - void setTotalSaturation(std::vector totSat) + void setTotalSaturation(std::vector totSat) { totalSaturation_ = totSat; } - + void totalSaturationOne(){ for(auto& v : totalSaturation_){ v=1.0; } } - + Scalar totalFlux(unsigned globalIndex,unsigned loc_index) const{ //unsigned globalIndx = elemCtx.globalSpaceIndex(/*spaceIdx=*/0, /*timeIdx=*/0); //for (unsigned scvfIdx = 0; scvfIdx < numInteriorFaces; scvfIdx++) { @@ -1987,22 +1987,22 @@ public: return overburdenPressure_[elementIdx]; } /*! - * \brief update pressure and totalSaturation + * \brief update pressure and totalSaturation * update copy of pressure and total saturation for sequential solve */ bool updatePressureAndFluxes(){ // maybe use simulation type instead - std::string simulationtype = EWOMS_GET_PARAM(TypeTag, std::string, SimulationType); + std::string simulationtype = EWOMS_GET_PARAM(TypeTag, std::string, SimulationType); bool updated = false; if(not(simulationtype == "implicit")){ - this->updatePressure_(); + this->updatePressure_(); this->updateFluxes_(); updated = true; } return updated; } bool updateTotalSaturation(){ - std::string simulationtype = EWOMS_GET_PARAM(TypeTag, std::string, SimulationType); + std::string simulationtype = EWOMS_GET_PARAM(TypeTag, std::string, SimulationType); // maybe use simulation type instead bool updated = false; if(not(simulationtype == "implicit")){ @@ -2274,7 +2274,7 @@ private: } bool updatePressure_() - { + { ElementContext elemCtx(this->simulator()); const auto& vanguard = this->simulator().vanguard(); auto elemIt = vanguard.gridView().template begin(); @@ -2302,7 +2302,7 @@ private: } bool updateTotalSaturation_() - { + { ElementContext elemCtx(this->simulator()); const auto& vanguard = this->simulator().vanguard(); auto elemIt = vanguard.gridView().template begin(); @@ -2315,11 +2315,11 @@ private: const auto& iq = elemCtx.intensiveQuantities(/*spaceIdx=*/0, /*timeIdx=*/0); const auto& fs = iq.fluidState(); totalSaturation_[compressedDofIdx] = Opm::getValue(fs.totalSaturation()); - } + } return true; } - + void readRockParameters_() { const auto& simulator = this->simulator(); @@ -2979,7 +2979,7 @@ private: { Opm::ConditionalStorage thermalHalfTrans; Scalar transmissibility; - }; + }; // update the prefetch friendly data object void updatePffDofData_() @@ -3005,8 +3005,8 @@ private: pffDofData_.update(distFn); } - - + + void updateFluxes_(){ const auto& vanguard = this->simulator().vanguard(); unsigned numElems = vanguard.gridView().size(/*codim=*/0); @@ -3016,7 +3016,7 @@ private: const auto& elemEndIt = vanguard.gridView().template end(); for (; elemIt != elemEndIt; ++elemIt) { const Element& elem = *elemIt; - + //elemCtx.updatePrimaryStencil(elem); //elemCtx.updatePrimaryIntensiveQuantities(/*timeIdx=*/0); elemCtx.updateStencil(elem); @@ -3036,10 +3036,10 @@ private: // this is what I want const auto& totalflux = extQuants.totalFlux(); totalFlux_[compressedDofIdx][scvfIdx] = Toolbox::value(totalflux); - } + } } } - + void readBoundaryConditions_() { nonTrivialBoundaryConditions_ = false; diff --git a/opm/simulators/flow/BlackoilModelEbos.hpp b/opm/simulators/flow/BlackoilModelEbos.hpp index 8e375c28fcf..27f8a275f4a 100644 --- a/opm/simulators/flow/BlackoilModelEbos.hpp +++ b/opm/simulators/flow/BlackoilModelEbos.hpp @@ -526,7 +526,7 @@ namespace Opm { std::function weightsCalculator;// dummy - Dune::FlexibleSolver pressureSolver(prm,pmatrix, weightsCalculator, *comm); + Dune::FlexibleSolver pressureSolver(pmatrix, *comm, prm, weightsCalculator); PressureVectorType xp(x.size(),0); Dune::InverseOperatorResult res; pressureSolver.apply(xp,rhs, res); From facd42b46836e3eec4bfb1b3c67fb24fae68b4a1 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Mon, 29 Jun 2020 13:05:31 +0200 Subject: [PATCH 53/93] fixing the running of flow_blackoil with this branch --- opm/simulators/wells/StandardWell_impl.hpp | 34 ++++++++++++---------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/opm/simulators/wells/StandardWell_impl.hpp b/opm/simulators/wells/StandardWell_impl.hpp index 2ec5ace07d5..e2ddaa3b181 100644 --- a/opm/simulators/wells/StandardWell_impl.hpp +++ b/opm/simulators/wells/StandardWell_impl.hpp @@ -356,8 +356,22 @@ namespace Opm Opm::DeferredLogger& deferred_logger, const Opm::LinearizationType& linearizationType) const { - //LinearizationType linearizatonType = ebosSimulator().linearizer().getLinarizationType(); - if(not(linearizationType.type == Opm::LinearizationType::seqtransport)){ + // auto cq_s_tmp = perf_rates.cq_s; + if(linearizationType.type == Opm::LinearizationType::seqtransport){ + perf_rates.cq_r_t = prev_well_state.perfTotalResRates()[first_perf_ + perf]; + computePerfRateSeq(intQuants,mob,/*bhp,Tw,perf,*/allow_cf,perf_rates,deferred_logger); + return; + } + + // TODO: the following is some sanity check of the for computePerfRateSeq, while it is not done + // without running the code following until the end of the function + /* if(not(linearizationType.type == Opm::LinearizationType::seqtransport)){ + for(size_t i = 0; i < cq_s_tmp.size(); ++i){ + typedef Opm::MathToolbox Toolbox; + assert(Toolbox::isSame(cq_s_tmp[i],perf_rates.cq_s[i],1e-6)); + } + } */ + auto& cq_s = perf_rates.cq_s; auto& cq_r = perf_rates.cq_r; auto& cq_r_t = perf_rates.cq_r_t; @@ -3206,19 +3220,7 @@ namespace Opm } } } - } - - auto cq_s_tmp = perf_rates.cq_s; - if(linearizationType.type == Opm::LinearizationType::seqtransport){ - perf_rates.cq_r_t = prev_well_state.perfTotalResRates()[first_perf_ + perf]; - } - computePerfRateSeq(intQuants,mob,/*bhp,Tw,perf,*/allow_cf,perf_rates,deferred_logger); - if(not(linearizationType.type == Opm::LinearizationType::seqtransport)){ - for(size_t i = 0; i < cq_s_tmp.size(); ++i){ - typedef Opm::MathToolbox Toolbox; - assert(Toolbox::isSame(cq_s_tmp[i],perf_rates.cq_s[i],1e-6)); - } - } + } @@ -3299,7 +3301,7 @@ namespace Opm } // // Using total mobilities - // EvalWell total_mob_dense = + // EvalWell total_mob_dense = // for (int componentIdx = 0; componentIdx < num_components_; ++componentIdx) { // total_mob_dense += mob[componentIdx]; // cq_r[componentIdx] = - Tw * (mob[componentIdx] * drawdown); From 838ee466e45e4f43690d5488dcf2f9982ed85980 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Wed, 29 Jul 2020 13:41:33 +0200 Subject: [PATCH 54/93] saving two pressures in eclproblem so that for the transport step we can use same origional pressure for the transport solve. --- ebos/eclblackoilintensivequantities.hh | 7 ++++--- ebos/eclproblem.hh | 20 ++++++++++++-------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/ebos/eclblackoilintensivequantities.hh b/ebos/eclblackoilintensivequantities.hh index 99b3fffa87a..9744858e3e6 100644 --- a/ebos/eclblackoilintensivequantities.hh +++ b/ebos/eclblackoilintensivequantities.hh @@ -214,7 +214,8 @@ public: if (linearizationType.type == Opm::LinearizationType::seqtransport) { pg = Toolbox::value( elemCtx.problem().pressure(globalSpaceIdx, - gasPhaseIdx)); // get current value assuem this is not updated + gasPhaseIdx, + timeIdx)); // get current value assuem this is not updated } else { pg = priVars.makeEvaluation(Indices::pressureSwitchIdx, timeIdx, linearizationType); //assert(pg>2.0);//enure not totalSaturation is present @@ -226,11 +227,11 @@ public: Evaluation po; if (linearizationType.type == Opm::LinearizationType::seqtransport) { // get current value assume this is never updated - po = Toolbox::value(elemCtx.problem().pressure(globalSpaceIdx, oilPhaseIdx)); + po = Toolbox::value(elemCtx.problem().pressure(globalSpaceIdx, oilPhaseIdx, timeIdx)); } else { po = priVars.makeEvaluation(Indices::pressureSwitchIdx, timeIdx, linearizationType); //assert(po>2.0);//enure not totalSaturation is present - } + } for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) if (FluidSystem::phaseIsActive(phaseIdx)) fluidState_.setPressure(phaseIdx, po + (pC[phaseIdx] - pC[oilPhaseIdx])); diff --git a/ebos/eclproblem.hh b/ebos/eclproblem.hh index 07041576069..38f8de68398 100644 --- a/ebos/eclproblem.hh +++ b/ebos/eclproblem.hh @@ -689,7 +689,8 @@ public: lastRv_.resize(numDof, 0.0); maxOilSaturation_.resize(numDof, 0.0); } - pressure_.resize(numDof); + pressure_[0].resize(numDof); + pressure_[1].resize(numDof); totalSaturation_.resize(numDof, 1.0); updateElementDepths_(); @@ -1807,10 +1808,10 @@ public: * of the timestep need for sequential * */ - Scalar pressure(unsigned globalDofIdx,unsigned phaseIndex) const + Scalar pressure(unsigned globalDofIdx, unsigned phaseIndex, const unsigned timeIdx = 0) const { // phase index is unused for now will give warning in compilation - return pressure_[globalDofIdx][phaseIndex]; + return pressure_[timeIdx][globalDofIdx][phaseIndex]; } Scalar totalSaturation(unsigned globalDofIdx) const { @@ -2290,11 +2291,14 @@ private: const auto& fs = iq.fluidState(); if (FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)) { - pressure_[compressedDofIdx][oilPhaseIdx] = Opm::getValue(fs.pressure(oilPhaseIdx)); - }else if( FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)){ - pressure_[compressedDofIdx][gasPhaseIdx] = Opm::getValue(fs.pressure(gasPhaseIdx)); + pressure_[1][compressedDofIdx][oilPhaseIdx] = pressure_[0][compressedDofIdx][oilPhaseIdx]; + pressure_[0][compressedDofIdx][oilPhaseIdx] = Opm::getValue(fs.pressure(oilPhaseIdx)); + }else if( FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)) { + pressure_[1][compressedDofIdx][gasPhaseIdx] = pressure_[0][compressedDofIdx][gasPhaseIdx]; + pressure_[0][compressedDofIdx][gasPhaseIdx] = Opm::getValue(fs.pressure(gasPhaseIdx)); }else{ - pressure_[compressedDofIdx][waterPhaseIdx] = Opm::getValue(fs.pressure(waterPhaseIdx)); + pressure_[1][compressedDofIdx][waterPhaseIdx] = pressure_[0][compressedDofIdx][waterPhaseIdx]; + pressure_[0][compressedDofIdx][waterPhaseIdx] = Opm::getValue(fs.pressure(waterPhaseIdx)); } } @@ -3261,7 +3265,7 @@ private: std::vector maxWaterSaturation_; std::vector overburdenPressure_; std::vector minOilPressure_; - std::vector< Dune::FieldVector > pressure_; + std::array< std::vector >, 2> pressure_; std::vector totalSaturation_; std::vector< std::vector > totalFlux_; From a230b5b9fddbccf2cf7d4763a820b0a19ef27bd5 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Wed, 29 Jul 2020 13:42:46 +0200 Subject: [PATCH 55/93] not updating the explicit quantities for well for transport solve the transport should use the same initial state. --- opm/simulators/wells/StandardWell_impl.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/opm/simulators/wells/StandardWell_impl.hpp b/opm/simulators/wells/StandardWell_impl.hpp index e2ddaa3b181..f8cb2754cfb 100644 --- a/opm/simulators/wells/StandardWell_impl.hpp +++ b/opm/simulators/wells/StandardWell_impl.hpp @@ -2312,6 +2312,9 @@ namespace Opm const WellState& well_state, Opm::DeferredLogger& deferred_logger) { + const LinearizationType& linearizationType = ebosSimulator.model().linearizer().getLinearizationType(); + if(linearizationType.type == Opm::LinearizationType::seqtransport) return; // not updating the explicit quantities + updatePrimaryVariables(well_state, deferred_logger); initPrimaryVariablesEvaluation(); computeWellConnectionPressures(ebosSimulator, well_state); From 6038edfa1113865d54c8c3d383aa838e25b82ce5 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Thu, 30 Jul 2020 11:14:33 +0200 Subject: [PATCH 56/93] fixing the compilation after rebasing to master --- opm/simulators/flow/BlackoilModelEbos.hpp | 10 +++++++++- opm/simulators/linalg/FlexibleSolver_impl.hpp | 11 ++++++++++- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/opm/simulators/flow/BlackoilModelEbos.hpp b/opm/simulators/flow/BlackoilModelEbos.hpp index 27f8a275f4a..af3e40f31bd 100644 --- a/opm/simulators/flow/BlackoilModelEbos.hpp +++ b/opm/simulators/flow/BlackoilModelEbos.hpp @@ -510,6 +510,8 @@ namespace Opm { } std::any parallelInformation; extractParallelGridInformationToISTL(ebosSimulator_.vanguard().grid(), parallelInformation); + using AbstractOperatorType = Dune::AssembledLinearOperator; + std::unique_ptr operator_for_flexiblesolver; #if HAVE_MPI using Communication = Dune::OwnerOverlapCopyCommunication; std::unique_ptr comm; @@ -519,14 +521,20 @@ namespace Opm { assert(parinfo); comm.reset(new Communication(parinfo->communicator())); } + using ParOperatorType = Dune::OverlappingSchwarzOperator; + operator_for_flexiblesolver = std::make_unique(pmatrix, *comm); #else using Communication = Dune::Amg::SequentialInformation; // Dummy type std::unique_ptr comm; + using SeqLinearOperator = Dune::MatrixAdapter; + operator_for_flexiblesolver = std::make_unique(pmatrix); #endif std::function weightsCalculator;// dummy - Dune::FlexibleSolver pressureSolver(pmatrix, *comm, prm, weightsCalculator); + Dune::FlexibleSolver pressureSolver(*operator_for_flexiblesolver, + *comm, prm, weightsCalculator); PressureVectorType xp(x.size(),0); Dune::InverseOperatorResult res; pressureSolver.apply(xp,rhs, res); diff --git a/opm/simulators/linalg/FlexibleSolver_impl.hpp b/opm/simulators/linalg/FlexibleSolver_impl.hpp index 05483054002..f78b032974a 100644 --- a/opm/simulators/linalg/FlexibleSolver_impl.hpp +++ b/opm/simulators/linalg/FlexibleSolver_impl.hpp @@ -228,9 +228,18 @@ template Dune::FlexibleSolver, BV>::FlexibleSolver(AbstractOperatorTyp #else // HAVE_MPI +using Comm = Dune::Amg::SequentialInformation; #define INSTANTIATE_FLEXIBLESOLVER(N) \ template class Dune::FlexibleSolver, BV>; \ -template class Dune::FlexibleSolver, BV>; +template class Dune::FlexibleSolver, BV>; \ +template Dune::FlexibleSolver, BV>::FlexibleSolver(AbstractOperatorType& op, \ + const Comm& comm, \ + const boost::property_tree::ptree& prm, \ + const std::function()>& weightsCalculator); \ +template Dune::FlexibleSolver, BV>::FlexibleSolver(AbstractOperatorType& op, \ + const Comm& comm, \ + const boost::property_tree::ptree& prm, \ + const std::function()>& weightsCalculator); #endif // HAVE_MPI From 9594da016a3823c2c0332d5b4346c968e34a8eec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Atgeirr=20Fl=C3=B8=20Rasmussen?= Date: Fri, 31 Jul 2020 13:44:16 +0200 Subject: [PATCH 57/93] Fixing to make both MPI and no-MPI work. --- opm/simulators/flow/BlackoilModelEbos.hpp | 44 +++++++++++++---------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/opm/simulators/flow/BlackoilModelEbos.hpp b/opm/simulators/flow/BlackoilModelEbos.hpp index af3e40f31bd..adead42f293 100644 --- a/opm/simulators/flow/BlackoilModelEbos.hpp +++ b/opm/simulators/flow/BlackoilModelEbos.hpp @@ -503,41 +503,49 @@ namespace Opm { PressureVectorType rhs(ebosResid.size(),0); PressureHelper::moveToPressureEqn(ebosResid, rhs, weights); boost::property_tree::ptree prm; - try{ + try{ boost::property_tree::read_json("pressuresolver.json", prm); }catch(...){ OPM_THROW(std::logic_error,"Configuration file pressuresolver.json not pressent"); } - std::any parallelInformation; + std::any parallelInformation; extractParallelGridInformationToISTL(ebosSimulator_.vanguard().grid(), parallelInformation); using AbstractOperatorType = Dune::AssembledLinearOperator; + using PressureSolverType = Dune::FlexibleSolver; std::unique_ptr operator_for_flexiblesolver; + std::function weightsCalculator;// dummy + std::unique_ptr pressureSolver; #if HAVE_MPI using Communication = Dune::OwnerOverlapCopyCommunication; +#else + using Communication = int; // Dummy type +#endif std::unique_ptr comm; - if (parallelInformation.type() == typeid(ParallelISTLInformation)) { + +#if HAVE_MPI + if (ebosSimulator_.gridView().comm().size() > 1) { + // Parallel case. + assert(parallelInformation.type() == typeid(ParallelISTLInformation)); // Parallel case. const ParallelISTLInformation* parinfo = std::any_cast(¶llelInformation); assert(parinfo); - comm.reset(new Communication(parinfo->communicator())); - } - using ParOperatorType = Dune::OverlappingSchwarzOperator; - operator_for_flexiblesolver = std::make_unique(pmatrix, *comm); -#else - using Communication = Dune::Amg::SequentialInformation; // Dummy type - std::unique_ptr comm; - using SeqLinearOperator = Dune::MatrixAdapter; - operator_for_flexiblesolver = std::make_unique(pmatrix); + comm = std::make_unique(parinfo->communicator()); + using ParOperatorType = Dune::OverlappingSchwarzOperator; + operator_for_flexiblesolver = std::make_unique(pmatrix, *comm); + pressureSolver = std::make_unique(*operator_for_flexiblesolver, *comm , prm, weightsCalculator); + } else #endif + { + // Serial case. + using SeqLinearOperator = Dune::MatrixAdapter; + operator_for_flexiblesolver = std::make_unique(pmatrix); + pressureSolver = std::make_unique(*operator_for_flexiblesolver, prm, weightsCalculator); + } - - std::function weightsCalculator;// dummy - Dune::FlexibleSolver pressureSolver(*operator_for_flexiblesolver, - *comm, prm, weightsCalculator); PressureVectorType xp(x.size(),0); Dune::InverseOperatorResult res; - pressureSolver.apply(xp,rhs, res); + pressureSolver->apply(xp,rhs, res); Opm::Helper::writeSystem(this->ebosSimulator_, //simulator is only used to get names pmatrix, rhs, From 5d4b8b5653b36cb2f7d9c59c756e734d8b83339e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Atgeirr=20Fl=C3=B8=20Rasmussen?= Date: Fri, 31 Jul 2020 13:44:48 +0200 Subject: [PATCH 58/93] Use four digits for timesteps in extra output file names. --- ebos/eclproblem.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ebos/eclproblem.hh b/ebos/eclproblem.hh index 38f8de68398..96f234fe9e6 100644 --- a/ebos/eclproblem.hh +++ b/ebos/eclproblem.hh @@ -1022,7 +1022,7 @@ public: fs::create_directory(output_dir); } std::ostringstream oss; - oss << "totalsat_" << this->simulator().episodeIndex() << "_time_"; + oss << "totalsat_" << std::setw(4) << std::setfill('0') << this->simulator().episodeIndex() << "_time_"; oss << std::setprecision(15) << std::setw(12) << std::setfill('0') << this->simulator().time() << "_"; std::string output_file(oss.str()); fs::path full_path = output_dir / output_file; From b889471730d61b195c44b7f493f76f565354a353 Mon Sep 17 00:00:00 2001 From: hnil Date: Tue, 4 Aug 2020 22:03:44 +0200 Subject: [PATCH 59/93] for now do now switching when updating presssure --- ebos/eclblackoilprimaryvariables.hh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ebos/eclblackoilprimaryvariables.hh b/ebos/eclblackoilprimaryvariables.hh index dc321708eb3..662609e8fd2 100644 --- a/ebos/eclblackoilprimaryvariables.hh +++ b/ebos/eclblackoilprimaryvariables.hh @@ -355,6 +355,12 @@ public: } Scalar pressure=-1.0; Scalar totalsaturation=-1.0; + if(simulationType_ == SimulationType::Implicit){ + if(linearizationType.type == LinearizationType::pressure){ + return false; //No switchin during pressure solve; + } + } + if(simulationType_ == SimulationType::Implicit){ pressure = (*this)[Indices::pressureSwitchIdx]; totalsaturation = problem.totalSaturation(globalDofIdx); From 045877dcd333a45babd5649ac8348e2c6fe466ca Mon Sep 17 00:00:00 2001 From: hnil Date: Wed, 5 Aug 2020 16:03:35 +0200 Subject: [PATCH 60/93] added fix to get min(rs,rsSat) --- ebos/eclblackoilintensivequantities.hh | 35 +++++++++++++++++++++----- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/ebos/eclblackoilintensivequantities.hh b/ebos/eclblackoilintensivequantities.hh index 9744858e3e6..894643b12be 100644 --- a/ebos/eclblackoilintensivequantities.hh +++ b/ebos/eclblackoilintensivequantities.hh @@ -283,11 +283,22 @@ public: else if (priVars.primaryVarsMeaning() == PrimaryVariables::Sw_po_Rs) { // if the switching variable is the mole fraction of the gas component in the Scalar RsMax = elemCtx.problem().maxGasDissolutionFactor(timeIdx, globalSpaceIdx); - - // oil phase, we can directly set the composition of the oil phase - const auto& Rs = priVars.makeEvaluation(Indices::compositionSwitchIdx, timeIdx, linearizationType); - fluidState_.setRs(Opm::min(RsMax, Rs)); - + if(linearizationType.type == Opm::LinearizationType::pressure){ + const Evaluation& RsSat = + FluidSystem::saturatedDissolutionFactor(fluidState_, + oilPhaseIdx, + pvtRegionIdx, + SoMax); + RsMax = Opm::min(RsMax,Toolbox::value(RsSat)); + auto priVarsCopy = priVars; + priVarsCopy[Indices::compositionSwitchIdx] = Opm::min(RsMax,priVarsCopy[Indices::compositionSwitchIdx]); + const auto& Rs = priVarsCopy.makeEvaluation(Indices::compositionSwitchIdx, timeIdx, linearizationType); + fluidState_.setRs(Rs); + }else{ + // oil phase, we can directly set the composition of the oil phase + const auto& Rs = priVars.makeEvaluation(Indices::compositionSwitchIdx, timeIdx, linearizationType); + fluidState_.setRs(Opm::min(RsMax, Rs)); + } if (FluidSystem::enableVaporizedOil()) { // the gas phase is not present, but we need to compute its "composition" // for the gravity correction anyway @@ -305,7 +316,19 @@ public: } else if (priVars.primaryVarsMeaning() == PrimaryVariables::Sw_pg_Rv) { const auto& Rv = priVars.makeEvaluation(Indices::compositionSwitchIdx, timeIdx, linearizationType); - fluidState_.setRv(Rv); + if(linearizationType.type == Opm::LinearizationType::pressure){ + const auto& RvSat = + FluidSystem::saturatedDissolutionFactor(fluidState_, + gasPhaseIdx, + pvtRegionIdx, + SoMax); + auto priVarsCopy = priVars; + priVarsCopy[Indices::compositionSwitchIdx] = Opm::min(Toolbox::value(RvMax),priVarsCopy[Indices::compositionSwitchIdx]); + const auto& Rv = priVarsCopy.makeEvaluation(Indices::compositionSwitchIdx, timeIdx, linearizationType); + fluidState_.setRv(Rv); + }else{ + fluidState_.setRv(Rv); + } if (FluidSystem::enableDissolvedGas()) { // the oil phase is not present, but we need to compute its "composition" for From 7c15117ad2c9eda94b8bec2406ae0d658a5215f2 Mon Sep 17 00:00:00 2001 From: hnil Date: Wed, 5 Aug 2020 22:29:34 +0200 Subject: [PATCH 61/93] fixed Rv error --- ebos/eclblackoilintensivequantities.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ebos/eclblackoilintensivequantities.hh b/ebos/eclblackoilintensivequantities.hh index 894643b12be..37b4c7a9c3e 100644 --- a/ebos/eclblackoilintensivequantities.hh +++ b/ebos/eclblackoilintensivequantities.hh @@ -323,7 +323,7 @@ public: pvtRegionIdx, SoMax); auto priVarsCopy = priVars; - priVarsCopy[Indices::compositionSwitchIdx] = Opm::min(Toolbox::value(RvMax),priVarsCopy[Indices::compositionSwitchIdx]); + priVarsCopy[Indices::compositionSwitchIdx] = Opm::min(Toolbox::value(RvSat),priVarsCopy[Indices::compositionSwitchIdx]); const auto& Rv = priVarsCopy.makeEvaluation(Indices::compositionSwitchIdx, timeIdx, linearizationType); fluidState_.setRv(Rv); }else{ From 83d8965c5aec3df755f13e2803a1e5ec7433f680 Mon Sep 17 00:00:00 2001 From: hnil Date: Wed, 5 Aug 2020 22:35:29 +0200 Subject: [PATCH 62/93] fix RV part for limiting RV on pressure solve --- ebos/eclblackoilintensivequantities.hh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ebos/eclblackoilintensivequantities.hh b/ebos/eclblackoilintensivequantities.hh index 37b4c7a9c3e..acd28cadb92 100644 --- a/ebos/eclblackoilintensivequantities.hh +++ b/ebos/eclblackoilintensivequantities.hh @@ -315,7 +315,7 @@ public: fluidState_.setRv(0.0); } else if (priVars.primaryVarsMeaning() == PrimaryVariables::Sw_pg_Rv) { - const auto& Rv = priVars.makeEvaluation(Indices::compositionSwitchIdx, timeIdx, linearizationType); + if(linearizationType.type == Opm::LinearizationType::pressure){ const auto& RvSat = FluidSystem::saturatedDissolutionFactor(fluidState_, @@ -326,7 +326,8 @@ public: priVarsCopy[Indices::compositionSwitchIdx] = Opm::min(Toolbox::value(RvSat),priVarsCopy[Indices::compositionSwitchIdx]); const auto& Rv = priVarsCopy.makeEvaluation(Indices::compositionSwitchIdx, timeIdx, linearizationType); fluidState_.setRv(Rv); - }else{ + }else{ + const auto& Rv = priVars.makeEvaluation(Indices::compositionSwitchIdx, timeIdx, linearizationType); fluidState_.setRv(Rv); } From a6945757ec2f89a3e49d0ff6b05387b7b3c3d2ea Mon Sep 17 00:00:00 2001 From: hnil Date: Fri, 7 Aug 2020 14:14:00 +0200 Subject: [PATCH 63/93] working version for spe1case2 --- ebos/eclblackoilintensivequantities.hh | 44 ++++++++++++++++----- opm/simulators/flow/NonlinearSolverEbos.hpp | 2 +- opm/simulators/wells/StandardWell_impl.hpp | 11 ++++++ 3 files changed, 47 insertions(+), 10 deletions(-) diff --git a/ebos/eclblackoilintensivequantities.hh b/ebos/eclblackoilintensivequantities.hh index acd28cadb92..21576e8a6c6 100644 --- a/ebos/eclblackoilintensivequantities.hh +++ b/ebos/eclblackoilintensivequantities.hh @@ -139,7 +139,7 @@ public: if (priVars.primaryVarsMeaning() == PrimaryVariables::Sw_po_Sg) { // -> threephase case assert( priVars.primaryVarsMeaning() != PrimaryVariables::OnePhase_p ); - Sg = priVars.makeEvaluation(Indices::compositionSwitchIdx, timeIdx); + Sg = priVars.makeEvaluation(Indices::compositionSwitchIdx, timeIdx,linearizationType); } else if (priVars.primaryVarsMeaning() == PrimaryVariables::Sw_pg_Rv) { // -> gas-water case Sg = 1.0 - Sw; @@ -151,8 +151,29 @@ public: else { assert(priVars.primaryVarsMeaning() == PrimaryVariables::Sw_po_Rs); + if(linearizationType.type == Opm::LinearizationType::pressure){ + Scalar po = priVars[Indices::pressureSwitchIdx]; + Scalar T = Toolbox::value(fluidState_.temperature(0));//priVars.temperature_(); + Scalar SoMax = problem.maxOilSaturation(globalSpaceIdx); + Scalar So2 = Toolbox::value(1.0 - Sw);// - priVars.solventSaturation_()); + Scalar RsMax = problem.maxGasDissolutionFactor(/*timeIdx=*/0, globalSpaceIdx); + Scalar RsSat = FluidSystem::oilPvt().saturatedGasDissolutionFactor(pvtRegionIdx, + T, + po, + So2, + SoMax); + Scalar Rs = priVars[Indices::compositionSwitchIdx]; + if(Rs>RsSat){ + auto priVarsCopy = priVars; + priVarsCopy[Indices::compositionSwitchIdx] = 0.0; + Sg = priVarsCopy.makeEvaluation(Indices::compositionSwitchIdx, timeIdx, linearizationType); + }else{ + Sg = 0.0; + } + }else{ // -> oil-water case - Sg = 0.0; + Sg = 0.0; + } } } @@ -281,19 +302,24 @@ public: fluidState_.setRv(0.0); } else if (priVars.primaryVarsMeaning() == PrimaryVariables::Sw_po_Rs) { - // if the switching variable is the mole fraction of the gas component in the - Scalar RsMax = elemCtx.problem().maxGasDissolutionFactor(timeIdx, globalSpaceIdx); + //if the switching variable is the mole fraction of the gas component in the + Evaluation RsMax = elemCtx.problem().maxGasDissolutionFactor(timeIdx, globalSpaceIdx); if(linearizationType.type == Opm::LinearizationType::pressure){ const Evaluation& RsSat = FluidSystem::saturatedDissolutionFactor(fluidState_, oilPhaseIdx, pvtRegionIdx, SoMax); - RsMax = Opm::min(RsMax,Toolbox::value(RsSat)); - auto priVarsCopy = priVars; - priVarsCopy[Indices::compositionSwitchIdx] = Opm::min(RsMax,priVarsCopy[Indices::compositionSwitchIdx]); - const auto& Rs = priVarsCopy.makeEvaluation(Indices::compositionSwitchIdx, timeIdx, linearizationType); - fluidState_.setRs(Rs); + RsMax = Opm::min(RsMax, RsSat); + //auto priVarsCopy = priVars; + //priVarsCopy[Indices::compositionSwitchIdx] = Opm::min(RsMax,priVarsCopy[Indices::compositionSwitchIdx]); + const auto& Rs = priVars.makeEvaluation(Indices::compositionSwitchIdx, timeIdx, linearizationType); + if(Rs>RsSat){ + fluidState_.setRs(RsSat); + }else{ + + fluidState_.setRs(Rs); + } }else{ // oil phase, we can directly set the composition of the oil phase const auto& Rs = priVars.makeEvaluation(Indices::compositionSwitchIdx, timeIdx, linearizationType); diff --git a/opm/simulators/flow/NonlinearSolverEbos.hpp b/opm/simulators/flow/NonlinearSolverEbos.hpp index f5a7dede45e..824f6d69e9d 100644 --- a/opm/simulators/flow/NonlinearSolverEbos.hpp +++ b/opm/simulators/flow/NonlinearSolverEbos.hpp @@ -180,7 +180,7 @@ namespace Opm { model_->updateSolution(); reportpre += lreportpre; try{ - model_->ebosSimulator().model().advanceTimeLevel(); + //model_->ebosSimulator().model().advanceTimeLevel(); //model_->ebosSimulator().problem().beginTimeStep(); SimulatorReportSingle lreportseq = this->stepDefault(timer,/*next*/false, false); // hopefully do not change any thing only update well quantities diff --git a/opm/simulators/wells/StandardWell_impl.hpp b/opm/simulators/wells/StandardWell_impl.hpp index f8cb2754cfb..68aa8495adf 100644 --- a/opm/simulators/wells/StandardWell_impl.hpp +++ b/opm/simulators/wells/StandardWell_impl.hpp @@ -3223,6 +3223,17 @@ namespace Opm } } } +#ifndef NDEBUG + auto cq_s_tmp = perf_rates.cq_s; + computePerfRateSeq(intQuants,mob,/*bhp,Tw,perf,*/allow_cf,perf_rates,deferred_logger); + if(not(linearizationType.type == Opm::LinearizationType::seqtransport)){ + for(size_t i = 0; i < cq_s_tmp.size(); ++i){ + typedef Opm::MathToolbox Toolbox; + assert(Toolbox::isSame(cq_s_tmp[i],perf_rates.cq_s[i],1e-6)); + } + } +#endif + } From acec19d48b7c38a162cd0a6524e5875b636f2f6d Mon Sep 17 00:00:00 2001 From: hnil Date: Fri, 7 Aug 2020 22:21:54 +0200 Subject: [PATCH 64/93] added chopping off sT, for now hardcoded. --- ebos/eclblackoilnewtonmethod.hh | 1 + ebos/eclblackoilprimaryvariables.hh | 3 +++ 2 files changed, 4 insertions(+) diff --git a/ebos/eclblackoilnewtonmethod.hh b/ebos/eclblackoilnewtonmethod.hh index 957bedffac4..3367651a5de 100644 --- a/ebos/eclblackoilnewtonmethod.hh +++ b/ebos/eclblackoilnewtonmethod.hh @@ -226,6 +226,7 @@ protected: LinearizationType linearizationType = this->model().linearizer().getLinearizationType(); if (linearizationType.type == Opm::LinearizationType::seqtransport) { // TODO: set max update of ST + delta = Opm::signum(delta)*std::min(delta,0.1); } else { if (std::abs(delta) > dpMaxRel_*currentValue[pvIdx]) delta = Opm::signum(delta)*dpMaxRel_*currentValue[pvIdx]; diff --git a/ebos/eclblackoilprimaryvariables.hh b/ebos/eclblackoilprimaryvariables.hh index 662609e8fd2..ab45e0cf05e 100644 --- a/ebos/eclblackoilprimaryvariables.hh +++ b/ebos/eclblackoilprimaryvariables.hh @@ -378,6 +378,9 @@ public: }else{ assert(false); } + totalsaturation = std::max(0.1,totalsaturation); + totalsaturation = std::min(totalsaturation,5.0); + if(linearizationType.type == LinearizationType::seqtransport){ (*this)[Indices::pressureSwitchIdx] = totalsaturation; this->simulationType_ = SimulationType::Seq; From d04b4bf7fe005992d7571a3a1a3eeff736f35c97 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Mon, 10 Aug 2020 12:03:04 +0200 Subject: [PATCH 65/93] fixing the bug when chopping the delta in eclblackoilnewtonmethod --- ebos/eclblackoilnewtonmethod.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ebos/eclblackoilnewtonmethod.hh b/ebos/eclblackoilnewtonmethod.hh index 3367651a5de..8db0a487fd1 100644 --- a/ebos/eclblackoilnewtonmethod.hh +++ b/ebos/eclblackoilnewtonmethod.hh @@ -226,7 +226,7 @@ protected: LinearizationType linearizationType = this->model().linearizer().getLinearizationType(); if (linearizationType.type == Opm::LinearizationType::seqtransport) { // TODO: set max update of ST - delta = Opm::signum(delta)*std::min(delta,0.1); + delta = Opm::signum(delta) * std::min(std::abs(delta), 0.1); } else { if (std::abs(delta) > dpMaxRel_*currentValue[pvIdx]) delta = Opm::signum(delta)*dpMaxRel_*currentValue[pvIdx]; From f0d1a86a6abc358d750badcb05ce33c265f614bf Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Mon, 10 Aug 2020 13:48:23 +0200 Subject: [PATCH 66/93] using umfpack as the default pressure solver when there is no pressuresolver.json file is provided. --- opm/simulators/flow/BlackoilModelEbos.hpp | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/opm/simulators/flow/BlackoilModelEbos.hpp b/opm/simulators/flow/BlackoilModelEbos.hpp index adead42f293..23dc1f06f40 100644 --- a/opm/simulators/flow/BlackoilModelEbos.hpp +++ b/opm/simulators/flow/BlackoilModelEbos.hpp @@ -69,6 +69,7 @@ #include #include #include +#include namespace Opm::Properties { @@ -503,10 +504,20 @@ namespace Opm { PressureVectorType rhs(ebosResid.size(),0); PressureHelper::moveToPressureEqn(ebosResid, rhs, weights); boost::property_tree::ptree prm; - try{ - boost::property_tree::read_json("pressuresolver.json", prm); - }catch(...){ - OPM_THROW(std::logic_error,"Configuration file pressuresolver.json not pressent"); + if (std::filesystem::exists("pressuresolver.json") ) { + try{ + boost::property_tree::read_json("pressuresolver.json", prm); + }catch(...){ + OPM_THROW(std::logic_error,"failed in passing configuration file pressuresolver.json"); + } + } else { + // using a default setup for pressure solver + std::stringstream ss; + ss << "{\n" + " \"solver\": \"umfpack\",\n" + " \"blocksize\": \"1\"\n" + "}"; + boost::property_tree::read_json(ss, prm); } std::any parallelInformation; extractParallelGridInformationToISTL(ebosSimulator_.vanguard().grid(), parallelInformation); From 9db26ac3a27788d8d79b648684bd6b51fc27eadd Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Mon, 10 Aug 2020 14:31:21 +0200 Subject: [PATCH 67/93] trying to add a test for sequential running for SPE1CASE2 --- compareECLFiles.cmake | 7 +++++++ tests/update_reference_data.sh | 1 + 2 files changed, 8 insertions(+) diff --git a/compareECLFiles.cmake b/compareECLFiles.cmake index 9bf092c2212..21ae2ca5622 100755 --- a/compareECLFiles.cmake +++ b/compareECLFiles.cmake @@ -196,6 +196,13 @@ add_test_compareECLFiles(CASENAME spe1 ABS_TOL ${abs_tol} REL_TOL ${coarse_rel_tol}) +add_test_compareECLFiles(CASENAME spe12_seq + FILENAME SPE1CASE2 + SIMULATOR flow_blackoil_dunecpr_seq + ABS_TOL ${abs_tol} + REL_TOL ${rel_tol} + TEST_ARGS --full-time-step-initially=true --enable-adaptive-time-stepping=false --simulation-type=seq --enable-storage-cache=false) + add_test_compareECLFiles(CASENAME spe1_2p FILENAME SPE1CASE2_2P SIMULATOR flow diff --git a/tests/update_reference_data.sh b/tests/update_reference_data.sh index f2e0b36e106..dce7b775f79 100755 --- a/tests/update_reference_data.sh +++ b/tests/update_reference_data.sh @@ -54,6 +54,7 @@ declare -A tests # to be used by cmake as an optional fourth argument. tests[spe1]="flow spe1 SPE1CASE1" tests[spe12]="flow spe1 SPE1CASE2" +tests[spe12_seq]="flow_blackoil_dunecpr_seq spe1 SPE1CASE2" tests[spe12p]="flow spe1 SPE1CASE2_2P spe1_2p" tests[spe1oilgas]="flow spe1 SPE1CASE2_OILGAS spe1_oilgas" tests[spe1nowells]="flow spe1 SPE1CASE2_NOWELLS spe1_nowells" From d7e9530c5fd833451a8ab537e972ee625485cd78 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Tue, 11 Aug 2020 09:20:23 +0200 Subject: [PATCH 68/93] fixing the time step calculation to make sure we have the consistent information when calculating relative change for time step calculation. --- opm/simulators/flow/BlackoilModelEbos.hpp | 9 +++++---- opm/simulators/flow/NonlinearSolverEbos.hpp | 6 +++++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/opm/simulators/flow/BlackoilModelEbos.hpp b/opm/simulators/flow/BlackoilModelEbos.hpp index 23dc1f06f40..00900ce1cbf 100644 --- a/opm/simulators/flow/BlackoilModelEbos.hpp +++ b/opm/simulators/flow/BlackoilModelEbos.hpp @@ -591,7 +591,8 @@ namespace Opm { void updateSolution(){ unsigned numDof = ebosSimulator_.model().numGridDof(); BVector dx(numDof,0); - this->updateSolution(dx); + this->updateSolution(dx, 0); + this->updateSolution(dx, 1); // for(unsigned timeidx; timeidx< 2; ++timidx){ // SolutionVector& sol = model().solution(/*historyIdx=*/timeidx); // size_t numGridDof = ebosSimulator_.model().numGridDof(); @@ -605,10 +606,10 @@ namespace Opm { } /// Apply an update to the primary variables. - void updateSolution(const BVector& dx) + void updateSolution(const BVector& dx, const int timeIdx = 0) { auto& ebosNewtonMethod = ebosSimulator_.model().newtonMethod(); - SolutionVector& solution = ebosSimulator_.model().solution(/*timeIdx=*/0); + SolutionVector& solution = ebosSimulator_.model().solution(timeIdx); ebosNewtonMethod.update_(/*nextSolution=*/solution, /*curSolution=*/solution, @@ -618,7 +619,7 @@ namespace Opm { // residual // if the solution is updated, the intensive quantities need to be recalculated - ebosSimulator_.model().invalidateIntensiveQuantitiesCache(/*timeIdx=*/0); + ebosSimulator_.model().invalidateIntensiveQuantitiesCache(timeIdx); } /// Return true if output to cout is wanted. diff --git a/opm/simulators/flow/NonlinearSolverEbos.hpp b/opm/simulators/flow/NonlinearSolverEbos.hpp index 824f6d69e9d..3a83a39e532 100644 --- a/opm/simulators/flow/NonlinearSolverEbos.hpp +++ b/opm/simulators/flow/NonlinearSolverEbos.hpp @@ -233,9 +233,13 @@ namespace Opm { if(not(converged)){ report.converged = false; }else{ - model_->updateSolution(); + // model_->updateSolution(); model_->ebosSimulator().problem().updateTotalSaturation(); model_->afterStep(timer); + // NOTE: updating solution again for information used in the relativeChange function. + linearizationType.type = Opm::LinearizationType::pressure; + model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); + model_->updateSolution(); report.converged = true; } //todo fill this report correctly From 2f02b8d192225faf408c24a850de92f6a1997ad1 Mon Sep 17 00:00:00 2001 From: hnil Date: Wed, 12 Aug 2020 09:08:56 +0200 Subject: [PATCH 69/93] go back to have state to be undersaturationed with rs=min(rsSat,rs) at border with derivative with respect to rs. - corrected update chopping sT - added asserts - output of iterarations to scrren - commented line on alternative inital guess for transport - skip well switching in transport --- ebos/eclblackoilintensivequantities.hh | 57 +++++++++---------- ebos/eclproblem.hh | 2 + opm/simulators/flow/BlackoilModelEbos.hpp | 2 + opm/simulators/flow/NonlinearSolverEbos.hpp | 4 +- .../wells/BlackoilWellModel_impl.hpp | 6 +- 5 files changed, 40 insertions(+), 31 deletions(-) diff --git a/ebos/eclblackoilintensivequantities.hh b/ebos/eclblackoilintensivequantities.hh index 21576e8a6c6..f26c8366c61 100644 --- a/ebos/eclblackoilintensivequantities.hh +++ b/ebos/eclblackoilintensivequantities.hh @@ -151,29 +151,29 @@ public: else { assert(priVars.primaryVarsMeaning() == PrimaryVariables::Sw_po_Rs); - if(linearizationType.type == Opm::LinearizationType::pressure){ - Scalar po = priVars[Indices::pressureSwitchIdx]; - Scalar T = Toolbox::value(fluidState_.temperature(0));//priVars.temperature_(); - Scalar SoMax = problem.maxOilSaturation(globalSpaceIdx); - Scalar So2 = Toolbox::value(1.0 - Sw);// - priVars.solventSaturation_()); - Scalar RsMax = problem.maxGasDissolutionFactor(/*timeIdx=*/0, globalSpaceIdx); - Scalar RsSat = FluidSystem::oilPvt().saturatedGasDissolutionFactor(pvtRegionIdx, - T, - po, - So2, - SoMax); - Scalar Rs = priVars[Indices::compositionSwitchIdx]; - if(Rs>RsSat){ - auto priVarsCopy = priVars; - priVarsCopy[Indices::compositionSwitchIdx] = 0.0; - Sg = priVarsCopy.makeEvaluation(Indices::compositionSwitchIdx, timeIdx, linearizationType); - }else{ - Sg = 0.0; - } - }else{ + // if(linearizationType.type == Opm::LinearizationType::pressure){ + // Scalar po = priVars[Indices::pressureSwitchIdx]; + // Scalar T = Toolbox::value(fluidState_.temperature(0));//priVars.temperature_(); + // Scalar SoMax = problem.maxOilSaturation(globalSpaceIdx); + // Scalar So2 = Toolbox::value(1.0 - Sw);// - priVars.solventSaturation_()); + // Scalar RsMax = problem.maxGasDissolutionFactor(/*timeIdx=*/0, globalSpaceIdx); + // Scalar RsSat = FluidSystem::oilPvt().saturatedGasDissolutionFactor(pvtRegionIdx, + // T, + // po, + // So2, + // SoMax); + // Scalar Rs = priVars[Indices::compositionSwitchIdx]; + // if(Rs>RsSat){ + // auto priVarsCopy = priVars; + // priVarsCopy[Indices::compositionSwitchIdx] = 0.0; + // Sg = priVarsCopy.makeEvaluation(Indices::compositionSwitchIdx, timeIdx, linearizationType); + // }else{ + // Sg = 0.0; + // } + // }else{ // -> oil-water case Sg = 0.0; - } + //} } } @@ -311,15 +311,14 @@ public: pvtRegionIdx, SoMax); RsMax = Opm::min(RsMax, RsSat); - //auto priVarsCopy = priVars; - //priVarsCopy[Indices::compositionSwitchIdx] = Opm::min(RsMax,priVarsCopy[Indices::compositionSwitchIdx]); + auto priVarsCopy = priVars; + priVarsCopy[Indices::compositionSwitchIdx] = Opm::min(Toolbox::value(RsMax),priVarsCopy[Indices::compositionSwitchIdx]); const auto& Rs = priVars.makeEvaluation(Indices::compositionSwitchIdx, timeIdx, linearizationType); - if(Rs>RsSat){ - fluidState_.setRs(RsSat); - }else{ - - fluidState_.setRs(Rs); - } + //if(Rs>RsSat){ + // fluidState_.setRs(RsSat); + //}else{ + fluidState_.setRs(Rs); + //} }else{ // oil phase, we can directly set the composition of the oil phase const auto& Rs = priVars.makeEvaluation(Indices::compositionSwitchIdx, timeIdx, linearizationType); diff --git a/ebos/eclproblem.hh b/ebos/eclproblem.hh index 96f234fe9e6..375c353bd2e 100644 --- a/ebos/eclproblem.hh +++ b/ebos/eclproblem.hh @@ -1034,8 +1034,10 @@ public: std::ofstream file(prefix.c_str()); std::string simulationType = EWOMS_GET_PARAM(TypeTag, std::string, SimulationType); if(simulationType == "seq"){ +#ifndef NDEBUG Opm::LinearizationType linearizationType = this->simulator().model().linearizer().getLinearizationType(); assert(linearizationType.type == Opm::LinearizationType::seqtransport); +#endif } for(const auto& v : totalSaturation_){ file << v << std::endl; diff --git a/opm/simulators/flow/BlackoilModelEbos.hpp b/opm/simulators/flow/BlackoilModelEbos.hpp index 00900ce1cbf..4d0f438abff 100644 --- a/opm/simulators/flow/BlackoilModelEbos.hpp +++ b/opm/simulators/flow/BlackoilModelEbos.hpp @@ -893,6 +893,7 @@ namespace Opm { msg += ") "; } OpmLog::debug(msg); + OpmLog::info(msg); } std::ostringstream ss; const std::streamsize oprec = ss.precision(3); @@ -907,6 +908,7 @@ namespace Opm { ss.precision(oprec); ss.flags(oflags); OpmLog::debug(ss.str()); + OpmLog::info(ss.str()); } return report; diff --git a/opm/simulators/flow/NonlinearSolverEbos.hpp b/opm/simulators/flow/NonlinearSolverEbos.hpp index 3a83a39e532..25f10c32698 100644 --- a/opm/simulators/flow/NonlinearSolverEbos.hpp +++ b/opm/simulators/flow/NonlinearSolverEbos.hpp @@ -176,7 +176,9 @@ namespace Opm { model_->ebosSimulator().problem().updatePressureAndFluxes();//update pressure ans ST linearizationType.type = Opm::LinearizationType::seqtransport; model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); - + // initial guess for transport use the old state + //auto& currsol = model_->ebosSimulator().model().solution(/*timeIdx=*/0); + //currsol = solutionOld; model_->updateSolution(); reportpre += lreportpre; try{ diff --git a/opm/simulators/wells/BlackoilWellModel_impl.hpp b/opm/simulators/wells/BlackoilWellModel_impl.hpp index 86e354266e7..08c895d84ab 100644 --- a/opm/simulators/wells/BlackoilWellModel_impl.hpp +++ b/opm/simulators/wells/BlackoilWellModel_impl.hpp @@ -23,7 +23,7 @@ #include #include #include - +#include namespace Opm { template BlackoilWellModel:: @@ -1181,6 +1181,10 @@ namespace Opm { // Even if there are no wells active locally, we cannot // return as the DeferredLogger uses global communication. // For no well active globally we simply return. + const LinearizationType& linearizationType = ebosSimulator_.model().linearizer().getLinearizationType(); + if(linearizationType.type == Opm::LinearizationType::seqtransport){ + return; + } if( !wellsActive() ) return ; updateAndCommunicateGroupData(); From 25be86170ccfb0dd6d7e26a7f30f842806455145 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Atgeirr=20Fl=C3=B8=20Rasmussen?= Date: Wed, 12 Aug 2020 10:27:55 +0200 Subject: [PATCH 70/93] Move mis-merged block of debug code. --- opm/simulators/wells/StandardWell_impl.hpp | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/opm/simulators/wells/StandardWell_impl.hpp b/opm/simulators/wells/StandardWell_impl.hpp index 68aa8495adf..1ec5b9095fc 100644 --- a/opm/simulators/wells/StandardWell_impl.hpp +++ b/opm/simulators/wells/StandardWell_impl.hpp @@ -531,6 +531,16 @@ namespace Opm } } } +#ifndef NDEBUG + auto cq_s_tmp = perf_rates.cq_s; + computePerfRateSeq(intQuants,mob,/*bhp,Tw,perf,*/allow_cf,perf_rates,deferred_logger); + if(not(linearizationType.type == Opm::LinearizationType::seqtransport)){ + for(size_t i = 0; i < cq_s_tmp.size(); ++i){ + typedef Opm::MathToolbox Toolbox; + assert(Toolbox::isSame(cq_s_tmp[i],perf_rates.cq_s[i],1e-6)); + } + } +#endif } @@ -3223,18 +3233,6 @@ namespace Opm } } } -#ifndef NDEBUG - auto cq_s_tmp = perf_rates.cq_s; - computePerfRateSeq(intQuants,mob,/*bhp,Tw,perf,*/allow_cf,perf_rates,deferred_logger); - if(not(linearizationType.type == Opm::LinearizationType::seqtransport)){ - for(size_t i = 0; i < cq_s_tmp.size(); ++i){ - typedef Opm::MathToolbox Toolbox; - assert(Toolbox::isSame(cq_s_tmp[i],perf_rates.cq_s[i],1e-6)); - } - } -#endif - - } From 58243e9077dc39613e1d734968f4ddd12def493f Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Wed, 12 Aug 2020 11:51:16 +0200 Subject: [PATCH 71/93] adding two totalSaturation_ in eclproblem --- ebos/eclproblem.hh | 26 ++++++++++++----------- opm/simulators/flow/BlackoilModelEbos.hpp | 4 ++-- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/ebos/eclproblem.hh b/ebos/eclproblem.hh index 375c353bd2e..d24e2153706 100644 --- a/ebos/eclproblem.hh +++ b/ebos/eclproblem.hh @@ -691,7 +691,8 @@ public: } pressure_[0].resize(numDof); pressure_[1].resize(numDof); - totalSaturation_.resize(numDof, 1.0); + totalSaturation_[0].resize(numDof, 1.0); + totalSaturation_[1].resize(numDof, 1.0); updateElementDepths_(); readRockParameters_(); @@ -1039,7 +1040,7 @@ public: assert(linearizationType.type == Opm::LinearizationType::seqtransport); #endif } - for(const auto& v : totalSaturation_){ + for(const auto& v : totalSaturation_[0]){ file << v << std::endl; } } @@ -1815,23 +1816,23 @@ public: // phase index is unused for now will give warning in compilation return pressure_[timeIdx][globalDofIdx][phaseIndex]; } - Scalar totalSaturation(unsigned globalDofIdx) const + Scalar totalSaturation(unsigned globalDofIdx, const unsigned timeIdx = 0) const { - return totalSaturation_[globalDofIdx]; + return totalSaturation_[timeIdx][globalDofIdx]; } - const std::vector& getTotalSaturation() const + const std::vector& getTotalSaturation(const unsigned timeIdx = 0) const { - return totalSaturation_; + return totalSaturation_[timeIdx]; } - void setTotalSaturation(std::vector totSat) + void setTotalSaturation(std::vector totSat, const unsigned timeIdx = 0) { - totalSaturation_ = totSat; + totalSaturation_[timeIdx] = totSat; } - void totalSaturationOne(){ - for(auto& v : totalSaturation_){ + void totalSaturationOne(const unsigned timeIdx = 0){ + for(auto& v : totalSaturation_[timeIdx]){ v=1.0; } } @@ -2320,7 +2321,8 @@ private: unsigned compressedDofIdx = elemCtx.globalSpaceIndex(/*spaceIdx=*/0, /*timeIdx=*/0); const auto& iq = elemCtx.intensiveQuantities(/*spaceIdx=*/0, /*timeIdx=*/0); const auto& fs = iq.fluidState(); - totalSaturation_[compressedDofIdx] = Opm::getValue(fs.totalSaturation()); + // TODO: not sure where to handle the update totalSaturation_[1] + totalSaturation_[/*timeIdx=*/0][compressedDofIdx] = Opm::getValue(fs.totalSaturation()); } return true; } @@ -3268,7 +3270,7 @@ private: std::vector overburdenPressure_; std::vector minOilPressure_; std::array< std::vector >, 2> pressure_; - std::vector totalSaturation_; + std::array, 2> totalSaturation_; std::vector< std::vector > totalFlux_; std::vector rockCompPoroMult_; diff --git a/opm/simulators/flow/BlackoilModelEbos.hpp b/opm/simulators/flow/BlackoilModelEbos.hpp index 4d0f438abff..1c4f51d9f88 100644 --- a/opm/simulators/flow/BlackoilModelEbos.hpp +++ b/opm/simulators/flow/BlackoilModelEbos.hpp @@ -892,7 +892,7 @@ namespace Opm { msg += compNames[compIdx][0]; msg += ") "; } - OpmLog::debug(msg); + // OpmLog::debug(msg); OpmLog::info(msg); } std::ostringstream ss; @@ -907,7 +907,7 @@ namespace Opm { } ss.precision(oprec); ss.flags(oflags); - OpmLog::debug(ss.str()); + // OpmLog::debug(ss.str()); OpmLog::info(ss.str()); } From 8dad63983dbf9bf0db308475dc79437c517237d8 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Wed, 12 Aug 2020 15:18:33 +0200 Subject: [PATCH 72/93] fixing the compilatin of ebos_plain and adding DIR to the test for flow_blackoil_dunecpr_seq --- compareECLFiles.cmake | 1 + ebos/ebos_plain.cc | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/compareECLFiles.cmake b/compareECLFiles.cmake index 21ae2ca5622..2090e0ba95a 100755 --- a/compareECLFiles.cmake +++ b/compareECLFiles.cmake @@ -201,6 +201,7 @@ add_test_compareECLFiles(CASENAME spe12_seq SIMULATOR flow_blackoil_dunecpr_seq ABS_TOL ${abs_tol} REL_TOL ${rel_tol} + DIR spe1 TEST_ARGS --full-time-step-initially=true --enable-adaptive-time-stepping=false --simulation-type=seq --enable-storage-cache=false) add_test_compareECLFiles(CASENAME spe1_2p diff --git a/ebos/ebos_plain.cc b/ebos/ebos_plain.cc index ab16342d897..ec2ed956ca7 100644 --- a/ebos/ebos_plain.cc +++ b/ebos/ebos_plain.cc @@ -33,7 +33,7 @@ namespace Opm::Properties { -NEW_TYPE_TAG(EbosPlainTypeTag, INHERITS_FROM(BlackOilModel, EclBaseProblem)); +NEW_TYPE_TAG(EbosPlainTypeTag, INHERITS_FROM(BlackOilModel, EclBaseProblem, FlowModelParameters)); } // namespace Opm::Properties From ac6947e78c8dde0a66a5fc9a65ff499c0fc5baf0 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Wed, 12 Aug 2020 23:35:33 +0200 Subject: [PATCH 73/93] During pressure solve, testing the perforation rates from different functions. It only happens during the sequential solution. This is to recover the running with flow. --- opm/simulators/wells/StandardWell_impl.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opm/simulators/wells/StandardWell_impl.hpp b/opm/simulators/wells/StandardWell_impl.hpp index 1ec5b9095fc..6940ae5eb14 100644 --- a/opm/simulators/wells/StandardWell_impl.hpp +++ b/opm/simulators/wells/StandardWell_impl.hpp @@ -534,7 +534,7 @@ namespace Opm #ifndef NDEBUG auto cq_s_tmp = perf_rates.cq_s; computePerfRateSeq(intQuants,mob,/*bhp,Tw,perf,*/allow_cf,perf_rates,deferred_logger); - if(not(linearizationType.type == Opm::LinearizationType::seqtransport)){ + if (linearizationType.type == Opm::LinearizationType::pressure) { for(size_t i = 0; i < cq_s_tmp.size(); ++i){ typedef Opm::MathToolbox Toolbox; assert(Toolbox::isSame(cq_s_tmp[i],perf_rates.cq_s[i],1e-6)); From 1bc2bd15e24818853d02b57067180132a503a267 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Thu, 13 Aug 2020 00:36:19 +0200 Subject: [PATCH 74/93] only writing extra_out for sequential running. --- ebos/eclproblem.hh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ebos/eclproblem.hh b/ebos/eclproblem.hh index d24e2153706..63c32fcfc1b 100644 --- a/ebos/eclproblem.hh +++ b/ebos/eclproblem.hh @@ -1009,6 +1009,8 @@ public: void writeExtra(){ + // Currently, the extra output is only for sequential simulation + if ( EWOMS_GET_PARAM(TypeTag, std::string, SimulationType) != "seq" ) return; std::string dir = this->simulator().problem().outputDir(); if (dir == ".") { dir = ""; From db3988a9431b2274b9c3b57ba5bee76bd1516594 Mon Sep 17 00:00:00 2001 From: hnil Date: Thu, 13 Aug 2020 12:07:10 +0200 Subject: [PATCH 75/93] added report on timing iteration ++ for pressure and transport solve --- opm/simulators/flow/NonlinearSolverEbos.hpp | 7 +- .../timestepping/SimulatorReport.cpp | 64 ++++++++++--------- .../timestepping/SimulatorReport.hpp | 34 ++++++++-- 3 files changed, 69 insertions(+), 36 deletions(-) diff --git a/opm/simulators/flow/NonlinearSolverEbos.hpp b/opm/simulators/flow/NonlinearSolverEbos.hpp index 25f10c32698..d702b4da2cb 100644 --- a/opm/simulators/flow/NonlinearSolverEbos.hpp +++ b/opm/simulators/flow/NonlinearSolverEbos.hpp @@ -231,7 +231,12 @@ namespace Opm { std::cout << "Sequantial fullimplicit iteration " << seqiterations << std::endl; seqiterations += 1; } - SimulatorReportSingle report; + SimulatorReportSingle report = reportseq; + report += reportpre; + report.setPressureReport(reportpre); + report.setTransportReport(reportseq); + report.total_newton_iterations = seqiterations; + //TODO add timings of call to implicit residual if(not(converged)){ report.converged = false; }else{ diff --git a/opm/simulators/timestepping/SimulatorReport.cpp b/opm/simulators/timestepping/SimulatorReport.cpp index 9c73a816a2f..fe7a05dc32d 100644 --- a/opm/simulators/timestepping/SimulatorReport.cpp +++ b/opm/simulators/timestepping/SimulatorReport.cpp @@ -29,10 +29,8 @@ namespace Opm { - SimulatorReportSingle::SimulatorReportSingle() - : pressure_time(0.0), - transport_time(0.0), - total_time(0.0), + SimulatorReportSingleBase::SimulatorReportSingleBase() + : total_time(0.0), solver_time(0.0), assemble_time(0.0), linear_solve_setup_time(0.0), @@ -50,10 +48,8 @@ namespace Opm { } - void SimulatorReportSingle::operator+=(const SimulatorReportSingle& sr) + void SimulatorReportSingleBase::operator+=(const SimulatorReportSingleBase& sr) { - pressure_time += sr.pressure_time; - transport_time += sr.transport_time; linear_solve_setup_time += sr.linear_solve_setup_time; linear_solve_time += sr.linear_solve_time; solver_time += sr.solver_time; @@ -69,7 +65,7 @@ namespace Opm } - void SimulatorReportSingle::reportStep(std::ostringstream& ss) const + void SimulatorReportSingleBase::reportStep(std::ostringstream& ss) const { ss << "Time step summary: "; if (total_well_iterations != 0) { @@ -82,7 +78,28 @@ namespace Opm << " (" << std::fixed << std::setprecision(3) << std::setw(6) << linear_solve_time << " sec)"; } - void SimulatorReportSingle::reportFullyImplicit(std::ostream& os, const SimulatorReportSingle* failureReport) const + void SimulatorReportSingleBase::fullReportStep(std::ostream& os) const{ + os.precision(10); + os << std::defaultfloat; + os << std::setw(11) << unit::convert::to(this->global_time, unit::day) << " "; + os << std::setw(11) << unit::convert::to(this->timestep_length, unit::day) << " "; + os.precision(4); + os << std::fixed; + os << std::setw(9) << this->assemble_time << " "; + os << std::setw(9) << this->linear_solve_setup_time << " "; + os << std::setw(9) << this->linear_solve_time << " "; + os << std::setw(9) << this->update_time << " "; + os << std::setw(9) << this->output_write_time << " "; + os.precision(6); + os << std::defaultfloat; + os << std::setw(6) << this->total_well_iterations << " "; + os << std::setw(4) << this->total_linearizations << " "; + os << std::setw(6) << this->total_newton_iterations << " "; + os << std::setw(5) << this->total_linear_iterations << " "; + os << std::setw(4) << this->converged << "\n"; + } + + void SimulatorReportSingleBase::reportFullyImplicit(std::ostream& os, const SimulatorReportSingleBase* failureReport) const { double t = total_time; os << "Total time (seconds): " << t; @@ -188,27 +205,16 @@ namespace Opm void SimulatorReport::fullReports(std::ostream& os) const { - os << " Time(day) TStep(day) Assembly LSolve LSetup Update Output WellIt Lins NewtIt LinIt Conv\n"; + os << " Time(day) TStep(day) Assembly LSolve LSetup Update Output WellIt Lins NewtIt LinIt Conv"; + os << " PreTime(day) PreTStep(day) PreAssembly PreLSolve PreLSetup PreUpdate PreOutput PreWellIt PreLins PreNewtIt PreLinIt PreConv"; + os << " TransTime(day) TransTStep(day) TransAssembly TransLSolve TransLSetup TransUpdate TransOutput TransWellIt TransLins TransNewtIt TransLinIt TransConv\n"; for (size_t i = 0; i < this->stepreports.size(); ++i) { - const SimulatorReportSingle& sr = this->stepreports[i]; - os.precision(10); - os << std::defaultfloat; - os << std::setw(11) << unit::convert::to(sr.global_time, unit::day) << " "; - os << std::setw(11) << unit::convert::to(sr.timestep_length, unit::day) << " "; - os.precision(4); - os << std::fixed; - os << std::setw(9) << sr.assemble_time << " "; - os << std::setw(9) << sr.linear_solve_setup_time << " "; - os << std::setw(9) << sr.linear_solve_time << " "; - os << std::setw(9) << sr.update_time << " "; - os << std::setw(9) << sr.output_write_time << " "; - os.precision(6); - os << std::defaultfloat; - os << std::setw(6) << sr.total_well_iterations << " "; - os << std::setw(4) << sr.total_linearizations << " "; - os << std::setw(6) << sr.total_newton_iterations << " "; - os << std::setw(5) << sr.total_linear_iterations << " "; - os << std::setw(4) << sr.converged << "\n"; + const SimulatorReportSingleBase& sr = this->stepreports[i]; + sr.fullReportStep(os); + const SimulatorReportSingleBase& srpre = this->stepreports[i].pressure_report; + srpre.fullReportStep(os); + const SimulatorReportSingleBase& srtrans = this->stepreports[i].transport_report; + srtrans.fullReportStep(os); } } diff --git a/opm/simulators/timestepping/SimulatorReport.hpp b/opm/simulators/timestepping/SimulatorReport.hpp index 46497558d05..dbf2a63b86b 100644 --- a/opm/simulators/timestepping/SimulatorReport.hpp +++ b/opm/simulators/timestepping/SimulatorReport.hpp @@ -27,10 +27,10 @@ namespace Opm { /// A struct for returning timing data from a simulator to its caller. - struct SimulatorReportSingle + struct SimulatorReportSingleBase { - double pressure_time; - double transport_time; + //double pressure_time; + //double transport_time; double total_time; double solver_time; double assemble_time; @@ -51,15 +51,37 @@ namespace Opm double timestep_length; /// Default constructor initializing all times to 0.0. - SimulatorReportSingle(); + SimulatorReportSingleBase(); /// Increment this report's times by those in sr. - void operator+=(const SimulatorReportSingle& sr); + void operator+=(const SimulatorReportSingleBase& sr); /// Print a report suitable for a single simulation step. void reportStep(std::ostringstream& os) const; /// Print a report suitable for the end of a fully implicit case, leaving out the pressure/transport time. - void reportFullyImplicit(std::ostream& os, const SimulatorReportSingle* failedReport = nullptr) const; + void reportFullyImplicit(std::ostream& os, const SimulatorReportSingleBase* failedReport = nullptr) const; + void fullReportStep(std::ostream& os) const; }; + /// A struct for returning timing data from a simulator to its caller. + struct SimulatorReportSingle: public SimulatorReportSingleBase + { + SimulatorReportSingleBase pressure_report; + SimulatorReportSingleBase transport_report; + void setPressureReport(SimulatorReportSingleBase pressure_report_){ + pressure_report = pressure_report_; + }; + void setTransportReport(SimulatorReportSingleBase transport_report_){ + transport_report = transport_report_; + }; + void operator+=(const SimulatorReportSingle& sr){ + SimulatorReportSingleBase::operator += (sr); + pressure_report += sr.pressure_report; + transport_report += sr.transport_report; + }; + }; + + + + struct SimulatorReport { SimulatorReportSingle success; From 59af41903a9ba2441b7c6959a17bb918ae3c5c58 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Fri, 14 Aug 2020 13:53:10 +0200 Subject: [PATCH 76/93] removing solveWells function in BlackoilWellModel It looks like not used and might be able to do different way with the added inner iteration for StandardWell. --- opm/simulators/flow/NonlinearSolverEbos.hpp | 4 +--- opm/simulators/wells/BlackoilWellModel.hpp | 22 --------------------- 2 files changed, 1 insertion(+), 25 deletions(-) diff --git a/opm/simulators/flow/NonlinearSolverEbos.hpp b/opm/simulators/flow/NonlinearSolverEbos.hpp index d702b4da2cb..71ed697a3fc 100644 --- a/opm/simulators/flow/NonlinearSolverEbos.hpp +++ b/opm/simulators/flow/NonlinearSolverEbos.hpp @@ -185,8 +185,6 @@ namespace Opm { //model_->ebosSimulator().model().advanceTimeLevel(); //model_->ebosSimulator().problem().beginTimeStep(); SimulatorReportSingle lreportseq = this->stepDefault(timer,/*next*/false, false); - // hopefully do not change any thing only update well quantities - //model_->wellModel().solveWells(model_->ebosSimulator().timeStepSize()); reportseq += lreportseq; }catch (...){ //set the prevois value to the staring point @@ -218,7 +216,7 @@ namespace Opm { //NB her only the convergenceshould be checked //SimulatorReportSingle lreportsim = this->stepDefault(timer,/*next*/false, false); std::vector residual_norms; - auto asreport = model_->assembleReservoir(timer, seqiterations); + model_->assembleReservoir(timer, seqiterations); auto convrep = model_->getConvergence(timer, seqiterations,residual_norms); converged = convrep.converged(); // if this used one probably have to invalidate the storage cache diff --git a/opm/simulators/wells/BlackoilWellModel.hpp b/opm/simulators/wells/BlackoilWellModel.hpp index 7a473dcc846..7ebba0529b5 100644 --- a/opm/simulators/wells/BlackoilWellModel.hpp +++ b/opm/simulators/wells/BlackoilWellModel.hpp @@ -162,28 +162,6 @@ namespace Opm { ebosSimulator_.timeStepSize()); } - void solveWells(double dt){ - last_report_ = SimulatorReportSingle(); - if ( ! wellsActive() ) { - return; - } - bool converged; - int exception_thrown = 0; - Opm::DeferredLogger local_deferredLogger; - try{ - updatePerforationIntensiveQuantities(); - std::vector< Scalar > B_avg(numComponents(), Scalar() ); - computeAverageFormationFactor(B_avg); - updatePerforationIntensiveQuantities(); - last_report_ = solveWellEq(B_avg, dt, local_deferredLogger); - } catch (std::exception& e) { - exception_thrown = 1; - } - logAndCheckForExceptionsAndThrow(local_deferredLogger, exception_thrown, "assemble() failed.", terminal_output_); - - last_report_.converged = true; - } - void endIteration() { } From 2a056424e6dcc198b2eb9241173bcbf7f3309c75 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Fri, 14 Aug 2020 16:00:06 +0200 Subject: [PATCH 77/93] cleaing up the well code a little bit removing the things not needed. --- opm/simulators/wells/StandardWell.hpp | 4 +- opm/simulators/wells/StandardWell_impl.hpp | 48 ++++++--------------- opm/simulators/wells/WellInterface.hpp | 6 --- opm/simulators/wells/WellInterface_impl.hpp | 4 -- 4 files changed, 13 insertions(+), 49 deletions(-) diff --git a/opm/simulators/wells/StandardWell.hpp b/opm/simulators/wells/StandardWell.hpp index fe845ed019d..2d68332a313 100644 --- a/opm/simulators/wells/StandardWell.hpp +++ b/opm/simulators/wells/StandardWell.hpp @@ -369,11 +369,10 @@ namespace Opm void computeWellConnectionPressures(const Simulator& ebosSimulator, const WellState& well_state); + // a struct to store all the relevant rates associated with perforations struct PerfRates { // surface perforation rates std::vector cq_s; - // reservoir perforation rates - std::vector cq_r; // reservor perfration total rates EvalWell cq_r_t; @@ -383,7 +382,6 @@ namespace Opm PerfRates(int num_components, int num_welleq) : cq_s(num_components, {num_welleq + numEq, 0.}) - , cq_r(num_components, {num_welleq + numEq, 0.}) , cq_r_t(num_welleq + numEq, 0.) , perf_dis_gas_rate(0.) , perf_vap_oil_rate(0.) diff --git a/opm/simulators/wells/StandardWell_impl.hpp b/opm/simulators/wells/StandardWell_impl.hpp index 6940ae5eb14..153f8af96a3 100644 --- a/opm/simulators/wells/StandardWell_impl.hpp +++ b/opm/simulators/wells/StandardWell_impl.hpp @@ -23,7 +23,6 @@ #include #include #include -// #include namespace Opm { @@ -356,24 +355,14 @@ namespace Opm Opm::DeferredLogger& deferred_logger, const Opm::LinearizationType& linearizationType) const { - // auto cq_s_tmp = perf_rates.cq_s; - if(linearizationType.type == Opm::LinearizationType::seqtransport){ + // for the transport step during sequential running, we use different way to calculate the perforation rates + if (linearizationType.type == Opm::LinearizationType::seqtransport) { perf_rates.cq_r_t = prev_well_state.perfTotalResRates()[first_perf_ + perf]; - computePerfRateSeq(intQuants,mob,/*bhp,Tw,perf,*/allow_cf,perf_rates,deferred_logger); + computePerfRateSeq(intQuants, mob, allow_cf, perf_rates, deferred_logger); return; } - // TODO: the following is some sanity check of the for computePerfRateSeq, while it is not done - // without running the code following until the end of the function - /* if(not(linearizationType.type == Opm::LinearizationType::seqtransport)){ - for(size_t i = 0; i < cq_s_tmp.size(); ++i){ - typedef Opm::MathToolbox Toolbox; - assert(Toolbox::isSame(cq_s_tmp[i],perf_rates.cq_s[i],1e-6)); - } - } */ - auto& cq_s = perf_rates.cq_s; - auto& cq_r = perf_rates.cq_r; auto& cq_r_t = perf_rates.cq_r_t; const auto& fs = intQuants.fluidState(); @@ -414,7 +403,6 @@ namespace Opm for (int componentIdx = 0; componentIdx < num_components_; ++componentIdx) { const EvalWell cq_p = - Tw * (mob[componentIdx] * drawdown); perf_rates.cq_s[componentIdx] = b_perfcells_dense[componentIdx] * cq_p; - perf_rates.cq_r[componentIdx] = cq_p; perf_rates.cq_r_t += cq_p; } @@ -446,13 +434,11 @@ namespace Opm EvalWell total_mob_dense =mob[0]* 0.0; for (int componentIdx = 0; componentIdx < num_components_; ++componentIdx) { total_mob_dense += mob[componentIdx]; - cq_r[componentIdx] = - Tw * (mob[componentIdx] * drawdown); - cq_r_t += cq_r[componentIdx]; } - // TODO: cqt_i should be same with cq_r_t, there is some repeated computation here // injection perforations total volume rates const EvalWell cqt_i = - Tw * (total_mob_dense * drawdown); + cq_r_t = cqt_i; // surface volume fraction of fluids within wellbore std::vector cmix_s(num_components_, EvalWell{numWellEq_ + numEq}); @@ -625,7 +611,7 @@ namespace Opm // better way to do here is that use the cq_s and then replace the cq_s_water here? if (has_polymer && this->has_polymermw && this->isInjector()) { - // TODO: we strictly, we probably should handle cq_r here too + // TODO: strictly, we probably should handle cq_r_t here too if running for sequential handleInjectivityRateAndEquations(intQuants, well_state, perf, perf_rates.cq_s, deferred_logger); } @@ -645,7 +631,6 @@ namespace Opm const EvalWell cq_s_effective = cq_s[componentIdx] * well_efficiency_factor_; connectionRates_[perf][componentIdx] = Base::restrictEval(cq_s_effective); - this->conResRates_[perf][componentIdx] = this->restrictEval(perf_rates.cq_r[componentIdx] * well_efficiency_factor_); // subtract sum of phase fluxes in the well equations. resWell_[0][componentIdx] += cq_s_effective.value(); @@ -668,7 +653,7 @@ namespace Opm well_state.perfPhaseRates()[(first_perf_ + perf) * np + ebosCompIdxToFlowCompIdx(componentIdx)] = cq_s[componentIdx].value(); } } - this->conTotalResRates_[perf] = this->restrictEval(perf_rates.cq_r_t * well_efficiency_factor_); + well_state.perfTotalResRates()[first_perf_ + perf] = perf_rates.cq_r_t.value(); if (has_energy) { @@ -820,6 +805,7 @@ namespace Opm const auto& summaryState = ebosSimulator.vanguard().summaryState(); const Opm::Schedule& schedule = ebosSimulator.vanguard().schedule(); + // during the transport step of sequential running, we have a trivial control eqution to keep bhp fixed if(ebosSimulator.model().linearizer().getLinearizationType().type == Opm::LinearizationType::seqtransport) { assembleControlEqSeqTrans(well_state); } else { @@ -2323,7 +2309,9 @@ namespace Opm Opm::DeferredLogger& deferred_logger) { const LinearizationType& linearizationType = ebosSimulator.model().linearizer().getLinearizationType(); - if(linearizationType.type == Opm::LinearizationType::seqtransport) return; // not updating the explicit quantities + + // not updating the explicit quantities during the transport solve of the sequential solution process + if(linearizationType.type == Opm::LinearizationType::seqtransport) return; updatePrimaryVariables(well_state, deferred_logger); initPrimaryVariablesEvaluation(); @@ -2904,6 +2892,7 @@ namespace Opm LinearizationType linearizationType = ebos_simulator.model().linearizer().getLinearizationType(); const WellState& prev_well_state = ebos_simulator.problem().wellModel().prevWellState(); computePerfRate(int_quant, mob, bhp, prev_well_state, Tw, perf, allow_cf, perf_rates, deferred_logger, linearizationType); + // TODO: make area a member const double area = 2 * M_PI * perf_rep_radius_[perf] * perf_length_[perf]; const auto& material_law_manager = ebos_simulator.problem().materialLawManager(); @@ -3241,15 +3230,11 @@ namespace Opm StandardWell:: computePerfRateSeq(const IntensiveQuantities& intQuants, const std::vector& mob, - //const EvalWell& bhp, - //const double Tw, - //const int perf, const bool allow_cf, PerfRates& perf_rates, Opm::DeferredLogger& deferred_logger) const { auto& cq_s = perf_rates.cq_s; - //const auto& cq_r = perf_rates.cq_r; const auto& cq_r_t = perf_rates.cq_r_t; const auto& fs = intQuants.fluidState(); @@ -3284,7 +3269,7 @@ namespace Opm // compute component volumetric rates at standard conditions for (int componentIdx = 0; componentIdx < num_components_; ++componentIdx) { // do upwinding of total saturation and mobility and totalmobility - const EvalWell cq_p = totalSaturation*mob[componentIdx]/mobt * cq_r_t; + const EvalWell cq_p = totalSaturation * mob[componentIdx] / mobt * cq_r_t; perf_rates.cq_s[componentIdx] = b_perfcells_dense[componentIdx] * cq_p; } @@ -3312,15 +3297,6 @@ namespace Opm return; } - // // Using total mobilities - // EvalWell total_mob_dense = - // for (int componentIdx = 0; componentIdx < num_components_; ++componentIdx) { - // total_mob_dense += mob[componentIdx]; - // cq_r[componentIdx] = - Tw * (mob[componentIdx] * drawdown); - // cq_r_t += cq_r[componentIdx]; - // } - - // TODO: cqt_i should be same with cq_r_t, there is some repeated computation here // injection perforations total volume rates const EvalWell cqt_i = cq_r_t; diff --git a/opm/simulators/wells/WellInterface.hpp b/opm/simulators/wells/WellInterface.hpp index e7643ae7550..308c052873a 100644 --- a/opm/simulators/wells/WellInterface.hpp +++ b/opm/simulators/wells/WellInterface.hpp @@ -374,12 +374,6 @@ namespace Opm std::vector connectionRates_; - // rates under reservoir condtion for each phase/component? - // RateVector is based on Dune::FieldVector - std::vector conResRates_; - - std::vector conTotalResRates_; - bool wellIsStopped_; double wsolvent_; diff --git a/opm/simulators/wells/WellInterface_impl.hpp b/opm/simulators/wells/WellInterface_impl.hpp index b351644441e..42db8a60def 100644 --- a/opm/simulators/wells/WellInterface_impl.hpp +++ b/opm/simulators/wells/WellInterface_impl.hpp @@ -90,10 +90,6 @@ namespace Opm connectionRates_.resize(number_of_perforations_); - conResRates_.resize(number_of_perforations_); - - conTotalResRates_.resize(number_of_perforations_); - well_productivity_index_logger_counter_ = 0; wellIsStopped_ = false; From fc7eead9a8c424109efdf357106c78c97c353018 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Fri, 14 Aug 2020 22:27:32 +0200 Subject: [PATCH 78/93] eclblackoilprimaryvariables adapts the changes in blackoilprimaryvariables.hh. Preparing for refactoring. --- ebos/eclblackoilprimaryvariables.hh | 87 +++++++++++++++-------------- 1 file changed, 44 insertions(+), 43 deletions(-) diff --git a/ebos/eclblackoilprimaryvariables.hh b/ebos/eclblackoilprimaryvariables.hh index ab45e0cf05e..8d2faa29285 100644 --- a/ebos/eclblackoilprimaryvariables.hh +++ b/ebos/eclblackoilprimaryvariables.hh @@ -38,19 +38,19 @@ namespace Opm{ template class EclBlackOilPrimaryVariables : public FvBasePrimaryVariables { - typedef FvBasePrimaryVariables ParentType; - typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) Implementation; + using ParentType = FvBasePrimaryVariables; + using Implementation = GetPropType; - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, Evaluation) Evaluation; - typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; - typedef typename GET_PROP_TYPE(TypeTag, Problem) Problem; - typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; - typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw; - typedef typename GET_PROP_TYPE(TypeTag, MaterialLawParams) MaterialLawParams; + using Scalar = GetPropType; + using Evaluation = GetPropType; + using Indices = GetPropType; + using Problem = GetPropType; + using FluidSystem = GetPropType; + using MaterialLaw = GetPropType; + using MaterialLawParams = GetPropType; // number of equations - enum { numEq = GET_PROP_VALUE(TypeTag, NumEq) }; + enum { numEq = getPropValue() }; // primary variable indices enum { waterSaturationIdx = Indices::waterSaturationIdx }; @@ -67,23 +67,23 @@ class EclBlackOilPrimaryVariables : public FvBasePrimaryVariables enum { oilPhaseIdx = FluidSystem::oilPhaseIdx }; // component indices from the fluid system - enum { numComponents = GET_PROP_VALUE(TypeTag, NumComponents) }; - enum { enableSolvent = GET_PROP_VALUE(TypeTag, EnableSolvent) }; - enum { enablePolymer = GET_PROP_VALUE(TypeTag, EnablePolymer) }; - enum { enableFoam = GET_PROP_VALUE(TypeTag, EnableFoam) }; - enum { enableBrine = GET_PROP_VALUE(TypeTag, EnableBrine) }; - enum { enableEnergy = GET_PROP_VALUE(TypeTag, EnableEnergy) }; + enum { numComponents = getPropValue() }; + enum { enableSolvent = getPropValue() }; + enum { enablePolymer = getPropValue() }; + enum { enableFoam = getPropValue() }; + enum { enableBrine = getPropValue() }; + enum { enableEnergy = getPropValue() }; enum { gasCompIdx = FluidSystem::gasCompIdx }; enum { waterCompIdx = FluidSystem::waterCompIdx }; enum { oilCompIdx = FluidSystem::oilCompIdx }; - typedef typename Opm::MathToolbox Toolbox; - typedef Dune::FieldVector ComponentVector; - typedef BlackOilSolventModule SolventModule; - typedef BlackOilPolymerModule PolymerModule; - typedef BlackOilEnergyModule EnergyModule; - typedef BlackOilFoamModule FoamModule; - typedef BlackOilBrineModule BrineModule; + using Toolbox = typename Opm::MathToolbox; + using ComponentVector = Dune::FieldVector; + using SolventModule = BlackOilSolventModule; + using PolymerModule = BlackOilPolymerModule; + using EnergyModule = BlackOilEnergyModule; + using FoamModule = BlackOilFoamModule; + using BrineModule = BlackOilBrineModule; static_assert(numPhases == 3, "The black-oil model assumes three phases!"); static_assert(numComponents == 3, "The black-oil model assumes three components!"); @@ -172,9 +172,10 @@ public: const MaterialLawParams& matParams, bool isInEquilibrium = false) { - typedef typename std::remove_reference::type ConstEvaluation; - typedef typename std::remove_const::type FsEvaluation; - typedef typename Opm::MathToolbox FsToolbox; + using ConstEvaluation = typename std::remove_reference::type; + using FsEvaluation = typename std::remove_const::type; + using FsToolbox = typename Opm::MathToolbox; + #ifndef NDEBUG // make sure the temperature is the same in all fluid phases for (unsigned phaseIdx = 1; phaseIdx < numPhases; ++phaseIdx) { @@ -199,8 +200,8 @@ public: paramCache.setMaxOilSat(FsToolbox::value(fluidState.saturation(oilPhaseIdx))); // create a mutable fluid state with well defined densities based on the input - typedef Opm::NcpFlash NcpFlash; - typedef Opm::CompositionalFluidState FlashFluidState; + using NcpFlash = Opm::NcpFlash; + using FlashFluidState = Opm::CompositionalFluidState; FlashFluidState fsFlash; fsFlash.setTemperature(FsToolbox::value(fluidState.temperature(/*phaseIdx=*/0))); for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { @@ -247,9 +248,9 @@ public: template void assignNaive(const FluidState& fluidState) { - typedef typename std::remove_reference::type ConstEvaluation; - typedef typename std::remove_const::type FsEvaluation; - typedef typename Opm::MathToolbox FsToolbox; + using ConstEvaluation = typename std::remove_reference::type; + using FsEvaluation = typename std::remove_const::type; + using FsToolbox = typename Opm::MathToolbox; bool gasPresent = FluidSystem::phaseIsActive(gasPhaseIdx)?(fluidState.saturation(gasPhaseIdx) > 0.0):false; bool oilPresent = FluidSystem::phaseIsActive(oilPhaseIdx)?(fluidState.saturation(oilPhaseIdx) > 0.0):false; @@ -780,18 +781,18 @@ private: Scalar Sw, const MaterialLawParams& matParams) const { - typedef Opm::SimpleModularFluidState SatOnlyFluidState; + using SatOnlyFluidState = Opm::SimpleModularFluidState; SatOnlyFluidState fluidState; fluidState.setSaturation(waterPhaseIdx, Sw); fluidState.setSaturation(oilPhaseIdx, So); From f1f4b85abad5532def28f9e347c867b7b8599e20 Mon Sep 17 00:00:00 2001 From: hnil Date: Mon, 17 Aug 2020 23:07:04 +0200 Subject: [PATCH 79/93] restructuring to prepare for iterative --- ebos/eclblackoilintensivequantities.hh | 11 +++-- ebos/eclproblem.hh | 43 ++++++++++++---- opm/simulators/flow/FlowMainEbos.hpp | 3 +- opm/simulators/flow/NonlinearSolverEbos.hpp | 54 ++++++++------------- 4 files changed, 63 insertions(+), 48 deletions(-) diff --git a/ebos/eclblackoilintensivequantities.hh b/ebos/eclblackoilintensivequantities.hh index f26c8366c61..6b9640ce313 100644 --- a/ebos/eclblackoilintensivequantities.hh +++ b/ebos/eclblackoilintensivequantities.hh @@ -220,14 +220,19 @@ public: //assert(totalSaturation<2);// debug to be sure no pressure is pressent //assert(timeIdx==0 || totalSaturation == 1);// for pure sequential with multiple steps this is always true. if(timeIdx == 1){ - totalSaturation = elemCtx.problem().totalSaturation(globalSpaceIdx); + totalSaturation = elemCtx.problem().totalSaturation(globalSpaceIdx,timeIdx); } - }else if (linearizationType.type == Opm::LinearizationType::pressure) { + }else if (linearizationType.type == Opm::LinearizationType::pressure || + linearizationType.type == Opm::LinearizationType::implicit + ) { + totalSaturation = 1.0;//fornew step // we are doing sequation pressure where totalSaturation may not be 1 any more if(timeIdx == 1){//pressure solves try to make new value i.e. timeIdx==0 so that totalSaturation==1; - totalSaturation = elemCtx.problem().totalSaturation(globalSpaceIdx); + totalSaturation = elemCtx.problem().totalSaturation(globalSpaceIdx,timeIdx); } + }else{ + assert(false); } fluidState_.setTotalSaturation(totalSaturation); if (priVars.primaryVarsMeaning() == PrimaryVariables::Sw_pg_Rv) { diff --git a/ebos/eclproblem.hh b/ebos/eclproblem.hh index 63c32fcfc1b..db95f7bc5bf 100644 --- a/ebos/eclproblem.hh +++ b/ebos/eclproblem.hh @@ -740,6 +740,9 @@ public: simulator.startNextEpisode(timeMap.getTimeStepLength(0)); simulator.setEpisodeIndex(0); } + //this->updatePressure_(/*timeIdx*/ 0); + //this->updatePressure_(/*timeIdx*/ 1); + } void prefetch(const Element& elem) const @@ -1996,17 +1999,36 @@ public: * \brief update pressure and totalSaturation * update copy of pressure and total saturation for sequential solve */ + bool updateAllPressures(){ + this->updatePressure_(0); + this->updatePressure_(1); + } + bool updatePressureAndFluxes(){ // maybe use simulation type instead std::string simulationtype = EWOMS_GET_PARAM(TypeTag, std::string, SimulationType); bool updated = false; if(not(simulationtype == "implicit")){ - this->updatePressure_(); + this->updatePressure_(/*timeIdx*/ 0); this->updateFluxes_(); updated = true; } return updated; } + void syncPressureForward(){ + pressure_[1] = pressure_[0]; + } + void syncPressureBackward(){ + pressure_[0] = pressure_[1]; + } + + void syncTotalSaturationForward(){ + totalSaturation_[1] = totalSaturation_[0]; + } + void syncTotalSaturationBackward(){ + totalSaturation_[0] = totalSaturation_[1]; + } + bool updateTotalSaturation(){ std::string simulationtype = EWOMS_GET_PARAM(TypeTag, std::string, SimulationType); // maybe use simulation type instead @@ -2278,8 +2300,8 @@ private: return true; } - - bool updatePressure_() + + bool updatePressure_(unsigned timeIdx) { ElementContext elemCtx(this->simulator()); const auto& vanguard = this->simulator().vanguard(); @@ -2289,20 +2311,17 @@ private: const Element& elem = *elemIt; elemCtx.updatePrimaryStencil(elem); - elemCtx.updatePrimaryIntensiveQuantities(/*timeIdx=*/0); + elemCtx.updatePrimaryIntensiveQuantities(timeIdx); - unsigned compressedDofIdx = elemCtx.globalSpaceIndex(/*spaceIdx=*/0, /*timeIdx=*/0); - const auto& iq = elemCtx.intensiveQuantities(/*spaceIdx=*/0, /*timeIdx=*/0); + unsigned compressedDofIdx = elemCtx.globalSpaceIndex(/*spaceIdx=*/0, timeIdx); + const auto& iq = elemCtx.intensiveQuantities(/*spaceIdx=*/0, timeIdx); const auto& fs = iq.fluidState(); if (FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)) { - pressure_[1][compressedDofIdx][oilPhaseIdx] = pressure_[0][compressedDofIdx][oilPhaseIdx]; pressure_[0][compressedDofIdx][oilPhaseIdx] = Opm::getValue(fs.pressure(oilPhaseIdx)); }else if( FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)) { - pressure_[1][compressedDofIdx][gasPhaseIdx] = pressure_[0][compressedDofIdx][gasPhaseIdx]; pressure_[0][compressedDofIdx][gasPhaseIdx] = Opm::getValue(fs.pressure(gasPhaseIdx)); }else{ - pressure_[1][compressedDofIdx][waterPhaseIdx] = pressure_[0][compressedDofIdx][waterPhaseIdx]; pressure_[0][compressedDofIdx][waterPhaseIdx] = Opm::getValue(fs.pressure(waterPhaseIdx)); } } @@ -2312,6 +2331,10 @@ private: bool updateTotalSaturation_() { +#ifndef NDEBUG + Opm::LinearizationType linearizationType = this->simulator().model().linearizer().getLinearizationType(); + assert(linearizationType.type == Opm::LinearizationType::seqtransport); +#endif ElementContext elemCtx(this->simulator()); const auto& vanguard = this->simulator().vanguard(); auto elemIt = vanguard.gridView().template begin(); @@ -2688,7 +2711,7 @@ private: int elemIdx = elemCtx.globalSpaceIndex(/*spaceIdx=*/0, /*timeIdx=*/0); initial(sol[elemIdx], elemCtx, /*spaceIdx=*/0, /*timeIdx=*/0); } - + this->updateAllPressures(); // make sure that the ghost and overlap entities exhibit the correct // solution. alternatively, this could be done in the loop above by also // considering non-interior elements. Since the initial() method might not work diff --git a/opm/simulators/flow/FlowMainEbos.hpp b/opm/simulators/flow/FlowMainEbos.hpp index b2d713873c8..c81fd3038e1 100644 --- a/opm/simulators/flow/FlowMainEbos.hpp +++ b/opm/simulators/flow/FlowMainEbos.hpp @@ -450,7 +450,8 @@ namespace Opm ebosSimulator_.reset(new EbosSimulator(/*verbose=*/false)); ebosSimulator_->executionTimer().start(); ebosSimulator_->model().applyInitialSolution(); - + // this should be moved to primary variables + ebosSimulator_->problem().updateAllPressures(); try { // Possible to force initialization only behavior (NOSIM). const std::string& dryRunString = EWOMS_GET_PARAM(TypeTag, std::string, EnableDryRun); diff --git a/opm/simulators/flow/NonlinearSolverEbos.hpp b/opm/simulators/flow/NonlinearSolverEbos.hpp index 71ed697a3fc..52769213c50 100644 --- a/opm/simulators/flow/NonlinearSolverEbos.hpp +++ b/opm/simulators/flow/NonlinearSolverEbos.hpp @@ -154,17 +154,19 @@ namespace Opm { SimulatorReportSingle reportseq; int seqiterations = 0; int maxseqiterations = 10; - // should probalby store for trying onse more + // sett the seq variable to be equal at beginning auto solutionOld = model_->ebosSimulator().model().solution(/*timeIdx=*/0); - auto oldTotalSaturation = model_->ebosSimulator().problem().getTotalSaturation(); + //auto oldTotalSaturation = model_->ebosSimulator().problem().getTotalSaturation(/*timeIdx*/0); + //model_->ebosSimulator().problem().setTotalSaturation(oldTotalSaturation,/*timeidx*/1); + model_->ebosSimulator().problem().syncPressureForward(); + model_->ebosSimulator().problem().syncTotalSaturationForward(); bool first= true; while(not(converged) && (seqiterations < maxseqiterations) ){ + // Always guess that nest step will give one in total saturation + model_->ebosSimulator().problem().totalSaturationOne(/*timeidx*/0); // do pressure step if(seqiterations>0){ - auto& prevsol = model_->ebosSimulator().model().solution(/*timeIdx=*/1); model_->ebosSimulator().model().invalidateIntensiveQuantitiesCache(/*timeIdx=*/1); - //NB is the storag cach allso invalidated?? - prevsol=solutionOld; } linearizationType.type = Opm::LinearizationType::pressure; model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); @@ -172,18 +174,15 @@ namespace Opm { SimulatorReportSingle lreportpre = this->stepDefault(timer, /*next*/first, false); first=false; // do transport step - model_->ebosSimulator().problem().wellModel().endTimeStep();// shouldupdate previous state NB do wee need to store it if transportstep fails? - model_->ebosSimulator().problem().updatePressureAndFluxes();//update pressure ans ST + // shouldupdate previous state NB do wee need to store it if transportstep fails? + model_->ebosSimulator().problem().wellModel().endTimeStep(); + //update pressure[0] and fluxes + model_->ebosSimulator().problem().updatePressureAndFluxes(); linearizationType.type = Opm::LinearizationType::seqtransport; model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); - // initial guess for transport use the old state - //auto& currsol = model_->ebosSimulator().model().solution(/*timeIdx=*/0); - //currsol = solutionOld; model_->updateSolution(); reportpre += lreportpre; try{ - //model_->ebosSimulator().model().advanceTimeLevel(); - //model_->ebosSimulator().problem().beginTimeStep(); SimulatorReportSingle lreportseq = this->stepDefault(timer,/*next*/false, false); reportseq += lreportseq; }catch (...){ @@ -192,36 +191,25 @@ namespace Opm { prevsol = solutionOld; auto& currsol = model_->ebosSimulator().model().solution(/*timeIdx=*/0); currsol = solutionOld; - // set back totalSaturation pressure and fluxes - model_->ebosSimulator().problem().setTotalSaturation(oldTotalSaturation); - // total pressure fluxes should be updated in the pressure solve anyway - + // set back the + // the sequantial variables should not be needed to put back + //model_->ebosSimulator().problem().setTotalSaturation(oldTotalSaturation,0); + //model_->ebosSimulator().problem().setTotalSaturation(oldTotalSaturation,1); + model_->ebosSimulator().problem().syncPressureBackward(); + model_->ebosSimulator().problem().syncTotalSaturationBackward(); throw; } - + model_->ebosSimulator().problem().updateTotalSaturation(); // for no not seq implicit if(implicit){ - // for now do full implicit solve - //NB storagecache need to be invalidated - //bool storagecache = EWOMS_GET_PARAM(TypeTag, bool, EnableStorageCache); - model_->ebosSimulator().model().setEnableStorageCache(false); - auto& prevsol = model_->ebosSimulator().model().solution(/*timeIdx=*/1); - prevsol=solutionOld; - model_->ebosSimulator().model().invalidateIntensiveQuantitiesCache(/*timeIdx=*/1); - model_->ebosSimulator().model().invalidateIntensiveQuantitiesCache(/*timeIdx=*/0); + //NB need to be carefull with storage cache linearizationType.type = Opm::LinearizationType::implicit; model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); - model_->updateSolution(); - - //NB her only the convergenceshould be checked - //SimulatorReportSingle lreportsim = this->stepDefault(timer,/*next*/false, false); + model_->updateSolution(); std::vector residual_norms; model_->assembleReservoir(timer, seqiterations); auto convrep = model_->getConvergence(timer, seqiterations,residual_norms); converged = convrep.converged(); - // if this used one probably have to invalidate the storage cache - //model_->ebosSimulator().model().setEnableStorageCache(storagecache); - model_->ebosSimulator().problem().totalSaturationOne(); }else{ converged = true; } @@ -239,7 +227,6 @@ namespace Opm { report.converged = false; }else{ // model_->updateSolution(); - model_->ebosSimulator().problem().updateTotalSaturation(); model_->afterStep(timer); // NOTE: updating solution again for information used in the relativeChange function. linearizationType.type = Opm::LinearizationType::pressure; @@ -247,7 +234,6 @@ namespace Opm { model_->updateSolution(); report.converged = true; } - //todo fill this report correctly return report; } From ce76599dd2577a8a1bdfc3f94577c6c68aeab7d0 Mon Sep 17 00:00:00 2001 From: hnil Date: Mon, 17 Aug 2020 23:49:58 +0200 Subject: [PATCH 80/93] removed default argument for timeidx, fixed bug for refactored code --- ebos/eclblackoilprimaryvariables.hh | 16 ++++++++-------- ebos/eclproblem.hh | 17 +++++++++-------- opm/simulators/flow/BlackoilModelEbos.hpp | 10 +++++----- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/ebos/eclblackoilprimaryvariables.hh b/ebos/eclblackoilprimaryvariables.hh index 8d2faa29285..d6a663fa67f 100644 --- a/ebos/eclblackoilprimaryvariables.hh +++ b/ebos/eclblackoilprimaryvariables.hh @@ -364,14 +364,14 @@ public: if(simulationType_ == SimulationType::Implicit){ pressure = (*this)[Indices::pressureSwitchIdx]; - totalsaturation = problem.totalSaturation(globalDofIdx); + totalsaturation = problem.totalSaturation(globalDofIdx,/*timeidx*/ 0);//NB hack }else if (simulationType_ == SimulationType::Seq){ if(primaryVarsMeaning() == Sw_po_Sg){ - pressure = problem.pressure(globalDofIdx, oilPhaseIdx); + pressure = problem.pressure(globalDofIdx, oilPhaseIdx,/*timeidx*/ 0);//NB hack }else if(primaryVarsMeaning() == Sw_po_Rs){ - pressure = problem.pressure(globalDofIdx, oilPhaseIdx); + pressure = problem.pressure(globalDofIdx, oilPhaseIdx,/*timeidx*/ 0);//NB hack }else if(primaryVarsMeaning() == Sw_pg_Rv){ - pressure = problem.pressure(globalDofIdx, gasPhaseIdx); + pressure = problem.pressure(globalDofIdx, gasPhaseIdx,/*timeidx*/ 0);//NB hack }else{ assert(false); } @@ -430,7 +430,7 @@ public: po = (*this)[Indices::pressureSwitchIdx]; assert(po>2.0); }else{ - po = problem.pressure(globalDofIdx, oilPhaseIdx); + po = problem.pressure(globalDofIdx, oilPhaseIdx,/*timeidx*/ 0); } Scalar T = asImp_().temperature_(); Scalar SoMax = problem.maxOilSaturation(globalDofIdx); @@ -457,7 +457,7 @@ public: po = (*this)[Indices::pressureSwitchIdx]; assert(po>2.0); }else{ - po = problem.pressure(globalDofIdx, oilPhaseIdx); + po = problem.pressure(globalDofIdx, oilPhaseIdx,/*timeidx*/ 0); } // we only have the oil pressure readily available, but we need the gas // pressure, i.e. we must determine capillary pressure @@ -514,7 +514,7 @@ public: po = (*this)[Indices::pressureSwitchIdx]; assert(po>2.0); } else { - po = problem.pressure(globalDofIdx, oilPhaseIdx); + po = problem.pressure(globalDofIdx, oilPhaseIdx,/*timeidx*/ 0); } Scalar So = 1.0 - Sw - solventSaturation_(); Scalar SoMax = std::max(So, problem.maxOilSaturation(globalDofIdx)); @@ -548,7 +548,7 @@ public: pg = (*this)[Indices::pressureSwitchIdx]; assert(pg>2.0); } else { - pg = problem.pressure(globalDofIdx, gasPhaseIdx); + pg = problem.pressure(globalDofIdx, gasPhaseIdx,/*timeidx*/ 0); } Scalar Sg = 1.0 - Sw - solventSaturation_(); diff --git a/ebos/eclproblem.hh b/ebos/eclproblem.hh index db95f7bc5bf..9e26f2f0e80 100644 --- a/ebos/eclproblem.hh +++ b/ebos/eclproblem.hh @@ -1816,27 +1816,27 @@ public: * of the timestep need for sequential * */ - Scalar pressure(unsigned globalDofIdx, unsigned phaseIndex, const unsigned timeIdx = 0) const + Scalar pressure(unsigned globalDofIdx, unsigned phaseIndex, const unsigned timeIdx) const { // phase index is unused for now will give warning in compilation return pressure_[timeIdx][globalDofIdx][phaseIndex]; } - Scalar totalSaturation(unsigned globalDofIdx, const unsigned timeIdx = 0) const + Scalar totalSaturation(unsigned globalDofIdx, const unsigned timeIdx) const { return totalSaturation_[timeIdx][globalDofIdx]; } - const std::vector& getTotalSaturation(const unsigned timeIdx = 0) const + const std::vector& getTotalSaturation(const unsigned timeIdx) const { return totalSaturation_[timeIdx]; } - void setTotalSaturation(std::vector totSat, const unsigned timeIdx = 0) + void setTotalSaturation(std::vector totSat, const unsigned timeIdx) { totalSaturation_[timeIdx] = totSat; } - void totalSaturationOne(const unsigned timeIdx = 0){ + void totalSaturationOne(const unsigned timeIdx){ for(auto& v : totalSaturation_[timeIdx]){ v=1.0; } @@ -2002,6 +2002,7 @@ public: bool updateAllPressures(){ this->updatePressure_(0); this->updatePressure_(1); + return true; } bool updatePressureAndFluxes(){ @@ -2318,11 +2319,11 @@ private: const auto& fs = iq.fluidState(); if (FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx)) { - pressure_[0][compressedDofIdx][oilPhaseIdx] = Opm::getValue(fs.pressure(oilPhaseIdx)); + pressure_[timeIdx][compressedDofIdx][oilPhaseIdx] = Opm::getValue(fs.pressure(oilPhaseIdx)); }else if( FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx)) { - pressure_[0][compressedDofIdx][gasPhaseIdx] = Opm::getValue(fs.pressure(gasPhaseIdx)); + pressure_[timeIdx][compressedDofIdx][gasPhaseIdx] = Opm::getValue(fs.pressure(gasPhaseIdx)); }else{ - pressure_[0][compressedDofIdx][waterPhaseIdx] = Opm::getValue(fs.pressure(waterPhaseIdx)); + pressure_[timeIdx][compressedDofIdx][waterPhaseIdx] = Opm::getValue(fs.pressure(waterPhaseIdx)); } } diff --git a/opm/simulators/flow/BlackoilModelEbos.hpp b/opm/simulators/flow/BlackoilModelEbos.hpp index 1c4f51d9f88..796112d7584 100644 --- a/opm/simulators/flow/BlackoilModelEbos.hpp +++ b/opm/simulators/flow/BlackoilModelEbos.hpp @@ -591,8 +591,8 @@ namespace Opm { void updateSolution(){ unsigned numDof = ebosSimulator_.model().numGridDof(); BVector dx(numDof,0); - this->updateSolution(dx, 0); - this->updateSolution(dx, 1); + this->updateSolution(dx); + //this->updateSolution(dx, 1);// can not be done // for(unsigned timeidx; timeidx< 2; ++timidx){ // SolutionVector& sol = model().solution(/*historyIdx=*/timeidx); // size_t numGridDof = ebosSimulator_.model().numGridDof(); @@ -606,10 +606,10 @@ namespace Opm { } /// Apply an update to the primary variables. - void updateSolution(const BVector& dx, const int timeIdx = 0) + void updateSolution(const BVector& dx) { auto& ebosNewtonMethod = ebosSimulator_.model().newtonMethod(); - SolutionVector& solution = ebosSimulator_.model().solution(timeIdx); + SolutionVector& solution = ebosSimulator_.model().solution(/*timeIdx*/ 0); ebosNewtonMethod.update_(/*nextSolution=*/solution, /*curSolution=*/solution, @@ -619,7 +619,7 @@ namespace Opm { // residual // if the solution is updated, the intensive quantities need to be recalculated - ebosSimulator_.model().invalidateIntensiveQuantitiesCache(timeIdx); + ebosSimulator_.model().invalidateIntensiveQuantitiesCache(/*timeIdx*/ 0); } /// Return true if output to cout is wanted. From 7f5c38ad15c63d0909e7acd4e62b8120fe7ab41c Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Tue, 18 Aug 2020 23:40:24 +0200 Subject: [PATCH 81/93] trying to output unconverged well residuals it needs more adjustment. --- opm/simulators/wells/StandardWell_impl.hpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/opm/simulators/wells/StandardWell_impl.hpp b/opm/simulators/wells/StandardWell_impl.hpp index 153f8af96a3..062414ed615 100644 --- a/opm/simulators/wells/StandardWell_impl.hpp +++ b/opm/simulators/wells/StandardWell_impl.hpp @@ -24,6 +24,8 @@ #include #include +#include + namespace Opm { @@ -2220,6 +2222,16 @@ namespace Opm checkConvergenceExtraEqs(res, report); + if ( !report.converged() ) { + std::stringstream ss; + ss << "UNCONVERGED WELL: " << name() << " residual "; + for ( int compIdx = 0; compIdx < num_components_; ++compIdx ) { + ss << std::setw(12) << well_flux_residual[compIdx]; + } + ss << std::setw(15) << res[this->numWellEq_ - 1]; + deferred_logger.info(ss.str()); + } + return report; } From 444e26de91423ff614c8d15795a4905352043785 Mon Sep 17 00:00:00 2001 From: hnil Date: Tue, 18 Aug 2020 09:10:36 +0200 Subject: [PATCH 82/93] Better logging --- opm/simulators/flow/NonlinearSolverEbos.hpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/opm/simulators/flow/NonlinearSolverEbos.hpp b/opm/simulators/flow/NonlinearSolverEbos.hpp index 52769213c50..f43182e8344 100644 --- a/opm/simulators/flow/NonlinearSolverEbos.hpp +++ b/opm/simulators/flow/NonlinearSolverEbos.hpp @@ -203,6 +203,7 @@ namespace Opm { // for no not seq implicit if(implicit){ //NB need to be carefull with storage cache + OpmLog::info("Error for sequential implicit:"); linearizationType.type = Opm::LinearizationType::implicit; model_->ebosSimulator().model().linearizer().setLinearizationType(linearizationType); model_->updateSolution(); @@ -213,8 +214,9 @@ namespace Opm { }else{ converged = true; } - - std::cout << "Sequantial fullimplicit iteration " << seqiterations << std::endl; + std::ostringstream ss; + ss << "Sequantial fullimplicit iteration " << seqiterations << std::endl; + OpmLog::info(ss.str()); seqiterations += 1; } SimulatorReportSingle report = reportseq; From 8c5524ea1a0fc3495b3ad1a38ed244993fb6f689 Mon Sep 17 00:00:00 2001 From: hnil Date: Tue, 18 Aug 2020 15:28:51 +0200 Subject: [PATCH 83/93] added parameters and refactored use of pressure linear solver --- opm/simulators/flow/BlackoilModelEbos.hpp | 92 ++++++++++++------- .../flow/BlackoilModelParametersEbos.hpp | 35 +++++++ opm/simulators/flow/NonlinearSolverEbos.hpp | 26 +++++- 3 files changed, 114 insertions(+), 39 deletions(-) diff --git a/opm/simulators/flow/BlackoilModelEbos.hpp b/opm/simulators/flow/BlackoilModelEbos.hpp index 796112d7584..62392cd8064 100644 --- a/opm/simulators/flow/BlackoilModelEbos.hpp +++ b/opm/simulators/flow/BlackoilModelEbos.hpp @@ -479,31 +479,13 @@ namespace Opm { return ebosSimulator_.model().newtonMethod().linearSolver().iterations (); } - /// Solve the Jacobian system Jx = r where J is the Jacobian and - /// r is the residual. - void solveJacobianSystem(BVector& x) - { - if(ebosSimulator_.model().linearizer().getLinearizationType().type == Opm::LinearizationType::pressure){ - auto& ebosJac = ebosSimulator_.model().linearizer().jacobian(); - auto& ebosResid = ebosSimulator_.model().linearizer().residual(); - // NB when tested the linear solver an the martrix could be part of linearizer - using PressureMatrixType = Dune::BCRSMatrix< Dune::FieldMatrix>; - using PressureVectorType = Dune::BlockVector>; - int pressureVarIndex=1; - // true impes case could add case with trivial weighs i equations is modifind with weights - // this would make a newton based method if derivative of the weights are takein into account - BVector weights = this->getPressureWeights(pressureVarIndex); - PressureMatrixType pmatrix = - PressureHelper::makePressureMatrix( - ebosJac.istlMatrix(), - pressureVarIndex, - weights); - PressureVectorType rhs(ebosResid.size(),0); - PressureHelper::moveToPressureEqn(ebosResid, rhs, weights); - boost::property_tree::ptree prm; + std::unique_ptr< + Dune::FlexibleSolver< Dune::BCRSMatrix< Dune::FieldMatrix>, + Dune::BlockVector> + > + > + makePressureSolver(Dune::BCRSMatrix< Dune::FieldMatrix>& pmatrix) { + boost::property_tree::ptree prm; if (std::filesystem::exists("pressuresolver.json") ) { try{ boost::property_tree::read_json("pressuresolver.json", prm); @@ -519,6 +501,8 @@ namespace Opm { "}"; boost::property_tree::read_json(ss, prm); } + using PressureMatrixType = Dune::BCRSMatrix< Dune::FieldMatrix>; + using PressureVectorType = Dune::BlockVector>; std::any parallelInformation; extractParallelGridInformationToISTL(ebosSimulator_.vanguard().grid(), parallelInformation); using AbstractOperatorType = Dune::AssembledLinearOperator; @@ -553,16 +537,51 @@ namespace Opm { operator_for_flexiblesolver = std::make_unique(pmatrix); pressureSolver = std::make_unique(*operator_for_flexiblesolver, prm, weightsCalculator); } + return pressureSolver; + } + + /// Solve the Jacobian system Jx = r where J is the Jacobian and + /// r is the residual. + void solveJacobianSystem(BVector& x) + { + if(ebosSimulator_.model().linearizer().getLinearizationType().type == Opm::LinearizationType::pressure){ + auto& ebosJac = ebosSimulator_.model().linearizer().jacobian(); + auto& ebosResid = ebosSimulator_.model().linearizer().residual(); + // NB when tested the linear solver an the martrix could be part of linearizer + using PressureMatrixType = Dune::BCRSMatrix< Dune::FieldMatrix>; + using PressureVectorType = Dune::BlockVector>; + int pressureVarIndex=1; + // true impes case could add case with trivial weighs i equations is modifind with weights + // this would make a newton based method if derivative of the weights are takein into account + BVector weights = this->getPressureWeights(pressureVarIndex); + PressureMatrixType pmatrix = + PressureHelper::makePressureMatrix( + ebosJac.istlMatrix(), + pressureVarIndex, + weights); + PressureVectorType rhs(ebosResid.size(),0); + PressureHelper::moveToPressureEqn(ebosResid, rhs, weights); + + using PressureSolverType = Dune::FlexibleSolver; + std::unique_ptr pressureSolver = makePressureSolver(pmatrix); PressureVectorType xp(x.size(),0); Dune::InverseOperatorResult res; pressureSolver->apply(xp,rhs, res); - Opm::Helper::writeSystem(this->ebosSimulator_, //simulator is only used to get names - pmatrix, - rhs, - comm.get(), - std::string("pressure_") - ); + /* + bool write_pressure_system = false; + if(write_pressure_system){ + Opm::Helper::writeSystem(this->ebosSimulator_, //simulator is only used to get names + pmatrix, + rhs, + comm.get(), + std::string("pressure_") + ); + } + */ x=0; PressureHelper::movePressureToBlock(x, xp, pressureVarIndex); // set initial guess @@ -792,7 +811,12 @@ namespace Opm { typedef std::vector< Scalar > Vector; const double tol_mb = param_.tolerance_mb_; - const double tol_cnv = (iteration < param_.max_strict_iter_) ? param_.tolerance_cnv_ : param_.tolerance_cnv_relaxed_; + double tol_cnv; + if(ebosSimulator_.model().linearizer().getLinearizationType().type == Opm::LinearizationType::seqtransport){ + tol_cnv = (iteration < param_.max_strict_iter_seq_) ? param_.tolerance_cnv_seq_ : param_.tolerance_cnv_relaxed_seq_; + }else{ + tol_cnv = (iteration < param_.max_strict_iter_) ? param_.tolerance_cnv_ : param_.tolerance_cnv_relaxed_; + } const int numComp = numEq; Vector R_sum(numComp, 0.0 ); @@ -948,8 +972,8 @@ namespace Opm { ss << "Iteration " << iteration << " Norm of pressure equation " << norm; OpmLog::info(ss.str()); // NB need better convergence criteria - const double tol_cnv = param_.tolerance_cnv_; - bool converged = norm < tol_cnv; + const double tol_pressure = param_.tolerance_pressure_; + bool converged = norm < tol_pressure; ConvergenceReport report; if(not(converged)){ diff --git a/opm/simulators/flow/BlackoilModelParametersEbos.hpp b/opm/simulators/flow/BlackoilModelParametersEbos.hpp index 5d89f21489e..eacd26e42df 100644 --- a/opm/simulators/flow/BlackoilModelParametersEbos.hpp +++ b/opm/simulators/flow/BlackoilModelParametersEbos.hpp @@ -49,6 +49,12 @@ NEW_PROP_TAG(MatrixAddWellContributions); NEW_PROP_TAG(EnableWellOperabilityCheck); NEW_PROP_TAG(SimulationType); +// for sequential +NEW_PROP_TAG(MaxStrictIterSeq); +NEW_PROP_TAG(ToleranceCnvSeq); +NEW_PROP_TAG(ToleranceCnvRelaxedSeq); +NEW_PROP_TAG(TolerancePressure); + // parameters for multisegment wells NEW_PROP_TAG(TolerancePressureMsWells); NEW_PROP_TAG(MaxPressureChangeMsWells); @@ -91,6 +97,12 @@ SET_STRING_PROP(FlowModelParameters, SimulationType, "implicit"); SET_SCALAR_PROP(FlowModelParameters, RelaxedFlowTolInnerIterMsw, 1); SET_SCALAR_PROP(FlowModelParameters, RelaxedPressureTolInnerIterMsw, 0.5e5); +// for sequential +SET_INT_PROP(FlowModelParameters, MaxStrictIterSeq, 8); +SET_SCALAR_PROP(FlowModelParameters, ToleranceCnvSeq,1e-2); +SET_SCALAR_PROP(FlowModelParameters, ToleranceCnvRelaxedSeq, 1e9); +SET_SCALAR_PROP(FlowModelParameters, TolerancePressure, 1e-4); + // if openMP is available, determine the number threads per process automatically. #if _OPENMP SET_INT_PROP(FlowModelParameters, ThreadsPerProcess, -1); @@ -186,6 +198,15 @@ namespace Opm // Whether to add influences of wells between cells to the matrix and preconditioner matrix bool matrix_add_well_contributions_; + // for sequential + /// Maximum number of Newton iterations before we give up on the CNV convergence criterion + int max_strict_iter_seq_; + /// Local convergence tolerance (max of local saturation errors). + double tolerance_cnv_seq_; + /// Relaxed local convergence tolerance (used when iter >= max_strict_iter_). + double tolerance_cnv_relaxed_seq_; + /// pressure tolerance + double tolerance_pressure_; /// Construct from user parameters or defaults. BlackoilModelParametersEbos() { @@ -217,6 +238,13 @@ namespace Opm matrix_add_well_contributions_ = EWOMS_GET_PARAM(TypeTag, bool, MatrixAddWellContributions); deck_file_name_ = EWOMS_GET_PARAM(TypeTag, std::string, EclDeckFileName); + + // for sequential + max_strict_iter_seq_ = EWOMS_GET_PARAM(TypeTag, int, MaxStrictIterSeq); + tolerance_cnv_seq_ = EWOMS_GET_PARAM(TypeTag, Scalar, ToleranceCnvSeq); + tolerance_cnv_relaxed_seq_ = EWOMS_GET_PARAM(TypeTag, Scalar, ToleranceCnvRelaxedSeq); + tolerance_pressure_ = EWOMS_GET_PARAM(TypeTag, Scalar, TolerancePressure); + } static void registerParameters() @@ -249,6 +277,13 @@ namespace Opm EWOMS_REGISTER_PARAM(TypeTag, bool, MatrixAddWellContributions, "Explicitly specify the influences of wells between cells in the Jacobian and preconditioner matrices"); EWOMS_REGISTER_PARAM(TypeTag, bool, EnableWellOperabilityCheck, "Enable the well operability checking"); EWOMS_REGISTER_PARAM(TypeTag, std::string, SimulationType, "Define simulation type: default implicit"); + + // for sequential + EWOMS_REGISTER_PARAM(TypeTag, int, MaxStrictIterSeq, "Maximum number of sequential iterations before relaxed tolerances are used for the CNV convergence criterion"); + EWOMS_REGISTER_PARAM(TypeTag, Scalar, ToleranceCnvSeq, "Local convergence tolerance for sequentialtransport(Maximum of local saturation errors)"); + EWOMS_REGISTER_PARAM(TypeTag, Scalar, ToleranceCnvRelaxedSeq, "Relaxed local convergence tolerance that applies for iterations after the iterations with the strict tolerance for sequential transport"); + EWOMS_REGISTER_PARAM(TypeTag, Scalar, TolerancePressure, "Relaxed local convergence tolerance that applies for iterations after the iterations with the strict tolerance for sequential transport"); + } }; } // namespace Opm diff --git a/opm/simulators/flow/NonlinearSolverEbos.hpp b/opm/simulators/flow/NonlinearSolverEbos.hpp index f43182e8344..feabd7351bc 100644 --- a/opm/simulators/flow/NonlinearSolverEbos.hpp +++ b/opm/simulators/flow/NonlinearSolverEbos.hpp @@ -40,11 +40,13 @@ NEW_TYPE_TAG(FlowNonLinearSolver); NEW_PROP_TAG(NewtonMaxRelax); NEW_PROP_TAG(FlowNewtonMaxIterations); NEW_PROP_TAG(FlowNewtonMinIterations); +NEW_PROP_TAG(FlowNewtonMaxSeqIterations); NEW_PROP_TAG(NewtonRelaxationType); SET_SCALAR_PROP(FlowNonLinearSolver, NewtonMaxRelax, 0.5); SET_INT_PROP(FlowNonLinearSolver, FlowNewtonMaxIterations, 20); SET_INT_PROP(FlowNonLinearSolver, FlowNewtonMinIterations, 1); +SET_INT_PROP(FlowNonLinearSolver, FlowNewtonMaxSeqIterations, 10); SET_STRING_PROP(FlowNonLinearSolver, NewtonRelaxationType, "dampen"); } // namespace Opm::Properties @@ -75,7 +77,7 @@ namespace Opm { double relaxRelTol_; int maxIter_; // max nonlinear iterations int minIter_; // min nonlinear iterations - + int maxSeqIter_;// max sequential iterations SolverParameters() { // set default values @@ -85,6 +87,7 @@ namespace Opm { relaxMax_ = EWOMS_GET_PARAM(TypeTag, Scalar, NewtonMaxRelax); maxIter_ = EWOMS_GET_PARAM(TypeTag, int, FlowNewtonMaxIterations); minIter_ = EWOMS_GET_PARAM(TypeTag, int, FlowNewtonMinIterations); + maxSeqIter_ = EWOMS_GET_PARAM(TypeTag, int, FlowNewtonMaxSeqIterations); const auto& relaxationTypeString = EWOMS_GET_PARAM(TypeTag, std::string, NewtonRelaxationType); if (relaxationTypeString == "dampen") { @@ -101,6 +104,7 @@ namespace Opm { EWOMS_REGISTER_PARAM(TypeTag, Scalar, NewtonMaxRelax, "The maximum relaxation factor of a Newton iteration used by flow"); EWOMS_REGISTER_PARAM(TypeTag, int, FlowNewtonMaxIterations, "The maximum number of Newton iterations per time step used by flow"); EWOMS_REGISTER_PARAM(TypeTag, int, FlowNewtonMinIterations, "The minimum number of Newton iterations per time step used by flow"); + EWOMS_REGISTER_PARAM(TypeTag, int, FlowNewtonMaxSeqIterations, "The maxismum number of Sequential iterations per time step used by flow"); EWOMS_REGISTER_PARAM(TypeTag, std::string, NewtonRelaxationType, "The type of relaxation used by flow's Newton method"); } @@ -113,6 +117,7 @@ namespace Opm { relaxRelTol_ = 0.2; maxIter_ = 10; minIter_ = 1; + maxSeqIter_ = 10; } }; @@ -153,7 +158,6 @@ namespace Opm { SimulatorReportSingle reportpre; SimulatorReportSingle reportseq; int seqiterations = 0; - int maxseqiterations = 10; // sett the seq variable to be equal at beginning auto solutionOld = model_->ebosSimulator().model().solution(/*timeIdx=*/0); //auto oldTotalSaturation = model_->ebosSimulator().problem().getTotalSaturation(/*timeIdx*/0); @@ -161,7 +165,7 @@ namespace Opm { model_->ebosSimulator().problem().syncPressureForward(); model_->ebosSimulator().problem().syncTotalSaturationForward(); bool first= true; - while(not(converged) && (seqiterations < maxseqiterations) ){ + while(not(converged) && (seqiterations < maxSeqIter()) ){ // Always guess that nest step will give one in total saturation model_->ebosSimulator().problem().totalSaturationOne(/*timeidx*/0); // do pressure step @@ -193,8 +197,6 @@ namespace Opm { currsol = solutionOld; // set back the // the sequantial variables should not be needed to put back - //model_->ebosSimulator().problem().setTotalSaturation(oldTotalSaturation,0); - //model_->ebosSimulator().problem().setTotalSaturation(oldTotalSaturation,1); model_->ebosSimulator().problem().syncPressureBackward(); model_->ebosSimulator().problem().syncTotalSaturationBackward(); throw; @@ -227,6 +229,17 @@ namespace Opm { //TODO add timings of call to implicit residual if(not(converged)){ report.converged = false; + failureReport_ = report; + auto& prevsol = model_->ebosSimulator().model().solution(/*timeIdx=*/1); + prevsol = solutionOld; + auto& currsol = model_->ebosSimulator().model().solution(/*timeIdx=*/0); + currsol = solutionOld; + // set back the + // the sequantial variables should not be needed to put back + model_->ebosSimulator().problem().syncPressureBackward(); + model_->ebosSimulator().problem().syncTotalSaturationBackward(); + std::string msg = "Solver iteration sin seq - Failed to complete a time step within " + std::to_string(maxIter()) + " iterations."; + OPM_THROW_NOLOG(Opm::TooManyIterations, msg); }else{ // model_->updateSolution(); model_->afterStep(timer); @@ -400,6 +413,9 @@ namespace Opm { int minIter() const { return param_.minIter_; } + int maxSeqIter() const + { return param_.maxSeqIter_; } + /// Set parameters to override those given at construction time. void setParameters(const SolverParameters& param) { param_ = param; } From 5b598acbb482c76a0418f33d9adc9fb0c7a77e59 Mon Sep 17 00:00:00 2001 From: hnil Date: Tue, 18 Aug 2020 22:22:05 +0200 Subject: [PATCH 84/93] made policy more like mrst. --- opm/simulators/flow/NonlinearSolverEbos.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/opm/simulators/flow/NonlinearSolverEbos.hpp b/opm/simulators/flow/NonlinearSolverEbos.hpp index feabd7351bc..2d60e3bc67f 100644 --- a/opm/simulators/flow/NonlinearSolverEbos.hpp +++ b/opm/simulators/flow/NonlinearSolverEbos.hpp @@ -227,7 +227,8 @@ namespace Opm { report.setTransportReport(reportseq); report.total_newton_iterations = seqiterations; //TODO add timings of call to implicit residual - if(not(converged)){ + bool mrst_policy = true;//accept step even if not converged + if(not(converged) && not(mrst_policy)){ report.converged = false; failureReport_ = report; auto& prevsol = model_->ebosSimulator().model().solution(/*timeIdx=*/1); From 735c4c095e29c56e0f5a7cf2007f47689b612bb5 Mon Sep 17 00:00:00 2001 From: hnil Date: Tue, 18 Aug 2020 22:36:08 +0200 Subject: [PATCH 85/93] changed policy fixed output --- opm/simulators/flow/NonlinearSolverEbos.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/opm/simulators/flow/NonlinearSolverEbos.hpp b/opm/simulators/flow/NonlinearSolverEbos.hpp index 2d60e3bc67f..d0c6ed5d021 100644 --- a/opm/simulators/flow/NonlinearSolverEbos.hpp +++ b/opm/simulators/flow/NonlinearSolverEbos.hpp @@ -239,7 +239,7 @@ namespace Opm { // the sequantial variables should not be needed to put back model_->ebosSimulator().problem().syncPressureBackward(); model_->ebosSimulator().problem().syncTotalSaturationBackward(); - std::string msg = "Solver iteration sin seq - Failed to complete a time step within " + std::to_string(maxIter()) + " iterations."; + std::string msg = "Solver iteration sin seq - Failed to complete a time step within " + std::to_string(maxSeqIter()) + " iterations."; OPM_THROW_NOLOG(Opm::TooManyIterations, msg); }else{ // model_->updateSolution(); From 86b48cb5e2d68011dd8722948d6dc32baf60bc3c Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Wed, 19 Aug 2020 11:46:53 +0200 Subject: [PATCH 86/93] eclblackoilprimaryvariables inherits blackoilprimaryvariables the fuction assignNaive does not work, need to adjust more. --- ebos/eclblackoilprimaryvariables.hh | 398 ++++------------------------ 1 file changed, 46 insertions(+), 352 deletions(-) diff --git a/ebos/eclblackoilprimaryvariables.hh b/ebos/eclblackoilprimaryvariables.hh index d6a663fa67f..9c95fabc355 100644 --- a/ebos/eclblackoilprimaryvariables.hh +++ b/ebos/eclblackoilprimaryvariables.hh @@ -36,65 +36,49 @@ namespace Opm{ * \brief Represents the primary variables used by the black-oil model. */ template -class EclBlackOilPrimaryVariables : public FvBasePrimaryVariables +class EclBlackOilPrimaryVariables : public BlackOilPrimaryVariables { - using ParentType = FvBasePrimaryVariables; - using Implementation = GetPropType; - - using Scalar = GetPropType; - using Evaluation = GetPropType; - using Indices = GetPropType; - using Problem = GetPropType; - using FluidSystem = GetPropType; - using MaterialLaw = GetPropType; - using MaterialLawParams = GetPropType; - - // number of equations - enum { numEq = getPropValue() }; - - // primary variable indices - enum { waterSaturationIdx = Indices::waterSaturationIdx }; - enum { pressureSwitchIdx = Indices::pressureSwitchIdx }; - enum { compositionSwitchIdx = Indices::compositionSwitchIdx }; - - static const bool compositionSwitchEnabled = Indices::gasEnabled; - static const bool waterEnabled = Indices::waterEnabled; - - // phase indices from the fluid system - enum { numPhases = GET_PROP_VALUE(TypeTag, NumPhases) }; - enum { gasPhaseIdx = FluidSystem::gasPhaseIdx }; - enum { waterPhaseIdx = FluidSystem::waterPhaseIdx }; - enum { oilPhaseIdx = FluidSystem::oilPhaseIdx }; - - // component indices from the fluid system - enum { numComponents = getPropValue() }; - enum { enableSolvent = getPropValue() }; - enum { enablePolymer = getPropValue() }; - enum { enableFoam = getPropValue() }; - enum { enableBrine = getPropValue() }; - enum { enableEnergy = getPropValue() }; - enum { gasCompIdx = FluidSystem::gasCompIdx }; - enum { waterCompIdx = FluidSystem::waterCompIdx }; - enum { oilCompIdx = FluidSystem::oilCompIdx }; - - using Toolbox = typename Opm::MathToolbox; - using ComponentVector = Dune::FieldVector; - using SolventModule = BlackOilSolventModule; - using PolymerModule = BlackOilPolymerModule; - using EnergyModule = BlackOilEnergyModule; - using FoamModule = BlackOilFoamModule; - using BrineModule = BlackOilBrineModule; - - static_assert(numPhases == 3, "The black-oil model assumes three phases!"); - static_assert(numComponents == 3, "The black-oil model assumes three components!"); + using BaseType = BlackOilPrimaryVariables; + + using typename BaseType::Scalar; + using typename BaseType::Problem; + using typename BaseType::Indices; + using typename BaseType::FluidSystem; + using typename BaseType::MaterialLawParams; + using typename BaseType::EnergyModule; + + using BaseType::numPhases; + using BaseType::oilPhaseIdx; + using BaseType::gasPhaseIdx; + using BaseType::waterPhaseIdx; + using BaseType::compositionSwitchEnabled; + + + using BaseType::waterEnabled; + using BaseType::solventSaturation_; + using BaseType::asImp_; + + using BaseType::primaryVarsMeaning_; + using BaseType::computeCapillaryPressures_; + + + using BaseType::pvtRegionIdx_; + + using BaseType::waterSaturationIdx; + using BaseType::pressureSwitchIdx; + using BaseType::compositionSwitchIdx; public: - enum PrimaryVarsMeaning { - Sw_po_Sg, // threephase case - Sw_po_Rs, // water + oil case - Sw_pg_Rv, // water + gas case - OnePhase_p, // onephase case - }; + using BaseType::Sw_pg_Rv; + using BaseType::Sw_po_Rs; + using BaseType::Sw_po_Sg; + + using BaseType::checkDefined; + using BaseType::OnePhase_p; + using BaseType::primaryVarsMeaning; + using BaseType::setPrimaryVarsMeaning; + + using BaseType::operator=; enum SimulationType { Implicit, @@ -102,22 +86,19 @@ public: }; EclBlackOilPrimaryVariables() - : ParentType() + : BaseType() { Opm::Valgrind::SetUndefined(*this); simulationType_ = SimulationType::Implicit; - pvtRegionIdx_ = 0; } /*! * \copydoc ImmisciblePrimaryVariables::ImmisciblePrimaryVariables(Scalar) */ EclBlackOilPrimaryVariables(Scalar value) - : ParentType(value) + : BaseType(value) { - Opm::Valgrind::SetUndefined(primaryVarsMeaning_); Opm::Valgrind::SetUndefined(simulationType_); - pvtRegionIdx_ = 0; } /*! @@ -125,122 +106,15 @@ public: */ EclBlackOilPrimaryVariables(const EclBlackOilPrimaryVariables& value) = default; - /*! - * \brief Set the index of the region which should be used for PVT properties. - * - * The concept of PVT regions is a hack to work around the fact that the - * pseudo-components used by the black oil model (i.e., oil, gas and water) change - * their composition within the spatial domain. We implement them because, the ECL - * file format mandates them. - */ - void setPvtRegionIndex(unsigned value) - { pvtRegionIdx_ = static_cast(value); } - - /*! - * \brief Return the index of the region which should be used for PVT properties. - */ - unsigned pvtRegionIndex() const - { return pvtRegionIdx_; } - - /*! - * \brief Return the interpretation which should be applied to the switching primary - * variables. - */ - PrimaryVarsMeaning primaryVarsMeaning() const - { return primaryVarsMeaning_; } SimulationType simulationType() const { return simulationType_; } - /*! - * \brief Set the interpretation which should be applied to the switching primary - * variables. - */ - void setPrimaryVarsMeaning(PrimaryVarsMeaning newMeaning) - { primaryVarsMeaning_ = newMeaning; } /* void setSimulaiontType(SimulationType simulationType) { simulaionType_ = simulationType; } */ - - /*! - * \copydoc ImmisciblePrimaryVariables::assignMassConservative - */ - template - void assignMassConservative(const FluidState& fluidState, - const MaterialLawParams& matParams, - bool isInEquilibrium = false) - { - using ConstEvaluation = typename std::remove_reference::type; - using FsEvaluation = typename std::remove_const::type; - using FsToolbox = typename Opm::MathToolbox; - -#ifndef NDEBUG - // make sure the temperature is the same in all fluid phases - for (unsigned phaseIdx = 1; phaseIdx < numPhases; ++phaseIdx) { - Opm::Valgrind::CheckDefined(fluidState.temperature(0)); - Opm::Valgrind::CheckDefined(fluidState.temperature(phaseIdx)); - - assert(fluidState.temperature(0) == fluidState.temperature(phaseIdx)); - } -#endif // NDEBUG - - // for the equilibrium case, we don't need complicated - // computations. - if (isInEquilibrium) { - assignNaive(fluidState); - return; - } - - // If your compiler bails out here, you're probably not using a suitable black - // oil fluid system. - typename FluidSystem::template ParameterCache paramCache; - paramCache.setRegionIndex(pvtRegionIdx_); - paramCache.setMaxOilSat(FsToolbox::value(fluidState.saturation(oilPhaseIdx))); - - // create a mutable fluid state with well defined densities based on the input - using NcpFlash = Opm::NcpFlash; - using FlashFluidState = Opm::CompositionalFluidState; - FlashFluidState fsFlash; - fsFlash.setTemperature(FsToolbox::value(fluidState.temperature(/*phaseIdx=*/0))); - for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { - fsFlash.setPressure(phaseIdx, FsToolbox::value(fluidState.pressure(phaseIdx))); - fsFlash.setSaturation(phaseIdx, FsToolbox::value(fluidState.saturation(phaseIdx))); - for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) - fsFlash.setMoleFraction(phaseIdx, compIdx, FsToolbox::value(fluidState.moleFraction(phaseIdx, compIdx))); - } - - paramCache.updateAll(fsFlash); - for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { - if (!FluidSystem::phaseIsActive(phaseIdx)) - continue; - - Scalar rho = FluidSystem::template density(fsFlash, paramCache, phaseIdx); - fsFlash.setDensity(phaseIdx, rho); - } - - // calculate the "global molarities" - ComponentVector globalMolarities(0.0); - for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) { - for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { - if (!FluidSystem::phaseIsActive(phaseIdx)) - continue; - - globalMolarities[compIdx] += - fsFlash.saturation(phaseIdx) * fsFlash.molarity(phaseIdx, compIdx); - } - } - - // use a flash calculation to calculate a fluid state in - // thermodynamic equilibrium - - // run the flash calculation - NcpFlash::template solve(fsFlash, matParams, paramCache, globalMolarities); - - // use the result to assign the primary variables - assignNaive(fsFlash); - } /*! * \copydoc ImmisciblePrimaryVariables::assignNaive @@ -295,7 +169,7 @@ public: } else { throw std::logic_error("For single-phase runs, only pure water is presently allowed."); } - + } else if (primaryVarsMeaning() == Sw_po_Sg) { if (waterEnabled) @@ -328,6 +202,7 @@ public: checkDefined(); } + /*! * \brief Adapt the interpretation of the switching variables to be physically * meaningful. @@ -606,7 +481,7 @@ public: Scalar po = pg + (pC[oilPhaseIdx] - pC[gasPhaseIdx]); setPrimaryVarsMeaning(Sw_po_Sg); - if (not(linearizationType.type == Opm::LinearizationType::seqtransport)) { + if (linearizationType.type != Opm::LinearizationType::seqtransport) { (*this)[Indices::pressureSwitchIdx] = po; } (*this)[Indices::compositionSwitchIdx] = Sg; // hydrocarbon gas saturation @@ -621,189 +496,8 @@ public: return false; } - bool chopAndNormalizeSaturations(){ - if (primaryVarsMeaning() == OnePhase_p){ - return false; - } - Scalar Sw = 0.0; - if (waterEnabled) - Sw = (*this)[Indices::waterSaturationIdx]; - - if (primaryVarsMeaning() == Sw_po_Sg) { - Scalar Sg = 0.0; - if (compositionSwitchEnabled) - Sg = (*this)[Indices::compositionSwitchIdx]; - Scalar Ssol = 0.0; - if (enableSolvent) - Ssol =(*this) [Indices::solventSaturationIdx]; - - Scalar So = 1.0 - Sw - Sg - Ssol; - Sw = std::min(std::max(Sw,0.0),1.0); - So = std::min(std::max(So,0.0),1.0); - Sg = std::min(std::max(Sg,0.0),1.0); - Ssol = std::min(std::max(Ssol,0.0),1.0); - - Scalar St = Sw + So + Sg + Ssol; - Sw = Sw/St; - Sg = Sg/St; - Ssol = Ssol/St; - assert(St>0.5); - if (waterEnabled) - (*this)[Indices::waterSaturationIdx]= Sw; - if (compositionSwitchEnabled) - (*this)[Indices::compositionSwitchIdx] = Sg; - if (enableSolvent) - (*this)[Indices::solventSaturationIdx] = Ssol; - return not(St==1); - - }else if (primaryVarsMeaning() == Sw_po_Rs) { - Scalar Ssol = 0.0; - if (enableSolvent) - Ssol = (*this)[Indices::solventSaturationIdx]; - Scalar So = 1.0 - Sw - Ssol; - Sw = std::min(std::max(Sw,0.0),1.0); - So = std::min(std::max(So,0.0),1.0); - Ssol = std::min(std::max(Ssol,0.0),1.0); - //Sg = 0.0; - Scalar St = Sw + So + Ssol; - assert(St>0.5); - Sw=Sw/St; - Ssol=Ssol/St; - if (waterEnabled) - (*this)[Indices::waterSaturationIdx]= Sw; - if (enableSolvent) - (*this)[Indices::solventSaturationIdx] = Ssol; - return not(St==1); - }else{ - assert(primaryVarsMeaning() == Sw_pg_Rv); - assert(compositionSwitchEnabled); - Scalar Ssol=0.0; - if (enableSolvent) - Ssol = (*this)[Indices::solventSaturationIdx]; - Scalar Sg = 1.0 - Sw - Ssol; - //So = 0.0; - Sw = std::min(std::max(Sw,0.0),1.0); - Sg = std::min(std::max(Sg,0.0),1.0); - Ssol = std::min(std::max(Ssol,0.0),1.0); - Scalar St = Sw + Sg + Ssol; - assert(St>0.5); - Sw=Sw/St; - Ssol=Ssol/St; - if (waterEnabled) - (*this)[Indices::waterSaturationIdx]= Sw; - if (enableSolvent) - (*this)[Indices::solventSaturationIdx] = Ssol; - return not(St==1); - } - assert(false); - } - - EclBlackOilPrimaryVariables& operator=(const EclBlackOilPrimaryVariables& other) = default; - EclBlackOilPrimaryVariables& operator=(Scalar value) - { - for (unsigned i = 0; i < numEq; ++i) - (*this)[i] = value; - - return *this; - } - - /*! - * \brief Instruct valgrind to check the definedness of all attributes of this class. - * - * We cannot simply check the definedness of the whole object because there might be - * "alignedness holes" in the memory layout which are caused by the pseudo primary - * variables. - */ - void checkDefined() const - { -#ifndef NDEBUG - // check the "real" primary variables - for (unsigned i = 0; i < this->size(); ++i) - Opm::Valgrind::CheckDefined((*this)[i]); - - // check the "pseudo" primary variables - Opm::Valgrind::CheckDefined(primaryVarsMeaning_); - Opm::Valgrind::CheckDefined(pvtRegionIdx_); -#endif // NDEBUG - } - -private: - Implementation& asImp_() - { return *static_cast(this); } - - const Implementation& asImp_() const - { return *static_cast(this); } - - Scalar solventSaturation_() const - { - if (!enableSolvent) - return 0.0; - - return (*this)[Indices::solventSaturationIdx]; - } - - Scalar polymerConcentration_() const - { - if (!enablePolymer) - return 0.0; - - return (*this)[Indices::polymerConcentrationIdx]; - } - - Scalar foamConcentration_() const - { - if (!enableFoam) - return 0.0; - - return (*this)[Indices::foamConcentrationIdx]; - } - - Scalar saltConcentration_() const - { - if (!enableBrine) - return 0.0; - - return (*this)[Indices::saltConcentrationIdx]; - } - - Scalar temperature_() const - { - if (!enableEnergy) - return FluidSystem::reservoirTemperature(); - - return (*this)[Indices::temperatureIdx]; - } - - template - void computeCapillaryPressures_(Container& result, - Scalar So, - Scalar Sg, - Scalar Sw, - const MaterialLawParams& matParams) const - { - using SatOnlyFluidState = Opm::SimpleModularFluidState; - SatOnlyFluidState fluidState; - fluidState.setSaturation(waterPhaseIdx, Sw); - fluidState.setSaturation(oilPhaseIdx, So); - fluidState.setSaturation(gasPhaseIdx, Sg); - - MaterialLaw::capillaryPressures(result, matParams, fluidState); - } - - PrimaryVarsMeaning primaryVarsMeaning_; +protected: SimulationType simulationType_; - unsigned short pvtRegionIdx_; }; From 77dd11c946f107afe41c12033cd3c3cd2bd37a19 Mon Sep 17 00:00:00 2001 From: hnil Date: Wed, 19 Aug 2020 10:38:28 +0200 Subject: [PATCH 87/93] Introduced more settings for pressure solver and reuse of pressure matrix --- opm/simulators/flow/BlackoilModelEbos.hpp | 77 ++++++++++++++----- .../flow/BlackoilModelParametersEbos.hpp | 21 ++++- 2 files changed, 74 insertions(+), 24 deletions(-) diff --git a/opm/simulators/flow/BlackoilModelEbos.hpp b/opm/simulators/flow/BlackoilModelEbos.hpp index 62392cd8064..006f9a905d4 100644 --- a/opm/simulators/flow/BlackoilModelEbos.hpp +++ b/opm/simulators/flow/BlackoilModelEbos.hpp @@ -143,6 +143,10 @@ namespace Opm { typedef Dune::BlockVector BVector; typedef ISTLSolverEbos ISTLSolverType; + + typedef Dune::BCRSMatrix< Dune::FieldMatrix> PressureMatrixType; + typedef Dune::BlockVector> PressureVectorType; + typedef Dune::FlexibleSolver PressureSolverType; //typedef typename SolutionVector :: value_type PrimaryVariables ; // --------- Public methods --------- @@ -486,27 +490,29 @@ namespace Opm { > makePressureSolver(Dune::BCRSMatrix< Dune::FieldMatrix>& pmatrix) { boost::property_tree::ptree prm; - if (std::filesystem::exists("pressuresolver.json") ) { + if (std::filesystem::exists(param_.pressure_solver_json_) ) { try{ - boost::property_tree::read_json("pressuresolver.json", prm); + boost::property_tree::read_json(param_.pressure_solver_json_, prm); }catch(...){ - OPM_THROW(std::logic_error,"failed in passing configuration file pressuresolver.json"); + OPM_THROW(std::logic_error,"failed in passing configuration file:" + param_.pressure_solver_json_); } } else { // using a default setup for pressure solver std::stringstream ss; + prm.put("solver","umfpack"); + prm.put("blocksize",1); + prm.put("verbosity",1); + /* ss << "{\n" " \"solver\": \"umfpack\",\n" " \"blocksize\": \"1\"\n" "}"; boost::property_tree::read_json(ss, prm); + */ } - using PressureMatrixType = Dune::BCRSMatrix< Dune::FieldMatrix>; - using PressureVectorType = Dune::BlockVector>; std::any parallelInformation; extractParallelGridInformationToISTL(ebosSimulator_.vanguard().grid(), parallelInformation); using AbstractOperatorType = Dune::AssembledLinearOperator; - using PressureSolverType = Dune::FlexibleSolver; std::unique_ptr operator_for_flexiblesolver; std::function weightsCalculator;// dummy std::unique_ptr pressureSolver; @@ -540,7 +546,18 @@ namespace Opm { return pressureSolver; } - + bool shouldCreatePressureSolver(){ + if(!pressureSolver_){ + return true; + } + if(param_.reuse_pressure_solver_ > 0){ + return false; + }else{ + return true; + } + assert(false); + + } /// Solve the Jacobian system Jx = r where J is the Jacobian and /// r is the residual. void solveJacobianSystem(BVector& x) @@ -549,28 +566,43 @@ namespace Opm { auto& ebosJac = ebosSimulator_.model().linearizer().jacobian(); auto& ebosResid = ebosSimulator_.model().linearizer().residual(); // NB when tested the linear solver an the martrix could be part of linearizer - using PressureMatrixType = Dune::BCRSMatrix< Dune::FieldMatrix>; - using PressureVectorType = Dune::BlockVector>; + int pressureVarIndex=1; // true impes case could add case with trivial weighs i equations is modifind with weights // this would make a newton based method if derivative of the weights are takein into account BVector weights = this->getPressureWeights(pressureVarIndex); - PressureMatrixType pmatrix = - PressureHelper::makePressureMatrix( - ebosJac.istlMatrix(), - pressureVarIndex, - weights); + if(!pmatrix_){ + // make matrix structure and fill with elements + pmatrix_ = + std::make_unique(PressureHelper::makePressureMatrix( + ebosJac.istlMatrix(), + pressureVarIndex, + weights)); + }else{ + //only update elements of matrix + // assume matrix structure never change + PressureHelper::makePressureMatrixEntries( + *pmatrix_, + ebosJac.istlMatrix(), + pressureVarIndex, + weights); + } PressureVectorType rhs(ebosResid.size(),0); PressureHelper::moveToPressureEqn(ebosResid, rhs, weights); - - using PressureSolverType = Dune::FlexibleSolver; - std::unique_ptr pressureSolver = makePressureSolver(pmatrix); + if(this->shouldCreatePressureSolver()){ + pressureSolver_ = makePressureSolver(*pmatrix_); + }else{ + pressureSolver_->preconditioner().update(); + } + PressureVectorType xp(x.size(),0); Dune::InverseOperatorResult res; - pressureSolver->apply(xp,rhs, res); + pressureSolver_->apply(xp,rhs, res); /* bool write_pressure_system = false; if(write_pressure_system){ @@ -1112,6 +1144,9 @@ namespace Opm { double drMaxRel() const { return param_.dr_max_rel_; } double maxResidualAllowed() const { return param_.max_residual_allowed_; } double linear_solve_setup_time_; + std::unique_ptr pressureSolver_; + std::unique_ptr pmatrix_; + public: std::vector wasSwitched_; }; diff --git a/opm/simulators/flow/BlackoilModelParametersEbos.hpp b/opm/simulators/flow/BlackoilModelParametersEbos.hpp index eacd26e42df..8c378a05581 100644 --- a/opm/simulators/flow/BlackoilModelParametersEbos.hpp +++ b/opm/simulators/flow/BlackoilModelParametersEbos.hpp @@ -47,13 +47,15 @@ NEW_PROP_TAG(UpdateEquationsScaling); NEW_PROP_TAG(UseUpdateStabilization); NEW_PROP_TAG(MatrixAddWellContributions); NEW_PROP_TAG(EnableWellOperabilityCheck); -NEW_PROP_TAG(SimulationType); // for sequential NEW_PROP_TAG(MaxStrictIterSeq); NEW_PROP_TAG(ToleranceCnvSeq); NEW_PROP_TAG(ToleranceCnvRelaxedSeq); NEW_PROP_TAG(TolerancePressure); +NEW_PROP_TAG(ReusePressureSolver); +NEW_PROP_TAG(SimulationType); +NEW_PROP_TAG(PressureSolverJson); // parameters for multisegment wells NEW_PROP_TAG(TolerancePressureMsWells); @@ -92,7 +94,6 @@ SET_INT_PROP(FlowModelParameters, MaxInnerIterWells, 50); SET_INT_PROP(FlowModelParameters, StrictInnerIterMsWells, 40); SET_SCALAR_PROP(FlowModelParameters, RegularizationFactorMsw, 1); SET_BOOL_PROP(FlowModelParameters, EnableWellOperabilityCheck, true); -SET_STRING_PROP(FlowModelParameters, SimulationType, "implicit"); SET_SCALAR_PROP(FlowModelParameters, RelaxedFlowTolInnerIterMsw, 1); SET_SCALAR_PROP(FlowModelParameters, RelaxedPressureTolInnerIterMsw, 0.5e5); @@ -102,6 +103,9 @@ SET_INT_PROP(FlowModelParameters, MaxStrictIterSeq, 8); SET_SCALAR_PROP(FlowModelParameters, ToleranceCnvSeq,1e-2); SET_SCALAR_PROP(FlowModelParameters, ToleranceCnvRelaxedSeq, 1e9); SET_SCALAR_PROP(FlowModelParameters, TolerancePressure, 1e-4); +SET_INT_PROP(FlowModelParameters, ReusePressureSolver, 0); +SET_STRING_PROP(FlowModelParameters, SimulationType, "implicit"); +SET_STRING_PROP(FlowModelParameters, PressureSolverJson, "pressuresolver.json"); // if openMP is available, determine the number threads per process automatically. #if _OPENMP @@ -207,7 +211,12 @@ namespace Opm double tolerance_cnv_relaxed_seq_; /// pressure tolerance double tolerance_pressure_; + /// policy for reuse of pressure solver + int reuse_pressure_solver_; + // name of json file for pressure setup + std::string pressure_solver_json_; /// Construct from user parameters or defaults. + BlackoilModelParametersEbos() { dbhp_max_rel_= EWOMS_GET_PARAM(TypeTag, Scalar, DbhpMaxRel); @@ -244,6 +253,9 @@ namespace Opm tolerance_cnv_seq_ = EWOMS_GET_PARAM(TypeTag, Scalar, ToleranceCnvSeq); tolerance_cnv_relaxed_seq_ = EWOMS_GET_PARAM(TypeTag, Scalar, ToleranceCnvRelaxedSeq); tolerance_pressure_ = EWOMS_GET_PARAM(TypeTag, Scalar, TolerancePressure); + reuse_pressure_solver_ = EWOMS_GET_PARAM(TypeTag, int, ReusePressureSolver); + pressure_solver_json_ = EWOMS_GET_PARAM(TypeTag, std::string,PressureSolverJson); + } @@ -276,13 +288,16 @@ namespace Opm EWOMS_REGISTER_PARAM(TypeTag, bool, UseUpdateStabilization, "Try to detect and correct oscillations or stagnation during the Newton method"); EWOMS_REGISTER_PARAM(TypeTag, bool, MatrixAddWellContributions, "Explicitly specify the influences of wells between cells in the Jacobian and preconditioner matrices"); EWOMS_REGISTER_PARAM(TypeTag, bool, EnableWellOperabilityCheck, "Enable the well operability checking"); - EWOMS_REGISTER_PARAM(TypeTag, std::string, SimulationType, "Define simulation type: default implicit"); + // for sequential EWOMS_REGISTER_PARAM(TypeTag, int, MaxStrictIterSeq, "Maximum number of sequential iterations before relaxed tolerances are used for the CNV convergence criterion"); EWOMS_REGISTER_PARAM(TypeTag, Scalar, ToleranceCnvSeq, "Local convergence tolerance for sequentialtransport(Maximum of local saturation errors)"); EWOMS_REGISTER_PARAM(TypeTag, Scalar, ToleranceCnvRelaxedSeq, "Relaxed local convergence tolerance that applies for iterations after the iterations with the strict tolerance for sequential transport"); EWOMS_REGISTER_PARAM(TypeTag, Scalar, TolerancePressure, "Relaxed local convergence tolerance that applies for iterations after the iterations with the strict tolerance for sequential transport"); + EWOMS_REGISTER_PARAM(TypeTag, int, ReusePressureSolver, "Reuse policy for pressure"); + EWOMS_REGISTER_PARAM(TypeTag, std::string, PressureSolverJson, "Json setupfile for pressure solver"); + EWOMS_REGISTER_PARAM(TypeTag, std::string, SimulationType, "Define simulation type: default implicit"); } }; From f9f4657c0e7f0ad125c0a0fc936dbf039eb763d8 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Wed, 19 Aug 2020 16:13:39 +0200 Subject: [PATCH 88/93] removing the duplicated assignNaive in eclblackoilprimaryvariables.hh --- ebos/eclblackoilprimaryvariables.hh | 102 +--------------------------- 1 file changed, 2 insertions(+), 100 deletions(-) diff --git a/ebos/eclblackoilprimaryvariables.hh b/ebos/eclblackoilprimaryvariables.hh index 9c95fabc355..f22b65240c5 100644 --- a/ebos/eclblackoilprimaryvariables.hh +++ b/ebos/eclblackoilprimaryvariables.hh @@ -45,7 +45,6 @@ class EclBlackOilPrimaryVariables : public BlackOilPrimaryVariables using typename BaseType::Indices; using typename BaseType::FluidSystem; using typename BaseType::MaterialLawParams; - using typename BaseType::EnergyModule; using BaseType::numPhases; using BaseType::oilPhaseIdx; @@ -57,11 +56,8 @@ class EclBlackOilPrimaryVariables : public BlackOilPrimaryVariables using BaseType::waterEnabled; using BaseType::solventSaturation_; using BaseType::asImp_; - - using BaseType::primaryVarsMeaning_; using BaseType::computeCapillaryPressures_; - using BaseType::pvtRegionIdx_; using BaseType::waterSaturationIdx; @@ -73,7 +69,6 @@ public: using BaseType::Sw_po_Rs; using BaseType::Sw_po_Sg; - using BaseType::checkDefined; using BaseType::OnePhase_p; using BaseType::primaryVarsMeaning; using BaseType::setPrimaryVarsMeaning; @@ -109,99 +104,6 @@ public: SimulationType simulationType() const { return simulationType_; } - - - /* - void setSimulaiontType(SimulationType simulationType) - { simulaionType_ = simulationType; } - */ - - /*! - * \copydoc ImmisciblePrimaryVariables::assignNaive - */ - template - void assignNaive(const FluidState& fluidState) - { - using ConstEvaluation = typename std::remove_reference::type; - using FsEvaluation = typename std::remove_const::type; - using FsToolbox = typename Opm::MathToolbox; - - bool gasPresent = FluidSystem::phaseIsActive(gasPhaseIdx)?(fluidState.saturation(gasPhaseIdx) > 0.0):false; - bool oilPresent = FluidSystem::phaseIsActive(oilPhaseIdx)?(fluidState.saturation(oilPhaseIdx) > 0.0):false; - static const Scalar thresholdWaterFilledCell = 1.0 - 1e-6; - bool onlyWater = FluidSystem::phaseIsActive(waterPhaseIdx)?(fluidState.saturation(waterPhaseIdx) > thresholdWaterFilledCell):false; - - // deal with the primary variables for the energy extension - EnergyModule::assignPrimaryVars(*this, fluidState); - - // determine the meaning of the primary variables - if (FluidSystem::numActivePhases() == 1) { - primaryVarsMeaning_ = OnePhase_p; - } - else if ((gasPresent && oilPresent) || (onlyWater && FluidSystem::phaseIsActive(oilPhaseIdx))) { - // gas and oil: both hydrocarbon phases are in equilibrium (i.e., saturated - // with the "protagonist" component of the other phase.) - primaryVarsMeaning_ = Sw_po_Sg; - } - else if (oilPresent) { - // only oil: if dissolved gas is enabled, we need to consider the oil phase - // composition, if it is disabled, the gas component must stick to its phase - if (FluidSystem::enableDissolvedGas()) - primaryVarsMeaning_ = Sw_po_Rs; - else - primaryVarsMeaning_ = Sw_po_Sg; - } - else { - assert(gasPresent); - // only gas: if vaporized oil is enabled, we need to consider the gas phase - // composition, if it is disabled, the oil component must stick to its phase - if (FluidSystem::enableVaporizedOil()) - primaryVarsMeaning_ = Sw_pg_Rv; - else - primaryVarsMeaning_ = Sw_po_Sg; - } - - // assign the actual primary variables - if (primaryVarsMeaning() == OnePhase_p) { - if (waterEnabled) { - (*this)[waterSaturationIdx] = FsToolbox::value(fluidState.saturation(waterPhaseIdx)); - (*this)[pressureSwitchIdx] = FsToolbox::value(fluidState.pressure(waterPhaseIdx)); - } else { - throw std::logic_error("For single-phase runs, only pure water is presently allowed."); - } - - } - else if (primaryVarsMeaning() == Sw_po_Sg) { - if (waterEnabled) - (*this)[waterSaturationIdx] = FsToolbox::value(fluidState.saturation(waterPhaseIdx)); - (*this)[pressureSwitchIdx] = FsToolbox::value(fluidState.pressure(oilPhaseIdx)); - if( compositionSwitchEnabled ) - (*this)[compositionSwitchIdx] = FsToolbox::value(fluidState.saturation(gasPhaseIdx)); - } - else if (primaryVarsMeaning() == Sw_po_Rs) { - const auto& Rs = Opm::BlackOil::getRs_(fluidState, pvtRegionIdx_); - - if (waterEnabled) - (*this)[waterSaturationIdx] = FsToolbox::value(fluidState.saturation(waterPhaseIdx)); - (*this)[pressureSwitchIdx] = FsToolbox::value(fluidState.pressure(oilPhaseIdx)); - if( compositionSwitchEnabled ) - (*this)[compositionSwitchIdx] = Rs; - } - else { - assert(primaryVarsMeaning() == Sw_pg_Rv); - - const auto& Rv = Opm::BlackOil::getRv_(fluidState, pvtRegionIdx_); - if (waterEnabled) - (*this)[waterSaturationIdx] = FsToolbox::value(fluidState.saturation(waterPhaseIdx)); - - (*this)[pressureSwitchIdx] = FsToolbox::value(fluidState.pressure(gasPhaseIdx)); - if( compositionSwitchEnabled ) - (*this)[compositionSwitchIdx] = Rv; - } - - checkDefined(); - } - /*! * \brief Adapt the interpretation of the switching variables to be physically @@ -353,7 +255,7 @@ public: Scalar(0), SoMax); setPrimaryVarsMeaning(Sw_pg_Rv); - if (not(linearizationType.type == Opm::LinearizationType::seqtransport)) { + if (linearizationType.type != Opm::LinearizationType::seqtransport) { (*this)[Indices::pressureSwitchIdx] = pg; } if (compositionSwitchEnabled) @@ -444,7 +346,7 @@ public: setPrimaryVarsMeaning(Sw_po_Sg); if (waterEnabled) (*this)[Indices::waterSaturationIdx] = 1.0; - if(not(linearizationType.type == Opm::LinearizationType::seqtransport)){ + if(linearizationType.type != Opm::LinearizationType::seqtransport){ (*this)[Indices::pressureSwitchIdx] = po; } (*this)[Indices::compositionSwitchIdx] = 0.0; // hydrocarbon gas saturation From 2c92bb56248f7fdc33f7c63cfb00c394d01d630d Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Thu, 20 Aug 2020 11:38:23 +0200 Subject: [PATCH 89/93] adapting the changes in eclblackoilintensivequantities.hh against blackoilintensivequantities.hh, preparing for the possible refactoring. --- ebos/eclblackoilintensivequantities.hh | 66 +++++++++++++------------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/ebos/eclblackoilintensivequantities.hh b/ebos/eclblackoilintensivequantities.hh index 6b9640ce313..cddb54bb2d8 100644 --- a/ebos/eclblackoilintensivequantities.hh +++ b/ebos/eclblackoilintensivequantities.hh @@ -47,28 +47,28 @@ class EclBlackOilIntensiveQuantities , public BlackOilBrineIntensiveQuantities , public BlackOilEnergyIntensiveQuantities { - typedef typename GET_PROP_TYPE(TypeTag, DiscIntensiveQuantities) ParentType; - typedef typename GET_PROP_TYPE(TypeTag, IntensiveQuantities) Implementation; - - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, Evaluation) Evaluation; - typedef typename GET_PROP_TYPE(TypeTag, FluidSystem) FluidSystem; - typedef typename GET_PROP_TYPE(TypeTag, MaterialLaw) MaterialLaw; - typedef typename GET_PROP_TYPE(TypeTag, ElementContext) ElementContext; - typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; - typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; - typedef typename GET_PROP_TYPE(TypeTag, GridView) GridView; - typedef typename GET_PROP_TYPE(TypeTag, FluxModule) FluxModule; - - enum { numEq = GET_PROP_VALUE(TypeTag, NumEq) }; - enum { enableSolvent = GET_PROP_VALUE(TypeTag, EnableSolvent) }; - enum { enablePolymer = GET_PROP_VALUE(TypeTag, EnablePolymer) }; - enum { enableFoam = GET_PROP_VALUE(TypeTag, EnableFoam) }; - enum { enableBrine = GET_PROP_VALUE(TypeTag, EnableBrine) }; - enum { enableTemperature = GET_PROP_VALUE(TypeTag, EnableTemperature) }; - enum { enableEnergy = GET_PROP_VALUE(TypeTag, EnableEnergy) }; - enum { numPhases = GET_PROP_VALUE(TypeTag, NumPhases) }; - enum { numComponents = GET_PROP_VALUE(TypeTag, NumComponents) }; + using ParentType = GetPropType; + using Implementation = GetPropType; + + using Scalar = GetPropType; + using Evaluation = GetPropType; + using FluidSystem = GetPropType; + using MaterialLaw = GetPropType; + using ElementContext = GetPropType; + using PrimaryVariables = GetPropType; + using Indices = GetPropType; + using GridView = GetPropType; + using FluxModule = GetPropType; + + enum { numEq = getPropValue() }; + enum { enableSolvent = getPropValue() }; + enum { enablePolymer = getPropValue() }; + enum { enableFoam = getPropValue() }; + enum { enableBrine = getPropValue() }; + enum { enableTemperature = getPropValue() }; + enum { enableEnergy = getPropValue() }; + enum { numPhases = getPropValue() }; + enum { numComponents = getPropValue() }; enum { waterCompIdx = FluidSystem::waterCompIdx }; enum { oilCompIdx = FluidSystem::oilCompIdx }; enum { gasCompIdx = FluidSystem::gasCompIdx }; @@ -81,10 +81,10 @@ class EclBlackOilIntensiveQuantities static const bool compositionSwitchEnabled = Indices::gasEnabled; static const bool waterEnabled = Indices::waterEnabled; - typedef Opm::MathToolbox Toolbox; - typedef Dune::FieldMatrix DimMatrix; - typedef typename FluxModule::FluxIntensiveQuantities FluxIntensiveQuantities; - typedef Opm::BlackOilFluidState FluidState; + using Toolbox = Opm::MathToolbox; + using DimMatrix = Dune::FieldMatrix; + using FluxIntensiveQuantities = typename FluxModule::FluxIntensiveQuantities; + using FluidState = Opm::BlackOilFluidState; public: EclBlackOilIntensiveQuantities() @@ -105,6 +105,7 @@ public: void update(const ElementContext& elemCtx, unsigned dofIdx, unsigned timeIdx) { ParentType::update(elemCtx, dofIdx, timeIdx); + const auto& problem = elemCtx.problem(); const auto& priVars = elemCtx.primaryVars(dofIdx, timeIdx); @@ -186,15 +187,15 @@ public: if (enableSolvent) So -= priVars.makeEvaluation(Indices::solventSaturationIdx, timeIdx, linearizationType); - if (FluidSystem::phaseIsActive(waterPhaseIdx)){ + if (FluidSystem::phaseIsActive(waterPhaseIdx)) fluidState_.setSaturation(waterPhaseIdx, Sw); - } - if (FluidSystem::phaseIsActive(gasPhaseIdx)){ + + if (FluidSystem::phaseIsActive(gasPhaseIdx)) fluidState_.setSaturation(gasPhaseIdx, Sg); - } - if (FluidSystem::phaseIsActive(oilPhaseIdx)){ + + if (FluidSystem::phaseIsActive(oilPhaseIdx)) fluidState_.setSaturation(oilPhaseIdx, So); - } + asImp_().solventPreSatFuncUpdate_(elemCtx, dofIdx, timeIdx); // now we compute all phase pressures @@ -444,6 +445,7 @@ public: if (FluidSystem::phaseIsActive(oilPhaseIdx)) { x = rockCompressibility*(fluidState_.pressure(oilPhaseIdx) - rockRefPressure); } else if (FluidSystem::phaseIsActive(waterPhaseIdx)){ + x = rockCompressibility*(fluidState_.pressure(waterPhaseIdx) - rockRefPressure); } else { x = rockCompressibility*(fluidState_.pressure(gasPhaseIdx) - rockRefPressure); } From bd70a6bea76d7e573d5a9efd31beea0286e99e3f Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Fri, 21 Aug 2020 09:21:21 +0200 Subject: [PATCH 90/93] adding output of the well convergence information for debugging purpose. it will be cleaned up when merging. --- .../wells/BlackoilWellModel_impl.hpp | 39 ++++++++++++++++++- opm/simulators/wells/MultisegmentWell.hpp | 4 +- .../wells/MultisegmentWell_impl.hpp | 10 +++-- opm/simulators/wells/StandardWell.hpp | 1 + opm/simulators/wells/StandardWell_impl.hpp | 22 +++++------ opm/simulators/wells/WellInterface.hpp | 4 +- 6 files changed, 63 insertions(+), 17 deletions(-) diff --git a/opm/simulators/wells/BlackoilWellModel_impl.hpp b/opm/simulators/wells/BlackoilWellModel_impl.hpp index 08c895d84ab..b417d8ca4f2 100644 --- a/opm/simulators/wells/BlackoilWellModel_impl.hpp +++ b/opm/simulators/wells/BlackoilWellModel_impl.hpp @@ -24,6 +24,9 @@ #include #include #include + +#include + namespace Opm { template BlackoilWellModel:: @@ -1122,11 +1125,23 @@ namespace Opm { Opm::DeferredLogger local_deferredLogger; // Get global (from all processes) convergence report. ConvergenceReport local_report; + std::vector residuals(B_avg.size() + 1, 0.); for (const auto& well : well_container_) { if (well->isOperable() ) { - local_report += well->getWellConvergence(well_state_, B_avg, local_deferredLogger); + local_report += well->getWellConvergence(well_state_, B_avg, local_deferredLogger, residuals); + } + } + + ebosSimulator_.vanguard().grid().comm().max(residuals.data(), residuals.size()); + if (terminal_output_) { + std::stringstream ss; + ss << "Well residuals: "; + for (const auto& res : residuals) { + ss << " " << std::setw(12) << res; } + OpmLog::info(ss.str()); } + Opm::DeferredLogger global_deferredLogger = gatherDeferredLogger(local_deferredLogger); if (terminal_output_) { global_deferredLogger.logMessages(); @@ -1136,12 +1151,29 @@ namespace Opm { // Log debug messages for NaN or too large residuals. if (terminal_output_) { + std::stringstream ss; + if ( !report.wellFailures().empty() ) { + ss << "UNCONVERGED WELLS: "; + } + std::vector failed_wells; for (const auto& f : report.wellFailures()) { if (f.severity() == ConvergenceReport::Severity::NotANumber) { OpmLog::debug("NaN residual found with phase " + std::to_string(f.phase()) + " for well " + f.wellName()); } else if (f.severity() == ConvergenceReport::Severity::TooLarge) { OpmLog::debug("Too large residual found with phase " + std::to_string(f.phase()) + " for well " + f.wellName()); } + failed_wells.push_back(f.wellName()); + } + // for more complicated situation, a sorting might be needed + const auto last = std::unique(failed_wells.begin(), failed_wells.end()); + failed_wells.erase(last, failed_wells.end()); + + for (const auto& w : failed_wells) { + ss << " " << w; + } + + if ( !report.wellFailures().empty() ) { + OpmLog::info(ss.str()); } } @@ -1151,6 +1183,11 @@ namespace Opm { bool violated = checkGroupConstraints(fieldGroup, global_deferredLogger); report.setGroupConverged(!violated); } + if (terminal_output_) { + if (report.converged()) { + OpmLog::info(" the well equations are converged "); + } + } return report; } diff --git a/opm/simulators/wells/MultisegmentWell.hpp b/opm/simulators/wells/MultisegmentWell.hpp index a09921fd2b0..d641e7bca1f 100644 --- a/opm/simulators/wells/MultisegmentWell.hpp +++ b/opm/simulators/wells/MultisegmentWell.hpp @@ -128,7 +128,9 @@ namespace Opm Opm::DeferredLogger& deferred_logger) const override; /// check whether the well equations get converged for this well - virtual ConvergenceReport getWellConvergence(const WellState& well_state, const std::vector& B_avg, Opm::DeferredLogger& deferred_logger, const bool relax_tolerance = false) const override; + virtual ConvergenceReport getWellConvergence(const WellState& well_state, const std::vector& B_avg, + Opm::DeferredLogger& deferred_logger, std::vector& residual, + const bool relax_tolerance = false) const override; /// Ax = Ax - C D^-1 B x virtual void apply(const BVector& x, BVector& Ax) const override; diff --git a/opm/simulators/wells/MultisegmentWell_impl.hpp b/opm/simulators/wells/MultisegmentWell_impl.hpp index f12d3dfac24..eb06cdf9fd9 100644 --- a/opm/simulators/wells/MultisegmentWell_impl.hpp +++ b/opm/simulators/wells/MultisegmentWell_impl.hpp @@ -539,7 +539,9 @@ namespace Opm template ConvergenceReport MultisegmentWell:: - getWellConvergence(const WellState& well_state, const std::vector& B_avg, Opm::DeferredLogger& deferred_logger, const bool relax_tolerance) const + getWellConvergence(const WellState& well_state, const std::vector& B_avg, + Opm::DeferredLogger& deferred_logger, std::vector& /* residual */, + const bool relax_tolerance) const { assert(int(B_avg.size()) == num_components_); @@ -2401,7 +2403,8 @@ namespace Opm if (it > param_.strict_inner_iter_ms_wells_) relax_convergence = true; - const auto report = getWellConvergence(well_state, B_avg, deferred_logger, relax_convergence); + std::vector residual; + const auto report = getWellConvergence(well_state, B_avg, deferred_logger, residual, relax_convergence); if (report.converged()) { converged = true; break; @@ -2425,7 +2428,8 @@ namespace Opm ++stagnate_count; if (stagnate_count == 6) { sstr << " well " << name() << " observes severe stagnation and/or oscillation. We relax the tolerance and check for convergence. \n"; - const auto reportStag = getWellConvergence(well_state, B_avg, deferred_logger, true); + std::vector temp_residual(numWellEq, 0.); + const auto reportStag = getWellConvergence(well_state, B_avg, deferred_logger, temp_residual, true); if (reportStag.converged()) { converged = true; sstr << " well " << name() << " manages to get converged with relaxed tolerances in " << it << " inner iterations"; diff --git a/opm/simulators/wells/StandardWell.hpp b/opm/simulators/wells/StandardWell.hpp index 2d68332a313..0a1451848f0 100644 --- a/opm/simulators/wells/StandardWell.hpp +++ b/opm/simulators/wells/StandardWell.hpp @@ -180,6 +180,7 @@ namespace Opm virtual ConvergenceReport getWellConvergence(const WellState& well_state, const std::vector& B_avg, Opm::DeferredLogger& deferred_logger, + std::vector& residual, const bool relax_tolerance = false) const override; /// Ax = Ax - C D^-1 B x diff --git a/opm/simulators/wells/StandardWell_impl.hpp b/opm/simulators/wells/StandardWell_impl.hpp index 062414ed615..d27d88ffa2c 100644 --- a/opm/simulators/wells/StandardWell_impl.hpp +++ b/opm/simulators/wells/StandardWell_impl.hpp @@ -2174,11 +2174,13 @@ namespace Opm getWellConvergence(const WellState& well_state, const std::vector& B_avg, Opm::DeferredLogger& deferred_logger, + std::vector& residual, const bool /*relax_tolerance*/) const { // the following implementation assume that the polymer is always after the w-o-g phases // For the polymer, energy and foam cases, there is one more mass balance equations of reservoir than wells assert((int(B_avg.size()) == num_components_) || has_polymer || has_energy || has_foam || has_brine); + assert( int(residual.size()) == numWellEq_ ); const double tol_wells = param_.tolerance_wells_; const double maxResidualAllowed = param_.max_residual_allowed_; @@ -2195,6 +2197,13 @@ namespace Opm for ( int compIdx = 0; compIdx < num_components_; ++compIdx ) { well_flux_residual[compIdx] = B_avg[compIdx] * res[compIdx]; + if (well_flux_residual[compIdx] > residual[compIdx]) { + residual[compIdx] = well_flux_residual[compIdx]; + } + } + + if (res[Bhp] > residual[Bhp]) { + residual[Bhp] = res[Bhp]; } ConvergenceReport report; @@ -2222,16 +2231,6 @@ namespace Opm checkConvergenceExtraEqs(res, report); - if ( !report.converged() ) { - std::stringstream ss; - ss << "UNCONVERGED WELL: " << name() << " residual "; - for ( int compIdx = 0; compIdx < num_components_; ++compIdx ) { - ss << std::setw(12) << well_flux_residual[compIdx]; - } - ss << std::setw(15) << res[this->numWellEq_ - 1]; - deferred_logger.info(ss.str()); - } - return report; } @@ -4042,7 +4041,8 @@ namespace Opm do { assembleWellEqWithoutIteration(ebosSimulator, dt, inj_controls, prod_controls, well_state, deferred_logger); - auto report = getWellConvergence(well_state, B_avg, deferred_logger); + std::vector residual(B_avg.size() + 1, 0.); + auto report = getWellConvergence(well_state, B_avg,deferred_logger, residual); converged = report.converged(); if (converged) { diff --git a/opm/simulators/wells/WellInterface.hpp b/opm/simulators/wells/WellInterface.hpp index 308c052873a..91feff3abaf 100644 --- a/opm/simulators/wells/WellInterface.hpp +++ b/opm/simulators/wells/WellInterface.hpp @@ -157,7 +157,9 @@ namespace Opm virtual void initPrimaryVariablesEvaluation() const = 0; - virtual ConvergenceReport getWellConvergence(const WellState& well_state, const std::vector& B_avg, Opm::DeferredLogger& deferred_logger, const bool relax_tolerance = false) const = 0; + virtual ConvergenceReport getWellConvergence(const WellState& well_state, const std::vector& B_avg, + Opm::DeferredLogger& deferred_logger, std::vector& residual, + const bool relax_tolerance = false) const = 0; virtual void solveEqAndUpdateWellState(WellState& well_state, Opm::DeferredLogger& deferred_logger) = 0; From b751342dd442a7e0847b58644467dd4f0174b0da Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Fri, 21 Aug 2020 11:01:18 +0200 Subject: [PATCH 91/93] cleaning up EclBlackOilNewtonMethod it looks like there are only a few lines different from BlackOilNewtonMethod --- ebos/eclblackoilnewtonmethod.hh | 24 +++++++++---------- .../flow/BlackoilModelParametersEbos.hpp | 10 ++++---- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/ebos/eclblackoilnewtonmethod.hh b/ebos/eclblackoilnewtonmethod.hh index 8db0a487fd1..67f0c26e39e 100644 --- a/ebos/eclblackoilnewtonmethod.hh +++ b/ebos/eclblackoilnewtonmethod.hh @@ -38,19 +38,19 @@ namespace Opm { * \brief A newton solver which is specific to the black oil model. */ template -class EclBlackOilNewtonMethod : public GET_PROP_TYPE(TypeTag, DiscNewtonMethod) +class EclBlackOilNewtonMethod : public GetPropType { - typedef typename GET_PROP_TYPE(TypeTag, DiscNewtonMethod) ParentType; - typedef typename GET_PROP_TYPE(TypeTag, Simulator) Simulator; - typedef typename GET_PROP_TYPE(TypeTag, SolutionVector) SolutionVector; - typedef typename GET_PROP_TYPE(TypeTag, GlobalEqVector) GlobalEqVector; - typedef typename GET_PROP_TYPE(TypeTag, PrimaryVariables) PrimaryVariables; - typedef typename GET_PROP_TYPE(TypeTag, EqVector) EqVector; - typedef typename GET_PROP_TYPE(TypeTag, Indices) Indices; - typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; - typedef typename GET_PROP_TYPE(TypeTag, Linearizer) Linearizer; - - static const unsigned numEq = GET_PROP_VALUE(TypeTag, NumEq); + using ParentType = GetPropType; + using Simulator = GetPropType; + using SolutionVector = GetPropType; + using GlobalEqVector = GetPropType; + using PrimaryVariables = GetPropType; + using EqVector = GetPropType; + using Indices = GetPropType; + using Scalar = GetPropType; + using Linearizer = GetPropType; + + static const unsigned numEq = getPropValue(); public: EclBlackOilNewtonMethod(Simulator& simulator) : ParentType(simulator) diff --git a/opm/simulators/flow/BlackoilModelParametersEbos.hpp b/opm/simulators/flow/BlackoilModelParametersEbos.hpp index 8c378a05581..7c3097c5710 100644 --- a/opm/simulators/flow/BlackoilModelParametersEbos.hpp +++ b/opm/simulators/flow/BlackoilModelParametersEbos.hpp @@ -216,7 +216,7 @@ namespace Opm // name of json file for pressure setup std::string pressure_solver_json_; /// Construct from user parameters or defaults. - + BlackoilModelParametersEbos() { dbhp_max_rel_= EWOMS_GET_PARAM(TypeTag, Scalar, DbhpMaxRel); @@ -255,8 +255,8 @@ namespace Opm tolerance_pressure_ = EWOMS_GET_PARAM(TypeTag, Scalar, TolerancePressure); reuse_pressure_solver_ = EWOMS_GET_PARAM(TypeTag, int, ReusePressureSolver); pressure_solver_json_ = EWOMS_GET_PARAM(TypeTag, std::string,PressureSolverJson); - - + + } static void registerParameters() @@ -288,7 +288,7 @@ namespace Opm EWOMS_REGISTER_PARAM(TypeTag, bool, UseUpdateStabilization, "Try to detect and correct oscillations or stagnation during the Newton method"); EWOMS_REGISTER_PARAM(TypeTag, bool, MatrixAddWellContributions, "Explicitly specify the influences of wells between cells in the Jacobian and preconditioner matrices"); EWOMS_REGISTER_PARAM(TypeTag, bool, EnableWellOperabilityCheck, "Enable the well operability checking"); - + // for sequential EWOMS_REGISTER_PARAM(TypeTag, int, MaxStrictIterSeq, "Maximum number of sequential iterations before relaxed tolerances are used for the CNV convergence criterion"); @@ -297,7 +297,7 @@ namespace Opm EWOMS_REGISTER_PARAM(TypeTag, Scalar, TolerancePressure, "Relaxed local convergence tolerance that applies for iterations after the iterations with the strict tolerance for sequential transport"); EWOMS_REGISTER_PARAM(TypeTag, int, ReusePressureSolver, "Reuse policy for pressure"); EWOMS_REGISTER_PARAM(TypeTag, std::string, PressureSolverJson, "Json setupfile for pressure solver"); - EWOMS_REGISTER_PARAM(TypeTag, std::string, SimulationType, "Define simulation type: default implicit"); + EWOMS_REGISTER_PARAM(TypeTag, std::string, SimulationType, "Define simulation type: implicit, seq, fimseq, pressure"); } }; From 35e2d68ae573f12f08139a8971b2bb5ec9100124 Mon Sep 17 00:00:00 2001 From: hnil Date: Fri, 21 Aug 2020 17:28:04 +0200 Subject: [PATCH 92/93] corrected output of total saturation --- ebos/eclproblem.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ebos/eclproblem.hh b/ebos/eclproblem.hh index 9e26f2f0e80..82de46474ff 100644 --- a/ebos/eclproblem.hh +++ b/ebos/eclproblem.hh @@ -1013,7 +1013,7 @@ public: void writeExtra(){ // Currently, the extra output is only for sequential simulation - if ( EWOMS_GET_PARAM(TypeTag, std::string, SimulationType) != "seq" ) return; + if ( not(EWOMS_GET_PARAM(TypeTag, std::string, SimulationType) == "implicit") ) return; std::string dir = this->simulator().problem().outputDir(); if (dir == ".") { dir = ""; From b1ab757e48d5462dd33882dc6ccc3e20a6b8056e Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Tue, 22 Sep 2020 15:54:30 +0200 Subject: [PATCH 93/93] fixing compilation after merging master. not sure it is totally corect yet, while it fixes the compilation. --- opm/simulators/flow/BlackoilModelEbos.hpp | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/opm/simulators/flow/BlackoilModelEbos.hpp b/opm/simulators/flow/BlackoilModelEbos.hpp index 6c12e0aa09d..afe367fd547 100644 --- a/opm/simulators/flow/BlackoilModelEbos.hpp +++ b/opm/simulators/flow/BlackoilModelEbos.hpp @@ -917,12 +917,6 @@ namespace Opm { typedef std::vector< Scalar > Vector; const double tol_mb = param_.tolerance_mb_; - double tol_cnv; - if(ebosSimulator_.model().linearizer().getLinearizationType().type == Opm::LinearizationType::seqtransport){ - tol_cnv = (iteration < param_.max_strict_iter_seq_) ? param_.tolerance_cnv_seq_ : param_.tolerance_cnv_relaxed_seq_; - }else{ - tol_cnv = (iteration < param_.max_strict_iter_) ? param_.tolerance_cnv_ : param_.tolerance_cnv_relaxed_; - } const int numComp = numEq; Vector R_sum(numComp, 0.0 ); @@ -936,13 +930,20 @@ namespace Opm { auto cnvErrorPvFraction = computeCnvErrorPv(B_avg, dt); cnvErrorPvFraction /= pvSum; - const double tol_mb = param_.tolerance_mb_; // Default value of relaxed_max_pv_fraction_ is 1 and // max_strict_iter_ is 8. Hence only iteration chooses // whether to use relaxed or not. // To activate only fraction use fraction below 1 and iter 0. - const bool use_relaxed = cnvErrorPvFraction < param_.relaxed_max_pv_fraction_ && iteration >= param_.max_strict_iter_; - const double tol_cnv = use_relaxed ? param_.tolerance_cnv_relaxed_ : param_.tolerance_cnv_; + const bool use_relaxed = cnvErrorPvFraction < param_.relaxed_max_pv_fraction_ && iteration >= param_.max_strict_iter_; + + // const double tol_cnv = use_relaxed ? param_.tolerance_cnv_relaxed_ : param_.tolerance_cnv_; + double tol_cnv; + if(ebosSimulator_.model().linearizer().getLinearizationType().type == Opm::LinearizationType::seqtransport){ + // TODO: maybe this one also should change to use_relaxed + tol_cnv = (iteration < param_.max_strict_iter_seq_) ? param_.tolerance_cnv_seq_ : param_.tolerance_cnv_relaxed_seq_; + }else{ + tol_cnv = use_relaxed ? param_.tolerance_cnv_ : param_.tolerance_cnv_relaxed_; + } // Finish computation std::vector CNV(numComp);