add EclWriter to FlowProblemComp

so the FlowProblemComp can output ecl style output.
it duplicates the OutputBlackoilModule and GenericOutputBlackoilModule
for compositional related output for now.
This commit is contained in:
Kai Bao
2024-10-01 23:31:24 +02:00
parent 0a128e8a17
commit 4ba1cd53d7
15 changed files with 4486 additions and 144 deletions

View File

@@ -98,6 +98,7 @@ list (APPEND MAIN_SOURCE_FILES
opm/simulators/flow/FlowUtils.cpp
opm/simulators/flow/GenericCpGridVanguard.cpp
opm/simulators/flow/GenericOutputBlackoilModule.cpp
opm/simulators/flow/GenericOutputCompositionalModule.cpp
opm/simulators/flow/GenericThresholdPressure.cpp
opm/simulators/flow/GenericTracerModel.cpp
opm/simulators/flow/InterRegFlows.cpp
@@ -817,6 +818,7 @@ list (APPEND PUBLIC_HEADER_FILES
opm/simulators/flow/FlowThresholdPressure.hpp
opm/simulators/flow/GenericCpGridVanguard.hpp
opm/simulators/flow/GenericOutputBlackoilModule.hpp
opm/simulators/flow/GenericOutputCompositionalModule.hpp
opm/simulators/flow/GenericThresholdPressure.hpp
opm/simulators/flow/GenericThresholdPressure_impl.hpp
opm/simulators/flow/GenericTracerModel.hpp
@@ -829,6 +831,7 @@ list (APPEND PUBLIC_HEADER_FILES
opm/simulators/flow/NewTranFluxModule.hpp
opm/simulators/flow/NonlinearSolver.hpp
opm/simulators/flow/OutputBlackoilModule.hpp
opm/simulators/flow/OutputCompositionalModule.hpp
opm/simulators/flow/partitionCells.hpp
opm/simulators/flow/PolyhedralGridVanguard.hpp
opm/simulators/flow/priVarsPacking.hpp

View File

@@ -669,7 +669,7 @@ public:
// write initial condition
if (problem_->shouldWriteOutput())
EWOMS_CATCH_PARALLEL_EXCEPTIONS_FATAL(problem_->writeOutput());
EWOMS_CATCH_PARALLEL_EXCEPTIONS_FATAL(problem_->writeOutput(true));
timeStepSize_ = oldTimeStepSize;
timeStepIdx_ = oldTimeStepIdx;
@@ -748,7 +748,7 @@ public:
// write the result to disk
writeTimer_.start();
if (problem_->shouldWriteOutput())
EWOMS_CATCH_PARALLEL_EXCEPTIONS_FATAL(problem_->writeOutput());
EWOMS_CATCH_PARALLEL_EXCEPTIONS_FATAL(problem_->writeOutput(true));
writeTimer_.stop();
// do the next time integration

View File

@@ -39,7 +39,7 @@
#include <opm/simulators/flow/DamarisParameters.hpp>
#include <opm/simulators/flow/EclGenericWriter.hpp>
#include <opm/simulators/flow/FlowBaseVanguard.hpp>
#include <opm/simulators/flow/OutputBlackoilModule.hpp>
#include <opm/simulators/flow/OutputCompositionalModule.hpp>
#include <opm/simulators/utils/DamarisVar.hpp>
#include <opm/simulators/utils/DamarisKeywords.hpp>
#include <opm/simulators/utils/DeferredLoggingErrorHelpers.hpp>

View File

@@ -134,6 +134,13 @@ protected:
bool isFloresn,
std::array<FlowsData<double>, 3>&& floresn);
void doWriteOutput(const int reportStepNum,
const std::optional<int> timeStepNum,
const bool isSubStep,
Scalar curTime,
Scalar nextStepSize,
data::Solution&& localCellData);
void evalSummary(int reportStepNum,
Scalar curTime,
const data::Wells& localWellData,

View File

@@ -136,10 +136,6 @@ getInterRegFlowsAsMap(const Opm::InterRegFlowMap& map)
struct EclWriteTasklet : public Opm::TaskletInterface
{
Opm::Action::State actionState_;
Opm::WellTestState wtestState_;
Opm::SummaryState summaryState_;
Opm::UDQState udqState_;
Opm::EclipseIO& eclIO_;
int reportStepNum_;
std::optional<int> timeStepNum_;
@@ -147,45 +143,48 @@ struct EclWriteTasklet : public Opm::TaskletInterface
double secondsElapsed_;
Opm::RestartValue restartValue_;
bool writeDoublePrecision_;
std::optional<Opm::Action::State> actionState_;
std::optional<Opm::WellTestState> wtestState_;
std::optional<Opm::SummaryState> summaryState_;
std::optional<Opm::UDQState> udqState_;
explicit EclWriteTasklet(const Opm::Action::State& actionState,
const Opm::WellTestState& wtestState,
const Opm::SummaryState& summaryState,
const Opm::UDQState& udqState,
Opm::EclipseIO& eclIO,
explicit EclWriteTasklet(Opm::EclipseIO& eclIO,
int reportStepNum,
std::optional<int> timeStepNum,
bool isSubStep,
double secondsElapsed,
Opm::RestartValue restartValue,
bool writeDoublePrecision)
: actionState_(actionState)
, wtestState_(wtestState)
, summaryState_(summaryState)
, udqState_(udqState)
, eclIO_(eclIO)
bool writeDoublePrecision,
std::optional<Opm::Action::State> actionState = std::nullopt,
std::optional<Opm::WellTestState> wtestState = std::nullopt,
std::optional<Opm::SummaryState> summaryState = std::nullopt,
std::optional<Opm::UDQState> udqState = std::nullopt)
: eclIO_(eclIO)
, reportStepNum_(reportStepNum)
, timeStepNum_(timeStepNum)
, isSubStep_(isSubStep)
, secondsElapsed_(secondsElapsed)
, restartValue_(std::move(restartValue))
, writeDoublePrecision_(writeDoublePrecision)
, actionState_(std::move(actionState))
, wtestState_(std::move(wtestState))
, summaryState_(std::move(summaryState))
, udqState_(std::move(udqState))
{}
// callback to eclIO serial writeTimeStep method
void run()
{
this->eclIO_.writeTimeStep(this->actionState_,
this->wtestState_,
this->summaryState_,
this->udqState_,
this->reportStepNum_,
this->eclIO_.writeTimeStep(this->reportStepNum_,
this->isSubStep_,
this->secondsElapsed_,
std::move(this->restartValue_),
this->writeDoublePrecision_,
this->timeStepNum_
);
this->timeStepNum_,
std::move(this->actionState_),
std::move(this->wtestState_),
std::move(this->summaryState_),
std::move(this->udqState_));
}
};
@@ -609,16 +608,102 @@ doWriteOutput(const int reportStepNum,
}
// create a tasklet to write the data for the current time step to disk
auto eclWriteTasklet = std::make_shared<EclWriteTasklet>(
auto eclWriteTasklet = std::make_shared<EclWriteTasklet>(/*
actionState,
isParallel ? this->collectOnIORank_.globalWellTestState() : std::move(localWTestState),
summaryState, udqState, *this->eclIO_,
summaryState, udqState, */*this->eclIO_,
reportStepNum, timeStepNum, isSubStep, curTime, std::move(restartValue), doublePrecision);
// finally, start a new output writing job
this->taskletRunner_->dispatch(std::move(eclWriteTasklet));
}
template<class Grid, class EquilGrid, class GridView, class ElementMapper, class Scalar>
void EclGenericWriter<Grid,EquilGrid,GridView,ElementMapper,Scalar>::
doWriteOutput(const int reportStepNum,
const std::optional<int> timeStepNum,
const bool isSubStep,
Scalar curTime,
Scalar nextStepSize,
data::Solution&& localCellData)
{
const auto isParallel = this->collectOnIORank_.isParallel();
const bool needsReordering = this->collectOnIORank_.doesNeedReordering();
data::Wells localWellData {};
data::WellBlockAveragePressures localWBP{};
data::GroupAndNetworkValues localGroupAndNetworkData{};
std::map<int,data::AquiferData> localAquiferData {};
RestartValue restartValue {
(isParallel || needsReordering)
? this->collectOnIORank_.globalCellData()
: std::move(localCellData),
isParallel ? this->collectOnIORank_.globalWellData()
: std::move(localWellData),
isParallel ? this->collectOnIORank_.globalGroupAndNetworkData()
: std::move(localGroupAndNetworkData),
isParallel ? this->collectOnIORank_.globalAquiferData()
: std::move(localAquiferData)
};
// if (eclState_.getSimulationConfig().useThresholdPressure()) {
// restartValue.addExtra("THRESHPR", UnitSystem::measure::pressure,
// thresholdPressure);
// }
// Add suggested next timestep to extra data.
if (! isSubStep) {
restartValue.addExtra("OPMEXTRA", std::vector<double>(1, nextStepSize));
}
// Add nnc flows and flores.
// if (false/*isFlowsn*/) {
// const auto flowsn_global = isParallel ? this->collectOnIORank_.globalFlowsn() : std::move(flowsn);
// for (const auto& flows : flowsn_global) {
// if (flows.name.empty())
// continue;
// if (flows.name == "FLOGASN+") {
// restartValue.addExtra(flows.name, UnitSystem::measure::gas_surface_rate, flows.values);
// } else {
// restartValue.addExtra(flows.name, UnitSystem::measure::liquid_surface_rate, flows.values);
// }
// }
// }
// if (/*isFloresn*/) {
// const auto floresn_global = isParallel ? this->collectOnIORank_.globalFloresn() : std::move(floresn);
// for (const auto& flores : floresn_global) {
// if (flores.name.empty()) {
// continue;
// }
// restartValue.addExtra(flores.name, UnitSystem::measure::rate, flores.values);
// }
// }
// make sure that the previous I/O request has been completed
// and the number of incomplete tasklets does not increase between
// time steps
this->taskletRunner_->barrier();
// check if there might have been a failure in the TaskletRunner
if (this->taskletRunner_->failure()) {
throw std::runtime_error("Failure in the TaskletRunner while writing output.");
}
// create a tasklet to write the data for the current time step to disk
auto eclWriteTasklet = std::make_shared<EclWriteTasklet>(
/* actionState,
isParallel ? this->collectOnIORank_.globalWellTestState() : std::move(localWTestState),
summaryState, udqState, */ *this->eclIO_,
reportStepNum, timeStepNum, isSubStep, curTime, std::move(restartValue), /* doublePrecision*/ false);
// finally, start a new output writing job
this->taskletRunner_->dispatch(std::move(eclWriteTasklet));
}
template<class Grid, class EquilGrid, class GridView, class ElementMapper, class Scalar>
void EclGenericWriter<Grid,EquilGrid,GridView,ElementMapper,Scalar>::
evalSummary(const int reportStepNum,

View File

@@ -41,7 +41,7 @@
#include <opm/simulators/flow/countGlobalCells.hpp>
#include <opm/simulators/flow/EclGenericWriter.hpp>
#include <opm/simulators/flow/FlowBaseVanguard.hpp>
#include <opm/simulators/flow/OutputBlackoilModule.hpp>
#include <opm/simulators/flow/OutputCompositionalModule.hpp>
#include <opm/simulators/timestepping/SimulatorTimer.hpp>
#include <opm/simulators/utils/DeferredLoggingErrorHelpers.hpp>
#include <opm/simulators/utils/ParallelRestart.hpp>
@@ -132,7 +132,7 @@ public:
static void registerParameters()
{
OutputBlackOilModule<TypeTag>::registerParameters();
OutputCompositionalModule<TypeTag>::registerParameters();
Parameters::Register<Parameters::EnableAsyncEclOutput>
("Write the ECL-formated results in a non-blocking way "
@@ -169,13 +169,13 @@ public:
eclBroadcast(this->simulator_.vanguard().grid().comm(), smryCfg);
this->outputModule_ = std::make_unique<OutputBlackOilModule<TypeTag>>
this->outputModule_ = std::make_unique<OutputCompositionalModule<TypeTag>>
(simulator, smryCfg, this->collectOnIORank_);
}
else
#endif
{
this->outputModule_ = std::make_unique<OutputBlackOilModule<TypeTag>>
this->outputModule_ = std::make_unique<OutputCompositionalModule<TypeTag>>
(simulator, this->eclIO_->finalSummaryConfig(), this->collectOnIORank_);
}
@@ -227,49 +227,49 @@ public:
simulator_.setupTimer().realTimeElapsed() +
simulator_.vanguard().setupTime();
const auto localWellData = simulator_.problem().wellModel().wellData();
const auto localWBP = simulator_.problem().wellModel().wellBlockAveragePressures();
const auto localGroupAndNetworkData = simulator_.problem().wellModel()
.groupAndNetworkData(reportStepNum);
const auto localAquiferData = simulator_.problem().aquiferModel().aquiferData();
const auto localWellTestState = simulator_.problem().wellModel().wellTestState();
// const auto localWellData = simulator_.problem().wellModel().wellData();
// const auto localWBP = simulator_.problem().wellModel().wellBlockAveragePressures();
// const auto localGroupAndNetworkData = simulator_.problem().wellModel()
// .groupAndNetworkData(reportStepNum);
//
// const auto localAquiferData = simulator_.problem().aquiferModel().aquiferData();
// const auto localWellTestState = simulator_.problem().wellModel().wellTestState();
this->prepareLocalCellData(isSubStep, reportStepNum);
if (this->outputModule_->needInterfaceFluxes(isSubStep)) {
this->captureLocalFluxData();
}
if (this->collectOnIORank_.isParallel()) {
OPM_BEGIN_PARALLEL_TRY_CATCH()
this->collectOnIORank_.collect({},
outputModule_->getBlockData(),
localWellData,
localWBP,
localGroupAndNetworkData,
localAquiferData,
localWellTestState,
this->outputModule_->getInterRegFlows(),
{},
{});
if (this->collectOnIORank_.isIORank()) {
auto& iregFlows = this->collectOnIORank_.globalInterRegFlows();
if (! iregFlows.readIsConsistent()) {
throw std::runtime_error {
"Inconsistent inter-region flow "
"region set names in parallel"
};
}
iregFlows.compress();
}
OPM_END_PARALLEL_TRY_CATCH("Collect to I/O rank: ",
this->simulator_.vanguard().grid().comm());
}
// if (this->collectOnIORank_.isParallel()) {
// OPM_BEGIN_PARALLEL_TRY_CATCH()
//
// this->collectOnIORank_.collect({},
// outputModule_->getBlockData(),
// localWellData,
// localWBP,
// localGroupAndNetworkData,
// localAquiferData,
// localWellTestState,
// this->outputModule_->getInterRegFlows(),
// {},
// {});
//
// if (this->collectOnIORank_.isIORank()) {
// auto& iregFlows = this->collectOnIORank_.globalInterRegFlows();
//
// if (! iregFlows.readIsConsistent()) {
// throw std::runtime_error {
// "Inconsistent inter-region flow "
// "region set names in parallel"
// };
// }
//
// iregFlows.compress();
// }
//
// OPM_END_PARALLEL_TRY_CATCH("Collect to I/O rank: ",
// this->simulator_.vanguard().grid().comm());
// }
std::map<std::string, double> miscSummaryData;
@@ -323,6 +323,11 @@ public:
? this->collectOnIORank_.globalInterRegFlows()
: this->outputModule_->getInterRegFlows();
const data::Wells& localWellData {};
const data::WellBlockAveragePressures& localWBP{};
const data::GroupAndNetworkValues& localGroupAndNetworkData{};
const std::map<int,data::AquiferData>& localAquiferData {};
this->evalSummary(reportStepNum,
curTime,
localWellData,
@@ -415,19 +420,19 @@ public:
this->outputModule_->outputErrorLog(simulator_.gridView().comm());
// output using eclWriter if enabled
auto localWellData = simulator_.problem().wellModel().wellData();
auto localGroupAndNetworkData = simulator_.problem().wellModel()
.groupAndNetworkData(reportStepNum);
auto localAquiferData = simulator_.problem().aquiferModel().aquiferData();
auto localWellTestState = simulator_.problem().wellModel().wellTestState();
const bool isFlowsn = this->outputModule_->hasFlowsn();
auto flowsn = this->outputModule_->getFlowsn();
const bool isFloresn = this->outputModule_->hasFloresn();
auto floresn = this->outputModule_->getFloresn();
// auto localWellData = simulator_.problem().wellModel().wellData();
// auto localGroupAndNetworkData = simulator_.problem().wellModel()
// .groupAndNetworkData(reportStepNum);
// auto localAquiferData = simulator_.problem().aquiferModel().aquiferData();
// auto localWellTestState = simulator_.problem().wellModel().wellTestState();
//
// const bool isFlowsn = this->outputModule_->hasFlowsn();
// auto flowsn = this->outputModule_->getFlowsn();
//
// const bool isFloresn = this->outputModule_->hasFloresn();
// auto floresn = this->outputModule_->getFloresn();
//
// data::Solution localCellData = {};
if (! isSubStep || Parameters::Get<Parameters::EnableWriteAllSolutions>()) {
@@ -438,7 +443,7 @@ public:
// Collect RFT data on rank 0
this->outputModule_->accumulateRftDataParallel(simulator_.gridView().comm());
// Add cell data to perforations for RFT output
this->outputModule_->addRftDataToWells(localWellData, reportStepNum);
// this->outputModule_->addRftDataToWells(localWellData, reportStepNum);
}
if (this->collectOnIORank_.isParallel() ||
@@ -449,19 +454,19 @@ public:
// output. There's consequently no need to collect those
// properties on the I/O rank.
this->collectOnIORank_.collect(localCellData,
this->outputModule_->getBlockData(),
localWellData,
/* wbpData = */ {},
localGroupAndNetworkData,
localAquiferData,
localWellTestState,
/* interRegFlows = */ {},
flowsn,
floresn);
if (this->collectOnIORank_.isIORank()) {
this->outputModule_->assignGlobalFieldsToSolution(this->collectOnIORank_.globalCellData());
}
// this->collectOnIORank_.collect(localCellData,
// this->outputModule_->getBlockData(),
// localWellData,
// /* wbpData = */ {},
// localGroupAndNetworkData,
// localAquiferData,
// localWellTestState,
// /* interRegFlows = */ {},
// flowsn,
// floresn);
// if (this->collectOnIORank_.isIORank()) {
// this->outputModule_->assignGlobalFieldsToSolution(this->collectOnIORank_.globalCellData());
// }
} else {
this->outputModule_->assignGlobalFieldsToSolution(localCellData);
}
@@ -473,20 +478,24 @@ public:
if (Parameters::Get<Parameters::EnableWriteAllSolutions>()) {
timeStepIdx = simulator_.timeStepIndex();
}
this->doWriteOutput(reportStepNum, timeStepIdx, isSubStep,
std::move(localCellData),
std::move(localWellData),
std::move(localGroupAndNetworkData),
std::move(localAquiferData),
std::move(localWellTestState),
this->actionState(),
this->udqState(),
this->summaryState(),
this->simulator_.problem().thresholdPressure().getRestartVector(),
curTime, nextStepSize,
Parameters::Get<Parameters::EclOutputDoublePrecision>(),
isFlowsn, std::move(flowsn),
isFloresn, std::move(floresn));
this->doWriteOutput(reportStepNum,
timeStepIdx,
isSubStep,
curTime,
nextStepSize,
std::move(localCellData) );
// std::move(localWellData),
// std::move(localGroupAndNetworkData),
// std::move(localAquiferData),
// std::move(localWellTestState),
// this->actionState(),
// this->udqState(),
// this->summaryState(),
// this->simulator_.problem().thresholdPressure().getRestartVector(),
// curTime, nextStepSize,
// Parameters::Get<Parameters::EclOutputDoublePrecision>(),
// isFlowsn, std::move(flowsn),
// isFloresn, std::move(floresn));
}
}
@@ -650,7 +659,7 @@ public:
// volumes at the restart time instead of the start of the base run.
// Nevertheless, this is how Flow has "always" done it.
//
// See GenericOutputBlackoilModule::accumulateRegionSums() for
// See GenericOutputCompositionalModule::accumulateRegionSums() for
// additional comments.
auto inplace = this->outputModule_
->calc_inplace(miscSummaryData, regionData,
@@ -661,10 +670,10 @@ public:
}
}
const OutputBlackOilModule<TypeTag>& outputModule() const
const OutputCompositionalModule<TypeTag>& outputModule() const
{ return *outputModule_; }
OutputBlackOilModule<TypeTag>& mutableOutputModule() const
OutputCompositionalModule<TypeTag>& mutableOutputModule() const
{ return *outputModule_; }
Scalar restartTimeStepSize() const
@@ -736,26 +745,26 @@ private:
this->outputModule_->accumulateDensityParallel();
}
if constexpr (enableMech) {
if (simulator_.vanguard().eclState().runspec().mech()) {
OPM_TIMEBLOCK(prepareMechData);
for (const auto& elem : elements(gridView, Dune::Partitions::interior)) {
elemCtx.updatePrimaryStencil(elem);
elemCtx.updatePrimaryIntensiveQuantities(/*timeIdx=*/0);
outputModule_->processElementMech(elemCtx);
}
}
}
// if constexpr (enableMech) {
// if (simulator_.vanguard().eclState().runspec().mech()) {
// OPM_TIMEBLOCK(prepareMechData);
// for (const auto& elem : elements(gridView, Dune::Partitions::interior)) {
// elemCtx.updatePrimaryStencil(elem);
// elemCtx.updatePrimaryIntensiveQuantities(/*timeIdx=*/0);
// outputModule_->processElementMech(elemCtx);
// }
// }
// }
if (! this->simulator_.model().linearizer().getFlowsInfo().empty()) {
OPM_TIMEBLOCK(prepareFlowsData);
for (const auto& elem : elements(gridView, Dune::Partitions::interior)) {
elemCtx.updatePrimaryStencil(elem);
elemCtx.updatePrimaryIntensiveQuantities(/*timeIdx=*/0);
this->outputModule_->processElementFlows(elemCtx);
}
}
// if (! this->simulator_.model().linearizer().getFlowsInfo().empty()) {
// OPM_TIMEBLOCK(prepareFlowsData);
// for (const auto& elem : elements(gridView, Dune::Partitions::interior)) {
// elemCtx.updatePrimaryStencil(elem);
// elemCtx.updatePrimaryIntensiveQuantities(/*timeIdx=*/0);
//
// this->outputModule_->processElementFlows(elemCtx);
// }
// }
{
OPM_TIMEBLOCK(prepareBlockData);
@@ -826,7 +835,8 @@ private:
}
Simulator& simulator_;
std::unique_ptr<OutputBlackOilModule<TypeTag> > outputModule_;
// TODO: OutputCompositionalModule needs to be part of the TypeTag
std::unique_ptr<OutputCompositionalModule<TypeTag> > outputModule_;
Scalar restartTimeStepSize_;
int rank_ ;
Inplace inplace_;

View File

@@ -493,7 +493,7 @@ public:
* \brief Write the requested quantities of the current solution into the output
* files.
*/
void writeOutput(bool verbose = true)
virtual void writeOutput(bool verbose)
{
OPM_TIMEBLOCK(problemWriteOutput);
// use the generic code to prepare the output fields and to

View File

@@ -432,7 +432,7 @@ public:
/*!
* \brief Called by the simulator after each time integration.
*/
void endTimeStep () override
void endTimeStep() override
{
FlowProblemType::endTimeStep();
@@ -517,7 +517,7 @@ public:
* \brief Write the requested quantities of the current solution into the output
* files.
*/
void writeOutput(bool verbose = true)
void writeOutput(bool verbose) override
{
FlowProblemType::writeOutput(verbose);

View File

@@ -82,6 +82,7 @@ class FlowProblemComp : public FlowProblem<TypeTag>
using typename FlowProblemType::RateVector;
using InitialFluidState = CompositionalFluidState<Scalar, FluidSystem>;
using EclWriterType = EclWriter<TypeTag>;
public:
using FlowProblemType::porosity;
@@ -94,6 +95,8 @@ public:
{
FlowProblemType::registerParameters();
EclWriterType::registerParameters();
// tighter tolerance is needed for compositional modeling here
Parameters::SetDefault<Parameters::NewtonTolerance<Scalar>>(1e-7);
}
@@ -105,6 +108,8 @@ public:
explicit FlowProblemComp(Simulator& simulator)
: FlowProblemType(simulator)
{
eclWriter_ = std::make_unique<EclWriterType>(simulator);
enableEclOutput_ = Parameters::Get<Parameters::EnableEclOutput>();
}
/*!
@@ -127,9 +132,18 @@ public:
[&vg = this->simulator().vanguard()](const unsigned int it) { return vg.gridIdxToEquilGridIdx(it); });
updated = true;
};
// TODO: we might need to do the same with FlowProblemBlackoil for parallel
finishTransmissibilities();
if (enableEclOutput_) {
eclWriter_->setTransmissibilities(&simulator.problem().eclTransmissibilities());
std::function<unsigned int(unsigned int)> equilGridToGrid = [&simulator](unsigned int i) {
return simulator.vanguard().gridEquilIdxToGridIdx(i);
};
eclWriter_->extractOutputTransAndNNC(equilGridToGrid);
}
const auto& eclState = simulator.vanguard().eclState();
const auto& schedule = simulator.vanguard().schedule();
@@ -179,6 +193,11 @@ public:
FlowProblemType::readMaterialParameters_();
FlowProblemType::readThermalParameters_();
// write the static output files (EGRID, INIT)
if (enableEclOutput_) {
eclWriter_->writeInit();
}
const auto& initconfig = eclState.getInitConfig();
if (initconfig.restartRequested())
readEclRestartSolution_();
@@ -220,6 +239,60 @@ public:
}
}
/*!
* \brief Called by the simulator after each time integration.
*/
void endTimeStep() override
{
FlowProblemType::endTimeStep();
const bool isSubStep = !this->simulator().episodeWillBeOver();
// after the solution is updated, the values in output module needs also updated
this->eclWriter_->mutableOutputModule().invalidateLocalData();
// For CpGrid with LGRs, ecl/vtk output is not supported yet.
const auto& grid = this->simulator().vanguard().gridView().grid();
using GridType = std::remove_cv_t<std::remove_reference_t<decltype(grid)>>;
constexpr bool isCpGrid = std::is_same_v<GridType, Dune::CpGrid>;
if (!isCpGrid || (grid.maxLevel() == 0)) {
this->eclWriter_->evalSummaryState(isSubStep);
}
}
void writeReports(const SimulatorTimer& timer) {
if (enableEclOutput_){
eclWriter_->writeReports(timer);
}
}
/*!
* \brief Write the requested quantities of the current solution into the output
* files.
*/
void writeOutput(bool verbose) override
{
FlowProblemType::writeOutput(verbose);
const bool isSubStep = !this->simulator().episodeWillBeOver();
data::Solution localCellData = {};
#if HAVE_DAMARIS
// N.B. the Damaris output has to be done before the ECL output as the ECL one
// does all kinds of std::move() relocation of data
if (enableDamarisOutput_) {
damarisWriter_->writeOutput(localCellData, isSubStep) ;
}
#endif
if (enableEclOutput_) {
if (Parameters::Get<Parameters::EnableWriteAllSolutions>() || !isSubStep) {
eclWriter_->writeOutput(std::move(localCellData), isSubStep);
}
}
}
/*!
* \copydoc FvBaseProblem::boundary
*
@@ -494,6 +567,9 @@ private:
std::vector<InitialFluidState> initialFluidStates_;
bool enableEclOutput_;
std::unique_ptr<EclWriterType> eclWriter_;
bool enableVtkOutput_;
};

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,566 @@
// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
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 2 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/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
* \copydoc Opm::OutputCompositionalModule
*/
#ifndef OPM_GENERIC_OUTPUT_COMPOSITIONAL_MODULE_HPP
#define OPM_GENERIC_OUTPUT_COMPOSITIONAL_MODULE_HPP
#include <opm/input/eclipse/EclipseState/Grid/FaceDir.hpp>
#include <opm/input/eclipse/EclipseState/SummaryConfig/SummaryConfig.hpp>
#include <opm/output/data/Wells.hpp>
#include <opm/output/eclipse/Inplace.hpp>
#include <opm/simulators/flow/FlowsData.hpp>
#include <opm/simulators/flow/InterRegFlows.hpp>
#include <opm/simulators/flow/LogOutputHelper.hpp>
#include <opm/simulators/flow/RegionPhasePVAverage.hpp>
#include <opm/simulators/utils/ParallelCommunication.hpp>
#include <array>
#include <cstddef>
#include <functional>
#include <map>
#include <optional>
#include <unordered_map>
#include <utility>
#include <vector>
namespace Opm {
namespace data { class Solution; }
class EclipseState;
class Schedule;
class SummaryConfig;
class SummaryConfigNode;
class SummaryState;
template<class FluidSystem>
class GenericOutputCompositionalModule {
public:
using Scalar = typename FluidSystem::Scalar;
// Virtual destructor for safer inheritance.
virtual ~GenericOutputCompositionalModule();
Scalar* getPRESSURE_ptr(void) {
return (this->fluidPressure_.data()) ;
};
int getPRESSURE_size( void ) {
return (this->fluidPressure_.size()) ;
};
void outputTimeStamp(const std::string& lbl,
double elapsed,
int rstep,
boost::posix_time::ptime currentDate);
/// Clear internal arrays for parallel accumulation of per-region phase
/// density averages.
void prepareDensityAccumulation();
/// Run cross-rank parallel accumulation of per-region phase density
/// running sums (average values).
void accumulateDensityParallel();
// write cumulative production and injection reports to output
void outputCumLog(std::size_t reportStepNum);
// write production report to output
void outputProdLog(std::size_t reportStepNum);
// write injection report to output
void outputInjLog(std::size_t reportStepNum);
// calculate Fluid In Place
Inplace calc_inplace(std::map<std::string, double>& miscSummaryData,
std::map<std::string, std::vector<double>>& regionData,
const Parallel::Communication& comm);
void outputFipAndResvLog(const Inplace& inplace,
const std::size_t reportStepNum,
double elapsed,
boost::posix_time::ptime currentDate,
const bool substep,
const Parallel::Communication& comm);
void outputErrorLog(const Parallel::Communication& comm) const;
void addRftDataToWells(data::Wells& wellDatas,
std::size_t reportStepNum);
/*!
* \brief Move all buffers to data::Solution.
*/
void assignToSolution(data::Solution& sol);
void setRestart(const data::Solution& sol,
unsigned elemIdx,
unsigned globalDofIndex);
Scalar getSolventSaturation(unsigned elemIdx) const
{
if (sSol_.size() > elemIdx)
return sSol_[elemIdx];
return 0;
}
Scalar getSolventRsw(unsigned elemIdx) const
{
if (rswSol_.size() > elemIdx)
return rswSol_[elemIdx];
return 0;
}
Scalar getPolymerConcentration(unsigned elemIdx) const
{
if (cPolymer_.size() > elemIdx)
return cPolymer_[elemIdx];
return 0;
}
Scalar getFoamConcentration(unsigned elemIdx) const
{
if (cFoam_.size() > elemIdx)
return cFoam_[elemIdx];
return 0;
}
Scalar getSaltConcentration(unsigned elemIdx) const
{
if (cSalt_.size() > elemIdx)
return cSalt_[elemIdx];
return 0;
}
Scalar getSaltSaturation(unsigned elemIdx) const
{
if (pSalt_.size() > elemIdx)
return pSalt_[elemIdx];
return 0;
}
Scalar getPermFactor(unsigned elemIdx) const
{
if (permFact_.size() > elemIdx)
return permFact_[elemIdx];
return 0;
}
Scalar getMicrobialConcentration(unsigned elemIdx) const
{
if (cMicrobes_.size() > elemIdx)
return cMicrobes_[elemIdx];
return 0;
}
Scalar getOxygenConcentration(unsigned elemIdx) const
{
if (cOxygen_.size() > elemIdx)
return cOxygen_[elemIdx];
return 0;
}
Scalar getUreaConcentration(unsigned elemIdx) const
{
if (cUrea_.size() > elemIdx)
return cUrea_[elemIdx];
return 0;
}
Scalar getBiofilmConcentration(unsigned elemIdx) const
{
if (cBiofilm_.size() > elemIdx)
return cBiofilm_[elemIdx];
return 0;
}
Scalar getCalciteConcentration(unsigned elemIdx) const
{
if (cCalcite_.size() > elemIdx)
return cCalcite_[elemIdx];
return 0;
}
const std::array<FlowsData<double>, 3>& getFlowsn() const
{
return this->flowsn_;
}
bool hasFlowsn() const
{
return enableFlowsn_;
}
bool hasFlows() const
{
return enableFlows_;
}
bool hasBlockFlows() const
{
return blockFlows_;
}
bool anyFlows() const
{
return anyFlows_;
}
const std::array<FlowsData<double>, 3>& getFloresn() const
{
return this->floresn_;
}
bool hasFloresn() const
{
return enableFloresn_;
}
bool hasFlores() const
{
return enableFlores_;
}
bool anyFlores() const
{
return anyFlores_;
}
bool needInterfaceFluxes([[maybe_unused]] const bool isSubStep) const
{
return this->interRegionFlows_.wantInterRegflowSummary();
}
const std::map<std::pair<std::string, int>, double>& getBlockData()
{
return blockData_;
}
const Inplace& initialInplace() const
{
return this->initialInplace_.value();
}
bool localDataValid() const{
return local_data_valid_;
}
void invalidateLocalData(){
local_data_valid_ = false;
}
void validateLocalData(){
local_data_valid_ = true;
}
void setCnvData(const std::vector<std::vector<int>>& data)
{
cnvData_ = data;
}
template<class Serializer>
void serializeOp(Serializer& serializer)
{
serializer(initialInplace_);
}
//! \brief Assign fields that are in global numbering to the solution.
//! \detail This is used to add fields that for some reason cannot be collected
//! using the regular collect mechanism to the solution. In particular this
//! is used with RPTRST CONV output.
void assignGlobalFieldsToSolution(data::Solution& sol);
protected:
using ScalarBuffer = std::vector<Scalar>;
using StringBuffer = std::vector<std::string>;
enum { numPhases = FluidSystem::numPhases };
enum { numComponents = FluidSystem::numComponents };
enum { gasPhaseIdx = FluidSystem::gasPhaseIdx };
enum { oilPhaseIdx = FluidSystem::oilPhaseIdx };
enum { waterPhaseIdx = FluidSystem::waterPhaseIdx };
enum { gasCompIdx = FluidSystem::gasCompIdx };
enum { oilCompIdx = FluidSystem::oilCompIdx };
enum { waterCompIdx = FluidSystem::waterCompIdx };
using Dir = FaceDir::DirEnum;
GenericOutputCompositionalModule(const EclipseState& eclState,
const Schedule& schedule,
const SummaryConfig& summaryConfig,
const SummaryState& summaryState,
const std::string& moduleVersionName,
bool enableEnergy,
bool enableTemperature,
bool enableMech,
bool enableSolvent,
bool enablePolymer,
bool enableFoam,
bool enableBrine,
bool enableSaltPrecipitation,
bool enableExtbo,
bool enableMICP);
void doAllocBuffers(unsigned bufferSize,
unsigned reportStepNum,
const bool substep,
const bool log,
const bool isRestart,
const bool vapparsActive = false,
const bool enablePCHysteresis = false,
const bool enableNonWettingHysteresis =false,
const bool enableWettingHysteresis = false,
unsigned numTracers = 0,
const std::vector<bool>& enableSolTracers = {},
unsigned numOutputNnc = 0);
void makeRegionSum(Inplace& inplace,
const std::string& region_name,
const Parallel::Communication& comm) const;
Inplace accumulateRegionSums(const Parallel::Communication& comm);
void updateSummaryRegionValues(const Inplace& inplace,
std::map<std::string, double>& miscSummaryData,
std::map<std::string, std::vector<double>>& regionData) const;
static bool isOutputCreationDirective_(const std::string& keyword);
// Sum Fip values over regions.
static ScalarBuffer regionSum(const ScalarBuffer& property,
const std::vector<int>& regionId,
const std::size_t maxNumberOfRegions,
const Parallel::Communication& comm);
static int regionMax(const std::vector<int>& region,
const Parallel::Communication& comm);
static void update(Inplace& inplace,
const std::string& region_name,
const Inplace::Phase phase,
const std::size_t ntFip,
const ScalarBuffer& values);
static Scalar sum(const ScalarBuffer& v);
void setupBlockData(std::function<bool(int)> isCartIdxOnThisRank);
virtual bool isDefunctParallelWell(std::string wname) const = 0;
const EclipseState& eclState_;
const Schedule& schedule_;
const SummaryState& summaryState_;
SummaryConfig summaryConfig_;
InterRegFlowMap interRegionFlows_;
LogOutputHelper<Scalar> logOutput_;
bool enableEnergy_{false};
bool enableTemperature_{false};
bool enableMech_{false};
bool enableSolvent_{false};
bool enablePolymer_{false};
bool enableFoam_{false};
bool enableBrine_{false};
bool enableSaltPrecipitation_{false};
bool enableExtbo_{false};
bool enableMICP_{false};
bool forceDisableFipOutput_{false};
bool forceDisableFipresvOutput_{false};
bool computeFip_{false};
struct OutputFIPRestart {
/// Whether or not run requests (surface condition) fluid-in-place
/// restart file output using the 'FIP' mnemonic.
bool noPrefix {false};
/// Whether or not run requests surface condition fluid-in-place
/// restart file output using the 'SFIP' mnemonic.
bool surface {false};
/// Whether or not run requests reservoir condition fluid-in-place
/// restart file output using the 'RFIP' mnemonic.
bool reservoir {false};
void clearBits()
{
this->noPrefix = this->surface = this->reservoir = false;
}
explicit operator bool() const
{
return this->noPrefix || this->surface || this->reservoir;
}
} outputFipRestart_{};
bool anyFlows_{false};
bool anyFlores_{false};
bool blockFlows_{false};
bool enableFlows_{false};
bool enableFlores_{false};
bool enableFlowsn_{false};
bool enableFloresn_{false};
std::unordered_map<Inplace::Phase, ScalarBuffer> fip_;
std::unordered_map<std::string, std::vector<int>> regions_;
std::unordered_map<Inplace::Phase, std::vector<SummaryConfigNode>> regionNodes_;
std::vector<SummaryConfigNode> RPRNodes_;
std::vector<SummaryConfigNode> RPRPNodes_;
std::vector<int> failedCellsPb_;
std::vector<int> failedCellsPd_;
ScalarBuffer gasFormationVolumeFactor_;
ScalarBuffer hydrocarbonPoreVolume_;
ScalarBuffer pressureTimesPoreVolume_;
ScalarBuffer pressureTimesHydrocarbonVolume_;
ScalarBuffer dynamicPoreVolume_;
ScalarBuffer rPorV_;
ScalarBuffer fluidPressure_;
ScalarBuffer temperature_;
ScalarBuffer rs_;
ScalarBuffer rsw_;
ScalarBuffer rv_;
ScalarBuffer rvw_;
ScalarBuffer overburdenPressure_;
ScalarBuffer oilSaturationPressure_;
ScalarBuffer drsdtcon_;
ScalarBuffer sSol_;
ScalarBuffer rswSol_;
ScalarBuffer cPolymer_;
ScalarBuffer cFoam_;
ScalarBuffer cSalt_;
ScalarBuffer pSalt_;
ScalarBuffer permFact_;
ScalarBuffer extboX_;
ScalarBuffer extboY_;
ScalarBuffer extboZ_;
ScalarBuffer mFracOil_;
ScalarBuffer mFracGas_;
ScalarBuffer mFracCo2_;
ScalarBuffer soMax_;
ScalarBuffer swMax_;
ScalarBuffer sgmax_;
ScalarBuffer shmax_;
ScalarBuffer somin_;
ScalarBuffer swmin_;
ScalarBuffer ppcw_;
ScalarBuffer gasDissolutionFactor_;
ScalarBuffer oilVaporizationFactor_;
ScalarBuffer gasDissolutionFactorInWater_;
ScalarBuffer waterVaporizationFactor_;
ScalarBuffer bubblePointPressure_;
ScalarBuffer dewPointPressure_;
ScalarBuffer rockCompPorvMultiplier_;
ScalarBuffer minimumOilPressure_;
ScalarBuffer saturatedOilFormationVolumeFactor_;
ScalarBuffer rockCompTransMultiplier_;
ScalarBuffer cMicrobes_;
ScalarBuffer cOxygen_;
ScalarBuffer cUrea_;
ScalarBuffer cBiofilm_;
ScalarBuffer cCalcite_;
ScalarBuffer pcgw_;
ScalarBuffer pcow_;
ScalarBuffer pcog_;
// buffers for mechanical output
ScalarBuffer mechPotentialForce_;
ScalarBuffer mechPotentialPressForce_;
ScalarBuffer mechPotentialTempForce_;
ScalarBuffer dispX_;
ScalarBuffer dispY_;
ScalarBuffer dispZ_;
ScalarBuffer stressXX_;
ScalarBuffer stressYY_;
ScalarBuffer stressZZ_;
ScalarBuffer stressXY_;
ScalarBuffer stressXZ_;
ScalarBuffer stressYZ_;
ScalarBuffer delstressXX_;
ScalarBuffer delstressYY_;
ScalarBuffer delstressZZ_;
ScalarBuffer delstressXY_;
ScalarBuffer delstressXZ_;
ScalarBuffer delstressYZ_;
ScalarBuffer strainXX_;
ScalarBuffer strainYY_;
ScalarBuffer strainZZ_;
ScalarBuffer strainXY_;
ScalarBuffer strainXZ_;
ScalarBuffer strainYZ_;
std::array<ScalarBuffer, numPhases> saturation_;
std::array<ScalarBuffer, numPhases> invB_;
std::array<ScalarBuffer, numPhases> density_;
std::array<ScalarBuffer, numPhases> viscosity_;
std::array<ScalarBuffer, numPhases> relativePermeability_;
std::array<ScalarBuffer, numComponents> moleFractions_;
std::vector<ScalarBuffer> freeTracerConcentrations_;
std::vector<ScalarBuffer> solTracerConcentrations_;
std::array<ScalarBuffer, numPhases> residual_;
std::array<std::array<ScalarBuffer, numPhases>, 6> flows_;
std::array<std::array<ScalarBuffer, numPhases>, 6> flores_;
std::array<FlowsData<double>, 3> floresn_;
std::array<FlowsData<double>, 3> flowsn_;
std::map<std::size_t, Scalar> oilConnectionPressures_;
std::map<std::size_t, Scalar> waterConnectionSaturations_;
std::map<std::size_t, Scalar> gasConnectionSaturations_;
std::map<std::pair<std::string, int>, double> blockData_;
std::vector<std::vector<int>> cnvData_; //!< Data for CNV_xxx arrays
std::optional<Inplace> initialInplace_;
bool local_data_valid_{false};
std::optional<RegionPhasePoreVolAverage> regionAvgDensity_;
};
} // namespace Opm
#endif // OPM_GENERIC_OUTPUT_BLACK_OIL_MODULE_HPP

View File

@@ -65,13 +65,13 @@
#include <utility>
#include <vector>
namespace Opm::Parameters {
struct ForceDisableFluidInPlaceOutput { static constexpr bool value = false; };
struct ForceDisableResvFluidInPlaceOutput { static constexpr bool value = false; };
} // namespace Opm::Parameters
//namespace Opm::Parameters {
//
//struct ForceDisableFluidInPlaceOutput { static constexpr bool value = false; };
//struct ForceDisableResvFluidInPlaceOutput { static constexpr bool value = false; };
//
//} // namespace Opm::Parameters
//
namespace Opm
{

File diff suppressed because it is too large Load Diff

View File

@@ -283,7 +283,7 @@ public:
simulator_.setEpisodeLength(0.0);
simulator_.setTimeStepSize(0.0);
wellModel_().beginReportStep(timer.currentStepNum());
simulator_.problem().writeOutput();
simulator_.problem().writeOutput(true);
report_.success.output_write_time += perfTimer.stop();
}
@@ -370,7 +370,7 @@ public:
perfTimer.start();
const double nextstep = adaptiveTimeStepping_ ? adaptiveTimeStepping_->suggestedNextStep() : -1.0;
simulator_.problem().setNextTimeStepSize(nextstep);
simulator_.problem().writeOutput();
simulator_.problem().writeOutput(true);
report_.success.output_write_time += perfTimer.stop();
solver_->model().endReportStep();

View File

@@ -353,7 +353,7 @@ void registerAdaptiveParameters();
time::StopWatch perfTimer;
perfTimer.start();
problem.writeOutput();
problem.writeOutput(true);
report.success.output_write_time += perfTimer.secsSinceStart();
}