Merge pull request #3540 from hakonhagland/python_set_sched

Initialize blackoil simulator from Opm::Schedule shared with Python.
This commit is contained in:
Bård Skaflestad
2021-09-23 13:32:31 +02:00
committed by GitHub
38 changed files with 1001 additions and 200 deletions

View File

@@ -82,13 +82,16 @@ struct FlowEarlyBird {
namespace Opm {
template <class TypeTag>
void flowEbosSetDeck(std::unique_ptr<Deck> deck, std::unique_ptr<EclipseState> eclState, std::unique_ptr<Schedule> schedule, std::unique_ptr<SummaryConfig> summaryConfig)
void flowEbosSetDeck(std::shared_ptr<Deck> deck,
std::shared_ptr<EclipseState> eclState,
std::shared_ptr<Schedule> schedule,
std::shared_ptr<SummaryConfig> summaryConfig)
{
using Vanguard = GetPropType<TypeTag, Properties::Vanguard>;
Vanguard::setExternalDeck(std::move(deck));
Vanguard::setExternalEclState(std::move(eclState));
Vanguard::setExternalSchedule(std::move(schedule));
Vanguard::setExternalSummaryConfig(std::move(summaryConfig));
Vanguard::setExternalDeck(deck);
Vanguard::setExternalEclState(eclState);
Vanguard::setExternalSchedule(schedule);
Vanguard::setExternalSummaryConfig(summaryConfig);
}
// ----------------- Main program -----------------
@@ -123,31 +126,27 @@ namespace Opm
public:
Main(int argc, char** argv) : argc_(argc), argv_(argv) { initMPI(); }
// This constructor can be called from Python
Main(const std::string &filename)
{
deckFilename_.assign(filename);
flowProgName_.assign("flow");
argc_ = 2;
saveArgs_[0] = const_cast<char *>(flowProgName_.c_str());
saveArgs_[1] = const_cast<char *>(deckFilename_.c_str());
argv_ = saveArgs_;
setArgvArgc_(filename);
initMPI();
}
Main(int argc,
char** argv,
std::unique_ptr<Deck> deck,
std::unique_ptr<EclipseState> eclipseState,
std::unique_ptr<Schedule> schedule,
std::unique_ptr<SummaryConfig> summaryConfig)
: argc_(argc)
, argv_(argv)
, deck_(std::move(deck))
, eclipseState_(std::move(eclipseState))
, schedule_(std::move(schedule))
, summaryConfig_(std::move(summaryConfig))
// This constructor can be called from Python when Python has already
// parsed a deck
Main(
std::shared_ptr<Deck> deck,
std::shared_ptr<EclipseState> eclipseState,
std::shared_ptr<Schedule> schedule,
std::shared_ptr<SummaryConfig> summaryConfig)
: deck_{std::move(deck)}
, eclipseState_{std::move(eclipseState)}
, schedule_{std::move(schedule)}
, summaryConfig_{std::move(summaryConfig)}
{
initMPI();
setArgvArgc_(deck_->getDataFile());
initMPI();
}
~Main()
@@ -159,6 +158,16 @@ namespace Opm
#endif
}
void setArgvArgc_(const std::string& filename)
{
deckFilename_.assign(filename);
flowProgName_.assign("flow");
argc_ = 2;
saveArgs_[0] = const_cast<char *>(flowProgName_.c_str());
saveArgs_[1] = const_cast<char *>(deckFilename_.c_str());
argv_ = saveArgs_;
}
void initMPI()
{
#if HAVE_DUNE_FEM
@@ -202,11 +211,11 @@ namespace Opm
// case. E.g. check that number of phases == 3
flowEbosBlackoilSetDeck(
setupTime_,
std::move(deck_),
std::move(eclipseState_),
std::move(schedule_),
deck_,
eclipseState_,
schedule_,
std::move(udqState_),
std::move(summaryConfig_));
summaryConfig_);
return flowEbosBlackoilMainInit(
argc_, argv_, outputCout_, outputFiles_);
} else {
@@ -230,18 +239,20 @@ namespace Opm
else if( phases.size() == 2 ) {
// oil-gas
if (phases.active( Phase::OIL ) && phases.active( Phase::GAS )) {
flowEbosGasOilSetDeck(setupTime_, std::move(deck_), std::move(eclipseState_),
std::move(schedule_), std::move(summaryConfig_));
flowEbosGasOilSetDeck(
setupTime_, deck_, eclipseState_, schedule_, summaryConfig_);
return flowEbosGasOilMain(argc_, argv_, outputCout_, outputFiles_);
}
// oil-water
else if ( phases.active( Phase::OIL ) && phases.active( Phase::WATER ) ) {
flowEbosOilWaterSetDeck(setupTime_, std::move(deck_), std::move(eclipseState_), std::move(schedule_), std::move(summaryConfig_));
flowEbosOilWaterSetDeck(
setupTime_, deck_, eclipseState_, schedule_, summaryConfig_);
return flowEbosOilWaterMain(argc_, argv_, outputCout_, outputFiles_);
}
// gas-water
else if ( phases.active( Phase::GAS ) && phases.active( Phase::WATER ) ) {
flowEbosGasWaterSetDeck(setupTime_, std::move(deck_), std::move(eclipseState_), std::move(schedule_), std::move(summaryConfig_));
flowEbosGasWaterSetDeck(
setupTime_, deck_, eclipseState_, schedule_, summaryConfig_);
return flowEbosGasWaterMain(argc_, argv_, outputCout_, outputFiles_);
}
else {
@@ -268,25 +279,19 @@ namespace Opm
}
if ( phases.size() == 3 ) { // oil water polymer case
flowEbosOilWaterPolymerSetDeck(setupTime_, std::move(deck_),
std::move(eclipseState_),
std::move(schedule_),
std::move(summaryConfig_));
flowEbosOilWaterPolymerSetDeck(
setupTime_, deck_, eclipseState_, schedule_, summaryConfig_);
return flowEbosOilWaterPolymerMain(argc_, argv_, outputCout_, outputFiles_);
} else {
flowEbosPolymerSetDeck(setupTime_, std::move(deck_),
std::move(eclipseState_),
std::move(schedule_),
std::move(summaryConfig_));
flowEbosPolymerSetDeck(
setupTime_, deck_, eclipseState_, schedule_, summaryConfig_);
return flowEbosPolymerMain(argc_, argv_, outputCout_, outputFiles_);
}
}
// Foam case
else if ( phases.active( Phase::FOAM ) ) {
flowEbosFoamSetDeck(setupTime_, std::move(deck_),
std::move(eclipseState_),
std::move(schedule_),
std::move(summaryConfig_));
flowEbosFoamSetDeck(
setupTime_, deck_, eclipseState_, schedule_, summaryConfig_);
return flowEbosFoamMain(argc_, argv_, outputCout_, outputFiles_);
}
// Brine case
@@ -298,51 +303,43 @@ namespace Opm
return EXIT_FAILURE;
}
if ( phases.size() == 3 ) { // oil water brine case
flowEbosOilWaterBrineSetDeck(setupTime_, std::move(deck_),
std::move(eclipseState_),
std::move(schedule_),
std::move(summaryConfig_));
flowEbosOilWaterBrineSetDeck(
setupTime_, deck_, eclipseState_, schedule_, summaryConfig_);
return flowEbosOilWaterBrineMain(argc_, argv_, outputCout_, outputFiles_);
} else {
flowEbosBrineSetDeck(setupTime_, std::move(deck_),
std::move(eclipseState_),
std::move(schedule_),
std::move(summaryConfig_));
flowEbosBrineSetDeck(
setupTime_, deck_, eclipseState_, schedule_, summaryConfig_);
return flowEbosBrineMain(argc_, argv_, outputCout_, outputFiles_);
}
}
// Solvent case
else if ( phases.active( Phase::SOLVENT ) ) {
flowEbosSolventSetDeck(setupTime_, std::move(deck_),
std::move(eclipseState_),
std::move(schedule_),
std::move(summaryConfig_));
flowEbosSolventSetDeck(
setupTime_, deck_, eclipseState_, schedule_, summaryConfig_);
return flowEbosSolventMain(argc_, argv_, outputCout_, outputFiles_);
}
// Extended BO case
else if ( phases.active( Phase::ZFRACTION ) ) {
flowEbosExtboSetDeck(setupTime_, std::move(deck_),
std::move(eclipseState_),
std::move(schedule_),
std::move(summaryConfig_));
flowEbosExtboSetDeck(
setupTime_, deck_, eclipseState_, schedule_, summaryConfig_);
return flowEbosExtboMain(argc_, argv_, outputCout_, outputFiles_);
}
// Energy case
else if (eclipseState_->getSimulationConfig().isThermal()) {
flowEbosEnergySetDeck(setupTime_, std::move(deck_),
std::move(eclipseState_),
std::move(schedule_),
std::move(summaryConfig_));
flowEbosEnergySetDeck(
setupTime_, deck_, eclipseState_, schedule_, summaryConfig_);
return flowEbosEnergyMain(argc_, argv_, outputCout_, outputFiles_);
}
#endif // FLOW_BLACKOIL_ONLY
// Blackoil case
else if( phases.size() == 3 ) {
flowEbosBlackoilSetDeck(setupTime_, std::move(deck_),
std::move(eclipseState_),
std::move(schedule_),
std::move(udqState_),
std::move(summaryConfig_));
flowEbosBlackoilSetDeck(
setupTime_,
deck_,
eclipseState_,
schedule_,
std::move(udqState_),
summaryConfig_);
return flowEbosBlackoilMain(argc_, argv_, outputCout_, outputFiles_);
}
else {
@@ -355,10 +352,8 @@ namespace Opm
template <class TypeTag>
int dispatchStatic_()
{
flowEbosSetDeck<TypeTag>(std::move(deck_),
std::move(eclipseState_),
std::move(schedule_),
std::move(summaryConfig_));
flowEbosSetDeck<TypeTag>(
deck_, eclipseState_, schedule_, summaryConfig_);
return flowEbosMain<TypeTag>(argc_, argv_, outputCout_, outputFiles_);
}
@@ -549,12 +544,14 @@ namespace Opm
std::string deckFilename_;
std::string flowProgName_;
char *saveArgs_[2];
std::unique_ptr<Deck> deck_;
std::unique_ptr<EclipseState> eclipseState_;
std::unique_ptr<Schedule> schedule_;
std::unique_ptr<UDQState> udqState_;
std::unique_ptr<Action::State> actionState_;
std::unique_ptr<SummaryConfig> summaryConfig_;
// These variables may be owned by both Python and the simulator
std::shared_ptr<Deck> deck_;
std::shared_ptr<EclipseState> eclipseState_;
std::shared_ptr<Schedule> schedule_;
std::shared_ptr<SummaryConfig> summaryConfig_;
};
} // namespace Opm

