Merge pull request #1730 from fgfuchs/exception_handling_in_wells_for_parallel_runs

correct exception handling in wells for parallel runs
This commit is contained in:
Atgeirr Flø Rasmussen 2019-03-13 15:40:36 +01:00 committed by GitHub
commit 569ee02622
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 712 additions and 494 deletions

View File

@ -174,6 +174,7 @@ list (APPEND PUBLIC_HEADER_FILES
opm/core/wells/WellsManager.hpp
opm/core/wells/WellsManager_impl.hpp
opm/simulators/ParallelFileMerger.hpp
opm/simulators/DeferredLoggingErrorHelpers.hpp
opm/simulators/DeferredLogger.hpp
opm/simulators/timestepping/AdaptiveSimulatorTimer.hpp
opm/simulators/timestepping/AdaptiveTimeSteppingEbos.hpp

View File

@ -290,9 +290,9 @@ namespace Opm {
std::vector<bool> is_cell_perforated_;
// create the well container
std::vector<WellInterfacePtr > createWellContainer(const int time_step);
std::vector<WellInterfacePtr > createWellContainer(const int time_step, Opm::DeferredLogger& deferred_logger);
WellInterfacePtr createWellForWellTest(const std::string& well_name, const int report_step) const;
WellInterfacePtr createWellForWellTest(const std::string& well_name, const int report_step, Opm::DeferredLogger& deferred_logger) const;
WellState well_state_;
WellState previous_well_state_;
@ -346,16 +346,16 @@ namespace Opm {
// xw to update Well State
void recoverWellSolutionAndUpdateWellState(const BVector& x);
void updateWellControls();
void updateWellControls(Opm::DeferredLogger& deferred_logger);
void updateGroupControls(Opm::DeferredLogger& deferred_logger);
// setting the well_solutions_ based on well_state.
void updatePrimaryVariables();
void updatePrimaryVariables(Opm::DeferredLogger& deferred_logger);
void setupCartesianToCompressed_(const int* global_cell, int number_of_cells);
void computeRepRadiusPerfLength(const Grid& grid);
void computeRepRadiusPerfLength(const Grid& grid, Opm::DeferredLogger& deferred_logger);
void computeAverageFormationFactor(std::vector<double>& B_avg) const;
@ -366,7 +366,7 @@ namespace Opm {
std::vector<double>& voidage_conversion_coeffs) const;
// Calculating well potentials for each well
void computeWellPotentials(std::vector<double>& well_potentials);
void computeWellPotentials(std::vector<double>& well_potentials, Opm::DeferredLogger& deferred_logger);
const std::vector<double>& wellPerfEfficiencyFactors() const;
@ -377,7 +377,7 @@ namespace Opm {
// twice at the beginning of the time step
/// Calculating the explict quantities used in the well calculation. By explicit, we mean they are cacluated
/// at the beginning of the time step and no derivatives are included in these quantities
void calculateExplicitQuantities() const;
void calculateExplicitQuantities(Opm::DeferredLogger& deferred_logger) const;
SimulatorReport solveWellEq(const double dt, Opm::DeferredLogger& deferred_logger);
@ -398,9 +398,9 @@ namespace Opm {
// at the beginning of each time step (Not report step)
void prepareTimeStep(Opm::DeferredLogger& deferred_logger);
void prepareGroupControl();
void prepareGroupControl(Opm::DeferredLogger& deferred_logger);
void computeRESV(const std::size_t step);
void computeRESV(const std::size_t step, Opm::DeferredLogger& deferred_logger);
void extractLegacyCellPvtRegionIndex_();
@ -419,7 +419,7 @@ namespace Opm {
void updatePerforationIntensiveQuantities();
void wellTesting(const int timeStepIdx, const double simulationTime);
void wellTesting(const int timeStepIdx, const double simulationTime, Opm::DeferredLogger& deferred_logger);
// convert well data from opm-common to well state from opm-core
void wellsToState( const data::Wells& wells,

View File

@ -1,5 +1,26 @@
/*
Copyright 2016 - 2019 SINTEF Digital, Mathematics & Cybernetics.
Copyright 2016 - 2018 Equinor ASA.
Copyright 2017 Dr. Blatt - HPC-Simulation-Software & Services
Copyright 2016 - 2018 Norce 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 <http://www.gnu.org/licenses/>.
*/
#include <opm/simulators/DeferredLoggingErrorHelpers.hpp>
namespace Opm {
template<typename TypeTag>
@ -146,18 +167,23 @@ namespace Opm {
forceShutWellByNameIfPredictionMode(const std::string& wellname,
const double simulation_time)
{
Opm::DeferredLogger local_deferredLogger;
// Only add the well to the closed list on the
// process that owns it.
int well_was_shut = 0;
for (const auto& well : well_container_) {
if (well->name() == wellname) {
if (well->underPredictionMode()) {
if (well->underPredictionMode(local_deferredLogger)) {
wellTestState_.addClosedWell(wellname, WellTestConfig::Reason::PHYSICAL, simulation_time);
well_was_shut = 1;
}
break;
}
}
Opm::DeferredLogger global_deferredLogger = gatherDeferredLogger(local_deferredLogger);
if (terminal_output_) {
global_deferredLogger.logMessages();
}
// Communicate across processes if a well was shut.
well_was_shut = ebosSimulator_.vanguard().grid().comm().max(well_was_shut);
@ -180,6 +206,8 @@ namespace Opm {
BlackoilWellModel<TypeTag>::
beginReportStep(const int timeStepIdx)
{
Opm::DeferredLogger local_deferredLogger;
const Grid& grid = ebosSimulator_.vanguard().grid();
const auto& defunct_well_names = ebosSimulator_.vanguard().defunctWellNames();
const auto& eclState = ebosSimulator_.vanguard().eclState();
@ -249,15 +277,20 @@ namespace Opm {
// Compute reservoir volumes for RESV controls.
rateConverter_.reset(new RateConverterType (phase_usage_,
std::vector<int>(number_of_cells_, 0)));
computeRESV(timeStepIdx);
int exception_thrown = 0;
try {
computeRESV(timeStepIdx, local_deferredLogger);
} catch (const std::exception& e){
exception_thrown = 1;
}
logAndCheckForExceptionsAndThrow(local_deferredLogger, exception_thrown, "beginReportStep() failed.", terminal_output_);
// update VFP properties
vfp_properties_.reset (new VFPProperties<VFPInjProperties,VFPProdProperties> (
schedule().getVFPInjTables(timeStepIdx),
schedule().getVFPProdTables(timeStepIdx)) );
}
@ -266,41 +299,51 @@ namespace Opm {
void
BlackoilWellModel<TypeTag>::
beginTimeStep() {
Opm::DeferredLogger local_deferredLogger;
well_state_ = previous_well_state_;
const int reportStepIdx = ebosSimulator_.episodeIndex();
const double simulationTime = ebosSimulator_.time();
// test wells
wellTesting(reportStepIdx, simulationTime);
int exception_thrown = 0;
try {
// test wells
wellTesting(reportStepIdx, simulationTime, local_deferredLogger);
// create the well container
well_container_ = createWellContainer(reportStepIdx);
// create the well container
well_container_ = createWellContainer(reportStepIdx, local_deferredLogger);
// do the initialization for all the wells
// TODO: to see whether we can postpone of the intialization of the well containers to
// optimize the usage of the following several member variables
for (auto& well : well_container_) {
well->init(&phase_usage_, depth_, gravity_, number_of_cells_);
}
// update the updated cell flag
std::fill(is_cell_perforated_.begin(), is_cell_perforated_.end(), false);
for (auto& well : well_container_) {
well->updatePerforatedCell(is_cell_perforated_);
}
// calculate the efficiency factors for each well
calculateEfficiencyFactors();
if (has_polymer_)
{
const Grid& grid = ebosSimulator_.vanguard().grid();
if (PolymerModule::hasPlyshlog() || GET_PROP_VALUE(TypeTag, EnablePolymerMW) ) {
computeRepRadiusPerfLength(grid);
// do the initialization for all the wells
// TODO: to see whether we can postpone of the intialization of the well containers to
// optimize the usage of the following several member variables
for (auto& well : well_container_) {
well->init(&phase_usage_, depth_, gravity_, number_of_cells_);
}
// update the updated cell flag
std::fill(is_cell_perforated_.begin(), is_cell_perforated_.end(), false);
for (auto& well : well_container_) {
well->updatePerforatedCell(is_cell_perforated_);
}
// calculate the efficiency factors for each well
calculateEfficiencyFactors();
if (has_polymer_)
{
const Grid& grid = ebosSimulator_.vanguard().grid();
if (PolymerModule::hasPlyshlog() || GET_PROP_VALUE(TypeTag, EnablePolymerMW) ) {
computeRepRadiusPerfLength(grid, local_deferredLogger);
}
}
} catch (std::exception& e) {
exception_thrown = 1;
}
logAndCheckForExceptionsAndThrow(local_deferredLogger, exception_thrown, "beginTimeStep() failed.", terminal_output_);
for (auto& well : well_container_) {
well->setVFPProperties(vfp_properties_.get());
}
@ -315,8 +358,7 @@ namespace Opm {
template<typename TypeTag>
void
BlackoilWellModel<TypeTag>::wellTesting(const int timeStepIdx, const double simulationTime) {
Opm::DeferredLogger local_deferredLogger;
BlackoilWellModel<TypeTag>::wellTesting(const int timeStepIdx, const double simulationTime, Opm::DeferredLogger& deferred_logger) {
const auto& wtest_config = schedule().wtestConfig(timeStepIdx);
if (wtest_config.size() != 0) { // there is a WTEST request
@ -331,7 +373,7 @@ namespace Opm {
const std::string& well_name = testWell.first;
// this is the well we will test
WellInterfacePtr well = createWellForWellTest(well_name, timeStepIdx);
WellInterfacePtr well = createWellForWellTest(well_name, timeStepIdx, deferred_logger);
// some preparation before the well can be used
well->init(&phase_usage_, depth_, gravity_, number_of_cells_);
@ -343,13 +385,9 @@ namespace Opm {
const WellTestConfig::Reason testing_reason = testWell.second;
well->wellTesting(ebosSimulator_, B_avg, simulationTime, timeStepIdx,
testing_reason, well_state_, wellTestState_, local_deferredLogger);
testing_reason, well_state_, wellTestState_, deferred_logger);
}
}
Opm::DeferredLogger global_deferredLogger = gatherDeferredLogger(local_deferredLogger);
if (terminal_output_) {
global_deferredLogger.logMessages();
}
}
// called at the end of a report step
@ -384,13 +422,10 @@ namespace Opm {
// calculate the well potentials for output
// TODO: when necessary
try
{
try {
std::vector<double> well_potentials;
computeWellPotentials(well_potentials);
}
catch ( std::runtime_error& e )
{
computeWellPotentials(well_potentials, local_deferredLogger);
} catch ( std::runtime_error& e ) {
const std::string msg = "A zero well potential is returned for output purposes. ";
local_deferredLogger.warning("WELL_POTENTIAL_CALCULATION_FAILED", msg);
}
@ -481,7 +516,7 @@ namespace Opm {
template<typename TypeTag>
std::vector<typename BlackoilWellModel<TypeTag>::WellInterfacePtr >
BlackoilWellModel<TypeTag>::
createWellContainer(const int time_step)
createWellContainer(const int time_step, Opm::DeferredLogger& deferred_logger)
{
std::vector<WellInterfacePtr> well_container;
@ -506,7 +541,7 @@ namespace Opm {
// It should be able to find in wells_ecl.
if (index_well == nw_wells_ecl) {
OPM_THROW(std::logic_error, "Could not find well " << well_name << " in wells_ecl ");
OPM_DEFLOG_THROW(std::runtime_error, "Could not find well " + well_name + " in wells_ecl ", deferred_logger);
}
const Well* well_ecl = wells_ecl_[index_well];
@ -567,6 +602,7 @@ namespace Opm {
}
}
}
return well_container;
}
@ -578,7 +614,8 @@ namespace Opm {
typename BlackoilWellModel<TypeTag>::WellInterfacePtr
BlackoilWellModel<TypeTag>::
createWellForWellTest(const std::string& well_name,
const int report_step) const
const int report_step,
Opm::DeferredLogger& deferred_logger) const
{
// Finding the location of the well in wells_ecl
const int nw_wells_ecl = wells_ecl_.size();
@ -590,7 +627,7 @@ namespace Opm {
}
// It should be able to find in wells_ecl.
if (index_well_ecl == nw_wells_ecl) {
OPM_THROW(std::logic_error, "Could not find well " << well_name << " in wells_ecl ");
OPM_DEFLOG_THROW(std::logic_error, "Could not find well " << well_name << " in wells_ecl ", deferred_logger);
}
const Well* well_ecl = wells_ecl_[index_well_ecl];
@ -606,7 +643,7 @@ namespace Opm {
}
if (well_index_wells < 0) {
OPM_THROW(std::logic_error, "Could not find the well " << well_name << " in the well struct ");
OPM_DEFLOG_THROW(std::logic_error, "Could not find the well " << well_name << " in the well struct ", deferred_logger);
}
// Use the pvtRegionIdx from the top cell
@ -643,45 +680,42 @@ namespace Opm {
updatePerforationIntensiveQuantities();
if (iterationIdx == 0) {
calculateExplicitQuantities();
prepareTimeStep(local_deferredLogger);
}
updateWellControls();
// Set the well primary variables based on the value of well solutions
initPrimaryVariablesEvaluation();
if (param_.solve_welleq_initially_ && iterationIdx == 0) {
// solve the well equations as a pre-processing step
last_report_ = solveWellEq(dt, local_deferredLogger);
if (initial_step_) {
// update the explicit quantities to get the initial fluid distribution in the well correct.
calculateExplicitQuantities();
int exception_thrown = 0;
try {
if (iterationIdx == 0) {
calculateExplicitQuantities(local_deferredLogger);
prepareTimeStep(local_deferredLogger);
last_report_ = solveWellEq(dt, local_deferredLogger);
initial_step_ = false;
}
// TODO: should we update the explicit related here again, or even prepareTimeStep().
// basically, this is a more updated state from the solveWellEq based on fixed
// reservoir state, will tihs be a better place to inialize the explict information?
}
assembleWellEq(dt, local_deferredLogger);
Opm::DeferredLogger global_deferredLogger = gatherDeferredLogger(local_deferredLogger);
if (terminal_output_) {
global_deferredLogger.logMessages();
}
updateWellControls(local_deferredLogger);
// Set the well primary variables based on the value of well solutions
initPrimaryVariablesEvaluation();
if (param_.solve_welleq_initially_ && iterationIdx == 0) {
// solve the well equations as a pre-processing step
last_report_ = solveWellEq(dt, local_deferredLogger);
if (initial_step_) {
// update the explicit quantities to get the initial fluid distribution in the well correct.
calculateExplicitQuantities(local_deferredLogger);
prepareTimeStep(local_deferredLogger);
last_report_ = solveWellEq(dt, local_deferredLogger);
initial_step_ = false;
}
// TODO: should we update the explicit related here again, or even prepareTimeStep().
// basically, this is a more updated state from the solveWellEq based on fixed
// reservoir state, will tihs be a better place to inialize the explict information?
}
assembleWellEq(dt, local_deferredLogger);
} catch (std::exception& e) {
exception_thrown = 1;
}
logAndCheckForExceptionsAndThrow(local_deferredLogger, exception_thrown, "assemble() failed.", terminal_output_);
last_report_.converged = true;
}
template<typename TypeTag>
void
BlackoilWellModel<TypeTag>::
@ -757,12 +791,19 @@ namespace Opm {
BlackoilWellModel<TypeTag>::
recoverWellSolutionAndUpdateWellState(const BVector& x)
{
if (!localWellsActive())
return;
Opm::DeferredLogger local_deferredLogger;
for (auto& well : well_container_) {
well->recoverWellSolutionAndUpdateWellState(x, well_state_);
int exception_thrown = 0;
try {
if (localWellsActive()) {
for (auto& well : well_container_) {
well->recoverWellSolutionAndUpdateWellState(x, well_state_, local_deferredLogger);
}
}
} catch (std::exception& e) {
exception_thrown = 1;
}
logAndCheckForExceptionsAndThrow(local_deferredLogger, exception_thrown, "recoverWellSolutionAndUpdateWellState() failed.", terminal_output_);
}
@ -848,8 +889,15 @@ namespace Opm {
int it = 0;
bool converged;
int exception_thrown = 0;
do {
assembleWellEq(dt, deferred_logger);
try {
assembleWellEq(dt, deferred_logger);
} catch (std::exception& e) {
exception_thrown = 1;
}
// We need to check on all processes, as getWellConvergence() below communicates on all processes.
logAndCheckForExceptionsAndThrow(deferred_logger, exception_thrown, "solveWellEq() failed.", terminal_output_);
const auto report = getWellConvergence(B_avg);
converged = report.converged();
@ -863,42 +911,54 @@ namespace Opm {
break;
}
++it;
if( localWellsActive() )
{
for (auto& well : well_container_) {
well->solveEqAndUpdateWellState(well_state_);
try {
if( localWellsActive() )
{
for (auto& well : well_container_) {
well->solveEqAndUpdateWellState(well_state_, deferred_logger);
}
}
// updateWellControls uses communication
// Therefore the following is executed if there
// are active wells anywhere in the global domain.
if( wellsActive() )
{
updateWellControls(deferred_logger);
initPrimaryVariablesEvaluation();
}
} catch (std::exception& e) {
exception_thrown = 1;
}
// updateWellControls uses communication
// Therefore the following is executed if there
// are active wells anywhere in the global domain.
if( wellsActive() )
{
updateWellControls();
initPrimaryVariablesEvaluation();
}
logAndCheckForExceptionsAndThrow(deferred_logger, exception_thrown, "solveWellEq() failed.", terminal_output_);
++it;
} while (it < max_iter);
if (converged) {
if (terminal_output_) {
deferred_logger.debug("Well equation solution gets converged with " + std::to_string(it) + " iterations");
}
} else {
if (terminal_output_) {
deferred_logger.debug("Well equation solution failed in getting converged with " + std::to_string(it) + " iterations");
}
try {
if (converged) {
if (terminal_output_) {
deferred_logger.debug("Well equation solution gets converged with " + std::to_string(it) + " iterations");
}
} else {
if (terminal_output_) {
deferred_logger.debug("Well equation solution failed in getting converged with " + std::to_string(it) + " iterations");
}
well_state_ = well_state0;
updatePrimaryVariables();
// also recover the old well controls
for (const auto& well : well_container_) {
const int index_of_well = well->indexOfWell();
WellControls* wc = well->wellControls();
well_controls_set_current(wc, well_state_.currentControls()[index_of_well]);
well_state_ = well_state0;
updatePrimaryVariables(deferred_logger);
// also recover the old well controls
for (const auto& well : well_container_) {
const int index_of_well = well->indexOfWell();
WellControls* wc = well->wellControls();
well_controls_set_current(wc, well_state_.currentControls()[index_of_well]);
}
}
} catch (std::exception& e) {
exception_thrown = 1;
}
logAndCheckForExceptionsAndThrow(deferred_logger, exception_thrown, "solveWellEq() failed.", terminal_output_);
SimulatorReport report;
report.converged = converged;
report.total_well_iterations = it;
@ -914,13 +974,21 @@ namespace Opm {
BlackoilWellModel<TypeTag>::
getWellConvergence(const std::vector<Scalar>& B_avg) const
{
Opm::DeferredLogger local_deferredLogger;
// Get global (from all processes) convergence report.
ConvergenceReport local_report;
for (const auto& well : well_container_) {
if (well->isOperable() ) {
local_report += well->getWellConvergence(B_avg);
local_report += well->getWellConvergence(B_avg, local_deferredLogger);
}
}
Opm::DeferredLogger global_deferredLogger = gatherDeferredLogger(local_deferredLogger);
if (terminal_output_) {
global_deferredLogger.logMessages();
}
ConvergenceReport report = gatherConvergenceReport(local_report);
// Log debug messages for NaN or too large residuals.
@ -944,11 +1012,11 @@ namespace Opm {
template<typename TypeTag>
void
BlackoilWellModel<TypeTag>::
calculateExplicitQuantities() const
calculateExplicitQuantities(Opm::DeferredLogger& deferred_logger) const
{
// TODO: checking isOperable() ?
for (auto& well : well_container_) {
well->calculateExplicitQuantities(ebosSimulator_, well_state_);
well->calculateExplicitQuantities(ebosSimulator_, well_state_, deferred_logger);
}
}
@ -959,25 +1027,18 @@ namespace Opm {
template<typename TypeTag>
void
BlackoilWellModel<TypeTag>::
updateWellControls()
updateWellControls(Opm::DeferredLogger& deferred_logger)
{
// 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.
if( !wellsActive() ) return ;
Opm::DeferredLogger local_deferredLogger;
for (const auto& well : well_container_) {
well->updateWellControl(ebosSimulator_, well_state_, local_deferredLogger);
well->updateWellControl(ebosSimulator_, well_state_, deferred_logger);
}
updateGroupControls(local_deferredLogger);
Opm::DeferredLogger global_deferredLogger = gatherDeferredLogger(local_deferredLogger);
if (terminal_output_) {
global_deferredLogger.logMessages();
}
updateGroupControls(deferred_logger);
}
@ -1005,7 +1066,7 @@ namespace Opm {
template<typename TypeTag>
void
BlackoilWellModel<TypeTag>::
computeWellPotentials(std::vector<double>& well_potentials)
computeWellPotentials(std::vector<double>& well_potentials, Opm::DeferredLogger& deferred_logger)
{
Opm::DeferredLogger local_deferredLogger;
// number of wells and phases
@ -1014,35 +1075,35 @@ namespace Opm {
well_potentials.resize(nw * np, 0.0);
const Opm::SummaryConfig& summaryConfig = ebosSimulator_.vanguard().summaryConfig();
for (const auto& well : well_container_) {
// Only compute the well potential when asked for
bool needed_for_output = ((summaryConfig.hasSummaryKey( "WWPI:" + well->name()) ||
summaryConfig.hasSummaryKey( "WOPI:" + well->name()) ||
summaryConfig.hasSummaryKey( "WGPI:" + well->name())) && well->wellType() == INJECTOR) ||
((summaryConfig.hasSummaryKey( "WWPP:" + well->name()) ||
summaryConfig.hasSummaryKey( "WOPP:" + well->name()) ||
summaryConfig.hasSummaryKey( "WGPP:" + well->name())) && well->wellType() == PRODUCER);
if (needed_for_output || wellCollection().requireWellPotentials())
{
std::vector<double> potentials;
well->computeWellPotentials(ebosSimulator_, well_state_, potentials, local_deferredLogger);
// putting the sucessfully calculated potentials to the well_potentials
for (int p = 0; p < np; ++p) {
well_potentials[well->indexOfWell() * np + p] = std::abs(potentials[p]);
int exception_thrown = 0;
try {
for (const auto& well : well_container_) {
// Only compute the well potential when asked for
bool needed_for_output = ((summaryConfig.hasSummaryKey( "WWPI:" + well->name()) ||
summaryConfig.hasSummaryKey( "WOPI:" + well->name()) ||
summaryConfig.hasSummaryKey( "WGPI:" + well->name())) && well->wellType() == INJECTOR) ||
((summaryConfig.hasSummaryKey( "WWPP:" + well->name()) ||
summaryConfig.hasSummaryKey( "WOPP:" + well->name()) ||
summaryConfig.hasSummaryKey( "WGPP:" + well->name())) && well->wellType() == PRODUCER);
if (needed_for_output || wellCollection().requireWellPotentials())
{
std::vector<double> potentials;
well->computeWellPotentials(ebosSimulator_, well_state_, potentials, deferred_logger);
// putting the sucessfully calculated potentials to the well_potentials
for (int p = 0; p < np; ++p) {
well_potentials[well->indexOfWell() * np + p] = std::abs(potentials[p]);
}
}
}
} // end of for (int w = 0; w < nw; ++w)
} // end of for (int w = 0; w < nw; ++w)
} catch (std::exception& e) {
exception_thrown = 1;
}
logAndCheckForExceptionsAndThrow(deferred_logger, exception_thrown, "computeWellPotentials() failed.", terminal_output_);
// Store it in the well state
well_state_.wellPotentials() = well_potentials;
Opm::DeferredLogger global_deferredLogger = gatherDeferredLogger(local_deferredLogger);
if (terminal_output_) {
global_deferredLogger.logMessages();
}
}
@ -1067,37 +1128,42 @@ namespace Opm {
resetWellControlFromState();
// process group control related
prepareGroupControl();
prepareGroupControl(deferred_logger);
for (const auto& well : well_container_) {
well->checkWellOperability(ebosSimulator_, well_state_, deferred_logger);
int exception_thrown = 0;
try {
for (const auto& well : well_container_) {
well->checkWellOperability(ebosSimulator_, well_state_, deferred_logger);
}
// since the controls are all updated, we should update well_state accordingly
for (const auto& well : well_container_) {
const int w = well->indexOfWell();
WellControls* wc = well->wellControls();
const int control = well_controls_get_current(wc);
well_state_.currentControls()[w] = control;
if (!well->isOperable() ) continue;
if (well_state_.effectiveEventsOccurred(w) ) {
well->updateWellStateWithTarget(ebosSimulator_, well_state_, deferred_logger);
}
// there is no new well control change input within a report step,
// so next time step, the well does not consider to have effective events anymore
// TODO: if we can know whether this is the first time step within the report step,
// we do not need to set it to false
// TODO: we should do this at the end of the time step in case we will need it within
// this time step somewhere
if (well_state_.effectiveEventsOccurred(w) ) {
well_state_.setEffectiveEventsOccurred(w, false);
}
} // end of for (const auto& well : well_container_)
updatePrimaryVariables(deferred_logger);
} catch (std::exception& e) {
exception_thrown = 1;
}
// since the controls are all updated, we should update well_state accordingly
for (const auto& well : well_container_) {
const int w = well->indexOfWell();
WellControls* wc = well->wellControls();
const int control = well_controls_get_current(wc);
well_state_.currentControls()[w] = control;
if (!well->isOperable() ) continue;
if (well_state_.effectiveEventsOccurred(w) ) {
well->updateWellStateWithTarget(ebosSimulator_, well_state_, deferred_logger);
}
// there is no new well control change input within a report step,
// so next time step, the well does not consider to have effective events anymore
// TODO: if we can know whether this is the first time step within the report step,
// we do not need to set it to false
// TODO: we should do this at the end of the time step in case we will need it within
// this time step somewhere
if (well_state_.effectiveEventsOccurred(w) ) {
well_state_.setEffectiveEventsOccurred(w, false);
}
} // end of for (const auto& well : well_container_)
updatePrimaryVariables();
logAndCheckForExceptionsAndThrow(deferred_logger, exception_thrown, "prepareTimestep() failed.", terminal_output_);
}
@ -1110,7 +1176,7 @@ namespace Opm {
template<typename TypeTag>
void
BlackoilWellModel<TypeTag>::
prepareGroupControl()
prepareGroupControl(Opm::DeferredLogger& deferred_logger)
{
// group control related processing
if (wellCollection().groupControlActive()) {
@ -1146,7 +1212,7 @@ namespace Opm {
// calculate the well potentials
std::vector<double> well_potentials;
computeWellPotentials(well_potentials);
computeWellPotentials(well_potentials, deferred_logger);
// update/setup guide rates for each well based on the well_potentials
// TODO: this is one of two places that still need Wells struct. In this function, only the well names
@ -1336,7 +1402,7 @@ namespace Opm {
// TODO: we should only do the well is involved in the update group targets
for (auto& well : well_container_) {
well->updateWellStateWithTarget(ebosSimulator_, well_state_, deferred_logger);
well->updatePrimaryVariables(well_state_);
well->updatePrimaryVariables(well_state_, deferred_logger);
}
}
}
@ -1367,10 +1433,10 @@ namespace Opm {
template<typename TypeTag>
void
BlackoilWellModel<TypeTag>::
computeRepRadiusPerfLength(const Grid& grid)
computeRepRadiusPerfLength(const Grid& grid, Opm::DeferredLogger& deferred_logger)
{
for (const auto& well : well_container_) {
well->computeRepRadiusPerfLength(grid, cartesian_to_compressed_);
well->computeRepRadiusPerfLength(grid, cartesian_to_compressed_, deferred_logger);
}
}
@ -1429,10 +1495,10 @@ namespace Opm {
template<typename TypeTag>
void
BlackoilWellModel<TypeTag>::
updatePrimaryVariables()
updatePrimaryVariables(Opm::DeferredLogger& deferred_logger)
{
for (const auto& well : well_container_) {
well->updatePrimaryVariables(well_state_);
well->updatePrimaryVariables(well_state_, deferred_logger);
}
}
@ -1521,7 +1587,7 @@ namespace Opm {
template<typename TypeTag>
void
BlackoilWellModel<TypeTag>::
computeRESV(const std::size_t step)
computeRESV(const std::size_t step, Opm::DeferredLogger& deferred_logger)
{
const std::vector<int>& resv_wells = SimFIBODetails::resvWells(wells());
@ -1574,7 +1640,7 @@ namespace Opm {
const WellMap::const_iterator i = wmap.find(wells()->name[*rp]);
if (i == wmap.end()) {
OPM_THROW(std::runtime_error, "Failed to find the well " << wells()->name[*rp] << " in wmap.");
OPM_DEFLOG_THROW(std::logic_error, "Failed to find the well " << wells()->name[*rp] << " in wmap.", deferred_logger);
}
const auto* wp = i->second;
const WellProductionProperties& production_properties = wp->getProductionProperties(step);

View File

@ -22,6 +22,8 @@
#ifndef OPM_MSWELLHELPERS_HEADER_INCLUDED
#define OPM_MSWELLHELPERS_HEADER_INCLUDED
#include <opm/simulators/DeferredLoggingErrorHelpers.hpp>
#include <opm/simulators/DeferredLogger.hpp>
#include <opm/common/ErrorMacros.hpp>
#include <dune/istl/solvers.hh>
#if HAVE_UMFPACK
@ -62,6 +64,7 @@ namespace mswellhelpers
return y;
#else
// this is not thread safe
OPM_THROW(std::runtime_error, "Cannot use invDXDirect() without UMFPACK. "
"Reconfigure opm-simulator with SuiteSparse/UMFPACK support and recompile.");
#endif // HAVE_UMFPACK
@ -74,7 +77,7 @@ namespace mswellhelpers
// obtain y = D^-1 * x with a BICSSTAB iterative solver
template <typename MatrixType, typename VectorType>
VectorType
invDX(const MatrixType& D, VectorType x)
invDX(const MatrixType& D, VectorType x, Opm::DeferredLogger& deferred_logger)
{
// the function will change the value of x, so we should not use reference of x here.
@ -107,7 +110,7 @@ namespace mswellhelpers
linsolver.apply(y, x, res);
if ( !res.converged ) {
OPM_THROW(Opm::NumericalIssue, "the invDX does not get converged! ");
OPM_DEFLOG_THROW(Opm::NumericalIssue, "the invDX does not get converged! ", deferred_logger);
}
return y;

View File

@ -123,7 +123,7 @@ namespace Opm
Opm::DeferredLogger& deferred_logger) const override;
/// check whether the well equations get converged for this well
virtual ConvergenceReport getWellConvergence(const std::vector<double>& B_avg) const override;
virtual ConvergenceReport getWellConvergence(const std::vector<double>& B_avg, Opm::DeferredLogger& deferred_logger) const override;
/// Ax = Ax - C D^-1 B x
virtual void apply(const BVector& x, BVector& Ax) const override;
@ -133,7 +133,8 @@ namespace Opm
/// using the solution x to recover the solution xw for wells and applying
/// xw to update Well State
virtual void recoverWellSolutionAndUpdateWellState(const BVector& x,
WellState& well_state) const override;
WellState& well_state,
Opm::DeferredLogger& deferred_logger) const override;
/// computing the well potentials for group control
virtual void computeWellPotentials(const Simulator& ebosSimulator,
@ -141,12 +142,13 @@ namespace Opm
std::vector<double>& well_potentials,
Opm::DeferredLogger& deferred_logger) override;
virtual void updatePrimaryVariables(const WellState& well_state) const override;
virtual void updatePrimaryVariables(const WellState& well_state, Opm::DeferredLogger& deferred_logger) const override;
virtual void solveEqAndUpdateWellState(WellState& well_state) override; // const?
virtual void solveEqAndUpdateWellState(WellState& well_state, Opm::DeferredLogger& deferred_logger) override; // const?
virtual void calculateExplicitQuantities(const Simulator& ebosSimulator,
const WellState& well_state) override; // should be const?
const WellState& well_state,
Opm::DeferredLogger& deferred_logger) override; // should be const?
/// number of segments for this well
/// int number_of_segments_;
@ -269,7 +271,8 @@ namespace Opm
// updating the well_state based on well solution dwells
void updateWellState(const BVectorWell& dwells,
const bool inner_iteration,
WellState& well_state) const;
WellState& well_state,
Opm::DeferredLogger& deferred_logger) const;
// initialize the segment rates with well rates
// when there is no more accurate way to initialize the segment rates, we initialize
@ -298,7 +301,8 @@ namespace Opm
const int perf,
const EvalWell& segment_pressure,
const bool& allow_cf,
std::vector<EvalWell>& cq_s) const;
std::vector<EvalWell>& cq_s,
Opm::DeferredLogger& deferred_logger) const;
// convert a Eval from reservoir to contain the derivative related to wells
EvalWell extendEval(const Eval& in) const;
@ -318,7 +322,7 @@ namespace Opm
const int perf,
std::vector<EvalWell>& mob) const;
void assembleControlEq() const;
void assembleControlEq(Opm::DeferredLogger& deferred_logger) const;
void assemblePressureEq(const int seg) const;
@ -348,11 +352,13 @@ namespace Opm
// TODO: try to make ebosSimulator const, as it should be
void iterateWellEquations(const Simulator& ebosSimulator,
const double dt,
WellState& well_state);
WellState& well_state,
Opm::DeferredLogger& deferred_logger);
void assembleWellEqWithoutIteration(const Simulator& ebosSimulator,
const double dt,
WellState& well_state);
WellState& well_state,
Opm::DeferredLogger& deferred_logger);
virtual void wellTestingPhysical(Simulator& simulator, const std::vector<double>& B_avg,
const double simulation_time, const int report_step,

View File

@ -20,6 +20,7 @@
#include <opm/autodiff/MSWellHelpers.hpp>
#include <opm/simulators/DeferredLoggingErrorHelpers.hpp>
namespace Opm
{
@ -240,10 +241,10 @@ namespace Opm
const bool use_inner_iterations = param_.use_inner_iterations_ms_wells_;
if (use_inner_iterations) {
iterateWellEquations(ebosSimulator, dt, well_state);
iterateWellEquations(ebosSimulator, dt, well_state, deferred_logger);
}
assembleWellEqWithoutIteration(ebosSimulator, dt, well_state);
assembleWellEqWithoutIteration(ebosSimulator, dt, well_state, deferred_logger);
}
@ -411,7 +412,7 @@ namespace Opm
template <typename TypeTag>
ConvergenceReport
MultisegmentWell<TypeTag>::
getWellConvergence(const std::vector<double>& B_avg) const
getWellConvergence(const std::vector<double>& B_avg, Opm::DeferredLogger& deferred_logger) const
{
assert(int(B_avg.size()) == num_components_);
@ -437,7 +438,7 @@ namespace Opm
ctrltype = CR::WellFailure::Type::ControlRate;
break;
default:
OPM_THROW(std::runtime_error, "Unknown well control control types for well " << name());
OPM_DEFLOG_THROW(std::runtime_error, "Unknown well control control types for well " << name(), deferred_logger);
}
assert(ctrltype != CR::WellFailure::Type::Invalid);
@ -544,11 +545,12 @@ namespace Opm
void
MultisegmentWell<TypeTag>::
recoverWellSolutionAndUpdateWellState(const BVector& x,
WellState& well_state) const
WellState& well_state,
Opm::DeferredLogger& deferred_logger) const
{
BVectorWell xw(1);
recoverSolutionWell(x, xw);
updateWellState(xw, false, well_state);
updateWellState(xw, false, well_state, deferred_logger);
}
@ -582,7 +584,7 @@ namespace Opm
template <typename TypeTag>
void
MultisegmentWell<TypeTag>::
updatePrimaryVariables(const WellState& well_state) const
updatePrimaryVariables(const WellState& well_state, Opm::DeferredLogger& deferred_logger) const
{
// TODO: to test using rate conversion coefficients to see if it will be better than
// this default one
@ -669,13 +671,13 @@ namespace Opm
template <typename TypeTag>
void
MultisegmentWell<TypeTag>::
solveEqAndUpdateWellState(WellState& well_state)
solveEqAndUpdateWellState(WellState& well_state, Opm::DeferredLogger& deferred_logger)
{
// We assemble the well equations, then we check the convergence,
// which is why we do not put the assembleWellEq here.
const BVectorWell dx_well = mswellhelpers::invDXDirect(duneD_, resWell_);
updateWellState(dx_well, false, well_state);
updateWellState(dx_well, false, well_state, deferred_logger);
}
@ -760,7 +762,8 @@ namespace Opm
MultisegmentWell<TypeTag>::
updateWellState(const BVectorWell& dwells,
const bool inner_iteration,
WellState& well_state) const
WellState& well_state,
Opm::DeferredLogger& deferred_logger) const
{
const bool use_inner_iterations = param_.use_inner_iterations_ms_wells_;
@ -811,7 +814,8 @@ namespace Opm
void
MultisegmentWell<TypeTag>::
calculateExplicitQuantities(const Simulator& ebosSimulator,
const WellState& /* well_state */)
const WellState& /* well_state */,
Opm::DeferredLogger& deferred_logger)
{
computePerfCellPressDiffs(ebosSimulator);
computeInitialComposition();
@ -973,7 +977,9 @@ namespace Opm
const int perf,
const EvalWell& segment_pressure,
const bool& allow_cf,
std::vector<EvalWell>& cq_s) const
std::vector<EvalWell>& cq_s,
Opm::DeferredLogger& deferred_logger) const
{
std::vector<EvalWell> cmix_s(num_components_, 0.0);
@ -1062,8 +1068,8 @@ namespace Opm
const EvalWell d = 1.0 - rv * rs;
if (d.value() == 0.0) {
OPM_THROW(Opm::NumericalIssue, "Zero d value obtained for well " << name() << " during flux calcuation"
<< " with rs " << rs << " and rv " << rv);
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;
@ -1376,14 +1382,14 @@ namespace Opm
template <typename TypeTag>
void
MultisegmentWell<TypeTag>::
assembleControlEq() const
assembleControlEq(Opm::DeferredLogger& deferred_logger) const
{
EvalWell control_eq(0.0);
switch (well_controls_get_current_type(well_controls_)) {
case THP: // not handling this one for now
{
OPM_THROW(std::runtime_error, "Not handling THP control for Multisegment wells for now");
OPM_DEFLOG_THROW(std::runtime_error, "Not handling THP control for Multisegment wells for now", deferred_logger);
}
case BHP:
{
@ -1441,7 +1447,7 @@ namespace Opm
break;
}
default:
OPM_THROW(std::runtime_error, "Unknown well control control types for well " << name());
OPM_DEFLOG_THROW(std::runtime_error, "Unknown well control control types for well " << name(), deferred_logger);
}
@ -1751,7 +1757,8 @@ namespace Opm
MultisegmentWell<TypeTag>::
iterateWellEquations(const Simulator& ebosSimulator,
const double dt,
WellState& well_state)
WellState& well_state,
Opm::DeferredLogger& deferred_logger)
{
// basically, it only iterate through the equations.
// we update the primary variables
@ -1762,7 +1769,7 @@ namespace Opm
int it = 0;
for (; it < max_iter_number; ++it) {
assembleWellEqWithoutIteration(ebosSimulator, dt, well_state);
assembleWellEqWithoutIteration(ebosSimulator, dt, well_state, deferred_logger);
const BVectorWell dx_well = mswellhelpers::invDXDirect(duneD_, resWell_);
@ -1773,12 +1780,12 @@ namespace Opm
// const std::vector<double> B {0.8, 0.8, 0.008};
const std::vector<double> B {0.5, 0.5, 0.005};
const auto report = getWellConvergence(B);
const auto report = getWellConvergence(B, deferred_logger);
if (report.converged()) {
break;
}
updateWellState(dx_well, true, well_state);
updateWellState(dx_well, true, well_state, deferred_logger);
initPrimaryVariablesEvaluation();
}
@ -1794,7 +1801,8 @@ namespace Opm
MultisegmentWell<TypeTag>::
assembleWellEqWithoutIteration(const Simulator& ebosSimulator,
const double dt,
WellState& well_state)
WellState& well_state,
Opm::DeferredLogger& deferred_logger)
{
// calculate the fluid properties needed.
computeSegmentFluidProperties(ebosSimulator);
@ -1853,7 +1861,7 @@ namespace Opm
std::vector<EvalWell> mob(num_components_, 0.0);
getMobility(ebosSimulator, perf, mob);
std::vector<EvalWell> cq_s(num_components_, 0.0);
computePerfRate(int_quants, mob, seg, perf, seg_pressure, allow_cf, cq_s);
computePerfRate(int_quants, mob, seg, perf, seg_pressure, allow_cf, cq_s, deferred_logger);
for (int comp_idx = 0; comp_idx < num_components_; ++comp_idx) {
// the cq_s entering mass balance equations need to consider the efficiency factors.
@ -1886,7 +1894,7 @@ namespace Opm
// the fourth dequation, the pressure drop equation
if (seg == 0) { // top segment, pressure equation is the control equation
assembleControlEq();
assembleControlEq(deferred_logger);
} else {
assemblePressureEq(seg);
}

View File

@ -151,7 +151,8 @@ namespace Opm
Opm::DeferredLogger& deferred_logger) const override;
/// check whether the well equations get converged for this well
virtual ConvergenceReport getWellConvergence(const std::vector<double>& B_avg) const override;
virtual ConvergenceReport getWellConvergence(const std::vector<double>& B_avg,
Opm::DeferredLogger& deferred_logger) const override;
/// Ax = Ax - C D^-1 B x
virtual void apply(const BVector& x, BVector& Ax) const override;
@ -161,7 +162,8 @@ namespace Opm
/// using the solution x to recover the solution xw for wells and applying
/// xw to update Well State
virtual void recoverWellSolutionAndUpdateWellState(const BVector& x,
WellState& well_state) const override;
WellState& well_state,
Opm::DeferredLogger& deferred_logger) const override;
/// computing the well potentials for group control
virtual void computeWellPotentials(const Simulator& ebosSimulator,
@ -169,12 +171,13 @@ namespace Opm
std::vector<double>& well_potentials,
Opm::DeferredLogger& deferred_logger) /* const */ override;
virtual void updatePrimaryVariables(const WellState& well_state) const override;
virtual void updatePrimaryVariables(const WellState& well_state, Opm::DeferredLogger& deferred_logger) const override;
virtual void solveEqAndUpdateWellState(WellState& well_state) override;
virtual void solveEqAndUpdateWellState(WellState& well_state, Opm::DeferredLogger& deferred_logger) override;
virtual void calculateExplicitQuantities(const Simulator& ebosSimulator,
const WellState& well_state) override; // should be const?
const WellState& well_state,
Opm::DeferredLogger& deferred_logger) override; // should be const?
virtual void addWellContributions(Mat& mat) const override;
@ -278,7 +281,8 @@ namespace Opm
// updating the well_state based on well solution dwells
void updateWellState(const BVectorWell& dwells,
WellState& well_state) const;
WellState& well_state,
Opm::DeferredLogger& deferred_logger) const;
// calculate the properties for the well connections
// to calulate the pressure difference between well connections.
@ -318,38 +322,43 @@ namespace Opm
const bool allow_cf,
std::vector<EvalWell>& cq_s,
double& perf_dis_gas_rate,
double& perf_vap_oil_rate) const;
double& perf_vap_oil_rate,
Opm::DeferredLogger& deferred_logger) const;
// TODO: maybe we should provide a light version of computePerfRate, which does not include the
// calculation of the derivatives
void computeWellRatesWithBhp(const Simulator& ebosSimulator,
const EvalWell& bhp,
std::vector<double>& well_flux) const;
std::vector<double>& well_flux,
Opm::DeferredLogger& deferred_logger) const;
std::vector<double> computeWellPotentialWithTHP(const Simulator& ebosSimulator,
const double initial_bhp, // bhp from BHP constraints
const std::vector<double>& initial_potential) const;
const std::vector<double>& initial_potential,
Opm::DeferredLogger& deferred_logger) const;
template <class ValueType>
ValueType calculateBhpFromThp(const std::vector<ValueType>& rates, const int control_index) const;
ValueType calculateBhpFromThp(const std::vector<ValueType>& rates, const int control_index, Opm::DeferredLogger& deferred_logger) const;
double calculateThpFromBhp(const std::vector<double>& rates, const double bhp) const;
double calculateThpFromBhp(const std::vector<double>& rates, const double bhp, Opm::DeferredLogger& deferred_logger) const;
// get the mobility for specific perforation
void getMobility(const Simulator& ebosSimulator,
const int perf,
std::vector<EvalWell>& mob) const;
std::vector<EvalWell>& mob,
Opm::DeferredLogger& deferred_logger) const;
void updateWaterMobilityWithPolymer(const Simulator& ebos_simulator,
const int perf,
std::vector<EvalWell>& mob_water) const;
std::vector<EvalWell>& mob_water,
Opm::DeferredLogger& deferred_logger) const;
void updatePrimaryVariablesNewton(const BVectorWell& dwells,
const WellState& well_state) const;
void updateWellStateFromPrimaryVariables(WellState& well_state) const;
void updateWellStateFromPrimaryVariables(WellState& well_state, Opm::DeferredLogger& deferred_logger) const;
void updateThp(WellState& well_state) const;
void updateThp(WellState& well_state, Opm::DeferredLogger& deferred_logger) const;
void assembleControlEq(Opm::DeferredLogger& deferred_logger);
@ -374,17 +383,19 @@ namespace Opm
);
// check whether the well is operable under BHP limit with current reservoir condition
void checkOperabilityUnderBHPLimitProducer(const Simulator& ebos_simulator);
void checkOperabilityUnderBHPLimitProducer(const Simulator& ebos_simulator, Opm::DeferredLogger& deferred_logger);
// check whether the well is operable under THP limit with current reservoir condition
void checkOperabilityUnderTHPLimitProducer(const Simulator& ebos_simulator, Opm::DeferredLogger& deferred_logger);
// update WellState based on IPR and associated VFP table
void updateWellStateWithTHPTargetIPR(const Simulator& ebos_simulator,
WellState& well_state) const;
WellState& well_state,
Opm::DeferredLogger& deferred_logger) const;
void updateWellStateWithTHPTargetIPRProducer(const Simulator& ebos_simulator,
WellState& well_state) const;
WellState& well_state,
Opm::DeferredLogger& deferred_logger) const;
// for a well, when all drawdown are in the wrong direction, then this well will not
// be able to produce/inject .
@ -405,7 +416,7 @@ namespace Opm
// calculate the BHP from THP target based on IPR
// TODO: we need to check the operablility here first, if not operable, then maybe there is
// no point to do this
double calculateBHPWithTHPTargetIPR() const;
double calculateBHPWithTHPTargetIPR(Opm::DeferredLogger& deferred_logger) const;
// relaxation factor considering only one fraction value
static double relaxationFactorFraction(const double old_value,

View File

@ -152,7 +152,7 @@ namespace Opm
Opm::DeferredLogger& deferred_logger) const override;
/// check whether the well equations get converged for this well
virtual ConvergenceReport getWellConvergence(const std::vector<double>& B_avg) const override;
virtual ConvergenceReport getWellConvergence(const std::vector<double>& B_avg, Opm::DeferredLogger& deferred_logger) const override;
/// Ax = Ax - C D^-1 B x
virtual void apply(const BVector& x, BVector& Ax) const override;
@ -162,7 +162,8 @@ namespace Opm
/// using the solution x to recover the solution xw for wells and applying
/// xw to update Well State
virtual void recoverWellSolutionAndUpdateWellState(const BVector& x,
WellState& well_state) const override;
WellState& well_state,
Opm::DeferredLogger& deferred_logger) const override;
/// computing the well potentials for group control
virtual void computeWellPotentials(const Simulator& ebosSimulator,
@ -170,12 +171,13 @@ namespace Opm
std::vector<double>& well_potentials,
Opm::DeferredLogger& deferred_logger) /* const */ override;
virtual void updatePrimaryVariables(const WellState& well_state) const override;
virtual void updatePrimaryVariables(const WellState& well_state, Opm::DeferredLogger& deferred_logger) const override;
virtual void solveEqAndUpdateWellState(WellState& well_state) override;
virtual void solveEqAndUpdateWellState(WellState& well_state, Opm::DeferredLogger& deferred_logger) override;
virtual void calculateExplicitQuantities(const Simulator& ebosSimulator,
const WellState& well_state) override; // should be const?
const WellState& well_state,
Opm::DeferredLogger& deferred_logger) override; // should be const?
virtual void addWellContributions(Mat& mat) const override;
@ -283,7 +285,8 @@ namespace Opm
// updating the well_state based on well solution dwells
void updateWellState(const BVectorWell& dwells,
WellState& well_state) const;
WellState& well_state,
Opm::DeferredLogger& deferred_logger) const;
// calculate the properties for the well connections
// to calulate the pressure difference between well connections.
@ -323,38 +326,43 @@ namespace Opm
const bool allow_cf,
std::vector<EvalWell>& cq_s,
double& perf_dis_gas_rate,
double& perf_vap_oil_rate) const;
double& perf_vap_oil_rate,
Opm::DeferredLogger& deferred_logger) const;
// TODO: maybe we should provide a light version of computePerfRate, which does not include the
// calculation of the derivatives
void computeWellRatesWithBhp(const Simulator& ebosSimulator,
const EvalWell& bhp,
std::vector<double>& well_flux) const;
std::vector<double>& well_flux,
Opm::DeferredLogger& deferred_logger) const;
std::vector<double> computeWellPotentialWithTHP(const Simulator& ebosSimulator,
const double initial_bhp, // bhp from BHP constraints
const std::vector<double>& initial_potential) const;
const std::vector<double>& initial_potential,
Opm::DeferredLogger& deferred_logger) const;
template <class ValueType>
ValueType calculateBhpFromThp(const std::vector<ValueType>& rates, const int control_index) const;
ValueType calculateBhpFromThp(const std::vector<ValueType>& rates, const int control_index, Opm::DeferredLogger& deferred_logger) const;
double calculateThpFromBhp(const std::vector<double>& rates, const double bhp) const;
double calculateThpFromBhp(const std::vector<double>& rates, const double bhp, Opm::DeferredLogger& deferred_logger) const;
// get the mobility for specific perforation
void getMobility(const Simulator& ebosSimulator,
const int perf,
std::vector<EvalWell>& mob) const;
std::vector<EvalWell>& mob,
Opm::DeferredLogger& deferred_logger) const;
void updateWaterMobilityWithPolymer(const Simulator& ebos_simulator,
const int perf,
std::vector<EvalWell>& mob_water) const;
std::vector<EvalWell>& mob_water,
Opm::DeferredLogger& deferred_logger) const;
void updatePrimaryVariablesNewton(const BVectorWell& dwells,
const WellState& well_state) const;
void updateWellStateFromPrimaryVariables(WellState& well_state) const;
void updateWellStateFromPrimaryVariables(WellState& well_state, Opm::DeferredLogger& deferred_logger) const;
void updateThp(WellState& well_state) const;
void updateThp(WellState& well_state, Opm::DeferredLogger& deferred_logger) const;
void assembleControlEq(Opm::DeferredLogger& deferred_logger);
@ -377,17 +385,19 @@ namespace Opm
Opm::DeferredLogger& deferred_logger);
// check whether the well is operable under BHP limit with current reservoir condition
void checkOperabilityUnderBHPLimitProducer(const Simulator& ebos_simulator);
void checkOperabilityUnderBHPLimitProducer(const Simulator& ebos_simulator, Opm::DeferredLogger& deferred_logger);
// check whether the well is operable under THP limit with current reservoir condition
void checkOperabilityUnderTHPLimitProducer(const Simulator& ebos_simulator, Opm::DeferredLogger& deferred_logger);
// update WellState based on IPR and associated VFP table
void updateWellStateWithTHPTargetIPR(const Simulator& ebos_simulator,
WellState& well_state) const;
WellState& well_state,
Opm::DeferredLogger& deferred_logger) const;
void updateWellStateWithTHPTargetIPRProducer(const Simulator& ebos_simulator,
WellState& well_state) const;
WellState& well_state,
Opm::DeferredLogger& deferred_logger) const;
// for a well, when all drawdown are in the wrong direction, then this well will not
// be able to produce/inject .
@ -408,7 +418,7 @@ namespace Opm
// calculate the BHP from THP target based on IPR
// TODO: we need to check the operablility here first, if not operable, then maybe there is
// no point to do this
double calculateBHPWithTHPTargetIPR() const;
double calculateBHPWithTHPTargetIPR(Opm::DeferredLogger& deferred_logger) const;
// relaxation factor considering only one fraction value
static double relaxationFactorFraction(const double old_value,
@ -433,21 +443,25 @@ namespace Opm
// to handle the effect from formation damage.
EvalWell pskin(const double throuhgput,
const EvalWell& water_velocity,
const EvalWell& poly_inj_conc) const;
const EvalWell& poly_inj_conc,
Opm::DeferredLogger& deferred_logger) const;
// calculate the skin pressure based on water velocity, throughput during water injection.
EvalWell pskinwater(const double throughput,
const EvalWell& water_velocity) const;
const EvalWell& water_velocity,
Opm::DeferredLogger& deferred_logger) const;
// calculate the injecting polymer molecular weight based on the througput and water velocity
EvalWell wpolymermw(const double throughput,
const EvalWell& water_velocity) const;
const EvalWell& water_velocity,
Opm::DeferredLogger& deferred_logger) const;
// handle the extra equations for polymer injectivity study
void handleInjectivityRateAndEquations(const IntensiveQuantities& int_quants,
const WellState& well_state,
const int perf,
std::vector<EvalWell>& cq_s);
std::vector<EvalWell>& cq_s,
Opm::DeferredLogger& deferred_logger);
virtual void updateWaterThroughput(const double dt, WellState& well_state) const override;
};

View File

@ -19,6 +19,7 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <opm/simulators/DeferredLoggingErrorHelpers.hpp>
namespace Opm
{
@ -313,7 +314,8 @@ namespace Opm
const bool allow_cf,
std::vector<EvalWell>& cq_s,
double& perf_dis_gas_rate,
double& perf_vap_oil_rate) const
double& perf_vap_oil_rate,
Opm::DeferredLogger& deferred_logger) const
{
const auto& fs = intQuants.fluidState();
@ -415,8 +417,8 @@ namespace Opm
const EvalWell d = EvalWell(numWellEq_ + numEq, 1.0) - rv * rs;
if (d.value() == 0.0) {
OPM_THROW(Opm::NumericalIssue, "Zero d value obtained for well " << name() << " during flux calcuation"
<< " with rs " << rs << " and rv " << rv);
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;
@ -516,17 +518,17 @@ namespace Opm
const int cell_idx = well_cells_[perf];
const auto& intQuants = *(ebosSimulator.model().cachedIntensiveQuantities(cell_idx, /*timeIdx=*/ 0));
std::vector<EvalWell> mob(num_components_, {numWellEq_ + numEq, 0.});
getMobility(ebosSimulator, perf, mob);
getMobility(ebosSimulator, perf, mob, deferred_logger);
std::vector<EvalWell> cq_s(num_components_, {numWellEq_ + numEq, 0.});
double perf_dis_gas_rate = 0.;
double perf_vap_oil_rate = 0.;
computePerfRate(intQuants, mob, bhp, perf, allow_cf,
cq_s, perf_dis_gas_rate, perf_vap_oil_rate);
cq_s, perf_dis_gas_rate, perf_vap_oil_rate, 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 && well_type_ == INJECTOR) {
handleInjectivityRateAndEquations(intQuants, well_state, perf, cq_s);
handleInjectivityRateAndEquations(intQuants, well_state, perf, cq_s, deferred_logger);
}
// updating the solution gas rate and solution oil rate
@ -643,7 +645,7 @@ namespace Opm
const EvalWell water_velocity = primary_variables_evaluation_[wat_vel_index];
if (water_velocity > 0.) { // injecting
const double throughput = well_state.perfThroughput()[first_perf_ + perf];
const EvalWell molecular_weight = wpolymermw(throughput, water_velocity);
const EvalWell molecular_weight = wpolymermw(throughput, water_velocity, deferred_logger);
cq_s_polymw *= molecular_weight;
} else {
// we do not consider the molecular weight from the polymer
@ -700,13 +702,10 @@ namespace Opm
assembleControlEq(deferred_logger);
// do the local inversion of D.
try
{
try {
Dune::ISTLUtility::invertMatrix(invDuneD_[0][0]);
}
catch( ... )
{
OPM_THROW(Opm::NumericalIssue,"Error when inverting local well equations for well " + name());
} catch( ... ) {
OPM_DEFLOG_THROW(Opm::NumericalIssue,"Error when inverting local well equations for well " + name(), deferred_logger);
}
@ -736,7 +735,7 @@ namespace Opm
rates[ Gas ] = getQs(flowPhaseToEbosCompIdx(Gas));
}
const int current = well_controls_get_current(well_controls_);
control_eq = getBhp() - calculateBhpFromThp(rates, current);
control_eq = getBhp() - calculateBhpFromThp(rates, current, deferred_logger);
break;
}
case BHP:
@ -814,7 +813,7 @@ namespace Opm
break;
}
default:
OPM_THROW(std::runtime_error, "Unknown well control control types for well " << name());
OPM_DEFLOG_THROW(std::runtime_error, "Unknown well control control types for well " << name(), deferred_logger);
}
// using control_eq to update the matrix and residuals
@ -834,7 +833,8 @@ namespace Opm
StandardWellV<TypeTag>::
getMobility(const Simulator& ebosSimulator,
const int perf,
std::vector<EvalWell>& mob) const
std::vector<EvalWell>& mob,
Opm::DeferredLogger& deferred_logger) const
{
const int cell_idx = well_cells_[perf];
assert (int(mob.size()) == num_components_);
@ -879,17 +879,17 @@ namespace Opm
// this may not work if viscosity and relperms has been modified?
if (has_solvent) {
OPM_THROW(std::runtime_error, "individual mobility for wells does not work in combination with solvent");
OPM_DEFLOG_THROW(std::runtime_error, "individual mobility for wells does not work in combination with solvent", deferred_logger);
}
}
// modify the water mobility if polymer is present
if (has_polymer) {
if (!FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx)) {
OPM_THROW(std::runtime_error, "Water is required when polymer is active");
OPM_DEFLOG_THROW(std::runtime_error, "Water is required when polymer is active", deferred_logger);
}
updateWaterMobilityWithPolymer(ebosSimulator, perf, mob);
updateWaterMobilityWithPolymer(ebosSimulator, perf, mob, deferred_logger);
}
}
@ -901,13 +901,14 @@ namespace Opm
void
StandardWellV<TypeTag>::
updateWellState(const BVectorWell& dwells,
WellState& well_state) const
WellState& well_state,
Opm::DeferredLogger& deferred_logger) const
{
if (!this->isOperable()) return;
updatePrimaryVariablesNewton(dwells, well_state);
updateWellStateFromPrimaryVariables(well_state);
updateWellStateFromPrimaryVariables(well_state, deferred_logger);
}
@ -1068,7 +1069,7 @@ namespace Opm
template<typename TypeTag>
void
StandardWellV<TypeTag>::
updateWellStateFromPrimaryVariables(WellState& well_state) const
updateWellStateFromPrimaryVariables(WellState& well_state, Opm::DeferredLogger& deferred_logger) const
{
const PhaseUsage& pu = phaseUsage();
assert( FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx) );
@ -1132,7 +1133,7 @@ namespace Opm
}
}
updateThp(well_state);
updateThp(well_state, deferred_logger);
// other primary variables related to polymer injectivity study
if (this->has_polymermw && well_type_ == INJECTOR) {
@ -1150,10 +1151,10 @@ namespace Opm
template<typename TypeTag>
void
StandardWellV<TypeTag>::
updateThp(WellState& well_state) const
updateThp(WellState& well_state, Opm::DeferredLogger& deferred_logger) const
{
// When there is no vaild VFP table provided, we set the thp to be zero.
if (!this->isVFPActive()) {
if (!this->isVFPActive(deferred_logger)) {
well_state.thp()[index_of_well_] = 0.;
return;
}
@ -1180,7 +1181,7 @@ namespace Opm
const double bhp = well_state.bhp()[index_of_well_];
well_state.thp()[index_of_well_] = calculateThpFromBhp(rates, bhp);
well_state.thp()[index_of_well_] = calculateThpFromBhp(rates, bhp, deferred_logger);
}
}
@ -1218,13 +1219,13 @@ namespace Opm
case THP: {
// when a well can not work under THP target, it switches to BHP control
if (this->operability_status_.isOperableUnderTHPLimit() ) {
updateWellStateWithTHPTargetIPR(ebos_simulator, well_state);
updateWellStateWithTHPTargetIPR(ebos_simulator, well_state, deferred_logger);
} else { // go to BHP limit
assert(this->operability_status_.isOperableUnderBHPLimit() );
deferred_logger.info("well " + name() + " can not work with THP target, switching to BHP control");
well_state.bhp()[well_index] = mostStrictBhpFromBhpLimits();
well_state.bhp()[well_index] = mostStrictBhpFromBhpLimits(deferred_logger);
}
break;
}
@ -1285,7 +1286,7 @@ namespace Opm
}
}
} else {
OPM_THROW(std::logic_error, "Expected PRODUCER or INJECTOR type of well");
OPM_DEFLOG_THROW(std::logic_error, "Expected PRODUCER or INJECTOR type of well", deferred_logger);
}
break;
@ -1316,7 +1317,7 @@ namespace Opm
for (int perf = 0; perf < number_of_perforations_; ++perf) {
std::vector<EvalWell> mob(num_components_, {numWellEq_ + numEq, 0.0});
// TODO: mabye we should store the mobility somewhere, so that we only need to calculate it one per iteration
getMobility(ebos_simulator, perf, mob);
getMobility(ebos_simulator, perf, mob, deferred_logger);
const int cell_idx = well_cells_[perf];
const auto& int_quantities = *(ebos_simulator.model().cachedIntensiveQuantities(cell_idx, /*timeIdx=*/ 0));
@ -1404,7 +1405,7 @@ namespace Opm
return;
}
if (!this->underPredictionMode() ) {
if (!this->underPredictionMode(deferred_logger) ) {
return;
}
@ -1437,7 +1438,7 @@ namespace Opm
updateIPR(ebos_simulator, deferred_logger);
// checking the BHP limit related
checkOperabilityUnderBHPLimitProducer(ebos_simulator);
checkOperabilityUnderBHPLimitProducer(ebos_simulator, deferred_logger);
// checking whether the well can operate under the THP constraints.
if (this->wellHasTHPConstraints()) {
@ -1452,9 +1453,9 @@ namespace Opm
template<typename TypeTag>
void
StandardWellV<TypeTag>::
checkOperabilityUnderBHPLimitProducer(const Simulator& ebos_simulator)
checkOperabilityUnderBHPLimitProducer(const Simulator& ebos_simulator, Opm::DeferredLogger& deferred_logger)
{
const double bhp_limit = mostStrictBhpFromBhpLimits();
const double bhp_limit = mostStrictBhpFromBhpLimits(deferred_logger);
// Crude but works: default is one atmosphere.
// TODO: a better way to detect whether the BHP is defaulted or not
const bool bhp_limit_not_defaulted = bhp_limit > 1.5 * unit::barsa;
@ -1476,10 +1477,10 @@ namespace Opm
// option 2: stick with the above IPR curve
// we use IPR here
std::vector<double> well_rates_bhp_limit;
computeWellRatesWithBhp(ebos_simulator, EvalWell(numWellEq_ + numEq, bhp_limit), well_rates_bhp_limit);
computeWellRatesWithBhp(ebos_simulator, EvalWell(numWellEq_ + numEq, bhp_limit), well_rates_bhp_limit, deferred_logger);
const double thp = calculateThpFromBhp(well_rates_bhp_limit, bhp_limit);
const double thp_limit = this->getTHPConstraint();
const double thp = calculateThpFromBhp(well_rates_bhp_limit, bhp_limit, deferred_logger);
const double thp_limit = this->getTHPConstraint(deferred_logger);
if (thp < thp_limit) {
this->operability_status_.obey_thp_limit_under_bhp_limit = false;
@ -1507,15 +1508,15 @@ namespace Opm
StandardWellV<TypeTag>::
checkOperabilityUnderTHPLimitProducer(const Simulator& ebos_simulator, Opm::DeferredLogger& deferred_logger)
{
const double obtain_bhp = calculateBHPWithTHPTargetIPR();
const double obtain_bhp = calculateBHPWithTHPTargetIPR(deferred_logger);
if (obtain_bhp > 0.) {
this->operability_status_.can_obtain_bhp_with_thp_limit = true;
const double bhp_limit = mostStrictBhpFromBhpLimits();
const double bhp_limit = mostStrictBhpFromBhpLimits(deferred_logger);
this->operability_status_.obey_bhp_limit_with_thp_limit = (obtain_bhp >= bhp_limit);
const double thp_limit = this->getTHPConstraint();
const double thp_limit = this->getTHPConstraint(deferred_logger);
if (obtain_bhp < thp_limit) {
const std::string msg = " obtained bhp " + std::to_string(unit::convert::to(obtain_bhp, unit::barsa))
+ " bars is SMALLER than thp limit "
@ -1525,7 +1526,7 @@ namespace Opm
}
} else {
this->operability_status_.can_obtain_bhp_with_thp_limit = false;
const double thp_limit = this->getTHPConstraint();
const double thp_limit = this->getTHPConstraint(deferred_logger);
deferred_logger.debug(" COULD NOT find bhp value under thp_limit "
+ std::to_string(unit::convert::to(thp_limit, unit::barsa))
+ " bars for well " + name() + ", the well might need to be closed ");
@ -1581,7 +1582,7 @@ namespace Opm
{
const double bhp = well_state.bhp()[index_of_well_];
std::vector<double> well_rates;
computeWellRatesWithBhp(ebos_simulator, bhp, well_rates);
computeWellRatesWithBhp(ebos_simulator, bhp, well_rates, deferred_logger);
const double sign = (well_type_ == PRODUCER) ? -1. : 1.;
const double threshold = sign * std::numeric_limits<double>::min();
@ -1624,15 +1625,17 @@ namespace Opm
void
StandardWellV<TypeTag>::
updateWellStateWithTHPTargetIPR(const Simulator& ebos_simulator,
WellState& well_state) const
WellState& well_state,
Opm::DeferredLogger& deferred_logger) const
{
if (well_type_ == PRODUCER) {
updateWellStateWithTHPTargetIPRProducer(ebos_simulator,
well_state);
well_state,
deferred_logger);
}
if (well_type_ == INJECTOR) {
well_state.thp()[index_of_well_] = this->getTHPConstraint();
well_state.thp()[index_of_well_] = this->getTHPConstraint(deferred_logger);
// TODO: more work needs to be done for the injectors here, while injectors
// have been okay with the current strategy relying on well control equation directly.
}
@ -1646,23 +1649,24 @@ namespace Opm
void
StandardWellV<TypeTag>::
updateWellStateWithTHPTargetIPRProducer(const Simulator& ebos_simulator,
WellState& well_state) const
WellState& well_state,
Opm::DeferredLogger& deferred_logger) const
{
well_state.thp()[index_of_well_] = this->getTHPConstraint();
well_state.thp()[index_of_well_] = this->getTHPConstraint(deferred_logger);
const double bhp = calculateBHPWithTHPTargetIPR();
const double bhp = calculateBHPWithTHPTargetIPR(deferred_logger);
assert(bhp > 0.0);
well_state.bhp()[index_of_well_] = bhp;
// TODO: explicit quantities are always tricky for this type of situation
updatePrimaryVariables(well_state);
updatePrimaryVariables(well_state, deferred_logger);
initPrimaryVariablesEvaluation();
std::vector<double> rates;
computeWellRatesWithBhp(ebos_simulator, EvalWell(numWellEq_ + numEq, bhp), rates);
computeWellRatesWithBhp(ebos_simulator, EvalWell(numWellEq_ + numEq, bhp), rates, deferred_logger);
// TODO: double checke the obtained rates
// this is another places we might obtain negative rates
@ -1682,9 +1686,9 @@ namespace Opm
template<typename TypeTag>
double
StandardWellV<TypeTag>::
calculateBHPWithTHPTargetIPR() const
calculateBHPWithTHPTargetIPR(Opm::DeferredLogger& deferred_logger) const
{
const double thp_target = this->getTHPConstraint();
const double thp_target = this->getTHPConstraint(deferred_logger);
const double thp_control_index = this->getTHPControlIndex();
const int thp_table_id = well_controls_iget_vfp(well_controls_, thp_control_index);
const double alq = well_controls_iget_alq(well_controls_, thp_control_index);
@ -1702,7 +1706,7 @@ namespace Opm
// TODO: call a/the function for dp
const double dp = (vfp_ref_depth - ref_depth_) * rho * gravity_;
const double bhp_limit = mostStrictBhpFromBhpLimits();
const double bhp_limit = mostStrictBhpFromBhpLimits(deferred_logger);
const double obtain_bhp = vfp_properties_->getProd()->calculateBhpWithTHPTarget(ipr_a_, ipr_b_,
bhp_limit, thp_table_id, thp_target, alq, dp);
@ -1977,7 +1981,7 @@ namespace Opm
template<typename TypeTag>
ConvergenceReport
StandardWellV<TypeTag>::
getWellConvergence(const std::vector<double>& B_avg) const
getWellConvergence(const std::vector<double>& B_avg, Opm::DeferredLogger& deferred_logger) const
{
// the following implementation assume that the polymer is always after the w-o-g phases
// For the polymer case and the energy case, there is one more mass balance equations of reservoir than wells
@ -2041,7 +2045,7 @@ namespace Opm
control_tolerance = 1.e-4; // smaller tolerance for rate control
break;
default:
OPM_THROW(std::runtime_error, "Unknown well control control types for well " << name());
OPM_DEFLOG_THROW(std::runtime_error, "Unknown well control control types for well " + name(), deferred_logger);
}
const int dummy_component = -1;
@ -2147,7 +2151,7 @@ namespace Opm
template<typename TypeTag>
void
StandardWellV<TypeTag>::
solveEqAndUpdateWellState(WellState& well_state)
solveEqAndUpdateWellState(WellState& well_state, Opm::DeferredLogger& deferred_logger)
{
if (!this->isOperable()) return;
@ -2157,7 +2161,7 @@ namespace Opm
dx_well[0].resize(numWellEq_);
invDuneD_.mv(resWell_, dx_well);
updateWellState(dx_well, well_state);
updateWellState(dx_well, well_state, deferred_logger);
}
@ -2168,9 +2172,10 @@ namespace Opm
void
StandardWellV<TypeTag>::
calculateExplicitQuantities(const Simulator& ebosSimulator,
const WellState& well_state)
const WellState& well_state,
Opm::DeferredLogger& deferred_logger)
{
updatePrimaryVariables(well_state);
updatePrimaryVariables(well_state, deferred_logger);
initPrimaryVariablesEvaluation();
computeWellConnectionPressures(ebosSimulator, well_state);
computeAccumWell();
@ -2265,7 +2270,8 @@ namespace Opm
void
StandardWellV<TypeTag>::
recoverWellSolutionAndUpdateWellState(const BVector& x,
WellState& well_state) const
WellState& well_state,
Opm::DeferredLogger& deferred_logger) const
{
if (!this->isOperable()) return;
@ -2273,7 +2279,7 @@ namespace Opm
xw[0].resize(numWellEq_);
recoverSolutionWell(x, xw);
updateWellState(xw, well_state);
updateWellState(xw, well_state, deferred_logger);
}
@ -2285,7 +2291,8 @@ namespace Opm
StandardWellV<TypeTag>::
computeWellRatesWithBhp(const Simulator& ebosSimulator,
const EvalWell& bhp,
std::vector<double>& well_flux) const
std::vector<double>& well_flux,
Opm::DeferredLogger& deferred_logger) const
{
const int np = number_of_phases_;
well_flux.resize(np, 0.0);
@ -2297,13 +2304,13 @@ namespace Opm
const auto& intQuants = *(ebosSimulator.model().cachedIntensiveQuantities(cell_idx, /*timeIdx=*/ 0));
// flux for each perforation
std::vector<EvalWell> mob(num_components_, {numWellEq_ + numEq, 0.});
getMobility(ebosSimulator, perf, mob);
getMobility(ebosSimulator, perf, mob, deferred_logger);
std::vector<EvalWell> cq_s(num_components_, {numWellEq_ + numEq, 0.});
double perf_dis_gas_rate = 0.;
double perf_vap_oil_rate = 0.;
computePerfRate(intQuants, mob, bhp, perf, allow_cf,
cq_s, perf_dis_gas_rate, perf_vap_oil_rate);
cq_s, perf_dis_gas_rate, perf_vap_oil_rate, deferred_logger);
for(int p = 0; p < np; ++p) {
well_flux[ebosCompIdxToFlowCompIdx(p)] += cq_s[p].value();
@ -2320,7 +2327,8 @@ namespace Opm
StandardWellV<TypeTag>::
computeWellPotentialWithTHP(const Simulator& ebosSimulator,
const double initial_bhp, // bhp from BHP constraints
const std::vector<double>& initial_potential) const
const std::vector<double>& initial_potential,
Opm::DeferredLogger& deferred_logger) const
{
// TODO: pay attention to the situation that finally the potential is calculated based on the bhp control
// TODO: should we consider the bhp constraints during the iterative process?
@ -2365,7 +2373,7 @@ namespace Opm
rates[ Gas ] = potentials[pu.phase_pos[ Gas ] ];
}
const double bhp_calculated = calculateBhpFromThp(rates, ctrl_index);
const double bhp_calculated = calculateBhpFromThp(rates, ctrl_index, deferred_logger);
if (well_type_ == INJECTOR && bhp_calculated < bhp ) {
bhp = bhp_calculated;
@ -2379,17 +2387,17 @@ namespace Opm
// there should be always some available bhp/thp constraints there
if (std::isinf(bhp) || std::isnan(bhp)) {
OPM_THROW(std::runtime_error, "Unvalid bhp value obtained during the potential calculation for well " << name());
OPM_DEFLOG_THROW(std::runtime_error, "Unvalid bhp value obtained during the potential calculation for well " << name(), deferred_logger);
}
converged = std::abs(old_bhp - bhp) < bhp_tolerance;
computeWellRatesWithBhp(ebosSimulator, EvalWell(numWellEq_ + numEq, bhp), potentials);
computeWellRatesWithBhp(ebosSimulator, EvalWell(numWellEq_ + numEq, bhp), potentials, deferred_logger);
// checking whether the potentials have valid values
for (const double value : potentials) {
if (std::isinf(value) || std::isnan(value)) {
OPM_THROW(std::runtime_error, "Unvalid potential value obtained during the potential calculation for well " << name());
OPM_DEFLOG_THROW(std::runtime_error, "Unvalid potential value obtained during the potential calculation for well " << name(), deferred_logger);
}
}
@ -2408,7 +2416,7 @@ namespace Opm
}
if (!converged) {
OPM_THROW(std::runtime_error, "Failed in getting converged for the potential calculation for well " << name());
OPM_DEFLOG_THROW(std::runtime_error, "Failed in getting converged for the potential calculation for well " << name(), deferred_logger);
}
return potentials;
@ -2426,7 +2434,7 @@ namespace Opm
std::vector<double>& well_potentials,
Opm::DeferredLogger& deferred_logger) // const
{
updatePrimaryVariables(well_state);
updatePrimaryVariables(well_state, deferred_logger);
computeWellConnectionPressures(ebosSimulator, well_state);
// initialize the primary variables in Evaluation, which is used in computePerfRate for computeWellPotentials
@ -2437,13 +2445,13 @@ namespace Opm
well_potentials.resize(np, 0.0);
// get the bhp value based on the bhp constraints
const double bhp = mostStrictBhpFromBhpLimits();
const double bhp = mostStrictBhpFromBhpLimits(deferred_logger);
// does the well have a THP related constraint?
if ( !wellHasTHPConstraints() ) {
assert(std::abs(bhp) != std::numeric_limits<double>::max());
computeWellRatesWithBhp(ebosSimulator, EvalWell(numWellEq_ + numEq, bhp), well_potentials);
computeWellRatesWithBhp(ebosSimulator, EvalWell(numWellEq_ + numEq, bhp), well_potentials, deferred_logger);
} else {
// the well has a THP related constraint
// checking whether a well is newly added, it only happens at the beginning of the report step
@ -2455,7 +2463,7 @@ namespace Opm
}
} else {
// We need to generate a reasonable rates to start the iteration process
computeWellRatesWithBhp(ebosSimulator, EvalWell(numWellEq_ + numEq, bhp), well_potentials);
computeWellRatesWithBhp(ebosSimulator, EvalWell(numWellEq_ + numEq, bhp), well_potentials, deferred_logger);
for (double& value : well_potentials) {
// make the value a little safer in case the BHP limits are default ones
// TODO: a better way should be a better rescaling based on the investigation of the VFP table.
@ -2464,7 +2472,7 @@ namespace Opm
}
}
well_potentials = computeWellPotentialWithTHP(ebosSimulator, bhp, well_potentials);
well_potentials = computeWellPotentialWithTHP(ebosSimulator, bhp, well_potentials, deferred_logger);
}
}
@ -2475,7 +2483,7 @@ namespace Opm
template<typename TypeTag>
void
StandardWellV<TypeTag>::
updatePrimaryVariables(const WellState& well_state) const
updatePrimaryVariables(const WellState& well_state, Opm::DeferredLogger& deferred_logger) const
{
if (!this->isOperable()) return;
@ -2552,7 +2560,7 @@ namespace Opm
primary_variables_[GFrac] = 1.0 / np;
}
} else {
OPM_THROW(std::logic_error, "Expected PRODUCER or INJECTOR type of well");
OPM_DEFLOG_THROW(std::logic_error, "Expected PRODUCER or INJECTOR type of well", deferred_logger);
}
}
@ -2578,7 +2586,8 @@ namespace Opm
ValueType
StandardWellV<TypeTag>::
calculateBhpFromThp(const std::vector<ValueType>& rates,
const int control_index) const
const int control_index,
Opm::DeferredLogger& deferred_logger) const
{
// TODO: when well is under THP control, the BHP is dependent on the rates,
// the well rates is also dependent on the BHP, so it might need to do some iteration.
@ -2615,7 +2624,7 @@ namespace Opm
return vfp_properties_->getProd()->bhp(vfp, aqua, liquid, vapour, thp, alq) - dp;
}
else {
OPM_THROW(std::logic_error, "Expected INJECTOR or PRODUCER well");
OPM_DEFLOG_THROW(std::logic_error, "Expected INJECTOR or PRODUCER well", deferred_logger);
}
}
@ -2627,7 +2636,8 @@ namespace Opm
double
StandardWellV<TypeTag>::
calculateThpFromBhp(const std::vector<double>& rates,
const double bhp) const
const double bhp,
Opm::DeferredLogger& deferred_logger) const
{
assert(int(rates.size()) == 3); // the vfp related only supports three phases now.
@ -2655,7 +2665,7 @@ namespace Opm
thp = vfp_properties_->getProd()->thp(table_id, aqua, liquid, vapour, bhp + dp, alq);
}
else {
OPM_THROW(std::logic_error, "Expected INJECTOR or PRODUCER well");
OPM_DEFLOG_THROW(std::logic_error, "Expected INJECTOR or PRODUCER well", deferred_logger);
}
return thp;
@ -2672,7 +2682,8 @@ namespace Opm
StandardWellV<TypeTag>::
updateWaterMobilityWithPolymer(const Simulator& ebos_simulator,
const int perf,
std::vector<EvalWell>& mob) const
std::vector<EvalWell>& mob,
Opm::DeferredLogger& deferred_logger) const
{
// for the cases related to polymer molecular weight, we assume fully mixing
// as a result, the polymer and water share the same viscosity
@ -2707,7 +2718,7 @@ namespace Opm
double perf_dis_gas_rate = 0.;
double perf_vap_oil_rate = 0.;
computePerfRate(int_quant, mob, bhp, perf, allow_cf,
cq_s, perf_dis_gas_rate, perf_vap_oil_rate);
cq_s, perf_dis_gas_rate, perf_vap_oil_rate, 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();
@ -2898,7 +2909,7 @@ namespace Opm
// TODO: well state for this well is kind of all zero status
// we should be able to provide a better initialization
calculateExplicitQuantities(ebos_simulator, well_state_copy);
calculateExplicitQuantities(ebos_simulator, well_state_copy, deferred_logger);
updateWellOperability(ebos_simulator, well_state_copy, deferred_logger);
@ -2910,8 +2921,8 @@ namespace Opm
updateWellStateWithTarget(ebos_simulator, well_state_copy, deferred_logger);
calculateExplicitQuantities(ebos_simulator, well_state_copy);
updatePrimaryVariables(well_state_copy);
calculateExplicitQuantities(ebos_simulator, well_state_copy, deferred_logger);
updatePrimaryVariables(well_state_copy, deferred_logger);
initPrimaryVariablesEvaluation();
const bool converged = this->solveWellEqUntilConverged(ebos_simulator, B_avg, well_state_copy, deferred_logger);
@ -2941,15 +2952,16 @@ namespace Opm
typename StandardWellV<TypeTag>::EvalWell
StandardWellV<TypeTag>::
pskinwater(const double throughput,
const EvalWell& water_velocity) const
const EvalWell& water_velocity,
Opm::DeferredLogger& deferred_logger) const
{
if (!this->has_polymermw) {
OPM_THROW(std::runtime_error, "Polymermw is not activated, "
"while injecting skin pressure is requested for well " << name());
OPM_DEFLOG_THROW(std::runtime_error, "Polymermw is not activated, "
"while injecting skin pressure is requested for well " << name(), deferred_logger);
}
const int water_table_id = well_ecl_->getPolymerProperties(current_step_).m_skprwattable;
if (water_table_id <= 0) {
OPM_THROW(std::runtime_error, "Unused SKPRWAT table id used for well " << name());
OPM_DEFLOG_THROW(std::runtime_error, "Unused SKPRWAT table id used for well " << name(), deferred_logger);
}
const auto& water_table_func = PolymerModule::getSkprwatTable(water_table_id);
const EvalWell throughput_eval(numWellEq_ + numEq, throughput);
@ -2968,20 +2980,21 @@ namespace Opm
StandardWellV<TypeTag>::
pskin(const double throughput,
const EvalWell& water_velocity,
const EvalWell& poly_inj_conc) const
const EvalWell& poly_inj_conc,
Opm::DeferredLogger& deferred_logger) const
{
if (!this->has_polymermw) {
OPM_THROW(std::runtime_error, "Polymermw is not activated, "
"while injecting skin pressure is requested for well " << name());
OPM_DEFLOG_THROW(std::runtime_error, "Polymermw is not activated, "
"while injecting skin pressure is requested for well " << name(), deferred_logger);
}
const double sign = water_velocity >= 0. ? 1.0 : -1.0;
const EvalWell water_velocity_abs = Opm::abs(water_velocity);
if (poly_inj_conc == 0.) {
return sign * pskinwater(throughput, water_velocity_abs);
return sign * pskinwater(throughput, water_velocity_abs, deferred_logger);
}
const int polymer_table_id = well_ecl_->getPolymerProperties(current_step_).m_skprpolytable;
if (polymer_table_id <= 0) {
OPM_THROW(std::runtime_error, "Unavailable SKPRPOLY table id used for well " << name());
OPM_DEFLOG_THROW(std::runtime_error, "Unavailable SKPRPOLY table id used for well " << name(), deferred_logger);
}
const auto& skprpolytable = PolymerModule::getSkprpolyTable(polymer_table_id);
const double reference_concentration = skprpolytable.refConcentration;
@ -2993,7 +3006,7 @@ namespace Opm
return sign * pskin_poly;
}
// poly_inj_conc != reference concentration of the table, then some interpolation will be required
const EvalWell pskin_water = pskinwater(throughput, water_velocity_abs);
const EvalWell pskin_water = pskinwater(throughput, water_velocity_abs, deferred_logger);
const EvalWell pskin = pskin_water + (pskin_poly - pskin_water) / reference_concentration * poly_inj_conc;
return sign * pskin;
}
@ -3006,11 +3019,12 @@ namespace Opm
typename StandardWellV<TypeTag>::EvalWell
StandardWellV<TypeTag>::
wpolymermw(const double throughput,
const EvalWell& water_velocity) const
const EvalWell& water_velocity,
Opm::DeferredLogger& deferred_logger) const
{
if (!this->has_polymermw) {
OPM_THROW(std::runtime_error, "Polymermw is not activated, "
"while injecting polymer molecular weight is requested for well " << name());
OPM_DEFLOG_THROW(std::runtime_error, "Polymermw is not activated, "
"while injecting polymer molecular weight is requested for well " << name(), deferred_logger);
}
const int table_id = well_ecl_->getPolymerProperties(current_step_).m_plymwinjtable;
const auto& table_func = PolymerModule::getPlymwinjTable(table_id);
@ -3053,7 +3067,8 @@ namespace Opm
handleInjectivityRateAndEquations(const IntensiveQuantities& int_quants,
const WellState& well_state,
const int perf,
std::vector<EvalWell>& cq_s)
std::vector<EvalWell>& cq_s,
Opm::DeferredLogger& deferred_logger)
{
const unsigned water_comp_idx = Indices::canonicalToActiveComponentIndex(FluidSystem::waterCompIdx);
const EvalWell& water_flux_s = cq_s[water_comp_idx];
@ -3076,7 +3091,7 @@ namespace Opm
// equation for the skin pressure
const EvalWell eq_pskin = primary_variables_evaluation_[pskin_index]
- pskin(throughput, primary_variables_evaluation_[wat_vel_index], poly_conc);
- pskin(throughput, primary_variables_evaluation_[wat_vel_index], poly_conc, deferred_logger);
resWell_[0][pskin_index] = eq_pskin.value();
for (int pvIdx = 0; pvIdx < numWellEq_; ++pvIdx) {

View File

@ -19,6 +19,7 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <opm/simulators/DeferredLoggingErrorHelpers.hpp>
namespace Opm
{
@ -285,7 +286,8 @@ namespace Opm
const bool allow_cf,
std::vector<EvalWell>& cq_s,
double& perf_dis_gas_rate,
double& perf_vap_oil_rate) const
double& perf_vap_oil_rate,
Opm::DeferredLogger& deferred_logger) const
{
const auto& fs = intQuants.fluidState();
const EvalWell pressure = extendEval(fs.pressure(FluidSystem::oilPhaseIdx));
@ -380,8 +382,8 @@ namespace Opm
const EvalWell d = 1.0 - rv * rs;
if (d.value() == 0.0) {
OPM_THROW(Opm::NumericalIssue, "Zero d value obtained for well " << name() << " during flux calcuation"
<< " with rs " << rs << " and rv " << rv);
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;
@ -479,13 +481,13 @@ namespace Opm
const int cell_idx = well_cells_[perf];
const auto& intQuants = *(ebosSimulator.model().cachedIntensiveQuantities(cell_idx, /*timeIdx=*/ 0));
std::vector<EvalWell> mob(num_components_, 0.0);
getMobility(ebosSimulator, perf, mob);
getMobility(ebosSimulator, perf, mob, deferred_logger);
std::vector<EvalWell> cq_s(num_components_, 0.0);
double perf_dis_gas_rate = 0.;
double perf_vap_oil_rate = 0.;
computePerfRate(intQuants, mob, bhp, perf, allow_cf,
cq_s, perf_dis_gas_rate, perf_vap_oil_rate);
cq_s, perf_dis_gas_rate, perf_vap_oil_rate, deferred_logger);
// updating the solution gas rate and solution oil rate
if (well_type_ == PRODUCER) {
@ -645,13 +647,10 @@ namespace Opm
assembleControlEq(deferred_logger);
// do the local inversion of D.
try
{
try {
Dune::ISTLUtility::invertMatrix(invDuneD_[0][0]);
}
catch( ... )
{
OPM_THROW(Opm::NumericalIssue,"Error when inverting local well equations for well " + name());
} catch( ... ) {
OPM_DEFLOG_THROW(Opm::NumericalIssue,"Error when inverting local well equations for well " + name(), deferred_logger);
}
@ -681,7 +680,7 @@ namespace Opm
rates[ Gas ] = getQs(flowPhaseToEbosCompIdx(Gas));
}
const int current = well_controls_get_current(well_controls_);
control_eq = getBhp() - calculateBhpFromThp(rates, current);
control_eq = getBhp() - calculateBhpFromThp(rates, current, deferred_logger);
break;
}
case BHP:
@ -759,7 +758,7 @@ namespace Opm
break;
}
default:
OPM_THROW(std::runtime_error, "Unknown well control control types for well " << name());
OPM_DEFLOG_THROW(std::runtime_error, "Unknown well control control types for well " << name(), deferred_logger);
}
// using control_eq to update the matrix and residuals
@ -779,7 +778,8 @@ namespace Opm
StandardWell<TypeTag>::
getMobility(const Simulator& ebosSimulator,
const int perf,
std::vector<EvalWell>& mob) const
std::vector<EvalWell>& mob,
Opm::DeferredLogger& deferred_logger) const
{
const int cell_idx = well_cells_[perf];
assert (int(mob.size()) == num_components_);
@ -824,17 +824,17 @@ namespace Opm
// this may not work if viscosity and relperms has been modified?
if (has_solvent) {
OPM_THROW(std::runtime_error, "individual mobility for wells does not work in combination with solvent");
OPM_DEFLOG_THROW(std::runtime_error, "individual mobility for wells does not work in combination with solvent", deferred_logger);
}
}
// modify the water mobility if polymer is present
if (has_polymer) {
if (!FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx)) {
OPM_THROW(std::runtime_error, "Water is required when polymer is active");
OPM_DEFLOG_THROW(std::runtime_error, "Water is required when polymer is active", deferred_logger);
}
updateWaterMobilityWithPolymer(ebosSimulator, perf, mob);
updateWaterMobilityWithPolymer(ebosSimulator, perf, mob, deferred_logger);
}
}
@ -846,13 +846,14 @@ namespace Opm
void
StandardWell<TypeTag>::
updateWellState(const BVectorWell& dwells,
WellState& well_state) const
WellState& well_state,
Opm::DeferredLogger& deferred_logger) const
{
if (!this->isOperable()) return;
updatePrimaryVariablesNewton(dwells, well_state);
updateWellStateFromPrimaryVariables(well_state);
updateWellStateFromPrimaryVariables(well_state, deferred_logger);
}
@ -998,7 +999,7 @@ namespace Opm
template<typename TypeTag>
void
StandardWell<TypeTag>::
updateWellStateFromPrimaryVariables(WellState& well_state) const
updateWellStateFromPrimaryVariables(WellState& well_state, Opm::DeferredLogger& deferred_logger) const
{
const PhaseUsage& pu = phaseUsage();
assert( FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx) );
@ -1062,7 +1063,7 @@ namespace Opm
}
}
updateThp(well_state);
updateThp(well_state, deferred_logger);
}
@ -1072,10 +1073,10 @@ namespace Opm
template<typename TypeTag>
void
StandardWell<TypeTag>::
updateThp(WellState& well_state) const
updateThp(WellState& well_state, Opm::DeferredLogger& deferred_logger) const
{
// When there is no vaild VFP table provided, we set the thp to be zero.
if (!this->isVFPActive()) {
if (!this->isVFPActive(deferred_logger)) {
well_state.thp()[index_of_well_] = 0.;
return;
}
@ -1102,7 +1103,7 @@ namespace Opm
const double bhp = well_state.bhp()[index_of_well_];
well_state.thp()[index_of_well_] = calculateThpFromBhp(rates, bhp);
well_state.thp()[index_of_well_] = calculateThpFromBhp(rates, bhp, deferred_logger);
}
}
@ -1117,6 +1118,7 @@ namespace Opm
WellState& well_state,
Opm::DeferredLogger& deferred_logger) const
{
// number of phases
const int np = number_of_phases_;
const int well_index = index_of_well_;
@ -1140,13 +1142,13 @@ namespace Opm
case THP: {
// when a well can not work under THP target, it switches to BHP control
if (this->operability_status_.isOperableUnderTHPLimit() ) {
updateWellStateWithTHPTargetIPR(ebos_simulator, well_state);
updateWellStateWithTHPTargetIPR(ebos_simulator, well_state, deferred_logger);
} else { // go to BHP limit
assert(this->operability_status_.isOperableUnderBHPLimit() );
deferred_logger.info("well " + name() + " can not work with THP target, switching to BHP control");
well_state.bhp()[well_index] = mostStrictBhpFromBhpLimits();
well_state.bhp()[well_index] = mostStrictBhpFromBhpLimits(deferred_logger);
}
break;
}
@ -1207,7 +1209,7 @@ namespace Opm
}
}
} else {
OPM_THROW(std::logic_error, "Expected PRODUCER or INJECTOR type of well");
OPM_DEFLOG_THROW(std::logic_error, "Expected PRODUCER or INJECTOR type of well", deferred_logger);
}
break;
@ -1238,7 +1240,7 @@ namespace Opm
for (int perf = 0; perf < number_of_perforations_; ++perf) {
std::vector<EvalWell> mob(num_components_, 0.0);
// TODO: mabye we should store the mobility somewhere, so that we only need to calculate it one per iteration
getMobility(ebos_simulator, perf, mob);
getMobility(ebos_simulator, perf, mob, deferred_logger);
const int cell_idx = well_cells_[perf];
const auto& int_quantities = *(ebos_simulator.model().cachedIntensiveQuantities(cell_idx, /*timeIdx=*/ 0));
@ -1327,7 +1329,7 @@ namespace Opm
return;
}
if (!this->underPredictionMode() ) {
if (!this->underPredictionMode(deferred_logger) ) {
return;
}
@ -1361,7 +1363,7 @@ namespace Opm
updateIPR(ebos_simulator, deferred_logger);
// checking the BHP limit related
checkOperabilityUnderBHPLimitProducer(ebos_simulator);
checkOperabilityUnderBHPLimitProducer(ebos_simulator, deferred_logger);
// checking whether the well can operate under the THP constraints.
if (this->wellHasTHPConstraints()) {
@ -1376,9 +1378,9 @@ namespace Opm
template<typename TypeTag>
void
StandardWell<TypeTag>::
checkOperabilityUnderBHPLimitProducer(const Simulator& ebos_simulator)
checkOperabilityUnderBHPLimitProducer(const Simulator& ebos_simulator, Opm::DeferredLogger& deferred_logger)
{
const double bhp_limit = mostStrictBhpFromBhpLimits();
const double bhp_limit = mostStrictBhpFromBhpLimits(deferred_logger);
// Crude but works: default is one atmosphere.
// TODO: a better way to detect whether the BHP is defaulted or not
const bool bhp_limit_not_defaulted = bhp_limit > 1.5 * unit::barsa;
@ -1400,10 +1402,10 @@ namespace Opm
// option 2: stick with the above IPR curve
// we use IPR here
std::vector<double> well_rates_bhp_limit;
computeWellRatesWithBhp(ebos_simulator, bhp_limit, well_rates_bhp_limit);
computeWellRatesWithBhp(ebos_simulator, bhp_limit, well_rates_bhp_limit, deferred_logger);
const double thp = calculateThpFromBhp(well_rates_bhp_limit, bhp_limit);
const double thp_limit = this->getTHPConstraint();
const double thp = calculateThpFromBhp(well_rates_bhp_limit, bhp_limit, deferred_logger);
const double thp_limit = this->getTHPConstraint(deferred_logger);
if (thp < thp_limit) {
this->operability_status_.obey_thp_limit_under_bhp_limit = false;
@ -1431,15 +1433,15 @@ namespace Opm
StandardWell<TypeTag>::
checkOperabilityUnderTHPLimitProducer(const Simulator& ebos_simulator, Opm::DeferredLogger& deferred_logger)
{
const double obtain_bhp = calculateBHPWithTHPTargetIPR();
const double obtain_bhp = calculateBHPWithTHPTargetIPR(deferred_logger);
if (obtain_bhp > 0.) {
this->operability_status_.can_obtain_bhp_with_thp_limit = true;
const double bhp_limit = mostStrictBhpFromBhpLimits();
const double bhp_limit = mostStrictBhpFromBhpLimits(deferred_logger);
this->operability_status_.obey_bhp_limit_with_thp_limit = (obtain_bhp >= bhp_limit);
const double thp_limit = this->getTHPConstraint();
const double thp_limit = this->getTHPConstraint(deferred_logger);
if (obtain_bhp < thp_limit) {
const std::string msg = " obtained bhp " + std::to_string(unit::convert::to(obtain_bhp, unit::barsa))
+ " bars is SMALLER than thp limit "
@ -1449,7 +1451,7 @@ namespace Opm
}
} else {
this->operability_status_.can_obtain_bhp_with_thp_limit = false;
const double thp_limit = this->getTHPConstraint();
const double thp_limit = this->getTHPConstraint(deferred_logger);
deferred_logger.debug(" COULD NOT find bhp value under thp_limit "
+ std::to_string(unit::convert::to(thp_limit, unit::barsa))
+ " bars for well " + name() + ", the well might need to be closed ");
@ -1506,7 +1508,7 @@ namespace Opm
{
const double bhp = well_state.bhp()[index_of_well_];
std::vector<double> well_rates;
computeWellRatesWithBhp(ebos_simulator, bhp, well_rates);
computeWellRatesWithBhp(ebos_simulator, bhp, well_rates, deferred_logger);
const double sign = (well_type_ == PRODUCER) ? -1. : 1.;
const double threshold = sign * std::numeric_limits<double>::min();
@ -1549,15 +1551,17 @@ namespace Opm
void
StandardWell<TypeTag>::
updateWellStateWithTHPTargetIPR(const Simulator& ebos_simulator,
WellState& well_state) const
WellState& well_state,
Opm::DeferredLogger& deferred_logger) const
{
if (well_type_ == PRODUCER) {
updateWellStateWithTHPTargetIPRProducer(ebos_simulator,
well_state);
well_state,
deferred_logger);
}
if (well_type_ == INJECTOR) {
well_state.thp()[index_of_well_] = this->getTHPConstraint();
well_state.thp()[index_of_well_] = this->getTHPConstraint(deferred_logger);
// TODO: more work needs to be done for the injectors here, while injectors
// have been okay with the current strategy relying on well control equation directly.
}
@ -1571,23 +1575,24 @@ namespace Opm
void
StandardWell<TypeTag>::
updateWellStateWithTHPTargetIPRProducer(const Simulator& ebos_simulator,
WellState& well_state) const
WellState& well_state,
Opm::DeferredLogger& deferred_logger) const
{
well_state.thp()[index_of_well_] = this->getTHPConstraint();
well_state.thp()[index_of_well_] = this->getTHPConstraint(deferred_logger);
const double bhp = calculateBHPWithTHPTargetIPR();
const double bhp = calculateBHPWithTHPTargetIPR(deferred_logger);
assert(bhp > 0.0);
well_state.bhp()[index_of_well_] = bhp;
// TODO: explicit quantities are always tricky for this type of situation
updatePrimaryVariables(well_state);
updatePrimaryVariables(well_state, deferred_logger);
initPrimaryVariablesEvaluation();
std::vector<double> rates;
computeWellRatesWithBhp(ebos_simulator, bhp, rates);
computeWellRatesWithBhp(ebos_simulator, bhp, rates, deferred_logger);
// TODO: double checke the obtained rates
// this is another places we might obtain negative rates
@ -1607,9 +1612,9 @@ namespace Opm
template<typename TypeTag>
double
StandardWell<TypeTag>::
calculateBHPWithTHPTargetIPR() const
calculateBHPWithTHPTargetIPR(Opm::DeferredLogger& deferred_logger) const
{
const double thp_target = this->getTHPConstraint();
const double thp_target = this->getTHPConstraint(deferred_logger);
const double thp_control_index = this->getTHPControlIndex();
const int thp_table_id = well_controls_iget_vfp(well_controls_, thp_control_index);
const double alq = well_controls_iget_alq(well_controls_, thp_control_index);
@ -1627,7 +1632,7 @@ namespace Opm
// TODO: call a/the function for dp
const double dp = (vfp_ref_depth - ref_depth_) * rho * gravity_;
const double bhp_limit = mostStrictBhpFromBhpLimits();
const double bhp_limit = mostStrictBhpFromBhpLimits(deferred_logger);
const double obtain_bhp = vfp_properties_->getProd()->calculateBhpWithTHPTarget(ipr_a_, ipr_b_,
bhp_limit, thp_table_id, thp_target, alq, dp);
@ -1902,7 +1907,8 @@ namespace Opm
template<typename TypeTag>
ConvergenceReport
StandardWell<TypeTag>::
getWellConvergence(const std::vector<double>& B_avg) const
getWellConvergence(const std::vector<double>& B_avg,
Opm::DeferredLogger& deferred_logger) const
{
// the following implementation assume that the polymer is always after the w-o-g phases
// For the polymer case and the energy case, there is one more mass balance equations of reservoir than wells
@ -1966,7 +1972,8 @@ namespace Opm
control_tolerance = 1.e-4; // smaller tolerance for rate control
break;
default:
OPM_THROW(std::runtime_error, "Unknown well control control types for well " << name());
// If this happens, control_tolerance will remain zero and convergence will fail.
deferred_logger.bug("Unknown well control type for well " + name());
}
const int dummy_component = -1;
@ -2042,7 +2049,7 @@ namespace Opm
template<typename TypeTag>
void
StandardWell<TypeTag>::
solveEqAndUpdateWellState(WellState& well_state)
solveEqAndUpdateWellState(WellState& well_state, Opm::DeferredLogger& deferred_logger)
{
if (!this->isOperable()) return;
@ -2051,7 +2058,7 @@ namespace Opm
BVectorWell dx_well(1);
invDuneD_.mv(resWell_, dx_well);
updateWellState(dx_well, well_state);
updateWellState(dx_well, well_state, deferred_logger);
}
@ -2062,9 +2069,10 @@ namespace Opm
void
StandardWell<TypeTag>::
calculateExplicitQuantities(const Simulator& ebosSimulator,
const WellState& well_state)
const WellState& well_state,
Opm::DeferredLogger& deferred_logger)
{
updatePrimaryVariables(well_state);
updatePrimaryVariables(well_state, deferred_logger);
initPrimaryVariablesEvaluation();
computeWellConnectionPressures(ebosSimulator, well_state);
computeAccumWell();
@ -2159,13 +2167,14 @@ namespace Opm
void
StandardWell<TypeTag>::
recoverWellSolutionAndUpdateWellState(const BVector& x,
WellState& well_state) const
WellState& well_state,
Opm::DeferredLogger& deferred_logger) const
{
if (!this->isOperable()) return;
BVectorWell xw(1);
recoverSolutionWell(x, xw);
updateWellState(xw, well_state);
updateWellState(xw, well_state, deferred_logger);
}
@ -2177,7 +2186,8 @@ namespace Opm
StandardWell<TypeTag>::
computeWellRatesWithBhp(const Simulator& ebosSimulator,
const EvalWell& bhp,
std::vector<double>& well_flux) const
std::vector<double>& well_flux,
Opm::DeferredLogger& deferred_logger) const
{
const int np = number_of_phases_;
well_flux.resize(np, 0.0);
@ -2189,13 +2199,13 @@ namespace Opm
const auto& intQuants = *(ebosSimulator.model().cachedIntensiveQuantities(cell_idx, /*timeIdx=*/ 0));
// flux for each perforation
std::vector<EvalWell> mob(num_components_, 0.0);
getMobility(ebosSimulator, perf, mob);
getMobility(ebosSimulator, perf, mob, deferred_logger);
std::vector<EvalWell> cq_s(num_components_, 0.0);
double perf_dis_gas_rate = 0.;
double perf_vap_oil_rate = 0.;
computePerfRate(intQuants, mob, bhp, perf, allow_cf,
cq_s, perf_dis_gas_rate, perf_vap_oil_rate);
cq_s, perf_dis_gas_rate, perf_vap_oil_rate, deferred_logger);
for(int p = 0; p < np; ++p) {
well_flux[ebosCompIdxToFlowCompIdx(p)] += cq_s[p].value();
@ -2212,7 +2222,8 @@ namespace Opm
StandardWell<TypeTag>::
computeWellPotentialWithTHP(const Simulator& ebosSimulator,
const double initial_bhp, // bhp from BHP constraints
const std::vector<double>& initial_potential) const
const std::vector<double>& initial_potential,
Opm::DeferredLogger& deferred_logger) const
{
// TODO: pay attention to the situation that finally the potential is calculated based on the bhp control
// TODO: should we consider the bhp constraints during the iterative process?
@ -2257,7 +2268,7 @@ namespace Opm
rates[ Gas ] = potentials[pu.phase_pos[ Gas ] ];
}
const double bhp_calculated = calculateBhpFromThp(rates, ctrl_index);
const double bhp_calculated = calculateBhpFromThp(rates, ctrl_index, deferred_logger);
if (well_type_ == INJECTOR && bhp_calculated < bhp ) {
bhp = bhp_calculated;
@ -2271,17 +2282,17 @@ namespace Opm
// there should be always some available bhp/thp constraints there
if (std::isinf(bhp) || std::isnan(bhp)) {
OPM_THROW(std::runtime_error, "Unvalid bhp value obtained during the potential calculation for well " << name());
OPM_DEFLOG_THROW(std::runtime_error, "Unvalid bhp value obtained during the potential calculation for well " << name(), deferred_logger);
}
converged = std::abs(old_bhp - bhp) < bhp_tolerance;
computeWellRatesWithBhp(ebosSimulator, bhp, potentials);
computeWellRatesWithBhp(ebosSimulator, bhp, potentials, deferred_logger);
// checking whether the potentials have valid values
for (const double value : potentials) {
if (std::isinf(value) || std::isnan(value)) {
OPM_THROW(std::runtime_error, "Unvalid potential value obtained during the potential calculation for well " << name());
OPM_DEFLOG_THROW(std::runtime_error, "Unvalid potential value obtained during the potential calculation for well " << name(), deferred_logger);
}
}
@ -2300,7 +2311,7 @@ namespace Opm
}
if (!converged) {
OPM_THROW(std::runtime_error, "Failed in getting converged for the potential calculation for well " << name());
OPM_DEFLOG_THROW(std::runtime_error, "Failed in getting converged for the potential calculation for well " << name(), deferred_logger);
}
return potentials;
@ -2318,7 +2329,8 @@ namespace Opm
std::vector<double>& well_potentials,
Opm::DeferredLogger& deferred_logger) // const
{
updatePrimaryVariables(well_state);
updatePrimaryVariables(well_state, deferred_logger);
computeWellConnectionPressures(ebosSimulator, well_state);
// initialize the primary variables in Evaluation, which is used in computePerfRate for computeWellPotentials
@ -2329,13 +2341,12 @@ namespace Opm
well_potentials.resize(np, 0.0);
// get the bhp value based on the bhp constraints
const double bhp = mostStrictBhpFromBhpLimits();
const double bhp = mostStrictBhpFromBhpLimits(deferred_logger);
// does the well have a THP related constraint?
if ( !wellHasTHPConstraints() ) {
assert(std::abs(bhp) != std::numeric_limits<double>::max());
computeWellRatesWithBhp(ebosSimulator, bhp, well_potentials);
computeWellRatesWithBhp(ebosSimulator, bhp, well_potentials, deferred_logger);
} else {
// the well has a THP related constraint
// checking whether a well is newly added, it only happens at the beginning of the report step
@ -2347,7 +2358,7 @@ namespace Opm
}
} else {
// We need to generate a reasonable rates to start the iteration process
computeWellRatesWithBhp(ebosSimulator, bhp, well_potentials);
computeWellRatesWithBhp(ebosSimulator, bhp, well_potentials, deferred_logger);
for (double& value : well_potentials) {
// make the value a little safer in case the BHP limits are default ones
// TODO: a better way should be a better rescaling based on the investigation of the VFP table.
@ -2356,7 +2367,7 @@ namespace Opm
}
}
well_potentials = computeWellPotentialWithTHP(ebosSimulator, bhp, well_potentials);
well_potentials = computeWellPotentialWithTHP(ebosSimulator, bhp, well_potentials, deferred_logger);
}
}
@ -2367,8 +2378,9 @@ namespace Opm
template<typename TypeTag>
void
StandardWell<TypeTag>::
updatePrimaryVariables(const WellState& well_state) const
updatePrimaryVariables(const WellState& well_state, Opm::DeferredLogger& deferred_logger) const
{
if (!this->isOperable()) return;
const int well_index = index_of_well_;
@ -2444,7 +2456,7 @@ namespace Opm
primary_variables_[GFrac] = 1.0 / np;
}
} else {
OPM_THROW(std::logic_error, "Expected PRODUCER or INJECTOR type of well");
OPM_DEFLOG_THROW(std::logic_error, "Expected PRODUCER or INJECTOR type of well", deferred_logger);
}
}
@ -2462,7 +2474,8 @@ namespace Opm
ValueType
StandardWell<TypeTag>::
calculateBhpFromThp(const std::vector<ValueType>& rates,
const int control_index) const
const int control_index,
Opm::DeferredLogger& deferred_logger) const
{
// TODO: when well is under THP control, the BHP is dependent on the rates,
// the well rates is also dependent on the BHP, so it might need to do some iteration.
@ -2500,7 +2513,7 @@ namespace Opm
bhp = vfp_properties_->getProd()->bhp(vfp, aqua, liquid, vapour, thp, alq) - dp;
}
else {
OPM_THROW(std::logic_error, "Expected INJECTOR or PRODUCER well");
OPM_DEFLOG_THROW(std::logic_error, "Expected INJECTOR or PRODUCER well", deferred_logger);
}
return bhp;
@ -2514,7 +2527,8 @@ namespace Opm
double
StandardWell<TypeTag>::
calculateThpFromBhp(const std::vector<double>& rates,
const double bhp) const
const double bhp,
Opm::DeferredLogger& deferred_logger) const
{
assert(int(rates.size()) == 3); // the vfp related only supports three phases now.
@ -2542,7 +2556,7 @@ namespace Opm
thp = vfp_properties_->getProd()->thp(table_id, aqua, liquid, vapour, bhp + dp, alq);
}
else {
OPM_THROW(std::logic_error, "Expected INJECTOR or PRODUCER well");
OPM_DEFLOG_THROW(std::logic_error, "Expected INJECTOR or PRODUCER well", deferred_logger);
}
return thp;
@ -2559,7 +2573,8 @@ namespace Opm
StandardWell<TypeTag>::
updateWaterMobilityWithPolymer(const Simulator& ebos_simulator,
const int perf,
std::vector<EvalWell>& mob) const
std::vector<EvalWell>& mob,
Opm::DeferredLogger& deferred_logger) const
{
const int cell_idx = well_cells_[perf];
const auto& int_quant = *(ebos_simulator.model().cachedIntensiveQuantities(cell_idx, /*timeIdx=*/ 0));
@ -2589,7 +2604,7 @@ namespace Opm
double perf_dis_gas_rate = 0.;
double perf_vap_oil_rate = 0.;
computePerfRate(int_quant, mob, bhp, perf, allow_cf,
cq_s, perf_dis_gas_rate, perf_vap_oil_rate);
cq_s, perf_dis_gas_rate, perf_vap_oil_rate, 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();
@ -2781,7 +2796,7 @@ namespace Opm
// TODO: well state for this well is kind of all zero status
// we should be able to provide a better initialization
calculateExplicitQuantities(ebos_simulator, well_state_copy);
calculateExplicitQuantities(ebos_simulator, well_state_copy, deferred_logger);
updateWellOperability(ebos_simulator, well_state_copy, deferred_logger);
@ -2793,8 +2808,8 @@ namespace Opm
updateWellStateWithTarget(ebos_simulator, well_state_copy, deferred_logger);
calculateExplicitQuantities(ebos_simulator, well_state_copy);
updatePrimaryVariables(well_state_copy);
calculateExplicitQuantities(ebos_simulator, well_state_copy, deferred_logger);
updatePrimaryVariables(well_state_copy, deferred_logger);
initPrimaryVariablesEvaluation();
const bool converged = this->solveWellEqUntilConverged(ebos_simulator, B_avg, well_state_copy, deferred_logger);

View File

@ -147,9 +147,9 @@ namespace Opm
virtual void initPrimaryVariablesEvaluation() const = 0;
virtual ConvergenceReport getWellConvergence(const std::vector<double>& B_avg) const = 0;
virtual ConvergenceReport getWellConvergence(const std::vector<double>& B_avg, Opm::DeferredLogger& deferred_logger) const = 0;
virtual void solveEqAndUpdateWellState(WellState& well_state) = 0;
virtual void solveEqAndUpdateWellState(WellState& well_state, Opm::DeferredLogger& deferred_logger) = 0;
virtual void assembleWellEq(const Simulator& ebosSimulator,
const double dt,
@ -165,12 +165,13 @@ namespace Opm
void setWellEfficiencyFactor(const double efficiency_factor);
void computeRepRadiusPerfLength(const Grid& grid, const std::vector<int>& cartesian_to_compressed);
void computeRepRadiusPerfLength(const Grid& grid, const std::vector<int>& cartesian_to_compressed, Opm::DeferredLogger& deferred_logger);
/// using the solution x to recover the solution xw for wells and applying
/// xw to update Well State
virtual void recoverWellSolutionAndUpdateWellState(const BVector& x,
WellState& well_state) const = 0;
WellState& well_state,
Opm::DeferredLogger& deferred_logger) const = 0;
/// Ax = Ax - C D^-1 B x
virtual void apply(const BVector& x, BVector& Ax) const = 0;
@ -192,10 +193,11 @@ namespace Opm
WellState& well_state,
Opm::DeferredLogger& deferred_logger) /* const */;
virtual void updatePrimaryVariables(const WellState& well_state) const = 0;
virtual void updatePrimaryVariables(const WellState& well_state, Opm::DeferredLogger& deferred_logger) const = 0;
virtual void calculateExplicitQuantities(const Simulator& ebosSimulator,
const WellState& well_state) = 0; // should be const?
const WellState& well_state,
Opm::DeferredLogger& deferred_logger) = 0; // should be const?
/// \brief Wether the Jacobian will also have well contributions in it.
virtual bool jacobianContainsWellContributions() const
@ -249,7 +251,7 @@ namespace Opm
bool wellHasTHPConstraints() const;
/// Returns true if the well is currently in prediction mode (i.e. not history mode).
bool underPredictionMode() const;
bool underPredictionMode(Opm::DeferredLogger& deferred_logger) const;
// update perforation water throughput based on solved water rate
virtual void updateWaterThroughput(const double dt, WellState& well_state) const = 0;
@ -349,14 +351,14 @@ namespace Opm
const WellState& well_state,
Opm::DeferredLogger& deferred_logger) const;
double getTHPConstraint() const;
double getTHPConstraint(Opm::DeferredLogger& deferred_logger) const;
int getTHPControlIndex() const;
// Component fractions for each phase for the well
const std::vector<double>& compFrac() const;
double mostStrictBhpFromBhpLimits() const;
double mostStrictBhpFromBhpLimits(Opm::DeferredLogger& deferred_logger) const;
// a tuple type for ratio limit check.
// first value indicates whether ratio limit is violated, when the ratio limit is not violated, the following two
@ -376,7 +378,7 @@ namespace Opm
double scalingFactor(const int comp_idx) const;
// whether a well is specified with a non-zero and valid VFP table number
bool isVFPActive() const;
bool isVFPActive(Opm::DeferredLogger& deferred_logger) const;
struct OperabilityStatus;

