ReservoirCouplingMaster.hpp
Go to the documentation of this file.
1/*
2 Copyright 2024 Equinor ASA
3
4 This file is part of the Open Porous Media project (OPM).
5
6 OPM is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 OPM is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with OPM. If not, see <http://www.gnu.org/licenses/>.
18*/
19
20#ifndef OPM_RESERVOIR_COUPLING_MASTER_HPP
21#define OPM_RESERVOIR_COUPLING_MASTER_HPP
22
27#include <opm/input/eclipse/EclipseState/Phase.hpp>
28#include <opm/input/eclipse/Schedule/Schedule.hpp>
29#include <opm/common/OpmLog/OpmLog.hpp>
30
31#include <mpi.h>
32
33#include <filesystem>
34#include <map>
35#include <string>
36#include <tuple>
37#include <utility>
38#include <vector>
39
40namespace Opm {
41
42template <class Scalar>
44public:
53
55 const Parallel::Communication &comm,
56 const Schedule &schedule,
57 int argc, char **argv
58 );
59
60 bool activated() { return this->activated_; }
61 void addSlaveCommunicator(MPI_Comm comm) {
62 this->master_slave_comm_.push_back(comm);
63 }
64 void addSlaveName(const std::string &name) { this->slave_names_.push_back(name); }
65 void addSlaveActivationDate(double date) { this->slave_activation_dates_.push_back(date); }
66 void addSlaveStartDate(std::time_t date) { this->slave_start_dates_.push_back(date); }
68
81 int effectiveGCW(const std::string& group_name) const {
82 const auto it = this->effective_gcw_.find(group_name);
83 return (it == this->effective_gcw_.end()) ? 1 : it->second;
84 }
85 void setEffectiveGCW(const std::string& group_name, int value) {
86 this->effective_gcw_[group_name] = value;
87 }
88
99 int effectiveInjectionGCW(const std::string& group_name, Phase phase) const {
100 const auto it = this->effective_injection_gcw_.find({group_name, phase});
101 return (it == this->effective_injection_gcw_.end()) ? 1 : it->second;
102 }
103 void setEffectiveInjectionGCW(const std::string& group_name, Phase phase, int value) {
104 this->effective_injection_gcw_[{group_name, phase}] = value;
105 }
106
111 this->effective_gcw_.clear();
112 this->effective_injection_gcw_.clear();
113 }
114
115 double getActivationDate() const { return this->activation_date_; }
116 int getArgc() const { return this->argc_; }
117 char *getArgv(int index) const { return this->argv_[index]; }
118 char **getArgv() const { return this->argv_; }
119 const Parallel::Communication &getComm() const { return this->comm_; }
120
133 const std::vector<std::string>& getMasterGroupNamesForSlave(std::size_t slave_idx) const;
134
142 const std::string &slave_name, const std::string &master_group_name) const;
143
145 const std::string &group_name, ReservoirCoupling::Phase phase, ReservoirCoupling::RateKind kind) const;
146 std::map<std::string, std::string>& getMasterGroupToSlaveNameMap() {
147 return this->master_group_slave_names_;
148 }
150 { return TimeService::to_time_t(this->schedule_.getStartTime()); }
151 double getSlaveActivationDate(int index) const { return this->slave_activation_dates_[index]; }
152 const double *getSlaveActivationDates() const { return this->slave_activation_dates_.data(); }
153 MPI_Comm getSlaveComm(int index) const { return this->master_slave_comm_[index]; }
154 std::map<std::string, std::vector<std::string>> &getSlaveNameToMasterGroupsMap() {
155 return this->slave_name_to_master_groups_map_;
156 }
157 int getSlaveGroupNumGroupControlledInjectors(const std::string &master_group_name,
158 ReservoirCoupling::Phase phase) const;
159 int getSlaveGroupNumGroupControlledProducers(const std::string &master_group_name) const;
160 const Potentials& getSlaveGroupPotentials(const std::string &master_group_name);
161 int getSlaveIdx(const std::string &slave_name) const;
162 const std::string &getSlaveName(int index) const { return this->slave_names_[index]; }
163 double getSlaveStartDate(int index) const { return this->slave_start_dates_[index]; }
164 const double *getSlaveStartDates() { return this->slave_start_dates_.data(); }
165 void initStartOfReportStep(int report_step_idx);
168 bool isMasterGroup(const std::string &group_name) const;
169
177
181 void setNeedsSlaveDataReceive(bool value);
182
183 ReservoirCoupling::Logger& logger() { return this->logger_; }
184 ReservoirCoupling::Logger& logger() const { return this->logger_; }
185 void maybeActivate(int report_step);
187 double maybeChopSubStep(double suggested_timestep, double current_time) const;
188 void maybeSpawnSlaveProcesses(int report_step);
189 std::size_t numSlaveGroups(unsigned int index);
190 std::size_t numSlaves() const { return this->numSlavesStarted(); }
191 std::size_t numSlavesStarted() const;
192
196 std::size_t numCoupledSlaves() const;
201 void resizeNextReportDates(int size);
202 void resizeSlaveActivationDates(int size) { this->slave_activation_dates_.resize(size); }
203 void resizeSlaveStartDates(int size) { this->slave_start_dates_.resize(size); }
204 const Schedule& schedule() const { return this->schedule_; }
205 void sendNextTimeStepToSlaves(double next_time_step) {
206 this->report_step_data_->setSyncStepLength(next_time_step);
207 this->time_stepper_->sendNextTimeStepToSlaves(next_time_step);
208 }
209
212 void saveGroupFlowsAtStartOfSyncStep() { this->report_step_data_->saveGroupFlowsAtStartOfSyncStep(); }
213
216 void updateFlowChangeTimeStepLimit() { this->report_step_data_->updateFlowChangeTimeStepLimit(); }
217
219 double flowChangeTimeStepLimit() const { return this->report_step_data_->flowChangeTimeStepLimit(); }
220
223 std::tuple<std::string, double, double> flowChangeLimitingGroup() const {
224 return this->report_step_data_->flowChangeLimitingGroup();
225 }
226
230 std::size_t slave_idx,
231 bool active
232 ) const;
234 std::size_t slave_idx,
235 const std::vector<InjectionGroupTarget>& injection_targets
236 ) const;
237
240 std::size_t slave_idx,
241 const std::vector<MasterGroupNodePressure>& pressures
242 ) const;
244 std::size_t slave_idx,
245 std::size_t num_injection_targets,
246 std::size_t num_production_constraints
247 ) const;
248
252 std::size_t slave_idx,
253 std::size_t num_pressures,
254 bool is_final
255 ) const;
257 std::size_t slave_idx,
258 const std::vector<ProductionGroupConstraints>& production_constraints
259 ) const;
260 void setDeferredLogger(DeferredLogger *deferred_logger) {
261 this->logger_.setDeferredLogger(deferred_logger);
262 }
264
268 data::ReservoirCouplingGroupRates collectGroupRatesForSummary() const;
269 // These are currently only used for unit testing
270 void setSlaveActivated(int index)
271 {
272 if (this->slave_activation_status_.size() < this->numSlavesStarted()) {
273 this->slave_activation_status_.resize(this->numSlavesStarted(), 0);
274 }
275 this->slave_activation_status_[index] = 1;
276 }
277 void setSlaveActivationDate(int index, double date) { this->slave_activation_dates_[index] = date; }
278 void setSlaveGroupInjectionData(const std::string& slave_name,
279 std::vector<SlaveGroupInjectionData> injection_data)
280 {
281 this->report_step_data_->setSlaveGroupInjectionData(slave_name, std::move(injection_data));
282 }
283 void setSlaveGroupProductionData(const std::string& slave_name,
284 std::vector<SlaveGroupProductionData> production_data)
285 {
286 this->report_step_data_->setSlaveGroupProductionData(slave_name, std::move(production_data));
287 }
288 void setSlaveNextReportTimeOffset(int index, double offset);
289 void setSlaveStartDate(int index, std::time_t date) { this->slave_start_dates_[index] = date; }
294 bool slaveIsActivated(int index) const { return this->slave_activation_status_[index] != 0; }
295
303 bool slaveHasEnded(int index) const
304 {
305 return (static_cast<std::size_t>(index) < this->slave_ended_.size())
306 && (this->slave_ended_[index] != 0);
307 }
308
314 bool slaveIsCoupled(int index) const
315 {
316 return this->slaveIsActivated(index) && !this->slaveHasEnded(index);
317 }
318
327
332 bool syncAtReportSteps() const { return this->sync_at_report_steps_; }
334 const std::string& slave_name, const std::map<std::string, std::size_t>& master_group_map);
335
343
354
355private:
356 double getMasterActivationDate_() const;
357
358 const Parallel::Communication &comm_;
359 const Schedule& schedule_;
360 int argc_;
361 char **argv_;
362 // Whether the master process has activated the reservoir coupling
363 bool activated_{false};
364
365 // NOTE: MPI_Comm is just an integer handle, so we can just copy it into the vector
366 std::vector<MPI_Comm> master_slave_comm_; // MPI communicators for the slave processes
367 std::vector<std::string> slave_names_;
368
369 // The start dates are in whole seconds since the epoch. We use a double to store the value
370 // since both schedule_.getStartTime(), converted to seconds since the epoch, and
371 // schedule_.stepLength(report_step) represent whole seconds.
372 // However, note that schedule_[report_step].start_time() returns a time_point
373 // which can include milliseconds. The double values are also convenient when we need to
374 // to add fractions of seconds for sub steps to the start date.
375 std::vector<double> slave_start_dates_;
376
377 // The activation dates are in whole seconds since the epoch.
378 std::vector<double> slave_activation_dates_;
379 double activation_date_{0.0}; // The date when SLAVES is encountered in the schedule
380
381 // A mapping from a slave name to the master group name order used when slaves send
382 // potentials to the master process.
383 std::map<std::string, std::map<std::string, std::size_t>> master_group_name_order_;
384
385 // Effective group-controlled-wells count per master group, used by guide-rate
386 // distribution independently of the production control mode (see effectiveGCW()).
387 // Reset and repopulated on each master-group constraint calculation.
388 std::map<std::string, int> effective_gcw_;
389
390 // Effective group-controlled-wells count per (master group, injection phase),
391 // the injection counterpart of effective_gcw_ (see effectiveInjectionGCW()).
392 std::map<std::pair<std::string, Phase>, int> effective_injection_gcw_;
393
394 mutable ReservoirCoupling::Logger logger_;
395
396 // Whether the slave has activated. Unfortunatley, we cannot use std::vector<bool> since
397 // it is not supported to get a pointer to the underlying array of bools needed
398 // with MPI broadcast().
399 std::vector<std::uint8_t> slave_activation_status_;
400
401 // Whether the slave has reached the end of its own schedule and disconnected. Same
402 // std::uint8_t-instead-of-bool reasoning as slave_activation_status_ above: the value is
403 // derived on every rank from the broadcast next-report-date vector, so it must be a plain
404 // array of bytes.
405 std::vector<std::uint8_t> slave_ended_;
406
407 // A mapping from master group names to slave names
408 std::map<std::string, std::string> master_group_slave_names_;
409
410 // A mapping from slave names to master group names
411 // NOTE: The order of the master groups in the vector is important,
412 // as the slaves will communicate the indices of the master groups in
413 // the vector instead of the group names themselves.
414 // NOTE: This map is created by ReservoirCouplingSpawnSlaves.cpp
415 std::map<std::string, std::vector<std::string>> slave_name_to_master_groups_map_;
416
417 // Direct index-based lookup for performance optimization (O(1) instead of O(log n))
418 // This vector is populated in parallel with slave_name_to_master_groups_map_
419 // and maintains the same ordering as slave_names_ vector for consistent indexing
420 std::vector<std::vector<std::string>> slave_idx_to_master_groups_;
421
422 // Stores data that changes for a single report step or for timesteps within a report step.
423 std::unique_ptr<ReservoirCouplingMasterReportStep<Scalar>> report_step_data_{nullptr};
424
425 // Handles time stepping for the master and slaves
426 std::unique_ptr<ReservoirCouplingTimeStepper<Scalar>> time_stepper_{nullptr};
427
428 // CLI flag --rescoup-sync-at-report-steps. When true, the master syncs with
429 // its slaves at report-step boundaries (RSYNC). When false
430 // (default), it syncs at every master time step (TSYNC).
431 bool sync_at_report_steps_{false};
432};
433
434} // namespace Opm
435
436#endif // OPM_RESERVOIR_COUPLING_MASTER_HPP
Definition: DeferredLogger.hpp:57
Definition: ReservoirCoupling.hpp:42
void setDeferredLogger(DeferredLogger *deferred_logger)
Definition: ReservoirCoupling.hpp:55
void clearDeferredLogger()
Definition: ReservoirCoupling.hpp:47
Definition: ReservoirCouplingMaster.hpp:43
void setSlaveGroupProductionData(const std::string &slave_name, std::vector< SlaveGroupProductionData > production_data)
Definition: ReservoirCouplingMaster.hpp:283
void resizeSlaveActivationDates(int size)
Definition: ReservoirCouplingMaster.hpp:202
void resizeSlaveStartDates(int size)
Definition: ReservoirCouplingMaster.hpp:203
std::map< std::string, std::vector< std::string > > & getSlaveNameToMasterGroupsMap()
Definition: ReservoirCouplingMaster.hpp:154
char * getArgv(int index) const
Definition: ReservoirCouplingMaster.hpp:117
bool slaveIsCoupled(int index) const
Whether the slave currently takes part in the coupling.
Definition: ReservoirCouplingMaster.hpp:314
bool slaveHasEnded(int index) const
Whether the slave has reached the end of its own schedule and left the coupling.
Definition: ReservoirCouplingMaster.hpp:303
int getSlaveGroupNumGroupControlledInjectors(const std::string &master_group_name, ReservoirCoupling::Phase phase) const
double getActivationDate() const
Definition: ReservoirCouplingMaster.hpp:115
char ** getArgv() const
Definition: ReservoirCouplingMaster.hpp:118
void maybeActivate(int report_step)
bool syncAtReportSteps() const
Whether the master syncs with slaves at slave report-step boundaries (true) or at every master actual...
Definition: ReservoirCouplingMaster.hpp:332
std::size_t numSlaveGroups(unsigned int index)
ReservoirCoupling::Logger & logger()
Definition: ReservoirCouplingMaster.hpp:183
void resizeNextReportDates(int size)
void maybeReceiveActivationHandshakeFromSlaves(double current_time)
void sendNextTimeStepToSlaves(double next_time_step)
Definition: ReservoirCouplingMaster.hpp:205
bool isFirstSubstepOfSyncTimestep() const
void setFirstSubstepOfSyncTimestep(bool value)
std::size_t numSlavesStarted() const
double maybeChopSubStep(double suggested_timestep, double current_time) const
bool slaveIsActivated(int index) const
Whether the slave has completed its activation handshake with the master.
Definition: ReservoirCouplingMaster.hpp:294
void setEffectiveGCW(const std::string &group_name, int value)
Definition: ReservoirCouplingMaster.hpp:85
void sendProductionConstraintsToSlave(std::size_t slave_idx, const std::vector< ProductionGroupConstraints > &production_constraints) const
std::size_t getMasterGroupCanonicalIdx(const std::string &slave_name, const std::string &master_group_name) const
Get the canonical index of the master group for a given slave name and master group name....
std::size_t numCoupledSlaves() const
Number of slaves that currently take part in the coupling.
void addSlaveCommunicator(MPI_Comm comm)
Definition: ReservoirCouplingMaster.hpp:61
void addSlaveStartDate(std::time_t date)
Definition: ReservoirCouplingMaster.hpp:66
bool activated()
Definition: ReservoirCouplingMaster.hpp:60
void initStartOfReportStep(int report_step_idx)
const Parallel::Communication & getComm() const
Definition: ReservoirCouplingMaster.hpp:119
ReservoirCoupling::Logger & logger() const
Definition: ReservoirCouplingMaster.hpp:184
void markSlaveEndedAndDisconnect(int index)
Record that a slave has ended, and close its intercommunicator.
int getSlaveIdx(const std::string &slave_name) const
void setSlaveActivated(int index)
Definition: ReservoirCouplingMaster.hpp:270
int effectiveInjectionGCW(const std::string &group_name, Phase phase) const
Effective group-controlled-wells (GCW) count for a master group in the injection guide-rate distribut...
Definition: ReservoirCouplingMaster.hpp:99
void setSlaveNextReportTimeOffset(int index, double offset)
void addSlaveActivationDate(double date)
Definition: ReservoirCouplingMaster.hpp:65
void setSlaveGroupInjectionData(const std::string &slave_name, std::vector< SlaveGroupInjectionData > injection_data)
Definition: ReservoirCouplingMaster.hpp:278
void clearDeferredLogger()
Definition: ReservoirCouplingMaster.hpp:67
bool needsSlaveDataReceive() const
Check if the master needs to receive production data from the slaves.
double flowChangeTimeStepLimit() const
Upper limit (in seconds) for the next sync step from GRUPMAST item 4, infinity if none.
Definition: ReservoirCouplingMaster.hpp:219
Scalar getMasterGroupRate(const std::string &group_name, ReservoirCoupling::Phase phase, ReservoirCoupling::RateKind kind) const
void setDeferredLogger(DeferredLogger *deferred_logger)
Definition: ReservoirCouplingMaster.hpp:260
void sendCoupledNetworkActiveStatusToSlave(std::size_t slave_idx, bool active) const
Send a single boolean to a slave telling it whether the master will iterate the cross-rescoup network...
void maybeSpawnSlaveProcesses(int report_step)
void sendTerminateAndDisconnect()
Send terminate signal to all active slaves and disconnect intercommunicators.
void resetEffectiveGCW()
Clear all effective-GCW entries, production and injection. Call at the start of each master-group con...
Definition: ReservoirCouplingMaster.hpp:110
const std::string & getSlaveName(int index) const
Definition: ReservoirCouplingMaster.hpp:162
void updateFlowChangeTimeStepLimit()
Update the flow-change time step limit (GRUPMAST item 4) from the flows received at the end of the sy...
Definition: ReservoirCouplingMaster.hpp:216
void sendMasterGroupNodePressuresToSlave(std::size_t slave_idx, const std::vector< MasterGroupNodePressure > &pressures) const
Send master-computed network-leaf node pressures to a slave.
const Potentials & getSlaveGroupPotentials(const std::string &master_group_name)
ReservoirCouplingMaster(const Parallel::Communication &comm, const Schedule &schedule, int argc, char **argv)
void addSlaveName(const std::string &name)
Definition: ReservoirCouplingMaster.hpp:64
void saveGroupFlowsAtStartOfSyncStep()
Save the master group flow rates at the start of the sync step.
Definition: ReservoirCouplingMaster.hpp:212
const double * getSlaveActivationDates() const
Definition: ReservoirCouplingMaster.hpp:152
void sendNumGroupConstraintsToSlave(std::size_t slave_idx, std::size_t num_injection_targets, std::size_t num_production_constraints) const
std::map< std::string, std::string > & getMasterGroupToSlaveNameMap()
Definition: ReservoirCouplingMaster.hpp:146
void sendDontTerminateSignalToSlaves()
Send "don't terminate" signal (value=0) to all active slaves.
const Schedule & schedule() const
Definition: ReservoirCouplingMaster.hpp:204
void updateMasterGroupNameOrderMap(const std::string &slave_name, const std::map< std::string, std::size_t > &master_group_map)
double getSlaveActivationDate(int index) const
Definition: ReservoirCouplingMaster.hpp:151
std::tuple< std::string, double, double > flowChangeLimitingGroup() const
The master group that sets flowChangeTimeStepLimit(): name, fractional flow change and limiting fract...
Definition: ReservoirCouplingMaster.hpp:223
void sendNumMasterGroupNodePressuresToSlave(std::size_t slave_idx, std::size_t num_pressures, bool is_final) const
Send the count of master-computed network-leaf node pressures plus the master's is_final flag for thi...
std::size_t numSlaves() const
Definition: ReservoirCouplingMaster.hpp:190
const double * getSlaveStartDates()
Definition: ReservoirCouplingMaster.hpp:164
int effectiveGCW(const std::string &group_name) const
Effective group-controlled-wells (GCW) count for a master group, used by guide-rate distribution inde...
Definition: ReservoirCouplingMaster.hpp:81
void setSlaveActivationDate(int index, double date)
Definition: ReservoirCouplingMaster.hpp:277
void setNeedsSlaveDataReceive(bool value)
Set whether the master needs to receive production data from the slaves.
MPI_Comm getSlaveComm(int index) const
Definition: ReservoirCouplingMaster.hpp:153
void setEffectiveInjectionGCW(const std::string &group_name, Phase phase, int value)
Definition: ReservoirCouplingMaster.hpp:103
double getSlaveStartDate(int index) const
Definition: ReservoirCouplingMaster.hpp:163
const std::vector< std::string > & getMasterGroupNamesForSlave(std::size_t slave_idx) const
Get the master group names associated with a slave reservoir by index.
int getSlaveGroupNumGroupControlledProducers(const std::string &master_group_name) const
double getSimulationStartDate() const
Definition: ReservoirCouplingMaster.hpp:149
void sendInjectionTargetsToSlave(std::size_t slave_idx, const std::vector< InjectionGroupTarget > &injection_targets) const
void setSlaveStartDate(int index, std::time_t date)
Definition: ReservoirCouplingMaster.hpp:289
data::ReservoirCouplingGroupRates collectGroupRatesForSummary() const
Collect production/injection rates for all master groups.
bool isMasterGroup(const std::string &group_name) const
int getArgc() const
Definition: ReservoirCouplingMaster.hpp:116
Dune::Communication< MPIComm > Communication
Definition: ParallelCommunication.hpp:30
RateKind
Selects which kind of rate to retrieve from slave group data.
Definition: ReservoirCoupling.hpp:195
MessageTag
Definition: ReservoirCoupling.hpp:138
Phase
Phase indices for reservoir coupling, we currently only support black-oil phases (oil,...
Definition: ReservoirCoupling.hpp:183
Definition: blackoilbioeffectsmodules.hh:45
Definition: ReservoirCoupling.hpp:298
Master-computed network-leaf node pressure for a single master group.
Definition: ReservoirCoupling.hpp:341
Definition: ReservoirCoupling.hpp:214
Definition: ReservoirCoupling.hpp:308
Utility class for comparing double values representing epoch dates or elapsed time.
Definition: ReservoirCoupling.hpp:410
Definition: ReservoirCoupling.hpp:278
Definition: ReservoirCoupling.hpp:238