Merge pull request #4197 from akva2/well_group_constraints

Add class for well group constraints
This commit is contained in:
Bård Skaflestad 2022-10-31 16:12:17 +01:00 committed by GitHub
commit dea582d296
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 300 additions and 167 deletions

View File

@ -105,6 +105,7 @@ list (APPEND MAIN_SOURCE_FILES
opm/simulators/wells/VFPInjProperties.cpp
opm/simulators/wells/WellBhpThpCalculator.cpp
opm/simulators/wells/WellConvergence.cpp
opm/simulators/wells/WellGroupConstraints.cpp
opm/simulators/wells/WellGroupControls.cpp
opm/simulators/wells/WellGroupHelpers.cpp
opm/simulators/wells/WellHelpers.cpp
@ -388,6 +389,7 @@ list (APPEND PUBLIC_HEADER_FILES
opm/simulators/wells/WellBhpThpCalculator.hpp
opm/simulators/wells/WellConnectionAuxiliaryModule.hpp
opm/simulators/wells/WellConvergence.hpp
opm/simulators/wells/WellGroupConstraints.hpp
opm/simulators/wells/WellGroupControls.hpp
opm/simulators/wells/WellGroupHelpers.hpp
opm/simulators/wells/WellHelpers.hpp

View File

@ -0,0 +1,202 @@
/*
Copyright 2017 SINTEF Digital, Mathematics and Cybernetics.
Copyright 2017 Statoil ASA.
Copyright 2018 IRIS
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 <config.h>
#include <opm/simulators/wells/WellGroupConstraints.hpp>
#include <opm/core/props/BlackoilPhases.hpp>
#include <opm/input/eclipse/Schedule/Schedule.hpp>
#include <opm/simulators/wells/WellGroupHelpers.hpp>
#include <opm/simulators/wells/WellInterfaceGeneric.hpp>
#include <opm/simulators/wells/WellState.hpp>
namespace Opm
{
std::pair<bool, double>
WellGroupConstraints::
checkGroupConstraintsInj(const Group& group,
const WellState& well_state,
const GroupState& group_state,
const double efficiencyFactor,
const Schedule& schedule,
const SummaryState& summaryState,
const RateConvFunc& rateConverter,
DeferredLogger& deferred_logger) const
{
// Translate injector type from control to Phase.
const auto& well_controls = well_.wellEcl().injectionControls(summaryState);
auto injectorType = well_controls.injector_type;
Phase injectionPhase;
switch (injectorType) {
case InjectorType::WATER:
{
injectionPhase = Phase::WATER;
break;
}
case InjectorType::OIL:
{
injectionPhase = Phase::OIL;
break;
}
case InjectorType::GAS:
{
injectionPhase = Phase::GAS;
break;
}
default:
throw("Expected WATER, OIL or GAS as type for injector " + well_.name());
}
// Make conversion factors for RESV <-> surface rates.
std::vector<double> resv_coeff(well_.phaseUsage().num_phases, 1.0);
rateConverter(0, well_.pvtRegionIdx(), resv_coeff); // FIPNUM region 0 here, should use FIPNUM from WELSPECS.
const auto& ws = well_state.well(well_.indexOfWell());
// Call check for the well's injection phase.
return WellGroupHelpers::checkGroupConstraintsInj(well_.name(),
well_.wellEcl().groupName(),
group,
well_state,
group_state,
well_.currentStep(),
well_.guideRate(),
ws.surface_rates.data(),
injectionPhase,
well_.phaseUsage(),
efficiencyFactor,
schedule,
summaryState,
resv_coeff,
deferred_logger);
}
std::pair<bool, double>
WellGroupConstraints::
checkGroupConstraintsProd(const Group& group,
const WellState& well_state,
const GroupState& group_state,
const double efficiencyFactor,
const Schedule& schedule,
const SummaryState& summaryState,
const RateConvFunc& rateConverter,
DeferredLogger& deferred_logger) const
{
// Make conversion factors for RESV <-> surface rates.
std::vector<double> resv_coeff(well_.phaseUsage().num_phases, 1.0);
rateConverter(0, well_.pvtRegionIdx(), resv_coeff); // FIPNUM region 0 here, should use FIPNUM from WELSPECS.
const auto& ws = well_state.well(well_.indexOfWell());
return WellGroupHelpers::checkGroupConstraintsProd(well_.name(),
well_.wellEcl().groupName(),
group,
well_state,
group_state,
well_.currentStep(),
well_.guideRate(),
ws.surface_rates.data(),
well_.phaseUsage(),
efficiencyFactor,
schedule,
summaryState,
resv_coeff,
deferred_logger);
}
bool WellGroupConstraints::
checkGroupConstraints(WellState& well_state,
const GroupState& group_state,
const Schedule& schedule,
const SummaryState& summaryState,
const RateConvFunc& rateConverter,
DeferredLogger& deferred_logger) const
{
const auto& well = well_.wellEcl();
const int well_index = well_.indexOfWell();
auto& ws = well_state.well(well_index);
if (well.isInjector()) {
const auto currentControl = ws.injection_cmode;
if (currentControl != Well::InjectorCMode::GRUP) {
// This checks only the first encountered group limit,
// in theory there could be several, and then we should
// test all but the one currently applied. At that point,
// this if-statement should be removed and we should always
// check, skipping over only the single group parent whose
// control is the active one for the well (if any).
const auto& group = schedule.getGroup(well.groupName(), well_.currentStep());
const double efficiencyFactor = well.getEfficiencyFactor();
const std::pair<bool, double> group_constraint =
this->checkGroupConstraintsInj(group, well_state,
group_state, efficiencyFactor,
schedule, summaryState,
rateConverter,
deferred_logger);
// If a group constraint was broken, we set the current well control to
// be GRUP.
if (group_constraint.first) {
ws.injection_cmode = Well::InjectorCMode::GRUP;
const int np = well_state.numPhases();
for (int p = 0; p<np; ++p) {
ws.surface_rates[p] *= group_constraint.second;
}
}
return group_constraint.first;
}
}
if (well.isProducer( )) {
const auto currentControl = ws.production_cmode;
if (currentControl != Well::ProducerCMode::GRUP) {
// This checks only the first encountered group limit,
// in theory there could be several, and then we should
// test all but the one currently applied. At that point,
// this if-statement should be removed and we should always
// check, skipping over only the single group parent whose
// control is the active one for the well (if any).
const auto& group = schedule.getGroup(well.groupName(), well_.currentStep());
const double efficiencyFactor = well.getEfficiencyFactor();
const std::pair<bool, double> group_constraint =
this->checkGroupConstraintsProd(group, well_state,
group_state, efficiencyFactor,
schedule, summaryState,
rateConverter, deferred_logger);
// If a group constraint was broken, we set the current well control to
// be GRUP.
if (group_constraint.first) {
ws.production_cmode = Well::ProducerCMode::GRUP;
const int np = well_state.numPhases();
for (int p = 0; p<np; ++p) {
ws.surface_rates[p] *= group_constraint.second;
}
}
return group_constraint.first;
}
}
return false;
}
} // namespace Opm

View File

@ -0,0 +1,85 @@
/*
Copyright 2017 SINTEF Digital, Mathematics and Cybernetics.
Copyright 2017 Statoil ASA.
Copyright 2017 IRIS
Copyright 2019 Norce
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_WELL_GROUP_CONSTRAINTS_HEADER_INCLUDED
#define OPM_WELL_GROUP_CONSTRAINTS_HEADER_INCLUDED
#include <functional>
#include <utility>
#include <vector>
namespace Opm
{
class DeferredLogger;
class Group;
class GroupState;
enum class InjectorType;
using RegionId = int;
class Schedule;
class SummaryState;
class WellInterfaceGeneric;
class WellState;
//! \brief Class for computing well group constraints.
class WellGroupConstraints {
public:
//! \brief Constructor sets reference to well.
WellGroupConstraints(const WellInterfaceGeneric& well) : well_(well) {}
using RateConvFunc = std::function<void(const RegionId, const int, std::vector<double>&)>;
bool checkGroupConstraints(WellState& well_state,
const GroupState& group_state,
const Schedule& schedule,
const SummaryState& summaryState,
const RateConvFunc& rateConverter,
DeferredLogger& deferred_logger) const;
private:
std::pair<bool, double>
checkGroupConstraintsInj(const Group& group,
const WellState& well_state,
const GroupState& group_state,
const double efficiencyFactor,
const Schedule& schedule,
const SummaryState& summaryState,
const RateConvFunc& rateConverter,
DeferredLogger& deferred_logger) const;
std::pair<bool, double>
checkGroupConstraintsProd(const Group& group,
const WellState& well_state,
const GroupState& group_state,
const double efficiencyFactor,
const Schedule& schedule,
const SummaryState& summaryState,
const RateConvFunc& rateConverter,
DeferredLogger& deferred_logger) const;
const WellInterfaceGeneric& well_; //!< Reference to well interface
};
}
#endif // OPM_WELL_GROUP_CONSTRAINTS_HEADER_INCLUDED

View File

@ -22,16 +22,19 @@
#include <config.h>
#include <opm/simulators/wells/WellInterfaceFluidSystem.hpp>
#include <opm/material/fluidsystems/BlackOilFluidSystem.hpp>
#include <opm/grid/utility/RegionMapping.hpp>
#include <opm/input/eclipse/Schedule/Schedule.hpp>
#include <opm/material/fluidsystems/BlackOilFluidSystem.hpp>
#include <opm/simulators/utils/DeferredLogger.hpp>
#include <opm/simulators/wells/GroupState.hpp>
#include <opm/simulators/wells/ParallelWellInfo.hpp>
#include <opm/simulators/wells/RateConverter.hpp>
#include <opm/simulators/wells/SingleWellState.hpp>
#include <opm/simulators/wells/TargetCalculator.hpp>
#include <opm/simulators/wells/WellGroupConstraints.hpp>
#include <opm/simulators/wells/WellGroupControls.hpp>
#include <opm/simulators/wells/WellGroupHelpers.hpp>
#include <opm/simulators/wells/WellState.hpp>
@ -324,96 +327,6 @@ checkIndividualConstraints(SingleWellState& ws,
return false;
}
template <typename FluidSystem>
std::pair<bool, double>
WellInterfaceFluidSystem<FluidSystem>::
checkGroupConstraintsInj(const Group& group,
const WellState& well_state,
const GroupState& group_state,
const double efficiencyFactor,
const Schedule& schedule,
const SummaryState& summaryState,
DeferredLogger& deferred_logger) const
{
// Translate injector type from control to Phase.
const auto& well_controls = this->well_ecl_.injectionControls(summaryState);
auto injectorType = well_controls.injector_type;
Phase injectionPhase;
switch (injectorType) {
case InjectorType::WATER:
{
injectionPhase = Phase::WATER;
break;
}
case InjectorType::OIL:
{
injectionPhase = Phase::OIL;
break;
}
case InjectorType::GAS:
{
injectionPhase = Phase::GAS;
break;
}
default:
throw("Expected WATER, OIL or GAS as type for injector " + name());
}
// Make conversion factors for RESV <-> surface rates.
std::vector<double> resv_coeff(phaseUsage().num_phases, 1.0);
rateConverter_.calcInjCoeff(0, pvtRegionIdx_, resv_coeff); // FIPNUM region 0 here, should use FIPNUM from WELSPECS.
const auto& ws = well_state.well(this->index_of_well_);
// Call check for the well's injection phase.
return WellGroupHelpers::checkGroupConstraintsInj(name(),
well_ecl_.groupName(),
group,
well_state,
group_state,
current_step_,
guide_rate_,
ws.surface_rates.data(),
injectionPhase,
phaseUsage(),
efficiencyFactor,
schedule,
summaryState,
resv_coeff,
deferred_logger);
}
template <typename FluidSystem>
std::pair<bool, double>
WellInterfaceFluidSystem<FluidSystem>::
checkGroupConstraintsProd(const Group& group,
const WellState& well_state,
const GroupState& group_state,
const double efficiencyFactor,
const Schedule& schedule,
const SummaryState& summaryState,
DeferredLogger& deferred_logger) const
{
// Make conversion factors for RESV <-> surface rates.
std::vector<double> resv_coeff(this->phaseUsage().num_phases, 1.0);
rateConverter_.calcCoeff(0, pvtRegionIdx_, resv_coeff); // FIPNUM region 0 here, should use FIPNUM from WELSPECS.
const auto& ws = well_state.well(this->index_of_well_);
return WellGroupHelpers::checkGroupConstraintsProd(name(),
well_ecl_.groupName(),
group,
well_state,
group_state,
current_step_,
guide_rate_,
ws.surface_rates.data(),
phaseUsage(),
efficiencyFactor,
schedule,
summaryState,
resv_coeff,
deferred_logger);
}
template <typename FluidSystem>
bool
WellInterfaceFluidSystem<FluidSystem>::
@ -423,67 +336,14 @@ checkGroupConstraints(WellState& well_state,
const SummaryState& summaryState,
DeferredLogger& deferred_logger) const
{
const auto& well = well_ecl_;
const int well_index = index_of_well_;
auto& ws = well_state.well(well_index);
auto rCoeff = [this](const int id, const int region, std::vector<double>& coeff)
{
this->rateConverter().calcCoeff(id, region, coeff);
};
if (well.isInjector()) {
const auto currentControl = ws.injection_cmode;
if (currentControl != Well::InjectorCMode::GRUP) {
// This checks only the first encountered group limit,
// in theory there could be several, and then we should
// test all but the one currently applied. At that point,
// this if-statement should be removed and we should always
// check, skipping over only the single group parent whose
// control is the active one for the well (if any).
const auto& group = schedule.getGroup( well.groupName(), current_step_ );
const double efficiencyFactor = well.getEfficiencyFactor();
const std::pair<bool, double> group_constraint =
checkGroupConstraintsInj(group, well_state, group_state, efficiencyFactor,
schedule, summaryState, deferred_logger);
// If a group constraint was broken, we set the current well control to
// be GRUP.
if (group_constraint.first) {
ws.injection_cmode = Well::InjectorCMode::GRUP;
const int np = well_state.numPhases();
for (int p = 0; p<np; ++p) {
ws.surface_rates[p] *= group_constraint.second;
}
}
return group_constraint.first;
}
}
if (well.isProducer( )) {
const auto currentControl = ws.production_cmode;
if (currentControl != Well::ProducerCMode::GRUP) {
// This checks only the first encountered group limit,
// in theory there could be several, and then we should
// test all but the one currently applied. At that point,
// this if-statement should be removed and we should always
// check, skipping over only the single group parent whose
// control is the active one for the well (if any).
const auto& group = schedule.getGroup( well.groupName(), current_step_ );
const double efficiencyFactor = well.getEfficiencyFactor();
const std::pair<bool, double> group_constraint =
checkGroupConstraintsProd(group, well_state, group_state, efficiencyFactor,
schedule, summaryState, deferred_logger);
// If a group constraint was broken, we set the current well control to
// be GRUP.
if (group_constraint.first) {
ws.production_cmode = Well::ProducerCMode::GRUP;
const int np = well_state.numPhases();
for (int p = 0; p<np; ++p) {
ws.surface_rates[p] *= group_constraint.second;
}
}
return group_constraint.first;
}
}
return false;
return WellGroupConstraints(*this).checkGroupConstraints(well_state, group_state,
schedule, summaryState,
rCoeff, deferred_logger);
}
template <typename FluidSystem>

View File

@ -89,22 +89,6 @@ protected:
const SummaryState& summaryState,
DeferredLogger& deferred_logger) const;
std::pair<bool, double> checkGroupConstraintsInj(const Group& group,
const WellState& well_state,
const GroupState& group_state,
const double efficiencyFactor,
const Schedule& schedule,
const SummaryState& summaryState,
DeferredLogger& deferred_logger) const;
std::pair<bool, double> checkGroupConstraintsProd(const Group& group,
const WellState& well_state,
const GroupState& group_state,
const double efficiencyFactor,
const Schedule& schedule,
const SummaryState& summaryState,
DeferredLogger& deferred_logger) const;
bool checkGroupConstraints(WellState& well_state,
const GroupState& group_state,
const Schedule& schedule,