View File

@@ -0,0 +1,76 @@
/*
Copyright 2020 Equinor ASA.
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_PY_BLACKOIL_SIMULATOR_HEADER_INCLUDED
#define OPM_PY_BLACKOIL_SIMULATOR_HEADER_INCLUDED
#include <opm/simulators/flow/Main.hpp>
#include <opm/simulators/flow/FlowMainEbos.hpp>
#include <opm/models/utils/propertysystem.hh>
#include <opm/simulators/flow/python/Pybind11Exporter.hpp>
#include <opm/simulators/flow/python/PyMaterialState.hpp>
#include <opm/parser/eclipse/Deck/Deck.hpp>
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
#include <opm/parser/eclipse/EclipseState/Schedule/Schedule.hpp>
#include <opm/parser/eclipse/EclipseState/SummaryConfig/SummaryConfig.hpp>
namespace Opm::Pybind {
class PyBlackOilSimulator
{
private:
using TypeTag = Opm::Properties::TTag::EclFlowProblem;
using Simulator = Opm::GetPropType<TypeTag, Opm::Properties::Simulator>;
public:
PyBlackOilSimulator( const std::string& deckFilename);
PyBlackOilSimulator(
std::shared_ptr<Opm::Deck> deck,
std::shared_ptr<Opm::EclipseState> state,
std::shared_ptr<Opm::Schedule> schedule,
std::shared_ptr<Opm::SummaryConfig> summary_config);
py::array_t<double> getPorosity();
int run();
void setPorosity(
py::array_t<double, py::array::c_style | py::array::forcecast> array);
int step();
int stepInit();
int stepCleanup();
const Opm::FlowMainEbos<TypeTag>& getFlowMainEbos() const;
private:
const std::string deckFilename_;
bool hasRunInit_ = false;
bool hasRunCleanup_ = false;
// This *must* be declared before other pointers
// to simulator objects. This in order to deinitialize
// MPI at the correct time (ie after the other objects).
std::unique_ptr<Opm::Main> main_;
std::unique_ptr<Opm::FlowMainEbos<TypeTag>> mainEbos_;
Simulator *ebosSimulator_;
std::unique_ptr<PyMaterialState<TypeTag>> materialState_;
std::shared_ptr<Opm::Deck> deck_;
std::shared_ptr<Opm::EclipseState> eclipse_state_;
std::shared_ptr<Opm::Schedule> schedule_;
std::shared_ptr<Opm::SummaryConfig> summary_config_;
};
} // namespace Opm::Pybind
#endif // OPM_PY_BLACKOIL_SIMULATOR_HEADER_INCLUDED

View File

@@ -0,0 +1,15 @@
#ifndef OPM_PYBIND11_EXPORTER_HEADER_INCLUDED
#define OPM_PYBIND11_EXPORTER_HEADER_INCLUDED
#include <pybind11/pybind11.h>
#include <pybind11/numpy.h>
//#include <pybind11/embed.h>
namespace py = pybind11;
namespace Opm::Pybind {
void export_all(py::module& m);
void export_PyBlackOilSimulator(py::module& m);
}
#endif //OPM_PYBIND11_EXPORTER_HEADER_INCLUDED

View File

@@ -191,8 +191,8 @@ void setupMessageLimiter(const Opm::MessageLimits msgLimits, const std::string&
}
void readDeck(int rank, std::string& deckFilename, std::unique_ptr<Opm::Deck>& deck, std::unique_ptr<Opm::EclipseState>& eclipseState,
std::unique_ptr<Opm::Schedule>& schedule, std::unique_ptr<UDQState>& udqState, std::unique_ptr<Action::State>& actionState, std::unique_ptr<Opm::SummaryConfig>& summaryConfig,
void readDeck(int rank, std::string& deckFilename, std::shared_ptr<Opm::Deck>& deck, std::shared_ptr<Opm::EclipseState>& eclipseState,
std::shared_ptr<Opm::Schedule>& schedule, std::unique_ptr<UDQState>& udqState, std::unique_ptr<Action::State>& actionState, std::shared_ptr<Opm::SummaryConfig>& summaryConfig,
std::unique_ptr<ErrorGuard> errorGuard, std::shared_ptr<Opm::Python>& python, std::unique_ptr<ParseContext> parseContext,
bool initFromRestart, bool checkDeck, const std::optional<int>& outputInterval)
{

View File

@@ -57,8 +57,8 @@ FileOutputMode setupLogging(int mpi_rank_, const std::string& deck_filename, con
/// \brief Reads the deck and creates all necessary objects if needed
///
/// If pointers already contains objects then they are used otherwise they are created and can be used outside later.
void readDeck(int rank, std::string& deckFilename, std::unique_ptr<Deck>& deck, std::unique_ptr<EclipseState>& eclipseState,
std::unique_ptr<Schedule>& schedule, std::unique_ptr<UDQState>& udqState, std::unique_ptr<Action::State>& actionState, std::unique_ptr<SummaryConfig>& summaryConfig,
void readDeck(int rank, std::string& deckFilename, std::shared_ptr<Deck>& deck, std::shared_ptr<EclipseState>& eclipseState,
std::shared_ptr<Schedule>& schedule, std::unique_ptr<UDQState>& udqState, std::unique_ptr<Action::State>& actionState, std::shared_ptr<SummaryConfig>& summaryConfig,
std::unique_ptr<ErrorGuard> errorGuard, std::shared_ptr<Python>& python, std::unique_ptr<ParseContext> parseContext,
bool initFromRestart, bool checkDeck, const std::optional<int>& outputInterval);
} // end namespace Opm