mirror of
https://github.com/OPM/opm-simulators.git
synced 2024-12-22 07:23:27 -06:00
added: support WCYCLE
This commit is contained in:
parent
82a9698d27
commit
0470502027
@ -317,11 +317,14 @@ public:
|
||||
// \Note: The report steps are met in any case
|
||||
// \Note: The sub stepping will require a copy of the state variables
|
||||
if (adaptiveTimeStepping_) {
|
||||
auto tuningUpdater = [enableTUNING, this, reportStep = timer.currentStepNum()]()
|
||||
auto tuningUpdater = [enableTUNING, this,
|
||||
reportStep = timer.currentStepNum()](const double curr_time,
|
||||
double dt, const int timeStep)
|
||||
{
|
||||
auto& schedule = this->simulator_.vanguard().schedule();
|
||||
auto& events = this->schedule()[reportStep].events();
|
||||
|
||||
bool result = false;
|
||||
if (events.hasEvent(ScheduleEvents::TUNING_CHANGE)) {
|
||||
// Unset the event to not trigger it again on the next sub step
|
||||
schedule.clear_event(ScheduleEvents::TUNING_CHANGE, reportStep);
|
||||
@ -335,14 +338,46 @@ public:
|
||||
// \Note: Need to update both solver (model) and simulator since solver is re-created each report step.
|
||||
solver_->model().updateTUNING(tuning);
|
||||
this->updateTUNING(tuning);
|
||||
dt = this->adaptiveTimeStepping_->suggestedNextStep();
|
||||
} else {
|
||||
dt = max_next_tstep;
|
||||
this->adaptiveTimeStepping_->updateNEXTSTEP(max_next_tstep);
|
||||
}
|
||||
return max_next_tstep >0;
|
||||
result = max_next_tstep > 0;
|
||||
}
|
||||
return false;
|
||||
|
||||
const auto& wcycle = schedule[reportStep].wcycle.get();
|
||||
if (wcycle.empty()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const auto& wmatcher = schedule.wellMatcher(reportStep);
|
||||
double wcycle_time_step =
|
||||
wcycle.nextTimeStep(curr_time,
|
||||
dt,
|
||||
wmatcher,
|
||||
this->wellModel_().wellOpenTimes(),
|
||||
this->wellModel_().wellCloseTimes(),
|
||||
[this, reportStep, schedule, timeStep](const std::string& name)
|
||||
{
|
||||
if (timeStep != 0) {
|
||||
return false;
|
||||
}
|
||||
const auto& wg_events = schedule[reportStep].wellgroup_events();
|
||||
return wg_events.hasEvent(name, ScheduleEvents::REQUEST_OPEN_WELL);
|
||||
});
|
||||
|
||||
if (dt != wcycle_time_step) {
|
||||
this->adaptiveTimeStepping_->updateNEXTSTEP(wcycle_time_step);
|
||||
return true;
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
tuningUpdater();
|
||||
|
||||
tuningUpdater(timer.simulationTimeElapsed(),
|
||||
this->adaptiveTimeStepping_->suggestedNextStep(), 0);
|
||||
|
||||
const auto& events = schedule()[timer.currentStepNum()].events();
|
||||
bool event = events.hasEvent(ScheduleEvents::NEW_WELL) ||
|
||||
events.hasEvent(ScheduleEvents::INJECTION_TYPE_CHANGED) ||
|
||||
|
@ -180,10 +180,10 @@ void registerAdaptiveParameters();
|
||||
SimulatorReport step(const SimulatorTimer& simulatorTimer,
|
||||
Solver& solver,
|
||||
const bool isEvent,
|
||||
const std::function<bool()> tuningUpdater)
|
||||
const std::function<bool(const double, const double, const int)> tuningUpdater)
|
||||
{
|
||||
// Maybe update tuning
|
||||
tuningUpdater();
|
||||
tuningUpdater(simulatorTimer.simulationTimeElapsed(), suggestedNextTimestep_, 0);
|
||||
SimulatorReport report;
|
||||
const double timestep = simulatorTimer.currentStepLength();
|
||||
|
||||
@ -215,7 +215,9 @@ void registerAdaptiveParameters();
|
||||
// Maybe update tuning
|
||||
// get current delta t
|
||||
auto oldValue = suggestedNextTimestep_;
|
||||
if (tuningUpdater()) {
|
||||
if (tuningUpdater(substepTimer.simulationTimeElapsed(),
|
||||
substepTimer.currentStepLength(),
|
||||
substepTimer.currentStepNum())) {
|
||||
// Use provideTimeStepEstimate to make we sure don't simulate longer than the report step is.
|
||||
substepTimer.provideTimeStepEstimate(suggestedNextTimestep_);
|
||||
suggestedNextTimestep_ = oldValue;
|
||||
|
@ -672,7 +672,6 @@ const KeywordValidation::UnsupportedKeywords& unsupportedKeywords()
|
||||
{"WCONINJP", {true, std::nullopt}},
|
||||
{"WCUTBACK", {true, std::nullopt}},
|
||||
{"WCUTBACT", {true, std::nullopt}},
|
||||
{"WCYCLE", {true, std::nullopt}},
|
||||
{"WDRILTIM", {true, std::nullopt}},
|
||||
{"WDRILPRI", {true, std::nullopt}},
|
||||
{"WDRILRES", {true, std::nullopt}},
|
||||
|
@ -450,7 +450,7 @@ template<class Scalar> class WellContributions;
|
||||
// Keep track of the domain of each well, if using subdomains.
|
||||
std::map<std::string, int> well_domain_;
|
||||
|
||||
// Store the local index of the wells perforated cells in the domain, if using sumdomains
|
||||
// Store the local index of the wells perforated cells in the domain, if using subdomains
|
||||
SparseTable<int> well_local_cells_;
|
||||
|
||||
const Grid& grid() const
|
||||
|
@ -205,6 +205,9 @@ public:
|
||||
|
||||
const GuideRate& guideRate() const { return guideRate_; }
|
||||
|
||||
const std::map<std::string, double>& wellOpenTimes() const { return well_open_times_; }
|
||||
const std::map<std::string, double>& wellCloseTimes() const { return well_close_times_; }
|
||||
|
||||
bool reportStepStarts() const { return report_step_starts_; }
|
||||
|
||||
bool shouldBalanceNetwork(const int reportStepIndex,
|
||||
@ -468,6 +471,12 @@ protected:
|
||||
std::vector<Well> wells_ecl_;
|
||||
std::vector<std::vector<PerforationData<Scalar>>> well_perf_data_;
|
||||
|
||||
// Times at which wells were opened (for WCYCLE)
|
||||
std::map<std::string, double> well_open_times_;
|
||||
|
||||
// Times at which wells were shut (for WCYCLE)
|
||||
std::map<std::string, double> well_close_times_;
|
||||
|
||||
/// Connection index mappings
|
||||
class ConnectionIndexMap
|
||||
{
|
||||
|
@ -33,6 +33,7 @@
|
||||
#include <opm/input/eclipse/Schedule/Network/Balance.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Network/ExtNetwork.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Well/PAvgDynamicSourceData.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Well/WellMatcher.hpp>
|
||||
#include <opm/input/eclipse/Schedule/Well/WellTestConfig.hpp>
|
||||
|
||||
#include <opm/input/eclipse/Units/UnitSystem.hpp>
|
||||
@ -177,6 +178,11 @@ namespace Opm {
|
||||
const auto& events = this->schedule()[reportStepIdx].wellgroup_events();
|
||||
for (auto& wellPtr : this->well_container_) {
|
||||
const bool well_opened_this_step = this->report_step_starts_ && events.hasEvent(wellPtr->name(), effective_events_mask);
|
||||
if (well_opened_this_step && this->wellState().well(wellPtr->name()).status == Well::Status::OPEN) {
|
||||
this->well_open_times_.insert_or_assign(wellPtr->name(), this->simulator_.time());
|
||||
this->well_close_times_.erase(wellPtr->name());
|
||||
}
|
||||
|
||||
wellPtr->init(&this->phase_usage_, this->depth_, this->gravity_, this->B_avg_, well_opened_this_step);
|
||||
}
|
||||
}
|
||||
@ -673,7 +679,7 @@ namespace Opm {
|
||||
initGliftEclWellMap(ecl_well_map);
|
||||
well->wellTesting(simulator_, simulationTime, this->wellState(),
|
||||
this->groupState(), this->wellTestState(), this->phase_usage_,
|
||||
ecl_well_map, deferred_logger);
|
||||
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);
|
||||
@ -919,6 +925,13 @@ namespace Opm {
|
||||
if (nw > 0) {
|
||||
well_container_.reserve(nw);
|
||||
|
||||
const auto& wmatcher = this->schedule().wellMatcher(report_step);
|
||||
const auto& wcycle = this->schedule()[report_step].wcycle.get();
|
||||
const auto cycle_states = wcycle.wellStatus(this->simulator_.time(),
|
||||
wmatcher,
|
||||
this->well_open_times_,
|
||||
this->well_close_times_);
|
||||
|
||||
for (int w = 0; w < nw; ++w) {
|
||||
const Well& well_ecl = this->wells_ecl_[w];
|
||||
|
||||
@ -940,6 +953,8 @@ namespace Opm {
|
||||
this->wellState().shutWell(w);
|
||||
}
|
||||
|
||||
this->well_open_times_.erase(well_name);
|
||||
this->well_close_times_.erase(well_name);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -957,6 +972,9 @@ namespace Opm {
|
||||
if (!closed_this_step) {
|
||||
this->wellTestState().open_well(well_name);
|
||||
this->wellTestState().open_completions(well_name);
|
||||
this->well_open_times_.insert_or_assign(well_name,
|
||||
this->simulator_.time());
|
||||
this->well_close_times_.erase(well_name);
|
||||
}
|
||||
events.clearEvent(ScheduleEvents::REQUEST_OPEN_WELL);
|
||||
}
|
||||
@ -970,12 +988,16 @@ namespace Opm {
|
||||
if (well_ecl.getAutomaticShutIn()) {
|
||||
// shut wells are not added to the well container
|
||||
this->wellState().shutWell(w);
|
||||
this->well_close_times_.erase(well_name);
|
||||
this->well_open_times_.erase(well_name);
|
||||
continue;
|
||||
} else {
|
||||
if (!well_ecl.getAllowCrossFlow()) {
|
||||
// stopped wells where cross flow is not allowed
|
||||
// are not added to the well container
|
||||
this->wellState().shutWell(w);
|
||||
this->well_close_times_.erase(well_name);
|
||||
this->well_open_times_.erase(well_name);
|
||||
continue;
|
||||
}
|
||||
// stopped wells are added to the container but marked as stopped
|
||||
@ -993,19 +1015,55 @@ namespace Opm {
|
||||
// Treat as shut, do not add to container.
|
||||
local_deferredLogger.debug(fmt::format(" Well {} gets shut due to having zero rate constraint and disallowing crossflow ", well_ecl.name()) );
|
||||
this->wellState().shutWell(w);
|
||||
this->well_close_times_.erase(well_name);
|
||||
this->well_open_times_.erase(well_name);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (well_status == Well::Status::STOP) {
|
||||
this->wellState().stopWell(w);
|
||||
this->well_close_times_.erase(well_name);
|
||||
this->well_open_times_.erase(well_name);
|
||||
wellIsStopped = true;
|
||||
}
|
||||
|
||||
if (!wcycle.empty()) {
|
||||
const auto it = cycle_states.find(well_name);
|
||||
if (it != cycle_states.end()) {
|
||||
if (!it->second) {
|
||||
this->wellState().shutWell(w);
|
||||
continue;
|
||||
} else {
|
||||
this->wellState().openWell(w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
well_container_.emplace_back(this->createWellPointer(w, report_step));
|
||||
|
||||
if (wellIsStopped)
|
||||
if (wellIsStopped) {
|
||||
well_container_.back()->stopWell();
|
||||
this->well_close_times_.erase(well_name);
|
||||
this->well_open_times_.erase(well_name);
|
||||
}
|
||||
}
|
||||
|
||||
if (!wcycle.empty()) {
|
||||
auto schedule_open = [this, report_step](const std::string& name)
|
||||
{
|
||||
const auto& wg_events = this->schedule()[report_step].wellgroup_events();
|
||||
return wg_events.hasEvent(name, ScheduleEvents::REQUEST_OPEN_WELL);
|
||||
};
|
||||
for (const auto& [wname, wscale] : wcycle.efficiencyScale(this->simulator_.time(),
|
||||
this->simulator_.timeStepSize(),
|
||||
wmatcher,
|
||||
this->well_open_times_,
|
||||
schedule_open))
|
||||
{
|
||||
this->wellState()[wname].efficiency_scaling_factor = wscale;
|
||||
this->schedule_.add_event(ScheduleEvents::WELLGROUP_EFFICIENCY_UPDATE, report_step);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -301,6 +301,7 @@ public:
|
||||
WellTestState& welltest_state,
|
||||
const PhaseUsage& phase_usage,
|
||||
GLiftEclWells& ecl_well_map,
|
||||
std::map<std::string, double>& open_times,
|
||||
DeferredLogger& deferred_logger);
|
||||
|
||||
void checkWellOperability(const Simulator& simulator,
|
||||
|
@ -384,6 +384,7 @@ namespace Opm
|
||||
WellTestState& well_test_state,
|
||||
const PhaseUsage& phase_usage,
|
||||
GLiftEclWells& ecl_well_map,
|
||||
std::map<std::string, double>& open_times,
|
||||
DeferredLogger& deferred_logger)
|
||||
{
|
||||
deferred_logger.info(" well " + this->name() + " is being tested");
|
||||
@ -480,6 +481,7 @@ namespace Opm
|
||||
// set the status of the well_state to open
|
||||
ws.open();
|
||||
well_state = well_state_copy;
|
||||
open_times.try_emplace(this->name(), well_test_state.lastTestTime(this->name()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -583,6 +583,17 @@ foreach(templ_case RANGE 1 6)
|
||||
)
|
||||
endforeach()
|
||||
|
||||
foreach(wcycle_case RANGE 0 7)
|
||||
add_test_compareECLFiles(CASENAME WCYCLE-${wcycle_case}
|
||||
FILENAME WCYCLE-${wcycle_case}
|
||||
SIMULATOR flow
|
||||
ABS_TOL ${abs_tol}
|
||||
REL_TOL ${rel_tol}
|
||||
DIR wcycle
|
||||
TEST_ARGS --enable-tuning=true
|
||||
)
|
||||
endforeach()
|
||||
|
||||
add_test_compareECLFiles(CASENAME udq_uadd
|
||||
FILENAME UDQ_M1
|
||||
SIMULATOR flow
|
||||
|
Loading…
Reference in New Issue
Block a user