Send slave start dates to master

This commit is contained in:
Håkon Hægland 2024-08-12 15:17:38 +02:00
parent e47c89832d
commit 09aa0be11c
5 changed files with 73 additions and 26 deletions

View File

@ -50,6 +50,37 @@ ReservoirCouplingMaster::ReservoirCouplingMaster(
// Public methods // Public methods
// ------------------ // ------------------
void ReservoirCouplingMaster::receiveSimulationStartDateFromSlaves() {
this->slave_start_dates_.resize(this->num_slaves_);
if (this->comm_.rank() == 0) {
// Ensure that std::time_t is of type long since we are sending it over MPI with MPI_LONG
static_assert(std::is_same<std::time_t, long>::value, "std::time_t is not of type long");
for (unsigned int i = 0; i < this->master_slave_comm_.size(); i++) {
std::time_t start_date;
int result = MPI_Recv(
&start_date,
/*count=*/1,
/*datatype=*/MPI_LONG,
/*source_rank=*/0,
/*tag=*/static_cast<int>(MessageTag::SimulationStartDate),
*this->master_slave_comm_[i].get(),
MPI_STATUS_IGNORE
);
if (result != MPI_SUCCESS) {
OPM_THROW(std::runtime_error, "Failed to receive simulation start date from slave process");
}
this->slave_start_dates_[i] = start_date;
OpmLog::info(
fmt::format(
"Received simulation start date from slave process with name: {}. "
"Start date: {}", this->slave_names_[i], start_date
)
);
}
}
this->comm_.broadcast(this->slave_start_dates_.data(), this->num_slaves_, /*emitter_rank=*/0);
}
// NOTE: This functions is executed for all ranks, but only rank 0 will spawn // NOTE: This functions is executed for all ranks, but only rank 0 will spawn
// the slave processes // the slave processes
void ReservoirCouplingMaster::spawnSlaveProcesses(int argc, char **argv) { void ReservoirCouplingMaster::spawnSlaveProcesses(int argc, char **argv) {
@ -101,6 +132,7 @@ void ReservoirCouplingMaster::spawnSlaveProcesses(int argc, char **argv) {
); );
this->master_slave_comm_.push_back(std::move(master_slave_comm)); this->master_slave_comm_.push_back(std::move(master_slave_comm));
this->slave_names_.push_back(slave_name); this->slave_names_.push_back(slave_name);
this->num_slaves_++;
} }
} }

View File

@ -34,12 +34,13 @@ namespace Opm {
class ReservoirCouplingMaster { class ReservoirCouplingMaster {
public: public:
using MPI_Comm_Ptr = ReservoirCoupling::MPI_Comm_Ptr;
using MessageTag = ReservoirCoupling::MessageTag;
ReservoirCouplingMaster(const Parallel::Communication &comm, const Schedule &schedule); ReservoirCouplingMaster(const Parallel::Communication &comm, const Schedule &schedule);
void spawnSlaveProcesses(int argc, char **argv); void spawnSlaveProcesses(int argc, char **argv);
void receiveSimulationStartDateFromSlaves();
using MPI_Comm_Ptr = ReservoirCoupling::MPI_Comm_Ptr;
private: private:
std::vector<char *> getSlaveArgv( std::vector<char *> getSlaveArgv(
@ -52,9 +53,10 @@ private:
const Parallel::Communication &comm_; const Parallel::Communication &comm_;
const Schedule& schedule_; const Schedule& schedule_;
// MPI communicators for the slave processes std::size_t num_slaves_ = 0; // Initially zero, will be updated in spawnSlaveProcesses()
std::vector<MPI_Comm_Ptr> master_slave_comm_; std::vector<MPI_Comm_Ptr> master_slave_comm_; // MPI communicators for the slave processes
std::vector<std::string> slave_names_; std::vector<std::string> slave_names_;
std::vector<std::time_t> slave_start_dates_;
}; };
} // namespace Opm } // namespace Opm

View File

@ -38,17 +38,30 @@ ReservoirCouplingSlave::ReservoirCouplingSlave(
) : ) :
comm_{comm}, comm_{comm},
schedule_{schedule} schedule_{schedule}
{ } {
void ReservoirCouplingSlave::sendSimulationStartDateToMasterProcess() { this->slave_master_comm_ = MPI_Comm_Ptr(new MPI_Comm(MPI_COMM_NULL));
// TODO: Implement this function next MPI_Comm_get_parent(this->slave_master_comm_.get());
if (*(this->slave_master_comm_) == MPI_COMM_NULL) {
OPM_THROW(std::runtime_error, "Slave process is not spawned by a master process");
}
}
//this->slave_master_comm_ = MPI_Comm_Ptr(new MPI_Comm(MPI_COMM_NULL)); void ReservoirCouplingSlave::sendSimulationStartDateToMasterProcess() {
//MPI_Comm_get_parent(this->slave_master_comm_.get());
//if (*(this->slave_master_comm_) == MPI_COMM_NULL) { if (this->comm_.rank() == 0) {
// OPM_THROW(std::runtime_error, "Slave process is not spawned by a master process"); // Ensure that std::time_t is of type long since we are sending it over MPI with MPI_LONG
//} static_assert(std::is_same<std::time_t, long>::value, "std::time_t is not of type long");
//MPI_Send(&start_date, 1, MPI_INT, 0, 0, parentcomm); std::time_t start_date = this->schedule_.getStartTime();
OpmLog::info("Sent simulation start date to master process"); MPI_Send(
&start_date,
/*count=*/1,
/*datatype=*/MPI_LONG,
/*dest_rank=*/0,
/*tag=*/static_cast<int>(MessageTag::SimulationStartDate),
*this->slave_master_comm_
);
OpmLog::info("Sent simulation start date to master process from rank 0");
}
} }
} // namespace Opm } // namespace Opm

