109class EclWriter :
public EclGenericWriter<GetPropType<TypeTag, Properties::Grid>,
110 GetPropType<TypeTag, Properties::EquilGrid>,
111 GetPropType<TypeTag, Properties::GridView>,
112 GetPropType<TypeTag, Properties::ElementMapper>,
113 GetPropType<TypeTag, Properties::Scalar>>
123 using Element =
typename GridView::template Codim<0>::Entity;
125 using ElementIterator =
typename GridView::template Codim<0>::Iterator;
126 using BaseType = EclGenericWriter<Grid,EquilGrid,GridView,ElementMapper,Scalar>;
128 typedef Dune::MultipleCodimMultipleGeomTypeMapper< GridView > VertexMapper;
137 static void registerParameters()
139 OutputModule::registerParameters();
142 (
"Write the ECL-formated results in a non-blocking way "
143 "(i.e., using a separate thread).");
145 (
"Write ESMRY file for fast loading of summary data.");
151 explicit EclWriter(Simulator& simulator)
152 : BaseType(simulator.vanguard().schedule(),
153 simulator.vanguard().eclState(),
154 simulator.vanguard().summaryConfig(),
155 simulator.vanguard().grid(),
156 ((simulator.vanguard().grid().comm().rank() == 0)
157 ? &simulator.vanguard().equilGrid()
159 simulator.vanguard().gridView(),
160 simulator.vanguard().cartesianIndexMapper(),
161 ((simulator.vanguard().grid().comm().rank() == 0)
162 ? &simulator.vanguard().equilCartesianIndexMapper()
166 , simulator_(simulator)
169 if (this->simulator_.vanguard().grid().comm().size() > 1) {
170 auto smryCfg = (this->simulator_.vanguard().grid().comm().rank() == 0)
171 ? this->eclIO_->finalSummaryConfig()
174 eclBroadcast(this->simulator_.vanguard().grid().comm(), smryCfg);
176 this->outputModule_ = std::make_unique<OutputModule>
177 (simulator, smryCfg, this->collectOnIORank_);
182 this->outputModule_ = std::make_unique<OutputModule>
183 (simulator, this->eclIO_->finalSummaryConfig(), this->collectOnIORank_);
186 this->rank_ = this->simulator_.vanguard().grid().comm().rank();
188 this->simulator_.vanguard().eclState().computeFipRegionStatistics();
194 const EquilGrid& globalGrid()
const
196 return simulator_.vanguard().equilGrid();
205 const int reportStepNum = simulator_.episodeIndex() + 1;
225 if (reportStepNum == 0)
228 const Scalar curTime = simulator_.time() + simulator_.timeStepSize();
229 const Scalar totalCpuTime =
230 simulator_.executionTimer().realTimeElapsed() +
231 simulator_.setupTimer().realTimeElapsed() +
232 simulator_.vanguard().setupTime();
234 const auto localWellData = simulator_.problem().wellModel().wellData();
235 const auto localWBP = simulator_.problem().wellModel().wellBlockAveragePressures();
236 const auto localGroupAndNetworkData = simulator_.problem().wellModel()
237 .groupAndNetworkData(reportStepNum);
239 const auto localAquiferData = simulator_.problem().aquiferModel().aquiferData();
240 const auto localWellTestState = simulator_.problem().wellModel().wellTestState();
241 this->prepareLocalCellData(isSubStep, reportStepNum);
243 if (this->outputModule_->needInterfaceFluxes(isSubStep)) {
244 this->captureLocalFluxData();
247 if (this->collectOnIORank_.isParallel()) {
248 OPM_BEGIN_PARALLEL_TRY_CATCH()
250 std::map<std::pair<std::string,int>,
double> dummy;
251 this->collectOnIORank_.collect({},
252 outputModule_->getBlockData(),
256 localGroupAndNetworkData,
259 this->outputModule_->getInterRegFlows(),
263 if (this->collectOnIORank_.isIORank()) {
264 auto& iregFlows = this->collectOnIORank_.globalInterRegFlows();
266 if (! iregFlows.readIsConsistent()) {
267 throw std::runtime_error {
268 "Inconsistent inter-region flow "
269 "region set names in parallel"
273 iregFlows.compress();
276 OPM_END_PARALLEL_TRY_CATCH(
"Collect to I/O rank: ",
277 this->simulator_.vanguard().grid().comm());
281 std::map<std::string, double> miscSummaryData;
282 std::map<std::string, std::vector<double>> regionData;
286 OPM_TIMEBLOCK(outputFipLogAndFipresvLog);
288 inplace = outputModule_->calc_inplace(miscSummaryData, regionData, simulator_.gridView().comm());
290 if (this->collectOnIORank_.isIORank()){
296 if (totalCpuTime != 0.0) {
297 miscSummaryData[
"TCPU"] = totalCpuTime;
299 if (this->sub_step_report_.total_newton_iterations != 0) {
300 miscSummaryData[
"NEWTON"] = this->sub_step_report_.total_newton_iterations;
302 if (this->sub_step_report_.total_linear_iterations != 0) {
303 miscSummaryData[
"MLINEARS"] = this->sub_step_report_.total_linear_iterations;
305 if (this->sub_step_report_.total_newton_iterations != 0) {
306 miscSummaryData[
"NLINEARS"] =
static_cast<float>(this->sub_step_report_.total_linear_iterations) / this->sub_step_report_.total_newton_iterations;
308 if (this->sub_step_report_.min_linear_iterations != std::numeric_limits<unsigned int>::max()) {
309 miscSummaryData[
"NLINSMIN"] = this->sub_step_report_.min_linear_iterations;
311 if (this->sub_step_report_.max_linear_iterations != 0) {
312 miscSummaryData[
"NLINSMAX"] = this->sub_step_report_.max_linear_iterations;
314 if (this->simulation_report_.success.total_linear_iterations != 0) {
315 miscSummaryData[
"MSUMLINS"] = this->simulation_report_.success.total_linear_iterations;
317 if (this->simulation_report_.success.total_newton_iterations != 0) {
318 miscSummaryData[
"MSUMNEWT"] = this->simulation_report_.success.total_newton_iterations;
322 OPM_TIMEBLOCK(evalSummary);
324 const auto& blockData = this->collectOnIORank_.isParallel()
325 ? this->collectOnIORank_.globalBlockData()
326 : this->outputModule_->getBlockData();
328 const auto& interRegFlows = this->collectOnIORank_.isParallel()
329 ? this->collectOnIORank_.globalInterRegFlows()
330 : this->outputModule_->getInterRegFlows();
332 this->evalSummary(reportStepNum,
336 localGroupAndNetworkData,
342 this->outputModule_->initialInplace(),
344 this->summaryState(),
352 const auto& gridView = simulator_.vanguard().gridView();
353 const int num_interior = detail::
354 countLocalInteriorCellsGridView(gridView);
356 this->outputModule_->
357 allocBuffers(num_interior, 0,
false,
false,
false);
360#pragma omp parallel for
362 for (
int dofIdx = 0; dofIdx < num_interior; ++dofIdx) {
363 const auto& intQuants = *simulator_.model().cachedIntensiveQuantities(dofIdx, 0);
364 const auto totVolume = simulator_.model().dofTotalVolume(dofIdx);
366 this->outputModule_->updateFluidInPlace(dofIdx, intQuants, totVolume);
371 outputModule_->calc_initial_inplace(simulator_.gridView().comm());
374 const auto& fip = simulator_.vanguard().eclState().getEclipseConfig().fip();
375 if (fip.output(FIPConfig::OutputField::FIELD) ||
376 fip.output(FIPConfig::OutputField::RESV))
378 OPM_TIMEBLOCK(outputFipLogAndFipresvLog);
379 boost::posix_time::ptime start_time =
380 boost::posix_time::from_time_t(simulator_.vanguard().schedule().getStartTime());
382 if (this->collectOnIORank_.isIORank()) {
383 inplace_ = outputModule_->initialInplace().value();
384 outputModule_->outputFipAndResvLog(inplace_, 0, 0.0, start_time,
385 false, simulator_.gridView().comm());
389 outputModule_->outputFipAndResvLogToCSV(0,
false, simulator_.gridView().comm());
394 if (! this->collectOnIORank_.isIORank()) {
406 const auto firstStep = this->initialStep();
410 const auto& rpt = this->schedule_[simStep].rpt_config();
412 if (rpt.contains(
"WELSPECS") && (rpt.at(
"WELSPECS") > 0)) {
415 this->writeWellspecReport(timer);
423 if (rpt.contains(
"WELLS") && rpt.at(
"WELLS") > 0) {
424 this->writeWellflowReport(timer, simStep, rpt.at(
"WELLS"));
427 this->outputModule_->outputFipAndResvLog(this->inplace_,
432 simulator_.gridView().comm());
437 void writeOutput(data::Solution&& localCellData,
bool isSubStep)
439 OPM_TIMEBLOCK(writeOutput);
441 const int reportStepNum = simulator_.episodeIndex() + 1;
442 this->prepareLocalCellData(isSubStep, reportStepNum);
443 this->outputModule_->outputErrorLog(simulator_.gridView().comm());
446 auto localWellData = simulator_.problem().wellModel().wellData();
447 auto localGroupAndNetworkData = simulator_.problem().wellModel()
448 .groupAndNetworkData(reportStepNum);
450 auto localAquiferData = simulator_.problem().aquiferModel().aquiferData();
451 auto localWellTestState = simulator_.problem().wellModel().wellTestState();
453 const bool isFlowsn = this->outputModule_->getFlows().hasFlowsn();
454 auto flowsn = this->outputModule_->getFlows().getFlowsn();
456 const bool isFloresn = this->outputModule_->getFlows().hasFloresn();
457 auto floresn = this->outputModule_->getFlows().getFloresn();
459 if (! isSubStep || Parameters::Get<Parameters::EnableWriteAllSolutions>()) {
461 if (localCellData.empty()) {
462 this->outputModule_->assignToSolution(localCellData);
466 this->outputModule_->addRftDataToWells(localWellData,
468 simulator_.gridView().comm());
471 if (this->collectOnIORank_.isParallel() ||
472 this->collectOnIORank_.doesNeedReordering())
479 this->collectOnIORank_.collect(localCellData,
480 this->outputModule_->getBlockData(),
481 this->outputModule_->getExtraBlockData(),
484 localGroupAndNetworkData,
490 if (this->collectOnIORank_.isIORank()) {
491 this->outputModule_->assignGlobalFieldsToSolution(this->collectOnIORank_.globalCellData());
494 this->outputModule_->assignGlobalFieldsToSolution(localCellData);
497 if (this->collectOnIORank_.isIORank()) {
498 const Scalar curTime = simulator_.time() + simulator_.timeStepSize();
499 const Scalar nextStepSize = simulator_.problem().nextTimeStepSize();
500 std::optional<int> timeStepIdx;
501 if (Parameters::Get<Parameters::EnableWriteAllSolutions>()) {
502 timeStepIdx = simulator_.timeStepIndex();
504 this->doWriteOutput(reportStepNum, timeStepIdx, isSubStep,
505 std::move(localCellData),
506 std::move(localWellData),
507 std::move(localGroupAndNetworkData),
508 std::move(localAquiferData),
509 std::move(localWellTestState),
512 this->summaryState(),
513 this->simulator_.problem().thresholdPressure().getRestartVector(),
514 curTime, nextStepSize,
515 Parameters::Get<Parameters::EclOutputDoublePrecision>(),
516 isFlowsn, std::move(flowsn),
517 isFloresn, std::move(floresn));
523 const auto enablePCHysteresis = simulator_.problem().materialLawManager()->enablePCHysteresis();
524 const auto enableNonWettingHysteresis = simulator_.problem().materialLawManager()->enableNonWettingHysteresis();
525 const auto enableWettingHysteresis = simulator_.problem().materialLawManager()->enableWettingHysteresis();
526 const auto oilActive = FluidSystem::phaseIsActive(FluidSystem::oilPhaseIdx);
527 const auto gasActive = FluidSystem::phaseIsActive(FluidSystem::gasPhaseIdx);
528 const auto waterActive = FluidSystem::phaseIsActive(FluidSystem::waterPhaseIdx);
529 const auto enableSwatinit = simulator_.vanguard().eclState().fieldProps().has_double(
"SWATINIT");
531 std::vector<RestartKey> solutionKeys {
532 {
"PRESSURE", UnitSystem::measure::pressure},
533 {
"SWAT", UnitSystem::measure::identity, waterActive},
534 {
"SGAS", UnitSystem::measure::identity, gasActive},
535 {
"TEMP", UnitSystem::measure::temperature, enableEnergy},
536 {
"SSOLVENT", UnitSystem::measure::identity, enableSolvent},
538 {
"RS", UnitSystem::measure::gas_oil_ratio, FluidSystem::enableDissolvedGas()},
539 {
"RV", UnitSystem::measure::oil_gas_ratio, FluidSystem::enableVaporizedOil()},
540 {
"RVW", UnitSystem::measure::oil_gas_ratio, FluidSystem::enableVaporizedWater()},
541 {
"RSW", UnitSystem::measure::gas_oil_ratio, FluidSystem::enableDissolvedGasInWater()},
543 {
"SGMAX", UnitSystem::measure::identity, enableNonWettingHysteresis && oilActive && gasActive},
544 {
"SHMAX", UnitSystem::measure::identity, enableWettingHysteresis && oilActive && gasActive},
546 {
"SOMAX", UnitSystem::measure::identity,
547 (enableNonWettingHysteresis && oilActive && waterActive)
548 || simulator_.problem().vapparsActive(simulator_.episodeIndex())},
550 {
"SOMIN", UnitSystem::measure::identity, enablePCHysteresis && oilActive && gasActive},
551 {
"SWHY1", UnitSystem::measure::identity, enablePCHysteresis && oilActive && waterActive},
552 {
"SWMAX", UnitSystem::measure::identity, enableWettingHysteresis && oilActive && waterActive},
554 {
"PPCW", UnitSystem::measure::pressure, enableSwatinit},
558 const auto& tracers = simulator_.vanguard().eclState().tracer();
560 for (
const auto& tracer : tracers) {
561 const auto enableSolTracer =
562 ((tracer.phase == Phase::GAS) && FluidSystem::enableDissolvedGas()) ||
563 ((tracer.phase == Phase::OIL) && FluidSystem::enableVaporizedOil());
565 solutionKeys.emplace_back(tracer.fname(), UnitSystem::measure::identity,
true);
566 solutionKeys.emplace_back(tracer.sname(), UnitSystem::measure::identity, enableSolTracer);
570 const auto& inputThpres = eclState().getSimulationConfig().getThresholdPressure();
571 const std::vector<RestartKey> extraKeys {
572 {
"OPMEXTRA", UnitSystem::measure::identity,
false},
573 {
"THRESHPR", UnitSystem::measure::pressure, inputThpres.active()},
576 const auto& gridView = this->simulator_.vanguard().gridView();
577 const auto numElements = gridView.size(0);
581 this->outputModule_->allocBuffers(numElements,
587 const auto restartSolution =
588 loadParallelRestartSolution(this->eclIO_.get(),
589 solutionKeys, gridView.comm(), 0);
591 if (!restartSolution.empty()) {
592 for (
auto elemIdx = 0*numElements; elemIdx < numElements; ++elemIdx) {
593 const auto globalIdx = this->collectOnIORank_.localIdxToGlobalIdx(elemIdx);
594 this->outputModule_->setRestart(restartSolution, elemIdx, globalIdx);
597 this->simulator_.problem().readSolutionFromOutputModule(0,
true);
598 ElementContext elemCtx(this->simulator_);
599 for (
const auto& elem : elements(gridView, Dune::Partitions::interior)) {
600 elemCtx.updatePrimaryStencil(elem);
601 elemCtx.updatePrimaryIntensiveQuantities(0);
603 this->outputModule_->updateFluidInPlace(elemCtx);
606 this->outputModule_->calc_initial_inplace(this->simulator_.gridView().comm());
614 const auto restartStepIdx = this->simulator_.vanguard()
615 .eclState().getInitConfig().getRestartStep();
617 this->outputModule_->allocBuffers(numElements,
625 const auto restartValues =
626 loadParallelRestart(this->eclIO_.get(),
628 this->summaryState(),
629 solutionKeys, extraKeys, gridView.comm());
631 for (
auto elemIdx = 0*numElements; elemIdx < numElements; ++elemIdx) {
632 const auto globalIdx = this->collectOnIORank_.localIdxToGlobalIdx(elemIdx);
633 this->outputModule_->setRestart(restartValues.solution, elemIdx, globalIdx);
636 auto& tracer_model = simulator_.problem().tracerModel();
637 for (
int tracer_index = 0; tracer_index < tracer_model.numTracers(); ++tracer_index) {
640 const auto& free_tracer_name = tracer_model.fname(tracer_index);
641 const auto& free_tracer_solution = restartValues.solution
642 .template data<double>(free_tracer_name);
644 for (
auto elemIdx = 0*numElements; elemIdx < numElements; ++elemIdx) {
645 const auto globalIdx = this->collectOnIORank_.localIdxToGlobalIdx(elemIdx);
646 tracer_model.setFreeTracerConcentration
647 (tracer_index, elemIdx, free_tracer_solution[globalIdx]);
652 if ((tracer_model.phase(tracer_index) == Phase::GAS && FluidSystem::enableDissolvedGas()) ||
653 (tracer_model.phase(tracer_index) == Phase::OIL && FluidSystem::enableVaporizedOil()))
655 tracer_model.setEnableSolTracers(tracer_index,
true);
657 const auto& sol_tracer_name = tracer_model.sname(tracer_index);
658 const auto& sol_tracer_solution = restartValues.solution
659 .template data<double>(sol_tracer_name);
661 for (
auto elemIdx = 0*numElements; elemIdx < numElements; ++elemIdx) {
662 const auto globalIdx = this->collectOnIORank_.localIdxToGlobalIdx(elemIdx);
663 tracer_model.setSolTracerConcentration
664 (tracer_index, elemIdx, sol_tracer_solution[globalIdx]);
668 tracer_model.setEnableSolTracers(tracer_index,
false);
670 for (
auto elemIdx = 0*numElements; elemIdx < numElements; ++elemIdx) {
671 tracer_model.setSolTracerConcentration(tracer_index, elemIdx, 0.0);
676 if (inputThpres.active()) {
677 const_cast<Simulator&
>(this->simulator_)
678 .problem().thresholdPressure()
679 .setFromRestart(restartValues.getExtra(
"THRESHPR"));
682 restartTimeStepSize_ = restartValues.getExtra(
"OPMEXTRA")[0];
683 if (restartTimeStepSize_ <= 0) {
684 restartTimeStepSize_ = std::numeric_limits<double>::max();
688 this->simulator_.problem().wellModel()
689 .initFromRestartFile(restartValues);
691 if (!restartValues.aquifer.empty()) {
692 this->simulator_.problem().mutableAquiferModel()
693 .initFromRestart(restartValues.aquifer);
703 this->outputModule_->calc_initial_inplace(this->simulator_.gridView().comm());
705 if (this->collectOnIORank_.isIORank()) {
706 if (this->outputModule_->initialInplace().has_value()) {
707 this->inplace_ = this->outputModule_->initialInplace().value();
712 const OutputModule& outputModule()
const
713 {
return *outputModule_; }
715 OutputModule& mutableOutputModule()
const
716 {
return *outputModule_; }
718 Scalar restartTimeStepSize()
const
719 {
return restartTimeStepSize_; }
721 template <
class Serializer>
722 void serializeOp(Serializer& serializer)
724 serializer(*outputModule_);
728 static bool enableEclOutput_()
730 static bool enable = Parameters::Get<Parameters::EnableEclOutput>();
734 const EclipseState& eclState()
const
735 {
return simulator_.vanguard().eclState(); }
737 SummaryState& summaryState()
738 {
return simulator_.vanguard().summaryState(); }
740 Action::State& actionState()
741 {
return simulator_.vanguard().actionState(); }
744 {
return simulator_.vanguard().udqState(); }
746 const Schedule& schedule()
const
747 {
return simulator_.vanguard().schedule(); }
749 void prepareLocalCellData(
const bool isSubStep,
750 const int reportStepNum)
752 OPM_TIMEBLOCK(prepareLocalCellData);
754 if (this->outputModule_->localDataValid()) {
758 const auto& gridView = simulator_.vanguard().gridView();
759 const bool log = this->collectOnIORank_.isIORank();
761 const int num_interior = detail::
762 countLocalInteriorCellsGridView(gridView);
763 this->outputModule_->
764 allocBuffers(num_interior, reportStepNum,
765 isSubStep && !Parameters::Get<Parameters::EnableWriteAllSolutions>(),
768 ElementContext elemCtx(simulator_);
770 OPM_BEGIN_PARALLEL_TRY_CATCH();
773 OPM_TIMEBLOCK(prepareCellBasedData);
775 this->outputModule_->prepareDensityAccumulation();
776 this->outputModule_->setupExtractors(isSubStep, reportStepNum);
777 for (
const auto& elem : elements(gridView, Dune::Partitions::interior)) {
778 elemCtx.updatePrimaryStencil(elem);
779 elemCtx.updatePrimaryIntensiveQuantities(0);
781 this->outputModule_->processElement(elemCtx);
782 this->outputModule_->processElementBlockData(elemCtx);
784 this->outputModule_->clearExtractors();
786 this->outputModule_->accumulateDensityParallel();
790 OPM_TIMEBLOCK(prepareFluidInPlace);
793#pragma omp parallel for
795 for (
int dofIdx = 0; dofIdx < num_interior; ++dofIdx) {
796 const auto& intQuants = *simulator_.model().cachedIntensiveQuantities(dofIdx, 0);
797 const auto totVolume = simulator_.model().dofTotalVolume(dofIdx);
799 this->outputModule_->updateFluidInPlace(dofIdx, intQuants, totVolume);
803 this->outputModule_->validateLocalData();
805 OPM_END_PARALLEL_TRY_CATCH(
"EclWriter::prepareLocalCellData() failed: ",
806 this->simulator_.vanguard().grid().comm());
809 void captureLocalFluxData()
811 OPM_TIMEBLOCK(captureLocalData);
813 const auto& gridView = this->simulator_.vanguard().gridView();
814 const auto timeIdx = 0u;
816 auto elemCtx = ElementContext { this->simulator_ };
818 const auto elemMapper = ElementMapper { gridView, Dune::mcmgElementLayout() };
819 const auto activeIndex = [&elemMapper](
const Element& e)
821 return elemMapper.index(e);
824 const auto cartesianIndex = [
this](
const int elemIndex)
826 return this->cartMapper_.cartesianIndex(elemIndex);
829 this->outputModule_->initializeFluxData();
831 OPM_BEGIN_PARALLEL_TRY_CATCH();
833 for (
const auto& elem : elements(gridView, Dune::Partitions::interiorBorder)) {
834 elemCtx.updateStencil(elem);
835 elemCtx.updateIntensiveQuantities(timeIdx);
836 elemCtx.updateExtensiveQuantities(timeIdx);
838 this->outputModule_->processFluxes(elemCtx, activeIndex, cartesianIndex);
841 OPM_END_PARALLEL_TRY_CATCH(
"EclWriter::captureLocalFluxData() failed: ",
842 this->simulator_.vanguard().grid().comm())
844 this->outputModule_->finalizeFluxData();
847 void writeWellspecReport(const SimulatorTimer& timer)
const
849 const auto changedWells = this->schedule_
850 .changed_wells(timer.reportStepNum(), this->initialStep());
852 if (changedWells.empty()) {
856 this->outputModule_->outputWellspecReport(changedWells,
857 timer.reportStepNum(),
858 timer.simulationTimeElapsed(),
859 timer.currentDateTime());
862 void writeWellflowReport(
const SimulatorTimer& timer,
864 const int wellsRequest)
const
866 this->outputModule_->outputTimeStamp(
"WELLS",
867 timer.simulationTimeElapsed(),
868 timer.reportStepNum(),
869 timer.currentDateTime());
871 const auto wantConnData = wellsRequest > 1;
873 this->outputModule_->outputProdLog(simStep, wantConnData);
874 this->outputModule_->outputInjLog(simStep, wantConnData);
875 this->outputModule_->outputCumLog(simStep, wantConnData);
876 this->outputModule_->outputMSWLog(simStep);
879 int initialStep()
const
881 const auto& initConfig = this->eclState().cfg().init();
883 return initConfig.restartRequested()
884 ? initConfig.getRestartStep()
888 Simulator& simulator_;
889 std::unique_ptr<OutputModule> outputModule_;
890 Scalar restartTimeStepSize_;