View File

@ -19,6 +19,7 @@
along with OPM. If not, see <http://www.gnu.org/licenses/>.
*/
#include <opm/simulators/DeferredLoggingErrorHelpers.hpp>
namespace Opm
{
@ -330,7 +331,7 @@ namespace Opm
template<typename TypeTag>
double
WellInterface<TypeTag>::
mostStrictBhpFromBhpLimits() const
mostStrictBhpFromBhpLimits(Opm::DeferredLogger& deferred_logger) const
{
double bhp;
@ -343,7 +344,7 @@ namespace Opm
bhp = -std::numeric_limits<double>::max();
break;
default:
OPM_THROW(std::logic_error, "Expected PRODUCER or INJECTOR type for well " << name());
OPM_DEFLOG_THROW(std::logic_error, "Expected PRODUCER or INJECTOR type for well " << name(), deferred_logger);
}
// The number of the well controls/constraints
@ -367,7 +368,7 @@ namespace Opm
}
break;
default:
OPM_THROW(std::logic_error, "Expected PRODUCER or INJECTOR type for well " << name());
OPM_DEFLOG_THROW(std::logic_error, "Expected PRODUCER or INJECTOR type for well " << name(), deferred_logger);
} // end of switch
}
}
@ -393,13 +394,13 @@ namespace Opm
template<typename TypeTag>
double
WellInterface<TypeTag>::
getTHPConstraint() const
getTHPConstraint(Opm::DeferredLogger& deferred_logger) const
{
const int thp_control_index = getTHPControlIndex();
if (thp_control_index < 0) {
OPM_THROW(std::runtime_error, " there is no THP constraint/limit for well " << name()
<< ", while we are requesting it ");
OPM_DEFLOG_THROW(std::runtime_error, " there is no THP constraint/limit for well " << name()
<< ", while we are requesting it ", deferred_logger);
}
return well_controls_iget_target(well_controls_, thp_control_index);
@ -509,7 +510,7 @@ namespace Opm
if (updated_control_index != old_control_index) { // || well_collection_->groupControlActive()) {
updateWellStateWithTarget(ebos_simulator, well_state, deferred_logger);
updatePrimaryVariables(well_state);
updatePrimaryVariables(well_state, deferred_logger);
}
}
@ -520,7 +521,7 @@ namespace Opm
template<typename TypeTag>
bool
WellInterface<TypeTag>::
underPredictionMode() const
underPredictionMode(Opm::DeferredLogger& deferred_logger) const
{
bool under_prediction_mode = false;
@ -532,7 +533,7 @@ namespace Opm
under_prediction_mode = well_ecl_->getInjectionProperties(current_step_).predictionMode;
break;
default:
OPM_THROW(std::logic_error, "Expected PRODUCER or INJECTOR type for well " << name());
OPM_DEFLOG_THROW(std::logic_error, "Expected PRODUCER or INJECTOR type for well " << name(), deferred_logger);
}
return under_prediction_mode;
@ -753,7 +754,7 @@ namespace Opm
// Based on current understanding, only under prediction mode, we need to shut well due to various
// reasons or limits. With more knowlage or testing cases later, this might need to be corrected.
if (!underPredictionMode() ) {
if (!underPredictionMode(deferred_logger) ) {
return;
}
@ -971,7 +972,7 @@ namespace Opm
WellState well_state_copy = well_state;
updatePrimaryVariables(well_state_copy);
updatePrimaryVariables(well_state_copy, deferred_logger);
initPrimaryVariablesEvaluation();
// create a well
@ -1020,7 +1021,9 @@ namespace Opm
void
WellInterface<TypeTag>::
computeRepRadiusPerfLength(const Grid& grid,
const std::vector<int>& cartesian_to_compressed)
const std::vector<int>& cartesian_to_compressed,
Opm::DeferredLogger& deferred_logger
)
{
const int* cart_dims = Opm::UgGridHelpers::cartDims(grid);
auto cell_to_faces = Opm::UgGridHelpers::cell2Faces(grid);
@ -1050,8 +1053,8 @@ namespace Opm
const int cell = cartesian_to_compressed[cart_grid_indx];
if (cell < 0) {
OPM_THROW(std::runtime_error, "Cell with i,j,k indices " << i << ' ' << j << ' '
<< k << " not found in grid (well = " << name() << ')');
OPM_DEFLOG_THROW(std::runtime_error, "Cell with i,j,k indices " << i << ' ' << j << ' '
<< k << " not found in grid (well = " << name() << ')', deferred_logger);
}
{
@ -1076,7 +1079,7 @@ namespace Opm
perf_length = cubical[2];
break;
default:
OPM_THROW(std::runtime_error, " Dirtecion of well is not supported ");
OPM_DEFLOG_THROW(std::runtime_error, " Dirtecion of well is not supported ", deferred_logger);
}
const double repR = std::sqrt(re * radius);
@ -1126,7 +1129,7 @@ namespace Opm
template<typename TypeTag>
bool
WellInterface<TypeTag>::isVFPActive() const
WellInterface<TypeTag>::isVFPActive(Opm::DeferredLogger& deferred_logger) const
{
// since the well_controls only handles the VFP number when THP constraint/target is there.
// we need to get the table number through the parser, in case THP constraint/target is not there.
@ -1141,8 +1144,8 @@ namespace Opm
if (vfp_properties_->getProd()->hasTable(table_id)) {
return true;
} else {
OPM_THROW(std::runtime_error, "VFPPROD table " << std::to_string(table_id) << " is specfied,"
<< " for well " << name() << ", while we could not access it during simulation");
OPM_DEFLOG_THROW(std::runtime_error, "VFPPROD table " << std::to_string(table_id) << " is specfied,"
<< " for well " << name() << ", while we could not access it during simulation", deferred_logger);
}
}
@ -1154,8 +1157,8 @@ namespace Opm
if (vfp_properties_->getInj()->hasTable(table_id)) {
return true;
} else {
OPM_THROW(std::runtime_error, "VFPINJ table " << std::to_string(table_id) << " is specfied,"
<< " for well " << name() << ", while we could not access it during simulation");
OPM_DEFLOG_THROW(std::runtime_error, "VFPINJ table " << std::to_string(table_id) << " is specfied,"
<< " for well " << name() << ", while we could not access it during simulation", deferred_logger);
}
}
}
@ -1181,14 +1184,15 @@ namespace Opm
do {
assembleWellEq(ebosSimulator, dt, well_state, deferred_logger);
auto report = getWellConvergence(B_avg);
auto report = getWellConvergence(B_avg, deferred_logger);
converged = report.converged();
if (converged) {
break;
}
++it;
solveEqAndUpdateWellState(well_state);
solveEqAndUpdateWellState(well_state, deferred_logger);
updateWellControl(ebosSimulator, well_state, deferred_logger);
initPrimaryVariablesEvaluation();
@ -1316,6 +1320,7 @@ namespace Opm
return connectionRates_[perfIdx][activeCompIdx].value();
}
}
// this is not thread safe
OPM_THROW(std::invalid_argument, "The well with name " + name()
+ " does not perforate cell " + std::to_string(cellIdx));
return 0.0;

