mirror of
https://github.com/OPM/opm-simulators.git
synced 2025-02-25 18:55:30 -06:00
Merge pull request #5832 from akva2/blackoilwellmodel_gaslift
changed: move GasLift code in BlackoilWellModel to separate class
This commit is contained in:
commit
09d7e8d8c5
@ -161,6 +161,7 @@ list (APPEND MAIN_SOURCE_FILES
|
||||
opm/simulators/utils/satfunc/RelpermDiagnostics.cpp
|
||||
opm/simulators/wells/ALQState.cpp
|
||||
opm/simulators/wells/BlackoilWellModelConstraints.cpp
|
||||
opm/simulators/wells/BlackoilWellModelGasLift.cpp
|
||||
opm/simulators/wells/BlackoilWellModelGeneric.cpp
|
||||
opm/simulators/wells/BlackoilWellModelGuideRates.cpp
|
||||
opm/simulators/wells/BlackoilWellModelRestart.cpp
|
||||
@ -959,6 +960,8 @@ list (APPEND PUBLIC_HEADER_FILES
|
||||
opm/simulators/wells/BlackoilWellModel.hpp
|
||||
opm/simulators/wells/BlackoilWellModel_impl.hpp
|
||||
opm/simulators/wells/BlackoilWellModelConstraints.hpp
|
||||
opm/simulators/wells/BlackoilWellModelGasLift.hpp
|
||||
opm/simulators/wells/BlackoilWellModelGasLift_impl.hpp
|
||||
opm/simulators/wells/BlackoilWellModelGeneric.hpp
|
||||
opm/simulators/wells/BlackoilWellModelGuideRates.hpp
|
||||
opm/simulators/wells/BlackoilWellModelRestart.hpp
|
||||
|
@ -29,7 +29,6 @@
|
||||
#include <cstddef>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@ -48,6 +47,7 @@
|
||||
|
||||
#include <opm/simulators/linalg/matrixblock.hh>
|
||||
|
||||
#include <opm/simulators/wells/BlackoilWellModelGasLift.hpp>
|
||||
#include <opm/simulators/wells/BlackoilWellModelGeneric.hpp>
|
||||
#include <opm/simulators/wells/BlackoilWellModelGuideRates.hpp>
|
||||
#include <opm/simulators/wells/GasLiftGroupInfo.hpp>
|
||||
@ -80,12 +80,6 @@
|
||||
|
||||
#include <opm/simulators/utils/DeferredLogger.hpp>
|
||||
|
||||
namespace Opm::Parameters {
|
||||
|
||||
struct EnableTerminalOutput { static constexpr bool value = true; };
|
||||
|
||||
} // namespace Opm::Parameters
|
||||
|
||||
namespace Opm {
|
||||
|
||||
#if COMPILE_GPU_BRIDGE
|
||||
@ -110,14 +104,6 @@ template<class Scalar> class WellContributions;
|
||||
using RateVector = GetPropType<TypeTag, Properties::RateVector>;
|
||||
using GlobalEqVector = GetPropType<TypeTag, Properties::GlobalEqVector>;
|
||||
using SparseMatrixAdapter = GetPropType<TypeTag, Properties::SparseMatrixAdapter>;
|
||||
using GasLiftSingleWell = typename WellInterface<TypeTag>::GasLiftSingleWell;
|
||||
using GLiftOptWells = typename BlackoilWellModelGeneric<Scalar>::GLiftOptWells;
|
||||
using GLiftProdWells = typename BlackoilWellModelGeneric<Scalar>::GLiftProdWells;
|
||||
using GLiftWellStateMap =
|
||||
typename BlackoilWellModelGeneric<Scalar>::GLiftWellStateMap;
|
||||
using GLiftEclWells = typename GasLiftGroupInfo<Scalar>::GLiftEclWells;
|
||||
using GLiftSyncGroups = typename GasLiftSingleWellGeneric<Scalar>::GLiftSyncGroups;
|
||||
|
||||
using ModelParameters = BlackoilModelParameters<Scalar>;
|
||||
|
||||
constexpr static std::size_t pressureVarIndex = GetPropType<TypeTag, Properties::Indices>::pressureSwitchIdx;
|
||||
@ -362,8 +348,6 @@ template<class Scalar> class WellContributions;
|
||||
|
||||
void addWellPressureEquationsStruct(PressureMatrix& jacobian) const;
|
||||
|
||||
void initGliftEclWellMap(GLiftEclWells &ecl_well_map);
|
||||
|
||||
/// \brief Get list of local nonshut wells
|
||||
const std::vector<WellInterfacePtr>& localNonshutWells() const
|
||||
{
|
||||
@ -525,23 +509,6 @@ template<class Scalar> class WellContributions;
|
||||
// TODO: finding a better naming
|
||||
void assembleWellEqWithoutIteration(const double dt, DeferredLogger& deferred_logger);
|
||||
|
||||
bool maybeDoGasLiftOptimize(DeferredLogger& deferred_logger);
|
||||
|
||||
void gasLiftOptimizationStage1(DeferredLogger& deferred_logger,
|
||||
GLiftProdWells& prod_wells,
|
||||
GLiftOptWells& glift_wells,
|
||||
GasLiftGroupInfo<Scalar>& group_info,
|
||||
GLiftWellStateMap& state_map);
|
||||
|
||||
// cannot be const since it accesses the non-const WellState
|
||||
void gasLiftOptimizationStage1SingleWell(WellInterface<TypeTag>* well,
|
||||
DeferredLogger& deferred_logger,
|
||||
GLiftProdWells& prod_wells,
|
||||
GLiftOptWells& glift_wells,
|
||||
GasLiftGroupInfo<Scalar>& group_info,
|
||||
GLiftWellStateMap& state_map,
|
||||
GLiftSyncGroups& groups_to_sync);
|
||||
|
||||
void extractLegacyCellPvtRegionIndex_();
|
||||
|
||||
void extractLegacyDepth_();
|
||||
@ -569,6 +536,8 @@ template<class Scalar> class WellContributions;
|
||||
private:
|
||||
BlackoilWellModel(Simulator& simulator, const PhaseUsage& pu);
|
||||
|
||||
BlackoilWellModelGasLift<TypeTag> gaslift_;
|
||||
|
||||
// These members are used to avoid reallocation in specific functions
|
||||
// instead of using local variables.
|
||||
// Their state is not relevant between function calls, so they can
|
||||
|
110
opm/simulators/wells/BlackoilWellModelGasLift.cpp
Normal file
110
opm/simulators/wells/BlackoilWellModelGasLift.cpp
Normal file
@ -0,0 +1,110 @@
|
||||
/*
|
||||
Copyright 2016 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2016 - 2017 Statoil ASA.
|
||||
Copyright 2017 Dr. Blatt - HPC-Simulation-Software & Services
|
||||
Copyright 2016 - 2018 IRIS AS
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <opm/simulators/utils/DeferredLogger.hpp>
|
||||
|
||||
#include <opm/simulators/wells/BlackoilWellModelGasLift.hpp>
|
||||
#include <opm/simulators/wells/GasLiftStage2.hpp>
|
||||
#include <opm/simulators/wells/WellInterfaceGeneric.hpp>
|
||||
#include <opm/simulators/wells/WellState.hpp>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
template<class Scalar>
|
||||
void BlackoilWellModelGasLiftGeneric<Scalar>::
|
||||
gliftDebug([[maybe_unused]] const std::string& msg,
|
||||
[[maybe_unused]] DeferredLogger& deferred_logger) const
|
||||
{
|
||||
if constexpr (glift_debug) {
|
||||
if (terminal_output_) {
|
||||
const std::string message =
|
||||
fmt::format(" GLIFT (DEBUG) : BlackoilWellModel : {}", msg);
|
||||
deferred_logger.info(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class Scalar>
|
||||
void BlackoilWellModelGasLiftGeneric<Scalar>::
|
||||
gliftDebugShowALQ(const std::vector<WellInterfaceGeneric<Scalar>*>& well_container,
|
||||
const WellState<Scalar>& wellState,
|
||||
DeferredLogger& deferred_logger)
|
||||
{
|
||||
for (const auto& well : well_container) {
|
||||
if (well->isProducer()) {
|
||||
auto alq = wellState.getALQ(well->name());
|
||||
const std::string msg = fmt::format("ALQ_REPORT : {} : {}",
|
||||
well->name(), alq);
|
||||
gliftDebug(msg, deferred_logger);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If a group has any production rate constraints, and/or a limit
|
||||
// on its total rate of lift gas supply, allocate lift gas
|
||||
// preferentially to the wells that gain the most benefit from
|
||||
// it. Lift gas increments are allocated in turn to the well that
|
||||
// currently has the largest weighted incremental gradient. The
|
||||
// procedure takes account of any limits on the group production
|
||||
// rate or lift gas supply applied to any level of group.
|
||||
template<class Scalar>
|
||||
void BlackoilWellModelGasLiftGeneric<Scalar>::
|
||||
gasLiftOptimizationStage2(const Parallel::Communication& comm,
|
||||
const Schedule& schedule,
|
||||
const SummaryState& summaryState,
|
||||
WellState<Scalar>& wellState,
|
||||
GroupState<Scalar>& groupState,
|
||||
GLiftProdWells& prod_wells,
|
||||
GLiftOptWells& glift_wells,
|
||||
GasLiftGroupInfo<Scalar>& group_info,
|
||||
GLiftWellStateMap& glift_well_state_map,
|
||||
const int episodeIndex,
|
||||
DeferredLogger& deferred_logger)
|
||||
|
||||
{
|
||||
GasLiftStage2 glift {episodeIndex,
|
||||
comm,
|
||||
schedule,
|
||||
summaryState,
|
||||
deferred_logger,
|
||||
wellState,
|
||||
groupState,
|
||||
prod_wells,
|
||||
glift_wells,
|
||||
group_info,
|
||||
glift_well_state_map,
|
||||
this->glift_debug
|
||||
};
|
||||
glift.runOptimize();
|
||||
}
|
||||
|
||||
template class BlackoilWellModelGasLiftGeneric<double>;
|
||||
|
||||
#if FLOW_INSTANTIATE_FLOAT
|
||||
template class BlackoilWellModelGasLiftGeneric<float>;
|
||||
#endif
|
||||
|
||||
}
|
143
opm/simulators/wells/BlackoilWellModelGasLift.hpp
Normal file
143
opm/simulators/wells/BlackoilWellModelGasLift.hpp
Normal file
@ -0,0 +1,143 @@
|
||||
/*
|
||||
Copyright 2016 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2016 - 2017 Statoil ASA.
|
||||
Copyright 2017 Dr. Blatt - HPC-Simulation-Software & Services
|
||||
Copyright 2016 - 2018 IRIS AS
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
OPM is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef OPM_BLACKOILWELLMODEL_GASLIFT_HEADER_INCLUDED
|
||||
#define OPM_BLACKOILWELLMODEL_GASLIFT_HEADER_INCLUDED
|
||||
|
||||
#include "opm/models/utils/basicproperties.hh"
|
||||
#include <opm/simulators/wells/GasLiftSingleWellGeneric.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
class DeferredLogger;
|
||||
template<class Scalar> class GroupState;
|
||||
template<class Scalar> class WellState;
|
||||
template<class TypeTag> class WellInterface;
|
||||
|
||||
template<class Scalar>
|
||||
class BlackoilWellModelGasLiftGeneric
|
||||
{
|
||||
public:
|
||||
using GLiftOptWells = std::map<std::string, std::unique_ptr<GasLiftSingleWellGeneric<Scalar>>>;
|
||||
using GLiftProdWells = std::map<std::string, const WellInterfaceGeneric<Scalar>*>;
|
||||
using GLiftWellStateMap = std::map<std::string, std::unique_ptr<GasLiftWellState<Scalar>>>;
|
||||
using GLiftEclWells = typename GasLiftGroupInfo<Scalar>::GLiftEclWells;
|
||||
using GLiftSyncGroups = typename GasLiftSingleWellGeneric<Scalar>::GLiftSyncGroups;
|
||||
|
||||
explicit BlackoilWellModelGasLiftGeneric(bool terminal_output)
|
||||
: terminal_output_(terminal_output)
|
||||
{}
|
||||
|
||||
static constexpr bool glift_debug = false;
|
||||
|
||||
void gliftDebug(const std::string& msg,
|
||||
DeferredLogger& deferred_logger) const;
|
||||
|
||||
bool terminalOutput() const { return terminal_output_; }
|
||||
|
||||
protected:
|
||||
void gliftDebugShowALQ(const std::vector<WellInterfaceGeneric<Scalar>*>& well_container,
|
||||
const WellState<Scalar>& wellState,
|
||||
DeferredLogger& deferred_logger);
|
||||
|
||||
void gasLiftOptimizationStage2(const Parallel::Communication& comm,
|
||||
const Schedule& schedule,
|
||||
const SummaryState& summaryState,
|
||||
WellState<Scalar>& wellState,
|
||||
GroupState<Scalar>& groupState,
|
||||
GLiftProdWells& prod_wells,
|
||||
GLiftOptWells& glift_wells,
|
||||
GasLiftGroupInfo<Scalar>& group_info,
|
||||
GLiftWellStateMap& map,
|
||||
const int episodeIndex,
|
||||
DeferredLogger& deferred_logger);
|
||||
|
||||
bool terminal_output_;
|
||||
double last_glift_opt_time_ = -1.0;
|
||||
};
|
||||
|
||||
/// Class for handling the gaslift in the blackoil well model.
|
||||
template<typename TypeTag>
|
||||
class BlackoilWellModelGasLift :
|
||||
public BlackoilWellModelGasLiftGeneric<GetPropType<TypeTag, Properties::Scalar>>
|
||||
{
|
||||
using Base = BlackoilWellModelGasLiftGeneric<GetPropType<TypeTag, Properties::Scalar>>;
|
||||
|
||||
public:
|
||||
using Scalar = GetPropType<TypeTag, Properties::Scalar>;
|
||||
using GLiftEclWells = typename GasLiftGroupInfo<Scalar>::GLiftEclWells;
|
||||
using GLiftOptWells = typename Base::GLiftOptWells;
|
||||
using GLiftProdWells = typename Base::GLiftProdWells;
|
||||
using GLiftSyncGroups = typename GasLiftSingleWellGeneric<Scalar>::GLiftSyncGroups;
|
||||
using GLiftWellStateMap = typename Base::GLiftWellStateMap;
|
||||
using Simulator = GetPropType<TypeTag, Properties::Simulator>;
|
||||
using WellInterfacePtr = std::shared_ptr<WellInterface<TypeTag>>;
|
||||
|
||||
BlackoilWellModelGasLift(bool terminal_output,
|
||||
const PhaseUsage& phase_usage)
|
||||
: Base(terminal_output)
|
||||
, phase_usage_(phase_usage)
|
||||
{}
|
||||
|
||||
static void initGliftEclWellMap(const std::vector<WellInterfacePtr>& well_container,
|
||||
GLiftEclWells& ecl_well_map);
|
||||
|
||||
bool maybeDoGasLiftOptimize(const Simulator& simulator,
|
||||
const std::vector<WellInterfacePtr>& well_container,
|
||||
WellState<Scalar>& wellState,
|
||||
GroupState<Scalar>& groupState,
|
||||
DeferredLogger& deferred_logger);
|
||||
|
||||
private:
|
||||
void gasLiftOptimizationStage1(const Simulator& simulator,
|
||||
const std::vector<WellInterfacePtr>& well_container,
|
||||
WellState<Scalar>& wellState,
|
||||
GroupState<Scalar>& groupState,
|
||||
GLiftProdWells& prod_wells,
|
||||
GLiftOptWells& glift_wells,
|
||||
GasLiftGroupInfo<Scalar>& group_info,
|
||||
GLiftWellStateMap& state_map,
|
||||
DeferredLogger& deferred_logger);
|
||||
|
||||
// cannot be const since it accesses the non-const WellState
|
||||
void gasLiftOptimizationStage1SingleWell(WellInterface<TypeTag>* well,
|
||||
const Simulator& simulator,
|
||||
WellState<Scalar>& wellState,
|
||||
GroupState<Scalar>& groupState,
|
||||
GLiftProdWells& prod_wells,
|
||||
GLiftOptWells& glift_wells,
|
||||
GasLiftGroupInfo<Scalar>& group_info,
|
||||
GLiftWellStateMap& state_map,
|
||||
GLiftSyncGroups& groups_to_sync,
|
||||
DeferredLogger& deferred_logger);
|
||||
|
||||
const PhaseUsage& phase_usage_;
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#include "BlackoilWellModelGasLift_impl.hpp"
|
||||
|
||||
#endif
|
295
opm/simulators/wells/BlackoilWellModelGasLift_impl.hpp
Normal file
295
opm/simulators/wells/BlackoilWellModelGasLift_impl.hpp
Normal file
@ -0,0 +1,295 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
#define OPM_BLACKOILWELLMODEL_GASLIFT_IMPL_HEADER_INCLUDED
|
||||
#define OPM_BLACKOILWELLMODEL_GASLIFT_IMPL_HEADER_INCLUDED
|
||||
|
||||
// Improve IDE experience
|
||||
#ifndef OPM_BLACKOILWELLMODEL_GASLIFT_HEADER_INCLUDED
|
||||
#include <config.h>
|
||||
#include <opm/simulators/wells/BlackoilWellModelGasLift.hpp>
|
||||
#endif
|
||||
|
||||
#include <opm/simulators/wells/GasLiftSingleWell.hpp>
|
||||
|
||||
#if HAVE_MPI
|
||||
#include <opm/simulators/utils/MPISerializer.hpp>
|
||||
#endif
|
||||
|
||||
namespace Opm {
|
||||
|
||||
template<typename TypeTag>
|
||||
bool
|
||||
BlackoilWellModelGasLift<TypeTag>::
|
||||
maybeDoGasLiftOptimize(const Simulator& simulator,
|
||||
const std::vector<WellInterfacePtr>& well_container,
|
||||
WellState<Scalar>& wellState,
|
||||
GroupState<Scalar>& groupState,
|
||||
DeferredLogger& deferred_logger)
|
||||
{
|
||||
bool do_glift_optimization = false;
|
||||
int num_wells_changed = 0;
|
||||
const double simulation_time = simulator.time();
|
||||
const Scalar min_wait = simulator.vanguard().schedule().glo(simulator.episodeIndex()).min_wait();
|
||||
// We only optimize if a min_wait time has past.
|
||||
// If all_newton is true we still want to optimize several times pr timestep
|
||||
// i.e. we also optimize if check simulation_time == last_glift_opt_time_
|
||||
// that is when the last_glift_opt_time is already updated with the current time step
|
||||
if (simulation_time == this->last_glift_opt_time_ ||
|
||||
simulation_time >= (this->last_glift_opt_time_ + min_wait))
|
||||
{
|
||||
do_glift_optimization = true;
|
||||
this->last_glift_opt_time_ = simulation_time;
|
||||
}
|
||||
|
||||
if (do_glift_optimization) {
|
||||
GLiftOptWells glift_wells;
|
||||
GLiftProdWells prod_wells;
|
||||
GLiftWellStateMap state_map;
|
||||
// NOTE: To make GasLiftGroupInfo (see below) independent of the TypeTag
|
||||
// associated with *this (i.e. BlackoilWellModel<TypeTag>) we observe
|
||||
// that GasLiftGroupInfo's only dependence on *this is that it needs to
|
||||
// access the eclipse Wells in the well container (the eclipse Wells
|
||||
// themselves are independent of the TypeTag).
|
||||
// Hence, we extract them from the well container such that we can pass
|
||||
// them to the GasLiftGroupInfo constructor.
|
||||
GLiftEclWells ecl_well_map;
|
||||
initGliftEclWellMap(well_container, ecl_well_map);
|
||||
GasLiftGroupInfo group_info {
|
||||
ecl_well_map,
|
||||
simulator.vanguard().schedule(),
|
||||
simulator.vanguard().summaryState(),
|
||||
simulator.episodeIndex(),
|
||||
simulator.model().newtonMethod().numIterations(),
|
||||
phase_usage_,
|
||||
deferred_logger,
|
||||
wellState,
|
||||
groupState,
|
||||
simulator.vanguard().grid().comm(),
|
||||
this->glift_debug
|
||||
};
|
||||
group_info.initialize();
|
||||
|
||||
gasLiftOptimizationStage1(simulator,
|
||||
well_container,
|
||||
wellState,
|
||||
groupState,
|
||||
prod_wells,
|
||||
glift_wells,
|
||||
group_info,
|
||||
state_map,
|
||||
deferred_logger);
|
||||
|
||||
this->gasLiftOptimizationStage2(simulator.vanguard().gridView().comm(),
|
||||
simulator.vanguard().schedule(),
|
||||
simulator.vanguard().summaryState(),
|
||||
wellState,
|
||||
groupState,
|
||||
prod_wells,
|
||||
glift_wells,
|
||||
group_info,
|
||||
state_map,
|
||||
simulator.episodeIndex(),
|
||||
deferred_logger);
|
||||
|
||||
if constexpr (this->glift_debug) {
|
||||
std::vector<WellInterfaceGeneric<Scalar>*> wc;
|
||||
wc.reserve(well_container.size());
|
||||
for (const auto& w : well_container) {
|
||||
wc.push_back(static_cast<WellInterfaceGeneric<Scalar>*>(w.get()));
|
||||
}
|
||||
this->gliftDebugShowALQ(wc,
|
||||
wellState,
|
||||
deferred_logger);
|
||||
}
|
||||
num_wells_changed = glift_wells.size();
|
||||
}
|
||||
num_wells_changed = simulator.vanguard().gridView().comm().sum(num_wells_changed);
|
||||
return num_wells_changed > 0;
|
||||
}
|
||||
|
||||
template<typename TypeTag>
|
||||
void
|
||||
BlackoilWellModelGasLift<TypeTag>::
|
||||
gasLiftOptimizationStage1(const Simulator& simulator,
|
||||
const std::vector<WellInterfacePtr>& well_container,
|
||||
WellState<Scalar>& wellState,
|
||||
GroupState<Scalar>& groupState,
|
||||
GLiftProdWells& prod_wells,
|
||||
GLiftOptWells &glift_wells,
|
||||
GasLiftGroupInfo<Scalar>& group_info,
|
||||
GLiftWellStateMap& state_map,
|
||||
DeferredLogger& deferred_logger)
|
||||
{
|
||||
auto comm = simulator.vanguard().grid().comm();
|
||||
int num_procs = comm.size();
|
||||
// NOTE: Gas lift optimization stage 1 seems to be difficult
|
||||
// to do in parallel since the wells are optimized on different
|
||||
// processes and each process needs to know the current ALQ allocated
|
||||
// to each group it is a memeber of in order to check group limits and avoid
|
||||
// allocating more ALQ than necessary. (Surplus ALQ is removed in
|
||||
// stage 2). In stage1, as each well is adding ALQ, the current group ALQ needs
|
||||
// to be communicated to the other processes. But there is no common
|
||||
// synchronization point that all process will reach in the
|
||||
// runOptimizeLoop_() in GasLiftSingleWell.cpp.
|
||||
//
|
||||
// TODO: Maybe a better solution could be invented by distributing
|
||||
// wells according to certain parent groups. Then updated group rates
|
||||
// might not have to be communicated to the other processors.
|
||||
|
||||
// Currently, the best option seems to be to run this part sequentially
|
||||
// (not in parallel).
|
||||
//
|
||||
// TODO: The simplest approach seems to be if a) one process could take
|
||||
// ownership of all the wells (the union of all the wells in the
|
||||
// well_container_ of each process) then this process could do the
|
||||
// optimization, while the other processes could wait for it to
|
||||
// finish (e.g. comm.barrier()), or alternatively, b) if all
|
||||
// processes could take ownership of all the wells. Then there
|
||||
// would be no need for synchronization here..
|
||||
//
|
||||
for (int i = 0; i< num_procs; i++) {
|
||||
int num_rates_to_sync = 0; // communication variable
|
||||
GLiftSyncGroups groups_to_sync;
|
||||
if (comm.rank() == i) {
|
||||
// Run stage1: Optimize single wells while also checking group limits
|
||||
for (const auto& well : well_container) {
|
||||
// NOTE: Only the wells in "group_info" needs to be optimized
|
||||
if (group_info.hasWell(well->name())) {
|
||||
gasLiftOptimizationStage1SingleWell(well.get(),
|
||||
simulator,
|
||||
wellState,
|
||||
groupState,
|
||||
prod_wells,
|
||||
glift_wells,
|
||||
group_info,
|
||||
state_map,
|
||||
groups_to_sync,
|
||||
deferred_logger);
|
||||
}
|
||||
}
|
||||
num_rates_to_sync = groups_to_sync.size();
|
||||
}
|
||||
num_rates_to_sync = comm.sum(num_rates_to_sync);
|
||||
if (num_rates_to_sync > 0) {
|
||||
std::vector<int> group_indexes;
|
||||
group_indexes.reserve(num_rates_to_sync);
|
||||
std::vector<Scalar> group_alq_rates;
|
||||
group_alq_rates.reserve(num_rates_to_sync);
|
||||
std::vector<Scalar> group_oil_rates;
|
||||
group_oil_rates.reserve(num_rates_to_sync);
|
||||
std::vector<Scalar> group_gas_rates;
|
||||
group_gas_rates.reserve(num_rates_to_sync);
|
||||
std::vector<Scalar> group_water_rates;
|
||||
group_water_rates.reserve(num_rates_to_sync);
|
||||
if (comm.rank() == i) {
|
||||
for (auto idx : groups_to_sync) {
|
||||
auto [oil_rate, gas_rate, water_rate, alq] = group_info.getRates(idx);
|
||||
group_indexes.push_back(idx);
|
||||
group_oil_rates.push_back(oil_rate);
|
||||
group_gas_rates.push_back(gas_rate);
|
||||
group_water_rates.push_back(water_rate);
|
||||
group_alq_rates.push_back(alq);
|
||||
}
|
||||
} else {
|
||||
group_indexes.resize(num_rates_to_sync);
|
||||
group_oil_rates.resize(num_rates_to_sync);
|
||||
group_gas_rates.resize(num_rates_to_sync);
|
||||
group_water_rates.resize(num_rates_to_sync);
|
||||
group_alq_rates.resize(num_rates_to_sync);
|
||||
}
|
||||
#if HAVE_MPI
|
||||
Parallel::MpiSerializer ser(comm);
|
||||
ser.broadcast(i, group_indexes, group_oil_rates,
|
||||
group_gas_rates, group_water_rates, group_alq_rates);
|
||||
#endif
|
||||
if (comm.rank() != i) {
|
||||
for (int j = 0; j < num_rates_to_sync; ++j) {
|
||||
group_info.updateRate(group_indexes[j],
|
||||
group_oil_rates[j],
|
||||
group_gas_rates[j],
|
||||
group_water_rates[j],
|
||||
group_alq_rates[j]);
|
||||
}
|
||||
}
|
||||
if (this->glift_debug) {
|
||||
int counter = 0;
|
||||
if (comm.rank() == i) {
|
||||
counter = wellState.gliftGetDebugCounter();
|
||||
}
|
||||
counter = comm.sum(counter);
|
||||
if (comm.rank() != i) {
|
||||
wellState.gliftSetDebugCounter(counter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: this method cannot be const since it passes this->wellState()
|
||||
// (see below) to the GasLiftSingleWell constructor which accepts WellState
|
||||
// as a non-const reference..
|
||||
template<typename TypeTag>
|
||||
void
|
||||
BlackoilWellModelGasLift<TypeTag>::
|
||||
gasLiftOptimizationStage1SingleWell(WellInterface<TypeTag>* well,
|
||||
const Simulator& simulator,
|
||||
WellState<Scalar>& wellState,
|
||||
GroupState<Scalar>& groupState,
|
||||
GLiftProdWells& prod_wells,
|
||||
GLiftOptWells& glift_wells,
|
||||
GasLiftGroupInfo<Scalar>& group_info,
|
||||
GLiftWellStateMap& state_map,
|
||||
GLiftSyncGroups& sync_groups,
|
||||
DeferredLogger& deferred_logger)
|
||||
{
|
||||
const auto& summary_state = simulator.vanguard().summaryState();
|
||||
auto glift = std::make_unique<GasLiftSingleWell<TypeTag>>(*well,
|
||||
simulator,
|
||||
summary_state,
|
||||
deferred_logger,
|
||||
wellState,
|
||||
groupState,
|
||||
group_info,
|
||||
sync_groups,
|
||||
simulator.vanguard().gridView().comm(),
|
||||
this->glift_debug);
|
||||
auto state = glift->runOptimize(simulator.model().newtonMethod().numIterations());
|
||||
if (state) {
|
||||
state_map.emplace(well->name(), std::move(state));
|
||||
glift_wells.emplace(well->name(), std::move(glift));
|
||||
return;
|
||||
}
|
||||
prod_wells.insert({well->name(), well});
|
||||
}
|
||||
|
||||
template<typename TypeTag>
|
||||
void
|
||||
BlackoilWellModelGasLift<TypeTag>::
|
||||
initGliftEclWellMap(const std::vector<WellInterfacePtr>& well_container,
|
||||
GLiftEclWells& ecl_well_map)
|
||||
{
|
||||
for (const auto& well : well_container) {
|
||||
ecl_well_map.try_emplace(well->name(), &well->wellEcl(), well->indexOfWell());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Opm
|
@ -49,6 +49,8 @@
|
||||
|
||||
#include <opm/input/eclipse/Units/Units.hpp>
|
||||
|
||||
#include <opm/models/utils/parametersystem.hpp>
|
||||
|
||||
#include <opm/simulators/utils/DeferredLogger.hpp>
|
||||
#include <opm/simulators/wells/BlackoilWellModelConstraints.hpp>
|
||||
#include <opm/simulators/wells/BlackoilWellModelGuideRates.hpp>
|
||||
@ -93,6 +95,8 @@ BlackoilWellModelGeneric(Schedule& schedule,
|
||||
, eclState_(eclState)
|
||||
, comm_(comm)
|
||||
, phase_usage_(phase_usage)
|
||||
, terminal_output_(comm_.rank() == 0 &&
|
||||
Parameters::Get<Parameters::EnableTerminalOutput>())
|
||||
, wbpCalculationService_ { eclState.gridDims(), comm_ }
|
||||
, guideRate_(schedule)
|
||||
, active_wgstate_(phase_usage)
|
||||
@ -1613,64 +1617,6 @@ setRepRadiusPerfLength()
|
||||
}
|
||||
}
|
||||
|
||||
template<class Scalar>
|
||||
void BlackoilWellModelGeneric<Scalar>::
|
||||
gliftDebug(const std::string& msg,
|
||||
DeferredLogger& deferred_logger) const
|
||||
{
|
||||
if (this->glift_debug && this->terminal_output_) {
|
||||
const std::string message = fmt::format(
|
||||
" GLIFT (DEBUG) : BlackoilWellModel : {}", msg);
|
||||
deferred_logger.info(message);
|
||||
}
|
||||
}
|
||||
|
||||
template<class Scalar>
|
||||
void BlackoilWellModelGeneric<Scalar>::
|
||||
gliftDebugShowALQ(DeferredLogger& deferred_logger)
|
||||
{
|
||||
for (auto& well : this->well_container_generic_) {
|
||||
if (well->isProducer()) {
|
||||
auto alq = this->wellState().getALQ(well->name());
|
||||
const std::string msg = fmt::format("ALQ_REPORT : {} : {}",
|
||||
well->name(), alq);
|
||||
gliftDebug(msg, deferred_logger);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If a group has any production rate constraints, and/or a limit
|
||||
// on its total rate of lift gas supply, allocate lift gas
|
||||
// preferentially to the wells that gain the most benefit from
|
||||
// it. Lift gas increments are allocated in turn to the well that
|
||||
// currently has the largest weighted incremental gradient. The
|
||||
// procedure takes account of any limits on the group production
|
||||
// rate or lift gas supply applied to any level of group.
|
||||
template<class Scalar>
|
||||
void BlackoilWellModelGeneric<Scalar>::
|
||||
gasLiftOptimizationStage2(DeferredLogger& deferred_logger,
|
||||
GLiftProdWells& prod_wells,
|
||||
GLiftOptWells& glift_wells,
|
||||
GasLiftGroupInfo<Scalar>& group_info,
|
||||
GLiftWellStateMap& glift_well_state_map,
|
||||
const int episodeIndex)
|
||||
{
|
||||
GasLiftStage2 glift {episodeIndex,
|
||||
comm_,
|
||||
schedule_,
|
||||
summaryState_,
|
||||
deferred_logger,
|
||||
this->wellState(),
|
||||
this->groupState(),
|
||||
prod_wells,
|
||||
glift_wells,
|
||||
group_info,
|
||||
glift_well_state_map,
|
||||
this->glift_debug
|
||||
};
|
||||
glift.runOptimize();
|
||||
}
|
||||
|
||||
template<class Scalar>
|
||||
void BlackoilWellModelGeneric<Scalar>::
|
||||
updateWellPotentials(const int reportStepIdx,
|
||||
|
@ -75,6 +75,12 @@ namespace Opm { namespace data {
|
||||
struct NodeData;
|
||||
}} // namespace Opm::data
|
||||
|
||||
namespace Opm::Parameters {
|
||||
|
||||
struct EnableTerminalOutput { static constexpr bool value = true; };
|
||||
|
||||
} // namespace Opm::Parameters
|
||||
|
||||
namespace Opm {
|
||||
|
||||
/// Class for handling the blackoil well model.
|
||||
@ -82,11 +88,6 @@ template<class Scalar>
|
||||
class BlackoilWellModelGeneric
|
||||
{
|
||||
public:
|
||||
// --------- Types ---------
|
||||
using GLiftOptWells = std::map<std::string, std::unique_ptr<GasLiftSingleWellGeneric<Scalar>>>;
|
||||
using GLiftProdWells = std::map<std::string, const WellInterfaceGeneric<Scalar>*>;
|
||||
using GLiftWellStateMap = std::map<std::string, std::unique_ptr<GasLiftWellState<Scalar>>>;
|
||||
|
||||
BlackoilWellModelGeneric(Schedule& schedule,
|
||||
const SummaryState& summaryState,
|
||||
const EclipseState& eclState,
|
||||
@ -242,7 +243,6 @@ public:
|
||||
serializer(active_wgstate_);
|
||||
serializer(last_valid_wgstate_);
|
||||
serializer(nupcol_wgstate_);
|
||||
serializer(last_glift_opt_time_);
|
||||
serializer(switched_prod_groups_);
|
||||
serializer(switched_inj_groups_);
|
||||
serializer(closed_offending_wells_);
|
||||
@ -260,7 +260,6 @@ public:
|
||||
this->active_wgstate_ == rhs.active_wgstate_ &&
|
||||
this->last_valid_wgstate_ == rhs.last_valid_wgstate_ &&
|
||||
this->nupcol_wgstate_ == rhs.nupcol_wgstate_ &&
|
||||
this->last_glift_opt_time_ == rhs.last_glift_opt_time_ &&
|
||||
this->switched_prod_groups_ == rhs.switched_prod_groups_ &&
|
||||
this->switched_inj_groups_ == rhs.switched_inj_groups_ &&
|
||||
this->closed_offending_wells_ == rhs.closed_offending_wells_;
|
||||
@ -399,18 +398,6 @@ protected:
|
||||
|
||||
void setRepRadiusPerfLength();
|
||||
|
||||
void gliftDebug(const std::string& msg,
|
||||
DeferredLogger& deferred_logger) const;
|
||||
|
||||
void gliftDebugShowALQ(DeferredLogger& deferred_logger);
|
||||
|
||||
void gasLiftOptimizationStage2(DeferredLogger& deferred_logger,
|
||||
GLiftProdWells& prod_wells,
|
||||
GLiftOptWells& glift_wells,
|
||||
GasLiftGroupInfo<Scalar>& group_info,
|
||||
GLiftWellStateMap& map,
|
||||
const int episodeIndex);
|
||||
|
||||
virtual void computePotentials(const std::size_t widx,
|
||||
const WellState<Scalar>& well_state_copy,
|
||||
std::string& exc_msg,
|
||||
@ -628,10 +615,6 @@ protected:
|
||||
WGState<Scalar> last_valid_wgstate_;
|
||||
WGState<Scalar> nupcol_wgstate_;
|
||||
|
||||
bool glift_debug = false;
|
||||
|
||||
double last_glift_opt_time_ = -1.0;
|
||||
|
||||
bool wellStructureChangedDynamically_{false};
|
||||
|
||||
// Store maps of group name and new group controls for output
|
||||
|
@ -79,10 +79,8 @@ namespace Opm {
|
||||
phase_usage,
|
||||
simulator.gridView().comm())
|
||||
, simulator_(simulator)
|
||||
, gaslift_(this->terminal_output_, this->phase_usage_)
|
||||
{
|
||||
this->terminal_output_ = (simulator.gridView().comm().rank() == 0)
|
||||
&& Parameters::Get<Parameters::EnableTerminalOutput>();
|
||||
|
||||
local_num_cells_ = simulator_.gridView().size(0);
|
||||
|
||||
// Number of cells the global grid view
|
||||
@ -680,11 +678,18 @@ namespace Opm {
|
||||
}
|
||||
|
||||
try {
|
||||
using GLiftEclWells = typename GasLiftGroupInfo<Scalar>::GLiftEclWells;
|
||||
GLiftEclWells ecl_well_map;
|
||||
initGliftEclWellMap(ecl_well_map);
|
||||
well->wellTesting(simulator_, simulationTime, this->wellState(),
|
||||
this->groupState(), this->wellTestState(), this->phase_usage_,
|
||||
ecl_well_map, this->well_open_times_, deferred_logger);
|
||||
gaslift_.initGliftEclWellMap(well_container_, ecl_well_map);
|
||||
well->wellTesting(simulator_,
|
||||
simulationTime,
|
||||
this->wellState(),
|
||||
this->groupState(),
|
||||
this->wellTestState(),
|
||||
this->phase_usage_,
|
||||
ecl_well_map,
|
||||
this->well_open_times_,
|
||||
deferred_logger);
|
||||
} catch (const std::exception& e) {
|
||||
const std::string msg = fmt::format("Exception during testing of well: {}. The well will not open.\n Exception message: {}", wellEcl.name(), e.what());
|
||||
deferred_logger.warning("WELL_TESTING_FAILED", msg);
|
||||
@ -844,8 +849,9 @@ namespace Opm {
|
||||
{
|
||||
rate = 0;
|
||||
|
||||
if (!is_cell_perforated_[elemIdx])
|
||||
if (!is_cell_perforated_[elemIdx]) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& well : well_container_)
|
||||
well->addCellRates(rate, elemIdx);
|
||||
@ -864,8 +870,9 @@ namespace Opm {
|
||||
rate = 0;
|
||||
int elemIdx = context.globalSpaceIndex(spaceIdx, timeIdx);
|
||||
|
||||
if (!is_cell_perforated_[elemIdx])
|
||||
if (!is_cell_perforated_[elemIdx]) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& well : well_container_)
|
||||
well->addCellRates(rate, elemIdx);
|
||||
@ -1233,12 +1240,14 @@ namespace Opm {
|
||||
assemble(const int iterationIdx,
|
||||
const double dt)
|
||||
{
|
||||
|
||||
DeferredLogger local_deferredLogger;
|
||||
if (this->glift_debug) {
|
||||
const std::string msg = fmt::format(
|
||||
"assemble() : iteration {}" , iterationIdx);
|
||||
this->gliftDebug(msg, local_deferredLogger);
|
||||
|
||||
if constexpr (gaslift_.glift_debug) {
|
||||
if (gaslift_.terminalOutput()) {
|
||||
const std::string msg =
|
||||
fmt::format("assemble() : iteration {}" , iterationIdx);
|
||||
gaslift_.gliftDebug(msg, local_deferredLogger);
|
||||
}
|
||||
}
|
||||
last_report_ = SimulatorReportSingle();
|
||||
Dune::Timer perfTimer;
|
||||
@ -1334,7 +1343,9 @@ namespace Opm {
|
||||
DeferredLogger& local_deferredLogger)
|
||||
{
|
||||
auto [well_group_control_changed, more_network_update] =
|
||||
updateWellControls(mandatory_network_balance, local_deferredLogger, relax_network_tolerance);
|
||||
updateWellControls(mandatory_network_balance,
|
||||
local_deferredLogger,
|
||||
relax_network_tolerance);
|
||||
|
||||
bool alq_updated = false;
|
||||
OPM_BEGIN_PARALLEL_TRY_CATCH();
|
||||
@ -1342,14 +1353,19 @@ namespace Opm {
|
||||
// Set the well primary variables based on the value of well solutions
|
||||
initPrimaryVariablesEvaluation();
|
||||
|
||||
alq_updated = maybeDoGasLiftOptimize(local_deferredLogger);
|
||||
alq_updated = gaslift_.maybeDoGasLiftOptimize(simulator_,
|
||||
well_container_,
|
||||
this->wellState(),
|
||||
this->groupState(),
|
||||
local_deferredLogger);
|
||||
|
||||
prepareWellsBeforeAssembling(dt, local_deferredLogger);
|
||||
}
|
||||
OPM_END_PARALLEL_TRY_CATCH_LOG(local_deferredLogger, "updateWellControlsAndNetworkIteration() failed: ",
|
||||
OPM_END_PARALLEL_TRY_CATCH_LOG(local_deferredLogger,
|
||||
"updateWellControlsAndNetworkIteration() failed: ",
|
||||
this->terminal_output_, grid().comm());
|
||||
|
||||
//update guide rates
|
||||
// update guide rates
|
||||
const int reportStepIdx = simulator_.episodeIndex();
|
||||
if (alq_updated || BlackoilWellModelGuideRates(*this).
|
||||
guideRateUpdateIsNeeded(reportStepIdx)) {
|
||||
@ -1591,212 +1607,6 @@ namespace Opm {
|
||||
}
|
||||
|
||||
|
||||
template<typename TypeTag>
|
||||
bool
|
||||
BlackoilWellModel<TypeTag>::
|
||||
maybeDoGasLiftOptimize(DeferredLogger& deferred_logger)
|
||||
{
|
||||
bool do_glift_optimization = false;
|
||||
int num_wells_changed = 0;
|
||||
const double simulation_time = simulator_.time();
|
||||
const Scalar min_wait = simulator_.vanguard().schedule().glo(simulator_.episodeIndex()).min_wait();
|
||||
// We only optimize if a min_wait time has past.
|
||||
// If all_newton is true we still want to optimize several times pr timestep
|
||||
// i.e. we also optimize if check simulation_time == last_glift_opt_time_
|
||||
// that is when the last_glift_opt_time is already updated with the current time step
|
||||
if ( simulation_time == this->last_glift_opt_time_ || simulation_time >= (this->last_glift_opt_time_ + min_wait)) {
|
||||
do_glift_optimization = true;
|
||||
this->last_glift_opt_time_ = simulation_time;
|
||||
}
|
||||
|
||||
if (do_glift_optimization) {
|
||||
GLiftOptWells glift_wells;
|
||||
GLiftProdWells prod_wells;
|
||||
GLiftWellStateMap state_map;
|
||||
// NOTE: To make GasLiftGroupInfo (see below) independent of the TypeTag
|
||||
// associated with *this (i.e. BlackoilWellModel<TypeTag>) we observe
|
||||
// that GasLiftGroupInfo's only dependence on *this is that it needs to
|
||||
// access the eclipse Wells in the well container (the eclipse Wells
|
||||
// themselves are independent of the TypeTag).
|
||||
// Hence, we extract them from the well container such that we can pass
|
||||
// them to the GasLiftGroupInfo constructor.
|
||||
GLiftEclWells ecl_well_map;
|
||||
initGliftEclWellMap(ecl_well_map);
|
||||
GasLiftGroupInfo group_info {
|
||||
ecl_well_map,
|
||||
simulator_.vanguard().schedule(),
|
||||
simulator_.vanguard().summaryState(),
|
||||
simulator_.episodeIndex(),
|
||||
simulator_.model().newtonMethod().numIterations(),
|
||||
this->phase_usage_,
|
||||
deferred_logger,
|
||||
this->wellState(),
|
||||
this->groupState(),
|
||||
simulator_.vanguard().grid().comm(),
|
||||
this->glift_debug
|
||||
};
|
||||
group_info.initialize();
|
||||
gasLiftOptimizationStage1(deferred_logger, prod_wells, glift_wells,
|
||||
group_info, state_map);
|
||||
this->gasLiftOptimizationStage2(deferred_logger, prod_wells, glift_wells,
|
||||
group_info, state_map, simulator_.episodeIndex());
|
||||
if (this->glift_debug) {
|
||||
this->gliftDebugShowALQ(deferred_logger);
|
||||
}
|
||||
num_wells_changed = glift_wells.size();
|
||||
}
|
||||
num_wells_changed = this->comm_.sum(num_wells_changed);
|
||||
return num_wells_changed > 0;
|
||||
}
|
||||
|
||||
template<typename TypeTag>
|
||||
void
|
||||
BlackoilWellModel<TypeTag>::
|
||||
gasLiftOptimizationStage1(DeferredLogger& deferred_logger,
|
||||
GLiftProdWells& prod_wells,
|
||||
GLiftOptWells &glift_wells,
|
||||
GasLiftGroupInfo<Scalar>& group_info,
|
||||
GLiftWellStateMap& state_map)
|
||||
{
|
||||
auto comm = simulator_.vanguard().grid().comm();
|
||||
int num_procs = comm.size();
|
||||
// NOTE: Gas lift optimization stage 1 seems to be difficult
|
||||
// to do in parallel since the wells are optimized on different
|
||||
// processes and each process needs to know the current ALQ allocated
|
||||
// to each group it is a memeber of in order to check group limits and avoid
|
||||
// allocating more ALQ than necessary. (Surplus ALQ is removed in
|
||||
// stage 2). In stage1, as each well is adding ALQ, the current group ALQ needs
|
||||
// to be communicated to the other processes. But there is no common
|
||||
// synchronization point that all process will reach in the
|
||||
// runOptimizeLoop_() in GasLiftSingleWell.cpp.
|
||||
//
|
||||
// TODO: Maybe a better solution could be invented by distributing
|
||||
// wells according to certain parent groups. Then updated group rates
|
||||
// might not have to be communicated to the other processors.
|
||||
|
||||
// Currently, the best option seems to be to run this part sequentially
|
||||
// (not in parallel).
|
||||
//
|
||||
// TODO: The simplest approach seems to be if a) one process could take
|
||||
// ownership of all the wells (the union of all the wells in the
|
||||
// well_container_ of each process) then this process could do the
|
||||
// optimization, while the other processes could wait for it to
|
||||
// finish (e.g. comm.barrier()), or alternatively, b) if all
|
||||
// processes could take ownership of all the wells. Then there
|
||||
// would be no need for synchronization here..
|
||||
//
|
||||
for (int i = 0; i< num_procs; i++) {
|
||||
int num_rates_to_sync = 0; // communication variable
|
||||
GLiftSyncGroups groups_to_sync;
|
||||
if (comm.rank() == i) {
|
||||
// Run stage1: Optimize single wells while also checking group limits
|
||||
for (const auto& well : well_container_) {
|
||||
// NOTE: Only the wells in "group_info" needs to be optimized
|
||||
if (group_info.hasWell(well->name())) {
|
||||
gasLiftOptimizationStage1SingleWell(
|
||||
well.get(), deferred_logger, prod_wells, glift_wells,
|
||||
group_info, state_map, groups_to_sync
|
||||
);
|
||||
}
|
||||
}
|
||||
num_rates_to_sync = groups_to_sync.size();
|
||||
}
|
||||
num_rates_to_sync = comm.sum(num_rates_to_sync);
|
||||
if (num_rates_to_sync > 0) {
|
||||
std::vector<int> group_indexes;
|
||||
group_indexes.reserve(num_rates_to_sync);
|
||||
std::vector<Scalar> group_alq_rates;
|
||||
group_alq_rates.reserve(num_rates_to_sync);
|
||||
std::vector<Scalar> group_oil_rates;
|
||||
group_oil_rates.reserve(num_rates_to_sync);
|
||||
std::vector<Scalar> group_gas_rates;
|
||||
group_gas_rates.reserve(num_rates_to_sync);
|
||||
std::vector<Scalar> group_water_rates;
|
||||
group_water_rates.reserve(num_rates_to_sync);
|
||||
if (comm.rank() == i) {
|
||||
for (auto idx : groups_to_sync) {
|
||||
auto [oil_rate, gas_rate, water_rate, alq] = group_info.getRates(idx);
|
||||
group_indexes.push_back(idx);
|
||||
group_oil_rates.push_back(oil_rate);
|
||||
group_gas_rates.push_back(gas_rate);
|
||||
group_water_rates.push_back(water_rate);
|
||||
group_alq_rates.push_back(alq);
|
||||
}
|
||||
} else {
|
||||
group_indexes.resize(num_rates_to_sync);
|
||||
group_oil_rates.resize(num_rates_to_sync);
|
||||
group_gas_rates.resize(num_rates_to_sync);
|
||||
group_water_rates.resize(num_rates_to_sync);
|
||||
group_alq_rates.resize(num_rates_to_sync);
|
||||
}
|
||||
#if HAVE_MPI
|
||||
Parallel::MpiSerializer ser(comm);
|
||||
ser.broadcast(i, group_indexes, group_oil_rates,
|
||||
group_gas_rates, group_water_rates, group_alq_rates);
|
||||
#endif
|
||||
if (comm.rank() != i) {
|
||||
for (int j=0; j<num_rates_to_sync; j++) {
|
||||
group_info.updateRate(group_indexes[j],
|
||||
group_oil_rates[j], group_gas_rates[j], group_water_rates[j], group_alq_rates[j]);
|
||||
}
|
||||
}
|
||||
if (this->glift_debug) {
|
||||
int counter = 0;
|
||||
if (comm.rank() == i) {
|
||||
counter = this->wellState().gliftGetDebugCounter();
|
||||
}
|
||||
counter = comm.sum(counter);
|
||||
if (comm.rank() != i) {
|
||||
this->wellState().gliftSetDebugCounter(counter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: this method cannot be const since it passes this->wellState()
|
||||
// (see below) to the GasLiftSingleWell constructor which accepts WellState
|
||||
// as a non-const reference..
|
||||
template<typename TypeTag>
|
||||
void
|
||||
BlackoilWellModel<TypeTag>::
|
||||
gasLiftOptimizationStage1SingleWell(WellInterface<TypeTag>* well,
|
||||
DeferredLogger& deferred_logger,
|
||||
GLiftProdWells& prod_wells,
|
||||
GLiftOptWells& glift_wells,
|
||||
GasLiftGroupInfo<Scalar>& group_info,
|
||||
GLiftWellStateMap& state_map,
|
||||
GLiftSyncGroups& sync_groups)
|
||||
{
|
||||
const auto& summary_state = simulator_.vanguard().summaryState();
|
||||
std::unique_ptr<GasLiftSingleWell> glift
|
||||
= std::make_unique<GasLiftSingleWell>(
|
||||
*well, simulator_, summary_state,
|
||||
deferred_logger, this->wellState(), this->groupState(),
|
||||
group_info, sync_groups, this->comm_, this->glift_debug);
|
||||
auto state = glift->runOptimize(
|
||||
simulator_.model().newtonMethod().numIterations());
|
||||
if (state) {
|
||||
state_map.insert({well->name(), std::move(state)});
|
||||
glift_wells.insert({well->name(), std::move(glift)});
|
||||
return;
|
||||
}
|
||||
prod_wells.insert({well->name(), well});
|
||||
}
|
||||
|
||||
|
||||
template<typename TypeTag>
|
||||
void
|
||||
BlackoilWellModel<TypeTag>::
|
||||
initGliftEclWellMap(GLiftEclWells &ecl_well_map)
|
||||
{
|
||||
for ( const auto& well: well_container_ ) {
|
||||
ecl_well_map.try_emplace(
|
||||
well->name(), &(well->wellEcl()), well->indexOfWell());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename TypeTag>
|
||||
void
|
||||
BlackoilWellModel<TypeTag>::
|
||||
|
@ -25,12 +25,13 @@
|
||||
#include <opm/models/discretization/common/fvbaseproperties.hh>
|
||||
#include <opm/simulators/wells/GasLiftSingleWellGeneric.hpp>
|
||||
#include <opm/simulators/wells/GasLiftGroupInfo.hpp>
|
||||
#include <opm/simulators/wells/WellInterface.hpp>
|
||||
|
||||
#include <optional>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
template<class TypeTag> class WellInterface;
|
||||
|
||||
template<class TypeTag>
|
||||
class GasLiftSingleWell : public GasLiftSingleWellGeneric<GetPropType<TypeTag, Properties::Scalar>>
|
||||
{
|
||||
|
@ -27,11 +27,13 @@
|
||||
#endif
|
||||
|
||||
#include <opm/input/eclipse/Schedule/GasLiftOpt.hpp>
|
||||
#include <fmt/format.h>
|
||||
#include <opm/input/eclipse/Schedule/Well/Well.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
template<typename TypeTag>
|
||||
|
@ -22,6 +22,8 @@
|
||||
#ifndef OPM_MULTISEGMENTWELL_HEADER_INCLUDED
|
||||
#define OPM_MULTISEGMENTWELL_HEADER_INCLUDED
|
||||
|
||||
#include <opm/models/common/multiphasebaseproperties.hh>
|
||||
|
||||
#include <opm/simulators/wells/WellInterface.hpp>
|
||||
#include <opm/simulators/wells/MultisegmentWellEval.hpp>
|
||||
|
||||
|
@ -37,6 +37,8 @@ namespace Opm {
|
||||
|
||||
#include <opm/input/eclipse/Schedule/Well/WellTestState.hpp>
|
||||
|
||||
#include <opm/material/fluidstates/BlackOilFluidState.hpp>
|
||||
|
||||
#include <opm/simulators/wells/BlackoilWellModel.hpp>
|
||||
#include <opm/simulators/wells/GasLiftGroupInfo.hpp>
|
||||
#include <opm/simulators/wells/GasLiftSingleWell.hpp>
|
||||
@ -82,12 +84,7 @@ public:
|
||||
using SparseMatrixAdapter = GetPropType<TypeTag, Properties::SparseMatrixAdapter>;
|
||||
using RateVector = GetPropType<TypeTag, Properties::RateVector>;
|
||||
using GasLiftSingleWell = ::Opm::GasLiftSingleWell<TypeTag>;
|
||||
using GLiftOptWells = typename BlackoilWellModel<TypeTag>::GLiftOptWells;
|
||||
using GLiftProdWells = typename BlackoilWellModel<TypeTag>::GLiftProdWells;
|
||||
using GLiftEclWells = typename GasLiftGroupInfo<Scalar>::GLiftEclWells;
|
||||
using GLiftWellStateMap =
|
||||
typename BlackoilWellModel<TypeTag>::GLiftWellStateMap;
|
||||
using GLiftSyncGroups = typename GasLiftSingleWellGeneric<Scalar>::GLiftSyncGroups;
|
||||
|
||||
using VectorBlockType = Dune::FieldVector<Scalar, Indices::numEq>;
|
||||
using MatrixBlockType = Dune::FieldMatrix<Scalar, Indices::numEq, Indices::numEq>;
|
||||
|
@ -324,7 +324,6 @@ public:
|
||||
active_wgstate_ = WGState<double>::serializationTestObject(dummy);
|
||||
last_valid_wgstate_ = WGState<double>::serializationTestObject(dummy);
|
||||
nupcol_wgstate_ = WGState<double>::serializationTestObject(dummy);
|
||||
last_glift_opt_time_ = 5.0;
|
||||
switched_prod_groups_ = {{"test4", {Group::ProductionCMode::NONE, Group::ProductionCMode::ORAT}}};
|
||||
const auto controls = {Group::InjectionCMode::NONE, Group::InjectionCMode::RATE, Group::InjectionCMode::RATE };
|
||||
switched_inj_groups_ = {{"test4", {controls, {}, controls} }};
|
||||
|
@ -175,7 +175,8 @@ BOOST_AUTO_TEST_CASE(G1)
|
||||
WellState &well_state = well_model.wellState();
|
||||
const auto &group_state = well_model.groupState();
|
||||
GLiftEclWells ecl_well_map;
|
||||
well_model.initGliftEclWellMap(ecl_well_map);
|
||||
Opm::BlackoilWellModelGasLift<TypeTag>::
|
||||
initGliftEclWellMap(well_model.localNonshutWells(), ecl_well_map);
|
||||
const int iteration_idx = simulator->model().newtonMethod().numIterations();
|
||||
const auto& comm = simulator->vanguard().grid().comm();
|
||||
GasLiftGroupInfo group_info {
|
||||
|
Loading…
Reference in New Issue
Block a user