View File

@ -20,7 +20,7 @@
#ifndef OPM_RESERVOIR_COUPLING_SLAVE_HPP #ifndef OPM_RESERVOIR_COUPLING_SLAVE_HPP
#define OPM_RESERVOIR_COUPLING_SLAVE_HPP #define OPM_RESERVOIR_COUPLING_SLAVE_HPP
#include <opm/simulators/flow/ReservoirCouplingMaster.hpp> #include <opm/simulators/flow/ReservoirCoupling.hpp>
#include <opm/input/eclipse/Schedule/Schedule.hpp> #include <opm/input/eclipse/Schedule/Schedule.hpp>
#include <opm/simulators/utils/ParallelCommunication.hpp> #include <opm/simulators/utils/ParallelCommunication.hpp>
#include <opm/common/OpmLog/OpmLog.hpp> #include <opm/common/OpmLog/OpmLog.hpp>
@ -33,7 +33,8 @@ namespace Opm {
class ReservoirCouplingSlave { class ReservoirCouplingSlave {
public: public:
using MPI_Comm_Ptr = ReservoirCouplingMaster::MPI_Comm_Ptr; using MPI_Comm_Ptr = ReservoirCoupling::MPI_Comm_Ptr;
using MessageTag = ReservoirCoupling::MessageTag;
ReservoirCouplingSlave(const Parallel::Communication &comm, const Schedule &schedule); ReservoirCouplingSlave(const Parallel::Communication &comm, const Schedule &schedule);
void sendSimulationStartDateToMasterProcess(); void sendSimulationStartDateToMasterProcess();

View File

@ -218,16 +218,15 @@ public:
// For now, we require that SLAVES and GRUPMAST are defined at the first // For now, we require that SLAVES and GRUPMAST are defined at the first
// schedule step, so it is enough to check the first step. See the // schedule step, so it is enough to check the first step. See the
// keyword handlers in opm-common for more information. // keyword handlers in opm-common for more information.
if (!this->schedule()[0].rescoup.empty()) { auto master_mode = this->schedule()[0].rescoup().masterMode();
auto master_mode = this->schedule()[0].rescoup().masterMode(); if (master_mode) {
if (master_mode) { this->reservoirCouplingMaster_ =
this->reservoirCouplingMaster_ = std::make_unique<ReservoirCouplingMaster>(
std::make_unique<ReservoirCouplingMaster>( FlowGenericVanguard::comm(),
FlowGenericVanguard::comm(), this->schedule()
this->schedule() );
); this->reservoirCouplingMaster_->spawnSlaveProcesses(argc, argv);
this->reservoirCouplingMaster_->spawnSlaveProcesses(argc, argv); this->reservoirCouplingMaster_->receiveSimulationStartDateFromSlaves();
}
} }
} }
#endif #endif