View File

@ -0,0 +1,72 @@
/*
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 <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_DEFERREDLOGGINGERRORHELPERS_HPP
#define OPM_DEFERREDLOGGINGERRORHELPERS_HPP
#include <opm/simulators/DeferredLogger.hpp>
#include <dune/common/version.hh>
#include <dune/common/parallel/mpihelper.hh>
#include <string>
#include <sstream>
#include <exception>
#include <stdexcept>
// Macro to throw an exception.
// Inspired by ErrorMacros.hpp in opm-common.
// NOTE: For this macro to work, the
// exception class must exhibit a constructor with the signature
// (const std::string &message). Since this condition is not fulfilled
// for the std::exception, you should use this macro with some
// exception class derived from either std::logic_error or
// std::runtime_error.
//
// Usage: OPM_DEFLOG_THROW(ExceptionClass, "Error message " << value, DeferredLogger);
#define OPM_DEFLOG_THROW(Exception, message, deferred_logger) \
do { \
std::ostringstream oss__; \
oss__ << "[" << __FILE__ << ":" << __LINE__ << "] " << message; \
deferred_logger.error(oss__.str()); \
throw Exception(oss__.str()); \
} while (false)
inline void checkForExceptionsAndThrow(int exception_thrown, const std::string& message)
{
const auto& cc = Dune::MPIHelper::getCollectiveCommunication();
if (cc.max(exception_thrown) == 1) {
throw std::logic_error(message);
}
}
inline void logAndCheckForExceptionsAndThrow(Opm::DeferredLogger& deferred_logger, int exception_thrown, const std::string& message, const bool terminal_output)
{
Opm::DeferredLogger global_deferredLogger = gatherDeferredLogger(deferred_logger);
if (terminal_output) {
global_deferredLogger.logMessages();
}
const auto& cc = Dune::MPIHelper::getCollectiveCommunication();
if (cc.max(exception_thrown) == 1) {
throw std::logic_error(message);
}
}
#endif // OPM_DEFERREDLOGGINGERRORHELPERS_HPP