From 4ba1cd53d79617eba458dadecdfb977684a8f089 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Tue, 1 Oct 2024 23:31:24 +0200 Subject: [PATCH 01/15] add EclWriter to FlowProblemComp so the FlowProblemComp can output ecl style output. it duplicates the OutputBlackoilModule and GenericOutputBlackoilModule for compositional related output for now. --- CMakeLists_files.cmake | 3 + opm/models/utils/simulator.hh | 4 +- opm/simulators/flow/DamarisWriter.hpp | 2 +- opm/simulators/flow/EclGenericWriter.hpp | 7 + opm/simulators/flow/EclGenericWriter_impl.hpp | 133 +- opm/simulators/flow/EclWriter.hpp | 218 +- opm/simulators/flow/FlowProblem.hpp | 2 +- opm/simulators/flow/FlowProblemBlackoil.hpp | 4 +- opm/simulators/flow/FlowProblemComp.hpp | 76 + .../flow/GenericOutputCompositionalModule.cpp | 1741 ++++++++++++++++ .../flow/GenericOutputCompositionalModule.hpp | 566 +++++ opm/simulators/flow/OutputBlackoilModule.hpp | 14 +- .../flow/OutputCompositionalModule.hpp | 1854 +++++++++++++++++ .../flow/SimulatorFullyImplicitBlackoil.hpp | 4 +- .../timestepping/AdaptiveTimeStepping.hpp | 2 +- 15 files changed, 4486 insertions(+), 144 deletions(-) create mode 100644 opm/simulators/flow/GenericOutputCompositionalModule.cpp create mode 100644 opm/simulators/flow/GenericOutputCompositionalModule.hpp create mode 100644 opm/simulators/flow/OutputCompositionalModule.hpp diff --git a/CMakeLists_files.cmake b/CMakeLists_files.cmake index 6825a3c2c..8e11d2038 100644 --- a/CMakeLists_files.cmake +++ b/CMakeLists_files.cmake @@ -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 diff --git a/opm/models/utils/simulator.hh b/opm/models/utils/simulator.hh index de4db24e0..2ebbce92b 100644 --- a/opm/models/utils/simulator.hh +++ b/opm/models/utils/simulator.hh @@ -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 diff --git a/opm/simulators/flow/DamarisWriter.hpp b/opm/simulators/flow/DamarisWriter.hpp index 22a7af7be..058e8570c 100644 --- a/opm/simulators/flow/DamarisWriter.hpp +++ b/opm/simulators/flow/DamarisWriter.hpp @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/opm/simulators/flow/EclGenericWriter.hpp b/opm/simulators/flow/EclGenericWriter.hpp index fee0f0c65..5dc13d013 100644 --- a/opm/simulators/flow/EclGenericWriter.hpp +++ b/opm/simulators/flow/EclGenericWriter.hpp @@ -134,6 +134,13 @@ protected: bool isFloresn, std::array, 3>&& floresn); + void doWriteOutput(const int reportStepNum, + const std::optional timeStepNum, + const bool isSubStep, + Scalar curTime, + Scalar nextStepSize, + data::Solution&& localCellData); + void evalSummary(int reportStepNum, Scalar curTime, const data::Wells& localWellData, diff --git a/opm/simulators/flow/EclGenericWriter_impl.hpp b/opm/simulators/flow/EclGenericWriter_impl.hpp index b033333aa..30e7e59da 100644 --- a/opm/simulators/flow/EclGenericWriter_impl.hpp +++ b/opm/simulators/flow/EclGenericWriter_impl.hpp @@ -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 timeStepNum_; @@ -147,45 +143,48 @@ struct EclWriteTasklet : public Opm::TaskletInterface double secondsElapsed_; Opm::RestartValue restartValue_; bool writeDoublePrecision_; + std::optional actionState_; + std::optional wtestState_; + std::optional summaryState_; + std::optional 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 timeStepNum, bool isSubStep, double secondsElapsed, Opm::RestartValue restartValue, - bool writeDoublePrecision) - : actionState_(actionState) - , wtestState_(wtestState) - , summaryState_(summaryState) - , udqState_(udqState) - , eclIO_(eclIO) + bool writeDoublePrecision, + std::optional actionState = std::nullopt, + std::optional wtestState = std::nullopt, + std::optional summaryState = std::nullopt, + std::optional 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( + auto eclWriteTasklet = std::make_shared(/* 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 +void EclGenericWriter:: +doWriteOutput(const int reportStepNum, + const std::optional 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 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(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( + /* 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 void EclGenericWriter:: evalSummary(const int reportStepNum, diff --git a/opm/simulators/flow/EclWriter.hpp b/opm/simulators/flow/EclWriter.hpp index 6b306fc83..b16454869 100644 --- a/opm/simulators/flow/EclWriter.hpp +++ b/opm/simulators/flow/EclWriter.hpp @@ -41,7 +41,7 @@ #include #include #include -#include +#include #include #include #include @@ -132,7 +132,7 @@ public: static void registerParameters() { - OutputBlackOilModule::registerParameters(); + OutputCompositionalModule::registerParameters(); Parameters::Register ("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> + this->outputModule_ = std::make_unique> (simulator, smryCfg, this->collectOnIORank_); } else #endif { - this->outputModule_ = std::make_unique> + this->outputModule_ = std::make_unique> (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 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& 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()) { @@ -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()) { 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(), - 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(), + // 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& outputModule() const + const OutputCompositionalModule& outputModule() const { return *outputModule_; } - OutputBlackOilModule& mutableOutputModule() const + OutputCompositionalModule& 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 > outputModule_; + // TODO: OutputCompositionalModule needs to be part of the TypeTag + std::unique_ptr > outputModule_; Scalar restartTimeStepSize_; int rank_ ; Inplace inplace_; diff --git a/opm/simulators/flow/FlowProblem.hpp b/opm/simulators/flow/FlowProblem.hpp index e96aa0b58..2e76f93b7 100644 --- a/opm/simulators/flow/FlowProblem.hpp +++ b/opm/simulators/flow/FlowProblem.hpp @@ -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 diff --git a/opm/simulators/flow/FlowProblemBlackoil.hpp b/opm/simulators/flow/FlowProblemBlackoil.hpp index e95994e0c..dd100c2e1 100644 --- a/opm/simulators/flow/FlowProblemBlackoil.hpp +++ b/opm/simulators/flow/FlowProblemBlackoil.hpp @@ -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); diff --git a/opm/simulators/flow/FlowProblemComp.hpp b/opm/simulators/flow/FlowProblemComp.hpp index 0b9cbe9a2..619985c5f 100644 --- a/opm/simulators/flow/FlowProblemComp.hpp +++ b/opm/simulators/flow/FlowProblemComp.hpp @@ -82,6 +82,7 @@ class FlowProblemComp : public FlowProblem using typename FlowProblemType::RateVector; using InitialFluidState = CompositionalFluidState; + using EclWriterType = EclWriter; public: using FlowProblemType::porosity; @@ -94,6 +95,8 @@ public: { FlowProblemType::registerParameters(); + EclWriterType::registerParameters(); + // tighter tolerance is needed for compositional modeling here Parameters::SetDefault>(1e-7); } @@ -105,6 +108,8 @@ public: explicit FlowProblemComp(Simulator& simulator) : FlowProblemType(simulator) { + eclWriter_ = std::make_unique(simulator); + enableEclOutput_ = Parameters::Get(); } /*! @@ -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 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>; + constexpr bool isCpGrid = std::is_same_v; + 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() || !isSubStep) { + eclWriter_->writeOutput(std::move(localCellData), isSubStep); + } + } + } + /*! * \copydoc FvBaseProblem::boundary * @@ -494,6 +567,9 @@ private: std::vector initialFluidStates_; + bool enableEclOutput_; + std::unique_ptr eclWriter_; + bool enableVtkOutput_; }; diff --git a/opm/simulators/flow/GenericOutputCompositionalModule.cpp b/opm/simulators/flow/GenericOutputCompositionalModule.cpp new file mode 100644 index 000000000..dc3a32440 --- /dev/null +++ b/opm/simulators/flow/GenericOutputCompositionalModule.cpp @@ -0,0 +1,1741 @@ +// -*- 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 . + 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. +*/ + +#include +#include + +#include + +#include +#include + +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +namespace { + +std::string EclString(const Opm::Inplace::Phase phase) +{ + switch (phase) { + case Opm::Inplace::Phase::WATER: + return "WIP"; + + case Opm::Inplace::Phase::OIL: + return "OIP"; + + case Opm::Inplace::Phase::GAS: + return "GIP"; + + case Opm::Inplace::Phase::OilInLiquidPhase: + return "OIPL"; + + case Opm::Inplace::Phase::OilInGasPhase: + return "OIPG"; + + case Opm::Inplace::Phase::GasInLiquidPhase: + return "GIPL"; + + case Opm::Inplace::Phase::GasInGasPhase: + return "GIPG"; + + case Opm::Inplace::Phase::PoreVolume: + return "RPV"; + + case Opm::Inplace::Phase::WaterResVolume: + return "WIPR"; + + case Opm::Inplace::Phase::OilResVolume: + return "OIPR"; + + case Opm::Inplace::Phase::GasResVolume: + return "GIPR"; + + case Opm::Inplace::Phase::SALT: + return "SIP"; + + case Opm::Inplace::Phase::CO2InWaterPhase: + return "WCD"; + + case Opm::Inplace::Phase::CO2InGasPhaseInMob: + return "GCDI"; + + case Opm::Inplace::Phase::CO2InGasPhaseMob: + return "GCDM"; + + case Opm::Inplace::Phase::CO2InGasPhaseInMobKrg: + return "GKDI"; + + case Opm::Inplace::Phase::CO2InGasPhaseMobKrg: + return "GKDM"; + + case Opm::Inplace::Phase::WaterInGasPhase: + return "WIPG"; + + case Opm::Inplace::Phase::WaterInWaterPhase: + return "WIPL"; + + case Opm::Inplace::Phase::CO2Mass: + return "GMIP"; + + case Opm::Inplace::Phase::CO2MassInWaterPhase: + return "GMDS"; + + case Opm::Inplace::Phase::CO2MassInGasPhase: + return "GMGP"; + + case Opm::Inplace::Phase::CO2MassInGasPhaseInMob: + return "GCDI_KG"; //Not used + + case Opm::Inplace::Phase::CO2MassInGasPhaseMob: + return "GKDM_KG"; //Not used + + case Opm::Inplace::Phase::CO2MassInGasPhaseInMobKrg: + return "GKTR"; + + case Opm::Inplace::Phase::CO2MassInGasPhaseMobKrg: + return "GKMO"; + + case Opm::Inplace::Phase::CO2MassInGasPhaseMaximumTrapped: + return "GMTR"; + + case Opm::Inplace::Phase::CO2MassInGasPhaseMaximumUnTrapped: + return "GMMO"; + + case Opm::Inplace::Phase::CO2MassInGasPhaseEffectiveTrapped: + return "GMST"; + + case Opm::Inplace::Phase::CO2MassInGasPhaseEffectiveUnTrapped: + return "GMUS"; + + default: + throw std::logic_error { + fmt::format("Phase enum with integer value: " + "{} not recognized", static_cast(phase)) + }; + } +} + + std::size_t numCells(const Opm::EclipseState& eclState) + { + return eclState.fieldProps().get_int("FIPNUM").size(); + } + + std::vector + defineInterRegionFlowArrays(const Opm::EclipseState& eclState, + const Opm::SummaryConfig& summaryConfig) + { + auto regions = std::vector{}; + + const auto& fprops = eclState.fieldProps(); + for (const auto& arrayName : summaryConfig.fip_regions_interreg_flow()) { + regions.push_back({ arrayName, std::cref(fprops.get_int(arrayName)) }); + } + + return regions; + } +} + +namespace Opm { + +template +GenericOutputCompositionalModule:: +GenericOutputCompositionalModule(const EclipseState& eclState, + const Schedule& schedule, + const SummaryConfig& summaryConfig, + const SummaryState& summaryState, + const std::string& moduleVersion, + bool enableEnergy, + bool enableTemperature, + bool enableMech, + bool enableSolvent, + bool enablePolymer, + bool enableFoam, + bool enableBrine, + bool enableSaltPrecipitation, + bool enableExtbo, + bool enableMICP) + : eclState_(eclState) + , schedule_(schedule) + , summaryState_(summaryState) + , summaryConfig_(summaryConfig) + , interRegionFlows_(numCells(eclState), + defineInterRegionFlowArrays(eclState, summaryConfig), + declaredMaxRegionID(eclState.runspec())) + , logOutput_(eclState, schedule, summaryState, moduleVersion) + , enableEnergy_(enableEnergy) + , enableTemperature_(enableTemperature) + , enableMech_(enableMech) + , enableSolvent_(enableSolvent) + , enablePolymer_(enablePolymer) + , enableFoam_(enableFoam) + , enableBrine_(enableBrine) + , enableSaltPrecipitation_(enableSaltPrecipitation) + , enableExtbo_(enableExtbo) + , enableMICP_(enableMICP) + , local_data_valid_(false) +{ + const auto& fp = eclState_.fieldProps(); + + this->regions_["FIPNUM"] = fp.get_int("FIPNUM"); + for (const auto& region : fp.fip_regions()) { + this->regions_[region] = fp.get_int(region); + } + + this->RPRNodes_ = summaryConfig_.keywords("RPR*"); + this->RPRPNodes_ = summaryConfig_.keywords("RPRP*"); + + for (const auto& phase : Inplace::phases()) { + std::string key_pattern = "R" + EclString(phase) + "*"; + this->regionNodes_[phase] = summaryConfig_.keywords(key_pattern); + } + + // Check for any BFLOW[I|J|K] summary keys + blockFlows_ = summaryConfig_.keywords("BFLOW*").size() > 0; + + // Check if FLORES/FLOWS is set in any RPTRST in the schedule + anyFlores_ = false; // Used for the initialization of the sparse table + anyFlows_ = blockFlows_; + enableFlores_ = false; // Used for the output of i+, j+, k+ + enableFloresn_ = false; // Used for the special case of nnc + enableFlows_ = false; + enableFlowsn_ = false; + + for (const auto& block : this->schedule_) { + const auto& rstkw = block.rst_config().keywords; + + if (! anyFlores_) { + anyFlores_ = rstkw.find("FLORES") != rstkw.end(); + } + + if (! anyFlows_) { + anyFlows_ = rstkw.find("FLOWS") != rstkw.end(); + } + + if (anyFlores_ && anyFlows_) { + // Terminate report step loop early if both FLORES and FLOWS + // have been set at some point as there's no need to search + // any further in that case. + break; + } + } +} + +template +GenericOutputCompositionalModule:: +~GenericOutputCompositionalModule() = default; + +template +void GenericOutputCompositionalModule:: +outputTimeStamp(const std::string& lbl, + const double elapsed, + const int rstep, + const boost::posix_time::ptime currentDate) +{ + logOutput_.timeStamp(lbl, elapsed, rstep, currentDate); +} + +template +void GenericOutputCompositionalModule:: +prepareDensityAccumulation() +{ + if (this->regionAvgDensity_.has_value()) { + this->regionAvgDensity_->prepareAccumulation(); + } +} + +template +void GenericOutputCompositionalModule:: +accumulateDensityParallel() +{ + if (this->regionAvgDensity_.has_value()) { + this->regionAvgDensity_->accumulateParallel(); + } +} + +template +void GenericOutputCompositionalModule:: +outputCumLog(std::size_t reportStepNum) +{ + this->logOutput_.cumulative(reportStepNum); +} + +template +void GenericOutputCompositionalModule:: +outputProdLog(std::size_t reportStepNum) +{ + this->logOutput_.production(reportStepNum); +} + +template +void GenericOutputCompositionalModule:: +outputInjLog(std::size_t reportStepNum) +{ + this->logOutput_.injection(reportStepNum); +} + +template +Inplace GenericOutputCompositionalModule:: +calc_inplace(std::map& miscSummaryData, + std::map>& regionData, + const Parallel::Communication& comm) +{ + auto inplace = this->accumulateRegionSums(comm); + + if (comm.rank() != 0) + return inplace; + + updateSummaryRegionValues(inplace, + miscSummaryData, + regionData); + + + return inplace; +} + +template +void GenericOutputCompositionalModule:: +outputFipAndResvLog(const Inplace& inplace, + const std::size_t reportStepNum, + double elapsed, + boost::posix_time::ptime currentDate, + const bool substep, + const Parallel::Communication& comm) +{ + if (comm.rank() != 0) + return; + + + // For report step 0 we use the RPTSOL config, else derive from RPTSCHED + std::unique_ptr fipSched; + if (reportStepNum > 0) { + const auto& rpt = this->schedule_[reportStepNum-1].rpt_config.get(); + fipSched = std::make_unique(rpt); + } + const FIPConfig& fipc = reportStepNum == 0 ? this->eclState_.getEclipseConfig().fip() + : *fipSched; + + if (!substep && !forceDisableFipOutput_ && fipc.output(FIPConfig::OutputField::FIELD)) { + + logOutput_.timeStamp("BALANCE", elapsed, reportStepNum, currentDate); + + logOutput_.fip(inplace, this->initialInplace(), ""); + + if (fipc.output(FIPConfig::OutputField::FIPNUM)) { + logOutput_.fip(inplace, this->initialInplace(), "FIPNUM"); + + if (fipc.output(FIPConfig::OutputField::RESV)) + logOutput_.fipResv(inplace, "FIPNUM"); + } + + if (fipc.output(FIPConfig::OutputField::FIP)) { + for (const auto& reg : this->regions_) { + if (reg.first != "FIPNUM") { + std::ostringstream ss; + ss << "BAL" << reg.first.substr(3); + logOutput_.timeStamp(ss.str(), elapsed, reportStepNum, currentDate); + logOutput_.fip(inplace, this->initialInplace(), reg.first); + + if (fipc.output(FIPConfig::OutputField::RESV)) + logOutput_.fipResv(inplace, reg.first); + } + } + } + } +} + +template +void GenericOutputCompositionalModule:: +addRftDataToWells(data::Wells& wellDatas, std::size_t reportStepNum) +{ + const auto& rft_config = schedule_[reportStepNum].rft_config(); + for (const auto& well: schedule_.getWells(reportStepNum)) { + + // don't bother with wells not on this process + if (isDefunctParallelWell(well.name())) { + continue; + } + + //add data infrastructure for shut wells + if (!wellDatas.count(well.name())) { + data::Well wellData; + + if (!rft_config.active()) + continue; + + wellData.connections.resize(well.getConnections().size()); + std::size_t count = 0; + for (const auto& connection: well.getConnections()) { + const std::size_t i = std::size_t(connection.getI()); + const std::size_t j = std::size_t(connection.getJ()); + const std::size_t k = std::size_t(connection.getK()); + + const std::size_t index = eclState_.gridDims().getGlobalIndex(i, j, k); + auto& connectionData = wellData.connections[count]; + connectionData.index = index; + count++; + } + wellDatas.emplace(std::make_pair(well.name(), wellData)); + } + + data::Well& wellData = wellDatas.at(well.name()); + for (auto& connectionData: wellData.connections) { + const auto index = connectionData.index; + if (oilConnectionPressures_.count(index) > 0) + connectionData.cell_pressure = oilConnectionPressures_.at(index); + if (waterConnectionSaturations_.count(index) > 0) + connectionData.cell_saturation_water = waterConnectionSaturations_.at(index); + if (gasConnectionSaturations_.count(index) > 0) + connectionData.cell_saturation_gas = gasConnectionSaturations_.at(index); + } + } + oilConnectionPressures_.clear(); + waterConnectionSaturations_.clear(); + gasConnectionSaturations_.clear(); +} + +template +void GenericOutputCompositionalModule:: +assignToSolution(data::Solution& sol) +{ + using DataEntry = + std::tuple&>; + + auto doInsert = [&sol](const DataEntry& entry, + const data::TargetType target) + { + if (std::get<2>(entry).empty()) { + return; + } + + sol.insert(std::get(entry), + std::get(entry), + std::move(std::get<2>(entry)), + target); + }; + + const auto baseSolutionArrays = std::array { + DataEntry{"1OVERBG", UnitSystem::measure::gas_inverse_formation_volume_factor, invB_[gasPhaseIdx]}, + DataEntry{"1OVERBO", UnitSystem::measure::oil_inverse_formation_volume_factor, invB_[oilPhaseIdx]}, + DataEntry{"1OVERBW", UnitSystem::measure::water_inverse_formation_volume_factor, invB_[waterPhaseIdx]}, + DataEntry{"FLRGASI+", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::XPlus)][gasCompIdx]}, + DataEntry{"FLRGASJ+", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::YPlus)][gasCompIdx]}, + DataEntry{"FLRGASK+", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::ZPlus)][gasCompIdx]}, + DataEntry{"FLROILI+", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::XPlus)][oilCompIdx]}, + DataEntry{"FLROILJ+", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::YPlus)][oilCompIdx]}, + DataEntry{"FLROILK+", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::ZPlus)][oilCompIdx]}, + DataEntry{"FLRWATI+", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::XPlus)][waterCompIdx]}, + DataEntry{"FLRWATJ+", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::YPlus)][waterCompIdx]}, + DataEntry{"FLRWATK+", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::ZPlus)][waterCompIdx]}, + DataEntry{"FOAM", UnitSystem::measure::identity, cFoam_}, + DataEntry{"GASKR", UnitSystem::measure::identity, relativePermeability_[gasPhaseIdx]}, + DataEntry{"GAS_DEN", UnitSystem::measure::density, density_[gasPhaseIdx]}, + DataEntry{"GAS_VISC", UnitSystem::measure::viscosity, viscosity_[gasPhaseIdx]}, + DataEntry{"OILKR", UnitSystem::measure::identity, relativePermeability_[oilPhaseIdx]}, + DataEntry{"OIL_DEN", UnitSystem::measure::density, density_[oilPhaseIdx]}, + DataEntry{"OIL_VISC", UnitSystem::measure::viscosity, viscosity_[oilPhaseIdx]}, + DataEntry{"PBUB", UnitSystem::measure::pressure, bubblePointPressure_}, + DataEntry{"PCGW", UnitSystem::measure::pressure, pcgw_}, + DataEntry{"PCOG", UnitSystem::measure::pressure, pcog_}, + DataEntry{"PCOW", UnitSystem::measure::pressure, pcow_}, + DataEntry{"PDEW", UnitSystem::measure::pressure, dewPointPressure_}, + DataEntry{"POLYMER", UnitSystem::measure::identity, cPolymer_}, + DataEntry{"PPCW", UnitSystem::measure::pressure, ppcw_}, + DataEntry{"PRESROCC", UnitSystem::measure::pressure, minimumOilPressure_}, + DataEntry{"PRESSURE", UnitSystem::measure::pressure, fluidPressure_}, + DataEntry{"RPORV", UnitSystem::measure::volume, rPorV_}, + DataEntry{"RS", UnitSystem::measure::gas_oil_ratio, rs_}, + DataEntry{"RSSAT", UnitSystem::measure::gas_oil_ratio, gasDissolutionFactor_}, + DataEntry{"RV", UnitSystem::measure::oil_gas_ratio, rv_}, + DataEntry{"RVSAT", UnitSystem::measure::oil_gas_ratio, oilVaporizationFactor_}, + DataEntry{"SALT", UnitSystem::measure::salinity, cSalt_}, + DataEntry{"SGMAX", UnitSystem::measure::identity, sgmax_}, + DataEntry{"SHMAX", UnitSystem::measure::identity, shmax_}, + DataEntry{"SOMAX", UnitSystem::measure::identity, soMax_}, + DataEntry{"SOMIN", UnitSystem::measure::identity, somin_}, + DataEntry{"SSOLVENT", UnitSystem::measure::identity, sSol_}, + DataEntry{"SWHY1", UnitSystem::measure::identity, swmin_}, + DataEntry{"SWMAX", UnitSystem::measure::identity, swMax_}, + DataEntry{"WATKR", UnitSystem::measure::identity, relativePermeability_[waterPhaseIdx]}, + DataEntry{"WAT_DEN", UnitSystem::measure::density, density_[waterPhaseIdx]}, + DataEntry{"WAT_VISC", UnitSystem::measure::viscosity, viscosity_[waterPhaseIdx]}, + }; + + // Separate these as flows*_ may be defined due to BFLOW[I|J|K] even without FLOWS in RPTRST + const auto flowsSolutionArrays = std::array { + DataEntry{"FLOGASI+", UnitSystem::measure::gas_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::XPlus)][gasCompIdx]}, + DataEntry{"FLOGASJ+", UnitSystem::measure::gas_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::YPlus)][gasCompIdx]}, + DataEntry{"FLOGASK+", UnitSystem::measure::gas_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::ZPlus)][gasCompIdx]}, + DataEntry{"FLOOILI+", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::XPlus)][oilCompIdx]}, + DataEntry{"FLOOILJ+", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::YPlus)][oilCompIdx]}, + DataEntry{"FLOOILK+", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::ZPlus)][oilCompIdx]}, + DataEntry{"FLOWATI+", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::XPlus)][waterCompIdx]}, + DataEntry{"FLOWATJ+", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::YPlus)][waterCompIdx]}, + DataEntry{"FLOWATK+", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::ZPlus)][waterCompIdx]}, + DataEntry{"FLOGASI-", UnitSystem::measure::gas_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::XMinus)][gasCompIdx]}, + DataEntry{"FLOGASJ-", UnitSystem::measure::gas_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::YMinus)][gasCompIdx]}, + DataEntry{"FLOGASK-", UnitSystem::measure::gas_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::ZMinus)][gasCompIdx]}, + DataEntry{"FLOOILI-", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::XMinus)][oilCompIdx]}, + DataEntry{"FLOOILJ-", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::YMinus)][oilCompIdx]}, + DataEntry{"FLOOILK-", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::ZMinus)][oilCompIdx]}, + DataEntry{"FLOWATI-", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::XMinus)][waterCompIdx]}, + DataEntry{"FLOWATJ-", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::YMinus)][waterCompIdx]}, + DataEntry{"FLOWATK-", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::ZMinus)][waterCompIdx]}, + DataEntry{"FLRGASI-", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::XMinus)][gasCompIdx]}, + DataEntry{"FLRGASJ-", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::YMinus)][gasCompIdx]}, + DataEntry{"FLRGASK-", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::ZMinus)][gasCompIdx]}, + DataEntry{"FLROILI-", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::XMinus)][oilCompIdx]}, + DataEntry{"FLROILJ-", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::YMinus)][oilCompIdx]}, + DataEntry{"FLROILK-", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::ZMinus)][oilCompIdx]}, + DataEntry{"FLRWATI-", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::XMinus)][waterCompIdx]}, + DataEntry{"FLRWATJ-", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::YMinus)][waterCompIdx]}, + DataEntry{"FLRWATK-", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::ZMinus)][waterCompIdx]}, + }; + + const auto extendedSolutionArrays = std::array { + DataEntry{"BIOFILM", UnitSystem::measure::identity, cBiofilm_}, + DataEntry{"CALCITE", UnitSystem::measure::identity, cCalcite_}, + DataEntry{"DELSTRXX", UnitSystem::measure::pressure, delstressXX_}, + DataEntry{"DELSTRYY", UnitSystem::measure::pressure, delstressYY_}, + DataEntry{"DELSTRZZ", UnitSystem::measure::pressure, delstressZZ_}, + DataEntry{"DELSTRXY", UnitSystem::measure::pressure, delstressXY_}, + DataEntry{"DELSTRXZ", UnitSystem::measure::pressure, delstressXZ_}, + DataEntry{"DELSTRYZ", UnitSystem::measure::pressure, delstressYZ_}, + DataEntry{"DISPX", UnitSystem::measure::length, dispX_}, + DataEntry{"DISPY", UnitSystem::measure::length, dispY_}, + DataEntry{"DISPZ", UnitSystem::measure::length, dispZ_}, + DataEntry{"DRSDTCON", UnitSystem::measure::gas_oil_ratio_rate, drsdtcon_}, + DataEntry{"MECHPOTF", UnitSystem::measure::pressure, mechPotentialForce_}, + DataEntry{"MICROBES", UnitSystem::measure::density, cMicrobes_}, + DataEntry{"OXYGEN", UnitSystem::measure::density, cOxygen_}, + DataEntry{"PERMFACT", UnitSystem::measure::identity, permFact_}, + DataEntry{"PORV_RC", UnitSystem::measure::identity, rockCompPorvMultiplier_}, + DataEntry{"PRESPOTF", UnitSystem::measure::pressure, mechPotentialPressForce_}, + DataEntry{"PRES_OVB", UnitSystem::measure::pressure, overburdenPressure_}, + DataEntry{"RSW", UnitSystem::measure::gas_oil_ratio, rsw_}, + DataEntry{"RSWSAT", UnitSystem::measure::gas_oil_ratio, gasDissolutionFactorInWater_}, + DataEntry{"RSWSOL", UnitSystem::measure::gas_oil_ratio, rswSol_}, + DataEntry{"RVW", UnitSystem::measure::oil_gas_ratio, rvw_}, + DataEntry{"RVWSAT", UnitSystem::measure::oil_gas_ratio, waterVaporizationFactor_}, + DataEntry{"SALTP", UnitSystem::measure::identity, pSalt_}, + DataEntry{"SS_X", UnitSystem::measure::identity, extboX_}, + DataEntry{"SS_Y", UnitSystem::measure::identity, extboY_}, + DataEntry{"SS_Z", UnitSystem::measure::identity, extboZ_}, + DataEntry{"STD_CO2", UnitSystem::measure::identity, mFracCo2_}, + DataEntry{"STD_GAS", UnitSystem::measure::identity, mFracGas_}, + DataEntry{"STD_OIL", UnitSystem::measure::identity, mFracOil_}, + DataEntry{"STRAINXX", UnitSystem::measure::identity, strainXX_}, + DataEntry{"STRAINYY", UnitSystem::measure::identity, strainYY_}, + DataEntry{"STRAINZZ", UnitSystem::measure::identity, strainZZ_}, + DataEntry{"STRAINXY", UnitSystem::measure::identity, strainXY_}, + DataEntry{"STRAINXZ", UnitSystem::measure::identity, strainXZ_}, + DataEntry{"STRAINYZ", UnitSystem::measure::identity, strainYZ_}, + DataEntry{"STRESSXX", UnitSystem::measure::length, stressXX_}, + DataEntry{"STRESSYY", UnitSystem::measure::length, stressYY_}, + DataEntry{"STRESSZZ", UnitSystem::measure::length, stressZZ_}, + DataEntry{"STRESSXY", UnitSystem::measure::length, stressXY_}, + DataEntry{"STRESSXZ", UnitSystem::measure::length, stressXZ_}, + DataEntry{"STRESSYZ", UnitSystem::measure::length, stressYZ_}, + DataEntry{"TEMPPOTF", UnitSystem::measure::pressure, mechPotentialTempForce_}, + DataEntry{"TMULT_RC", UnitSystem::measure::identity, rockCompTransMultiplier_}, + DataEntry{"UREA", UnitSystem::measure::density, cUrea_}, + }; + + // basically, for compositional, we can not use std::array for this. We need to generate the ZMF1, ZMF2, and so on + // and also, we need to map these values. + + for (const auto& array : baseSolutionArrays) { + doInsert(array, data::TargetType::RESTART_SOLUTION); + } + + if (this->enableFlows_) { + for (const auto& array : flowsSolutionArrays) { + doInsert(array, data::TargetType::RESTART_SOLUTION); + } + } + + for (const auto& array : extendedSolutionArrays) { + doInsert(array, data::TargetType::RESTART_OPM_EXTENDED); + } + + if (! this->temperature_.empty()) + { + sol.insert("TEMP", UnitSystem::measure::temperature, + std::move(this->temperature_), data::TargetType::RESTART_SOLUTION); + } + + if (FluidSystem::phaseIsActive(waterPhaseIdx) && + ! this->saturation_[waterPhaseIdx].empty()) + { + sol.insert("SWAT", UnitSystem::measure::identity, + std::move(this->saturation_[waterPhaseIdx]), + data::TargetType::RESTART_SOLUTION); + } + + if (FluidSystem::phaseIsActive(gasPhaseIdx) && + ! this->saturation_[gasPhaseIdx].empty()) + { + sol.insert("SGAS", UnitSystem::measure::identity, + std::move(this->saturation_[gasPhaseIdx]), + data::TargetType::RESTART_SOLUTION); + } + + if (FluidSystem::phaseIsActive(oilPhaseIdx) && + ! this->saturation_[oilPhaseIdx].empty()) + { + sol.insert("SOIL", UnitSystem::measure::identity, + std::move(this->saturation_[oilPhaseIdx]), + data::TargetType::RESTART_SOLUTION); + } + + /* if ((eclState_.runspec().co2Storage() || eclState_.runspec().h2Storage()) && !rsw_.empty()) { + auto mfrac = std::vector(this->rsw_.size(), 0.0); + + std::transform(this->rsw_.begin(), this->rsw_.end(), + this->eclState_.fieldProps().get_int("PVTNUM").begin(), + mfrac.begin(), + [](const auto& rsw, const int pvtReg) + { + const auto xwg = FluidSystem::convertRswToXwG(rsw, pvtReg - 1); + return FluidSystem::convertXwGToxwG(xwg, pvtReg - 1); + }); + + std::string moleFracName = eclState_.runspec().co2Storage() ? "XMFCO2" : "XMFH2"; + sol.insert(moleFracName, + UnitSystem::measure::identity, + std::move(mfrac), + data::TargetType::RESTART_OPM_EXTENDED); + } + + if ((eclState_.runspec().co2Storage() || eclState_.runspec().h2Storage()) && !rvw_.empty()) { + auto mfrac = std::vector(this->rvw_.size(), 0.0); + + std::transform(this->rvw_.begin(), this->rvw_.end(), + this->eclState_.fieldProps().get_int("PVTNUM").begin(), + mfrac.begin(), + [](const auto& rvw, const int pvtReg) + { + const auto xgw = FluidSystem::convertRvwToXgW(rvw, pvtReg - 1); + return FluidSystem::convertXgWToxgW(xgw, pvtReg - 1); + }); + + sol.insert("YMFWAT", + UnitSystem::measure::identity, + std::move(mfrac), + data::TargetType::RESTART_OPM_EXTENDED); + } */ + + if (FluidSystem::phaseIsActive(waterPhaseIdx) && + ! this->residual_[waterPhaseIdx].empty()) + { + sol.insert("RES_WAT", UnitSystem::measure::liquid_surface_volume, + std::move(this->residual_[waterPhaseIdx]), + data::TargetType::RESTART_OPM_EXTENDED); + } + if (FluidSystem::phaseIsActive(gasPhaseIdx) && + ! this->residual_[gasPhaseIdx].empty()) + { + sol.insert("RES_GAS", UnitSystem::measure::gas_surface_volume, + std::move(this->residual_[gasPhaseIdx]), + data::TargetType::RESTART_OPM_EXTENDED); + } + if (FluidSystem::phaseIsActive(oilPhaseIdx) && + ! this->residual_[oilPhaseIdx].empty()) + { + sol.insert("RES_OIL", UnitSystem::measure::liquid_surface_volume, + std::move(this->residual_[oilPhaseIdx]), + data::TargetType::RESTART_OPM_EXTENDED); + } + + // Fluid in place + if (this->outputFipRestart_) { + using namespace std::string_literals; + + using M = UnitSystem::measure; + using FIPEntry = std::tuple; + + auto fipArrays = std::vector {}; + if (this->outputFipRestart_.surface) { + fipArrays.insert(fipArrays.end(), { + FIPEntry {"SFIPOIL"s, M::liquid_surface_volume, Inplace::Phase::OIL }, + FIPEntry {"SFIPWAT"s, M::liquid_surface_volume, Inplace::Phase::WATER }, + FIPEntry {"SFIPGAS"s, M::gas_surface_volume, Inplace::Phase::GAS }, + }); + } + + if (this->outputFipRestart_.reservoir) { + fipArrays.insert(fipArrays.end(), { + FIPEntry {"RFIPOIL"s, M::volume, Inplace::Phase::OilResVolume }, + FIPEntry {"RFIPWAT"s, M::volume, Inplace::Phase::WaterResVolume }, + FIPEntry {"RFIPGAS"s, M::volume, Inplace::Phase::GasResVolume }, + }); + } + + if (this->outputFipRestart_.noPrefix && !this->outputFipRestart_.surface) { + fipArrays.insert(fipArrays.end(), { + FIPEntry { "FIPOIL"s, M::liquid_surface_volume, Inplace::Phase::OIL }, + FIPEntry { "FIPWAT"s, M::liquid_surface_volume, Inplace::Phase::WATER }, + FIPEntry { "FIPGAS"s, M::gas_surface_volume, Inplace::Phase::GAS }, + }); + } + + for (const auto& [mnemonic, unit, phase] : fipArrays) { + if (! this->fip_[phase].empty()) { + sol.insert(mnemonic, unit, std::move(this->fip_[phase]), + data::TargetType::RESTART_SOLUTION); + } + } + + for (const auto& phase : Inplace::mixingPhases()) { + if (! this->fip_[phase].empty()) { + sol.insert(EclString(phase), + UnitSystem::measure::volume, + this->fip_[phase], + data::TargetType::SUMMARY); + } + } + } + + // Tracers + if (! this->freeTracerConcentrations_.empty()) { + const auto& tracers = this->eclState_.tracer(); + for (auto tracerIdx = 0*tracers.size(); + tracerIdx < tracers.size(); ++tracerIdx) + { + sol.insert(tracers[tracerIdx].fname(), + UnitSystem::measure::identity, + std::move(freeTracerConcentrations_[tracerIdx]), + data::TargetType::RESTART_TRACER_SOLUTION); + } + + // Put freeTracerConcentrations container into a valid state. Otherwise + // we'll move from vectors that have already been moved from if we + // get here and it's not a restart step. + this->freeTracerConcentrations_.clear(); + } + if (! this->solTracerConcentrations_.empty()) { + const auto& tracers = this->eclState_.tracer(); + for (auto tracerIdx = 0*tracers.size(); + tracerIdx < tracers.size(); ++tracerIdx) + { + if (solTracerConcentrations_[tracerIdx].empty()) + continue; + + sol.insert(tracers[tracerIdx].sname(), + UnitSystem::measure::identity, + std::move(solTracerConcentrations_[tracerIdx]), + data::TargetType::RESTART_TRACER_SOLUTION); + } + + // Put solTracerConcentrations container into a valid state. Otherwise + // we'll move from vectors that have already been moved from if we + // get here and it's not a restart step. + this->solTracerConcentrations_.clear(); + } +} + +template +void GenericOutputCompositionalModule:: +setRestart(const data::Solution& sol, + unsigned elemIdx, + unsigned globalDofIndex) +{ + Scalar so = 1.0; + if (!saturation_[waterPhaseIdx].empty() && sol.has("SWAT")) { + saturation_[waterPhaseIdx][elemIdx] = sol.data("SWAT")[globalDofIndex]; + so -= sol.data("SWAT")[globalDofIndex]; + } + if (!saturation_[gasPhaseIdx].empty() && sol.has("SGAS")) { + saturation_[gasPhaseIdx][elemIdx] = sol.data("SGAS")[globalDofIndex]; + so -= sol.data("SGAS")[globalDofIndex]; + } + + if (!sSol_.empty()) { + // keep the SSOL option for backward compatibility + // should be removed after 10.2018 release + if (sol.has("SSOL")) + sSol_[elemIdx] = sol.data("SSOL")[globalDofIndex]; + else if (sol.has("SSOLVENT")) + sSol_[elemIdx] = sol.data("SSOLVENT")[globalDofIndex]; + + so -= sSol_[elemIdx]; + } + + if (!rswSol_.empty()) { + if (sol.has("RSWSOL")) + rswSol_[elemIdx] = sol.data("RSWSOL")[globalDofIndex]; + + } + + assert(!saturation_[oilPhaseIdx].empty()); + saturation_[oilPhaseIdx][elemIdx] = so; + + auto assign = [elemIdx, globalDofIndex, &sol](const std::string& name, + ScalarBuffer& data) + + { + if (!data.empty() && sol.has(name)) { + data[elemIdx] = sol.data(name)[globalDofIndex]; + } + }; + + const auto fields = std::array{ + std::pair{"BIOFILM", &cBiofilm_}, + std::pair{"CALCITE", &cCalcite_}, + std::pair{"FOAM", &cFoam_}, + std::pair{"MICROBES", &cMicrobes_}, + std::pair{"OXYGEN", &cOxygen_}, + std::pair{"PERMFACT", &permFact_}, + std::pair{"POLYMER", &cPolymer_}, + std::pair{"PPCW", &ppcw_}, + std::pair{"PRESSURE", &fluidPressure_}, + std::pair{"RS", &rs_}, + std::pair{"RSW", &rsw_}, + std::pair{"RV", &rv_}, + std::pair{"RVW", &rvw_}, + std::pair{"SALT", &cSalt_}, + std::pair{"SALTP", &pSalt_}, + std::pair{"SGMAX", &sgmax_}, + std::pair{"SHMAX", &shmax_}, + std::pair{"SOMAX", &soMax_}, + std::pair{"SOMIN", &somin_}, + std::pair{"SWHY1", &swmin_}, + std::pair{"SWMAX", &swMax_}, + std::pair{"TEMP", &temperature_}, + std::pair{"UREA", &cUrea_}, + }; + + std::for_each(fields.begin(), fields.end(), + [&assign](const auto& p) + { assign(p.first, *p.second); }); +} + +template +typename GenericOutputCompositionalModule::ScalarBuffer +GenericOutputCompositionalModule:: +regionSum(const ScalarBuffer& property, + const std::vector& regionId, + std::size_t maxNumberOfRegions, + const Parallel::Communication& comm) +{ + ScalarBuffer totals(maxNumberOfRegions, 0.0); + + if (property.empty()) + return totals; + + // the regionId contains the ghost cells + // the property does not contain the ghostcells + // This code assumes that that the ghostcells are + // added after the interior cells + // OwnerCellsFirst = True + assert(regionId.size() >= property.size()); + for (std::size_t j = 0; j < property.size(); ++j) { + const int regionIdx = regionId[j] - 1; + // the cell is not attributed to any region. ignore it! + if (regionIdx < 0) + continue; + + assert(regionIdx < static_cast(maxNumberOfRegions)); + totals[regionIdx] += property[j]; + } + + for (std::size_t i = 0; i < maxNumberOfRegions; ++i) + totals[i] = comm.sum(totals[i]); + + return totals; + } + +template +void GenericOutputCompositionalModule:: +doAllocBuffers(const unsigned bufferSize, + const unsigned reportStepNum, + const bool substep, + const bool log, + const bool isRestart, + const bool vapparsActive, + const bool enablePCHysteresis, + const bool enableNonWettingHysteresis, + const bool enableWettingHysteresis, + const unsigned numTracers, + const std::vector& enableSolTracers, + const unsigned numOutputNnc) +{ + // Output RESTART_OPM_EXTENDED only when explicitly requested by user. + std::map rstKeywords = schedule_.rst_keywords(reportStepNum); + for (auto& [keyword, should_write] : rstKeywords) { + if (this->isOutputCreationDirective_(keyword)) { + // 'BASIC', 'FREQ' and similar. Don't attempt to create + // cell-based output for these keywords and don't warn about + // not being able to create such cell-based result vectors. + should_write = 0; + } + } + + if (auto& norst = rstKeywords["NORST"]; norst > 0) { + // Don't emit diagnostic messages about unsupported 'NORST' key. + norst = 0; + } + + // Fluid in place + { + using namespace std::string_literals; + + const auto fipctrl = std::array { + std::pair { "FIP"s , &OutputFIPRestart::noPrefix }, + std::pair { "SFIP"s, &OutputFIPRestart::surface }, + std::pair { "RFIP"s, &OutputFIPRestart::reservoir }, + }; + + this->outputFipRestart_.clearBits(); + this->computeFip_ = false; + + for (const auto& [mnemonic, kind] : fipctrl) { + if (auto fipPos = rstKeywords.find(mnemonic); + fipPos != rstKeywords.end()) + { + fipPos->second = 0; + this->outputFipRestart_.*kind = true; + } + } + + for (const auto& phase : Inplace::phases()) { + if (!substep || summaryConfig_.require3DField(EclString(phase))) { + this->fip_[phase].resize(bufferSize, 0.0); + this->computeFip_ = true; + } + else { + this->fip_[phase].clear(); + } + } + } + + const auto needAvgPress = !substep || + !this->RPRNodes_.empty() || + this->summaryConfig_.hasKeyword("FPR") || + this->summaryConfig_.hasKeyword("FPRP"); + + const auto needPoreVolume = needAvgPress || + this->summaryConfig_.hasKeyword("FHPV") || + this->summaryConfig_.match("RHPV*"); + + if (needPoreVolume) { + this->fip_[Inplace::Phase::PoreVolume].resize(bufferSize, 0.0); + this->dynamicPoreVolume_.resize(bufferSize, 0.0); + this->hydrocarbonPoreVolume_.resize(bufferSize, 0.0); + } + else { + this->dynamicPoreVolume_.clear(); + this->hydrocarbonPoreVolume_.clear(); + } + + if (needAvgPress) { + this->pressureTimesPoreVolume_.resize(bufferSize, 0.0); + this->pressureTimesHydrocarbonVolume_.resize(bufferSize, 0.0); + } + else { + this->pressureTimesPoreVolume_.clear(); + this->pressureTimesHydrocarbonVolume_.clear(); + } + + // Well RFT data + if (!substep) { + const auto& rft_config = schedule_[reportStepNum].rft_config(); + for (const auto& well: schedule_.getWells(reportStepNum)) { + + // don't bother with wells not on this process + if (isDefunctParallelWell(well.name())) { + continue; + } + + if (!rft_config.active()) + continue; + + for (const auto& connection: well.getConnections()) { + const std::size_t i = std::size_t(connection.getI()); + const std::size_t j = std::size_t(connection.getJ()); + const std::size_t k = std::size_t(connection.getK()); + const std::size_t index = eclState_.gridDims().getGlobalIndex(i, j, k); + + if (FluidSystem::phaseIsActive(oilPhaseIdx)) + oilConnectionPressures_.emplace(std::make_pair(index, 0.0)); + + if (FluidSystem::phaseIsActive(waterPhaseIdx)) + waterConnectionSaturations_.emplace(std::make_pair(index, 0.0)); + + if (FluidSystem::phaseIsActive(gasPhaseIdx)) + gasConnectionSaturations_.emplace(std::make_pair(index, 0.0)); + } + } + } + + // Flows may need to be allocated even when there is no restart due to BFLOW* summary keywords + if (blockFlows_ ) { + const std::array phaseIdxs = { gasPhaseIdx, oilPhaseIdx, waterPhaseIdx }; + const std::array compIdxs = { gasCompIdx, oilCompIdx, waterCompIdx }; + + for (unsigned ii = 0; ii < phaseIdxs.size(); ++ii) { + if (FluidSystem::phaseIsActive(phaseIdxs[ii])) { + flows_[FaceDir::ToIntersectionIndex(Dir::XPlus)][compIdxs[ii]].resize(bufferSize, 0.0); + flows_[FaceDir::ToIntersectionIndex(Dir::YPlus)][compIdxs[ii]].resize(bufferSize, 0.0); + flows_[FaceDir::ToIntersectionIndex(Dir::ZPlus)][compIdxs[ii]].resize(bufferSize, 0.0); + } + } + } + + // Field data should be allocated + // 1) When we want to restart + // 2) When it is ask for by the user via restartConfig + // 3) When it is not a substep + if (!isRestart && (!schedule_.write_rst_file(reportStepNum) || substep)) { + return; + } + + // Always output saturation of active phases + for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { + if (! FluidSystem::phaseIsActive(phaseIdx)) { + continue; + } + + this->saturation_[phaseIdx].resize(bufferSize, 0.0); + } + + // And oil pressure + fluidPressure_.resize(bufferSize, 0.0); + rstKeywords["PRES"] = 0; + rstKeywords["PRESSURE"] = 0; + + if (enableMech_ && eclState_.runspec().mech()) { + this->mechPotentialForce_.resize(bufferSize,0.0); + rstKeywords["MECHPOTF"] = 0; + this->mechPotentialTempForce_.resize(bufferSize,0.0); + rstKeywords["TEMPPOTF"] = 0; + this->mechPotentialPressForce_.resize(bufferSize,0.0); + rstKeywords["PRESPOTF"] = 0; + + this->dispX_.resize(bufferSize,0.0); + rstKeywords["DISPX"] = 0; + this->dispY_.resize(bufferSize,0.0); + rstKeywords["DISPY"] = 0; + this->dispZ_.resize(bufferSize,0.0); + rstKeywords["DISPZ"] = 0; + this->stressXX_.resize(bufferSize,0.0); + rstKeywords["STRESSXX"] = 0; + this->stressYY_.resize(bufferSize,0.0); + rstKeywords["STRESSYY"] = 0; + this->stressZZ_.resize(bufferSize,0.0); + rstKeywords["STRESSZZ"] = 0; + this->stressXY_.resize(bufferSize,0.0); + rstKeywords["STRESSXY"] = 0; + this->stressXZ_.resize(bufferSize,0.0); + rstKeywords["STRESSXZ"] = 0; + this->stressXY_.resize(bufferSize,0.0); + rstKeywords["STRESSXY"] = 0; + this->stressYZ_.resize(bufferSize,0.0); + rstKeywords["STRESSYZ"] = 0; + + this->strainXX_.resize(bufferSize,0.0); + rstKeywords["STRAINXX"] = 0; + this->strainYY_.resize(bufferSize,0.0); + rstKeywords["STRAINYY"] = 0; + this->strainZZ_.resize(bufferSize,0.0); + rstKeywords["STRAINZZ"] = 0; + this->strainXY_.resize(bufferSize,0.0); + rstKeywords["STRAINXY"] = 0; + this->strainXZ_.resize(bufferSize,0.0); + rstKeywords["STRAINXZ"] = 0; + this->strainXY_.resize(bufferSize,0.0); + rstKeywords["STRAINXY"] = 0; + this->strainYZ_.resize(bufferSize,0.0); + rstKeywords["STRAINYZ"] = 0; + + this->delstressXX_.resize(bufferSize,0.0); + rstKeywords["DELSTRXX"] = 0; + this->delstressYY_.resize(bufferSize,0.0); + rstKeywords["DELSTRYY"] = 0; + this->delstressZZ_.resize(bufferSize,0.0); + rstKeywords["DELSTRZZ"] = 0; + this->delstressXY_.resize(bufferSize,0.0); + rstKeywords["DELSTRXY"] = 0; + this->delstressXZ_.resize(bufferSize,0.0); + rstKeywords["DELSTRXZ"] = 0; + this->delstressXY_.resize(bufferSize,0.0); + rstKeywords["DELSTRXY"] = 0; + this->delstressYZ_.resize(bufferSize,0.0); + rstKeywords["DELSTRYZ"] = 0; + } + + // If TEMP is set in RPTRST we output temperature even if THERMAL + // is not activated + if (enableEnergy_ || rstKeywords["TEMP"] > 0) { + this->temperature_.resize(bufferSize, 0.0); + rstKeywords["TEMP"] = 0; + } + + if (FluidSystem::phaseIsActive(oilPhaseIdx)) { + rstKeywords["SOIL"] = 0; + } + if (FluidSystem::phaseIsActive(gasPhaseIdx)) { + rstKeywords["SGAS"] = 0; + } + if (FluidSystem::phaseIsActive(waterPhaseIdx)) { + rstKeywords["SWAT"] = 0; + } + + /* if (FluidSystem::enableDissolvedGas()) { + rs_.resize(bufferSize, 0.0); + rstKeywords["RS"] = 0; + } + if (FluidSystem::enableDissolvedGasInWater()) { + rsw_.resize(bufferSize, 0.0); + rstKeywords["RSW"] = 0; + } + if (FluidSystem::enableVaporizedOil()) { + rv_.resize(bufferSize, 0.0); + rstKeywords["RV"] = 0; + } + if (FluidSystem::enableVaporizedWater()) { + rvw_.resize(bufferSize, 0.0); + rstKeywords["RVW"] = 0; + } */ + + if (schedule_[reportStepNum].oilvap().drsdtConvective()) { + drsdtcon_.resize(bufferSize, 0.0); + } + + if (enableSolvent_) { + sSol_.resize(bufferSize, 0.0); + if (eclState_.getSimulationConfig().hasDISGASW()) { + rswSol_.resize(bufferSize, 0.0); + } + } + + if (enablePolymer_) { + cPolymer_.resize(bufferSize, 0.0); + } + + if (enableFoam_) { + cFoam_.resize(bufferSize, 0.0); + } + + if (enableBrine_) { + cSalt_.resize(bufferSize, 0.0); + } + + if (enableSaltPrecipitation_) { + pSalt_.resize(bufferSize, 0.0); + permFact_.resize(bufferSize, 0.0); + } + + if (enableExtbo_) { + extboX_.resize(bufferSize, 0.0); + extboY_.resize(bufferSize, 0.0); + extboZ_.resize(bufferSize, 0.0); + mFracOil_.resize(bufferSize, 0.0); + mFracGas_.resize(bufferSize, 0.0); + mFracCo2_.resize(bufferSize, 0.0); + } + + if (enableMICP_) { + cMicrobes_.resize(bufferSize, 0.0); + cOxygen_.resize(bufferSize, 0.0); + cUrea_.resize(bufferSize, 0.0); + cBiofilm_.resize(bufferSize, 0.0); + cCalcite_.resize(bufferSize, 0.0); + } + + if (vapparsActive) { + soMax_.resize(bufferSize, 0.0); + } + + if (enableNonWettingHysteresis) { + if (FluidSystem::phaseIsActive(oilPhaseIdx)){ + if (FluidSystem::phaseIsActive(waterPhaseIdx)){ + soMax_.resize(bufferSize, 0.0); + } + if (FluidSystem::phaseIsActive(gasPhaseIdx)){ + sgmax_.resize(bufferSize, 0.0); + } + } else { + //TODO add support for gas-water + } + } + if (enableWettingHysteresis) { + if (FluidSystem::phaseIsActive(oilPhaseIdx)){ + if (FluidSystem::phaseIsActive(waterPhaseIdx)){ + swMax_.resize(bufferSize, 0.0); + } + if (FluidSystem::phaseIsActive(gasPhaseIdx)){ + shmax_.resize(bufferSize, 0.0); + } + } else { + //TODO add support for gas-water + } + } + if (enablePCHysteresis) { + if (FluidSystem::phaseIsActive(oilPhaseIdx)){ + if (FluidSystem::phaseIsActive(waterPhaseIdx)){ + swmin_.resize(bufferSize, 0.0); + } + if (FluidSystem::phaseIsActive(gasPhaseIdx)){ + somin_.resize(bufferSize, 0.0); + } + } else { + //TODO add support for gas-water + } + } + + if (eclState_.fieldProps().has_double("SWATINIT")) { + ppcw_.resize(bufferSize, 0.0); + rstKeywords["PPCW"] = 0; + } + + /* if (FluidSystem::enableDissolvedGas() && rstKeywords["RSSAT"] > 0) { + rstKeywords["RSSAT"] = 0; + gasDissolutionFactor_.resize(bufferSize, 0.0); + } + if (FluidSystem::enableVaporizedOil() && rstKeywords["RVSAT"] > 0) { + rstKeywords["RVSAT"] = 0; + oilVaporizationFactor_.resize(bufferSize, 0.0); + } + if (FluidSystem::enableDissolvedGasInWater() && rstKeywords["RSWSAT"] > 0) { + rstKeywords["RSWSAT"] = 0; + gasDissolutionFactorInWater_.resize(bufferSize, 0.0); + } + if (FluidSystem::enableVaporizedWater() && rstKeywords["RVWSAT"] > 0) { + rstKeywords["RVWSAT"] = 0; + waterVaporizationFactor_.resize(bufferSize, 0.0); + } + + if (FluidSystem::phaseIsActive(waterPhaseIdx) && rstKeywords["BW"] > 0) { + rstKeywords["BW"] = 0; + invB_[waterPhaseIdx].resize(bufferSize, 0.0); + } + if (FluidSystem::phaseIsActive(oilPhaseIdx) && rstKeywords["BO"] > 0) { + rstKeywords["BO"] = 0; + invB_[oilPhaseIdx].resize(bufferSize, 0.0); + } + if (FluidSystem::phaseIsActive(gasPhaseIdx) && rstKeywords["BG"] > 0) { + rstKeywords["BG"] = 0; + invB_[gasPhaseIdx].resize(bufferSize, 0.0); + } + if (rstKeywords["RPORV"] > 0) { + rstKeywords["RPORV"] = 0; + rPorV_.resize(bufferSize, 0.0); + } */ + + enableFlows_ = false; + enableFlowsn_ = false; + const bool rstFlows = (rstKeywords["FLOWS"] > 0); + if (rstFlows) { + rstKeywords["FLOWS"] = 0; + enableFlows_ = true; + + const std::array phaseIdxs = { gasPhaseIdx, oilPhaseIdx, waterPhaseIdx }; + const std::array compIdxs = { gasCompIdx, oilCompIdx, waterCompIdx }; + const auto rstName = std::array { "FLOGASN+", "FLOOILN+", "FLOWATN+" }; + + for (unsigned ii = 0; ii < phaseIdxs.size(); ++ii) { + if (FluidSystem::phaseIsActive(phaseIdxs[ii])) { + if (!blockFlows_) { // Already allocated if summary vectors requested + flows_[FaceDir::ToIntersectionIndex(Dir::XPlus)][compIdxs[ii]].resize(bufferSize, 0.0); + flows_[FaceDir::ToIntersectionIndex(Dir::YPlus)][compIdxs[ii]].resize(bufferSize, 0.0); + flows_[FaceDir::ToIntersectionIndex(Dir::ZPlus)][compIdxs[ii]].resize(bufferSize, 0.0); + } + + if (rstKeywords["FLOWS-"] > 0) { + flows_[FaceDir::ToIntersectionIndex(Dir::XMinus)][compIdxs[ii]].resize(bufferSize, 0.0); + flows_[FaceDir::ToIntersectionIndex(Dir::YMinus)][compIdxs[ii]].resize(bufferSize, 0.0); + flows_[FaceDir::ToIntersectionIndex(Dir::ZMinus)][compIdxs[ii]].resize(bufferSize, 0.0); + } + + if (numOutputNnc > 0) { + enableFlowsn_ = true; + + flowsn_[compIdxs[ii]].name = rstName[ii]; + flowsn_[compIdxs[ii]].indices.resize(numOutputNnc, -1); + flowsn_[compIdxs[ii]].values.resize(numOutputNnc, 0.0); + } + } + } + if (rstKeywords["FLOWS-"] > 0) { + rstKeywords["FLOWS-"] = 0; + } + } + + enableFlores_ = false; + enableFloresn_ = false; + if (rstKeywords["FLORES"] > 0) { + rstKeywords["FLORES"] = 0; + enableFlores_ = true; + + const std::array phaseIdxs = { gasPhaseIdx, oilPhaseIdx, waterPhaseIdx }; + const std::array compIdxs = { gasCompIdx, oilCompIdx, waterCompIdx }; + const auto rstName = std::array{ "FLRGASN+", "FLROILN+", "FLRWATN+" }; + + for (unsigned ii = 0; ii < phaseIdxs.size(); ++ii) { + if (FluidSystem::phaseIsActive(phaseIdxs[ii])) { + flores_[FaceDir::ToIntersectionIndex(Dir::XPlus)][compIdxs[ii]].resize(bufferSize, 0.0); + flores_[FaceDir::ToIntersectionIndex(Dir::YPlus)][compIdxs[ii]].resize(bufferSize, 0.0); + flores_[FaceDir::ToIntersectionIndex(Dir::ZPlus)][compIdxs[ii]].resize(bufferSize, 0.0); + + if (rstKeywords["FLORES-"] > 0) { + flores_[FaceDir::ToIntersectionIndex(Dir::XMinus)][compIdxs[ii]].resize(bufferSize, 0.0); + flores_[FaceDir::ToIntersectionIndex(Dir::YMinus)][compIdxs[ii]].resize(bufferSize, 0.0); + flores_[FaceDir::ToIntersectionIndex(Dir::ZMinus)][compIdxs[ii]].resize(bufferSize, 0.0); + } + + if (numOutputNnc > 0) { + enableFloresn_ = true; + + floresn_[compIdxs[ii]].name = rstName[ii]; + floresn_[compIdxs[ii]].indices.resize(numOutputNnc, -1); + floresn_[compIdxs[ii]].values.resize(numOutputNnc, 0.0); + } + } + } + if (rstKeywords["FLORES-"] > 0) { + rstKeywords["FLORES-"] = 0; + } + } + + if (auto& den = rstKeywords["DEN"]; den > 0) { + den = 0; + for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) { + if (!FluidSystem::phaseIsActive(phaseIdx)) { + continue; + } + + this->density_[phaseIdx].resize(bufferSize, 0.0); + } + } + + if (auto& deng = rstKeywords["DENG"]; (deng > 0) && FluidSystem::phaseIsActive(gasPhaseIdx)) { + deng = 0; + this->density_[gasPhaseIdx].resize(bufferSize, 0.0); + } + + if (auto& deno = rstKeywords["DENO"]; (deno > 0) && FluidSystem::phaseIsActive(oilPhaseIdx)) { + deno = 0; + this->density_[oilPhaseIdx].resize(bufferSize, 0.0); + } + + if (auto& denw = rstKeywords["DENW"]; (denw > 0) && FluidSystem::phaseIsActive(waterPhaseIdx)) { + denw = 0; + this->density_[waterPhaseIdx].resize(bufferSize, 0.0); + } + + const bool hasVWAT = (rstKeywords["VISC"] > 0) || (rstKeywords["VWAT"] > 0); + const bool hasVOIL = (rstKeywords["VISC"] > 0) || (rstKeywords["VOIL"] > 0); + const bool hasVGAS = (rstKeywords["VISC"] > 0) || (rstKeywords["VGAS"] > 0); + rstKeywords["VISC"] = 0; + + if (FluidSystem::phaseIsActive(waterPhaseIdx) && hasVWAT) { + rstKeywords["VWAT"] = 0; + viscosity_[waterPhaseIdx].resize(bufferSize, 0.0); + } + if (FluidSystem::phaseIsActive(oilPhaseIdx) && hasVOIL > 0) { + rstKeywords["VOIL"] = 0; + viscosity_[oilPhaseIdx].resize(bufferSize, 0.0); + } + if (FluidSystem::phaseIsActive(gasPhaseIdx) && hasVGAS > 0) { + rstKeywords["VGAS"] = 0; + viscosity_[gasPhaseIdx].resize(bufferSize, 0.0); + } + + if (FluidSystem::phaseIsActive(waterPhaseIdx) && rstKeywords["KRW"] > 0) { + rstKeywords["KRW"] = 0; + relativePermeability_[waterPhaseIdx].resize(bufferSize, 0.0); + } + if (FluidSystem::phaseIsActive(oilPhaseIdx) && rstKeywords["KRO"] > 0) { + rstKeywords["KRO"] = 0; + relativePermeability_[oilPhaseIdx].resize(bufferSize, 0.0); + } + if (FluidSystem::phaseIsActive(gasPhaseIdx) && rstKeywords["KRG"] > 0) { + rstKeywords["KRG"] = 0; + relativePermeability_[gasPhaseIdx].resize(bufferSize, 0.0); + } + + if (FluidSystem::phaseIsActive(gasPhaseIdx) && FluidSystem::phaseIsActive(waterPhaseIdx) && rstKeywords["PCGW"] > 0) { + rstKeywords["PCGW"] = 0; + pcgw_.resize(bufferSize, 0.0); + } + if (FluidSystem::phaseIsActive(oilPhaseIdx) && FluidSystem::phaseIsActive(waterPhaseIdx) && rstKeywords["PCOW"] > 0) { + rstKeywords["PCOW"] = 0; + pcow_.resize(bufferSize, 0.0); + } + if (FluidSystem::phaseIsActive(oilPhaseIdx) && FluidSystem::phaseIsActive(gasPhaseIdx) && rstKeywords["PCOG"] > 0) { + rstKeywords["PCOG"] = 0; + pcog_.resize(bufferSize, 0.0); + } + + if (rstKeywords["PBPD"] > 0) { + rstKeywords["PBPD"] = 0; + bubblePointPressure_.resize(bufferSize, 0.0); + dewPointPressure_.resize(bufferSize, 0.0); + } + + // tracers + if (numTracers > 0) { + freeTracerConcentrations_.resize(numTracers); + for (unsigned tracerIdx = 0; tracerIdx < numTracers; ++tracerIdx) + { + freeTracerConcentrations_[tracerIdx].resize(bufferSize, 0.0); + } + solTracerConcentrations_.resize(numTracers); + for (unsigned tracerIdx = 0; tracerIdx < numTracers; ++tracerIdx) + { + if (enableSolTracers[tracerIdx]) + solTracerConcentrations_[tracerIdx].resize(bufferSize, 0.0); + } + } + + if (rstKeywords["RESIDUAL"] > 0) { + rstKeywords["RESIDUAL"] = 0; + for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) + { + if (FluidSystem::phaseIsActive(phaseIdx)) { + this->residual_[phaseIdx].resize(bufferSize, 0.0); + } + } + } + + // ROCKC + if (rstKeywords["ROCKC"] > 0) { + rstKeywords["ROCKC"] = 0; + rockCompPorvMultiplier_.resize(bufferSize, 0.0); + rockCompTransMultiplier_.resize(bufferSize, 0.0); + swMax_.resize(bufferSize, 0.0); + minimumOilPressure_.resize(bufferSize, 0.0); + overburdenPressure_.resize(bufferSize, 0.0); + } + + if (rstKeywords["ZMF"] > 0) { + } + + //Warn for any unhandled keyword + if (log) { + for (auto& keyValue: rstKeywords) { + if (keyValue.second > 0) { + std::string logstring = "Keyword '"; + logstring.append(keyValue.first); + logstring.append("' is unhandled for output to restart file."); + OpmLog::warning("Unhandled output keyword", logstring); + } + } + } + + failedCellsPb_.clear(); + failedCellsPd_.clear(); + + // Not supported in flow legacy + if (false) { + saturatedOilFormationVolumeFactor_.resize(bufferSize, 0.0); + } + + if (false) { + oilSaturationPressure_.resize(bufferSize, 0.0); + } +} + +template +bool GenericOutputCompositionalModule:: +isOutputCreationDirective_(const std::string& keyword) +{ + return (keyword == "BASIC") || (keyword == "FREQ") + || (keyword == "RESTART") // From RPTSCHED + || (keyword == "SAVE") || (keyword == "SFREQ"); // Not really supported +} + +template +void GenericOutputCompositionalModule:: +outputErrorLog(const Parallel::Communication& comm) const +{ + const auto root = 0; + auto globalFailedCellsPbub = gatherv(this->failedCellsPb_, comm, root); + auto globalFailedCellsPdew = gatherv(this->failedCellsPd_, comm, root); + + if (std::empty(std::get<0>(globalFailedCellsPbub)) && + std::empty(std::get<0>(globalFailedCellsPdew))) + { + return; + } + + logOutput_.error(std::get<0>(globalFailedCellsPbub), + std::get<0>(globalFailedCellsPdew)); +} + +template +int GenericOutputCompositionalModule:: +regionMax(const std::vector& region, + const Parallel::Communication& comm) +{ + const auto max_value = region.empty() ? 0 : *std::max_element(region.begin(), region.end()); + return comm.max(max_value); +} + +template +void GenericOutputCompositionalModule:: +update(Inplace& inplace, + const std::string& region_name, + const Inplace::Phase phase, + const std::size_t ntFip, + const ScalarBuffer& values) +{ + double sum = 0.0; + for (std::size_t region_number = 0; region_number < ntFip; ++region_number) { + const auto rval = static_cast(values[region_number]); + inplace.add(region_name, phase, region_number + 1, rval); + sum += rval; + } + inplace.add(phase, sum); +} + +template +void GenericOutputCompositionalModule:: +makeRegionSum(Inplace& inplace, + const std::string& region_name, + const Parallel::Communication& comm) const +{ + const auto& region = this->regions_.at(region_name); + const std::size_t ntFip = this->regionMax(region, comm); + + auto update_inplace = + [&inplace, ®ion, ®ion_name, &comm, ntFip, this] + (const Inplace::Phase phase, + const std::vector& value) + { + update(inplace, region_name, phase, ntFip, + this->regionSum(value, region, ntFip, comm)); + }; + + update_inplace(Inplace::Phase::PressurePV, + this->pressureTimesPoreVolume_); + + update_inplace(Inplace::Phase::HydroCarbonPV, + this->hydrocarbonPoreVolume_); + + update_inplace(Inplace::Phase::PressureHydroCarbonPV, + this->pressureTimesHydrocarbonVolume_); + + update_inplace(Inplace::Phase::DynamicPoreVolume, + this->dynamicPoreVolume_); + + for (const auto& phase : Inplace::phases()) { + auto fipPos = this->fip_.find(phase); + if (fipPos != this->fip_.end()) { + update_inplace(phase, fipPos->second); + } + } +} + +template +Inplace GenericOutputCompositionalModule:: +accumulateRegionSums(const Parallel::Communication& comm) +{ + Inplace inplace; + + for (const auto& region : this->regions_) { + makeRegionSum(inplace, region.first, comm); + } + + // The first time the outputFipLog function is run we store the inplace values in + // the initialInplace_ member. This has a problem: + // + // o For restarted runs this is obviously wrong. + // + // Finally it is of course not desirable to mutate state in an output + // routine. + if (!this->initialInplace_.has_value()) + this->initialInplace_ = inplace; + return inplace; +} + +template +typename GenericOutputCompositionalModule::Scalar +GenericOutputCompositionalModule:: +sum(const ScalarBuffer& v) +{ + return std::accumulate(v.begin(), v.end(), Scalar{0}); +} + +template +void GenericOutputCompositionalModule:: +updateSummaryRegionValues(const Inplace& inplace, + std::map& miscSummaryData, + std::map>& regionData) const +{ + // The field summary vectors should only use the FIPNUM based region sum. + { + for (const auto& phase : Inplace::phases()) { + const std::string key = "F" + EclString(phase); + if (this->summaryConfig_.hasKeyword(key)) { + miscSummaryData[key] = inplace.get(phase); + } + } + + if (this->summaryConfig_.hasKeyword("FHPV")) { + miscSummaryData["FHPV"] = inplace.get(Inplace::Phase::HydroCarbonPV); + } + + if (this->summaryConfig_.hasKeyword("FOE") && this->initialInplace_) { + miscSummaryData["FOE"] = (this->initialInplace_.value().get(Inplace::Phase::OIL) - inplace.get(Inplace::Phase::OIL)) + / this->initialInplace_.value().get(Inplace::Phase::OIL); + } + + if (this->summaryConfig_.hasKeyword("FPR")) { + miscSummaryData["FPR"] = + detail::pressureAverage(inplace.get(Inplace::Phase::PressureHydroCarbonPV), + inplace.get(Inplace::Phase::HydroCarbonPV), + inplace.get(Inplace::Phase::PressurePV), + inplace.get(Inplace::Phase::DynamicPoreVolume), + true); + } + + if (this->summaryConfig_.hasKeyword("FPRP")) { + miscSummaryData["FPRP"] = + detail::pressureAverage(inplace.get(Inplace::Phase::PressureHydroCarbonPV), + inplace.get(Inplace::Phase::HydroCarbonPV), + inplace.get(Inplace::Phase::PressurePV), + inplace.get(Inplace::Phase::DynamicPoreVolume), + false); + } + } + + // The region summary vectors should loop through the FIPxxx regions to + // support the RPR__xxx summary keywords. + { + auto get_vector = [&inplace] + (const auto& node_, + const Inplace::Phase phase_) + { + return inplace.get_vector(node_.fip_region(), phase_); + }; + + for (const auto& phase : Inplace::phases()) { + for (const auto& node : this->regionNodes_.at(phase)) + regionData[node.keyword()] = get_vector(node, phase); + } + + for (const auto& node : this->RPRNodes_) { + regionData[node.keyword()] = + detail::pressureAverage(get_vector(node, Inplace::Phase::PressureHydroCarbonPV), + get_vector(node, Inplace::Phase::HydroCarbonPV), + get_vector(node, Inplace::Phase::PressurePV), + get_vector(node, Inplace::Phase::DynamicPoreVolume), + true); + } + + for (const auto& node : this->RPRPNodes_) { + regionData[node.keyword()] = + detail::pressureAverage(get_vector(node, Inplace::Phase::PressureHydroCarbonPV), + get_vector(node, Inplace::Phase::HydroCarbonPV), + get_vector(node, Inplace::Phase::PressurePV), + get_vector(node, Inplace::Phase::DynamicPoreVolume), + false); + } + + for (const auto& node : this->summaryConfig_.keywords("RHPV*")) { + regionData[node.keyword()] = + get_vector(node, Inplace::Phase::HydroCarbonPV); + } + } +} + +template +void GenericOutputCompositionalModule:: +setupBlockData(std::function isCartIdxOnThisRank) +{ + for (const auto& node : summaryConfig_) { + if ((node.category() == SummaryConfigNode::Category::Block) && + isCartIdxOnThisRank(node.number() - 1)) + { + this->blockData_.emplace(std::piecewise_construct, + std::forward_as_tuple(node.keyword(), + node.number()), + std::forward_as_tuple(0.0)); + } + } +} + +template +void GenericOutputCompositionalModule:: +assignGlobalFieldsToSolution(data::Solution& sol) +{ + if (!this->cnvData_.empty()) { + constexpr const std::array names{"CNV_OIL", "CNV_GAS", "CNV_WAT", + "CNV_PLY", "CNV_SAL", "CNV_SOL"}; + for (std::size_t i = 0; i < names.size(); ++i) { + if (!this->cnvData_[i].empty()) { + sol.insert(names[i], this->cnvData_[i], data::TargetType::RESTART_SOLUTION); + } + } + } +} + +/* INSTANTIATE_TYPE(double) + +#if FLOW_INSTANTIATE_FLOAT +INSTANTIATE_TYPE(float) +#endif */ + +#define INSTANTIATE_FS(NUM) \ + template using FS##NUM = GenericOilGasFluidSystem; \ + template class GenericOutputCompositionalModule>; + +INSTANTIATE_FS(2) +INSTANTIATE_FS(3) +INSTANTIATE_FS(4) +INSTANTIATE_FS(5) +INSTANTIATE_FS(6) +INSTANTIATE_FS(7) + +} // namespace Opm diff --git a/opm/simulators/flow/GenericOutputCompositionalModule.hpp b/opm/simulators/flow/GenericOutputCompositionalModule.hpp new file mode 100644 index 000000000..4b863cc41 --- /dev/null +++ b/opm/simulators/flow/GenericOutputCompositionalModule.hpp @@ -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 . + 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 +#include + +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Opm { + +namespace data { class Solution; } +class EclipseState; +class Schedule; +class SummaryConfig; +class SummaryConfigNode; +class SummaryState; + +template +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& miscSummaryData, + std::map>& 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, 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, 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, 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>& data) + { + cnvData_ = data; + } + + template + 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; + using StringBuffer = std::vector; + 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& 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& miscSummaryData, + std::map>& regionData) const; + + static bool isOutputCreationDirective_(const std::string& keyword); + + // Sum Fip values over regions. + static ScalarBuffer regionSum(const ScalarBuffer& property, + const std::vector& regionId, + const std::size_t maxNumberOfRegions, + const Parallel::Communication& comm); + + static int regionMax(const std::vector& 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 isCartIdxOnThisRank); + + virtual bool isDefunctParallelWell(std::string wname) const = 0; + + const EclipseState& eclState_; + const Schedule& schedule_; + const SummaryState& summaryState_; + + SummaryConfig summaryConfig_; + + InterRegFlowMap interRegionFlows_; + LogOutputHelper 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 fip_; + std::unordered_map> regions_; + std::unordered_map> regionNodes_; + + std::vector RPRNodes_; + std::vector RPRPNodes_; + + std::vector failedCellsPb_; + std::vector 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 saturation_; + std::array invB_; + std::array density_; + std::array viscosity_; + std::array relativePermeability_; + + std::array moleFractions_; + + std::vector freeTracerConcentrations_; + std::vector solTracerConcentrations_; + + std::array residual_; + + std::array, 6> flows_; + std::array, 6> flores_; + + std::array, 3> floresn_; + std::array, 3> flowsn_; + + std::map oilConnectionPressures_; + std::map waterConnectionSaturations_; + std::map gasConnectionSaturations_; + std::map, double> blockData_; + + std::vector> cnvData_; //!< Data for CNV_xxx arrays + + std::optional initialInplace_; + bool local_data_valid_{false}; + + std::optional regionAvgDensity_; +}; + +} // namespace Opm + +#endif // OPM_GENERIC_OUTPUT_BLACK_OIL_MODULE_HPP diff --git a/opm/simulators/flow/OutputBlackoilModule.hpp b/opm/simulators/flow/OutputBlackoilModule.hpp index 9104e7deb..c3fb57d31 100644 --- a/opm/simulators/flow/OutputBlackoilModule.hpp +++ b/opm/simulators/flow/OutputBlackoilModule.hpp @@ -65,13 +65,13 @@ #include #include -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 { diff --git a/opm/simulators/flow/OutputCompositionalModule.hpp b/opm/simulators/flow/OutputCompositionalModule.hpp new file mode 100644 index 000000000..982e7227f --- /dev/null +++ b/opm/simulators/flow/OutputCompositionalModule.hpp @@ -0,0 +1,1854 @@ +// -*- 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 . + + 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::OutputBlackOilModule + */ +#ifndef OPM_OUTPUT_COMPOSITIONAL_MODULE_HPP +#define OPM_OUTPUT_COMPOSITIONAL_MODULE_HPP + +#include + +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace Opm::Parameters { + +struct ForceDisableFluidInPlaceOutput { static constexpr bool value = false; }; +struct ForceDisableResvFluidInPlaceOutput { static constexpr bool value = false; }; + +} // namespace Opm::Parameters + +namespace Opm +{ + +// forward declaration +template +class EcfvDiscretization; + +/*! + * \ingroup BlackOilSimulator + * + * \brief Output module for the results black oil model writing in + * ECL binary format. + */ +template +class OutputCompositionalModule : public GenericOutputCompositionalModule> +{ + using Simulator = GetPropType; + using Discretization = GetPropType; + using Scalar = GetPropType; + using Evaluation = GetPropType; + using ElementContext = GetPropType; + using MaterialLaw = GetPropType; + using MaterialLawParams = GetPropType; + using IntensiveQuantities = GetPropType; + using FluidSystem = GetPropType; + using GridView = GetPropType; + using Element = typename GridView::template Codim<0>::Entity; + using ElementIterator = typename GridView::template Codim<0>::Iterator; + using BaseType = GenericOutputCompositionalModule; + using Indices = GetPropType; + using Dir = FaceDir::DirEnum; + + enum { conti0EqIdx = Indices::conti0EqIdx }; + enum { numPhases = FluidSystem::numPhases }; + enum { oilPhaseIdx = FluidSystem::oilPhaseIdx }; + enum { gasPhaseIdx = FluidSystem::gasPhaseIdx }; + enum { waterPhaseIdx = FluidSystem::waterPhaseIdx }; + enum { gasCompIdx = FluidSystem::gasCompIdx }; + enum { oilCompIdx = FluidSystem::oilCompIdx }; + enum { waterCompIdx = FluidSystem::waterCompIdx }; + enum { enableEnergy = getPropValue() }; + +public: + template + OutputCompositionalModule(const Simulator& simulator, + const SummaryConfig& smryCfg, + const CollectDataToIORankType& collectToIORank) + : BaseType(simulator.vanguard().eclState(), + simulator.vanguard().schedule(), + smryCfg, + simulator.vanguard().summaryState(), + moduleVersionName(), + getPropValue(), + getPropValue(), + getPropValue(), + getPropValue(), + getPropValue(), + getPropValue(), + getPropValue(), + getPropValue(), + getPropValue(), + getPropValue()) + , simulator_(simulator) + { + for (auto& region_pair : this->regions_) { + this->createLocalRegion_(region_pair.second); + } + + auto isCartIdxOnThisRank = [&collectToIORank](const int idx) { + return collectToIORank.isCartIdxOnThisRank(idx); + }; + + this->setupBlockData(isCartIdxOnThisRank); + + this->forceDisableFipOutput_ = + Parameters::Get(); + + this->forceDisableFipresvOutput_ = + Parameters::Get(); + + if (! Parameters::Get()) { + const std::string msg = "The output code does not support --owner-cells-first=false."; + if (collectToIORank.isIORank()) { + OpmLog::error(msg); + } + OPM_THROW_NOLOG(std::runtime_error, msg); + } + + if (smryCfg.match("[FB]PP[OGW]") || smryCfg.match("RPP[OGW]*")) { + auto rset = this->eclState_.fieldProps().fip_regions(); + rset.push_back("PVTNUM"); + + // Note: We explicitly use decltype(auto) here because the + // default scheme (-> auto) will deduce an undesirable type. We + // need the "reference to vector" semantics in this instance. + this->regionAvgDensity_ + .emplace(this->simulator_.gridView().comm(), + FluidSystem::numPhases, rset, + [fp = std::cref(this->eclState_.fieldProps())] + (const std::string& rsetName) -> decltype(auto) + { return fp.get().get_int(rsetName); }); + } + } + + /*! + * \brief Register all run-time parameters for the Vtk output module. + */ + static void registerParameters() + { + Parameters::Register + ("Do not print fluid-in-place values after each report step " + "even if requested by the deck."); + Parameters::Register + ("Do not print reservoir volumes values after each report step " + "even if requested by the deck."); + } + + /*! + * \brief Allocate memory for the scalar fields we would like to + * write to ECL output files + */ + void + allocBuffers(const unsigned bufferSize, + const unsigned reportStepNum, + const bool substep, + const bool log, + const bool isRestart) + { + if (! std::is_same>::value) { + return; + } + + const auto& problem = this->simulator_.problem(); + + std::cout << " let us do doAllocBuffers " << std::endl; + + this->doAllocBuffers(bufferSize, + reportStepNum, + substep, + log, + isRestart); + // problem.vapparsActive(std::max(simulator_.episodeIndex(), 0)), + // problem.materialLawManager()->enablePCHysteresis(), + // problem.materialLawManager()->enableNonWettingHysteresis(), + // problem.materialLawManager()->enableWettingHysteresis(), + // problem.tracerModel().numTracers(), + // problem.tracerModel().enableSolTracers(), + // problem.eclWriter()->getOutputNnc().size()); + } + +// void processElementMech(const ElementContext& elemCtx) +// { +// if constexpr (getPropValue()) { +// const auto& problem = elemCtx.simulator().problem(); +// const auto& model = problem.geoMechModel(); +// for (unsigned dofIdx = 0; dofIdx < elemCtx.numPrimaryDof(/*timeIdx=*/0); ++dofIdx) { +// unsigned globalDofIdx = elemCtx.globalSpaceIndex(dofIdx, /*timeIdx=*/0); +// if (!this->mechPotentialForce_.empty()) { +// // assume all mechanical things should be written +// this->mechPotentialForce_[globalDofIdx] = model.mechPotentialForce(globalDofIdx); +// this->mechPotentialPressForce_[globalDofIdx] = model.mechPotentialPressForce(globalDofIdx); +// this->mechPotentialTempForce_[globalDofIdx] = model.mechPotentialTempForce(globalDofIdx); +// +// this->dispX_[globalDofIdx] = model.disp(globalDofIdx, 0); +// this->dispY_[globalDofIdx] = model.disp(globalDofIdx, 1); +// this->dispZ_[globalDofIdx] = model.disp(globalDofIdx, 2); +// this->stressXX_[globalDofIdx] = model.stress(globalDofIdx, 0); +// this->stressYY_[globalDofIdx] = model.stress(globalDofIdx, 1); +// this->stressZZ_[globalDofIdx] = model.stress(globalDofIdx, 2); +// // voight notation +// this->stressXY_[globalDofIdx] = model.stress(globalDofIdx, 5); +// this->stressXZ_[globalDofIdx] = model.stress(globalDofIdx, 4); +// this->stressYZ_[globalDofIdx] = model.stress(globalDofIdx, 3); +// +// this->strainXX_[globalDofIdx] = model.strain(globalDofIdx, 0); +// this->strainYY_[globalDofIdx] = model.strain(globalDofIdx, 1); +// this->strainZZ_[globalDofIdx] = model.strain(globalDofIdx, 2); +// // voight notation +// this->strainXY_[globalDofIdx] = model.strain(globalDofIdx, 5); +// this->strainXZ_[globalDofIdx] = model.strain(globalDofIdx, 4); +// this->strainYZ_[globalDofIdx] = model.strain(globalDofIdx, 3); +// +// +// this->delstressXX_[globalDofIdx] = model.delstress(globalDofIdx, 0); +// this->delstressYY_[globalDofIdx] = model.delstress(globalDofIdx, 1); +// this->delstressZZ_[globalDofIdx] = model.delstress(globalDofIdx, 2); +// // voight notation +// this->delstressXY_[globalDofIdx] = model.delstress(globalDofIdx, 5); +// this->delstressXZ_[globalDofIdx] = model.delstress(globalDofIdx, 4); +// this->delstressYZ_[globalDofIdx] = model.delstress(globalDofIdx, 3); +// } +// } +// } +// } + + /*! + * \brief Modify the internal buffers according to the intensive + * quanties relevant for an element + */ + void processElement(const ElementContext& elemCtx) + { + OPM_TIMEBLOCK_LOCAL(processElement); + if (!std::is_same>::value) + return; + + const auto& problem = elemCtx.simulator().problem(); + const auto& modelResid = elemCtx.simulator().model().linearizer().residual(); + for (unsigned dofIdx = 0; dofIdx < elemCtx.numPrimaryDof(/*timeIdx=*/0); ++dofIdx) { + const auto& intQuants = elemCtx.intensiveQuantities(dofIdx, /*timeIdx=*/0); + const auto& fs = intQuants.fluidState(); + + using FluidState = std::remove_cv_t>; + + const unsigned globalDofIdx = elemCtx.globalSpaceIndex(dofIdx, /*timeIdx=*/0); + // const unsigned pvtRegionIdx = 0; // elemCtx.primaryVars(dofIdx, /*timeIdx=*/0).pvtRegionIndex(); + + for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { + if (this->saturation_[phaseIdx].empty()) + continue; + + this->saturation_[phaseIdx][globalDofIdx] = getValue(fs.saturation(phaseIdx)); + Valgrind::CheckDefined(this->saturation_[phaseIdx][globalDofIdx]); + } + +// if (this->regionAvgDensity_.has_value()) { +// // Note: We intentionally exclude effects of rock +// // compressibility by using referencePorosity() here. +// const auto porv = 0; // intQuants.referencePorosity() +// // * elemCtx.simulator().model().dofTotalVolume(globalDofIdx); +// +// this->aggregateAverageDensityContributions_(fs, globalDofIdx, +// static_cast(porv)); +// } + + if (!this->fluidPressure_.empty()) { + if (FluidSystem::phaseIsActive(oilPhaseIdx)) { + // Output oil pressure as default + this->fluidPressure_[globalDofIdx] = getValue(fs.pressure(oilPhaseIdx)); + } else if (FluidSystem::phaseIsActive(gasPhaseIdx)) { + // Output gas if oil is not present + this->fluidPressure_[globalDofIdx] = getValue(fs.pressure(gasPhaseIdx)); + } else { + // Output water if neither oil nor gas is present + this->fluidPressure_[globalDofIdx] = getValue(fs.pressure(waterPhaseIdx)); + } + Valgrind::CheckDefined(this->fluidPressure_[globalDofIdx]); + } + + if (!this->temperature_.empty()) { + this->temperature_[globalDofIdx] = getValue(fs.temperature(oilPhaseIdx)); + Valgrind::CheckDefined(this->temperature_[globalDofIdx]); + } +// if (!this->gasDissolutionFactor_.empty()) { +// Scalar SoMax = elemCtx.problem().maxOilSaturation(globalDofIdx); +// this->gasDissolutionFactor_[globalDofIdx] +// = 0; //FluidSystem::template saturatedDissolutionFactor( +// // fs, oilPhaseIdx, pvtRegionIdx, SoMax); +// Valgrind::CheckDefined(this->gasDissolutionFactor_[globalDofIdx]); +// } +// if (!this->oilVaporizationFactor_.empty()) { +// Scalar SoMax = elemCtx.problem().maxOilSaturation(globalDofIdx); +// this->oilVaporizationFactor_[globalDofIdx] +// = 0; // FluidSystem::template saturatedDissolutionFactor( +// // fs, gasPhaseIdx, pvtRegionIdx, SoMax); +// Valgrind::CheckDefined(this->oilVaporizationFactor_[globalDofIdx]); +// } + // if (!this->gasDissolutionFactorInWater_.empty()) { + // Scalar SwMax = elemCtx.problem().maxWaterSaturation(globalDofIdx); + // this->gasDissolutionFactorInWater_[globalDofIdx] + // = FluidSystem::template saturatedDissolutionFactor( + // fs, waterPhaseIdx, pvtRegionIdx, SwMax); + // Valgrind::CheckDefined(this->gasDissolutionFactorInWater_[globalDofIdx]); + // } + // if (!this->waterVaporizationFactor_.empty()) { + // this->waterVaporizationFactor_[globalDofIdx] + // = FluidSystem::template saturatedVaporizationFactor( + // fs, gasPhaseIdx, pvtRegionIdx); + // Valgrind::CheckDefined(this->waterVaporizationFactor_[globalDofIdx]); + // } + // if (!this->gasFormationVolumeFactor_.empty()) { + // this->gasFormationVolumeFactor_[globalDofIdx] = 1.0 + // / FluidSystem::template inverseFormationVolumeFactor( + // fs, gasPhaseIdx, pvtRegionIdx); + // Valgrind::CheckDefined(this->gasFormationVolumeFactor_[globalDofIdx]); + // } + // if (!this->saturatedOilFormationVolumeFactor_.empty()) { + // this->saturatedOilFormationVolumeFactor_[globalDofIdx] = 1.0 + // / FluidSystem::template saturatedInverseFormationVolumeFactor( + // fs, oilPhaseIdx, pvtRegionIdx); + // Valgrind::CheckDefined(this->saturatedOilFormationVolumeFactor_[globalDofIdx]); + // } + // if (!this->oilSaturationPressure_.empty()) { + // this->oilSaturationPressure_[globalDofIdx] + // = FluidSystem::template saturationPressure(fs, oilPhaseIdx, pvtRegionIdx); + // Valgrind::CheckDefined(this->oilSaturationPressure_[globalDofIdx]); + // } + // + // if (!this->rs_.empty()) { + // this->rs_[globalDofIdx] = getValue(fs.Rs()); + // Valgrind::CheckDefined(this->rs_[globalDofIdx]); + // } + // if (!this->rsw_.empty()) { + // this->rsw_[globalDofIdx] = getValue(fs.Rsw()); + // Valgrind::CheckDefined(this->rsw_[globalDofIdx]); + // } + // + // if (!this->rv_.empty()) { + // this->rv_[globalDofIdx] = getValue(fs.Rv()); + // Valgrind::CheckDefined(this->rv_[globalDofIdx]); + // } + // if (!this->pcgw_.empty()) { + // this->pcgw_[globalDofIdx] = getValue(fs.pressure(gasPhaseIdx)) - getValue(fs.pressure(waterPhaseIdx)); + // Valgrind::CheckDefined(this->pcgw_[globalDofIdx]); + // } + // if (!this->pcow_.empty()) { + // this->pcow_[globalDofIdx] = getValue(fs.pressure(oilPhaseIdx)) - getValue(fs.pressure(waterPhaseIdx)); + // Valgrind::CheckDefined(this->pcow_[globalDofIdx]); + // } + // if (!this->pcog_.empty()) { + // this->pcog_[globalDofIdx] = getValue(fs.pressure(gasPhaseIdx)) - getValue(fs.pressure(oilPhaseIdx)); + // Valgrind::CheckDefined(this->pcog_[globalDofIdx]); + // } + // + // if (!this->rvw_.empty()) { + // this->rvw_[globalDofIdx] = getValue(fs.Rvw()); + // Valgrind::CheckDefined(this->rvw_[globalDofIdx]); + // } + // + // for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { + // if (this->invB_[phaseIdx].empty()) + // continue; + // + // this->invB_[phaseIdx][globalDofIdx] = getValue(fs.invB(phaseIdx)); + // Valgrind::CheckDefined(this->invB_[phaseIdx][globalDofIdx]); + // } + // + // for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { + // if (this->density_[phaseIdx].empty()) + // continue; + // + // this->density_[phaseIdx][globalDofIdx] = getValue(fs.density(phaseIdx)); + // Valgrind::CheckDefined(this->density_[phaseIdx][globalDofIdx]); + // } + // + // for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { + // if (this->viscosity_[phaseIdx].empty()) + // continue; + // + // if (!this->extboX_.empty() && phaseIdx == oilPhaseIdx) + // this->viscosity_[phaseIdx][globalDofIdx] = getValue(intQuants.oilViscosity()); + // else if (!this->extboX_.empty() && phaseIdx == gasPhaseIdx) + // this->viscosity_[phaseIdx][globalDofIdx] = getValue(intQuants.gasViscosity()); + // else + // this->viscosity_[phaseIdx][globalDofIdx] = getValue(fs.viscosity(phaseIdx)); + // Valgrind::CheckDefined(this->viscosity_[phaseIdx][globalDofIdx]); + // } + // + // for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { + // if (this->relativePermeability_[phaseIdx].empty()) + // continue; + // + // this->relativePermeability_[phaseIdx][globalDofIdx] + // = getValue(intQuants.relativePermeability(phaseIdx)); + // Valgrind::CheckDefined(this->relativePermeability_[phaseIdx][globalDofIdx]); + // } + // + // if (!this->drsdtcon_.empty()) { + // this->drsdtcon_[globalDofIdx] = problem.drsdtcon(globalDofIdx, elemCtx.simulator().episodeIndex()); + // } + // + // if (!this->sSol_.empty()) { + // this->sSol_[globalDofIdx] = intQuants.solventSaturation().value(); + // } + // + // if (!this->rswSol_.empty()) { + // this->rswSol_[globalDofIdx] = intQuants.rsSolw().value(); + // } + // + // if (!this->cPolymer_.empty()) { + // this->cPolymer_[globalDofIdx] = intQuants.polymerConcentration().value(); + // } + // + // if (!this->cFoam_.empty()) { + // this->cFoam_[globalDofIdx] = intQuants.foamConcentration().value(); + // } + // + // if (!this->cSalt_.empty()) { + // this->cSalt_[globalDofIdx] = fs.saltConcentration().value(); + // } + // + // if (!this->pSalt_.empty()) { + // this->pSalt_[globalDofIdx] = intQuants.saltSaturation().value(); + // } + // + // if (!this->permFact_.empty()) { + // this->permFact_[globalDofIdx] = intQuants.permFactor().value(); + // } + // + // if (!this->extboX_.empty()) { + // this->extboX_[globalDofIdx] = intQuants.xVolume().value(); + // } + // + // if (!this->extboY_.empty()) { + // this->extboY_[globalDofIdx] = intQuants.yVolume().value(); + // } + // + // if (!this->extboZ_.empty()) { + // this->extboZ_[globalDofIdx] = intQuants.zFraction().value(); + // } + // + // if (!this->rPorV_.empty()) { + // const auto totVolume = elemCtx.simulator().model().dofTotalVolume(globalDofIdx); + // this->rPorV_[globalDofIdx] = totVolume * intQuants.porosity().value(); + // } + // + // if (!this->mFracCo2_.empty()) { + // const Scalar stdVolOil = getValue(fs.saturation(oilPhaseIdx)) * getValue(fs.invB(oilPhaseIdx)) + // + getValue(fs.saturation(gasPhaseIdx)) * getValue(fs.invB(gasPhaseIdx)) * getValue(fs.Rv()); + // const Scalar stdVolGas = getValue(fs.saturation(gasPhaseIdx)) * getValue(fs.invB(gasPhaseIdx)) + // * (1.0 - intQuants.yVolume().value()) + // + getValue(fs.saturation(oilPhaseIdx)) * getValue(fs.invB(oilPhaseIdx)) * getValue(fs.Rs()) + // * (1.0 - intQuants.xVolume().value()); + // const Scalar stdVolCo2 = getValue(fs.saturation(gasPhaseIdx)) * getValue(fs.invB(gasPhaseIdx)) + // * intQuants.yVolume().value() + // + getValue(fs.saturation(oilPhaseIdx)) * getValue(fs.invB(oilPhaseIdx)) * getValue(fs.Rs()) + // * intQuants.xVolume().value(); + // const Scalar rhoO = FluidSystem::referenceDensity(gasPhaseIdx, pvtRegionIdx); + // const Scalar rhoG = FluidSystem::referenceDensity(gasPhaseIdx, pvtRegionIdx); + // const Scalar rhoCO2 = intQuants.zRefDensity(); + // const Scalar stdMassTotal = 1.0e-10 + stdVolOil * rhoO + stdVolGas * rhoG + stdVolCo2 * rhoCO2; + // this->mFracOil_[globalDofIdx] = stdVolOil * rhoO / stdMassTotal; + // this->mFracGas_[globalDofIdx] = stdVolGas * rhoG / stdMassTotal; + // this->mFracCo2_[globalDofIdx] = stdVolCo2 * rhoCO2 / stdMassTotal; + // } + // + // if (!this->cMicrobes_.empty()) { + // this->cMicrobes_[globalDofIdx] = intQuants.microbialConcentration().value(); + // } + // + // if (!this->cOxygen_.empty()) { + // this->cOxygen_[globalDofIdx] = intQuants.oxygenConcentration().value(); + // } + // + // if (!this->cUrea_.empty()) { + // this->cUrea_[globalDofIdx] = 10 + // * intQuants.ureaConcentration() + // .value(); // Reescaling back the urea concentration (see WellInterface_impl.hpp) + // } + // + // if (!this->cBiofilm_.empty()) { + // this->cBiofilm_[globalDofIdx] = intQuants.biofilmConcentration().value(); + // } + // + // if (!this->cCalcite_.empty()) { + // this->cCalcite_[globalDofIdx] = intQuants.calciteConcentration().value(); + // } + // + // if (!this->bubblePointPressure_.empty()) { + // try { + // this->bubblePointPressure_[globalDofIdx] + // = getValue(FluidSystem::bubblePointPressure(fs, intQuants.pvtRegionIndex())); + // } catch (const NumericalProblem&) { + // const auto cartesianIdx = elemCtx.simulator().vanguard().cartesianIndex(globalDofIdx); + // this->failedCellsPb_.push_back(cartesianIdx); + // } + // } + // + // if (!this->dewPointPressure_.empty()) { + // try { + // this->dewPointPressure_[globalDofIdx] + // = getValue(FluidSystem::dewPointPressure(fs, intQuants.pvtRegionIndex())); + // } catch (const NumericalProblem&) { + // const auto cartesianIdx = elemCtx.simulator().vanguard().cartesianIndex(globalDofIdx); + // this->failedCellsPd_.push_back(cartesianIdx); + // } + // } + // + // if (!this->minimumOilPressure_.empty()) + // this->minimumOilPressure_[globalDofIdx] + // = std::min(getValue(fs.pressure(oilPhaseIdx)), problem.minOilPressure(globalDofIdx)); + // + // if (!this->overburdenPressure_.empty()) + // this->overburdenPressure_[globalDofIdx] = problem.overburdenPressure(globalDofIdx); + // + // if (!this->rockCompPorvMultiplier_.empty()) + // this->rockCompPorvMultiplier_[globalDofIdx] + // = problem.template rockCompPoroMultiplier(intQuants, globalDofIdx); + // + // if (!this->rockCompTransMultiplier_.empty()) + // this->rockCompTransMultiplier_[globalDofIdx] + // = problem.template rockCompTransMultiplier(intQuants, globalDofIdx); + // + // const auto& matLawManager = problem.materialLawManager(); + // if (matLawManager->enableHysteresis()) { + // if (FluidSystem::phaseIsActive(oilPhaseIdx) + // && FluidSystem::phaseIsActive(waterPhaseIdx)) { + // Scalar somax; + // Scalar swmax; + // Scalar swmin; + // + // matLawManager->oilWaterHysteresisParams( + // somax, swmax, swmin, globalDofIdx); + // + // if (matLawManager->enableNonWettingHysteresis()) { + // if (!this->soMax_.empty()) { + // this->soMax_[globalDofIdx] = somax; + // } + // } + // if (matLawManager->enableWettingHysteresis()) { + // if (!this->swMax_.empty()) { + // this->swMax_[globalDofIdx] = swmax; + // } + // } + // if (matLawManager->enablePCHysteresis()) { + // if (!this->swmin_.empty()) { + // this->swmin_[globalDofIdx] = swmin; + // } + // } + // } + // + // if (FluidSystem::phaseIsActive(oilPhaseIdx) + // && FluidSystem::phaseIsActive(gasPhaseIdx)) { + // Scalar sgmax; + // Scalar shmax; + // Scalar somin; + // matLawManager->gasOilHysteresisParams( + // sgmax, shmax, somin, globalDofIdx); + // + // if (matLawManager->enableNonWettingHysteresis()) { + // if (!this->sgmax_.empty()) { + // this->sgmax_[globalDofIdx] = sgmax; + // } + // } + // if (matLawManager->enableWettingHysteresis()) { + // if (!this->shmax_.empty()) { + // this->shmax_[globalDofIdx] = shmax; + // } + // } + // if (matLawManager->enablePCHysteresis()) { + // if (!this->somin_.empty()) { + // this->somin_[globalDofIdx] = somin; + // } + // } + // } + // } else { + // + // if (!this->soMax_.empty()) + // this->soMax_[globalDofIdx] + // = std::max(getValue(fs.saturation(oilPhaseIdx)), problem.maxOilSaturation(globalDofIdx)); + // + // if (!this->swMax_.empty()) + // this->swMax_[globalDofIdx] + // = std::max(getValue(fs.saturation(waterPhaseIdx)), problem.maxWaterSaturation(globalDofIdx)); + // + // } + // if (!this->ppcw_.empty()) { + // this->ppcw_[globalDofIdx] = matLawManager->oilWaterScaledEpsInfoDrainage(globalDofIdx).maxPcow; + // // printf("ppcw_[%d] = %lg\n", globalDofIdx, ppcw_[globalDofIdx]); + // } + // + // // hack to make the intial output of rs and rv Ecl compatible. + // // For cells with swat == 1 Ecl outputs; rs = rsSat and rv=rvSat, in all but the initial step + // // where it outputs rs and rv values calculated by the initialization. To be compatible we overwrite + // // rs and rv with the values computed in the initially. + // // Volume factors, densities and viscosities need to be recalculated with the updated rs and rv values. + // if ((elemCtx.simulator().episodeIndex() < 0) && + // FluidSystem::phaseIsActive(oilPhaseIdx) && + // FluidSystem::phaseIsActive(gasPhaseIdx)) + // { + // const auto& fsInitial = problem.initialFluidState(globalDofIdx); + // + // // use initial rs and rv values + // if (!this->rv_.empty()) + // this->rv_[globalDofIdx] = fsInitial.Rv(); + // + // if (!this->rs_.empty()) + // this->rs_[globalDofIdx] = fsInitial.Rs(); + // + // if (!this->rsw_.empty()) + // this->rsw_[globalDofIdx] = fsInitial.Rsw(); + // + // if (!this->rvw_.empty()) + // this->rvw_[globalDofIdx] = fsInitial.Rvw(); + // + // // re-compute the volume factors, viscosities and densities if asked for + // if (!this->density_[oilPhaseIdx].empty()) + // this->density_[oilPhaseIdx][globalDofIdx] + // = FluidSystem::density(fsInitial, oilPhaseIdx, intQuants.pvtRegionIndex()); + // + // if (!this->density_[gasPhaseIdx].empty()) + // this->density_[gasPhaseIdx][globalDofIdx] + // = FluidSystem::density(fsInitial, gasPhaseIdx, intQuants.pvtRegionIndex()); + // + // if (!this->invB_[oilPhaseIdx].empty()) + // this->invB_[oilPhaseIdx][globalDofIdx] + // = FluidSystem::inverseFormationVolumeFactor(fsInitial, oilPhaseIdx, intQuants.pvtRegionIndex()); + // + // if (!this->invB_[gasPhaseIdx].empty()) + // this->invB_[gasPhaseIdx][globalDofIdx] + // = FluidSystem::inverseFormationVolumeFactor(fsInitial, gasPhaseIdx, intQuants.pvtRegionIndex()); + // + // if (!this->viscosity_[oilPhaseIdx].empty()) + // this->viscosity_[oilPhaseIdx][globalDofIdx] + // = FluidSystem::viscosity(fsInitial, oilPhaseIdx, intQuants.pvtRegionIndex()); + // + // if (!this->viscosity_[gasPhaseIdx].empty()) + // this->viscosity_[gasPhaseIdx][globalDofIdx] + // = FluidSystem::viscosity(fsInitial, gasPhaseIdx, intQuants.pvtRegionIndex()); + // } + // + // // Adding Well RFT data + // const auto cartesianIdx = elemCtx.simulator().vanguard().cartesianIndex(globalDofIdx); + // if (this->oilConnectionPressures_.count(cartesianIdx) > 0) { + // this->oilConnectionPressures_[cartesianIdx] = getValue(fs.pressure(oilPhaseIdx)); + // } + // if (this->waterConnectionSaturations_.count(cartesianIdx) > 0) { + // this->waterConnectionSaturations_[cartesianIdx] = getValue(fs.saturation(waterPhaseIdx)); + // } + // if (this->gasConnectionSaturations_.count(cartesianIdx) > 0) { + // this->gasConnectionSaturations_[cartesianIdx] = getValue(fs.saturation(gasPhaseIdx)); + // } + // + // // tracers + // const auto& tracerModel = simulator_.problem().tracerModel(); + // if (! this->freeTracerConcentrations_.empty()) { + // for (int tracerIdx = 0; tracerIdx < tracerModel.numTracers(); ++tracerIdx) { + // if (this->freeTracerConcentrations_[tracerIdx].empty()) { + // continue; + // } + // this->freeTracerConcentrations_[tracerIdx][globalDofIdx] = + // tracerModel.freeTracerConcentration(tracerIdx, globalDofIdx); + // } + // } + // if (! this->solTracerConcentrations_.empty()) { + // for (int tracerIdx = 0; tracerIdx < tracerModel.numTracers(); ++tracerIdx) { + // if (this->solTracerConcentrations_[tracerIdx].empty()) { + // continue; + // } + // this->solTracerConcentrations_[tracerIdx][globalDofIdx] = + // tracerModel.solTracerConcentration(tracerIdx, globalDofIdx); + // + // } + // } + // + // // output residual + // for ( int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx ) + // { + // if (!this->residual_[phaseIdx].empty()) { + // const unsigned activeCompIdx = Indices::canonicalToActiveComponentIndex(FluidSystem::solventComponentIndex(phaseIdx)); + // this->residual_[phaseIdx][globalDofIdx] = modelResid[globalDofIdx][activeCompIdx]; + // } + // } + } + } + + void processElementFlows(const ElementContext& elemCtx) + { + OPM_TIMEBLOCK_LOCAL(processElementBlockData); + if (!std::is_same_v>) + return; + + // const auto& problem = elemCtx.simulator().problem(); + // for (unsigned dofIdx = 0; dofIdx < elemCtx.numPrimaryDof(/*timeIdx=*/0); ++dofIdx) { + // + // unsigned globalDofIdx = elemCtx.globalSpaceIndex(dofIdx, /*timeIdx=*/0); + // if (!problem.model().linearizer().getFlowsInfo().empty()) { + // const auto& flowsInf = problem.model().linearizer().getFlowsInfo(); + // auto flowsInfos = flowsInf[globalDofIdx]; + // for (auto& flowsInfo : flowsInfos) { + // if (flowsInfo.faceId >= 0) { + // if (!this->flows_[flowsInfo.faceId][gasCompIdx].empty()) { + // this->flows_[flowsInfo.faceId][gasCompIdx][globalDofIdx] + // = flowsInfo.flow[conti0EqIdx + Indices::canonicalToActiveComponentIndex(gasCompIdx)]; + // } + // if (!this->flows_[flowsInfo.faceId][oilCompIdx].empty()) { + // this->flows_[flowsInfo.faceId][oilCompIdx][globalDofIdx] + // = flowsInfo.flow[conti0EqIdx + Indices::canonicalToActiveComponentIndex(oilCompIdx)]; + // } + // if (!this->flows_[flowsInfo.faceId][waterCompIdx].empty()) { + // this->flows_[flowsInfo.faceId][waterCompIdx][globalDofIdx] + // = flowsInfo.flow[conti0EqIdx + Indices::canonicalToActiveComponentIndex(waterCompIdx)]; + // } + // } + // if (flowsInfo.faceId == -2) { + // if (!this->flowsn_[gasCompIdx].indices.empty()) { + // this->flowsn_[gasCompIdx].indices[flowsInfo.nncId] = flowsInfo.nncId; + // this->flowsn_[gasCompIdx].values[flowsInfo.nncId] + // = flowsInfo.flow[conti0EqIdx + Indices::canonicalToActiveComponentIndex(gasCompIdx)]; + // } + // if (!this->flowsn_[oilCompIdx].indices.empty()) { + // this->flowsn_[oilCompIdx].indices[flowsInfo.nncId] = flowsInfo.nncId; + // this->flowsn_[oilCompIdx].values[flowsInfo.nncId] + // = flowsInfo.flow[conti0EqIdx + Indices::canonicalToActiveComponentIndex(oilCompIdx)]; + // } + // if (!this->flowsn_[waterCompIdx].indices.empty()) { + // this->flowsn_[waterCompIdx].indices[flowsInfo.nncId] = flowsInfo.nncId; + // this->flowsn_[waterCompIdx].values[flowsInfo.nncId] + // = flowsInfo.flow[conti0EqIdx + Indices::canonicalToActiveComponentIndex(waterCompIdx)]; + // } + // } + // } + // } + // + // // flores + // if (!problem.model().linearizer().getFloresInfo().empty()) { + // const auto& floresInf = problem.model().linearizer().getFloresInfo(); + // auto floresInfos =floresInf[globalDofIdx]; + // for (auto& floresInfo : floresInfos) { + // if (floresInfo.faceId >= 0) { + // if (!this->flores_[floresInfo.faceId][gasCompIdx].empty()) { + // this->flores_[floresInfo.faceId][gasCompIdx][globalDofIdx] + // = floresInfo.flow[conti0EqIdx + Indices::canonicalToActiveComponentIndex(gasCompIdx)]; + // } + // if (!this->flores_[floresInfo.faceId][oilCompIdx].empty()) { + // this->flores_[floresInfo.faceId][oilCompIdx][globalDofIdx] + // = floresInfo.flow[conti0EqIdx + Indices::canonicalToActiveComponentIndex(oilCompIdx)]; + // } + // if (!this->flores_[floresInfo.faceId][waterCompIdx].empty()) { + // this->flores_[floresInfo.faceId][waterCompIdx][globalDofIdx] + // = floresInfo.flow[conti0EqIdx + Indices::canonicalToActiveComponentIndex(waterCompIdx)]; + // } + // } + // + // if (floresInfo.faceId == -2) { + // if (!this->floresn_[gasCompIdx].indices.empty()) { + // this->floresn_[gasCompIdx].indices[floresInfo.nncId] = floresInfo.nncId; + // this->floresn_[gasCompIdx].values[floresInfo.nncId] + // = floresInfo.flow[conti0EqIdx + Indices::canonicalToActiveComponentIndex(gasCompIdx)]; + // } + // if (!this->floresn_[oilCompIdx].indices.empty()) { + // this->floresn_[oilCompIdx].indices[floresInfo.nncId] = floresInfo.nncId; + // this->floresn_[oilCompIdx].values[floresInfo.nncId] + // = floresInfo.flow[conti0EqIdx + Indices::canonicalToActiveComponentIndex(oilCompIdx)]; + // } + // if (!this->floresn_[waterCompIdx].indices.empty()) { + // this->floresn_[waterCompIdx].indices[floresInfo.nncId] = floresInfo.nncId; + // this->floresn_[waterCompIdx].values[floresInfo.nncId] + // = floresInfo.flow[conti0EqIdx + Indices::canonicalToActiveComponentIndex(waterCompIdx)]; + // } + // } + // } + // } + // } + } + + void processElementBlockData(const ElementContext& elemCtx) + { + OPM_TIMEBLOCK_LOCAL(processElementBlockData); + if (!std::is_same>::value) + return; + // + // const auto& problem = elemCtx.simulator().problem(); + // for (unsigned dofIdx = 0; dofIdx < elemCtx.numPrimaryDof(/*timeIdx=*/0); ++dofIdx) { + // // Adding block data + // const auto globalDofIdx = elemCtx.globalSpaceIndex(dofIdx, /*timeIdx=*/0); + // const auto cartesianIdx = elemCtx.simulator().vanguard().cartesianIndex(globalDofIdx); + // const auto& intQuants = elemCtx.intensiveQuantities(dofIdx, /*timeIdx=*/0); + // const auto& fs = intQuants.fluidState(); + // for (auto& val : this->blockData_) { + // const auto& key = val.first; + // assert(key.second > 0); + // + // const auto cartesianIdxBlock = static_cast>>(key.second - 1); + // + // if (cartesianIdx == cartesianIdxBlock) { + // if ((key.first == "BWSAT") || (key.first == "BSWAT")) + // val.second = getValue(fs.saturation(waterPhaseIdx)); + // else if ((key.first == "BGSAT") || (key.first == "BSGAS")) + // val.second = getValue(fs.saturation(gasPhaseIdx)); + // else if ((key.first == "BOSAT") || (key.first == "BSOIL")) + // val.second = getValue(fs.saturation(oilPhaseIdx)); + // else if (key.first == "BNSAT") + // val.second = intQuants.solventSaturation().value(); + // else if ((key.first == "BPR") || (key.first == "BPRESSUR")) { + // if (FluidSystem::phaseIsActive(oilPhaseIdx)) + // val.second = getValue(fs.pressure(oilPhaseIdx)); + // else if (FluidSystem::phaseIsActive(gasPhaseIdx)) + // val.second = getValue(fs.pressure(gasPhaseIdx)); + // else if (FluidSystem::phaseIsActive(waterPhaseIdx)) + // val.second = getValue(fs.pressure(waterPhaseIdx)); + // } + // else if ((key.first == "BTCNFHEA") || (key.first == "BTEMP")) { + // if (FluidSystem::phaseIsActive(oilPhaseIdx)) + // val.second = getValue(fs.temperature(oilPhaseIdx)); + // else if (FluidSystem::phaseIsActive(gasPhaseIdx)) + // val.second = getValue(fs.temperature(gasPhaseIdx)); + // else if (FluidSystem::phaseIsActive(waterPhaseIdx)) + // val.second = getValue(fs.temperature(waterPhaseIdx)); + // } + // else if (key.first == "BWKR" || key.first == "BKRW") + // val.second = getValue(intQuants.relativePermeability(waterPhaseIdx)); + // else if (key.first == "BGKR" || key.first == "BKRG") + // val.second = getValue(intQuants.relativePermeability(gasPhaseIdx)); + // else if (key.first == "BOKR" || key.first == "BKRO") + // val.second = getValue(intQuants.relativePermeability(oilPhaseIdx)); + // else if (key.first == "BKROG") { + // const auto& materialParams = problem.materialLawParams(elemCtx, dofIdx, /* timeIdx = */ 0); + // const auto krog + // = MaterialLaw::template relpermOilInOilGasSystem(materialParams, fs); + // val.second = getValue(krog); + // } + // else if (key.first == "BKROW") { + // const auto& materialParams = problem.materialLawParams(elemCtx, dofIdx, /* timeIdx = */ 0); + // const auto krow + // = MaterialLaw::template relpermOilInOilWaterSystem(materialParams, fs); + // val.second = getValue(krow); + // } + // else if (key.first == "BWPC") + // val.second = getValue(fs.pressure(oilPhaseIdx)) - getValue(fs.pressure(waterPhaseIdx)); + // else if (key.first == "BGPC") + // val.second = getValue(fs.pressure(gasPhaseIdx)) - getValue(fs.pressure(oilPhaseIdx)); + // else if (key.first == "BWPR") + // val.second = getValue(fs.pressure(waterPhaseIdx)); + // else if (key.first == "BGPR") + // val.second = getValue(fs.pressure(gasPhaseIdx)); + // else if (key.first == "BVWAT" || key.first == "BWVIS") + // val.second = getValue(fs.viscosity(waterPhaseIdx)); + // else if (key.first == "BVGAS" || key.first == "BGVIS") + // val.second = getValue(fs.viscosity(gasPhaseIdx)); + // else if (key.first == "BVOIL" || key.first == "BOVIS") + // val.second = getValue(fs.viscosity(oilPhaseIdx)); + // else if ((key.first == "BODEN") || (key.first == "BDENO")) + // val.second = getValue(fs.density(oilPhaseIdx)); + // else if ((key.first == "BGDEN") || (key.first == "BDENG")) + // val.second = getValue(fs.density(gasPhaseIdx)); + // else if ((key.first == "BWDEN") || (key.first == "BDENW")) + // val.second = getValue(fs.density(waterPhaseIdx)); + // else if ((key.first == "BRPV") || + // (key.first == "BOPV") || + // (key.first == "BWPV") || + // (key.first == "BGPV")) + // { + // if (key.first == "BRPV") { + // val.second = 1.0; + // } + // else if (key.first == "BOPV") { + // val.second = getValue(fs.saturation(oilPhaseIdx)); + // } + // else if (key.first == "BWPV") { + // val.second = getValue(fs.saturation(waterPhaseIdx)); + // } + // else { + // val.second = getValue(fs.saturation(gasPhaseIdx)); + // } + // + // // Include active pore-volume. + // val.second *= getValue(intQuants.porosity()) + // * elemCtx.simulator().model().dofTotalVolume(globalDofIdx); + // } + // else if (key.first == "BRS") + // val.second = getValue(fs.Rs()); + // else if (key.first == "BRV") + // val.second = getValue(fs.Rv()); + // else if ((key.first == "BOIP") || (key.first == "BOIPL") || (key.first == "BOIPG") || + // (key.first == "BGIP") || (key.first == "BGIPL") || (key.first == "BGIPG") || + // (key.first == "BWIP")) + // { + // if ((key.first == "BOIP") || (key.first == "BOIPL")) { + // val.second = getValue(fs.invB(oilPhaseIdx)) * getValue(fs.saturation(oilPhaseIdx)); + // + // if (key.first == "BOIP") { + // val.second += getValue(fs.Rv()) * getValue(fs.invB(gasPhaseIdx)) + // * getValue(fs.saturation(gasPhaseIdx)); + // } + // } + // else if (key.first == "BOIPG") { + // val.second = getValue(fs.Rv()) * getValue(fs.invB(gasPhaseIdx)) + // * getValue(fs.saturation(gasPhaseIdx)); + // } + // else if ((key.first == "BGIP") || (key.first == "BGIPG")) { + // val.second = getValue(fs.invB(gasPhaseIdx)) * getValue(fs.saturation(gasPhaseIdx)); + // + // if (key.first == "BGIP") { + // if (!FluidSystem::phaseIsActive(oilPhaseIdx)) { + // val.second += getValue(fs.Rsw()) * getValue(fs.invB(waterPhaseIdx)) + // * getValue(fs.saturation(waterPhaseIdx)); + // } + // else { + // val.second += getValue(fs.Rs()) * getValue(fs.invB(oilPhaseIdx)) + // * getValue(fs.saturation(oilPhaseIdx)); + // } + // } + // } + // else if (key.first == "BGIPL") { + // if (!FluidSystem::phaseIsActive(oilPhaseIdx)) { + // val.second = getValue(fs.Rsw()) * getValue(fs.invB(waterPhaseIdx)) + // * getValue(fs.saturation(waterPhaseIdx)); + // } + // else { + // val.second = getValue(fs.Rs()) * getValue(fs.invB(oilPhaseIdx)) + // * getValue(fs.saturation(oilPhaseIdx)); + // } + // } + // else { // BWIP + // val.second = getValue(fs.invB(waterPhaseIdx)) * getValue(fs.saturation(waterPhaseIdx)); + // } + // + // // Include active pore-volume. + // val.second *= elemCtx.simulator().model().dofTotalVolume(globalDofIdx) + // * getValue(intQuants.porosity()); + // } + // else if ((key.first == "BPPO") || + // (key.first == "BPPG") || + // (key.first == "BPPW")) + // { + // auto phase = RegionPhasePoreVolAverage::Phase{}; + // + // if (key.first == "BPPO") { + // phase.ix = oilPhaseIdx; + // } + // else if (key.first == "BPPG") { + // phase.ix = gasPhaseIdx; + // } + // else { // BPPW + // phase.ix = waterPhaseIdx; + // } + // + // // Note different region handling here. FIPNUM is + // // one-based, but we need zero-based lookup in + // // DatumDepth. On the other hand, pvtRegionIndex is + // // zero-based but we need one-based lookup in + // // RegionPhasePoreVolAverage. + // + // // Subtract one to convert FIPNUM to region index. + // const auto datum = this->eclState_.getSimulationConfig() + // .datumDepths()(this->regions_["FIPNUM"][dofIdx] - 1); + // + // // Add one to convert region index to region ID. + // const auto region = RegionPhasePoreVolAverage::Region { + // elemCtx.primaryVars(dofIdx, /*timeIdx=*/0).pvtRegionIndex() + 1 + // }; + // + // const auto density = this->regionAvgDensity_ + // ->value("PVTNUM", phase, region); + // + // const auto press = getValue(fs.pressure(phase.ix)); + // const auto grav = + // elemCtx.problem().gravity()[GridView::dimensionworld - 1]; + // const auto dz = problem.dofCenterDepth(globalDofIdx) - datum; + // + // val.second = press - density*dz*grav; + // } + // else if ((key.first == "BFLOWI") || + // (key.first == "BFLOWJ") || + // (key.first == "BFLOWK")) + // { + // auto dir = FaceDir::ToIntersectionIndex(Dir::XPlus); + // + // if (key.first == "BFLOWJ") { + // dir = FaceDir::ToIntersectionIndex(Dir::YPlus); + // } + // else if (key.first == "BFLOWK") { + // dir = FaceDir::ToIntersectionIndex(Dir::ZPlus); + // } + // + // val.second = this->flows_[dir][waterCompIdx][globalDofIdx]; + // } + // else { + // std::string logstring = "Keyword '"; + // logstring.append(key.first); + // logstring.append("' is unhandled for output to summary file."); + // OpmLog::warning("Unhandled output keyword", logstring); + // } + // } + // } + // } + } + + /*! + * \brief Capture connection fluxes, particularly to account for inter-region flows. + * + * \tparam ActiveIndex Callable type, typically a lambda, that enables + * retrieving the active index, on the local MPI rank, of a + * particular cell/element. Must support a function call operator of + * the form + \code + int operator()(const Element& elem) const + \endcode + * + * \tparam CartesianIndex Callable type, typically a lambda, that + * enables retrieving the globally unique Cartesian index of a + * particular cell/element given its active index on the local MPI + * rank. Must support a function call operator of the form + \code + int operator()(const int activeIndex) const + \endcode + * + * \param[in] elemCtx Primary lookup structure for per-cell/element + * dynamic information. + * + * \param[in] activeIndex Mapping from cell/elements to linear indices + * on local MPI rank. + * + * \param[in] cartesianIndex Mapping from active index on local MPI rank + * to globally unique Cartesian cell/element index. + */ + template + void processFluxes(const ElementContext& elemCtx, + ActiveIndex&& activeIndex, + CartesianIndex&& cartesianIndex) + { + OPM_TIMEBLOCK_LOCAL(processFluxes); + const auto identifyCell = [&activeIndex, &cartesianIndex](const Element& elem) + -> InterRegFlowMap::Cell + { + const auto cellIndex = activeIndex(elem); + + return { + static_cast(cellIndex), + cartesianIndex(cellIndex), + elem.partitionType() == Dune::InteriorEntity + }; + }; + + const auto timeIdx = 0u; + const auto& stencil = elemCtx.stencil(timeIdx); + const auto numInteriorFaces = elemCtx.numInteriorFaces(timeIdx); + + for (auto scvfIdx = 0 * numInteriorFaces; scvfIdx < numInteriorFaces; ++scvfIdx) { + const auto& face = stencil.interiorFace(scvfIdx); + const auto left = identifyCell(stencil.element(face.interiorIndex())); + const auto right = identifyCell(stencil.element(face.exteriorIndex())); + + const auto rates = this-> + getComponentSurfaceRates(elemCtx, face.area(), scvfIdx, timeIdx); + + this->interRegionFlows_.addConnection(left, right, rates); + } + } + + /*! + * \brief Prepare for capturing connection fluxes, particularly to + * account for inter-region flows. + */ + void initializeFluxData() + { + // Inter-region flow rates. Note: ".clear()" prepares to accumulate + // contributions per bulk connection between FIP regions. + this->interRegionFlows_.clear(); + } + + /*! + * \brief Finalize capturing connection fluxes. + */ + void finalizeFluxData() + { + this->interRegionFlows_.compress(); + } + + /*! + * \brief Get read-only access to collection of inter-region flows. + */ + const InterRegFlowMap& getInterRegFlows() const + { + return this->interRegionFlows_; + } + + template + void assignToFluidState(FluidState& fs, unsigned elemIdx) const + { + for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { + if (this->saturation_[phaseIdx].empty()) + continue; + + fs.setSaturation(phaseIdx, this->saturation_[phaseIdx][elemIdx]); + } + + if (!this->fluidPressure_.empty()) { + // this assumes that capillary pressures only depend on the phase saturations + // and possibly on temperature. (this is always the case for ECL problems.) + std::array pc = {0}; + const MaterialLawParams& matParams = simulator_.problem().materialLawParams(elemIdx); + MaterialLaw::capillaryPressures(pc, matParams, fs); + Valgrind::CheckDefined(this->fluidPressure_[elemIdx]); + Valgrind::CheckDefined(pc); + assert(FluidSystem::phaseIsActive(oilPhaseIdx)); + for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { + if (!FluidSystem::phaseIsActive(phaseIdx)) + continue; + + fs.setPressure(phaseIdx, this->fluidPressure_[elemIdx] + (pc[phaseIdx] - pc[oilPhaseIdx])); + } + } + + if (!this->temperature_.empty()) + fs.setTemperature(this->temperature_[elemIdx]); + if (!this->rs_.empty()) + fs.setRs(this->rs_[elemIdx]); + if (!this->rsw_.empty()) + fs.setRsw(this->rsw_[elemIdx]); + if (!this->rv_.empty()) + fs.setRv(this->rv_[elemIdx]); + if (!this->rvw_.empty()) + fs.setRvw(this->rvw_[elemIdx]); + } + + void initHysteresisParams(Simulator& simulator, unsigned elemIdx) const + { + if (!this->soMax_.empty()) + simulator.problem().setMaxOilSaturation(elemIdx, this->soMax_[elemIdx]); + + if (simulator.problem().materialLawManager()->enableHysteresis()) { + auto matLawManager = simulator.problem().materialLawManager(); + + if (FluidSystem::phaseIsActive(oilPhaseIdx) + && FluidSystem::phaseIsActive(waterPhaseIdx)) { + Scalar somax = 2.0; + Scalar swmax = -2.0; + Scalar swmin = 2.0; + + if (matLawManager->enableNonWettingHysteresis()) { + if (!this->soMax_.empty()) { + somax = this->soMax_[elemIdx]; + } + } + if (matLawManager->enableWettingHysteresis()) { + if (!this->swMax_.empty()) { + swmax = this->swMax_[elemIdx]; + } + } + if (matLawManager->enablePCHysteresis()) { + if (!this->swmin_.empty()) { + swmin = this->swmin_[elemIdx]; + } + } + matLawManager->setOilWaterHysteresisParams( + somax, swmax, swmin, elemIdx); + } + if (FluidSystem::phaseIsActive(oilPhaseIdx) + && FluidSystem::phaseIsActive(gasPhaseIdx)) { + Scalar sgmax = 2.0; + Scalar shmax = -2.0; + Scalar somin = 2.0; + + if (matLawManager->enableNonWettingHysteresis()) { + if (!this->sgmax_.empty()) { + sgmax = this->sgmax_[elemIdx]; + } + } + if (matLawManager->enableWettingHysteresis()) { + if (!this->shmax_.empty()) { + shmax = this->shmax_[elemIdx]; + } + } + if (matLawManager->enablePCHysteresis()) { + if (!this->somin_.empty()) { + somin = this->somin_[elemIdx]; + } + } + matLawManager->setGasOilHysteresisParams( + sgmax, shmax, somin, elemIdx); + } + + } + + if (simulator_.vanguard().eclState().fieldProps().has_double("SWATINIT")) { + simulator.problem().materialLawManager() + ->applyRestartSwatInit(elemIdx, this->ppcw_[elemIdx]); + } + } + + void updateFluidInPlace(const ElementContext& elemCtx) + { + for (unsigned dofIdx = 0; dofIdx < elemCtx.numPrimaryDof(/*timeIdx=*/0); ++dofIdx) { + updateFluidInPlace_(elemCtx, dofIdx); + } + } + + void updateFluidInPlace(const unsigned globalDofIdx, + const IntensiveQuantities& intQuants, + const double totVolume) + { + this->updateFluidInPlace_(globalDofIdx, intQuants, totVolume); + } + +private: + bool isDefunctParallelWell(std::string wname) const override + { + if (simulator_.gridView().comm().size() == 1) + return false; + const auto& parallelWells = simulator_.vanguard().parallelWells(); + std::pair value {wname, true}; + auto candidate = std::lower_bound(parallelWells.begin(), parallelWells.end(), value); + return candidate == parallelWells.end() || *candidate != value; + } + + void updateFluidInPlace_(const ElementContext& elemCtx, const unsigned dofIdx) + { + const auto& intQuants = elemCtx.intensiveQuantities(dofIdx, /*timeIdx=*/0); + const unsigned globalDofIdx = elemCtx.globalSpaceIndex(dofIdx, /*timeIdx=*/0); + const auto totVolume = elemCtx.simulator().model().dofTotalVolume(globalDofIdx); + + this->updateFluidInPlace_(globalDofIdx, intQuants, totVolume); + } + + void updateFluidInPlace_(const unsigned globalDofIdx, + const IntensiveQuantities& intQuants, + const double totVolume) + { + OPM_TIMEBLOCK_LOCAL(updateFluidInPlace); + + this->updateTotalVolumesAndPressures_(globalDofIdx, intQuants, totVolume); + + if (this->computeFip_) { + this->updatePhaseInplaceVolumes_(globalDofIdx, intQuants, totVolume); + } + } + + void createLocalRegion_(std::vector& region) + { + std::size_t elemIdx = 0; + for (const auto& elem : elements(simulator_.gridView())) { + if (elem.partitionType() != Dune::InteriorEntity) { + region[elemIdx] = 0; + } + + ++elemIdx; + } + } + + template + void aggregateAverageDensityContributions_(const FluidState& fs, + const unsigned int globalDofIdx, + const double porv) + { + auto pvCellValue = RegionPhasePoreVolAverage::CellValue{}; + pvCellValue.porv = porv; + + for (auto phaseIdx = 0*FluidSystem::numPhases; + phaseIdx < FluidSystem::numPhases; ++phaseIdx) + { + if (! FluidSystem::phaseIsActive(phaseIdx)) { + continue; + } + + pvCellValue.value = getValue(fs.density(phaseIdx)); + pvCellValue.sat = getValue(fs.saturation(phaseIdx)); + + this->regionAvgDensity_ + ->addCell(globalDofIdx, + RegionPhasePoreVolAverage::Phase { phaseIdx }, + pvCellValue); + } + } + + /*! + * \brief Compute surface level component flow rates across a single + * intersection. + * + * \param[in] elemCtx Primary lookup structure for per-cell/element + * dynamic information. + * + * \param[in] scvfIdx Linear index of current interior bulk connection. + * + * \param[in] timeIdx Historical time-point at which to evaluate dynamic + * quantities (e.g., reciprocal FVF or dissolved gas concentration). + * Zero for the current time. + * + * \return Surface level component flow rates. + */ + data::InterRegFlowMap::FlowRates + getComponentSurfaceRates(const ElementContext& elemCtx, + const Scalar faceArea, + const std::size_t scvfIdx, + const std::size_t timeIdx) const + { + using Component = data::InterRegFlowMap::Component; + + auto rates = data::InterRegFlowMap::FlowRates {}; + // + // const auto& extQuant = elemCtx.extensiveQuantities(scvfIdx, timeIdx); + // + // const auto alpha = getValue(extQuant.extrusionFactor()) * faceArea; + // + // if (FluidSystem::phaseIsActive(oilPhaseIdx)) { + // const auto& up = elemCtx + // .intensiveQuantities(extQuant.upstreamIndex(oilPhaseIdx), timeIdx); + // + // using FluidState = std::remove_cv_t>; + // + // const auto pvtReg = up.pvtRegionIndex(); + // + // const auto bO = getValue(getInvB_ + // (up.fluidState(), oilPhaseIdx, pvtReg)); + // + // const auto qO = alpha * bO * getValue(extQuant.volumeFlux(oilPhaseIdx)); + // + // rates[Component::Oil] += qO; + // + // if (FluidSystem::phaseIsActive(gasPhaseIdx)) { + // const auto Rs = getValue( + // BlackOil::getRs_ + // (up.fluidState(), pvtReg)); + // + // rates[Component::Gas] += qO * Rs; + // rates[Component::Disgas] += qO * Rs; + // } + // } + // + // if (FluidSystem::phaseIsActive(gasPhaseIdx)) { + // const auto& up = elemCtx + // .intensiveQuantities(extQuant.upstreamIndex(gasPhaseIdx), timeIdx); + // + // using FluidState = std::remove_cv_t>; + // + // const auto pvtReg = up.pvtRegionIndex(); + // + // const auto bG = getValue(getInvB_ + // (up.fluidState(), gasPhaseIdx, pvtReg)); + // + // const auto qG = alpha * bG * getValue(extQuant.volumeFlux(gasPhaseIdx)); + // + // rates[Component::Gas] += qG; + // + // if (FluidSystem::phaseIsActive(oilPhaseIdx)) { + // const auto Rv = getValue( + // BlackOil::getRv_ + // (up.fluidState(), pvtReg)); + // + // rates[Component::Oil] += qG * Rv; + // rates[Component::Vapoil] += qG * Rv; + // } + // } + // + // if (FluidSystem::phaseIsActive(waterPhaseIdx)) { + // const auto& up = elemCtx + // .intensiveQuantities(extQuant.upstreamIndex(waterPhaseIdx), timeIdx); + // + // using FluidState = std::remove_cv_t>; + // + // const auto pvtReg = up.pvtRegionIndex(); + // + // const auto bW = getValue(getInvB_ + // (up.fluidState(), waterPhaseIdx, pvtReg)); + // + // rates[Component::Water] += + // alpha * bW * getValue(extQuant.volumeFlux(waterPhaseIdx)); + // } + + return rates; + } + + template + Scalar hydroCarbonFraction(const FluidState& fs) const + { + if (this->eclState_.runspec().co2Storage()) { + // CO2 storage: Hydrocarbon volume is full pore-volume. + return 1.0; + } + + // Common case. Hydrocarbon volume is fraction occupied by actual + // hydrocarbons. + auto hydrocarbon = Scalar {0}; + if (FluidSystem::phaseIsActive(oilPhaseIdx)) { + hydrocarbon += getValue(fs.saturation(oilPhaseIdx)); + } + + if (FluidSystem::phaseIsActive(gasPhaseIdx)) { + hydrocarbon += getValue(fs.saturation(gasPhaseIdx)); + } + + return hydrocarbon; + } + + void updateTotalVolumesAndPressures_(const unsigned globalDofIdx, + const IntensiveQuantities& intQuants, + const double totVolume) + { + const auto& fs = intQuants.fluidState(); + + const double pv = totVolume * intQuants.porosity().value(); + const auto hydrocarbon = this->hydroCarbonFraction(fs); + + if (! this->hydrocarbonPoreVolume_.empty()) { + this->fip_[Inplace::Phase::PoreVolume][globalDofIdx] = 0; +// totVolume * intQuants.referencePorosity(); + + this->dynamicPoreVolume_[globalDofIdx] = pv; + this->hydrocarbonPoreVolume_[globalDofIdx] = pv * hydrocarbon; + } + + if (!this->pressureTimesHydrocarbonVolume_.empty() && + !this->pressureTimesPoreVolume_.empty()) + { + assert(this->hydrocarbonPoreVolume_.size() == this->pressureTimesHydrocarbonVolume_.size()); + assert(this->fip_[Inplace::Phase::PoreVolume].size() == this->pressureTimesPoreVolume_.size()); + + if (FluidSystem::phaseIsActive(oilPhaseIdx)) { + this->pressureTimesPoreVolume_[globalDofIdx] = + getValue(fs.pressure(oilPhaseIdx)) * pv; + + this->pressureTimesHydrocarbonVolume_[globalDofIdx] = + this->pressureTimesPoreVolume_[globalDofIdx] * hydrocarbon; + } + else if (FluidSystem::phaseIsActive(gasPhaseIdx)) { + this->pressureTimesPoreVolume_[globalDofIdx] = + getValue(fs.pressure(gasPhaseIdx)) * pv; + + this->pressureTimesHydrocarbonVolume_[globalDofIdx] = + this->pressureTimesPoreVolume_[globalDofIdx] * hydrocarbon; + } + else if (FluidSystem::phaseIsActive(waterPhaseIdx)) { + this->pressureTimesPoreVolume_[globalDofIdx] = + getValue(fs.pressure(waterPhaseIdx)) * pv; + } + } + } + + void updatePhaseInplaceVolumes_(const unsigned globalDofIdx, + const IntensiveQuantities& intQuants, + const double totVolume) + { + // std::array fip {}; + // std::array fipr{}; // at reservoir condition + // + // const auto& fs = intQuants.fluidState(); + // const auto pv = totVolume * intQuants.porosity().value(); + // + // for (unsigned phaseIdx = 0; phaseIdx < FluidSystem::numPhases; ++phaseIdx) { + // if (!FluidSystem::phaseIsActive(phaseIdx)) { + // continue; + // } + // + // const auto b = getValue(fs.invB(phaseIdx)); + // const auto s = getValue(fs.saturation(phaseIdx)); + // + // fipr[phaseIdx] = s * pv; + // fip [phaseIdx] = b * fipr[phaseIdx]; + // } + // + // this->updateInplaceVolumesSurface(globalDofIdx, fip); + // this->updateInplaceVolumesReservoir(globalDofIdx, fs, fipr); + // + // if (FluidSystem::phaseIsActive(oilPhaseIdx) && + // FluidSystem::phaseIsActive(gasPhaseIdx)) + // { + // this->updateOilGasDistribution(globalDofIdx, fs, fip); + // } + // + // if (FluidSystem::phaseIsActive(waterPhaseIdx) && + // FluidSystem::phaseIsActive(gasPhaseIdx)) + // { + // this->updateGasWaterDistribution(globalDofIdx, fs, fip); + // } + // + // if (FluidSystem::phaseIsActive(gasPhaseIdx) && + // (!this->fip_[Inplace::Phase::CO2InGasPhaseInMob].empty() || + // !this->fip_[Inplace::Phase::CO2InGasPhaseMob].empty() || + // !this->fip_[Inplace::Phase::CO2MassInGasPhaseInMob].empty() || + // !this->fip_[Inplace::Phase::CO2MassInGasPhaseMob].empty() || + // !this->fip_[Inplace::Phase::CO2Mass].empty() || + // !this->fip_[Inplace::Phase::CO2MassInGasPhase].empty() || + // !this->fip_[Inplace::Phase::CO2InGasPhaseInMobKrg].empty() || + // !this->fip_[Inplace::Phase::CO2InGasPhaseMobKrg].empty() || + // !this->fip_[Inplace::Phase::CO2MassInGasPhaseInMobKrg].empty() || + // !this->fip_[Inplace::Phase::CO2MassInGasPhaseMobKrg].empty() || + // !this->fip_[Inplace::Phase::CO2MassInGasPhaseEffectiveTrapped].empty() || + // !this->fip_[Inplace::Phase::CO2MassInGasPhaseEffectiveUnTrapped].empty() || + // !this->fip_[Inplace::Phase::CO2MassInGasPhaseMaximumTrapped].empty() || + // !this->fip_[Inplace::Phase::CO2MassInGasPhaseMaximumUnTrapped].empty())) + // { + // this->updateCO2InGas(globalDofIdx, pv, intQuants); + // } + // + // if ((!this->fip_[Inplace::Phase::CO2InWaterPhase].empty() || + // !this->fip_[Inplace::Phase::CO2MassInWaterPhase].empty() || + // !this->fip_[Inplace::Phase::CO2Mass].empty()) && + // (FluidSystem::phaseIsActive(waterPhaseIdx) || + // FluidSystem::phaseIsActive(oilPhaseIdx))) + // { + // this->updateCO2InWater(globalDofIdx, pv, fs); + // } + } + + template + void updateInplaceVolumesSurface(const unsigned globalDofIdx, + const FIPArray& fip) + { + if (FluidSystem::phaseIsActive(oilPhaseIdx) && + !this->fip_[Inplace::Phase::OIL].empty()) + { + this->fip_[Inplace::Phase::OIL][globalDofIdx] = fip[oilPhaseIdx]; + } + + if (FluidSystem::phaseIsActive(oilPhaseIdx) && + !this->fip_[Inplace::Phase::OilInLiquidPhase].empty()) + { + this->fip_[Inplace::Phase::OilInLiquidPhase][globalDofIdx] = fip[oilPhaseIdx]; + } + + if (FluidSystem::phaseIsActive(gasPhaseIdx) && + !this->fip_[Inplace::Phase::GAS].empty()) + { + this->fip_[Inplace::Phase::GAS][globalDofIdx] = fip[gasPhaseIdx]; + } + + if (FluidSystem::phaseIsActive(gasPhaseIdx) && + !this->fip_[Inplace::Phase::GasInGasPhase].empty()) + { + this->fip_[Inplace::Phase::GasInGasPhase][globalDofIdx] = fip[gasPhaseIdx]; + } + + if (FluidSystem::phaseIsActive(waterPhaseIdx) && + !this->fip_[Inplace::Phase::WATER].empty()) + { + this->fip_[Inplace::Phase::WATER][globalDofIdx] = fip[waterPhaseIdx]; + } + } + + template + void updateInplaceVolumesReservoir(const unsigned globalDofIdx, + const FluidState& fs, + const FIPArray& fipr) + { + if (FluidSystem::phaseIsActive(oilPhaseIdx) && + !this->fip_[Inplace::Phase::OilResVolume].empty()) + { + this->fip_[Inplace::Phase::OilResVolume][globalDofIdx] = fipr[oilPhaseIdx]; + } + + if (FluidSystem::phaseIsActive(gasPhaseIdx) && + !this->fip_[Inplace::Phase::GasResVolume].empty()) + { + this->fip_[Inplace::Phase::GasResVolume][globalDofIdx] = fipr[gasPhaseIdx]; + } + + if (FluidSystem::phaseIsActive(waterPhaseIdx) && + !this->fip_[Inplace::Phase::WaterResVolume].empty()) + { + this->fip_[Inplace::Phase::WaterResVolume][globalDofIdx] = fipr[waterPhaseIdx]; + } + + if (FluidSystem::phaseIsActive(waterPhaseIdx) && + !this->fip_[Inplace::Phase::SALT].empty()) + { + this->fip_[Inplace::Phase::SALT][globalDofIdx] = + fipr[waterPhaseIdx] * fs.saltConcentration().value(); + } + } + + template + void updateOilGasDistribution(const unsigned globalDofIdx, + const FluidState& fs, + const FIPArray& fip) + { + // Gas dissolved in oil and vaporized oil + const auto gasInPlaceLiquid = getValue(fs.Rs()) * fip[oilPhaseIdx]; + const auto oilInPlaceGas = getValue(fs.Rv()) * fip[gasPhaseIdx]; + + if (!this->fip_[Inplace::Phase::GasInLiquidPhase].empty()) { + this->fip_[Inplace::Phase::GasInLiquidPhase][globalDofIdx] = gasInPlaceLiquid; + } + + if (!this->fip_[Inplace::Phase::OilInGasPhase].empty()) { + this->fip_[Inplace::Phase::OilInGasPhase][globalDofIdx] = oilInPlaceGas; + } + + // Add dissolved gas and vaporized oil to total Fip + if (!this->fip_[Inplace::Phase::OIL].empty()) { + this->fip_[Inplace::Phase::OIL][globalDofIdx] += oilInPlaceGas; + } + + if (!this->fip_[Inplace::Phase::GAS].empty()) { + this->fip_[Inplace::Phase::GAS][globalDofIdx] += gasInPlaceLiquid; + } + } + + template + void updateGasWaterDistribution(const unsigned globalDofIdx, + const FluidState& fs, + const FIPArray& fip) + { + // Gas dissolved in water and vaporized water + const auto gasInPlaceWater = getValue(fs.Rsw()) * fip[waterPhaseIdx]; + const auto waterInPlaceGas = getValue(fs.Rvw()) * fip[gasPhaseIdx]; + + if (!this->fip_[Inplace::Phase::WaterInGasPhase].empty()) { + this->fip_[Inplace::Phase::WaterInGasPhase][globalDofIdx] = waterInPlaceGas; + } + + if (!this->fip_[Inplace::Phase::WaterInWaterPhase].empty()) { + this->fip_[Inplace::Phase::WaterInWaterPhase][globalDofIdx] = fip[waterPhaseIdx]; + } + + // For water+gas cases the gas in water is added to the GIPL value + if (!this->fip_[Inplace::Phase::GasInLiquidPhase].empty() && + !FluidSystem::phaseIsActive(oilPhaseIdx)) + { + this->fip_[Inplace::Phase::GasInLiquidPhase][globalDofIdx] = gasInPlaceWater; + } + + // Add dissolved gas and vaporized water to total Fip + if (!this->fip_[Inplace::Phase::WATER].empty()) { + this->fip_[Inplace::Phase::WATER][globalDofIdx] += waterInPlaceGas; + } + + if (!this->fip_[Inplace::Phase::GAS].empty()) { + this->fip_[Inplace::Phase::GAS][globalDofIdx] += gasInPlaceWater; + } + } + + template + void updateCO2InGas(const unsigned globalDofIdx, + const double pv, + const IntensiveQuantities& intQuants) + { + const auto& scaledDrainageInfo = this->simulator_.problem().materialLawManager() + ->oilWaterScaledEpsInfoDrainage(globalDofIdx); + + const auto& fs = intQuants.fluidState(); + Scalar sgcr = scaledDrainageInfo.Sgcr; + if (this->simulator_.problem().materialLawManager()->enableHysteresis()) { + const auto& matParams = simulator_.problem().materialLawParams(globalDofIdx); + sgcr = MaterialLaw::trappedGasSaturation(matParams, /*maximumTrapping*/false); + } + + const Scalar sg = getValue(fs.saturation(gasPhaseIdx)); + const Scalar rhog = getValue(fs.density(gasPhaseIdx)); + const Scalar xgW = FluidSystem::phaseIsActive(waterPhaseIdx) + ? FluidSystem::convertRvwToXgW(getValue(fs.Rvw()), fs.pvtRegionIndex()) + : FluidSystem::convertRvToXgO(getValue(fs.Rv()), fs.pvtRegionIndex()); + + const Scalar mM = FluidSystem::molarMass(gasCompIdx, fs.pvtRegionIndex()); + const Scalar massGas = (1 - xgW) * pv * rhog; + if (!this->fip_[Inplace::Phase::CO2Mass].empty()) { + this->fip_[Inplace::Phase::CO2Mass][globalDofIdx] = massGas * sg; + } + + if (!this->fip_[Inplace::Phase::CO2MassInGasPhase].empty()) { + this->fip_[Inplace::Phase::CO2MassInGasPhase][globalDofIdx] = massGas * sg; + } + + if (!this->fip_[Inplace::Phase::CO2InGasPhaseInMob].empty()) { + const Scalar imMobileGas = massGas / mM * std::min(sgcr , sg); + this->fip_[Inplace::Phase::CO2InGasPhaseInMob][globalDofIdx] = imMobileGas; + } + + if (!this->fip_[Inplace::Phase::CO2InGasPhaseMob].empty()) { + const Scalar mobileGas = massGas / mM * std::max(Scalar{0.0}, sg - sgcr); + this->fip_[Inplace::Phase::CO2InGasPhaseMob][globalDofIdx] = mobileGas; + } + + if (!this->fip_[Inplace::Phase::CO2InGasPhaseInMobKrg].empty()) { + if (sgcr >= sg) { + const Scalar imMobileGasKrg = massGas / mM * sg; + this->fip_[Inplace::Phase::CO2InGasPhaseInMobKrg][globalDofIdx] = imMobileGasKrg; + } else { + this->fip_[Inplace::Phase::CO2InGasPhaseInMobKrg][globalDofIdx] = 0; + } + } + + if (!this->fip_[Inplace::Phase::CO2InGasPhaseMobKrg].empty()) { + if (sg > sgcr) { + const Scalar mobileGasKrg = massGas / mM * sg; + this->fip_[Inplace::Phase::CO2InGasPhaseMobKrg][globalDofIdx] = mobileGasKrg; + } else { + this->fip_[Inplace::Phase::CO2InGasPhaseMobKrg][globalDofIdx] = 0; + } + } + + if (!this->fip_[Inplace::Phase::CO2MassInGasPhaseInMob].empty()) { + const Scalar imMobileMassGas = massGas * std::min(sgcr , sg); + this->fip_[Inplace::Phase::CO2MassInGasPhaseInMob][globalDofIdx] = imMobileMassGas; + } + + if (!this->fip_[Inplace::Phase::CO2MassInGasPhaseMob].empty()) { + const Scalar mobileMassGas = massGas * std::max(Scalar{0.0}, sg - sgcr); + this->fip_[Inplace::Phase::CO2MassInGasPhaseMob][globalDofIdx] = mobileMassGas; + } + + if (!this->fip_[Inplace::Phase::CO2MassInGasPhaseInMobKrg].empty()) { + if (sgcr >= sg) { + const Scalar imMobileMassGasKrg = massGas * sg; + this->fip_[Inplace::Phase::CO2MassInGasPhaseInMobKrg][globalDofIdx] = imMobileMassGasKrg; + } else { + this->fip_[Inplace::Phase::CO2MassInGasPhaseInMobKrg][globalDofIdx] = 0; + } + } + + if (!this->fip_[Inplace::Phase::CO2MassInGasPhaseMobKrg].empty()) { + if (sg > sgcr) { + const Scalar mobileMassGasKrg = massGas * sg; + this->fip_[Inplace::Phase::CO2MassInGasPhaseMobKrg][globalDofIdx] = mobileMassGasKrg; + } else { + this->fip_[Inplace::Phase::CO2MassInGasPhaseMobKrg][globalDofIdx] = 0; + } + } + + if (!this->fip_[Inplace::Phase::CO2MassInGasPhaseMaximumTrapped].empty() || + !this->fip_[Inplace::Phase::CO2MassInGasPhaseMaximumUnTrapped].empty() ) { + Scalar trappedGasSaturation = scaledDrainageInfo.Sgcr; + if (this->simulator_.problem().materialLawManager()->enableHysteresis()) { + const auto& matParams = simulator_.problem().materialLawParams(globalDofIdx); + // Get the maximum trapped gas saturation + trappedGasSaturation = MaterialLaw::trappedGasSaturation(matParams, /*maximumTrapping*/true); + } + if (!this->fip_[Inplace::Phase::CO2MassInGasPhaseMaximumTrapped].empty()) { + const Scalar imMobileMassGas = massGas * std::min(trappedGasSaturation , sg); + this->fip_[Inplace::Phase::CO2MassInGasPhaseMaximumTrapped][globalDofIdx] = imMobileMassGas; + } + if (!this->fip_[Inplace::Phase::CO2MassInGasPhaseMaximumUnTrapped].empty()) { + const Scalar mobileMassGas = massGas * std::max(Scalar{0.0}, sg - trappedGasSaturation); + this->fip_[Inplace::Phase::CO2MassInGasPhaseMaximumUnTrapped][globalDofIdx] = mobileMassGas; + } + } + + if (!this->fip_[Inplace::Phase::CO2MassInGasPhaseEffectiveTrapped].empty() || + !this->fip_[Inplace::Phase::CO2MassInGasPhaseEffectiveUnTrapped].empty()) { + Scalar trappedGasSaturation = scaledDrainageInfo.Sgcr; + if (this->simulator_.problem().materialLawManager()->enableHysteresis()) { + const auto& matParams = simulator_.problem().materialLawParams(globalDofIdx); + const double krg = getValue(intQuants.relativePermeability(gasPhaseIdx)); + trappedGasSaturation = MaterialLaw::strandedGasSaturation(matParams, sg, krg); + } + if (!this->fip_[Inplace::Phase::CO2MassInGasPhaseEffectiveTrapped].empty()) { + const Scalar imMobileMassGas = massGas * std::min(trappedGasSaturation , sg); + this->fip_[Inplace::Phase::CO2MassInGasPhaseEffectiveTrapped][globalDofIdx] = imMobileMassGas; + } + if (!this->fip_[Inplace::Phase::CO2MassInGasPhaseEffectiveUnTrapped].empty()) { + const Scalar mobileMassGas = massGas * std::max(Scalar{0.0}, sg - trappedGasSaturation); + this->fip_[Inplace::Phase::CO2MassInGasPhaseEffectiveUnTrapped][globalDofIdx] = mobileMassGas; + } + } + } + + template + void updateCO2InWater(const unsigned globalDofIdx, + const double pv, + const FluidState& fs) + { + const auto co2InWater = FluidSystem::phaseIsActive(oilPhaseIdx) + ? this->co2InWaterFromOil(fs, pv) + : this->co2InWaterFromWater(fs, pv); + + const Scalar mM = FluidSystem::molarMass(gasCompIdx, fs.pvtRegionIndex()); + if (!this->fip_[Inplace::Phase::CO2Mass].empty()) { + this->fip_[Inplace::Phase::CO2Mass][globalDofIdx] += co2InWater * mM; + } + if (!this->fip_[Inplace::Phase::CO2MassInWaterPhase].empty()) { + this->fip_[Inplace::Phase::CO2MassInWaterPhase][globalDofIdx] = co2InWater * mM; + } + if (!this->fip_[Inplace::Phase::CO2InWaterPhase].empty()) { + this->fip_[Inplace::Phase::CO2InWaterPhase][globalDofIdx] = co2InWater; + } + } + + template + Scalar co2InWaterFromWater(const FluidState& fs, const double pv) const + { + const double rhow = getValue(fs.density(waterPhaseIdx)); + const double sw = getValue(fs.saturation(waterPhaseIdx)); + const double xwG = FluidSystem::convertRswToXwG(getValue(fs.Rsw()), fs.pvtRegionIndex()); + + const Scalar mM = FluidSystem::molarMass(gasCompIdx, fs.pvtRegionIndex()); + + return xwG * pv * rhow * sw / mM; + } + + template + Scalar co2InWaterFromOil(const FluidState& fs, const double pv) const + { + const double rhoo = getValue(fs.density(oilPhaseIdx)); + const double so = getValue(fs.saturation(oilPhaseIdx)); + const double xoG = FluidSystem::convertRsToXoG(getValue(fs.Rs()), fs.pvtRegionIndex()); + + const Scalar mM = FluidSystem::molarMass(gasCompIdx, fs.pvtRegionIndex()); + + return xoG * pv * rhoo * so / mM; + } + + const Simulator& simulator_; +}; + +} // namespace Opm + +#endif // OPM_OUTPUT_BLACK_OIL_MODULE_HPP diff --git a/opm/simulators/flow/SimulatorFullyImplicitBlackoil.hpp b/opm/simulators/flow/SimulatorFullyImplicitBlackoil.hpp index 796177bf7..c7cf62c30 100644 --- a/opm/simulators/flow/SimulatorFullyImplicitBlackoil.hpp +++ b/opm/simulators/flow/SimulatorFullyImplicitBlackoil.hpp @@ -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(); diff --git a/opm/simulators/timestepping/AdaptiveTimeStepping.hpp b/opm/simulators/timestepping/AdaptiveTimeStepping.hpp index bd6accd82..485afca1b 100644 --- a/opm/simulators/timestepping/AdaptiveTimeStepping.hpp +++ b/opm/simulators/timestepping/AdaptiveTimeStepping.hpp @@ -353,7 +353,7 @@ void registerAdaptiveParameters(); time::StopWatch perfTimer; perfTimer.start(); - problem.writeOutput(); + problem.writeOutput(true); report.success.output_write_time += perfTimer.secsSinceStart(); } From ad587e77ad08ca7554fa1c12c94b69d9c607d8b2 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Mon, 14 Oct 2024 14:57:46 +0200 Subject: [PATCH 02/15] output XMF ,YMF and ZMF in UNRST file. currently, it looks the value for ZMF is based on XMF and YMF. ideally, the ZMF is part of the primary varialbes, it does not need to be calculated based on XMF and YMF. there is some refactoring that we can do here. --- .../ptflash/flashintensivequantities.hh | 6 +++ opm/models/ptflash/flashprimaryvariables.hh | 16 +----- opm/simulators/flow/FlowProblemComp.hpp | 43 +++++++++++----- .../flow/GenericOutputCompositionalModule.cpp | 49 ++++++++++++++++++- .../flow/GenericOutputCompositionalModule.hpp | 1 + opm/simulators/flow/OutputBlackoilModule.hpp | 13 +++-- .../flow/OutputCompositionalModule.hpp | 24 +++++++-- 7 files changed, 116 insertions(+), 36 deletions(-) diff --git a/opm/models/ptflash/flashintensivequantities.hh b/opm/models/ptflash/flashintensivequantities.hh index 52f3c309b..098e836e6 100644 --- a/opm/models/ptflash/flashintensivequantities.hh +++ b/opm/models/ptflash/flashintensivequantities.hh @@ -113,6 +113,8 @@ public: const Scalar flashTolerance = Parameters::Get>(); const int flashVerbosity = Parameters::Get(); const std::string flashTwoPhaseMethod = Parameters::Get(); + // TODO: the formulation here is still to begin with XMF and YMF values to derive ZMF value + // TODO: we should check how we update ZMF in the newton update, since it is the primary variables. // extract the total molar densities of the components ComponentVector z(0.); @@ -132,6 +134,10 @@ public: z /= sumz; } + for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) { + fluidState_.setMoleFraction(compIdx, z[compIdx]); + } + Evaluation p = priVars.makeEvaluation(pressure0Idx, timeIdx); for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) fluidState_.setPressure(phaseIdx, p); diff --git a/opm/models/ptflash/flashprimaryvariables.hh b/opm/models/ptflash/flashprimaryvariables.hh index 2c84db947..258209ace 100644 --- a/opm/models/ptflash/flashprimaryvariables.hh +++ b/opm/models/ptflash/flashprimaryvariables.hh @@ -120,22 +120,10 @@ public: // the energy module EnergyModule::setPriVarTemperatures(*this, fluidState); - // determine the component fractions - Dune::FieldVector z(0.0); - Scalar sumMoles = 0.0; - for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { - for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) { - Scalar tmp = Opm::getValue(fluidState.molarity(phaseIdx, compIdx) * fluidState.saturation(phaseIdx)); - z[compIdx] += Opm::max(tmp, 1e-8); - sumMoles += tmp; - } - } - z /= sumMoles; - for (int i = 0; i < numComponents - 1; ++i) - (*this)[z0Idx + i] = z[i]; + (*this)[z0Idx + i] = getValue(fluidState.moleFraction(i)); - (*this)[pressure0Idx] = Opm::getValue(fluidState.pressure(0)); + (*this)[pressure0Idx] = getValue(fluidState.pressure(0)); } /*! diff --git a/opm/simulators/flow/FlowProblemComp.hpp b/opm/simulators/flow/FlowProblemComp.hpp index 619985c5f..86f6774e8 100644 --- a/opm/simulators/flow/FlowProblemComp.hpp +++ b/opm/simulators/flow/FlowProblemComp.hpp @@ -326,25 +326,26 @@ public: { const unsigned globalDofIdx = context.globalSpaceIndex(spaceIdx, timeIdx); const auto& initial_fs = initialFluidStates_[globalDofIdx]; - Opm::CompositionalFluidState fs; - using ComponentVector = Dune::FieldVector; + Opm::CompositionalFluidState fs; + // TODO: the current approach is assuming we begin with XMF and YMF. + // TODO: maybe we should make it begin with ZMF + using ComponentVector = Dune::FieldVector; for (unsigned p = 0; p < numPhases; ++p) { // TODO: assuming the phaseidx continuous - ComponentVector evals; - auto& last_eval = evals[numComponents - 1]; + ComponentVector vals; + auto& last_eval = vals[numComponents - 1]; last_eval = 1.; for (unsigned c = 0; c < numComponents - 1; ++c) { const auto val = initial_fs.moleFraction(p, c); - const Evaluation eval = Evaluation::createVariable(val, c + 1); - evals[c] = eval; - last_eval -= eval; + vals[c] = val; + last_eval -= val; } for (unsigned c = 0; c < numComponents; ++c) { - fs.setMoleFraction(p, c, evals[c]); + fs.setMoleFraction(p, c, vals[c]); } // pressure const auto p_val = initial_fs.pressure(p); - fs.setPressure(p, Evaluation::createVariable(p_val, 0)); + fs.setPressure(p, p_val); const auto sat_val = initial_fs.saturation(p); fs.setSaturation(p, sat_val); @@ -354,7 +355,7 @@ public: } { - typename FluidSystem::template ParameterCache paramCache; + typename FluidSystem::template ParameterCache paramCache; paramCache.updatePhase(fs, FluidSystem::oilPhaseIdx); paramCache.updatePhase(fs, FluidSystem::gasPhaseIdx); fs.setDensity(FluidSystem::oilPhaseIdx, FluidSystem::density(fs, paramCache, FluidSystem::oilPhaseIdx)); @@ -363,13 +364,29 @@ public: fs.setViscosity(FluidSystem::gasPhaseIdx, FluidSystem::viscosity(fs, paramCache, FluidSystem::gasPhaseIdx)); } + // determine the component fractions + Dune::FieldVector z(0.0); + Scalar sumMoles = 0.0; + for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { + for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) { + Scalar tmp = Opm::getValue(fs.molarity(phaseIdx, compIdx) * fs.saturation(phaseIdx)); + z[compIdx] += Opm::max(tmp, 1e-8); + sumMoles += tmp; + } + } + z /= sumMoles; + // Set initial K and L for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) { - const Evaluation Ktmp = fs.wilsonK_(compIdx); + const auto& Ktmp = fs.wilsonK_(compIdx); fs.setKvalue(compIdx, Ktmp); } - const Evaluation& Ltmp = -1.0; + for (unsigned compIdx = 0; compIdx < numComponents - 1; ++compIdx) { + fs.setMoleFraction(compIdx, z[compIdx]); + } + + const Scalar& Ltmp = -1.0; fs.setLvalue(Ltmp); values.assignNaive(fs); @@ -540,6 +557,8 @@ protected: for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) { const std::size_t data_idx = compIdx * numDof + dofIdx; const Scalar zmf = zmfData[data_idx]; + dofFluidState.setMoleFraction(compIdx, zmf); + if (gas_active) { const auto ymf = (dofFluidState.saturation(FluidSystem::gasPhaseIdx) > 0.) ? zmf : Scalar{0}; dofFluidState.setMoleFraction(FluidSystem::gasPhaseIdx, compIdx, ymf); diff --git a/opm/simulators/flow/GenericOutputCompositionalModule.cpp b/opm/simulators/flow/GenericOutputCompositionalModule.cpp index dc3a32440..1d893a367 100644 --- a/opm/simulators/flow/GenericOutputCompositionalModule.cpp +++ b/opm/simulators/flow/GenericOutputCompositionalModule.cpp @@ -25,8 +25,8 @@ #include -#include -#include +// #include +// #include #include @@ -590,6 +590,32 @@ assignToSolution(data::Solution& sol) DataEntry{"UREA", UnitSystem::measure::density, cUrea_}, }; + auto compositionalEntries = std::vector{}; + + { + // ZMF + for (int i = 0; i < numComponents; ++i) { + const std::string name = "ZMF" + std::to_string(i + 1); // Generate ZMF1, ZMF2, ... + compositionalEntries.emplace_back(name, UnitSystem::measure::identity, moleFractions_[i]); + } + + // XMF + for (int i = 0; i < numComponents; ++i) { + const std::string name = "XMF" + std::to_string(i + 1); // Generate XMF1, XMF2, ... + compositionalEntries.emplace_back(name, UnitSystem::measure::identity, phaseMoleFractions_[oilPhaseIdx][i]); + } + + // YMF + for (int i = 0; i < numComponents; ++i) { + const std::string name = "YMF" + std::to_string(i + 1); // Generate YMF1, YMF2, ... + compositionalEntries.emplace_back(name, UnitSystem::measure::identity, phaseMoleFractions_[gasPhaseIdx][i]); + } + } + + for (const auto& array : compositionalEntries) { + doInsert(array, data::TargetType::RESTART_SOLUTION); + } + // basically, for compositional, we can not use std::array for this. We need to generate the ZMF1, ZMF2, and so on // and also, we need to map these values. @@ -1459,8 +1485,27 @@ doAllocBuffers(const unsigned bufferSize, } if (rstKeywords["ZMF"] > 0) { + rstKeywords["ZMF"] = 0; + for (int i = 0; i < numComponents; ++i) { + moleFractions_[i].resize(bufferSize, 0.0); + } } + if (rstKeywords["XMF"] > 0 && FluidSystem::phaseIsActive(oilPhaseIdx)) { + rstKeywords["XMF"] = 0; + for (int i = 0; i < numComponents; ++i) { + phaseMoleFractions_[oilPhaseIdx][i].resize(bufferSize, 0.0); + } + } + + if (rstKeywords["YMF"] > 0 && FluidSystem::phaseIsActive(gasPhaseIdx)) { + rstKeywords["YMF"] = 0; + for (int i = 0; i < numComponents; ++i) { + phaseMoleFractions_[gasPhaseIdx][i].resize(bufferSize, 0.0); + } + } + + //Warn for any unhandled keyword if (log) { for (auto& keyValue: rstKeywords) { diff --git a/opm/simulators/flow/GenericOutputCompositionalModule.hpp b/opm/simulators/flow/GenericOutputCompositionalModule.hpp index 4b863cc41..998411602 100644 --- a/opm/simulators/flow/GenericOutputCompositionalModule.hpp +++ b/opm/simulators/flow/GenericOutputCompositionalModule.hpp @@ -536,6 +536,7 @@ protected: std::array relativePermeability_; std::array moleFractions_; + std::array, numPhases> phaseMoleFractions_; std::vector freeTracerConcentrations_; std::vector solTracerConcentrations_; diff --git a/opm/simulators/flow/OutputBlackoilModule.hpp b/opm/simulators/flow/OutputBlackoilModule.hpp index c3fb57d31..13d24d12f 100644 --- a/opm/simulators/flow/OutputBlackoilModule.hpp +++ b/opm/simulators/flow/OutputBlackoilModule.hpp @@ -65,13 +65,16 @@ #include #include -//namespace Opm::Parameters { +// TODO: EclWriter how includes both OutputBlackoilModule and OutputCompositionalModule, so the following are defined twice +// Will see whether some refactoring are needed here. + +// namespace Opm::Parameters { // -//struct ForceDisableFluidInPlaceOutput { static constexpr bool value = false; }; -//struct ForceDisableResvFluidInPlaceOutput { static constexpr bool value = false; }; -// -//} // namespace Opm::Parameters +// struct ForceDisableFluidInPlaceOutput { static constexpr bool value = false; }; +// struct ForceDisableResvFluidInPlaceOutput { static constexpr bool value = false; }; // +// } // namespace Opm::Parameters + namespace Opm { diff --git a/opm/simulators/flow/OutputCompositionalModule.hpp b/opm/simulators/flow/OutputCompositionalModule.hpp index 982e7227f..3e370cdb0 100644 --- a/opm/simulators/flow/OutputCompositionalModule.hpp +++ b/opm/simulators/flow/OutputCompositionalModule.hpp @@ -39,8 +39,8 @@ #include #include -#include -#include +// #include +// #include #include #include @@ -106,6 +106,7 @@ class OutputCompositionalModule : public GenericOutputCompositionalModulesetupBlockData(isCartIdxOnThisRank); + this->setupBlockData(isCartIdxOnThisRank); this->forceDisableFipOutput_ = Parameters::Get(); @@ -296,6 +297,23 @@ public: Valgrind::CheckDefined(this->saturation_[phaseIdx][globalDofIdx]); } + for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) { + if (this->moleFractions_[compIdx].empty()) continue; + + this->moleFractions_[compIdx][globalDofIdx] = getValue(fs.moleFraction(compIdx)); + } + // XMF and YMF + for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) { + if (FluidSystem::phaseIsActive(oilPhaseIdx)) { + if (this->phaseMoleFractions_[oilPhaseIdx][compIdx].empty()) continue; + this->phaseMoleFractions_[oilPhaseIdx][compIdx][globalDofIdx] = getValue(fs.moleFraction(oilPhaseIdx, compIdx)); + } + if (FluidSystem::phaseIsActive(gasPhaseIdx)) { + if (this->phaseMoleFractions_[gasPhaseIdx][compIdx].empty()) continue; + this->phaseMoleFractions_[gasPhaseIdx][compIdx][globalDofIdx] = getValue(fs.moleFraction(gasPhaseIdx, compIdx)); + } + } + // if (this->regionAvgDensity_.has_value()) { // // Note: We intentionally exclude effects of rock // // compressibility by using referencePorosity() here. From a8d2c5bc2ce6d260917836747c66bea326a6df29 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Wed, 16 Oct 2024 13:49:35 +0200 Subject: [PATCH 03/15] removing GenericOutputCompositionalModule we do the compostional related in GenericOutputBlackoilModule to minimize the code change. there needs to be refatoring for GenericOutputBlackoilModule to split the black oil and compostional related. --- CMakeLists_files.cmake | 2 - .../flow/GenericOutputBlackoilModule.cpp | 73 + .../flow/GenericOutputBlackoilModule.hpp | 18 +- .../flow/GenericOutputCompositionalModule.cpp | 1786 ----------------- .../flow/GenericOutputCompositionalModule.hpp | 567 ------ .../flow/OutputCompositionalModule.hpp | 7 +- 6 files changed, 88 insertions(+), 2365 deletions(-) delete mode 100644 opm/simulators/flow/GenericOutputCompositionalModule.cpp delete mode 100644 opm/simulators/flow/GenericOutputCompositionalModule.hpp diff --git a/CMakeLists_files.cmake b/CMakeLists_files.cmake index 8e11d2038..9caf1e8a8 100644 --- a/CMakeLists_files.cmake +++ b/CMakeLists_files.cmake @@ -98,7 +98,6 @@ 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 @@ -818,7 +817,6 @@ 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 diff --git a/opm/simulators/flow/GenericOutputBlackoilModule.cpp b/opm/simulators/flow/GenericOutputBlackoilModule.cpp index e1d218c31..027eef1ee 100644 --- a/opm/simulators/flow/GenericOutputBlackoilModule.cpp +++ b/opm/simulators/flow/GenericOutputBlackoilModule.cpp @@ -28,6 +28,8 @@ #include #include +#include + #include #include @@ -624,6 +626,33 @@ assignToSolution(data::Solution& sol) DataEntry{"UREA", UnitSystem::measure::density, cUrea_}, }; + // basically, for compositional, we can not use std::array for this. We need to generate the ZMF1, ZMF2, and so on + // and also, we need to map these values. + auto compositionalEntries = std::vector{}; + { + // ZMF + for (int i = 0; i < numComponents; ++i) { + const std::string name = "ZMF" + std::to_string(i + 1); // Generate ZMF1, ZMF2, ... + compositionalEntries.emplace_back(name, UnitSystem::measure::identity, moleFractions_[i]); + } + + // XMF + for (int i = 0; i < numComponents; ++i) { + const std::string name = "XMF" + std::to_string(i + 1); // Generate XMF1, XMF2, ... + compositionalEntries.emplace_back(name, UnitSystem::measure::identity, phaseMoleFractions_[oilPhaseIdx][i]); + } + + // YMF + for (int i = 0; i < numComponents; ++i) { + const std::string name = "YMF" + std::to_string(i + 1); // Generate YMF1, YMF2, ... + compositionalEntries.emplace_back(name, UnitSystem::measure::identity, phaseMoleFractions_[gasPhaseIdx][i]); + } + } + + for (const auto& array : compositionalEntries) { + doInsert(array, data::TargetType::RESTART_SOLUTION); + } + for (const auto& array : baseSolutionArrays) { doInsert(array, data::TargetType::RESTART_SOLUTION); } @@ -659,6 +688,15 @@ assignToSolution(data::Solution& sol) std::move(this->saturation_[gasPhaseIdx]), data::TargetType::RESTART_SOLUTION); } + + if (FluidSystem::phaseIsActive(oilPhaseIdx) && + ! this->saturation_[oilPhaseIdx].empty()) + { + sol.insert("SOIL", UnitSystem::measure::identity, + std::move(this->saturation_[oilPhaseIdx]), + data::TargetType::RESTART_SOLUTION); + } + if ((eclState_.runspec().co2Storage() || eclState_.runspec().h2Storage()) && !rsw_.empty()) { auto mfrac = std::vector(this->rsw_.size(), 0.0); @@ -1481,6 +1519,28 @@ doAllocBuffers(const unsigned bufferSize, overburdenPressure_.resize(bufferSize, 0.0); } + if (rstKeywords["ZMF"] > 0) { + rstKeywords["ZMF"] = 0; + for (int i = 0; i < numComponents; ++i) { + moleFractions_[i].resize(bufferSize, 0.0); + } + } + + if (rstKeywords["XMF"] > 0 && FluidSystem::phaseIsActive(oilPhaseIdx)) { + rstKeywords["XMF"] = 0; + for (int i = 0; i < numComponents; ++i) { + phaseMoleFractions_[oilPhaseIdx][i].resize(bufferSize, 0.0); + } + } + + if (rstKeywords["YMF"] > 0 && FluidSystem::phaseIsActive(gasPhaseIdx)) { + rstKeywords["YMF"] = 0; + for (int i = 0; i < numComponents; ++i) { + phaseMoleFractions_[gasPhaseIdx][i].resize(bufferSize, 0.0); + } + } + + //Warn for any unhandled keyword if (log) { for (auto& keyValue: rstKeywords) { @@ -1752,4 +1812,17 @@ INSTANTIATE_TYPE(double) INSTANTIATE_TYPE(float) #endif +#define INSTANTIATE_COMP(NUM) \ + template using FS##NUM = GenericOilGasFluidSystem; \ + template class GenericOutputBlackoilModule>; + +//INSTANTIATE_COMP(2) +INSTANTIATE_COMP(3) +//INSTANTIATE_COMP(4) +//INSTANTIATE_COMP(5) +//INSTANTIATE_COMP(6) +//INSTANTIATE_COMP(7) +// template class GenericOutputBlackoilModule>; + + } // namespace Opm diff --git a/opm/simulators/flow/GenericOutputBlackoilModule.hpp b/opm/simulators/flow/GenericOutputBlackoilModule.hpp index b7d8c2769..9281f0467 100644 --- a/opm/simulators/flow/GenericOutputBlackoilModule.hpp +++ b/opm/simulators/flow/GenericOutputBlackoilModule.hpp @@ -342,13 +342,13 @@ protected: const bool substep, const bool log, const bool isRestart, - const bool vapparsActive, - const bool enablePCHysteresis, - const bool enableNonWettingHysteresis, - const bool enableWettingHysteresis, - unsigned numTracers, - const std::vector& enableSolTracers, - unsigned numOutputNnc); + const bool vapparsActive = false, + const bool enablePCHysteresis = false, + const bool enableNonWettingHysteresis =false, + const bool enableWettingHysteresis = false, + unsigned numTracers = 0, + const std::vector& enableSolTracers = {}, + unsigned numOutputNnc = 0); void makeRegionSum(Inplace& inplace, const std::string& region_name, @@ -539,6 +539,10 @@ protected: std::array viscosity_; std::array relativePermeability_; + // totoal mole fractions for each component + std::array moleFractions_; + // mole fractions for each component in each phase + std::array, numPhases> phaseMoleFractions_; std::vector freeTracerConcentrations_; std::vector solTracerConcentrations_; diff --git a/opm/simulators/flow/GenericOutputCompositionalModule.cpp b/opm/simulators/flow/GenericOutputCompositionalModule.cpp deleted file mode 100644 index 1d893a367..000000000 --- a/opm/simulators/flow/GenericOutputCompositionalModule.cpp +++ /dev/null @@ -1,1786 +0,0 @@ -// -*- 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 . - 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. -*/ - -#include -#include - -#include - -// #include -// #include - -#include - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -namespace { - -std::string EclString(const Opm::Inplace::Phase phase) -{ - switch (phase) { - case Opm::Inplace::Phase::WATER: - return "WIP"; - - case Opm::Inplace::Phase::OIL: - return "OIP"; - - case Opm::Inplace::Phase::GAS: - return "GIP"; - - case Opm::Inplace::Phase::OilInLiquidPhase: - return "OIPL"; - - case Opm::Inplace::Phase::OilInGasPhase: - return "OIPG"; - - case Opm::Inplace::Phase::GasInLiquidPhase: - return "GIPL"; - - case Opm::Inplace::Phase::GasInGasPhase: - return "GIPG"; - - case Opm::Inplace::Phase::PoreVolume: - return "RPV"; - - case Opm::Inplace::Phase::WaterResVolume: - return "WIPR"; - - case Opm::Inplace::Phase::OilResVolume: - return "OIPR"; - - case Opm::Inplace::Phase::GasResVolume: - return "GIPR"; - - case Opm::Inplace::Phase::SALT: - return "SIP"; - - case Opm::Inplace::Phase::CO2InWaterPhase: - return "WCD"; - - case Opm::Inplace::Phase::CO2InGasPhaseInMob: - return "GCDI"; - - case Opm::Inplace::Phase::CO2InGasPhaseMob: - return "GCDM"; - - case Opm::Inplace::Phase::CO2InGasPhaseInMobKrg: - return "GKDI"; - - case Opm::Inplace::Phase::CO2InGasPhaseMobKrg: - return "GKDM"; - - case Opm::Inplace::Phase::WaterInGasPhase: - return "WIPG"; - - case Opm::Inplace::Phase::WaterInWaterPhase: - return "WIPL"; - - case Opm::Inplace::Phase::CO2Mass: - return "GMIP"; - - case Opm::Inplace::Phase::CO2MassInWaterPhase: - return "GMDS"; - - case Opm::Inplace::Phase::CO2MassInGasPhase: - return "GMGP"; - - case Opm::Inplace::Phase::CO2MassInGasPhaseInMob: - return "GCDI_KG"; //Not used - - case Opm::Inplace::Phase::CO2MassInGasPhaseMob: - return "GKDM_KG"; //Not used - - case Opm::Inplace::Phase::CO2MassInGasPhaseInMobKrg: - return "GKTR"; - - case Opm::Inplace::Phase::CO2MassInGasPhaseMobKrg: - return "GKMO"; - - case Opm::Inplace::Phase::CO2MassInGasPhaseMaximumTrapped: - return "GMTR"; - - case Opm::Inplace::Phase::CO2MassInGasPhaseMaximumUnTrapped: - return "GMMO"; - - case Opm::Inplace::Phase::CO2MassInGasPhaseEffectiveTrapped: - return "GMST"; - - case Opm::Inplace::Phase::CO2MassInGasPhaseEffectiveUnTrapped: - return "GMUS"; - - default: - throw std::logic_error { - fmt::format("Phase enum with integer value: " - "{} not recognized", static_cast(phase)) - }; - } -} - - std::size_t numCells(const Opm::EclipseState& eclState) - { - return eclState.fieldProps().get_int("FIPNUM").size(); - } - - std::vector - defineInterRegionFlowArrays(const Opm::EclipseState& eclState, - const Opm::SummaryConfig& summaryConfig) - { - auto regions = std::vector{}; - - const auto& fprops = eclState.fieldProps(); - for (const auto& arrayName : summaryConfig.fip_regions_interreg_flow()) { - regions.push_back({ arrayName, std::cref(fprops.get_int(arrayName)) }); - } - - return regions; - } -} - -namespace Opm { - -template -GenericOutputCompositionalModule:: -GenericOutputCompositionalModule(const EclipseState& eclState, - const Schedule& schedule, - const SummaryConfig& summaryConfig, - const SummaryState& summaryState, - const std::string& moduleVersion, - bool enableEnergy, - bool enableTemperature, - bool enableMech, - bool enableSolvent, - bool enablePolymer, - bool enableFoam, - bool enableBrine, - bool enableSaltPrecipitation, - bool enableExtbo, - bool enableMICP) - : eclState_(eclState) - , schedule_(schedule) - , summaryState_(summaryState) - , summaryConfig_(summaryConfig) - , interRegionFlows_(numCells(eclState), - defineInterRegionFlowArrays(eclState, summaryConfig), - declaredMaxRegionID(eclState.runspec())) - , logOutput_(eclState, schedule, summaryState, moduleVersion) - , enableEnergy_(enableEnergy) - , enableTemperature_(enableTemperature) - , enableMech_(enableMech) - , enableSolvent_(enableSolvent) - , enablePolymer_(enablePolymer) - , enableFoam_(enableFoam) - , enableBrine_(enableBrine) - , enableSaltPrecipitation_(enableSaltPrecipitation) - , enableExtbo_(enableExtbo) - , enableMICP_(enableMICP) - , local_data_valid_(false) -{ - const auto& fp = eclState_.fieldProps(); - - this->regions_["FIPNUM"] = fp.get_int("FIPNUM"); - for (const auto& region : fp.fip_regions()) { - this->regions_[region] = fp.get_int(region); - } - - this->RPRNodes_ = summaryConfig_.keywords("RPR*"); - this->RPRPNodes_ = summaryConfig_.keywords("RPRP*"); - - for (const auto& phase : Inplace::phases()) { - std::string key_pattern = "R" + EclString(phase) + "*"; - this->regionNodes_[phase] = summaryConfig_.keywords(key_pattern); - } - - // Check for any BFLOW[I|J|K] summary keys - blockFlows_ = summaryConfig_.keywords("BFLOW*").size() > 0; - - // Check if FLORES/FLOWS is set in any RPTRST in the schedule - anyFlores_ = false; // Used for the initialization of the sparse table - anyFlows_ = blockFlows_; - enableFlores_ = false; // Used for the output of i+, j+, k+ - enableFloresn_ = false; // Used for the special case of nnc - enableFlows_ = false; - enableFlowsn_ = false; - - for (const auto& block : this->schedule_) { - const auto& rstkw = block.rst_config().keywords; - - if (! anyFlores_) { - anyFlores_ = rstkw.find("FLORES") != rstkw.end(); - } - - if (! anyFlows_) { - anyFlows_ = rstkw.find("FLOWS") != rstkw.end(); - } - - if (anyFlores_ && anyFlows_) { - // Terminate report step loop early if both FLORES and FLOWS - // have been set at some point as there's no need to search - // any further in that case. - break; - } - } -} - -template -GenericOutputCompositionalModule:: -~GenericOutputCompositionalModule() = default; - -template -void GenericOutputCompositionalModule:: -outputTimeStamp(const std::string& lbl, - const double elapsed, - const int rstep, - const boost::posix_time::ptime currentDate) -{ - logOutput_.timeStamp(lbl, elapsed, rstep, currentDate); -} - -template -void GenericOutputCompositionalModule:: -prepareDensityAccumulation() -{ - if (this->regionAvgDensity_.has_value()) { - this->regionAvgDensity_->prepareAccumulation(); - } -} - -template -void GenericOutputCompositionalModule:: -accumulateDensityParallel() -{ - if (this->regionAvgDensity_.has_value()) { - this->regionAvgDensity_->accumulateParallel(); - } -} - -template -void GenericOutputCompositionalModule:: -outputCumLog(std::size_t reportStepNum) -{ - this->logOutput_.cumulative(reportStepNum); -} - -template -void GenericOutputCompositionalModule:: -outputProdLog(std::size_t reportStepNum) -{ - this->logOutput_.production(reportStepNum); -} - -template -void GenericOutputCompositionalModule:: -outputInjLog(std::size_t reportStepNum) -{ - this->logOutput_.injection(reportStepNum); -} - -template -Inplace GenericOutputCompositionalModule:: -calc_inplace(std::map& miscSummaryData, - std::map>& regionData, - const Parallel::Communication& comm) -{ - auto inplace = this->accumulateRegionSums(comm); - - if (comm.rank() != 0) - return inplace; - - updateSummaryRegionValues(inplace, - miscSummaryData, - regionData); - - - return inplace; -} - -template -void GenericOutputCompositionalModule:: -outputFipAndResvLog(const Inplace& inplace, - const std::size_t reportStepNum, - double elapsed, - boost::posix_time::ptime currentDate, - const bool substep, - const Parallel::Communication& comm) -{ - if (comm.rank() != 0) - return; - - - // For report step 0 we use the RPTSOL config, else derive from RPTSCHED - std::unique_ptr fipSched; - if (reportStepNum > 0) { - const auto& rpt = this->schedule_[reportStepNum-1].rpt_config.get(); - fipSched = std::make_unique(rpt); - } - const FIPConfig& fipc = reportStepNum == 0 ? this->eclState_.getEclipseConfig().fip() - : *fipSched; - - if (!substep && !forceDisableFipOutput_ && fipc.output(FIPConfig::OutputField::FIELD)) { - - logOutput_.timeStamp("BALANCE", elapsed, reportStepNum, currentDate); - - logOutput_.fip(inplace, this->initialInplace(), ""); - - if (fipc.output(FIPConfig::OutputField::FIPNUM)) { - logOutput_.fip(inplace, this->initialInplace(), "FIPNUM"); - - if (fipc.output(FIPConfig::OutputField::RESV)) - logOutput_.fipResv(inplace, "FIPNUM"); - } - - if (fipc.output(FIPConfig::OutputField::FIP)) { - for (const auto& reg : this->regions_) { - if (reg.first != "FIPNUM") { - std::ostringstream ss; - ss << "BAL" << reg.first.substr(3); - logOutput_.timeStamp(ss.str(), elapsed, reportStepNum, currentDate); - logOutput_.fip(inplace, this->initialInplace(), reg.first); - - if (fipc.output(FIPConfig::OutputField::RESV)) - logOutput_.fipResv(inplace, reg.first); - } - } - } - } -} - -template -void GenericOutputCompositionalModule:: -addRftDataToWells(data::Wells& wellDatas, std::size_t reportStepNum) -{ - const auto& rft_config = schedule_[reportStepNum].rft_config(); - for (const auto& well: schedule_.getWells(reportStepNum)) { - - // don't bother with wells not on this process - if (isDefunctParallelWell(well.name())) { - continue; - } - - //add data infrastructure for shut wells - if (!wellDatas.count(well.name())) { - data::Well wellData; - - if (!rft_config.active()) - continue; - - wellData.connections.resize(well.getConnections().size()); - std::size_t count = 0; - for (const auto& connection: well.getConnections()) { - const std::size_t i = std::size_t(connection.getI()); - const std::size_t j = std::size_t(connection.getJ()); - const std::size_t k = std::size_t(connection.getK()); - - const std::size_t index = eclState_.gridDims().getGlobalIndex(i, j, k); - auto& connectionData = wellData.connections[count]; - connectionData.index = index; - count++; - } - wellDatas.emplace(std::make_pair(well.name(), wellData)); - } - - data::Well& wellData = wellDatas.at(well.name()); - for (auto& connectionData: wellData.connections) { - const auto index = connectionData.index; - if (oilConnectionPressures_.count(index) > 0) - connectionData.cell_pressure = oilConnectionPressures_.at(index); - if (waterConnectionSaturations_.count(index) > 0) - connectionData.cell_saturation_water = waterConnectionSaturations_.at(index); - if (gasConnectionSaturations_.count(index) > 0) - connectionData.cell_saturation_gas = gasConnectionSaturations_.at(index); - } - } - oilConnectionPressures_.clear(); - waterConnectionSaturations_.clear(); - gasConnectionSaturations_.clear(); -} - -template -void GenericOutputCompositionalModule:: -assignToSolution(data::Solution& sol) -{ - using DataEntry = - std::tuple&>; - - auto doInsert = [&sol](const DataEntry& entry, - const data::TargetType target) - { - if (std::get<2>(entry).empty()) { - return; - } - - sol.insert(std::get(entry), - std::get(entry), - std::move(std::get<2>(entry)), - target); - }; - - const auto baseSolutionArrays = std::array { - DataEntry{"1OVERBG", UnitSystem::measure::gas_inverse_formation_volume_factor, invB_[gasPhaseIdx]}, - DataEntry{"1OVERBO", UnitSystem::measure::oil_inverse_formation_volume_factor, invB_[oilPhaseIdx]}, - DataEntry{"1OVERBW", UnitSystem::measure::water_inverse_formation_volume_factor, invB_[waterPhaseIdx]}, - DataEntry{"FLRGASI+", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::XPlus)][gasCompIdx]}, - DataEntry{"FLRGASJ+", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::YPlus)][gasCompIdx]}, - DataEntry{"FLRGASK+", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::ZPlus)][gasCompIdx]}, - DataEntry{"FLROILI+", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::XPlus)][oilCompIdx]}, - DataEntry{"FLROILJ+", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::YPlus)][oilCompIdx]}, - DataEntry{"FLROILK+", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::ZPlus)][oilCompIdx]}, - DataEntry{"FLRWATI+", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::XPlus)][waterCompIdx]}, - DataEntry{"FLRWATJ+", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::YPlus)][waterCompIdx]}, - DataEntry{"FLRWATK+", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::ZPlus)][waterCompIdx]}, - DataEntry{"FOAM", UnitSystem::measure::identity, cFoam_}, - DataEntry{"GASKR", UnitSystem::measure::identity, relativePermeability_[gasPhaseIdx]}, - DataEntry{"GAS_DEN", UnitSystem::measure::density, density_[gasPhaseIdx]}, - DataEntry{"GAS_VISC", UnitSystem::measure::viscosity, viscosity_[gasPhaseIdx]}, - DataEntry{"OILKR", UnitSystem::measure::identity, relativePermeability_[oilPhaseIdx]}, - DataEntry{"OIL_DEN", UnitSystem::measure::density, density_[oilPhaseIdx]}, - DataEntry{"OIL_VISC", UnitSystem::measure::viscosity, viscosity_[oilPhaseIdx]}, - DataEntry{"PBUB", UnitSystem::measure::pressure, bubblePointPressure_}, - DataEntry{"PCGW", UnitSystem::measure::pressure, pcgw_}, - DataEntry{"PCOG", UnitSystem::measure::pressure, pcog_}, - DataEntry{"PCOW", UnitSystem::measure::pressure, pcow_}, - DataEntry{"PDEW", UnitSystem::measure::pressure, dewPointPressure_}, - DataEntry{"POLYMER", UnitSystem::measure::identity, cPolymer_}, - DataEntry{"PPCW", UnitSystem::measure::pressure, ppcw_}, - DataEntry{"PRESROCC", UnitSystem::measure::pressure, minimumOilPressure_}, - DataEntry{"PRESSURE", UnitSystem::measure::pressure, fluidPressure_}, - DataEntry{"RPORV", UnitSystem::measure::volume, rPorV_}, - DataEntry{"RS", UnitSystem::measure::gas_oil_ratio, rs_}, - DataEntry{"RSSAT", UnitSystem::measure::gas_oil_ratio, gasDissolutionFactor_}, - DataEntry{"RV", UnitSystem::measure::oil_gas_ratio, rv_}, - DataEntry{"RVSAT", UnitSystem::measure::oil_gas_ratio, oilVaporizationFactor_}, - DataEntry{"SALT", UnitSystem::measure::salinity, cSalt_}, - DataEntry{"SGMAX", UnitSystem::measure::identity, sgmax_}, - DataEntry{"SHMAX", UnitSystem::measure::identity, shmax_}, - DataEntry{"SOMAX", UnitSystem::measure::identity, soMax_}, - DataEntry{"SOMIN", UnitSystem::measure::identity, somin_}, - DataEntry{"SSOLVENT", UnitSystem::measure::identity, sSol_}, - DataEntry{"SWHY1", UnitSystem::measure::identity, swmin_}, - DataEntry{"SWMAX", UnitSystem::measure::identity, swMax_}, - DataEntry{"WATKR", UnitSystem::measure::identity, relativePermeability_[waterPhaseIdx]}, - DataEntry{"WAT_DEN", UnitSystem::measure::density, density_[waterPhaseIdx]}, - DataEntry{"WAT_VISC", UnitSystem::measure::viscosity, viscosity_[waterPhaseIdx]}, - }; - - // Separate these as flows*_ may be defined due to BFLOW[I|J|K] even without FLOWS in RPTRST - const auto flowsSolutionArrays = std::array { - DataEntry{"FLOGASI+", UnitSystem::measure::gas_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::XPlus)][gasCompIdx]}, - DataEntry{"FLOGASJ+", UnitSystem::measure::gas_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::YPlus)][gasCompIdx]}, - DataEntry{"FLOGASK+", UnitSystem::measure::gas_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::ZPlus)][gasCompIdx]}, - DataEntry{"FLOOILI+", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::XPlus)][oilCompIdx]}, - DataEntry{"FLOOILJ+", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::YPlus)][oilCompIdx]}, - DataEntry{"FLOOILK+", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::ZPlus)][oilCompIdx]}, - DataEntry{"FLOWATI+", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::XPlus)][waterCompIdx]}, - DataEntry{"FLOWATJ+", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::YPlus)][waterCompIdx]}, - DataEntry{"FLOWATK+", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::ZPlus)][waterCompIdx]}, - DataEntry{"FLOGASI-", UnitSystem::measure::gas_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::XMinus)][gasCompIdx]}, - DataEntry{"FLOGASJ-", UnitSystem::measure::gas_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::YMinus)][gasCompIdx]}, - DataEntry{"FLOGASK-", UnitSystem::measure::gas_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::ZMinus)][gasCompIdx]}, - DataEntry{"FLOOILI-", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::XMinus)][oilCompIdx]}, - DataEntry{"FLOOILJ-", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::YMinus)][oilCompIdx]}, - DataEntry{"FLOOILK-", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::ZMinus)][oilCompIdx]}, - DataEntry{"FLOWATI-", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::XMinus)][waterCompIdx]}, - DataEntry{"FLOWATJ-", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::YMinus)][waterCompIdx]}, - DataEntry{"FLOWATK-", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::ZMinus)][waterCompIdx]}, - DataEntry{"FLRGASI-", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::XMinus)][gasCompIdx]}, - DataEntry{"FLRGASJ-", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::YMinus)][gasCompIdx]}, - DataEntry{"FLRGASK-", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::ZMinus)][gasCompIdx]}, - DataEntry{"FLROILI-", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::XMinus)][oilCompIdx]}, - DataEntry{"FLROILJ-", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::YMinus)][oilCompIdx]}, - DataEntry{"FLROILK-", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::ZMinus)][oilCompIdx]}, - DataEntry{"FLRWATI-", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::XMinus)][waterCompIdx]}, - DataEntry{"FLRWATJ-", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::YMinus)][waterCompIdx]}, - DataEntry{"FLRWATK-", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::ZMinus)][waterCompIdx]}, - }; - - const auto extendedSolutionArrays = std::array { - DataEntry{"BIOFILM", UnitSystem::measure::identity, cBiofilm_}, - DataEntry{"CALCITE", UnitSystem::measure::identity, cCalcite_}, - DataEntry{"DELSTRXX", UnitSystem::measure::pressure, delstressXX_}, - DataEntry{"DELSTRYY", UnitSystem::measure::pressure, delstressYY_}, - DataEntry{"DELSTRZZ", UnitSystem::measure::pressure, delstressZZ_}, - DataEntry{"DELSTRXY", UnitSystem::measure::pressure, delstressXY_}, - DataEntry{"DELSTRXZ", UnitSystem::measure::pressure, delstressXZ_}, - DataEntry{"DELSTRYZ", UnitSystem::measure::pressure, delstressYZ_}, - DataEntry{"DISPX", UnitSystem::measure::length, dispX_}, - DataEntry{"DISPY", UnitSystem::measure::length, dispY_}, - DataEntry{"DISPZ", UnitSystem::measure::length, dispZ_}, - DataEntry{"DRSDTCON", UnitSystem::measure::gas_oil_ratio_rate, drsdtcon_}, - DataEntry{"MECHPOTF", UnitSystem::measure::pressure, mechPotentialForce_}, - DataEntry{"MICROBES", UnitSystem::measure::density, cMicrobes_}, - DataEntry{"OXYGEN", UnitSystem::measure::density, cOxygen_}, - DataEntry{"PERMFACT", UnitSystem::measure::identity, permFact_}, - DataEntry{"PORV_RC", UnitSystem::measure::identity, rockCompPorvMultiplier_}, - DataEntry{"PRESPOTF", UnitSystem::measure::pressure, mechPotentialPressForce_}, - DataEntry{"PRES_OVB", UnitSystem::measure::pressure, overburdenPressure_}, - DataEntry{"RSW", UnitSystem::measure::gas_oil_ratio, rsw_}, - DataEntry{"RSWSAT", UnitSystem::measure::gas_oil_ratio, gasDissolutionFactorInWater_}, - DataEntry{"RSWSOL", UnitSystem::measure::gas_oil_ratio, rswSol_}, - DataEntry{"RVW", UnitSystem::measure::oil_gas_ratio, rvw_}, - DataEntry{"RVWSAT", UnitSystem::measure::oil_gas_ratio, waterVaporizationFactor_}, - DataEntry{"SALTP", UnitSystem::measure::identity, pSalt_}, - DataEntry{"SS_X", UnitSystem::measure::identity, extboX_}, - DataEntry{"SS_Y", UnitSystem::measure::identity, extboY_}, - DataEntry{"SS_Z", UnitSystem::measure::identity, extboZ_}, - DataEntry{"STD_CO2", UnitSystem::measure::identity, mFracCo2_}, - DataEntry{"STD_GAS", UnitSystem::measure::identity, mFracGas_}, - DataEntry{"STD_OIL", UnitSystem::measure::identity, mFracOil_}, - DataEntry{"STRAINXX", UnitSystem::measure::identity, strainXX_}, - DataEntry{"STRAINYY", UnitSystem::measure::identity, strainYY_}, - DataEntry{"STRAINZZ", UnitSystem::measure::identity, strainZZ_}, - DataEntry{"STRAINXY", UnitSystem::measure::identity, strainXY_}, - DataEntry{"STRAINXZ", UnitSystem::measure::identity, strainXZ_}, - DataEntry{"STRAINYZ", UnitSystem::measure::identity, strainYZ_}, - DataEntry{"STRESSXX", UnitSystem::measure::length, stressXX_}, - DataEntry{"STRESSYY", UnitSystem::measure::length, stressYY_}, - DataEntry{"STRESSZZ", UnitSystem::measure::length, stressZZ_}, - DataEntry{"STRESSXY", UnitSystem::measure::length, stressXY_}, - DataEntry{"STRESSXZ", UnitSystem::measure::length, stressXZ_}, - DataEntry{"STRESSYZ", UnitSystem::measure::length, stressYZ_}, - DataEntry{"TEMPPOTF", UnitSystem::measure::pressure, mechPotentialTempForce_}, - DataEntry{"TMULT_RC", UnitSystem::measure::identity, rockCompTransMultiplier_}, - DataEntry{"UREA", UnitSystem::measure::density, cUrea_}, - }; - - auto compositionalEntries = std::vector{}; - - { - // ZMF - for (int i = 0; i < numComponents; ++i) { - const std::string name = "ZMF" + std::to_string(i + 1); // Generate ZMF1, ZMF2, ... - compositionalEntries.emplace_back(name, UnitSystem::measure::identity, moleFractions_[i]); - } - - // XMF - for (int i = 0; i < numComponents; ++i) { - const std::string name = "XMF" + std::to_string(i + 1); // Generate XMF1, XMF2, ... - compositionalEntries.emplace_back(name, UnitSystem::measure::identity, phaseMoleFractions_[oilPhaseIdx][i]); - } - - // YMF - for (int i = 0; i < numComponents; ++i) { - const std::string name = "YMF" + std::to_string(i + 1); // Generate YMF1, YMF2, ... - compositionalEntries.emplace_back(name, UnitSystem::measure::identity, phaseMoleFractions_[gasPhaseIdx][i]); - } - } - - for (const auto& array : compositionalEntries) { - doInsert(array, data::TargetType::RESTART_SOLUTION); - } - - // basically, for compositional, we can not use std::array for this. We need to generate the ZMF1, ZMF2, and so on - // and also, we need to map these values. - - for (const auto& array : baseSolutionArrays) { - doInsert(array, data::TargetType::RESTART_SOLUTION); - } - - if (this->enableFlows_) { - for (const auto& array : flowsSolutionArrays) { - doInsert(array, data::TargetType::RESTART_SOLUTION); - } - } - - for (const auto& array : extendedSolutionArrays) { - doInsert(array, data::TargetType::RESTART_OPM_EXTENDED); - } - - if (! this->temperature_.empty()) - { - sol.insert("TEMP", UnitSystem::measure::temperature, - std::move(this->temperature_), data::TargetType::RESTART_SOLUTION); - } - - if (FluidSystem::phaseIsActive(waterPhaseIdx) && - ! this->saturation_[waterPhaseIdx].empty()) - { - sol.insert("SWAT", UnitSystem::measure::identity, - std::move(this->saturation_[waterPhaseIdx]), - data::TargetType::RESTART_SOLUTION); - } - - if (FluidSystem::phaseIsActive(gasPhaseIdx) && - ! this->saturation_[gasPhaseIdx].empty()) - { - sol.insert("SGAS", UnitSystem::measure::identity, - std::move(this->saturation_[gasPhaseIdx]), - data::TargetType::RESTART_SOLUTION); - } - - if (FluidSystem::phaseIsActive(oilPhaseIdx) && - ! this->saturation_[oilPhaseIdx].empty()) - { - sol.insert("SOIL", UnitSystem::measure::identity, - std::move(this->saturation_[oilPhaseIdx]), - data::TargetType::RESTART_SOLUTION); - } - - /* if ((eclState_.runspec().co2Storage() || eclState_.runspec().h2Storage()) && !rsw_.empty()) { - auto mfrac = std::vector(this->rsw_.size(), 0.0); - - std::transform(this->rsw_.begin(), this->rsw_.end(), - this->eclState_.fieldProps().get_int("PVTNUM").begin(), - mfrac.begin(), - [](const auto& rsw, const int pvtReg) - { - const auto xwg = FluidSystem::convertRswToXwG(rsw, pvtReg - 1); - return FluidSystem::convertXwGToxwG(xwg, pvtReg - 1); - }); - - std::string moleFracName = eclState_.runspec().co2Storage() ? "XMFCO2" : "XMFH2"; - sol.insert(moleFracName, - UnitSystem::measure::identity, - std::move(mfrac), - data::TargetType::RESTART_OPM_EXTENDED); - } - - if ((eclState_.runspec().co2Storage() || eclState_.runspec().h2Storage()) && !rvw_.empty()) { - auto mfrac = std::vector(this->rvw_.size(), 0.0); - - std::transform(this->rvw_.begin(), this->rvw_.end(), - this->eclState_.fieldProps().get_int("PVTNUM").begin(), - mfrac.begin(), - [](const auto& rvw, const int pvtReg) - { - const auto xgw = FluidSystem::convertRvwToXgW(rvw, pvtReg - 1); - return FluidSystem::convertXgWToxgW(xgw, pvtReg - 1); - }); - - sol.insert("YMFWAT", - UnitSystem::measure::identity, - std::move(mfrac), - data::TargetType::RESTART_OPM_EXTENDED); - } */ - - if (FluidSystem::phaseIsActive(waterPhaseIdx) && - ! this->residual_[waterPhaseIdx].empty()) - { - sol.insert("RES_WAT", UnitSystem::measure::liquid_surface_volume, - std::move(this->residual_[waterPhaseIdx]), - data::TargetType::RESTART_OPM_EXTENDED); - } - if (FluidSystem::phaseIsActive(gasPhaseIdx) && - ! this->residual_[gasPhaseIdx].empty()) - { - sol.insert("RES_GAS", UnitSystem::measure::gas_surface_volume, - std::move(this->residual_[gasPhaseIdx]), - data::TargetType::RESTART_OPM_EXTENDED); - } - if (FluidSystem::phaseIsActive(oilPhaseIdx) && - ! this->residual_[oilPhaseIdx].empty()) - { - sol.insert("RES_OIL", UnitSystem::measure::liquid_surface_volume, - std::move(this->residual_[oilPhaseIdx]), - data::TargetType::RESTART_OPM_EXTENDED); - } - - // Fluid in place - if (this->outputFipRestart_) { - using namespace std::string_literals; - - using M = UnitSystem::measure; - using FIPEntry = std::tuple; - - auto fipArrays = std::vector {}; - if (this->outputFipRestart_.surface) { - fipArrays.insert(fipArrays.end(), { - FIPEntry {"SFIPOIL"s, M::liquid_surface_volume, Inplace::Phase::OIL }, - FIPEntry {"SFIPWAT"s, M::liquid_surface_volume, Inplace::Phase::WATER }, - FIPEntry {"SFIPGAS"s, M::gas_surface_volume, Inplace::Phase::GAS }, - }); - } - - if (this->outputFipRestart_.reservoir) { - fipArrays.insert(fipArrays.end(), { - FIPEntry {"RFIPOIL"s, M::volume, Inplace::Phase::OilResVolume }, - FIPEntry {"RFIPWAT"s, M::volume, Inplace::Phase::WaterResVolume }, - FIPEntry {"RFIPGAS"s, M::volume, Inplace::Phase::GasResVolume }, - }); - } - - if (this->outputFipRestart_.noPrefix && !this->outputFipRestart_.surface) { - fipArrays.insert(fipArrays.end(), { - FIPEntry { "FIPOIL"s, M::liquid_surface_volume, Inplace::Phase::OIL }, - FIPEntry { "FIPWAT"s, M::liquid_surface_volume, Inplace::Phase::WATER }, - FIPEntry { "FIPGAS"s, M::gas_surface_volume, Inplace::Phase::GAS }, - }); - } - - for (const auto& [mnemonic, unit, phase] : fipArrays) { - if (! this->fip_[phase].empty()) { - sol.insert(mnemonic, unit, std::move(this->fip_[phase]), - data::TargetType::RESTART_SOLUTION); - } - } - - for (const auto& phase : Inplace::mixingPhases()) { - if (! this->fip_[phase].empty()) { - sol.insert(EclString(phase), - UnitSystem::measure::volume, - this->fip_[phase], - data::TargetType::SUMMARY); - } - } - } - - // Tracers - if (! this->freeTracerConcentrations_.empty()) { - const auto& tracers = this->eclState_.tracer(); - for (auto tracerIdx = 0*tracers.size(); - tracerIdx < tracers.size(); ++tracerIdx) - { - sol.insert(tracers[tracerIdx].fname(), - UnitSystem::measure::identity, - std::move(freeTracerConcentrations_[tracerIdx]), - data::TargetType::RESTART_TRACER_SOLUTION); - } - - // Put freeTracerConcentrations container into a valid state. Otherwise - // we'll move from vectors that have already been moved from if we - // get here and it's not a restart step. - this->freeTracerConcentrations_.clear(); - } - if (! this->solTracerConcentrations_.empty()) { - const auto& tracers = this->eclState_.tracer(); - for (auto tracerIdx = 0*tracers.size(); - tracerIdx < tracers.size(); ++tracerIdx) - { - if (solTracerConcentrations_[tracerIdx].empty()) - continue; - - sol.insert(tracers[tracerIdx].sname(), - UnitSystem::measure::identity, - std::move(solTracerConcentrations_[tracerIdx]), - data::TargetType::RESTART_TRACER_SOLUTION); - } - - // Put solTracerConcentrations container into a valid state. Otherwise - // we'll move from vectors that have already been moved from if we - // get here and it's not a restart step. - this->solTracerConcentrations_.clear(); - } -} - -template -void GenericOutputCompositionalModule:: -setRestart(const data::Solution& sol, - unsigned elemIdx, - unsigned globalDofIndex) -{ - Scalar so = 1.0; - if (!saturation_[waterPhaseIdx].empty() && sol.has("SWAT")) { - saturation_[waterPhaseIdx][elemIdx] = sol.data("SWAT")[globalDofIndex]; - so -= sol.data("SWAT")[globalDofIndex]; - } - if (!saturation_[gasPhaseIdx].empty() && sol.has("SGAS")) { - saturation_[gasPhaseIdx][elemIdx] = sol.data("SGAS")[globalDofIndex]; - so -= sol.data("SGAS")[globalDofIndex]; - } - - if (!sSol_.empty()) { - // keep the SSOL option for backward compatibility - // should be removed after 10.2018 release - if (sol.has("SSOL")) - sSol_[elemIdx] = sol.data("SSOL")[globalDofIndex]; - else if (sol.has("SSOLVENT")) - sSol_[elemIdx] = sol.data("SSOLVENT")[globalDofIndex]; - - so -= sSol_[elemIdx]; - } - - if (!rswSol_.empty()) { - if (sol.has("RSWSOL")) - rswSol_[elemIdx] = sol.data("RSWSOL")[globalDofIndex]; - - } - - assert(!saturation_[oilPhaseIdx].empty()); - saturation_[oilPhaseIdx][elemIdx] = so; - - auto assign = [elemIdx, globalDofIndex, &sol](const std::string& name, - ScalarBuffer& data) - - { - if (!data.empty() && sol.has(name)) { - data[elemIdx] = sol.data(name)[globalDofIndex]; - } - }; - - const auto fields = std::array{ - std::pair{"BIOFILM", &cBiofilm_}, - std::pair{"CALCITE", &cCalcite_}, - std::pair{"FOAM", &cFoam_}, - std::pair{"MICROBES", &cMicrobes_}, - std::pair{"OXYGEN", &cOxygen_}, - std::pair{"PERMFACT", &permFact_}, - std::pair{"POLYMER", &cPolymer_}, - std::pair{"PPCW", &ppcw_}, - std::pair{"PRESSURE", &fluidPressure_}, - std::pair{"RS", &rs_}, - std::pair{"RSW", &rsw_}, - std::pair{"RV", &rv_}, - std::pair{"RVW", &rvw_}, - std::pair{"SALT", &cSalt_}, - std::pair{"SALTP", &pSalt_}, - std::pair{"SGMAX", &sgmax_}, - std::pair{"SHMAX", &shmax_}, - std::pair{"SOMAX", &soMax_}, - std::pair{"SOMIN", &somin_}, - std::pair{"SWHY1", &swmin_}, - std::pair{"SWMAX", &swMax_}, - std::pair{"TEMP", &temperature_}, - std::pair{"UREA", &cUrea_}, - }; - - std::for_each(fields.begin(), fields.end(), - [&assign](const auto& p) - { assign(p.first, *p.second); }); -} - -template -typename GenericOutputCompositionalModule::ScalarBuffer -GenericOutputCompositionalModule:: -regionSum(const ScalarBuffer& property, - const std::vector& regionId, - std::size_t maxNumberOfRegions, - const Parallel::Communication& comm) -{ - ScalarBuffer totals(maxNumberOfRegions, 0.0); - - if (property.empty()) - return totals; - - // the regionId contains the ghost cells - // the property does not contain the ghostcells - // This code assumes that that the ghostcells are - // added after the interior cells - // OwnerCellsFirst = True - assert(regionId.size() >= property.size()); - for (std::size_t j = 0; j < property.size(); ++j) { - const int regionIdx = regionId[j] - 1; - // the cell is not attributed to any region. ignore it! - if (regionIdx < 0) - continue; - - assert(regionIdx < static_cast(maxNumberOfRegions)); - totals[regionIdx] += property[j]; - } - - for (std::size_t i = 0; i < maxNumberOfRegions; ++i) - totals[i] = comm.sum(totals[i]); - - return totals; - } - -template -void GenericOutputCompositionalModule:: -doAllocBuffers(const unsigned bufferSize, - const unsigned reportStepNum, - const bool substep, - const bool log, - const bool isRestart, - const bool vapparsActive, - const bool enablePCHysteresis, - const bool enableNonWettingHysteresis, - const bool enableWettingHysteresis, - const unsigned numTracers, - const std::vector& enableSolTracers, - const unsigned numOutputNnc) -{ - // Output RESTART_OPM_EXTENDED only when explicitly requested by user. - std::map rstKeywords = schedule_.rst_keywords(reportStepNum); - for (auto& [keyword, should_write] : rstKeywords) { - if (this->isOutputCreationDirective_(keyword)) { - // 'BASIC', 'FREQ' and similar. Don't attempt to create - // cell-based output for these keywords and don't warn about - // not being able to create such cell-based result vectors. - should_write = 0; - } - } - - if (auto& norst = rstKeywords["NORST"]; norst > 0) { - // Don't emit diagnostic messages about unsupported 'NORST' key. - norst = 0; - } - - // Fluid in place - { - using namespace std::string_literals; - - const auto fipctrl = std::array { - std::pair { "FIP"s , &OutputFIPRestart::noPrefix }, - std::pair { "SFIP"s, &OutputFIPRestart::surface }, - std::pair { "RFIP"s, &OutputFIPRestart::reservoir }, - }; - - this->outputFipRestart_.clearBits(); - this->computeFip_ = false; - - for (const auto& [mnemonic, kind] : fipctrl) { - if (auto fipPos = rstKeywords.find(mnemonic); - fipPos != rstKeywords.end()) - { - fipPos->second = 0; - this->outputFipRestart_.*kind = true; - } - } - - for (const auto& phase : Inplace::phases()) { - if (!substep || summaryConfig_.require3DField(EclString(phase))) { - this->fip_[phase].resize(bufferSize, 0.0); - this->computeFip_ = true; - } - else { - this->fip_[phase].clear(); - } - } - } - - const auto needAvgPress = !substep || - !this->RPRNodes_.empty() || - this->summaryConfig_.hasKeyword("FPR") || - this->summaryConfig_.hasKeyword("FPRP"); - - const auto needPoreVolume = needAvgPress || - this->summaryConfig_.hasKeyword("FHPV") || - this->summaryConfig_.match("RHPV*"); - - if (needPoreVolume) { - this->fip_[Inplace::Phase::PoreVolume].resize(bufferSize, 0.0); - this->dynamicPoreVolume_.resize(bufferSize, 0.0); - this->hydrocarbonPoreVolume_.resize(bufferSize, 0.0); - } - else { - this->dynamicPoreVolume_.clear(); - this->hydrocarbonPoreVolume_.clear(); - } - - if (needAvgPress) { - this->pressureTimesPoreVolume_.resize(bufferSize, 0.0); - this->pressureTimesHydrocarbonVolume_.resize(bufferSize, 0.0); - } - else { - this->pressureTimesPoreVolume_.clear(); - this->pressureTimesHydrocarbonVolume_.clear(); - } - - // Well RFT data - if (!substep) { - const auto& rft_config = schedule_[reportStepNum].rft_config(); - for (const auto& well: schedule_.getWells(reportStepNum)) { - - // don't bother with wells not on this process - if (isDefunctParallelWell(well.name())) { - continue; - } - - if (!rft_config.active()) - continue; - - for (const auto& connection: well.getConnections()) { - const std::size_t i = std::size_t(connection.getI()); - const std::size_t j = std::size_t(connection.getJ()); - const std::size_t k = std::size_t(connection.getK()); - const std::size_t index = eclState_.gridDims().getGlobalIndex(i, j, k); - - if (FluidSystem::phaseIsActive(oilPhaseIdx)) - oilConnectionPressures_.emplace(std::make_pair(index, 0.0)); - - if (FluidSystem::phaseIsActive(waterPhaseIdx)) - waterConnectionSaturations_.emplace(std::make_pair(index, 0.0)); - - if (FluidSystem::phaseIsActive(gasPhaseIdx)) - gasConnectionSaturations_.emplace(std::make_pair(index, 0.0)); - } - } - } - - // Flows may need to be allocated even when there is no restart due to BFLOW* summary keywords - if (blockFlows_ ) { - const std::array phaseIdxs = { gasPhaseIdx, oilPhaseIdx, waterPhaseIdx }; - const std::array compIdxs = { gasCompIdx, oilCompIdx, waterCompIdx }; - - for (unsigned ii = 0; ii < phaseIdxs.size(); ++ii) { - if (FluidSystem::phaseIsActive(phaseIdxs[ii])) { - flows_[FaceDir::ToIntersectionIndex(Dir::XPlus)][compIdxs[ii]].resize(bufferSize, 0.0); - flows_[FaceDir::ToIntersectionIndex(Dir::YPlus)][compIdxs[ii]].resize(bufferSize, 0.0); - flows_[FaceDir::ToIntersectionIndex(Dir::ZPlus)][compIdxs[ii]].resize(bufferSize, 0.0); - } - } - } - - // Field data should be allocated - // 1) When we want to restart - // 2) When it is ask for by the user via restartConfig - // 3) When it is not a substep - if (!isRestart && (!schedule_.write_rst_file(reportStepNum) || substep)) { - return; - } - - // Always output saturation of active phases - for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { - if (! FluidSystem::phaseIsActive(phaseIdx)) { - continue; - } - - this->saturation_[phaseIdx].resize(bufferSize, 0.0); - } - - // And oil pressure - fluidPressure_.resize(bufferSize, 0.0); - rstKeywords["PRES"] = 0; - rstKeywords["PRESSURE"] = 0; - - if (enableMech_ && eclState_.runspec().mech()) { - this->mechPotentialForce_.resize(bufferSize,0.0); - rstKeywords["MECHPOTF"] = 0; - this->mechPotentialTempForce_.resize(bufferSize,0.0); - rstKeywords["TEMPPOTF"] = 0; - this->mechPotentialPressForce_.resize(bufferSize,0.0); - rstKeywords["PRESPOTF"] = 0; - - this->dispX_.resize(bufferSize,0.0); - rstKeywords["DISPX"] = 0; - this->dispY_.resize(bufferSize,0.0); - rstKeywords["DISPY"] = 0; - this->dispZ_.resize(bufferSize,0.0); - rstKeywords["DISPZ"] = 0; - this->stressXX_.resize(bufferSize,0.0); - rstKeywords["STRESSXX"] = 0; - this->stressYY_.resize(bufferSize,0.0); - rstKeywords["STRESSYY"] = 0; - this->stressZZ_.resize(bufferSize,0.0); - rstKeywords["STRESSZZ"] = 0; - this->stressXY_.resize(bufferSize,0.0); - rstKeywords["STRESSXY"] = 0; - this->stressXZ_.resize(bufferSize,0.0); - rstKeywords["STRESSXZ"] = 0; - this->stressXY_.resize(bufferSize,0.0); - rstKeywords["STRESSXY"] = 0; - this->stressYZ_.resize(bufferSize,0.0); - rstKeywords["STRESSYZ"] = 0; - - this->strainXX_.resize(bufferSize,0.0); - rstKeywords["STRAINXX"] = 0; - this->strainYY_.resize(bufferSize,0.0); - rstKeywords["STRAINYY"] = 0; - this->strainZZ_.resize(bufferSize,0.0); - rstKeywords["STRAINZZ"] = 0; - this->strainXY_.resize(bufferSize,0.0); - rstKeywords["STRAINXY"] = 0; - this->strainXZ_.resize(bufferSize,0.0); - rstKeywords["STRAINXZ"] = 0; - this->strainXY_.resize(bufferSize,0.0); - rstKeywords["STRAINXY"] = 0; - this->strainYZ_.resize(bufferSize,0.0); - rstKeywords["STRAINYZ"] = 0; - - this->delstressXX_.resize(bufferSize,0.0); - rstKeywords["DELSTRXX"] = 0; - this->delstressYY_.resize(bufferSize,0.0); - rstKeywords["DELSTRYY"] = 0; - this->delstressZZ_.resize(bufferSize,0.0); - rstKeywords["DELSTRZZ"] = 0; - this->delstressXY_.resize(bufferSize,0.0); - rstKeywords["DELSTRXY"] = 0; - this->delstressXZ_.resize(bufferSize,0.0); - rstKeywords["DELSTRXZ"] = 0; - this->delstressXY_.resize(bufferSize,0.0); - rstKeywords["DELSTRXY"] = 0; - this->delstressYZ_.resize(bufferSize,0.0); - rstKeywords["DELSTRYZ"] = 0; - } - - // If TEMP is set in RPTRST we output temperature even if THERMAL - // is not activated - if (enableEnergy_ || rstKeywords["TEMP"] > 0) { - this->temperature_.resize(bufferSize, 0.0); - rstKeywords["TEMP"] = 0; - } - - if (FluidSystem::phaseIsActive(oilPhaseIdx)) { - rstKeywords["SOIL"] = 0; - } - if (FluidSystem::phaseIsActive(gasPhaseIdx)) { - rstKeywords["SGAS"] = 0; - } - if (FluidSystem::phaseIsActive(waterPhaseIdx)) { - rstKeywords["SWAT"] = 0; - } - - /* if (FluidSystem::enableDissolvedGas()) { - rs_.resize(bufferSize, 0.0); - rstKeywords["RS"] = 0; - } - if (FluidSystem::enableDissolvedGasInWater()) { - rsw_.resize(bufferSize, 0.0); - rstKeywords["RSW"] = 0; - } - if (FluidSystem::enableVaporizedOil()) { - rv_.resize(bufferSize, 0.0); - rstKeywords["RV"] = 0; - } - if (FluidSystem::enableVaporizedWater()) { - rvw_.resize(bufferSize, 0.0); - rstKeywords["RVW"] = 0; - } */ - - if (schedule_[reportStepNum].oilvap().drsdtConvective()) { - drsdtcon_.resize(bufferSize, 0.0); - } - - if (enableSolvent_) { - sSol_.resize(bufferSize, 0.0); - if (eclState_.getSimulationConfig().hasDISGASW()) { - rswSol_.resize(bufferSize, 0.0); - } - } - - if (enablePolymer_) { - cPolymer_.resize(bufferSize, 0.0); - } - - if (enableFoam_) { - cFoam_.resize(bufferSize, 0.0); - } - - if (enableBrine_) { - cSalt_.resize(bufferSize, 0.0); - } - - if (enableSaltPrecipitation_) { - pSalt_.resize(bufferSize, 0.0); - permFact_.resize(bufferSize, 0.0); - } - - if (enableExtbo_) { - extboX_.resize(bufferSize, 0.0); - extboY_.resize(bufferSize, 0.0); - extboZ_.resize(bufferSize, 0.0); - mFracOil_.resize(bufferSize, 0.0); - mFracGas_.resize(bufferSize, 0.0); - mFracCo2_.resize(bufferSize, 0.0); - } - - if (enableMICP_) { - cMicrobes_.resize(bufferSize, 0.0); - cOxygen_.resize(bufferSize, 0.0); - cUrea_.resize(bufferSize, 0.0); - cBiofilm_.resize(bufferSize, 0.0); - cCalcite_.resize(bufferSize, 0.0); - } - - if (vapparsActive) { - soMax_.resize(bufferSize, 0.0); - } - - if (enableNonWettingHysteresis) { - if (FluidSystem::phaseIsActive(oilPhaseIdx)){ - if (FluidSystem::phaseIsActive(waterPhaseIdx)){ - soMax_.resize(bufferSize, 0.0); - } - if (FluidSystem::phaseIsActive(gasPhaseIdx)){ - sgmax_.resize(bufferSize, 0.0); - } - } else { - //TODO add support for gas-water - } - } - if (enableWettingHysteresis) { - if (FluidSystem::phaseIsActive(oilPhaseIdx)){ - if (FluidSystem::phaseIsActive(waterPhaseIdx)){ - swMax_.resize(bufferSize, 0.0); - } - if (FluidSystem::phaseIsActive(gasPhaseIdx)){ - shmax_.resize(bufferSize, 0.0); - } - } else { - //TODO add support for gas-water - } - } - if (enablePCHysteresis) { - if (FluidSystem::phaseIsActive(oilPhaseIdx)){ - if (FluidSystem::phaseIsActive(waterPhaseIdx)){ - swmin_.resize(bufferSize, 0.0); - } - if (FluidSystem::phaseIsActive(gasPhaseIdx)){ - somin_.resize(bufferSize, 0.0); - } - } else { - //TODO add support for gas-water - } - } - - if (eclState_.fieldProps().has_double("SWATINIT")) { - ppcw_.resize(bufferSize, 0.0); - rstKeywords["PPCW"] = 0; - } - - /* if (FluidSystem::enableDissolvedGas() && rstKeywords["RSSAT"] > 0) { - rstKeywords["RSSAT"] = 0; - gasDissolutionFactor_.resize(bufferSize, 0.0); - } - if (FluidSystem::enableVaporizedOil() && rstKeywords["RVSAT"] > 0) { - rstKeywords["RVSAT"] = 0; - oilVaporizationFactor_.resize(bufferSize, 0.0); - } - if (FluidSystem::enableDissolvedGasInWater() && rstKeywords["RSWSAT"] > 0) { - rstKeywords["RSWSAT"] = 0; - gasDissolutionFactorInWater_.resize(bufferSize, 0.0); - } - if (FluidSystem::enableVaporizedWater() && rstKeywords["RVWSAT"] > 0) { - rstKeywords["RVWSAT"] = 0; - waterVaporizationFactor_.resize(bufferSize, 0.0); - } - - if (FluidSystem::phaseIsActive(waterPhaseIdx) && rstKeywords["BW"] > 0) { - rstKeywords["BW"] = 0; - invB_[waterPhaseIdx].resize(bufferSize, 0.0); - } - if (FluidSystem::phaseIsActive(oilPhaseIdx) && rstKeywords["BO"] > 0) { - rstKeywords["BO"] = 0; - invB_[oilPhaseIdx].resize(bufferSize, 0.0); - } - if (FluidSystem::phaseIsActive(gasPhaseIdx) && rstKeywords["BG"] > 0) { - rstKeywords["BG"] = 0; - invB_[gasPhaseIdx].resize(bufferSize, 0.0); - } - if (rstKeywords["RPORV"] > 0) { - rstKeywords["RPORV"] = 0; - rPorV_.resize(bufferSize, 0.0); - } */ - - enableFlows_ = false; - enableFlowsn_ = false; - const bool rstFlows = (rstKeywords["FLOWS"] > 0); - if (rstFlows) { - rstKeywords["FLOWS"] = 0; - enableFlows_ = true; - - const std::array phaseIdxs = { gasPhaseIdx, oilPhaseIdx, waterPhaseIdx }; - const std::array compIdxs = { gasCompIdx, oilCompIdx, waterCompIdx }; - const auto rstName = std::array { "FLOGASN+", "FLOOILN+", "FLOWATN+" }; - - for (unsigned ii = 0; ii < phaseIdxs.size(); ++ii) { - if (FluidSystem::phaseIsActive(phaseIdxs[ii])) { - if (!blockFlows_) { // Already allocated if summary vectors requested - flows_[FaceDir::ToIntersectionIndex(Dir::XPlus)][compIdxs[ii]].resize(bufferSize, 0.0); - flows_[FaceDir::ToIntersectionIndex(Dir::YPlus)][compIdxs[ii]].resize(bufferSize, 0.0); - flows_[FaceDir::ToIntersectionIndex(Dir::ZPlus)][compIdxs[ii]].resize(bufferSize, 0.0); - } - - if (rstKeywords["FLOWS-"] > 0) { - flows_[FaceDir::ToIntersectionIndex(Dir::XMinus)][compIdxs[ii]].resize(bufferSize, 0.0); - flows_[FaceDir::ToIntersectionIndex(Dir::YMinus)][compIdxs[ii]].resize(bufferSize, 0.0); - flows_[FaceDir::ToIntersectionIndex(Dir::ZMinus)][compIdxs[ii]].resize(bufferSize, 0.0); - } - - if (numOutputNnc > 0) { - enableFlowsn_ = true; - - flowsn_[compIdxs[ii]].name = rstName[ii]; - flowsn_[compIdxs[ii]].indices.resize(numOutputNnc, -1); - flowsn_[compIdxs[ii]].values.resize(numOutputNnc, 0.0); - } - } - } - if (rstKeywords["FLOWS-"] > 0) { - rstKeywords["FLOWS-"] = 0; - } - } - - enableFlores_ = false; - enableFloresn_ = false; - if (rstKeywords["FLORES"] > 0) { - rstKeywords["FLORES"] = 0; - enableFlores_ = true; - - const std::array phaseIdxs = { gasPhaseIdx, oilPhaseIdx, waterPhaseIdx }; - const std::array compIdxs = { gasCompIdx, oilCompIdx, waterCompIdx }; - const auto rstName = std::array{ "FLRGASN+", "FLROILN+", "FLRWATN+" }; - - for (unsigned ii = 0; ii < phaseIdxs.size(); ++ii) { - if (FluidSystem::phaseIsActive(phaseIdxs[ii])) { - flores_[FaceDir::ToIntersectionIndex(Dir::XPlus)][compIdxs[ii]].resize(bufferSize, 0.0); - flores_[FaceDir::ToIntersectionIndex(Dir::YPlus)][compIdxs[ii]].resize(bufferSize, 0.0); - flores_[FaceDir::ToIntersectionIndex(Dir::ZPlus)][compIdxs[ii]].resize(bufferSize, 0.0); - - if (rstKeywords["FLORES-"] > 0) { - flores_[FaceDir::ToIntersectionIndex(Dir::XMinus)][compIdxs[ii]].resize(bufferSize, 0.0); - flores_[FaceDir::ToIntersectionIndex(Dir::YMinus)][compIdxs[ii]].resize(bufferSize, 0.0); - flores_[FaceDir::ToIntersectionIndex(Dir::ZMinus)][compIdxs[ii]].resize(bufferSize, 0.0); - } - - if (numOutputNnc > 0) { - enableFloresn_ = true; - - floresn_[compIdxs[ii]].name = rstName[ii]; - floresn_[compIdxs[ii]].indices.resize(numOutputNnc, -1); - floresn_[compIdxs[ii]].values.resize(numOutputNnc, 0.0); - } - } - } - if (rstKeywords["FLORES-"] > 0) { - rstKeywords["FLORES-"] = 0; - } - } - - if (auto& den = rstKeywords["DEN"]; den > 0) { - den = 0; - for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++ phaseIdx) { - if (!FluidSystem::phaseIsActive(phaseIdx)) { - continue; - } - - this->density_[phaseIdx].resize(bufferSize, 0.0); - } - } - - if (auto& deng = rstKeywords["DENG"]; (deng > 0) && FluidSystem::phaseIsActive(gasPhaseIdx)) { - deng = 0; - this->density_[gasPhaseIdx].resize(bufferSize, 0.0); - } - - if (auto& deno = rstKeywords["DENO"]; (deno > 0) && FluidSystem::phaseIsActive(oilPhaseIdx)) { - deno = 0; - this->density_[oilPhaseIdx].resize(bufferSize, 0.0); - } - - if (auto& denw = rstKeywords["DENW"]; (denw > 0) && FluidSystem::phaseIsActive(waterPhaseIdx)) { - denw = 0; - this->density_[waterPhaseIdx].resize(bufferSize, 0.0); - } - - const bool hasVWAT = (rstKeywords["VISC"] > 0) || (rstKeywords["VWAT"] > 0); - const bool hasVOIL = (rstKeywords["VISC"] > 0) || (rstKeywords["VOIL"] > 0); - const bool hasVGAS = (rstKeywords["VISC"] > 0) || (rstKeywords["VGAS"] > 0); - rstKeywords["VISC"] = 0; - - if (FluidSystem::phaseIsActive(waterPhaseIdx) && hasVWAT) { - rstKeywords["VWAT"] = 0; - viscosity_[waterPhaseIdx].resize(bufferSize, 0.0); - } - if (FluidSystem::phaseIsActive(oilPhaseIdx) && hasVOIL > 0) { - rstKeywords["VOIL"] = 0; - viscosity_[oilPhaseIdx].resize(bufferSize, 0.0); - } - if (FluidSystem::phaseIsActive(gasPhaseIdx) && hasVGAS > 0) { - rstKeywords["VGAS"] = 0; - viscosity_[gasPhaseIdx].resize(bufferSize, 0.0); - } - - if (FluidSystem::phaseIsActive(waterPhaseIdx) && rstKeywords["KRW"] > 0) { - rstKeywords["KRW"] = 0; - relativePermeability_[waterPhaseIdx].resize(bufferSize, 0.0); - } - if (FluidSystem::phaseIsActive(oilPhaseIdx) && rstKeywords["KRO"] > 0) { - rstKeywords["KRO"] = 0; - relativePermeability_[oilPhaseIdx].resize(bufferSize, 0.0); - } - if (FluidSystem::phaseIsActive(gasPhaseIdx) && rstKeywords["KRG"] > 0) { - rstKeywords["KRG"] = 0; - relativePermeability_[gasPhaseIdx].resize(bufferSize, 0.0); - } - - if (FluidSystem::phaseIsActive(gasPhaseIdx) && FluidSystem::phaseIsActive(waterPhaseIdx) && rstKeywords["PCGW"] > 0) { - rstKeywords["PCGW"] = 0; - pcgw_.resize(bufferSize, 0.0); - } - if (FluidSystem::phaseIsActive(oilPhaseIdx) && FluidSystem::phaseIsActive(waterPhaseIdx) && rstKeywords["PCOW"] > 0) { - rstKeywords["PCOW"] = 0; - pcow_.resize(bufferSize, 0.0); - } - if (FluidSystem::phaseIsActive(oilPhaseIdx) && FluidSystem::phaseIsActive(gasPhaseIdx) && rstKeywords["PCOG"] > 0) { - rstKeywords["PCOG"] = 0; - pcog_.resize(bufferSize, 0.0); - } - - if (rstKeywords["PBPD"] > 0) { - rstKeywords["PBPD"] = 0; - bubblePointPressure_.resize(bufferSize, 0.0); - dewPointPressure_.resize(bufferSize, 0.0); - } - - // tracers - if (numTracers > 0) { - freeTracerConcentrations_.resize(numTracers); - for (unsigned tracerIdx = 0; tracerIdx < numTracers; ++tracerIdx) - { - freeTracerConcentrations_[tracerIdx].resize(bufferSize, 0.0); - } - solTracerConcentrations_.resize(numTracers); - for (unsigned tracerIdx = 0; tracerIdx < numTracers; ++tracerIdx) - { - if (enableSolTracers[tracerIdx]) - solTracerConcentrations_[tracerIdx].resize(bufferSize, 0.0); - } - } - - if (rstKeywords["RESIDUAL"] > 0) { - rstKeywords["RESIDUAL"] = 0; - for (int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) - { - if (FluidSystem::phaseIsActive(phaseIdx)) { - this->residual_[phaseIdx].resize(bufferSize, 0.0); - } - } - } - - // ROCKC - if (rstKeywords["ROCKC"] > 0) { - rstKeywords["ROCKC"] = 0; - rockCompPorvMultiplier_.resize(bufferSize, 0.0); - rockCompTransMultiplier_.resize(bufferSize, 0.0); - swMax_.resize(bufferSize, 0.0); - minimumOilPressure_.resize(bufferSize, 0.0); - overburdenPressure_.resize(bufferSize, 0.0); - } - - if (rstKeywords["ZMF"] > 0) { - rstKeywords["ZMF"] = 0; - for (int i = 0; i < numComponents; ++i) { - moleFractions_[i].resize(bufferSize, 0.0); - } - } - - if (rstKeywords["XMF"] > 0 && FluidSystem::phaseIsActive(oilPhaseIdx)) { - rstKeywords["XMF"] = 0; - for (int i = 0; i < numComponents; ++i) { - phaseMoleFractions_[oilPhaseIdx][i].resize(bufferSize, 0.0); - } - } - - if (rstKeywords["YMF"] > 0 && FluidSystem::phaseIsActive(gasPhaseIdx)) { - rstKeywords["YMF"] = 0; - for (int i = 0; i < numComponents; ++i) { - phaseMoleFractions_[gasPhaseIdx][i].resize(bufferSize, 0.0); - } - } - - - //Warn for any unhandled keyword - if (log) { - for (auto& keyValue: rstKeywords) { - if (keyValue.second > 0) { - std::string logstring = "Keyword '"; - logstring.append(keyValue.first); - logstring.append("' is unhandled for output to restart file."); - OpmLog::warning("Unhandled output keyword", logstring); - } - } - } - - failedCellsPb_.clear(); - failedCellsPd_.clear(); - - // Not supported in flow legacy - if (false) { - saturatedOilFormationVolumeFactor_.resize(bufferSize, 0.0); - } - - if (false) { - oilSaturationPressure_.resize(bufferSize, 0.0); - } -} - -template -bool GenericOutputCompositionalModule:: -isOutputCreationDirective_(const std::string& keyword) -{ - return (keyword == "BASIC") || (keyword == "FREQ") - || (keyword == "RESTART") // From RPTSCHED - || (keyword == "SAVE") || (keyword == "SFREQ"); // Not really supported -} - -template -void GenericOutputCompositionalModule:: -outputErrorLog(const Parallel::Communication& comm) const -{ - const auto root = 0; - auto globalFailedCellsPbub = gatherv(this->failedCellsPb_, comm, root); - auto globalFailedCellsPdew = gatherv(this->failedCellsPd_, comm, root); - - if (std::empty(std::get<0>(globalFailedCellsPbub)) && - std::empty(std::get<0>(globalFailedCellsPdew))) - { - return; - } - - logOutput_.error(std::get<0>(globalFailedCellsPbub), - std::get<0>(globalFailedCellsPdew)); -} - -template -int GenericOutputCompositionalModule:: -regionMax(const std::vector& region, - const Parallel::Communication& comm) -{ - const auto max_value = region.empty() ? 0 : *std::max_element(region.begin(), region.end()); - return comm.max(max_value); -} - -template -void GenericOutputCompositionalModule:: -update(Inplace& inplace, - const std::string& region_name, - const Inplace::Phase phase, - const std::size_t ntFip, - const ScalarBuffer& values) -{ - double sum = 0.0; - for (std::size_t region_number = 0; region_number < ntFip; ++region_number) { - const auto rval = static_cast(values[region_number]); - inplace.add(region_name, phase, region_number + 1, rval); - sum += rval; - } - inplace.add(phase, sum); -} - -template -void GenericOutputCompositionalModule:: -makeRegionSum(Inplace& inplace, - const std::string& region_name, - const Parallel::Communication& comm) const -{ - const auto& region = this->regions_.at(region_name); - const std::size_t ntFip = this->regionMax(region, comm); - - auto update_inplace = - [&inplace, ®ion, ®ion_name, &comm, ntFip, this] - (const Inplace::Phase phase, - const std::vector& value) - { - update(inplace, region_name, phase, ntFip, - this->regionSum(value, region, ntFip, comm)); - }; - - update_inplace(Inplace::Phase::PressurePV, - this->pressureTimesPoreVolume_); - - update_inplace(Inplace::Phase::HydroCarbonPV, - this->hydrocarbonPoreVolume_); - - update_inplace(Inplace::Phase::PressureHydroCarbonPV, - this->pressureTimesHydrocarbonVolume_); - - update_inplace(Inplace::Phase::DynamicPoreVolume, - this->dynamicPoreVolume_); - - for (const auto& phase : Inplace::phases()) { - auto fipPos = this->fip_.find(phase); - if (fipPos != this->fip_.end()) { - update_inplace(phase, fipPos->second); - } - } -} - -template -Inplace GenericOutputCompositionalModule:: -accumulateRegionSums(const Parallel::Communication& comm) -{ - Inplace inplace; - - for (const auto& region : this->regions_) { - makeRegionSum(inplace, region.first, comm); - } - - // The first time the outputFipLog function is run we store the inplace values in - // the initialInplace_ member. This has a problem: - // - // o For restarted runs this is obviously wrong. - // - // Finally it is of course not desirable to mutate state in an output - // routine. - if (!this->initialInplace_.has_value()) - this->initialInplace_ = inplace; - return inplace; -} - -template -typename GenericOutputCompositionalModule::Scalar -GenericOutputCompositionalModule:: -sum(const ScalarBuffer& v) -{ - return std::accumulate(v.begin(), v.end(), Scalar{0}); -} - -template -void GenericOutputCompositionalModule:: -updateSummaryRegionValues(const Inplace& inplace, - std::map& miscSummaryData, - std::map>& regionData) const -{ - // The field summary vectors should only use the FIPNUM based region sum. - { - for (const auto& phase : Inplace::phases()) { - const std::string key = "F" + EclString(phase); - if (this->summaryConfig_.hasKeyword(key)) { - miscSummaryData[key] = inplace.get(phase); - } - } - - if (this->summaryConfig_.hasKeyword("FHPV")) { - miscSummaryData["FHPV"] = inplace.get(Inplace::Phase::HydroCarbonPV); - } - - if (this->summaryConfig_.hasKeyword("FOE") && this->initialInplace_) { - miscSummaryData["FOE"] = (this->initialInplace_.value().get(Inplace::Phase::OIL) - inplace.get(Inplace::Phase::OIL)) - / this->initialInplace_.value().get(Inplace::Phase::OIL); - } - - if (this->summaryConfig_.hasKeyword("FPR")) { - miscSummaryData["FPR"] = - detail::pressureAverage(inplace.get(Inplace::Phase::PressureHydroCarbonPV), - inplace.get(Inplace::Phase::HydroCarbonPV), - inplace.get(Inplace::Phase::PressurePV), - inplace.get(Inplace::Phase::DynamicPoreVolume), - true); - } - - if (this->summaryConfig_.hasKeyword("FPRP")) { - miscSummaryData["FPRP"] = - detail::pressureAverage(inplace.get(Inplace::Phase::PressureHydroCarbonPV), - inplace.get(Inplace::Phase::HydroCarbonPV), - inplace.get(Inplace::Phase::PressurePV), - inplace.get(Inplace::Phase::DynamicPoreVolume), - false); - } - } - - // The region summary vectors should loop through the FIPxxx regions to - // support the RPR__xxx summary keywords. - { - auto get_vector = [&inplace] - (const auto& node_, - const Inplace::Phase phase_) - { - return inplace.get_vector(node_.fip_region(), phase_); - }; - - for (const auto& phase : Inplace::phases()) { - for (const auto& node : this->regionNodes_.at(phase)) - regionData[node.keyword()] = get_vector(node, phase); - } - - for (const auto& node : this->RPRNodes_) { - regionData[node.keyword()] = - detail::pressureAverage(get_vector(node, Inplace::Phase::PressureHydroCarbonPV), - get_vector(node, Inplace::Phase::HydroCarbonPV), - get_vector(node, Inplace::Phase::PressurePV), - get_vector(node, Inplace::Phase::DynamicPoreVolume), - true); - } - - for (const auto& node : this->RPRPNodes_) { - regionData[node.keyword()] = - detail::pressureAverage(get_vector(node, Inplace::Phase::PressureHydroCarbonPV), - get_vector(node, Inplace::Phase::HydroCarbonPV), - get_vector(node, Inplace::Phase::PressurePV), - get_vector(node, Inplace::Phase::DynamicPoreVolume), - false); - } - - for (const auto& node : this->summaryConfig_.keywords("RHPV*")) { - regionData[node.keyword()] = - get_vector(node, Inplace::Phase::HydroCarbonPV); - } - } -} - -template -void GenericOutputCompositionalModule:: -setupBlockData(std::function isCartIdxOnThisRank) -{ - for (const auto& node : summaryConfig_) { - if ((node.category() == SummaryConfigNode::Category::Block) && - isCartIdxOnThisRank(node.number() - 1)) - { - this->blockData_.emplace(std::piecewise_construct, - std::forward_as_tuple(node.keyword(), - node.number()), - std::forward_as_tuple(0.0)); - } - } -} - -template -void GenericOutputCompositionalModule:: -assignGlobalFieldsToSolution(data::Solution& sol) -{ - if (!this->cnvData_.empty()) { - constexpr const std::array names{"CNV_OIL", "CNV_GAS", "CNV_WAT", - "CNV_PLY", "CNV_SAL", "CNV_SOL"}; - for (std::size_t i = 0; i < names.size(); ++i) { - if (!this->cnvData_[i].empty()) { - sol.insert(names[i], this->cnvData_[i], data::TargetType::RESTART_SOLUTION); - } - } - } -} - -/* INSTANTIATE_TYPE(double) - -#if FLOW_INSTANTIATE_FLOAT -INSTANTIATE_TYPE(float) -#endif */ - -#define INSTANTIATE_FS(NUM) \ - template using FS##NUM = GenericOilGasFluidSystem; \ - template class GenericOutputCompositionalModule>; - -INSTANTIATE_FS(2) -INSTANTIATE_FS(3) -INSTANTIATE_FS(4) -INSTANTIATE_FS(5) -INSTANTIATE_FS(6) -INSTANTIATE_FS(7) - -} // namespace Opm diff --git a/opm/simulators/flow/GenericOutputCompositionalModule.hpp b/opm/simulators/flow/GenericOutputCompositionalModule.hpp deleted file mode 100644 index 998411602..000000000 --- a/opm/simulators/flow/GenericOutputCompositionalModule.hpp +++ /dev/null @@ -1,567 +0,0 @@ -// -*- 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 . - 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 -#include - -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Opm { - -namespace data { class Solution; } -class EclipseState; -class Schedule; -class SummaryConfig; -class SummaryConfigNode; -class SummaryState; - -template -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& miscSummaryData, - std::map>& 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, 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, 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, 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>& data) - { - cnvData_ = data; - } - - template - 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; - using StringBuffer = std::vector; - 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& 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& miscSummaryData, - std::map>& regionData) const; - - static bool isOutputCreationDirective_(const std::string& keyword); - - // Sum Fip values over regions. - static ScalarBuffer regionSum(const ScalarBuffer& property, - const std::vector& regionId, - const std::size_t maxNumberOfRegions, - const Parallel::Communication& comm); - - static int regionMax(const std::vector& 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 isCartIdxOnThisRank); - - virtual bool isDefunctParallelWell(std::string wname) const = 0; - - const EclipseState& eclState_; - const Schedule& schedule_; - const SummaryState& summaryState_; - - SummaryConfig summaryConfig_; - - InterRegFlowMap interRegionFlows_; - LogOutputHelper 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 fip_; - std::unordered_map> regions_; - std::unordered_map> regionNodes_; - - std::vector RPRNodes_; - std::vector RPRPNodes_; - - std::vector failedCellsPb_; - std::vector 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 saturation_; - std::array invB_; - std::array density_; - std::array viscosity_; - std::array relativePermeability_; - - std::array moleFractions_; - std::array, numPhases> phaseMoleFractions_; - - std::vector freeTracerConcentrations_; - std::vector solTracerConcentrations_; - - std::array residual_; - - std::array, 6> flows_; - std::array, 6> flores_; - - std::array, 3> floresn_; - std::array, 3> flowsn_; - - std::map oilConnectionPressures_; - std::map waterConnectionSaturations_; - std::map gasConnectionSaturations_; - std::map, double> blockData_; - - std::vector> cnvData_; //!< Data for CNV_xxx arrays - - std::optional initialInplace_; - bool local_data_valid_{false}; - - std::optional regionAvgDensity_; -}; - -} // namespace Opm - -#endif // OPM_GENERIC_OUTPUT_BLACK_OIL_MODULE_HPP diff --git a/opm/simulators/flow/OutputCompositionalModule.hpp b/opm/simulators/flow/OutputCompositionalModule.hpp index 3e370cdb0..2064015de 100644 --- a/opm/simulators/flow/OutputCompositionalModule.hpp +++ b/opm/simulators/flow/OutputCompositionalModule.hpp @@ -52,7 +52,8 @@ #include #include -#include +// #include +#include #include #include @@ -86,7 +87,7 @@ class EcfvDiscretization; * ECL binary format. */ template -class OutputCompositionalModule : public GenericOutputCompositionalModule> +class OutputCompositionalModule : public GenericOutputBlackoilModule> { using Simulator = GetPropType; using Discretization = GetPropType; @@ -100,7 +101,7 @@ class OutputCompositionalModule : public GenericOutputCompositionalModule; using Element = typename GridView::template Codim<0>::Entity; using ElementIterator = typename GridView::template Codim<0>::Iterator; - using BaseType = GenericOutputCompositionalModule; + using BaseType = GenericOutputBlackoilModule; using Indices = GetPropType; using Dir = FaceDir::DirEnum; From 0153da2009af1181f4ad690bdf467142043fa044 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Wed, 16 Oct 2024 15:01:45 +0200 Subject: [PATCH 04/15] cleaning up OutputCompositionalModule --- opm/simulators/flow/EclGenericWriter.hpp | 12 +- opm/simulators/flow/EclGenericWriter_impl.hpp | 12 +- opm/simulators/flow/OutputBlackoilModule.hpp | 14 +- .../flow/OutputCompositionalModule.hpp | 1504 +---------------- 4 files changed, 20 insertions(+), 1522 deletions(-) diff --git a/opm/simulators/flow/EclGenericWriter.hpp b/opm/simulators/flow/EclGenericWriter.hpp index 5dc13d013..f28912e9b 100644 --- a/opm/simulators/flow/EclGenericWriter.hpp +++ b/opm/simulators/flow/EclGenericWriter.hpp @@ -134,12 +134,12 @@ protected: bool isFloresn, std::array, 3>&& floresn); - void doWriteOutput(const int reportStepNum, - const std::optional timeStepNum, - const bool isSubStep, - Scalar curTime, - Scalar nextStepSize, - data::Solution&& localCellData); + void doWriteOutput(const int reportStepNum, + const std::optional timeStepNum, + const bool isSubStep, + Scalar curTime, + Scalar nextStepSize, + data::Solution&& localCellData); void evalSummary(int reportStepNum, Scalar curTime, diff --git a/opm/simulators/flow/EclGenericWriter_impl.hpp b/opm/simulators/flow/EclGenericWriter_impl.hpp index 30e7e59da..05f943590 100644 --- a/opm/simulators/flow/EclGenericWriter_impl.hpp +++ b/opm/simulators/flow/EclGenericWriter_impl.hpp @@ -620,12 +620,12 @@ doWriteOutput(const int reportStepNum, template void EclGenericWriter:: -doWriteOutput(const int reportStepNum, - const std::optional timeStepNum, - const bool isSubStep, - Scalar curTime, - Scalar nextStepSize, - data::Solution&& localCellData) +doWriteOutput(const int reportStepNum, + const std::optional timeStepNum, + const bool isSubStep, + Scalar curTime, + Scalar nextStepSize, + data::Solution&& localCellData) { const auto isParallel = this->collectOnIORank_.isParallel(); diff --git a/opm/simulators/flow/OutputBlackoilModule.hpp b/opm/simulators/flow/OutputBlackoilModule.hpp index 13d24d12f..5aa4a9bcd 100644 --- a/opm/simulators/flow/OutputBlackoilModule.hpp +++ b/opm/simulators/flow/OutputBlackoilModule.hpp @@ -65,15 +65,13 @@ #include #include -// TODO: EclWriter how includes both OutputBlackoilModule and OutputCompositionalModule, so the following are defined twice -// Will see whether some refactoring are needed here. -// 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 { diff --git a/opm/simulators/flow/OutputCompositionalModule.hpp b/opm/simulators/flow/OutputCompositionalModule.hpp index 2064015de..0b6cfa4d3 100644 --- a/opm/simulators/flow/OutputCompositionalModule.hpp +++ b/opm/simulators/flow/OutputCompositionalModule.hpp @@ -39,8 +39,6 @@ #include #include -// #include -// #include #include #include @@ -52,7 +50,6 @@ #include #include -// #include #include #include @@ -66,12 +63,6 @@ #include #include -namespace Opm::Parameters { - -struct ForceDisableFluidInPlaceOutput { static constexpr bool value = false; }; -struct ForceDisableResvFluidInPlaceOutput { static constexpr bool value = false; }; - -} // namespace Opm::Parameters namespace Opm { @@ -148,12 +139,6 @@ public: this->setupBlockData(isCartIdxOnThisRank); - this->forceDisableFipOutput_ = - Parameters::Get(); - - this->forceDisableFipresvOutput_ = - Parameters::Get(); - if (! Parameters::Get()) { const std::string msg = "The output code does not support --owner-cells-first=false."; if (collectToIORank.isIORank()) { @@ -183,12 +168,6 @@ public: */ static void registerParameters() { - Parameters::Register - ("Do not print fluid-in-place values after each report step " - "even if requested by the deck."); - Parameters::Register - ("Do not print reservoir volumes values after each report step " - "even if requested by the deck."); } /*! @@ -206,69 +185,13 @@ public: return; } - const auto& problem = this->simulator_.problem(); - - std::cout << " let us do doAllocBuffers " << std::endl; - this->doAllocBuffers(bufferSize, reportStepNum, substep, log, isRestart); - // problem.vapparsActive(std::max(simulator_.episodeIndex(), 0)), - // problem.materialLawManager()->enablePCHysteresis(), - // problem.materialLawManager()->enableNonWettingHysteresis(), - // problem.materialLawManager()->enableWettingHysteresis(), - // problem.tracerModel().numTracers(), - // problem.tracerModel().enableSolTracers(), - // problem.eclWriter()->getOutputNnc().size()); } -// void processElementMech(const ElementContext& elemCtx) -// { -// if constexpr (getPropValue()) { -// const auto& problem = elemCtx.simulator().problem(); -// const auto& model = problem.geoMechModel(); -// for (unsigned dofIdx = 0; dofIdx < elemCtx.numPrimaryDof(/*timeIdx=*/0); ++dofIdx) { -// unsigned globalDofIdx = elemCtx.globalSpaceIndex(dofIdx, /*timeIdx=*/0); -// if (!this->mechPotentialForce_.empty()) { -// // assume all mechanical things should be written -// this->mechPotentialForce_[globalDofIdx] = model.mechPotentialForce(globalDofIdx); -// this->mechPotentialPressForce_[globalDofIdx] = model.mechPotentialPressForce(globalDofIdx); -// this->mechPotentialTempForce_[globalDofIdx] = model.mechPotentialTempForce(globalDofIdx); -// -// this->dispX_[globalDofIdx] = model.disp(globalDofIdx, 0); -// this->dispY_[globalDofIdx] = model.disp(globalDofIdx, 1); -// this->dispZ_[globalDofIdx] = model.disp(globalDofIdx, 2); -// this->stressXX_[globalDofIdx] = model.stress(globalDofIdx, 0); -// this->stressYY_[globalDofIdx] = model.stress(globalDofIdx, 1); -// this->stressZZ_[globalDofIdx] = model.stress(globalDofIdx, 2); -// // voight notation -// this->stressXY_[globalDofIdx] = model.stress(globalDofIdx, 5); -// this->stressXZ_[globalDofIdx] = model.stress(globalDofIdx, 4); -// this->stressYZ_[globalDofIdx] = model.stress(globalDofIdx, 3); -// -// this->strainXX_[globalDofIdx] = model.strain(globalDofIdx, 0); -// this->strainYY_[globalDofIdx] = model.strain(globalDofIdx, 1); -// this->strainZZ_[globalDofIdx] = model.strain(globalDofIdx, 2); -// // voight notation -// this->strainXY_[globalDofIdx] = model.strain(globalDofIdx, 5); -// this->strainXZ_[globalDofIdx] = model.strain(globalDofIdx, 4); -// this->strainYZ_[globalDofIdx] = model.strain(globalDofIdx, 3); -// -// -// this->delstressXX_[globalDofIdx] = model.delstress(globalDofIdx, 0); -// this->delstressYY_[globalDofIdx] = model.delstress(globalDofIdx, 1); -// this->delstressZZ_[globalDofIdx] = model.delstress(globalDofIdx, 2); -// // voight notation -// this->delstressXY_[globalDofIdx] = model.delstress(globalDofIdx, 5); -// this->delstressXZ_[globalDofIdx] = model.delstress(globalDofIdx, 4); -// this->delstressYZ_[globalDofIdx] = model.delstress(globalDofIdx, 3); -// } -// } -// } -// } - /*! * \brief Modify the internal buffers according to the intensive * quanties relevant for an element @@ -315,16 +238,6 @@ public: } } -// if (this->regionAvgDensity_.has_value()) { -// // Note: We intentionally exclude effects of rock -// // compressibility by using referencePorosity() here. -// const auto porv = 0; // intQuants.referencePorosity() -// // * elemCtx.simulator().model().dofTotalVolume(globalDofIdx); -// -// this->aggregateAverageDensityContributions_(fs, globalDofIdx, -// static_cast(porv)); -// } - if (!this->fluidPressure_.empty()) { if (FluidSystem::phaseIsActive(oilPhaseIdx)) { // Output oil pressure as default @@ -343,406 +256,6 @@ public: this->temperature_[globalDofIdx] = getValue(fs.temperature(oilPhaseIdx)); Valgrind::CheckDefined(this->temperature_[globalDofIdx]); } -// if (!this->gasDissolutionFactor_.empty()) { -// Scalar SoMax = elemCtx.problem().maxOilSaturation(globalDofIdx); -// this->gasDissolutionFactor_[globalDofIdx] -// = 0; //FluidSystem::template saturatedDissolutionFactor( -// // fs, oilPhaseIdx, pvtRegionIdx, SoMax); -// Valgrind::CheckDefined(this->gasDissolutionFactor_[globalDofIdx]); -// } -// if (!this->oilVaporizationFactor_.empty()) { -// Scalar SoMax = elemCtx.problem().maxOilSaturation(globalDofIdx); -// this->oilVaporizationFactor_[globalDofIdx] -// = 0; // FluidSystem::template saturatedDissolutionFactor( -// // fs, gasPhaseIdx, pvtRegionIdx, SoMax); -// Valgrind::CheckDefined(this->oilVaporizationFactor_[globalDofIdx]); -// } - // if (!this->gasDissolutionFactorInWater_.empty()) { - // Scalar SwMax = elemCtx.problem().maxWaterSaturation(globalDofIdx); - // this->gasDissolutionFactorInWater_[globalDofIdx] - // = FluidSystem::template saturatedDissolutionFactor( - // fs, waterPhaseIdx, pvtRegionIdx, SwMax); - // Valgrind::CheckDefined(this->gasDissolutionFactorInWater_[globalDofIdx]); - // } - // if (!this->waterVaporizationFactor_.empty()) { - // this->waterVaporizationFactor_[globalDofIdx] - // = FluidSystem::template saturatedVaporizationFactor( - // fs, gasPhaseIdx, pvtRegionIdx); - // Valgrind::CheckDefined(this->waterVaporizationFactor_[globalDofIdx]); - // } - // if (!this->gasFormationVolumeFactor_.empty()) { - // this->gasFormationVolumeFactor_[globalDofIdx] = 1.0 - // / FluidSystem::template inverseFormationVolumeFactor( - // fs, gasPhaseIdx, pvtRegionIdx); - // Valgrind::CheckDefined(this->gasFormationVolumeFactor_[globalDofIdx]); - // } - // if (!this->saturatedOilFormationVolumeFactor_.empty()) { - // this->saturatedOilFormationVolumeFactor_[globalDofIdx] = 1.0 - // / FluidSystem::template saturatedInverseFormationVolumeFactor( - // fs, oilPhaseIdx, pvtRegionIdx); - // Valgrind::CheckDefined(this->saturatedOilFormationVolumeFactor_[globalDofIdx]); - // } - // if (!this->oilSaturationPressure_.empty()) { - // this->oilSaturationPressure_[globalDofIdx] - // = FluidSystem::template saturationPressure(fs, oilPhaseIdx, pvtRegionIdx); - // Valgrind::CheckDefined(this->oilSaturationPressure_[globalDofIdx]); - // } - // - // if (!this->rs_.empty()) { - // this->rs_[globalDofIdx] = getValue(fs.Rs()); - // Valgrind::CheckDefined(this->rs_[globalDofIdx]); - // } - // if (!this->rsw_.empty()) { - // this->rsw_[globalDofIdx] = getValue(fs.Rsw()); - // Valgrind::CheckDefined(this->rsw_[globalDofIdx]); - // } - // - // if (!this->rv_.empty()) { - // this->rv_[globalDofIdx] = getValue(fs.Rv()); - // Valgrind::CheckDefined(this->rv_[globalDofIdx]); - // } - // if (!this->pcgw_.empty()) { - // this->pcgw_[globalDofIdx] = getValue(fs.pressure(gasPhaseIdx)) - getValue(fs.pressure(waterPhaseIdx)); - // Valgrind::CheckDefined(this->pcgw_[globalDofIdx]); - // } - // if (!this->pcow_.empty()) { - // this->pcow_[globalDofIdx] = getValue(fs.pressure(oilPhaseIdx)) - getValue(fs.pressure(waterPhaseIdx)); - // Valgrind::CheckDefined(this->pcow_[globalDofIdx]); - // } - // if (!this->pcog_.empty()) { - // this->pcog_[globalDofIdx] = getValue(fs.pressure(gasPhaseIdx)) - getValue(fs.pressure(oilPhaseIdx)); - // Valgrind::CheckDefined(this->pcog_[globalDofIdx]); - // } - // - // if (!this->rvw_.empty()) { - // this->rvw_[globalDofIdx] = getValue(fs.Rvw()); - // Valgrind::CheckDefined(this->rvw_[globalDofIdx]); - // } - // - // for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { - // if (this->invB_[phaseIdx].empty()) - // continue; - // - // this->invB_[phaseIdx][globalDofIdx] = getValue(fs.invB(phaseIdx)); - // Valgrind::CheckDefined(this->invB_[phaseIdx][globalDofIdx]); - // } - // - // for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { - // if (this->density_[phaseIdx].empty()) - // continue; - // - // this->density_[phaseIdx][globalDofIdx] = getValue(fs.density(phaseIdx)); - // Valgrind::CheckDefined(this->density_[phaseIdx][globalDofIdx]); - // } - // - // for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { - // if (this->viscosity_[phaseIdx].empty()) - // continue; - // - // if (!this->extboX_.empty() && phaseIdx == oilPhaseIdx) - // this->viscosity_[phaseIdx][globalDofIdx] = getValue(intQuants.oilViscosity()); - // else if (!this->extboX_.empty() && phaseIdx == gasPhaseIdx) - // this->viscosity_[phaseIdx][globalDofIdx] = getValue(intQuants.gasViscosity()); - // else - // this->viscosity_[phaseIdx][globalDofIdx] = getValue(fs.viscosity(phaseIdx)); - // Valgrind::CheckDefined(this->viscosity_[phaseIdx][globalDofIdx]); - // } - // - // for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { - // if (this->relativePermeability_[phaseIdx].empty()) - // continue; - // - // this->relativePermeability_[phaseIdx][globalDofIdx] - // = getValue(intQuants.relativePermeability(phaseIdx)); - // Valgrind::CheckDefined(this->relativePermeability_[phaseIdx][globalDofIdx]); - // } - // - // if (!this->drsdtcon_.empty()) { - // this->drsdtcon_[globalDofIdx] = problem.drsdtcon(globalDofIdx, elemCtx.simulator().episodeIndex()); - // } - // - // if (!this->sSol_.empty()) { - // this->sSol_[globalDofIdx] = intQuants.solventSaturation().value(); - // } - // - // if (!this->rswSol_.empty()) { - // this->rswSol_[globalDofIdx] = intQuants.rsSolw().value(); - // } - // - // if (!this->cPolymer_.empty()) { - // this->cPolymer_[globalDofIdx] = intQuants.polymerConcentration().value(); - // } - // - // if (!this->cFoam_.empty()) { - // this->cFoam_[globalDofIdx] = intQuants.foamConcentration().value(); - // } - // - // if (!this->cSalt_.empty()) { - // this->cSalt_[globalDofIdx] = fs.saltConcentration().value(); - // } - // - // if (!this->pSalt_.empty()) { - // this->pSalt_[globalDofIdx] = intQuants.saltSaturation().value(); - // } - // - // if (!this->permFact_.empty()) { - // this->permFact_[globalDofIdx] = intQuants.permFactor().value(); - // } - // - // if (!this->extboX_.empty()) { - // this->extboX_[globalDofIdx] = intQuants.xVolume().value(); - // } - // - // if (!this->extboY_.empty()) { - // this->extboY_[globalDofIdx] = intQuants.yVolume().value(); - // } - // - // if (!this->extboZ_.empty()) { - // this->extboZ_[globalDofIdx] = intQuants.zFraction().value(); - // } - // - // if (!this->rPorV_.empty()) { - // const auto totVolume = elemCtx.simulator().model().dofTotalVolume(globalDofIdx); - // this->rPorV_[globalDofIdx] = totVolume * intQuants.porosity().value(); - // } - // - // if (!this->mFracCo2_.empty()) { - // const Scalar stdVolOil = getValue(fs.saturation(oilPhaseIdx)) * getValue(fs.invB(oilPhaseIdx)) - // + getValue(fs.saturation(gasPhaseIdx)) * getValue(fs.invB(gasPhaseIdx)) * getValue(fs.Rv()); - // const Scalar stdVolGas = getValue(fs.saturation(gasPhaseIdx)) * getValue(fs.invB(gasPhaseIdx)) - // * (1.0 - intQuants.yVolume().value()) - // + getValue(fs.saturation(oilPhaseIdx)) * getValue(fs.invB(oilPhaseIdx)) * getValue(fs.Rs()) - // * (1.0 - intQuants.xVolume().value()); - // const Scalar stdVolCo2 = getValue(fs.saturation(gasPhaseIdx)) * getValue(fs.invB(gasPhaseIdx)) - // * intQuants.yVolume().value() - // + getValue(fs.saturation(oilPhaseIdx)) * getValue(fs.invB(oilPhaseIdx)) * getValue(fs.Rs()) - // * intQuants.xVolume().value(); - // const Scalar rhoO = FluidSystem::referenceDensity(gasPhaseIdx, pvtRegionIdx); - // const Scalar rhoG = FluidSystem::referenceDensity(gasPhaseIdx, pvtRegionIdx); - // const Scalar rhoCO2 = intQuants.zRefDensity(); - // const Scalar stdMassTotal = 1.0e-10 + stdVolOil * rhoO + stdVolGas * rhoG + stdVolCo2 * rhoCO2; - // this->mFracOil_[globalDofIdx] = stdVolOil * rhoO / stdMassTotal; - // this->mFracGas_[globalDofIdx] = stdVolGas * rhoG / stdMassTotal; - // this->mFracCo2_[globalDofIdx] = stdVolCo2 * rhoCO2 / stdMassTotal; - // } - // - // if (!this->cMicrobes_.empty()) { - // this->cMicrobes_[globalDofIdx] = intQuants.microbialConcentration().value(); - // } - // - // if (!this->cOxygen_.empty()) { - // this->cOxygen_[globalDofIdx] = intQuants.oxygenConcentration().value(); - // } - // - // if (!this->cUrea_.empty()) { - // this->cUrea_[globalDofIdx] = 10 - // * intQuants.ureaConcentration() - // .value(); // Reescaling back the urea concentration (see WellInterface_impl.hpp) - // } - // - // if (!this->cBiofilm_.empty()) { - // this->cBiofilm_[globalDofIdx] = intQuants.biofilmConcentration().value(); - // } - // - // if (!this->cCalcite_.empty()) { - // this->cCalcite_[globalDofIdx] = intQuants.calciteConcentration().value(); - // } - // - // if (!this->bubblePointPressure_.empty()) { - // try { - // this->bubblePointPressure_[globalDofIdx] - // = getValue(FluidSystem::bubblePointPressure(fs, intQuants.pvtRegionIndex())); - // } catch (const NumericalProblem&) { - // const auto cartesianIdx = elemCtx.simulator().vanguard().cartesianIndex(globalDofIdx); - // this->failedCellsPb_.push_back(cartesianIdx); - // } - // } - // - // if (!this->dewPointPressure_.empty()) { - // try { - // this->dewPointPressure_[globalDofIdx] - // = getValue(FluidSystem::dewPointPressure(fs, intQuants.pvtRegionIndex())); - // } catch (const NumericalProblem&) { - // const auto cartesianIdx = elemCtx.simulator().vanguard().cartesianIndex(globalDofIdx); - // this->failedCellsPd_.push_back(cartesianIdx); - // } - // } - // - // if (!this->minimumOilPressure_.empty()) - // this->minimumOilPressure_[globalDofIdx] - // = std::min(getValue(fs.pressure(oilPhaseIdx)), problem.minOilPressure(globalDofIdx)); - // - // if (!this->overburdenPressure_.empty()) - // this->overburdenPressure_[globalDofIdx] = problem.overburdenPressure(globalDofIdx); - // - // if (!this->rockCompPorvMultiplier_.empty()) - // this->rockCompPorvMultiplier_[globalDofIdx] - // = problem.template rockCompPoroMultiplier(intQuants, globalDofIdx); - // - // if (!this->rockCompTransMultiplier_.empty()) - // this->rockCompTransMultiplier_[globalDofIdx] - // = problem.template rockCompTransMultiplier(intQuants, globalDofIdx); - // - // const auto& matLawManager = problem.materialLawManager(); - // if (matLawManager->enableHysteresis()) { - // if (FluidSystem::phaseIsActive(oilPhaseIdx) - // && FluidSystem::phaseIsActive(waterPhaseIdx)) { - // Scalar somax; - // Scalar swmax; - // Scalar swmin; - // - // matLawManager->oilWaterHysteresisParams( - // somax, swmax, swmin, globalDofIdx); - // - // if (matLawManager->enableNonWettingHysteresis()) { - // if (!this->soMax_.empty()) { - // this->soMax_[globalDofIdx] = somax; - // } - // } - // if (matLawManager->enableWettingHysteresis()) { - // if (!this->swMax_.empty()) { - // this->swMax_[globalDofIdx] = swmax; - // } - // } - // if (matLawManager->enablePCHysteresis()) { - // if (!this->swmin_.empty()) { - // this->swmin_[globalDofIdx] = swmin; - // } - // } - // } - // - // if (FluidSystem::phaseIsActive(oilPhaseIdx) - // && FluidSystem::phaseIsActive(gasPhaseIdx)) { - // Scalar sgmax; - // Scalar shmax; - // Scalar somin; - // matLawManager->gasOilHysteresisParams( - // sgmax, shmax, somin, globalDofIdx); - // - // if (matLawManager->enableNonWettingHysteresis()) { - // if (!this->sgmax_.empty()) { - // this->sgmax_[globalDofIdx] = sgmax; - // } - // } - // if (matLawManager->enableWettingHysteresis()) { - // if (!this->shmax_.empty()) { - // this->shmax_[globalDofIdx] = shmax; - // } - // } - // if (matLawManager->enablePCHysteresis()) { - // if (!this->somin_.empty()) { - // this->somin_[globalDofIdx] = somin; - // } - // } - // } - // } else { - // - // if (!this->soMax_.empty()) - // this->soMax_[globalDofIdx] - // = std::max(getValue(fs.saturation(oilPhaseIdx)), problem.maxOilSaturation(globalDofIdx)); - // - // if (!this->swMax_.empty()) - // this->swMax_[globalDofIdx] - // = std::max(getValue(fs.saturation(waterPhaseIdx)), problem.maxWaterSaturation(globalDofIdx)); - // - // } - // if (!this->ppcw_.empty()) { - // this->ppcw_[globalDofIdx] = matLawManager->oilWaterScaledEpsInfoDrainage(globalDofIdx).maxPcow; - // // printf("ppcw_[%d] = %lg\n", globalDofIdx, ppcw_[globalDofIdx]); - // } - // - // // hack to make the intial output of rs and rv Ecl compatible. - // // For cells with swat == 1 Ecl outputs; rs = rsSat and rv=rvSat, in all but the initial step - // // where it outputs rs and rv values calculated by the initialization. To be compatible we overwrite - // // rs and rv with the values computed in the initially. - // // Volume factors, densities and viscosities need to be recalculated with the updated rs and rv values. - // if ((elemCtx.simulator().episodeIndex() < 0) && - // FluidSystem::phaseIsActive(oilPhaseIdx) && - // FluidSystem::phaseIsActive(gasPhaseIdx)) - // { - // const auto& fsInitial = problem.initialFluidState(globalDofIdx); - // - // // use initial rs and rv values - // if (!this->rv_.empty()) - // this->rv_[globalDofIdx] = fsInitial.Rv(); - // - // if (!this->rs_.empty()) - // this->rs_[globalDofIdx] = fsInitial.Rs(); - // - // if (!this->rsw_.empty()) - // this->rsw_[globalDofIdx] = fsInitial.Rsw(); - // - // if (!this->rvw_.empty()) - // this->rvw_[globalDofIdx] = fsInitial.Rvw(); - // - // // re-compute the volume factors, viscosities and densities if asked for - // if (!this->density_[oilPhaseIdx].empty()) - // this->density_[oilPhaseIdx][globalDofIdx] - // = FluidSystem::density(fsInitial, oilPhaseIdx, intQuants.pvtRegionIndex()); - // - // if (!this->density_[gasPhaseIdx].empty()) - // this->density_[gasPhaseIdx][globalDofIdx] - // = FluidSystem::density(fsInitial, gasPhaseIdx, intQuants.pvtRegionIndex()); - // - // if (!this->invB_[oilPhaseIdx].empty()) - // this->invB_[oilPhaseIdx][globalDofIdx] - // = FluidSystem::inverseFormationVolumeFactor(fsInitial, oilPhaseIdx, intQuants.pvtRegionIndex()); - // - // if (!this->invB_[gasPhaseIdx].empty()) - // this->invB_[gasPhaseIdx][globalDofIdx] - // = FluidSystem::inverseFormationVolumeFactor(fsInitial, gasPhaseIdx, intQuants.pvtRegionIndex()); - // - // if (!this->viscosity_[oilPhaseIdx].empty()) - // this->viscosity_[oilPhaseIdx][globalDofIdx] - // = FluidSystem::viscosity(fsInitial, oilPhaseIdx, intQuants.pvtRegionIndex()); - // - // if (!this->viscosity_[gasPhaseIdx].empty()) - // this->viscosity_[gasPhaseIdx][globalDofIdx] - // = FluidSystem::viscosity(fsInitial, gasPhaseIdx, intQuants.pvtRegionIndex()); - // } - // - // // Adding Well RFT data - // const auto cartesianIdx = elemCtx.simulator().vanguard().cartesianIndex(globalDofIdx); - // if (this->oilConnectionPressures_.count(cartesianIdx) > 0) { - // this->oilConnectionPressures_[cartesianIdx] = getValue(fs.pressure(oilPhaseIdx)); - // } - // if (this->waterConnectionSaturations_.count(cartesianIdx) > 0) { - // this->waterConnectionSaturations_[cartesianIdx] = getValue(fs.saturation(waterPhaseIdx)); - // } - // if (this->gasConnectionSaturations_.count(cartesianIdx) > 0) { - // this->gasConnectionSaturations_[cartesianIdx] = getValue(fs.saturation(gasPhaseIdx)); - // } - // - // // tracers - // const auto& tracerModel = simulator_.problem().tracerModel(); - // if (! this->freeTracerConcentrations_.empty()) { - // for (int tracerIdx = 0; tracerIdx < tracerModel.numTracers(); ++tracerIdx) { - // if (this->freeTracerConcentrations_[tracerIdx].empty()) { - // continue; - // } - // this->freeTracerConcentrations_[tracerIdx][globalDofIdx] = - // tracerModel.freeTracerConcentration(tracerIdx, globalDofIdx); - // } - // } - // if (! this->solTracerConcentrations_.empty()) { - // for (int tracerIdx = 0; tracerIdx < tracerModel.numTracers(); ++tracerIdx) { - // if (this->solTracerConcentrations_[tracerIdx].empty()) { - // continue; - // } - // this->solTracerConcentrations_[tracerIdx][globalDofIdx] = - // tracerModel.solTracerConcentration(tracerIdx, globalDofIdx); - // - // } - // } - // - // // output residual - // for ( int phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx ) - // { - // if (!this->residual_[phaseIdx].empty()) { - // const unsigned activeCompIdx = Indices::canonicalToActiveComponentIndex(FluidSystem::solventComponentIndex(phaseIdx)); - // this->residual_[phaseIdx][globalDofIdx] = modelResid[globalDofIdx][activeCompIdx]; - // } - // } } } @@ -751,89 +264,6 @@ public: OPM_TIMEBLOCK_LOCAL(processElementBlockData); if (!std::is_same_v>) return; - - // const auto& problem = elemCtx.simulator().problem(); - // for (unsigned dofIdx = 0; dofIdx < elemCtx.numPrimaryDof(/*timeIdx=*/0); ++dofIdx) { - // - // unsigned globalDofIdx = elemCtx.globalSpaceIndex(dofIdx, /*timeIdx=*/0); - // if (!problem.model().linearizer().getFlowsInfo().empty()) { - // const auto& flowsInf = problem.model().linearizer().getFlowsInfo(); - // auto flowsInfos = flowsInf[globalDofIdx]; - // for (auto& flowsInfo : flowsInfos) { - // if (flowsInfo.faceId >= 0) { - // if (!this->flows_[flowsInfo.faceId][gasCompIdx].empty()) { - // this->flows_[flowsInfo.faceId][gasCompIdx][globalDofIdx] - // = flowsInfo.flow[conti0EqIdx + Indices::canonicalToActiveComponentIndex(gasCompIdx)]; - // } - // if (!this->flows_[flowsInfo.faceId][oilCompIdx].empty()) { - // this->flows_[flowsInfo.faceId][oilCompIdx][globalDofIdx] - // = flowsInfo.flow[conti0EqIdx + Indices::canonicalToActiveComponentIndex(oilCompIdx)]; - // } - // if (!this->flows_[flowsInfo.faceId][waterCompIdx].empty()) { - // this->flows_[flowsInfo.faceId][waterCompIdx][globalDofIdx] - // = flowsInfo.flow[conti0EqIdx + Indices::canonicalToActiveComponentIndex(waterCompIdx)]; - // } - // } - // if (flowsInfo.faceId == -2) { - // if (!this->flowsn_[gasCompIdx].indices.empty()) { - // this->flowsn_[gasCompIdx].indices[flowsInfo.nncId] = flowsInfo.nncId; - // this->flowsn_[gasCompIdx].values[flowsInfo.nncId] - // = flowsInfo.flow[conti0EqIdx + Indices::canonicalToActiveComponentIndex(gasCompIdx)]; - // } - // if (!this->flowsn_[oilCompIdx].indices.empty()) { - // this->flowsn_[oilCompIdx].indices[flowsInfo.nncId] = flowsInfo.nncId; - // this->flowsn_[oilCompIdx].values[flowsInfo.nncId] - // = flowsInfo.flow[conti0EqIdx + Indices::canonicalToActiveComponentIndex(oilCompIdx)]; - // } - // if (!this->flowsn_[waterCompIdx].indices.empty()) { - // this->flowsn_[waterCompIdx].indices[flowsInfo.nncId] = flowsInfo.nncId; - // this->flowsn_[waterCompIdx].values[flowsInfo.nncId] - // = flowsInfo.flow[conti0EqIdx + Indices::canonicalToActiveComponentIndex(waterCompIdx)]; - // } - // } - // } - // } - // - // // flores - // if (!problem.model().linearizer().getFloresInfo().empty()) { - // const auto& floresInf = problem.model().linearizer().getFloresInfo(); - // auto floresInfos =floresInf[globalDofIdx]; - // for (auto& floresInfo : floresInfos) { - // if (floresInfo.faceId >= 0) { - // if (!this->flores_[floresInfo.faceId][gasCompIdx].empty()) { - // this->flores_[floresInfo.faceId][gasCompIdx][globalDofIdx] - // = floresInfo.flow[conti0EqIdx + Indices::canonicalToActiveComponentIndex(gasCompIdx)]; - // } - // if (!this->flores_[floresInfo.faceId][oilCompIdx].empty()) { - // this->flores_[floresInfo.faceId][oilCompIdx][globalDofIdx] - // = floresInfo.flow[conti0EqIdx + Indices::canonicalToActiveComponentIndex(oilCompIdx)]; - // } - // if (!this->flores_[floresInfo.faceId][waterCompIdx].empty()) { - // this->flores_[floresInfo.faceId][waterCompIdx][globalDofIdx] - // = floresInfo.flow[conti0EqIdx + Indices::canonicalToActiveComponentIndex(waterCompIdx)]; - // } - // } - // - // if (floresInfo.faceId == -2) { - // if (!this->floresn_[gasCompIdx].indices.empty()) { - // this->floresn_[gasCompIdx].indices[floresInfo.nncId] = floresInfo.nncId; - // this->floresn_[gasCompIdx].values[floresInfo.nncId] - // = floresInfo.flow[conti0EqIdx + Indices::canonicalToActiveComponentIndex(gasCompIdx)]; - // } - // if (!this->floresn_[oilCompIdx].indices.empty()) { - // this->floresn_[oilCompIdx].indices[floresInfo.nncId] = floresInfo.nncId; - // this->floresn_[oilCompIdx].values[floresInfo.nncId] - // = floresInfo.flow[conti0EqIdx + Indices::canonicalToActiveComponentIndex(oilCompIdx)]; - // } - // if (!this->floresn_[waterCompIdx].indices.empty()) { - // this->floresn_[waterCompIdx].indices[floresInfo.nncId] = floresInfo.nncId; - // this->floresn_[waterCompIdx].values[floresInfo.nncId] - // = floresInfo.flow[conti0EqIdx + Indices::canonicalToActiveComponentIndex(waterCompIdx)]; - // } - // } - // } - // } - // } } void processElementBlockData(const ElementContext& elemCtx) @@ -841,223 +271,6 @@ public: OPM_TIMEBLOCK_LOCAL(processElementBlockData); if (!std::is_same>::value) return; - // - // const auto& problem = elemCtx.simulator().problem(); - // for (unsigned dofIdx = 0; dofIdx < elemCtx.numPrimaryDof(/*timeIdx=*/0); ++dofIdx) { - // // Adding block data - // const auto globalDofIdx = elemCtx.globalSpaceIndex(dofIdx, /*timeIdx=*/0); - // const auto cartesianIdx = elemCtx.simulator().vanguard().cartesianIndex(globalDofIdx); - // const auto& intQuants = elemCtx.intensiveQuantities(dofIdx, /*timeIdx=*/0); - // const auto& fs = intQuants.fluidState(); - // for (auto& val : this->blockData_) { - // const auto& key = val.first; - // assert(key.second > 0); - // - // const auto cartesianIdxBlock = static_cast>>(key.second - 1); - // - // if (cartesianIdx == cartesianIdxBlock) { - // if ((key.first == "BWSAT") || (key.first == "BSWAT")) - // val.second = getValue(fs.saturation(waterPhaseIdx)); - // else if ((key.first == "BGSAT") || (key.first == "BSGAS")) - // val.second = getValue(fs.saturation(gasPhaseIdx)); - // else if ((key.first == "BOSAT") || (key.first == "BSOIL")) - // val.second = getValue(fs.saturation(oilPhaseIdx)); - // else if (key.first == "BNSAT") - // val.second = intQuants.solventSaturation().value(); - // else if ((key.first == "BPR") || (key.first == "BPRESSUR")) { - // if (FluidSystem::phaseIsActive(oilPhaseIdx)) - // val.second = getValue(fs.pressure(oilPhaseIdx)); - // else if (FluidSystem::phaseIsActive(gasPhaseIdx)) - // val.second = getValue(fs.pressure(gasPhaseIdx)); - // else if (FluidSystem::phaseIsActive(waterPhaseIdx)) - // val.second = getValue(fs.pressure(waterPhaseIdx)); - // } - // else if ((key.first == "BTCNFHEA") || (key.first == "BTEMP")) { - // if (FluidSystem::phaseIsActive(oilPhaseIdx)) - // val.second = getValue(fs.temperature(oilPhaseIdx)); - // else if (FluidSystem::phaseIsActive(gasPhaseIdx)) - // val.second = getValue(fs.temperature(gasPhaseIdx)); - // else if (FluidSystem::phaseIsActive(waterPhaseIdx)) - // val.second = getValue(fs.temperature(waterPhaseIdx)); - // } - // else if (key.first == "BWKR" || key.first == "BKRW") - // val.second = getValue(intQuants.relativePermeability(waterPhaseIdx)); - // else if (key.first == "BGKR" || key.first == "BKRG") - // val.second = getValue(intQuants.relativePermeability(gasPhaseIdx)); - // else if (key.first == "BOKR" || key.first == "BKRO") - // val.second = getValue(intQuants.relativePermeability(oilPhaseIdx)); - // else if (key.first == "BKROG") { - // const auto& materialParams = problem.materialLawParams(elemCtx, dofIdx, /* timeIdx = */ 0); - // const auto krog - // = MaterialLaw::template relpermOilInOilGasSystem(materialParams, fs); - // val.second = getValue(krog); - // } - // else if (key.first == "BKROW") { - // const auto& materialParams = problem.materialLawParams(elemCtx, dofIdx, /* timeIdx = */ 0); - // const auto krow - // = MaterialLaw::template relpermOilInOilWaterSystem(materialParams, fs); - // val.second = getValue(krow); - // } - // else if (key.first == "BWPC") - // val.second = getValue(fs.pressure(oilPhaseIdx)) - getValue(fs.pressure(waterPhaseIdx)); - // else if (key.first == "BGPC") - // val.second = getValue(fs.pressure(gasPhaseIdx)) - getValue(fs.pressure(oilPhaseIdx)); - // else if (key.first == "BWPR") - // val.second = getValue(fs.pressure(waterPhaseIdx)); - // else if (key.first == "BGPR") - // val.second = getValue(fs.pressure(gasPhaseIdx)); - // else if (key.first == "BVWAT" || key.first == "BWVIS") - // val.second = getValue(fs.viscosity(waterPhaseIdx)); - // else if (key.first == "BVGAS" || key.first == "BGVIS") - // val.second = getValue(fs.viscosity(gasPhaseIdx)); - // else if (key.first == "BVOIL" || key.first == "BOVIS") - // val.second = getValue(fs.viscosity(oilPhaseIdx)); - // else if ((key.first == "BODEN") || (key.first == "BDENO")) - // val.second = getValue(fs.density(oilPhaseIdx)); - // else if ((key.first == "BGDEN") || (key.first == "BDENG")) - // val.second = getValue(fs.density(gasPhaseIdx)); - // else if ((key.first == "BWDEN") || (key.first == "BDENW")) - // val.second = getValue(fs.density(waterPhaseIdx)); - // else if ((key.first == "BRPV") || - // (key.first == "BOPV") || - // (key.first == "BWPV") || - // (key.first == "BGPV")) - // { - // if (key.first == "BRPV") { - // val.second = 1.0; - // } - // else if (key.first == "BOPV") { - // val.second = getValue(fs.saturation(oilPhaseIdx)); - // } - // else if (key.first == "BWPV") { - // val.second = getValue(fs.saturation(waterPhaseIdx)); - // } - // else { - // val.second = getValue(fs.saturation(gasPhaseIdx)); - // } - // - // // Include active pore-volume. - // val.second *= getValue(intQuants.porosity()) - // * elemCtx.simulator().model().dofTotalVolume(globalDofIdx); - // } - // else if (key.first == "BRS") - // val.second = getValue(fs.Rs()); - // else if (key.first == "BRV") - // val.second = getValue(fs.Rv()); - // else if ((key.first == "BOIP") || (key.first == "BOIPL") || (key.first == "BOIPG") || - // (key.first == "BGIP") || (key.first == "BGIPL") || (key.first == "BGIPG") || - // (key.first == "BWIP")) - // { - // if ((key.first == "BOIP") || (key.first == "BOIPL")) { - // val.second = getValue(fs.invB(oilPhaseIdx)) * getValue(fs.saturation(oilPhaseIdx)); - // - // if (key.first == "BOIP") { - // val.second += getValue(fs.Rv()) * getValue(fs.invB(gasPhaseIdx)) - // * getValue(fs.saturation(gasPhaseIdx)); - // } - // } - // else if (key.first == "BOIPG") { - // val.second = getValue(fs.Rv()) * getValue(fs.invB(gasPhaseIdx)) - // * getValue(fs.saturation(gasPhaseIdx)); - // } - // else if ((key.first == "BGIP") || (key.first == "BGIPG")) { - // val.second = getValue(fs.invB(gasPhaseIdx)) * getValue(fs.saturation(gasPhaseIdx)); - // - // if (key.first == "BGIP") { - // if (!FluidSystem::phaseIsActive(oilPhaseIdx)) { - // val.second += getValue(fs.Rsw()) * getValue(fs.invB(waterPhaseIdx)) - // * getValue(fs.saturation(waterPhaseIdx)); - // } - // else { - // val.second += getValue(fs.Rs()) * getValue(fs.invB(oilPhaseIdx)) - // * getValue(fs.saturation(oilPhaseIdx)); - // } - // } - // } - // else if (key.first == "BGIPL") { - // if (!FluidSystem::phaseIsActive(oilPhaseIdx)) { - // val.second = getValue(fs.Rsw()) * getValue(fs.invB(waterPhaseIdx)) - // * getValue(fs.saturation(waterPhaseIdx)); - // } - // else { - // val.second = getValue(fs.Rs()) * getValue(fs.invB(oilPhaseIdx)) - // * getValue(fs.saturation(oilPhaseIdx)); - // } - // } - // else { // BWIP - // val.second = getValue(fs.invB(waterPhaseIdx)) * getValue(fs.saturation(waterPhaseIdx)); - // } - // - // // Include active pore-volume. - // val.second *= elemCtx.simulator().model().dofTotalVolume(globalDofIdx) - // * getValue(intQuants.porosity()); - // } - // else if ((key.first == "BPPO") || - // (key.first == "BPPG") || - // (key.first == "BPPW")) - // { - // auto phase = RegionPhasePoreVolAverage::Phase{}; - // - // if (key.first == "BPPO") { - // phase.ix = oilPhaseIdx; - // } - // else if (key.first == "BPPG") { - // phase.ix = gasPhaseIdx; - // } - // else { // BPPW - // phase.ix = waterPhaseIdx; - // } - // - // // Note different region handling here. FIPNUM is - // // one-based, but we need zero-based lookup in - // // DatumDepth. On the other hand, pvtRegionIndex is - // // zero-based but we need one-based lookup in - // // RegionPhasePoreVolAverage. - // - // // Subtract one to convert FIPNUM to region index. - // const auto datum = this->eclState_.getSimulationConfig() - // .datumDepths()(this->regions_["FIPNUM"][dofIdx] - 1); - // - // // Add one to convert region index to region ID. - // const auto region = RegionPhasePoreVolAverage::Region { - // elemCtx.primaryVars(dofIdx, /*timeIdx=*/0).pvtRegionIndex() + 1 - // }; - // - // const auto density = this->regionAvgDensity_ - // ->value("PVTNUM", phase, region); - // - // const auto press = getValue(fs.pressure(phase.ix)); - // const auto grav = - // elemCtx.problem().gravity()[GridView::dimensionworld - 1]; - // const auto dz = problem.dofCenterDepth(globalDofIdx) - datum; - // - // val.second = press - density*dz*grav; - // } - // else if ((key.first == "BFLOWI") || - // (key.first == "BFLOWJ") || - // (key.first == "BFLOWK")) - // { - // auto dir = FaceDir::ToIntersectionIndex(Dir::XPlus); - // - // if (key.first == "BFLOWJ") { - // dir = FaceDir::ToIntersectionIndex(Dir::YPlus); - // } - // else if (key.first == "BFLOWK") { - // dir = FaceDir::ToIntersectionIndex(Dir::ZPlus); - // } - // - // val.second = this->flows_[dir][waterCompIdx][globalDofIdx]; - // } - // else { - // std::string logstring = "Keyword '"; - // logstring.append(key.first); - // logstring.append("' is unhandled for output to summary file."); - // OpmLog::warning("Unhandled output keyword", logstring); - // } - // } - // } - // } } /*! @@ -1093,33 +306,6 @@ public: ActiveIndex&& activeIndex, CartesianIndex&& cartesianIndex) { - OPM_TIMEBLOCK_LOCAL(processFluxes); - const auto identifyCell = [&activeIndex, &cartesianIndex](const Element& elem) - -> InterRegFlowMap::Cell - { - const auto cellIndex = activeIndex(elem); - - return { - static_cast(cellIndex), - cartesianIndex(cellIndex), - elem.partitionType() == Dune::InteriorEntity - }; - }; - - const auto timeIdx = 0u; - const auto& stencil = elemCtx.stencil(timeIdx); - const auto numInteriorFaces = elemCtx.numInteriorFaces(timeIdx); - - for (auto scvfIdx = 0 * numInteriorFaces; scvfIdx < numInteriorFaces; ++scvfIdx) { - const auto& face = stencil.interiorFace(scvfIdx); - const auto left = identifyCell(stencil.element(face.interiorIndex())); - const auto right = identifyCell(stencil.element(face.exteriorIndex())); - - const auto rates = this-> - getComponentSurfaceRates(elemCtx, face.area(), scvfIdx, timeIdx); - - this->interRegionFlows_.addConnection(left, right, rates); - } } /*! @@ -1149,122 +335,11 @@ public: return this->interRegionFlows_; } - template - void assignToFluidState(FluidState& fs, unsigned elemIdx) const - { - for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { - if (this->saturation_[phaseIdx].empty()) - continue; - - fs.setSaturation(phaseIdx, this->saturation_[phaseIdx][elemIdx]); - } - - if (!this->fluidPressure_.empty()) { - // this assumes that capillary pressures only depend on the phase saturations - // and possibly on temperature. (this is always the case for ECL problems.) - std::array pc = {0}; - const MaterialLawParams& matParams = simulator_.problem().materialLawParams(elemIdx); - MaterialLaw::capillaryPressures(pc, matParams, fs); - Valgrind::CheckDefined(this->fluidPressure_[elemIdx]); - Valgrind::CheckDefined(pc); - assert(FluidSystem::phaseIsActive(oilPhaseIdx)); - for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { - if (!FluidSystem::phaseIsActive(phaseIdx)) - continue; - - fs.setPressure(phaseIdx, this->fluidPressure_[elemIdx] + (pc[phaseIdx] - pc[oilPhaseIdx])); - } - } - - if (!this->temperature_.empty()) - fs.setTemperature(this->temperature_[elemIdx]); - if (!this->rs_.empty()) - fs.setRs(this->rs_[elemIdx]); - if (!this->rsw_.empty()) - fs.setRsw(this->rsw_[elemIdx]); - if (!this->rv_.empty()) - fs.setRv(this->rv_[elemIdx]); - if (!this->rvw_.empty()) - fs.setRvw(this->rvw_[elemIdx]); - } - - void initHysteresisParams(Simulator& simulator, unsigned elemIdx) const - { - if (!this->soMax_.empty()) - simulator.problem().setMaxOilSaturation(elemIdx, this->soMax_[elemIdx]); - - if (simulator.problem().materialLawManager()->enableHysteresis()) { - auto matLawManager = simulator.problem().materialLawManager(); - - if (FluidSystem::phaseIsActive(oilPhaseIdx) - && FluidSystem::phaseIsActive(waterPhaseIdx)) { - Scalar somax = 2.0; - Scalar swmax = -2.0; - Scalar swmin = 2.0; - - if (matLawManager->enableNonWettingHysteresis()) { - if (!this->soMax_.empty()) { - somax = this->soMax_[elemIdx]; - } - } - if (matLawManager->enableWettingHysteresis()) { - if (!this->swMax_.empty()) { - swmax = this->swMax_[elemIdx]; - } - } - if (matLawManager->enablePCHysteresis()) { - if (!this->swmin_.empty()) { - swmin = this->swmin_[elemIdx]; - } - } - matLawManager->setOilWaterHysteresisParams( - somax, swmax, swmin, elemIdx); - } - if (FluidSystem::phaseIsActive(oilPhaseIdx) - && FluidSystem::phaseIsActive(gasPhaseIdx)) { - Scalar sgmax = 2.0; - Scalar shmax = -2.0; - Scalar somin = 2.0; - - if (matLawManager->enableNonWettingHysteresis()) { - if (!this->sgmax_.empty()) { - sgmax = this->sgmax_[elemIdx]; - } - } - if (matLawManager->enableWettingHysteresis()) { - if (!this->shmax_.empty()) { - shmax = this->shmax_[elemIdx]; - } - } - if (matLawManager->enablePCHysteresis()) { - if (!this->somin_.empty()) { - somin = this->somin_[elemIdx]; - } - } - matLawManager->setGasOilHysteresisParams( - sgmax, shmax, somin, elemIdx); - } - - } - - if (simulator_.vanguard().eclState().fieldProps().has_double("SWATINIT")) { - simulator.problem().materialLawManager() - ->applyRestartSwatInit(elemIdx, this->ppcw_[elemIdx]); - } - } - - void updateFluidInPlace(const ElementContext& elemCtx) - { - for (unsigned dofIdx = 0; dofIdx < elemCtx.numPrimaryDof(/*timeIdx=*/0); ++dofIdx) { - updateFluidInPlace_(elemCtx, dofIdx); - } - } - void updateFluidInPlace(const unsigned globalDofIdx, const IntensiveQuantities& intQuants, const double totVolume) { - this->updateFluidInPlace_(globalDofIdx, intQuants, totVolume); +// this->updateFluidInPlace_(globalDofIdx, intQuants, totVolume); } private: @@ -1278,28 +353,6 @@ private: return candidate == parallelWells.end() || *candidate != value; } - void updateFluidInPlace_(const ElementContext& elemCtx, const unsigned dofIdx) - { - const auto& intQuants = elemCtx.intensiveQuantities(dofIdx, /*timeIdx=*/0); - const unsigned globalDofIdx = elemCtx.globalSpaceIndex(dofIdx, /*timeIdx=*/0); - const auto totVolume = elemCtx.simulator().model().dofTotalVolume(globalDofIdx); - - this->updateFluidInPlace_(globalDofIdx, intQuants, totVolume); - } - - void updateFluidInPlace_(const unsigned globalDofIdx, - const IntensiveQuantities& intQuants, - const double totVolume) - { - OPM_TIMEBLOCK_LOCAL(updateFluidInPlace); - - this->updateTotalVolumesAndPressures_(globalDofIdx, intQuants, totVolume); - - if (this->computeFip_) { - this->updatePhaseInplaceVolumes_(globalDofIdx, intQuants, totVolume); - } - } - void createLocalRegion_(std::vector& region) { std::size_t elemIdx = 0; @@ -1312,562 +365,9 @@ private: } } - template - void aggregateAverageDensityContributions_(const FluidState& fs, - const unsigned int globalDofIdx, - const double porv) - { - auto pvCellValue = RegionPhasePoreVolAverage::CellValue{}; - pvCellValue.porv = porv; - - for (auto phaseIdx = 0*FluidSystem::numPhases; - phaseIdx < FluidSystem::numPhases; ++phaseIdx) - { - if (! FluidSystem::phaseIsActive(phaseIdx)) { - continue; - } - - pvCellValue.value = getValue(fs.density(phaseIdx)); - pvCellValue.sat = getValue(fs.saturation(phaseIdx)); - - this->regionAvgDensity_ - ->addCell(globalDofIdx, - RegionPhasePoreVolAverage::Phase { phaseIdx }, - pvCellValue); - } - } - - /*! - * \brief Compute surface level component flow rates across a single - * intersection. - * - * \param[in] elemCtx Primary lookup structure for per-cell/element - * dynamic information. - * - * \param[in] scvfIdx Linear index of current interior bulk connection. - * - * \param[in] timeIdx Historical time-point at which to evaluate dynamic - * quantities (e.g., reciprocal FVF or dissolved gas concentration). - * Zero for the current time. - * - * \return Surface level component flow rates. - */ - data::InterRegFlowMap::FlowRates - getComponentSurfaceRates(const ElementContext& elemCtx, - const Scalar faceArea, - const std::size_t scvfIdx, - const std::size_t timeIdx) const - { - using Component = data::InterRegFlowMap::Component; - - auto rates = data::InterRegFlowMap::FlowRates {}; - // - // const auto& extQuant = elemCtx.extensiveQuantities(scvfIdx, timeIdx); - // - // const auto alpha = getValue(extQuant.extrusionFactor()) * faceArea; - // - // if (FluidSystem::phaseIsActive(oilPhaseIdx)) { - // const auto& up = elemCtx - // .intensiveQuantities(extQuant.upstreamIndex(oilPhaseIdx), timeIdx); - // - // using FluidState = std::remove_cv_t>; - // - // const auto pvtReg = up.pvtRegionIndex(); - // - // const auto bO = getValue(getInvB_ - // (up.fluidState(), oilPhaseIdx, pvtReg)); - // - // const auto qO = alpha * bO * getValue(extQuant.volumeFlux(oilPhaseIdx)); - // - // rates[Component::Oil] += qO; - // - // if (FluidSystem::phaseIsActive(gasPhaseIdx)) { - // const auto Rs = getValue( - // BlackOil::getRs_ - // (up.fluidState(), pvtReg)); - // - // rates[Component::Gas] += qO * Rs; - // rates[Component::Disgas] += qO * Rs; - // } - // } - // - // if (FluidSystem::phaseIsActive(gasPhaseIdx)) { - // const auto& up = elemCtx - // .intensiveQuantities(extQuant.upstreamIndex(gasPhaseIdx), timeIdx); - // - // using FluidState = std::remove_cv_t>; - // - // const auto pvtReg = up.pvtRegionIndex(); - // - // const auto bG = getValue(getInvB_ - // (up.fluidState(), gasPhaseIdx, pvtReg)); - // - // const auto qG = alpha * bG * getValue(extQuant.volumeFlux(gasPhaseIdx)); - // - // rates[Component::Gas] += qG; - // - // if (FluidSystem::phaseIsActive(oilPhaseIdx)) { - // const auto Rv = getValue( - // BlackOil::getRv_ - // (up.fluidState(), pvtReg)); - // - // rates[Component::Oil] += qG * Rv; - // rates[Component::Vapoil] += qG * Rv; - // } - // } - // - // if (FluidSystem::phaseIsActive(waterPhaseIdx)) { - // const auto& up = elemCtx - // .intensiveQuantities(extQuant.upstreamIndex(waterPhaseIdx), timeIdx); - // - // using FluidState = std::remove_cv_t>; - // - // const auto pvtReg = up.pvtRegionIndex(); - // - // const auto bW = getValue(getInvB_ - // (up.fluidState(), waterPhaseIdx, pvtReg)); - // - // rates[Component::Water] += - // alpha * bW * getValue(extQuant.volumeFlux(waterPhaseIdx)); - // } - - return rates; - } - - template - Scalar hydroCarbonFraction(const FluidState& fs) const - { - if (this->eclState_.runspec().co2Storage()) { - // CO2 storage: Hydrocarbon volume is full pore-volume. - return 1.0; - } - - // Common case. Hydrocarbon volume is fraction occupied by actual - // hydrocarbons. - auto hydrocarbon = Scalar {0}; - if (FluidSystem::phaseIsActive(oilPhaseIdx)) { - hydrocarbon += getValue(fs.saturation(oilPhaseIdx)); - } - - if (FluidSystem::phaseIsActive(gasPhaseIdx)) { - hydrocarbon += getValue(fs.saturation(gasPhaseIdx)); - } - - return hydrocarbon; - } - - void updateTotalVolumesAndPressures_(const unsigned globalDofIdx, - const IntensiveQuantities& intQuants, - const double totVolume) - { - const auto& fs = intQuants.fluidState(); - - const double pv = totVolume * intQuants.porosity().value(); - const auto hydrocarbon = this->hydroCarbonFraction(fs); - - if (! this->hydrocarbonPoreVolume_.empty()) { - this->fip_[Inplace::Phase::PoreVolume][globalDofIdx] = 0; -// totVolume * intQuants.referencePorosity(); - - this->dynamicPoreVolume_[globalDofIdx] = pv; - this->hydrocarbonPoreVolume_[globalDofIdx] = pv * hydrocarbon; - } - - if (!this->pressureTimesHydrocarbonVolume_.empty() && - !this->pressureTimesPoreVolume_.empty()) - { - assert(this->hydrocarbonPoreVolume_.size() == this->pressureTimesHydrocarbonVolume_.size()); - assert(this->fip_[Inplace::Phase::PoreVolume].size() == this->pressureTimesPoreVolume_.size()); - - if (FluidSystem::phaseIsActive(oilPhaseIdx)) { - this->pressureTimesPoreVolume_[globalDofIdx] = - getValue(fs.pressure(oilPhaseIdx)) * pv; - - this->pressureTimesHydrocarbonVolume_[globalDofIdx] = - this->pressureTimesPoreVolume_[globalDofIdx] * hydrocarbon; - } - else if (FluidSystem::phaseIsActive(gasPhaseIdx)) { - this->pressureTimesPoreVolume_[globalDofIdx] = - getValue(fs.pressure(gasPhaseIdx)) * pv; - - this->pressureTimesHydrocarbonVolume_[globalDofIdx] = - this->pressureTimesPoreVolume_[globalDofIdx] * hydrocarbon; - } - else if (FluidSystem::phaseIsActive(waterPhaseIdx)) { - this->pressureTimesPoreVolume_[globalDofIdx] = - getValue(fs.pressure(waterPhaseIdx)) * pv; - } - } - } - - void updatePhaseInplaceVolumes_(const unsigned globalDofIdx, - const IntensiveQuantities& intQuants, - const double totVolume) - { - // std::array fip {}; - // std::array fipr{}; // at reservoir condition - // - // const auto& fs = intQuants.fluidState(); - // const auto pv = totVolume * intQuants.porosity().value(); - // - // for (unsigned phaseIdx = 0; phaseIdx < FluidSystem::numPhases; ++phaseIdx) { - // if (!FluidSystem::phaseIsActive(phaseIdx)) { - // continue; - // } - // - // const auto b = getValue(fs.invB(phaseIdx)); - // const auto s = getValue(fs.saturation(phaseIdx)); - // - // fipr[phaseIdx] = s * pv; - // fip [phaseIdx] = b * fipr[phaseIdx]; - // } - // - // this->updateInplaceVolumesSurface(globalDofIdx, fip); - // this->updateInplaceVolumesReservoir(globalDofIdx, fs, fipr); - // - // if (FluidSystem::phaseIsActive(oilPhaseIdx) && - // FluidSystem::phaseIsActive(gasPhaseIdx)) - // { - // this->updateOilGasDistribution(globalDofIdx, fs, fip); - // } - // - // if (FluidSystem::phaseIsActive(waterPhaseIdx) && - // FluidSystem::phaseIsActive(gasPhaseIdx)) - // { - // this->updateGasWaterDistribution(globalDofIdx, fs, fip); - // } - // - // if (FluidSystem::phaseIsActive(gasPhaseIdx) && - // (!this->fip_[Inplace::Phase::CO2InGasPhaseInMob].empty() || - // !this->fip_[Inplace::Phase::CO2InGasPhaseMob].empty() || - // !this->fip_[Inplace::Phase::CO2MassInGasPhaseInMob].empty() || - // !this->fip_[Inplace::Phase::CO2MassInGasPhaseMob].empty() || - // !this->fip_[Inplace::Phase::CO2Mass].empty() || - // !this->fip_[Inplace::Phase::CO2MassInGasPhase].empty() || - // !this->fip_[Inplace::Phase::CO2InGasPhaseInMobKrg].empty() || - // !this->fip_[Inplace::Phase::CO2InGasPhaseMobKrg].empty() || - // !this->fip_[Inplace::Phase::CO2MassInGasPhaseInMobKrg].empty() || - // !this->fip_[Inplace::Phase::CO2MassInGasPhaseMobKrg].empty() || - // !this->fip_[Inplace::Phase::CO2MassInGasPhaseEffectiveTrapped].empty() || - // !this->fip_[Inplace::Phase::CO2MassInGasPhaseEffectiveUnTrapped].empty() || - // !this->fip_[Inplace::Phase::CO2MassInGasPhaseMaximumTrapped].empty() || - // !this->fip_[Inplace::Phase::CO2MassInGasPhaseMaximumUnTrapped].empty())) - // { - // this->updateCO2InGas(globalDofIdx, pv, intQuants); - // } - // - // if ((!this->fip_[Inplace::Phase::CO2InWaterPhase].empty() || - // !this->fip_[Inplace::Phase::CO2MassInWaterPhase].empty() || - // !this->fip_[Inplace::Phase::CO2Mass].empty()) && - // (FluidSystem::phaseIsActive(waterPhaseIdx) || - // FluidSystem::phaseIsActive(oilPhaseIdx))) - // { - // this->updateCO2InWater(globalDofIdx, pv, fs); - // } - } - - template - void updateInplaceVolumesSurface(const unsigned globalDofIdx, - const FIPArray& fip) - { - if (FluidSystem::phaseIsActive(oilPhaseIdx) && - !this->fip_[Inplace::Phase::OIL].empty()) - { - this->fip_[Inplace::Phase::OIL][globalDofIdx] = fip[oilPhaseIdx]; - } - - if (FluidSystem::phaseIsActive(oilPhaseIdx) && - !this->fip_[Inplace::Phase::OilInLiquidPhase].empty()) - { - this->fip_[Inplace::Phase::OilInLiquidPhase][globalDofIdx] = fip[oilPhaseIdx]; - } - - if (FluidSystem::phaseIsActive(gasPhaseIdx) && - !this->fip_[Inplace::Phase::GAS].empty()) - { - this->fip_[Inplace::Phase::GAS][globalDofIdx] = fip[gasPhaseIdx]; - } - - if (FluidSystem::phaseIsActive(gasPhaseIdx) && - !this->fip_[Inplace::Phase::GasInGasPhase].empty()) - { - this->fip_[Inplace::Phase::GasInGasPhase][globalDofIdx] = fip[gasPhaseIdx]; - } - - if (FluidSystem::phaseIsActive(waterPhaseIdx) && - !this->fip_[Inplace::Phase::WATER].empty()) - { - this->fip_[Inplace::Phase::WATER][globalDofIdx] = fip[waterPhaseIdx]; - } - } - - template - void updateInplaceVolumesReservoir(const unsigned globalDofIdx, - const FluidState& fs, - const FIPArray& fipr) - { - if (FluidSystem::phaseIsActive(oilPhaseIdx) && - !this->fip_[Inplace::Phase::OilResVolume].empty()) - { - this->fip_[Inplace::Phase::OilResVolume][globalDofIdx] = fipr[oilPhaseIdx]; - } - - if (FluidSystem::phaseIsActive(gasPhaseIdx) && - !this->fip_[Inplace::Phase::GasResVolume].empty()) - { - this->fip_[Inplace::Phase::GasResVolume][globalDofIdx] = fipr[gasPhaseIdx]; - } - - if (FluidSystem::phaseIsActive(waterPhaseIdx) && - !this->fip_[Inplace::Phase::WaterResVolume].empty()) - { - this->fip_[Inplace::Phase::WaterResVolume][globalDofIdx] = fipr[waterPhaseIdx]; - } - - if (FluidSystem::phaseIsActive(waterPhaseIdx) && - !this->fip_[Inplace::Phase::SALT].empty()) - { - this->fip_[Inplace::Phase::SALT][globalDofIdx] = - fipr[waterPhaseIdx] * fs.saltConcentration().value(); - } - } - - template - void updateOilGasDistribution(const unsigned globalDofIdx, - const FluidState& fs, - const FIPArray& fip) - { - // Gas dissolved in oil and vaporized oil - const auto gasInPlaceLiquid = getValue(fs.Rs()) * fip[oilPhaseIdx]; - const auto oilInPlaceGas = getValue(fs.Rv()) * fip[gasPhaseIdx]; - - if (!this->fip_[Inplace::Phase::GasInLiquidPhase].empty()) { - this->fip_[Inplace::Phase::GasInLiquidPhase][globalDofIdx] = gasInPlaceLiquid; - } - - if (!this->fip_[Inplace::Phase::OilInGasPhase].empty()) { - this->fip_[Inplace::Phase::OilInGasPhase][globalDofIdx] = oilInPlaceGas; - } - - // Add dissolved gas and vaporized oil to total Fip - if (!this->fip_[Inplace::Phase::OIL].empty()) { - this->fip_[Inplace::Phase::OIL][globalDofIdx] += oilInPlaceGas; - } - - if (!this->fip_[Inplace::Phase::GAS].empty()) { - this->fip_[Inplace::Phase::GAS][globalDofIdx] += gasInPlaceLiquid; - } - } - - template - void updateGasWaterDistribution(const unsigned globalDofIdx, - const FluidState& fs, - const FIPArray& fip) - { - // Gas dissolved in water and vaporized water - const auto gasInPlaceWater = getValue(fs.Rsw()) * fip[waterPhaseIdx]; - const auto waterInPlaceGas = getValue(fs.Rvw()) * fip[gasPhaseIdx]; - - if (!this->fip_[Inplace::Phase::WaterInGasPhase].empty()) { - this->fip_[Inplace::Phase::WaterInGasPhase][globalDofIdx] = waterInPlaceGas; - } - - if (!this->fip_[Inplace::Phase::WaterInWaterPhase].empty()) { - this->fip_[Inplace::Phase::WaterInWaterPhase][globalDofIdx] = fip[waterPhaseIdx]; - } - - // For water+gas cases the gas in water is added to the GIPL value - if (!this->fip_[Inplace::Phase::GasInLiquidPhase].empty() && - !FluidSystem::phaseIsActive(oilPhaseIdx)) - { - this->fip_[Inplace::Phase::GasInLiquidPhase][globalDofIdx] = gasInPlaceWater; - } - - // Add dissolved gas and vaporized water to total Fip - if (!this->fip_[Inplace::Phase::WATER].empty()) { - this->fip_[Inplace::Phase::WATER][globalDofIdx] += waterInPlaceGas; - } - - if (!this->fip_[Inplace::Phase::GAS].empty()) { - this->fip_[Inplace::Phase::GAS][globalDofIdx] += gasInPlaceWater; - } - } - - template - void updateCO2InGas(const unsigned globalDofIdx, - const double pv, - const IntensiveQuantities& intQuants) - { - const auto& scaledDrainageInfo = this->simulator_.problem().materialLawManager() - ->oilWaterScaledEpsInfoDrainage(globalDofIdx); - - const auto& fs = intQuants.fluidState(); - Scalar sgcr = scaledDrainageInfo.Sgcr; - if (this->simulator_.problem().materialLawManager()->enableHysteresis()) { - const auto& matParams = simulator_.problem().materialLawParams(globalDofIdx); - sgcr = MaterialLaw::trappedGasSaturation(matParams, /*maximumTrapping*/false); - } - - const Scalar sg = getValue(fs.saturation(gasPhaseIdx)); - const Scalar rhog = getValue(fs.density(gasPhaseIdx)); - const Scalar xgW = FluidSystem::phaseIsActive(waterPhaseIdx) - ? FluidSystem::convertRvwToXgW(getValue(fs.Rvw()), fs.pvtRegionIndex()) - : FluidSystem::convertRvToXgO(getValue(fs.Rv()), fs.pvtRegionIndex()); - - const Scalar mM = FluidSystem::molarMass(gasCompIdx, fs.pvtRegionIndex()); - const Scalar massGas = (1 - xgW) * pv * rhog; - if (!this->fip_[Inplace::Phase::CO2Mass].empty()) { - this->fip_[Inplace::Phase::CO2Mass][globalDofIdx] = massGas * sg; - } - - if (!this->fip_[Inplace::Phase::CO2MassInGasPhase].empty()) { - this->fip_[Inplace::Phase::CO2MassInGasPhase][globalDofIdx] = massGas * sg; - } - - if (!this->fip_[Inplace::Phase::CO2InGasPhaseInMob].empty()) { - const Scalar imMobileGas = massGas / mM * std::min(sgcr , sg); - this->fip_[Inplace::Phase::CO2InGasPhaseInMob][globalDofIdx] = imMobileGas; - } - - if (!this->fip_[Inplace::Phase::CO2InGasPhaseMob].empty()) { - const Scalar mobileGas = massGas / mM * std::max(Scalar{0.0}, sg - sgcr); - this->fip_[Inplace::Phase::CO2InGasPhaseMob][globalDofIdx] = mobileGas; - } - - if (!this->fip_[Inplace::Phase::CO2InGasPhaseInMobKrg].empty()) { - if (sgcr >= sg) { - const Scalar imMobileGasKrg = massGas / mM * sg; - this->fip_[Inplace::Phase::CO2InGasPhaseInMobKrg][globalDofIdx] = imMobileGasKrg; - } else { - this->fip_[Inplace::Phase::CO2InGasPhaseInMobKrg][globalDofIdx] = 0; - } - } - - if (!this->fip_[Inplace::Phase::CO2InGasPhaseMobKrg].empty()) { - if (sg > sgcr) { - const Scalar mobileGasKrg = massGas / mM * sg; - this->fip_[Inplace::Phase::CO2InGasPhaseMobKrg][globalDofIdx] = mobileGasKrg; - } else { - this->fip_[Inplace::Phase::CO2InGasPhaseMobKrg][globalDofIdx] = 0; - } - } - - if (!this->fip_[Inplace::Phase::CO2MassInGasPhaseInMob].empty()) { - const Scalar imMobileMassGas = massGas * std::min(sgcr , sg); - this->fip_[Inplace::Phase::CO2MassInGasPhaseInMob][globalDofIdx] = imMobileMassGas; - } - - if (!this->fip_[Inplace::Phase::CO2MassInGasPhaseMob].empty()) { - const Scalar mobileMassGas = massGas * std::max(Scalar{0.0}, sg - sgcr); - this->fip_[Inplace::Phase::CO2MassInGasPhaseMob][globalDofIdx] = mobileMassGas; - } - - if (!this->fip_[Inplace::Phase::CO2MassInGasPhaseInMobKrg].empty()) { - if (sgcr >= sg) { - const Scalar imMobileMassGasKrg = massGas * sg; - this->fip_[Inplace::Phase::CO2MassInGasPhaseInMobKrg][globalDofIdx] = imMobileMassGasKrg; - } else { - this->fip_[Inplace::Phase::CO2MassInGasPhaseInMobKrg][globalDofIdx] = 0; - } - } - - if (!this->fip_[Inplace::Phase::CO2MassInGasPhaseMobKrg].empty()) { - if (sg > sgcr) { - const Scalar mobileMassGasKrg = massGas * sg; - this->fip_[Inplace::Phase::CO2MassInGasPhaseMobKrg][globalDofIdx] = mobileMassGasKrg; - } else { - this->fip_[Inplace::Phase::CO2MassInGasPhaseMobKrg][globalDofIdx] = 0; - } - } - - if (!this->fip_[Inplace::Phase::CO2MassInGasPhaseMaximumTrapped].empty() || - !this->fip_[Inplace::Phase::CO2MassInGasPhaseMaximumUnTrapped].empty() ) { - Scalar trappedGasSaturation = scaledDrainageInfo.Sgcr; - if (this->simulator_.problem().materialLawManager()->enableHysteresis()) { - const auto& matParams = simulator_.problem().materialLawParams(globalDofIdx); - // Get the maximum trapped gas saturation - trappedGasSaturation = MaterialLaw::trappedGasSaturation(matParams, /*maximumTrapping*/true); - } - if (!this->fip_[Inplace::Phase::CO2MassInGasPhaseMaximumTrapped].empty()) { - const Scalar imMobileMassGas = massGas * std::min(trappedGasSaturation , sg); - this->fip_[Inplace::Phase::CO2MassInGasPhaseMaximumTrapped][globalDofIdx] = imMobileMassGas; - } - if (!this->fip_[Inplace::Phase::CO2MassInGasPhaseMaximumUnTrapped].empty()) { - const Scalar mobileMassGas = massGas * std::max(Scalar{0.0}, sg - trappedGasSaturation); - this->fip_[Inplace::Phase::CO2MassInGasPhaseMaximumUnTrapped][globalDofIdx] = mobileMassGas; - } - } - - if (!this->fip_[Inplace::Phase::CO2MassInGasPhaseEffectiveTrapped].empty() || - !this->fip_[Inplace::Phase::CO2MassInGasPhaseEffectiveUnTrapped].empty()) { - Scalar trappedGasSaturation = scaledDrainageInfo.Sgcr; - if (this->simulator_.problem().materialLawManager()->enableHysteresis()) { - const auto& matParams = simulator_.problem().materialLawParams(globalDofIdx); - const double krg = getValue(intQuants.relativePermeability(gasPhaseIdx)); - trappedGasSaturation = MaterialLaw::strandedGasSaturation(matParams, sg, krg); - } - if (!this->fip_[Inplace::Phase::CO2MassInGasPhaseEffectiveTrapped].empty()) { - const Scalar imMobileMassGas = massGas * std::min(trappedGasSaturation , sg); - this->fip_[Inplace::Phase::CO2MassInGasPhaseEffectiveTrapped][globalDofIdx] = imMobileMassGas; - } - if (!this->fip_[Inplace::Phase::CO2MassInGasPhaseEffectiveUnTrapped].empty()) { - const Scalar mobileMassGas = massGas * std::max(Scalar{0.0}, sg - trappedGasSaturation); - this->fip_[Inplace::Phase::CO2MassInGasPhaseEffectiveUnTrapped][globalDofIdx] = mobileMassGas; - } - } - } - - template - void updateCO2InWater(const unsigned globalDofIdx, - const double pv, - const FluidState& fs) - { - const auto co2InWater = FluidSystem::phaseIsActive(oilPhaseIdx) - ? this->co2InWaterFromOil(fs, pv) - : this->co2InWaterFromWater(fs, pv); - - const Scalar mM = FluidSystem::molarMass(gasCompIdx, fs.pvtRegionIndex()); - if (!this->fip_[Inplace::Phase::CO2Mass].empty()) { - this->fip_[Inplace::Phase::CO2Mass][globalDofIdx] += co2InWater * mM; - } - if (!this->fip_[Inplace::Phase::CO2MassInWaterPhase].empty()) { - this->fip_[Inplace::Phase::CO2MassInWaterPhase][globalDofIdx] = co2InWater * mM; - } - if (!this->fip_[Inplace::Phase::CO2InWaterPhase].empty()) { - this->fip_[Inplace::Phase::CO2InWaterPhase][globalDofIdx] = co2InWater; - } - } - - template - Scalar co2InWaterFromWater(const FluidState& fs, const double pv) const - { - const double rhow = getValue(fs.density(waterPhaseIdx)); - const double sw = getValue(fs.saturation(waterPhaseIdx)); - const double xwG = FluidSystem::convertRswToXwG(getValue(fs.Rsw()), fs.pvtRegionIndex()); - - const Scalar mM = FluidSystem::molarMass(gasCompIdx, fs.pvtRegionIndex()); - - return xwG * pv * rhow * sw / mM; - } - - template - Scalar co2InWaterFromOil(const FluidState& fs, const double pv) const - { - const double rhoo = getValue(fs.density(oilPhaseIdx)); - const double so = getValue(fs.saturation(oilPhaseIdx)); - const double xoG = FluidSystem::convertRsToXoG(getValue(fs.Rs()), fs.pvtRegionIndex()); - - const Scalar mM = FluidSystem::molarMass(gasCompIdx, fs.pvtRegionIndex()); - - return xoG * pv * rhoo * so / mM; - } - const Simulator& simulator_; }; } // namespace Opm -#endif // OPM_OUTPUT_BLACK_OIL_MODULE_HPP +#endif // OPM_OUTPUT_COMPOSITIONAL_MODULE_HPP From 197282ccfcf0b98d15c9f808e704185652f46098 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Thu, 17 Oct 2024 13:05:39 +0200 Subject: [PATCH 05/15] cleaing up EclWriter related and DamarisWriter.hpp --- flowexperimental/comp/EmptyModel.hpp | 97 +++++++++ flowexperimental/comp/flowexp_comp.hpp | 51 +---- opm/simulators/flow/DamarisWriter.hpp | 2 +- opm/simulators/flow/EclGenericWriter.hpp | 7 - opm/simulators/flow/EclGenericWriter_impl.hpp | 133 +++--------- opm/simulators/flow/EclWriter.hpp | 202 +++++++++--------- 6 files changed, 220 insertions(+), 272 deletions(-) create mode 100644 flowexperimental/comp/EmptyModel.hpp diff --git a/flowexperimental/comp/EmptyModel.hpp b/flowexperimental/comp/EmptyModel.hpp new file mode 100644 index 000000000..9b772320c --- /dev/null +++ b/flowexperimental/comp/EmptyModel.hpp @@ -0,0 +1,97 @@ +/* + Copyright 2024, SINTEF Digital + + 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 . +*/ + + +// this is an empty model that having a lot of empty interfaces. +// it is use for the development when some facility class are not ready + +#include +#include + +#include +#include + +namespace Opm { + +template +class EmptyModel : public BaseAuxiliaryModule +{ + using Scalar = GetPropType; + using GridView = GetPropType; + using GlobalEqVector = GetPropType; + using SparseMatrixAdapter = GetPropType; + +public: + using Simulator = GetPropType; + EmptyModel(Simulator& /*simulator*/) + { + } + + void init(){} + template + void init(Something /*A*/){} + void prepareTracerBatches(){}; + using NeighborSet = std::set; + void linearize(SparseMatrixAdapter& /*matrix*/, GlobalEqVector& /*residual*/){}; + unsigned numDofs() const{return 0;}; + void addNeighbors(std::vector& /*neighbors*/) const{}; + //void applyInitial(){}; + void initialSolutionApplied(){}; + //void initFromRestart(const data::Aquifers& aquiferSoln); + template + void serialize(Restarter& /*res*/){}; + + template + void deserialize(Restarter& /*res*/){}; + + void beginEpisode(){}; + void beginTimeStep(){}; + void beginIteration(){}; + // add the water rate due to aquifers to the source term. + template + void addToSource(RateVector& /*rates*/, const Context& /*context*/, + unsigned /*spaceIdx*/, unsigned /*timeIdx*/) const {} + template + void addToSource(RateVector& /*rates*/, unsigned /*globalSpaceIdx*/, + unsigned /*timeIdx*/) const {} + void endIteration()const{}; + void endTimeStep(){}; + void endEpisode(){}; + void applyInitial(){}; + template + void computeTotalRatesForDof(RateType& /*rate*/, unsigned /*globalIdx*/) const{}; + + auto wellData() const { + return data::Wells{}; + } + auto wellBlockAveragePressures() const { + return data::WellBlockAveragePressures{}; + } + auto groupAndNetworkData(const int&) const { + return data::GroupAndNetworkValues{}; + } + auto wellTestState() const { + return WellTestState{}; + } + auto aquiferData() const { + return data::Aquifers{}; + } +}; + +} // end of namespace Opm diff --git a/flowexperimental/comp/flowexp_comp.hpp b/flowexperimental/comp/flowexp_comp.hpp index 10884ab55..213d63c07 100644 --- a/flowexperimental/comp/flowexp_comp.hpp +++ b/flowexperimental/comp/flowexp_comp.hpp @@ -30,6 +30,8 @@ #include +#include + // // the current code use eclnewtonmethod adding other conditions to proceed_ should do the trick for KA // // adding linearshe sould be chaning the update_ function in the same class with condition that the error is reduced. // the trick is to be able to recalculate the residual from here. @@ -37,55 +39,6 @@ // suggestTimeStep is taken from newton solver in problem.limitTimestep namespace Opm { -template -class EmptyModel : public BaseAuxiliaryModule -{ - using Scalar = GetPropType; - using GridView = GetPropType; - using GlobalEqVector = GetPropType; - using SparseMatrixAdapter = GetPropType; - -public: - using Simulator = GetPropType; - EmptyModel(Simulator& /*simulator*/) - { - } - - void init(){} - template - void init(Something /*A*/){} - void prepareTracerBatches(){}; - using NeighborSet = std::set; - void linearize(SparseMatrixAdapter& /*matrix*/, GlobalEqVector& /*residual*/){}; - unsigned numDofs() const{return 0;}; - void addNeighbors(std::vector& /*neighbors*/) const{}; - //void applyInitial(){}; - void initialSolutionApplied(){}; - //void initFromRestart(const data::Aquifers& aquiferSoln); - template - void serialize(Restarter& /*res*/){}; - - template - void deserialize(Restarter& /*res*/){}; - - void beginEpisode(){}; - void beginTimeStep(){}; - void beginIteration(){}; - // add the water rate due to aquifers to the source term. - template - void addToSource(RateVector& /*rates*/, const Context& /*context*/, - unsigned /*spaceIdx*/, unsigned /*timeIdx*/) const {} - template - void addToSource(RateVector& /*rates*/, unsigned /*globalSpaceIdx*/, - unsigned /*timeIdx*/) const {} - void endIteration()const{}; - void endTimeStep(){}; - void endEpisode(){}; - void applyInitial(){}; - template - void computeTotalRatesForDof(RateType& /*rate*/, unsigned /*globalIdx*/) const{}; -}; - template int dispatchFlowExpComp(int argc, char** argv); diff --git a/opm/simulators/flow/DamarisWriter.hpp b/opm/simulators/flow/DamarisWriter.hpp index 058e8570c..22a7af7be 100644 --- a/opm/simulators/flow/DamarisWriter.hpp +++ b/opm/simulators/flow/DamarisWriter.hpp @@ -39,7 +39,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/opm/simulators/flow/EclGenericWriter.hpp b/opm/simulators/flow/EclGenericWriter.hpp index f28912e9b..fee0f0c65 100644 --- a/opm/simulators/flow/EclGenericWriter.hpp +++ b/opm/simulators/flow/EclGenericWriter.hpp @@ -134,13 +134,6 @@ protected: bool isFloresn, std::array, 3>&& floresn); - void doWriteOutput(const int reportStepNum, - const std::optional timeStepNum, - const bool isSubStep, - Scalar curTime, - Scalar nextStepSize, - data::Solution&& localCellData); - void evalSummary(int reportStepNum, Scalar curTime, const data::Wells& localWellData, diff --git a/opm/simulators/flow/EclGenericWriter_impl.hpp b/opm/simulators/flow/EclGenericWriter_impl.hpp index 05f943590..b033333aa 100644 --- a/opm/simulators/flow/EclGenericWriter_impl.hpp +++ b/opm/simulators/flow/EclGenericWriter_impl.hpp @@ -136,6 +136,10 @@ 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 timeStepNum_; @@ -143,48 +147,45 @@ struct EclWriteTasklet : public Opm::TaskletInterface double secondsElapsed_; Opm::RestartValue restartValue_; bool writeDoublePrecision_; - std::optional actionState_; - std::optional wtestState_; - std::optional summaryState_; - std::optional udqState_; - explicit EclWriteTasklet(Opm::EclipseIO& eclIO, + explicit EclWriteTasklet(const Opm::Action::State& actionState, + const Opm::WellTestState& wtestState, + const Opm::SummaryState& summaryState, + const Opm::UDQState& udqState, + Opm::EclipseIO& eclIO, int reportStepNum, std::optional timeStepNum, bool isSubStep, double secondsElapsed, Opm::RestartValue restartValue, - bool writeDoublePrecision, - std::optional actionState = std::nullopt, - std::optional wtestState = std::nullopt, - std::optional summaryState = std::nullopt, - std::optional udqState = std::nullopt) - : eclIO_(eclIO) + bool writeDoublePrecision) + : actionState_(actionState) + , wtestState_(wtestState) + , summaryState_(summaryState) + , udqState_(udqState) + , 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->reportStepNum_, + this->eclIO_.writeTimeStep(this->actionState_, + this->wtestState_, + this->summaryState_, + this->udqState_, + this->reportStepNum_, this->isSubStep_, this->secondsElapsed_, std::move(this->restartValue_), this->writeDoublePrecision_, - this->timeStepNum_, - std::move(this->actionState_), - std::move(this->wtestState_), - std::move(this->summaryState_), - std::move(this->udqState_)); + this->timeStepNum_ +); } }; @@ -608,102 +609,16 @@ doWriteOutput(const int reportStepNum, } // create a tasklet to write the data for the current time step to disk - auto eclWriteTasklet = std::make_shared(/* + auto eclWriteTasklet = std::make_shared( 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 -void EclGenericWriter:: -doWriteOutput(const int reportStepNum, - const std::optional 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 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(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( - /* 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 void EclGenericWriter:: evalSummary(const int reportStepNum, diff --git a/opm/simulators/flow/EclWriter.hpp b/opm/simulators/flow/EclWriter.hpp index b16454869..775f63de0 100644 --- a/opm/simulators/flow/EclWriter.hpp +++ b/opm/simulators/flow/EclWriter.hpp @@ -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 miscSummaryData; @@ -323,11 +323,6 @@ public: ? this->collectOnIORank_.globalInterRegFlows() : this->outputModule_->getInterRegFlows(); - const data::Wells& localWellData {}; - const data::WellBlockAveragePressures& localWBP{}; - const data::GroupAndNetworkValues& localGroupAndNetworkData{}; - const std::map& localAquiferData {}; - this->evalSummary(reportStepNum, curTime, localWellData, @@ -420,20 +415,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 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 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()) { if (localCellData.empty()) { @@ -443,7 +437,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() || @@ -454,19 +448,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); } @@ -478,24 +472,20 @@ public: if (Parameters::Get()) { timeStepIdx = simulator_.timeStepIndex(); } - 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(), - // isFlowsn, std::move(flowsn), - // isFloresn, std::move(floresn)); + 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(), + isFlowsn, std::move(flowsn), + isFloresn, std::move(floresn)); } } @@ -745,26 +735,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); From 3635132d95a8b6edd23f7b163c6272adc322279f Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Mon, 21 Oct 2024 16:14:03 +0200 Subject: [PATCH 06/15] making OutputModule template parameter of EclWriter --- opm/simulators/flow/EclWriter.hpp | 27 +++++++++++++-------- opm/simulators/flow/FlowProblemBlackoil.hpp | 3 ++- opm/simulators/flow/FlowProblemComp.hpp | 4 ++- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/opm/simulators/flow/EclWriter.hpp b/opm/simulators/flow/EclWriter.hpp index 775f63de0..a87a016c7 100644 --- a/opm/simulators/flow/EclWriter.hpp +++ b/opm/simulators/flow/EclWriter.hpp @@ -30,23 +30,30 @@ #include +#include // OPM_TIMEBLOCK #include #include #include +#include +#include #include +#include // Properties::EnableMech, EnableTemperature, EnableSolvent +#include // Properties::FluidSystem + #include #include #include #include -#include #include #include #include #include +#include + #include #include #include @@ -101,7 +108,7 @@ namespace Opm { * - This class requires to use the black oil model with the element * centered finite volume discretization. */ -template +template class EclWriter : public EclGenericWriter, GetPropType, GetPropType, @@ -120,7 +127,7 @@ class EclWriter : public EclGenericWriter using ElementMapper = GetPropType; using ElementIterator = typename GridView::template Codim<0>::Iterator; using BaseType = EclGenericWriter; - + typedef Dune::MultipleCodimMultipleGeomTypeMapper< GridView > VertexMapper; enum { enableEnergy = getPropValue() }; @@ -132,7 +139,7 @@ public: static void registerParameters() { - OutputCompositionalModule::registerParameters(); + OutputModule::registerParameters(); Parameters::Register ("Write the ECL-formated results in a non-blocking way " @@ -169,13 +176,13 @@ public: eclBroadcast(this->simulator_.vanguard().grid().comm(), smryCfg); - this->outputModule_ = std::make_unique> + this->outputModule_ = std::make_unique (simulator, smryCfg, this->collectOnIORank_); } else #endif { - this->outputModule_ = std::make_unique> + this->outputModule_ = std::make_unique (simulator, this->eclIO_->finalSummaryConfig(), this->collectOnIORank_); } @@ -660,10 +667,10 @@ public: } } - const OutputCompositionalModule& outputModule() const + const OutputModule& outputModule() const { return *outputModule_; } - OutputCompositionalModule& mutableOutputModule() const + OutputModule& mutableOutputModule() const { return *outputModule_; } Scalar restartTimeStepSize() const @@ -825,8 +832,8 @@ private: } Simulator& simulator_; - // TODO: OutputCompositionalModule needs to be part of the TypeTag - std::unique_ptr > outputModule_; + // TODO: OutputModule needs to be part of the TypeTag + std::unique_ptr outputModule_; Scalar restartTimeStepSize_; int rank_ ; Inplace inplace_; diff --git a/opm/simulators/flow/FlowProblemBlackoil.hpp b/opm/simulators/flow/FlowProblemBlackoil.hpp index dd100c2e1..bd70762d7 100644 --- a/opm/simulators/flow/FlowProblemBlackoil.hpp +++ b/opm/simulators/flow/FlowProblemBlackoil.hpp @@ -50,6 +50,7 @@ #include #include #include +#include #include #include @@ -141,7 +142,7 @@ class FlowProblemBlackoil : public FlowProblem using ModuleParams = typename BlackOilLocalResidualTPFA::ModuleParams; using InitialFluidState = typename EquilInitializer::ScalarFluidState; - using EclWriterType = EclWriter; + using EclWriterType = EclWriter >; #if HAVE_DAMARIS using DamarisWriterType = DamarisWriter; #endif diff --git a/opm/simulators/flow/FlowProblemComp.hpp b/opm/simulators/flow/FlowProblemComp.hpp index 86f6774e8..9bc35b073 100644 --- a/opm/simulators/flow/FlowProblemComp.hpp +++ b/opm/simulators/flow/FlowProblemComp.hpp @@ -32,6 +32,8 @@ #include +#include + #include #include @@ -82,7 +84,7 @@ class FlowProblemComp : public FlowProblem using typename FlowProblemType::RateVector; using InitialFluidState = CompositionalFluidState; - using EclWriterType = EclWriter; + using EclWriterType = EclWriter >; public: using FlowProblemType::porosity; From e4d1311589d2eb91e75a4fa17af0d6fea7bd6e7d Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Mon, 21 Oct 2024 17:57:22 +0200 Subject: [PATCH 07/15] adding thresholdPressure() interface to FlowProblemComp although we do not support it yet. --- opm/simulators/flow/EclWriter.hpp | 2 +- opm/simulators/flow/FlowProblemComp.hpp | 12 ++++++++++++ opm/simulators/flow/GenericOutputBlackoilModule.cpp | 12 +++++------- opm/simulators/flow/GenericThresholdPressure.hpp | 2 ++ .../flow/GenericThresholdPressure_impl.hpp | 9 +++++++++ 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/opm/simulators/flow/EclWriter.hpp b/opm/simulators/flow/EclWriter.hpp index a87a016c7..e11093c7a 100644 --- a/opm/simulators/flow/EclWriter.hpp +++ b/opm/simulators/flow/EclWriter.hpp @@ -488,7 +488,7 @@ public: this->actionState(), this->udqState(), this->summaryState(), - {}, // this->simulator_.problem().thresholdPressure().getRestartVector(), + this->simulator_.problem().thresholdPressure().getRestartVector(), curTime, nextStepSize, Parameters::Get(), isFlowsn, std::move(flowsn), diff --git a/opm/simulators/flow/FlowProblemComp.hpp b/opm/simulators/flow/FlowProblemComp.hpp index 9bc35b073..d97ccc9ea 100644 --- a/opm/simulators/flow/FlowProblemComp.hpp +++ b/opm/simulators/flow/FlowProblemComp.hpp @@ -32,6 +32,7 @@ #include +#include #include #include @@ -109,6 +110,7 @@ public: */ explicit FlowProblemComp(Simulator& simulator) : FlowProblemType(simulator) + , thresholdPressures_(simulator) { eclWriter_ = std::make_unique(simulator); enableEclOutput_ = Parameters::Get(); @@ -408,11 +410,19 @@ public: const std::vector& initialFluidStates() const { return initialFluidStates_; } + const FlowThresholdPressure& thresholdPressure() const + { + assert( !thresholdPressures_.enableThresholdPressure() && + " Threshold Pressures are not supported by compostional simulation "); + return thresholdPressures_; + } + // TODO: do we need this one? template void serializeOp(Serializer& serializer) { serializer(static_cast(*this)); + serializer(*eclWriter_); } protected: @@ -586,6 +596,8 @@ private: throw std::logic_error("polymer is disabled for compositional modeling and you're trying to add polymer to BC"); } + FlowThresholdPressure thresholdPressures_; + std::vector initialFluidStates_; bool enableEclOutput_; diff --git a/opm/simulators/flow/GenericOutputBlackoilModule.cpp b/opm/simulators/flow/GenericOutputBlackoilModule.cpp index 027eef1ee..d03ef18ac 100644 --- a/opm/simulators/flow/GenericOutputBlackoilModule.cpp +++ b/opm/simulators/flow/GenericOutputBlackoilModule.cpp @@ -1816,13 +1816,11 @@ INSTANTIATE_TYPE(float) template using FS##NUM = GenericOilGasFluidSystem; \ template class GenericOutputBlackoilModule>; -//INSTANTIATE_COMP(2) +INSTANTIATE_COMP(2) INSTANTIATE_COMP(3) -//INSTANTIATE_COMP(4) -//INSTANTIATE_COMP(5) -//INSTANTIATE_COMP(6) -//INSTANTIATE_COMP(7) -// template class GenericOutputBlackoilModule>; - +INSTANTIATE_COMP(4) +INSTANTIATE_COMP(5) +INSTANTIATE_COMP(6) +INSTANTIATE_COMP(7) } // namespace Opm diff --git a/opm/simulators/flow/GenericThresholdPressure.hpp b/opm/simulators/flow/GenericThresholdPressure.hpp index 0e9915f7b..235411abd 100644 --- a/opm/simulators/flow/GenericThresholdPressure.hpp +++ b/opm/simulators/flow/GenericThresholdPressure.hpp @@ -81,6 +81,8 @@ public: //! \details Returns the union of explicitly configured entries and defaulted values. std::vector getRestartVector() const; + bool enableThresholdPressure() const; + protected: /*! * \brief Actually compute the threshold pressures over a face as a pre-compute step. diff --git a/opm/simulators/flow/GenericThresholdPressure_impl.hpp b/opm/simulators/flow/GenericThresholdPressure_impl.hpp index 6ad6e3416..7ca47594d 100644 --- a/opm/simulators/flow/GenericThresholdPressure_impl.hpp +++ b/opm/simulators/flow/GenericThresholdPressure_impl.hpp @@ -246,6 +246,15 @@ getRestartVector() const return result; } +template +bool +GenericThresholdPressure:: +enableThresholdPressure() const +{ + return this->enableThresholdPressure_; +} + + template void GenericThresholdPressure:: From def30fa13172ec4d1514998256d4b97ad5171195 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Tue, 22 Oct 2024 10:51:18 +0200 Subject: [PATCH 08/15] recovering OutputBlackoilModule there is not change needed for this file. --- opm/simulators/flow/OutputBlackoilModule.hpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/opm/simulators/flow/OutputBlackoilModule.hpp b/opm/simulators/flow/OutputBlackoilModule.hpp index 5aa4a9bcd..9104e7deb 100644 --- a/opm/simulators/flow/OutputBlackoilModule.hpp +++ b/opm/simulators/flow/OutputBlackoilModule.hpp @@ -65,13 +65,12 @@ #include #include +namespace Opm::Parameters { - namespace Opm::Parameters { +struct ForceDisableFluidInPlaceOutput { static constexpr bool value = false; }; +struct ForceDisableResvFluidInPlaceOutput { static constexpr bool value = false; }; - struct ForceDisableFluidInPlaceOutput { static constexpr bool value = false; }; - struct ForceDisableResvFluidInPlaceOutput { static constexpr bool value = false; }; - - } // namespace Opm::Parameters +} // namespace Opm::Parameters namespace Opm { From 8541048f83f618df31181f4e5f48cf2af29b9bb3 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Thu, 24 Oct 2024 10:45:00 +0200 Subject: [PATCH 09/15] fixing the running of co2_ptflash_ecfv --- examples/problems/co2ptflashproblem.hh | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/examples/problems/co2ptflashproblem.hh b/examples/problems/co2ptflashproblem.hh index 318b772b2..15059b2b9 100644 --- a/examples/problems/co2ptflashproblem.hh +++ b/examples/problems/co2ptflashproblem.hh @@ -498,6 +498,24 @@ private: fs.setViscosity(FluidSystem::gasPhaseIdx, FluidSystem::viscosity(fs, paramCache, FluidSystem::gasPhaseIdx)); } + // determine the component total fractions + // TODO: duplicated code here, while should be refactored out when we swithing + // to starting from total mole fractions + Dune::FieldVector z(0.0); + Scalar sumMoles = 0.0; + for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { + for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) { + Scalar tmp = Opm::getValue(fs.molarity(phaseIdx, compIdx) * fs.saturation(phaseIdx)); + z[compIdx] += Opm::max(tmp, 1e-8); + sumMoles += tmp; + } + } + z /= sumMoles; + + for (unsigned compIdx = 0; compIdx < numComponents - 1; ++compIdx) { + fs.setMoleFraction(compIdx, z[compIdx]); + } + // Set initial K and L for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) { const Evaluation Ktmp = fs.wilsonK_(compIdx); From 51c534e6fb9a506242664132fd5e71a713ae4c86 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Mon, 21 Oct 2024 22:14:37 +0200 Subject: [PATCH 10/15] removing Damaris from FlowProblemComp --- opm/simulators/flow/FlowProblemComp.hpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/opm/simulators/flow/FlowProblemComp.hpp b/opm/simulators/flow/FlowProblemComp.hpp index d97ccc9ea..85c10a940 100644 --- a/opm/simulators/flow/FlowProblemComp.hpp +++ b/opm/simulators/flow/FlowProblemComp.hpp @@ -283,13 +283,6 @@ public: 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() || !isSubStep) { eclWriter_->writeOutput(std::move(localCellData), isSubStep); From 65e858c84cc8668090bfa8da6c0e965152aa3c5b Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Thu, 24 Oct 2024 11:29:53 +0200 Subject: [PATCH 11/15] fixing all the warnings related --- .../flow/OutputCompositionalModule.hpp | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/opm/simulators/flow/OutputCompositionalModule.hpp b/opm/simulators/flow/OutputCompositionalModule.hpp index 0b6cfa4d3..bbd6880e5 100644 --- a/opm/simulators/flow/OutputCompositionalModule.hpp +++ b/opm/simulators/flow/OutputCompositionalModule.hpp @@ -202,14 +202,10 @@ public: if (!std::is_same>::value) return; - const auto& problem = elemCtx.simulator().problem(); - const auto& modelResid = elemCtx.simulator().model().linearizer().residual(); for (unsigned dofIdx = 0; dofIdx < elemCtx.numPrimaryDof(/*timeIdx=*/0); ++dofIdx) { const auto& intQuants = elemCtx.intensiveQuantities(dofIdx, /*timeIdx=*/0); const auto& fs = intQuants.fluidState(); - using FluidState = std::remove_cv_t>; - const unsigned globalDofIdx = elemCtx.globalSpaceIndex(dofIdx, /*timeIdx=*/0); // const unsigned pvtRegionIdx = 0; // elemCtx.primaryVars(dofIdx, /*timeIdx=*/0).pvtRegionIndex(); @@ -259,14 +255,14 @@ public: } } - void processElementFlows(const ElementContext& elemCtx) + void processElementFlows(const ElementContext& /* elemCtx */) { OPM_TIMEBLOCK_LOCAL(processElementBlockData); if (!std::is_same_v>) return; } - void processElementBlockData(const ElementContext& elemCtx) + void processElementBlockData(const ElementContext& /* elemCtx */) { OPM_TIMEBLOCK_LOCAL(processElementBlockData); if (!std::is_same>::value) @@ -302,9 +298,9 @@ public: * to globally unique Cartesian cell/element index. */ template - void processFluxes(const ElementContext& elemCtx, - ActiveIndex&& activeIndex, - CartesianIndex&& cartesianIndex) + void processFluxes(const ElementContext& /* elemCtx */, + ActiveIndex&& /* activeIndex*/, + CartesianIndex&& /* cartesianIndex */) { } @@ -335,9 +331,9 @@ public: return this->interRegionFlows_; } - void updateFluidInPlace(const unsigned globalDofIdx, - const IntensiveQuantities& intQuants, - const double totVolume) + void updateFluidInPlace(const unsigned /* globalDofIdx */, + const IntensiveQuantities& /* intQuants */, + const double /* totVolume */) { // this->updateFluidInPlace_(globalDofIdx, intQuants, totVolume); } From cd9009dc75e2c0e3c540d0e976f7750c64f3f666 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Thu, 24 Oct 2024 14:25:20 +0200 Subject: [PATCH 12/15] adding isCompositional_ variable to GenericOutputBlackoilModule to indicate whether it is a compostional simulation. --- .../flow/GenericOutputBlackoilModule.cpp | 83 ++++++++++--------- .../flow/GenericOutputBlackoilModule.hpp | 4 +- .../flow/OutputCompositionalModule.hpp | 3 +- 3 files changed, 51 insertions(+), 39 deletions(-) diff --git a/opm/simulators/flow/GenericOutputBlackoilModule.cpp b/opm/simulators/flow/GenericOutputBlackoilModule.cpp index d03ef18ac..7cebdee0f 100644 --- a/opm/simulators/flow/GenericOutputBlackoilModule.cpp +++ b/opm/simulators/flow/GenericOutputBlackoilModule.cpp @@ -203,7 +203,8 @@ GenericOutputBlackoilModule(const EclipseState& eclState, bool enableBrine, bool enableSaltPrecipitation, bool enableExtbo, - bool enableMICP) + bool enableMICP, + bool isCompositional) : eclState_(eclState) , schedule_(schedule) , summaryState_(summaryState) @@ -222,6 +223,7 @@ GenericOutputBlackoilModule(const EclipseState& eclState, , enableSaltPrecipitation_(enableSaltPrecipitation) , enableExtbo_(enableExtbo) , enableMICP_(enableMICP) + , isCompositional_(isCompositional) , local_data_valid_(false) { const auto& fp = eclState_.fieldProps(); @@ -628,29 +630,34 @@ assignToSolution(data::Solution& sol) // basically, for compositional, we can not use std::array for this. We need to generate the ZMF1, ZMF2, and so on // and also, we need to map these values. - auto compositionalEntries = std::vector{}; - { - // ZMF - for (int i = 0; i < numComponents; ++i) { - const std::string name = "ZMF" + std::to_string(i + 1); // Generate ZMF1, ZMF2, ... - compositionalEntries.emplace_back(name, UnitSystem::measure::identity, moleFractions_[i]); + // TODO: the following should go to a function + if (this->isCompositional_) { + auto compositionalEntries = std::vector{}; + { + // ZMF + for (int i = 0; i < numComponents; ++i) { + const std::string name = "ZMF" + std::to_string(i + 1); // Generate ZMF1, ZMF2, ... + compositionalEntries.emplace_back(name, UnitSystem::measure::identity, moleFractions_[i]); + } + + // XMF + for (int i = 0; i < numComponents; ++i) { + const std::string name = "XMF" + std::to_string(i + 1); // Generate XMF1, XMF2, ... + compositionalEntries.emplace_back(name, UnitSystem::measure::identity, + phaseMoleFractions_[oilPhaseIdx][i]); + } + + // YMF + for (int i = 0; i < numComponents; ++i) { + const std::string name = "YMF" + std::to_string(i + 1); // Generate YMF1, YMF2, ... + compositionalEntries.emplace_back(name, UnitSystem::measure::identity, + phaseMoleFractions_[gasPhaseIdx][i]); + } } - // XMF - for (int i = 0; i < numComponents; ++i) { - const std::string name = "XMF" + std::to_string(i + 1); // Generate XMF1, XMF2, ... - compositionalEntries.emplace_back(name, UnitSystem::measure::identity, phaseMoleFractions_[oilPhaseIdx][i]); + for (const auto& array: compositionalEntries) { + doInsert(array, data::TargetType::RESTART_SOLUTION); } - - // YMF - for (int i = 0; i < numComponents; ++i) { - const std::string name = "YMF" + std::to_string(i + 1); // Generate YMF1, YMF2, ... - compositionalEntries.emplace_back(name, UnitSystem::measure::identity, phaseMoleFractions_[gasPhaseIdx][i]); - } - } - - for (const auto& array : compositionalEntries) { - doInsert(array, data::TargetType::RESTART_SOLUTION); } for (const auto& array : baseSolutionArrays) { @@ -688,8 +695,8 @@ assignToSolution(data::Solution& sol) std::move(this->saturation_[gasPhaseIdx]), data::TargetType::RESTART_SOLUTION); } - - if (FluidSystem::phaseIsActive(oilPhaseIdx) && + + if (this->isCompositional_ && FluidSystem::phaseIsActive(oilPhaseIdx) && ! this->saturation_[oilPhaseIdx].empty()) { sol.insert("SOIL", UnitSystem::measure::identity, @@ -1519,24 +1526,26 @@ doAllocBuffers(const unsigned bufferSize, overburdenPressure_.resize(bufferSize, 0.0); } - if (rstKeywords["ZMF"] > 0) { - rstKeywords["ZMF"] = 0; - for (int i = 0; i < numComponents; ++i) { - moleFractions_[i].resize(bufferSize, 0.0); + if (this->isCompositional_) { + if (rstKeywords["ZMF"] > 0) { + rstKeywords["ZMF"] = 0; + for (int i = 0; i < numComponents; ++i) { + moleFractions_[i].resize(bufferSize, 0.0); + } } - } - if (rstKeywords["XMF"] > 0 && FluidSystem::phaseIsActive(oilPhaseIdx)) { - rstKeywords["XMF"] = 0; - for (int i = 0; i < numComponents; ++i) { - phaseMoleFractions_[oilPhaseIdx][i].resize(bufferSize, 0.0); + if (rstKeywords["XMF"] > 0 && FluidSystem::phaseIsActive(oilPhaseIdx)) { + rstKeywords["XMF"] = 0; + for (int i = 0; i < numComponents; ++i) { + phaseMoleFractions_[oilPhaseIdx][i].resize(bufferSize, 0.0); + } } - } - if (rstKeywords["YMF"] > 0 && FluidSystem::phaseIsActive(gasPhaseIdx)) { - rstKeywords["YMF"] = 0; - for (int i = 0; i < numComponents; ++i) { - phaseMoleFractions_[gasPhaseIdx][i].resize(bufferSize, 0.0); + if (rstKeywords["YMF"] > 0 && FluidSystem::phaseIsActive(gasPhaseIdx)) { + rstKeywords["YMF"] = 0; + for (int i = 0; i < numComponents; ++i) { + phaseMoleFractions_[gasPhaseIdx][i].resize(bufferSize, 0.0); + } } } diff --git a/opm/simulators/flow/GenericOutputBlackoilModule.hpp b/opm/simulators/flow/GenericOutputBlackoilModule.hpp index 9281f0467..19aff9caa 100644 --- a/opm/simulators/flow/GenericOutputBlackoilModule.hpp +++ b/opm/simulators/flow/GenericOutputBlackoilModule.hpp @@ -335,7 +335,8 @@ protected: bool enableBrine, bool enableSaltPrecipitation, bool enableExtbo, - bool enableMICP); + bool enableMICP, + bool isCompositional = false); void doAllocBuffers(unsigned bufferSize, unsigned reportStepNum, @@ -405,6 +406,7 @@ protected: bool enableSaltPrecipitation_{false}; bool enableExtbo_{false}; bool enableMICP_{false}; + bool isCompositional_{false}; bool forceDisableFipOutput_{false}; bool forceDisableFipresvOutput_{false}; diff --git a/opm/simulators/flow/OutputCompositionalModule.hpp b/opm/simulators/flow/OutputCompositionalModule.hpp index bbd6880e5..02eccf908 100644 --- a/opm/simulators/flow/OutputCompositionalModule.hpp +++ b/opm/simulators/flow/OutputCompositionalModule.hpp @@ -126,7 +126,8 @@ public: getPropValue(), getPropValue(), getPropValue(), - getPropValue()) + getPropValue(), + true) , simulator_(simulator) { for (auto& region_pair : this->regions_) { From 56db6ad3fe04e0249d6eb4a694e593d30169c45b Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Mon, 28 Oct 2024 11:46:19 +0100 Subject: [PATCH 13/15] cleaning unused headers and declarations in OutputCompositionalModule --- opm/simulators/flow/EclWriter.hpp | 3 +- .../flow/OutputCompositionalModule.hpp | 30 ++----------------- 2 files changed, 4 insertions(+), 29 deletions(-) diff --git a/opm/simulators/flow/EclWriter.hpp b/opm/simulators/flow/EclWriter.hpp index e11093c7a..6a75ebb33 100644 --- a/opm/simulators/flow/EclWriter.hpp +++ b/opm/simulators/flow/EclWriter.hpp @@ -656,7 +656,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 GenericOutputCompositionalModule::accumulateRegionSums() for + // See GenericOutputBlackoilModule::accumulateRegionSums() for // additional comments. auto inplace = this->outputModule_ ->calc_inplace(miscSummaryData, regionData, @@ -832,7 +832,6 @@ private: } Simulator& simulator_; - // TODO: OutputModule needs to be part of the TypeTag std::unique_ptr outputModule_; Scalar restartTimeStepSize_; int rank_ ; diff --git a/opm/simulators/flow/OutputCompositionalModule.hpp b/opm/simulators/flow/OutputCompositionalModule.hpp index 02eccf908..7d65398c3 100644 --- a/opm/simulators/flow/OutputCompositionalModule.hpp +++ b/opm/simulators/flow/OutputCompositionalModule.hpp @@ -22,12 +22,12 @@ */ /*! * \file - * \copydoc Opm::OutputBlackOilModule + * \copydoc Opm::OutputCompositionalModule */ #ifndef OPM_OUTPUT_COMPOSITIONAL_MODULE_HPP #define OPM_OUTPUT_COMPOSITIONAL_MODULE_HPP -#include +#include #include @@ -38,25 +38,14 @@ #include #include -#include - -#include -#include #include #include -#include -#include -#include - #include #include #include -#include -#include #include -#include #include #include #include @@ -83,29 +72,16 @@ class OutputCompositionalModule : public GenericOutputBlackoilModule; using Discretization = GetPropType; using Scalar = GetPropType; - using Evaluation = GetPropType; using ElementContext = GetPropType; - using MaterialLaw = GetPropType; - using MaterialLawParams = GetPropType; using IntensiveQuantities = GetPropType; using FluidSystem = GetPropType; - using GridView = GetPropType; - using Element = typename GridView::template Codim<0>::Entity; - using ElementIterator = typename GridView::template Codim<0>::Iterator; using BaseType = GenericOutputBlackoilModule; - using Indices = GetPropType; - using Dir = FaceDir::DirEnum; - enum { conti0EqIdx = Indices::conti0EqIdx }; enum { numPhases = FluidSystem::numPhases }; enum { numComponents = FluidSystem::numComponents }; enum { oilPhaseIdx = FluidSystem::oilPhaseIdx }; enum { gasPhaseIdx = FluidSystem::gasPhaseIdx }; enum { waterPhaseIdx = FluidSystem::waterPhaseIdx }; - enum { gasCompIdx = FluidSystem::gasCompIdx }; - enum { oilCompIdx = FluidSystem::oilCompIdx }; - enum { waterCompIdx = FluidSystem::waterCompIdx }; - enum { enableEnergy = getPropValue() }; public: template @@ -336,7 +312,7 @@ public: const IntensiveQuantities& /* intQuants */, const double /* totVolume */) { -// this->updateFluidInPlace_(globalDofIdx, intQuants, totVolume); + // this->updateFluidInPlace_(globalDofIdx, intQuants, totVolume); } private: From c6201e9b6a562141c5932570c74dc951e06f4b42 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Wed, 30 Oct 2024 10:20:13 +0100 Subject: [PATCH 14/15] addressing reviewing comments --- examples/problems/co2ptflashproblem.hh | 6 ++++-- opm/simulators/flow/FlowProblemComp.hpp | 12 +++++++----- opm/simulators/flow/GenericOutputBlackoilModule.cpp | 6 +++--- opm/simulators/flow/GenericOutputBlackoilModule.hpp | 2 +- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/examples/problems/co2ptflashproblem.hh b/examples/problems/co2ptflashproblem.hh index 15059b2b9..1f0e496a5 100644 --- a/examples/problems/co2ptflashproblem.hh +++ b/examples/problems/co2ptflashproblem.hh @@ -504,9 +504,11 @@ private: Dune::FieldVector z(0.0); Scalar sumMoles = 0.0; for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { + const auto saturation = getValue(fs.saturation(phaseIdx)); for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) { - Scalar tmp = Opm::getValue(fs.molarity(phaseIdx, compIdx) * fs.saturation(phaseIdx)); - z[compIdx] += Opm::max(tmp, 1e-8); + Scalar tmp = getValue(fs.molarity(phaseIdx, compIdx)) * saturation; + tmp = max(tmp, 1.e-8); + z[compIdx] += tmp; sumMoles += tmp; } } diff --git a/opm/simulators/flow/FlowProblemComp.hpp b/opm/simulators/flow/FlowProblemComp.hpp index 85c10a940..8434e8b26 100644 --- a/opm/simulators/flow/FlowProblemComp.hpp +++ b/opm/simulators/flow/FlowProblemComp.hpp @@ -252,7 +252,7 @@ public: const bool isSubStep = !this->simulator().episodeWillBeOver(); - // after the solution is updated, the values in output module needs also updated + // after the solution is updated, the values in output module also needs to be updated this->eclWriter_->mutableOutputModule().invalidateLocalData(); // For CpGrid with LGRs, ecl/vtk output is not supported yet. @@ -365,9 +365,11 @@ public: Dune::FieldVector z(0.0); Scalar sumMoles = 0.0; for (unsigned phaseIdx = 0; phaseIdx < numPhases; ++phaseIdx) { + const auto saturation = getValue(fs.saturation(phaseIdx)); for (unsigned compIdx = 0; compIdx < numComponents; ++compIdx) { - Scalar tmp = Opm::getValue(fs.molarity(phaseIdx, compIdx) * fs.saturation(phaseIdx)); - z[compIdx] += Opm::max(tmp, 1e-8); + Scalar tmp = getValue(fs.molarity(phaseIdx, compIdx)) * saturation; + tmp = max(tmp, 1e-8); + z[compIdx] += tmp; sumMoles += tmp; } } @@ -593,10 +595,10 @@ private: std::vector initialFluidStates_; - bool enableEclOutput_; + bool enableEclOutput_{false}; std::unique_ptr eclWriter_; - bool enableVtkOutput_; + bool enableVtkOutput_{false}; }; } // namespace Opm diff --git a/opm/simulators/flow/GenericOutputBlackoilModule.cpp b/opm/simulators/flow/GenericOutputBlackoilModule.cpp index 7cebdee0f..c6734607b 100644 --- a/opm/simulators/flow/GenericOutputBlackoilModule.cpp +++ b/opm/simulators/flow/GenericOutputBlackoilModule.cpp @@ -636,20 +636,20 @@ assignToSolution(data::Solution& sol) { // ZMF for (int i = 0; i < numComponents; ++i) { - const std::string name = "ZMF" + std::to_string(i + 1); // Generate ZMF1, ZMF2, ... + const auto name = fmt::format("ZMF{}", i + 1); // Generate ZMF1, ZMF2, ... compositionalEntries.emplace_back(name, UnitSystem::measure::identity, moleFractions_[i]); } // XMF for (int i = 0; i < numComponents; ++i) { - const std::string name = "XMF" + std::to_string(i + 1); // Generate XMF1, XMF2, ... + const auto name = fmt::format("XMF{}", i + 1); // Generate XMF1, XMF2, ... compositionalEntries.emplace_back(name, UnitSystem::measure::identity, phaseMoleFractions_[oilPhaseIdx][i]); } // YMF for (int i = 0; i < numComponents; ++i) { - const std::string name = "YMF" + std::to_string(i + 1); // Generate YMF1, YMF2, ... + const auto name = fmt::format("YMF{}", i + 1); // Generate YMF1, YMF2, ... compositionalEntries.emplace_back(name, UnitSystem::measure::identity, phaseMoleFractions_[gasPhaseIdx][i]); } diff --git a/opm/simulators/flow/GenericOutputBlackoilModule.hpp b/opm/simulators/flow/GenericOutputBlackoilModule.hpp index 19aff9caa..7a23b5bc4 100644 --- a/opm/simulators/flow/GenericOutputBlackoilModule.hpp +++ b/opm/simulators/flow/GenericOutputBlackoilModule.hpp @@ -541,7 +541,7 @@ protected: std::array viscosity_; std::array relativePermeability_; - // totoal mole fractions for each component + // total mole fractions for each component std::array moleFractions_; // mole fractions for each component in each phase std::array, numPhases> phaseMoleFractions_; From 0edb5a462d3a8bc47ae89b76c14a0f780c7d69e3 Mon Sep 17 00:00:00 2001 From: Kai Bao Date: Wed, 30 Oct 2024 15:30:08 +0100 Subject: [PATCH 15/15] checking compIdx or phaseIdx when adding entries to SolutionVector std::vector is used instead of std::array. when compIdx is -1, the origional code trigger array-bounds warning. --- .../flow/GenericOutputBlackoilModule.cpp | 159 +++++++++--------- 1 file changed, 83 insertions(+), 76 deletions(-) diff --git a/opm/simulators/flow/GenericOutputBlackoilModule.cpp b/opm/simulators/flow/GenericOutputBlackoilModule.cpp index c6734607b..6d8834cad 100644 --- a/opm/simulators/flow/GenericOutputBlackoilModule.cpp +++ b/opm/simulators/flow/GenericOutputBlackoilModule.cpp @@ -501,83 +501,90 @@ assignToSolution(data::Solution& sol) target); }; - const auto baseSolutionArrays = std::array { - DataEntry{"1OVERBG", UnitSystem::measure::gas_inverse_formation_volume_factor, invB_[gasPhaseIdx]}, - DataEntry{"1OVERBO", UnitSystem::measure::oil_inverse_formation_volume_factor, invB_[oilPhaseIdx]}, - DataEntry{"1OVERBW", UnitSystem::measure::water_inverse_formation_volume_factor, invB_[waterPhaseIdx]}, - DataEntry{"FLRGASI+", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::XPlus)][gasCompIdx]}, - DataEntry{"FLRGASJ+", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::YPlus)][gasCompIdx]}, - DataEntry{"FLRGASK+", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::ZPlus)][gasCompIdx]}, - DataEntry{"FLROILI+", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::XPlus)][oilCompIdx]}, - DataEntry{"FLROILJ+", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::YPlus)][oilCompIdx]}, - DataEntry{"FLROILK+", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::ZPlus)][oilCompIdx]}, - DataEntry{"FLRWATI+", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::XPlus)][waterCompIdx]}, - DataEntry{"FLRWATJ+", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::YPlus)][waterCompIdx]}, - DataEntry{"FLRWATK+", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::ZPlus)][waterCompIdx]}, - DataEntry{"FOAM", UnitSystem::measure::identity, cFoam_}, - DataEntry{"GASKR", UnitSystem::measure::identity, relativePermeability_[gasPhaseIdx]}, - DataEntry{"GAS_DEN", UnitSystem::measure::density, density_[gasPhaseIdx]}, - DataEntry{"GAS_VISC", UnitSystem::measure::viscosity, viscosity_[gasPhaseIdx]}, - DataEntry{"OILKR", UnitSystem::measure::identity, relativePermeability_[oilPhaseIdx]}, - DataEntry{"OIL_DEN", UnitSystem::measure::density, density_[oilPhaseIdx]}, - DataEntry{"OIL_VISC", UnitSystem::measure::viscosity, viscosity_[oilPhaseIdx]}, - DataEntry{"PBUB", UnitSystem::measure::pressure, bubblePointPressure_}, - DataEntry{"PCGW", UnitSystem::measure::pressure, pcgw_}, - DataEntry{"PCOG", UnitSystem::measure::pressure, pcog_}, - DataEntry{"PCOW", UnitSystem::measure::pressure, pcow_}, - DataEntry{"PDEW", UnitSystem::measure::pressure, dewPointPressure_}, - DataEntry{"POLYMER", UnitSystem::measure::identity, cPolymer_}, - DataEntry{"PPCW", UnitSystem::measure::pressure, ppcw_}, - DataEntry{"PRESROCC", UnitSystem::measure::pressure, minimumOilPressure_}, - DataEntry{"PRESSURE", UnitSystem::measure::pressure, fluidPressure_}, - DataEntry{"RPORV", UnitSystem::measure::volume, rPorV_}, - DataEntry{"RS", UnitSystem::measure::gas_oil_ratio, rs_}, - DataEntry{"RSSAT", UnitSystem::measure::gas_oil_ratio, gasDissolutionFactor_}, - DataEntry{"RV", UnitSystem::measure::oil_gas_ratio, rv_}, - DataEntry{"RVSAT", UnitSystem::measure::oil_gas_ratio, oilVaporizationFactor_}, - DataEntry{"SALT", UnitSystem::measure::salinity, cSalt_}, - DataEntry{"SGMAX", UnitSystem::measure::identity, sgmax_}, - DataEntry{"SHMAX", UnitSystem::measure::identity, shmax_}, - DataEntry{"SOMAX", UnitSystem::measure::identity, soMax_}, - DataEntry{"SOMIN", UnitSystem::measure::identity, somin_}, - DataEntry{"SSOLVENT", UnitSystem::measure::identity, sSol_}, - DataEntry{"SWHY1", UnitSystem::measure::identity, swmin_}, - DataEntry{"SWMAX", UnitSystem::measure::identity, swMax_}, - DataEntry{"WATKR", UnitSystem::measure::identity, relativePermeability_[waterPhaseIdx]}, - DataEntry{"WAT_DEN", UnitSystem::measure::density, density_[waterPhaseIdx]}, - DataEntry{"WAT_VISC", UnitSystem::measure::viscosity, viscosity_[waterPhaseIdx]}, + // if index not specified, we treat it as valid (>= 0) + auto addEntry = [](std::vector& container, const std::string& name, UnitSystem::measure measure, const auto& flowArray, int index = 1) { + if (index >= 0) { // Only add if index is valid + container.emplace_back(name, measure, flowArray); + } }; + + std::vector baseSolutionVector; + addEntry(baseSolutionVector, "1OVERBG", UnitSystem::measure::gas_inverse_formation_volume_factor, invB_[gasPhaseIdx], gasPhaseIdx); + addEntry(baseSolutionVector, "1OVERBO", UnitSystem::measure::oil_inverse_formation_volume_factor, invB_[oilPhaseIdx], oilPhaseIdx); + addEntry(baseSolutionVector, "1OVERBW", UnitSystem::measure::water_inverse_formation_volume_factor, invB_[waterPhaseIdx], waterPhaseIdx); + addEntry(baseSolutionVector, "FLRGASI+", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::XPlus)][gasCompIdx], gasCompIdx); + addEntry(baseSolutionVector, "FLRGASJ+", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::YPlus)][gasCompIdx], gasCompIdx); + addEntry(baseSolutionVector, "FLRGASK+", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::ZPlus)][gasCompIdx], gasCompIdx); + addEntry(baseSolutionVector, "FLROILI+", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::XPlus)][oilCompIdx], oilCompIdx); + addEntry(baseSolutionVector, "FLROILJ+", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::YPlus)][oilCompIdx], oilCompIdx); + addEntry(baseSolutionVector, "FLROILK+", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::ZPlus)][oilCompIdx], oilCompIdx); + addEntry(baseSolutionVector, "FLRWATI+", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::XPlus)][waterCompIdx], waterCompIdx); + addEntry(baseSolutionVector, "FLRWATJ+", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::YPlus)][waterCompIdx], waterCompIdx); + addEntry(baseSolutionVector, "FLRWATK+", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::ZPlus)][waterCompIdx], waterCompIdx); + addEntry(baseSolutionVector, "FOAM", UnitSystem::measure::identity, cFoam_); + addEntry(baseSolutionVector, "GASKR", UnitSystem::measure::identity, relativePermeability_[gasPhaseIdx], gasPhaseIdx); + addEntry(baseSolutionVector, "GAS_DEN", UnitSystem::measure::density, density_[gasPhaseIdx], gasPhaseIdx); + addEntry(baseSolutionVector, "GAS_VISC", UnitSystem::measure::viscosity, viscosity_[gasPhaseIdx], gasPhaseIdx); + addEntry(baseSolutionVector, "OILKR", UnitSystem::measure::identity, relativePermeability_[oilPhaseIdx], oilPhaseIdx); + addEntry(baseSolutionVector, "OIL_DEN", UnitSystem::measure::density, density_[oilPhaseIdx], oilPhaseIdx); + addEntry(baseSolutionVector, "OIL_VISC", UnitSystem::measure::viscosity, viscosity_[oilPhaseIdx], oilPhaseIdx); + addEntry(baseSolutionVector, "PBUB", UnitSystem::measure::pressure, bubblePointPressure_); + addEntry(baseSolutionVector, "PCGW", UnitSystem::measure::pressure, pcgw_); + addEntry(baseSolutionVector, "PCOG", UnitSystem::measure::pressure, pcog_); + addEntry(baseSolutionVector, "PCOW", UnitSystem::measure::pressure, pcow_); + addEntry(baseSolutionVector, "PDEW", UnitSystem::measure::pressure, dewPointPressure_); + addEntry(baseSolutionVector, "POLYMER", UnitSystem::measure::identity, cPolymer_); + addEntry(baseSolutionVector, "PPCW", UnitSystem::measure::pressure, ppcw_); + addEntry(baseSolutionVector, "PRESROCC", UnitSystem::measure::pressure, minimumOilPressure_); + addEntry(baseSolutionVector, "PRESSURE", UnitSystem::measure::pressure, fluidPressure_); + addEntry(baseSolutionVector, "RPORV", UnitSystem::measure::volume, rPorV_); + addEntry(baseSolutionVector, "RS", UnitSystem::measure::gas_oil_ratio, rs_); + addEntry(baseSolutionVector, "RSSAT", UnitSystem::measure::gas_oil_ratio, gasDissolutionFactor_); + addEntry(baseSolutionVector, "RV", UnitSystem::measure::oil_gas_ratio, rv_); + addEntry(baseSolutionVector, "RVSAT", UnitSystem::measure::oil_gas_ratio, oilVaporizationFactor_); + addEntry(baseSolutionVector, "SALT", UnitSystem::measure::salinity, cSalt_); + addEntry(baseSolutionVector, "SGMAX", UnitSystem::measure::identity, sgmax_); + addEntry(baseSolutionVector, "SHMAX", UnitSystem::measure::identity, shmax_); + addEntry(baseSolutionVector, "SOMAX", UnitSystem::measure::identity, soMax_); + addEntry(baseSolutionVector, "SOMIN", UnitSystem::measure::identity, somin_); + addEntry(baseSolutionVector, "SSOLVENT", UnitSystem::measure::identity, sSol_); + addEntry(baseSolutionVector, "SWHY1", UnitSystem::measure::identity, swmin_); + addEntry(baseSolutionVector, "SWMAX", UnitSystem::measure::identity, swMax_); + addEntry(baseSolutionVector, "WATKR", UnitSystem::measure::identity, relativePermeability_[waterPhaseIdx], waterPhaseIdx); + addEntry(baseSolutionVector, "WAT_DEN", UnitSystem::measure::density, density_[waterPhaseIdx], waterPhaseIdx); + addEntry(baseSolutionVector, "WAT_VISC", UnitSystem::measure::viscosity, viscosity_[waterPhaseIdx], waterPhaseIdx); + + // Separate these as flows*_ may be defined due to BFLOW[I|J|K] even without FLOWS in RPTRST - const auto flowsSolutionArrays = std::array { - DataEntry{"FLOGASI+", UnitSystem::measure::gas_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::XPlus)][gasCompIdx]}, - DataEntry{"FLOGASJ+", UnitSystem::measure::gas_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::YPlus)][gasCompIdx]}, - DataEntry{"FLOGASK+", UnitSystem::measure::gas_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::ZPlus)][gasCompIdx]}, - DataEntry{"FLOOILI+", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::XPlus)][oilCompIdx]}, - DataEntry{"FLOOILJ+", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::YPlus)][oilCompIdx]}, - DataEntry{"FLOOILK+", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::ZPlus)][oilCompIdx]}, - DataEntry{"FLOWATI+", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::XPlus)][waterCompIdx]}, - DataEntry{"FLOWATJ+", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::YPlus)][waterCompIdx]}, - DataEntry{"FLOWATK+", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::ZPlus)][waterCompIdx]}, - DataEntry{"FLOGASI-", UnitSystem::measure::gas_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::XMinus)][gasCompIdx]}, - DataEntry{"FLOGASJ-", UnitSystem::measure::gas_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::YMinus)][gasCompIdx]}, - DataEntry{"FLOGASK-", UnitSystem::measure::gas_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::ZMinus)][gasCompIdx]}, - DataEntry{"FLOOILI-", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::XMinus)][oilCompIdx]}, - DataEntry{"FLOOILJ-", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::YMinus)][oilCompIdx]}, - DataEntry{"FLOOILK-", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::ZMinus)][oilCompIdx]}, - DataEntry{"FLOWATI-", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::XMinus)][waterCompIdx]}, - DataEntry{"FLOWATJ-", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::YMinus)][waterCompIdx]}, - DataEntry{"FLOWATK-", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::ZMinus)][waterCompIdx]}, - DataEntry{"FLRGASI-", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::XMinus)][gasCompIdx]}, - DataEntry{"FLRGASJ-", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::YMinus)][gasCompIdx]}, - DataEntry{"FLRGASK-", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::ZMinus)][gasCompIdx]}, - DataEntry{"FLROILI-", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::XMinus)][oilCompIdx]}, - DataEntry{"FLROILJ-", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::YMinus)][oilCompIdx]}, - DataEntry{"FLROILK-", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::ZMinus)][oilCompIdx]}, - DataEntry{"FLRWATI-", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::XMinus)][waterCompIdx]}, - DataEntry{"FLRWATJ-", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::YMinus)][waterCompIdx]}, - DataEntry{"FLRWATK-", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::ZMinus)][waterCompIdx]}, - }; + std::vector flowsSolutionVector; + addEntry(flowsSolutionVector, "FLOGASI+", UnitSystem::measure::gas_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::XPlus)][gasCompIdx], gasCompIdx); + addEntry(flowsSolutionVector, "FLOGASJ+", UnitSystem::measure::gas_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::YPlus)][gasCompIdx], gasCompIdx); + addEntry(flowsSolutionVector, "FLOGASK+", UnitSystem::measure::gas_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::ZPlus)][gasCompIdx], gasCompIdx); + addEntry(flowsSolutionVector, "FLOOILI+", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::XPlus)][oilCompIdx], oilCompIdx); + addEntry(flowsSolutionVector, "FLOOILJ+", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::YPlus)][oilCompIdx], oilCompIdx); + addEntry(flowsSolutionVector, "FLOOILK+", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::ZPlus)][oilCompIdx], oilCompIdx); + addEntry(flowsSolutionVector, "FLOWATI+", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::XPlus)][waterCompIdx], waterCompIdx); + addEntry(flowsSolutionVector, "FLOWATJ+", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::YPlus)][waterCompIdx], waterCompIdx); + addEntry(flowsSolutionVector, "FLOWATK+", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::ZPlus)][waterCompIdx], waterCompIdx); + addEntry(flowsSolutionVector, "FLOGASI-", UnitSystem::measure::gas_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::XMinus)][gasCompIdx], gasCompIdx); + addEntry(flowsSolutionVector, "FLOGASJ-", UnitSystem::measure::gas_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::YMinus)][gasCompIdx], gasCompIdx); + addEntry(flowsSolutionVector, "FLOGASK-", UnitSystem::measure::gas_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::ZMinus)][gasCompIdx], gasCompIdx); + addEntry(flowsSolutionVector, "FLOOILI-", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::XMinus)][oilCompIdx], oilCompIdx); + addEntry(flowsSolutionVector, "FLOOILJ-", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::YMinus)][oilCompIdx], oilCompIdx); + addEntry(flowsSolutionVector, "FLOOILK-", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::ZMinus)][oilCompIdx], oilCompIdx); + addEntry(flowsSolutionVector, "FLOWATI-", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::XMinus)][waterCompIdx], waterCompIdx); + addEntry(flowsSolutionVector, "FLOWATJ-", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::YMinus)][waterCompIdx], waterCompIdx); + addEntry(flowsSolutionVector, "FLOWATK-", UnitSystem::measure::liquid_surface_rate, flows_[FaceDir::ToIntersectionIndex(Dir::ZMinus)][waterCompIdx], waterCompIdx); + addEntry(flowsSolutionVector, "FLRGASI-", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::XMinus)][gasCompIdx], gasCompIdx); + addEntry(flowsSolutionVector, "FLRGASJ-", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::YMinus)][gasCompIdx], gasCompIdx); + addEntry(flowsSolutionVector, "FLRGASK-", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::ZMinus)][gasCompIdx], gasCompIdx); + addEntry(flowsSolutionVector, "FLROILI-", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::XMinus)][oilCompIdx], oilCompIdx); + addEntry(flowsSolutionVector, "FLROILJ-", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::YMinus)][oilCompIdx], oilCompIdx); + addEntry(flowsSolutionVector, "FLROILK-", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::ZMinus)][oilCompIdx], oilCompIdx); + addEntry(flowsSolutionVector, "FLRWATI-", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::XMinus)][waterCompIdx], waterCompIdx); + addEntry(flowsSolutionVector, "FLRWATJ-", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::YMinus)][waterCompIdx], waterCompIdx); + addEntry(flowsSolutionVector, "FLRWATK-", UnitSystem::measure::rate, flores_[FaceDir::ToIntersectionIndex(Dir::ZMinus)][waterCompIdx], waterCompIdx); const auto extendedSolutionArrays = std::array { DataEntry{"BIOFILM", UnitSystem::measure::identity, cBiofilm_}, @@ -660,12 +667,12 @@ assignToSolution(data::Solution& sol) } } - for (const auto& array : baseSolutionArrays) { + for (const auto& array : baseSolutionVector) { doInsert(array, data::TargetType::RESTART_SOLUTION); } if (this->enableFlows_) { - for (const auto& array : flowsSolutionArrays) { + for (const auto& array : flowsSolutionVector) { doInsert(array, data::TargetType::RESTART_SOLUTION); } }