/* Copyright (c) 2014 SINTEF ICT, Applied Mathematics. Copyright (c) 2015 IRIS AS 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 . */ #ifndef OPM_SIMULATORFULLYIMPLICITBLACKOILOUTPUT_HEADER_INCLUDED #define OPM_SIMULATORFULLYIMPLICITBLACKOILOUTPUT_HEADER_INCLUDED #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 #include #ifdef HAVE_OPM_GRID #include #endif namespace Opm { class SimulationDataContainer; class BlackoilState; void outputStateVtk(const UnstructuredGrid& grid, const Opm::SimulationDataContainer& state, const int step, const std::string& output_dir); void outputWellStateMatlab(const Opm::WellState& well_state, const int step, const std::string& output_dir); #ifdef HAVE_OPM_GRID void outputStateVtk(const Dune::CpGrid& grid, const Opm::SimulationDataContainer& state, const int step, const std::string& output_dir); #endif template void outputStateMatlab(const Grid& grid, const Opm::SimulationDataContainer& state, const int step, const std::string& output_dir) { Opm::DataMap dm; dm["saturation"] = &state.saturation(); dm["pressure"] = &state.pressure(); for (const auto& pair : state.cellData()) { const std::string& name = pair.first; std::string key; if( name == "SURFACEVOL" ) { key = "surfvolume"; } else if( name == "RV" ) { key = "rv"; } else if( name == "GASOILRATIO" ) { key = "rs"; } else { // otherwise skip entry continue; } // set data to datmap dm[ key ] = &pair.second; } std::vector cell_velocity; Opm::estimateCellVelocity(AutoDiffGrid::numCells(grid), AutoDiffGrid::numFaces(grid), AutoDiffGrid::beginFaceCentroids(grid), UgGridHelpers::faceCells(grid), AutoDiffGrid::beginCellCentroids(grid), AutoDiffGrid::beginCellVolumes(grid), AutoDiffGrid::dimensions(grid), state.faceflux(), cell_velocity); dm["velocity"] = &cell_velocity; // Write data (not grid) in Matlab format for (Opm::DataMap::const_iterator it = dm.begin(); it != dm.end(); ++it) { std::ostringstream fname; fname << output_dir << "/" << it->first; ensureDirectoryExists(fname.str()); fname << "/" << std::setw(3) << std::setfill('0') << step << ".txt"; std::ofstream file(fname.str().c_str()); if (!file) { OPM_THROW(std::runtime_error, "Failed to open " << fname.str()); } file.precision(15); const std::vector& d = *(it->second); std::copy(d.begin(), d.end(), std::ostream_iterator(file, "\n")); } } class BlackoilSubWriter { public: BlackoilSubWriter( const std::string& outputDir ) : outputDir_( outputDir ) {} virtual void writeTimeStep(const SimulatorTimerInterface& timer, const SimulationDataContainer& state, const WellStateFullyImplicitBlackoil&, bool /*substep*/ = false) = 0; protected: const std::string outputDir_; }; template< class Grid > class BlackoilVTKWriter : public BlackoilSubWriter { public: BlackoilVTKWriter( const Grid& grid, const std::string& outputDir ) : BlackoilSubWriter( outputDir ) , grid_( grid ) {} void writeTimeStep(const SimulatorTimerInterface& timer, const SimulationDataContainer& state, const WellStateFullyImplicitBlackoil&, bool /*substep*/ = false) override { outputStateVtk(grid_, state, timer.currentStepNum(), outputDir_); } protected: const Grid& grid_; }; template< typename Grid > class BlackoilMatlabWriter : public BlackoilSubWriter { public: BlackoilMatlabWriter( const Grid& grid, const std::string& outputDir ) : BlackoilSubWriter( outputDir ) , grid_( grid ) {} void writeTimeStep(const SimulatorTimerInterface& timer, const SimulationDataContainer& reservoirState, const WellStateFullyImplicitBlackoil& wellState, bool /*substep*/ = false) override { outputStateMatlab(grid_, reservoirState, timer.currentStepNum(), outputDir_); outputWellStateMatlab(wellState, timer.currentStepNum(), outputDir_); } protected: const Grid& grid_; }; /// Extra data to read/write for OPM restarting struct ExtraData { double suggested_step = -1.0; }; /** \brief Wrapper class for VTK, Matlab, and ECL output. */ class BlackoilOutputWriter { public: // constructor creating different sub writers template BlackoilOutputWriter(const Grid& grid, const ParameterGroup& param, const Opm::EclipseState& eclipseState, const Opm::Schedule& schedule, const Opm::SummaryConfig& summaryConfig, std::unique_ptr&& eclIO, const Opm::PhaseUsage &phaseUsage); /** \copydoc Opm::OutputWriter::writeInit */ void writeInit(const data::Solution& simProps, const NNC& nnc); /*! * \brief Write a blackoil reservoir state to disk for later inspection with * visualization tools like ResInsight. This function will extract the * requested output cell properties specified by the RPTRST keyword * and write these to file. */ template void writeTimeStep(const SimulatorTimerInterface& timer, const SimulationDataContainer& reservoirState, const Opm::WellStateFullyImplicitBlackoil& wellState, const Model& physicalModel, const bool substep = false, const double nextstep = -1.0, const SimulatorReport& simulatorReport = SimulatorReport()); /*! * \brief Write a blackoil reservoir state to disk for later inspection with * visualization tools like ResInsight. This function will write all * CellData in simProps to the file as well as the extraRestartData. */ void writeTimeStepWithCellProperties( const SimulatorTimerInterface& timer, const SimulationDataContainer& reservoirState, const data::Solution& cellData, const Opm::WellStateFullyImplicitBlackoil& wellState, const std::map& miscSummaryData, const RestartValue::ExtraVector& extraRestartData, bool substep = false); /*! * \brief Write a blackoil reservoir state to disk for later inspection with * visualization tools like ResInsight. This function will not write * any cell properties (e.g., those requested by RPTRST keyword) */ void writeTimeStepWithoutCellProperties( const SimulatorTimerInterface& timer, const SimulationDataContainer& reservoirState, const Opm::WellStateFullyImplicitBlackoil& wellState, const std::map& miscSummaryData, const RestartValue::ExtraVector& extraRestartData, bool substep = false); /*! * \brief Write a blackoil reservoir state to disk for later inspection with * visualization tools like ResInsight. This is the function which does * the actual write to file. */ void writeTimeStepSerial(const SimulatorTimerInterface& timer, const SimulationDataContainer& reservoirState, const Opm::WellStateFullyImplicitBlackoil& wellState, const data::Solution& simProps, const std::map& miscSummaryData, const RestartValue::ExtraVector& extraRestartData, bool substep ); /** \brief return output directory */ const std::string& outputDirectory() const { return outputDir_; } /** \brief return true if output is enabled */ bool output () const { return output_; } /** \brief Whether this process does write to disk */ bool isIORank () const { return parallelOutput_->isIORank(); } template void initFromRestartFile(const PhaseUsage& phaseUsage, const Grid& grid, SimulationDataContainer& simulatorstate, WellState& wellstate, ExtraData& extra); bool isRestart() const; bool requireFIPNUM() const; protected: const bool output_; std::unique_ptr< ParallelDebugOutputInterface > parallelOutput_; // Parameters for output. const std::string outputDir_; const bool restart_double_si_; Opm::PhaseUsage phaseUsage_; std::unique_ptr< BlackoilSubWriter > vtkWriter_; std::unique_ptr< BlackoilSubWriter > matlabWriter_; std::unique_ptr< EclipseIO > eclIO_; const EclipseState& eclipseState_; const Schedule& schedule_; const SummaryConfig& summaryConfig_; std::unique_ptr< ThreadHandle > asyncOutput_; const int* globalCellIdxMap_; }; ////////////////////////////////////////////////////////////// // // Implementation // ////////////////////////////////////////////////////////////// template inline BlackoilOutputWriter:: BlackoilOutputWriter(const Grid& grid, const ParameterGroup& param, const Opm::EclipseState& eclipseState, const Opm::Schedule& schedule, const Opm::SummaryConfig& summaryConfig, std::unique_ptr&& eclIO, const Opm::PhaseUsage &phaseUsage) : output_( [ ¶m ] () -> bool { // If output parameter is true or all, then we do output const std::string outputString = param.getDefault("output", std::string("all")); return ( outputString == "all" || outputString == "true" ); }() ), parallelOutput_( output_ ? new ParallelDebugOutput< Grid >( grid, eclipseState, schedule, phaseUsage.num_phases, phaseUsage ) : 0 ), outputDir_( eclipseState.getIOConfig().getOutputDir() ), restart_double_si_( output_ ? param.getDefault("restart_double_si", false) : false ), phaseUsage_( phaseUsage ), eclipseState_(eclipseState), schedule_(schedule), summaryConfig_(summaryConfig), asyncOutput_(), globalCellIdxMap_(Opm::UgGridHelpers::globalCell(grid)) { // For output. if ( output_ ) { if ( param.getDefault("output_vtk",false) ) { vtkWriter_ .reset(new BlackoilVTKWriter< Grid >( grid, outputDir_ )); } auto output_matlab = param.getDefault("output_matlab", false ); if ( parallelOutput_->isParallel() && output_matlab ) { Opm::OpmLog::warning("Parallel Output Config", "Velocity output for matlab is broken in parallel."); } if( parallelOutput_->isIORank() ) { if ( output_matlab ) { matlabWriter_ .reset(new BlackoilMatlabWriter< Grid >( grid, outputDir_ )); } eclIO_ = std::move(eclIO); // Ensure that output dir exists ensureDirectoryExists(outputDir_); } // create output thread if enabled and rank is I/O rank // async output is enabled by default if pthread are enabled #if HAVE_PTHREAD const bool asyncOutputDefault = true; #else const bool asyncOutputDefault = false; #endif if( param.getDefault("async_output", asyncOutputDefault ) ) { const bool isIORank = parallelOutput_ ? parallelOutput_->isIORank() : true; #if HAVE_PTHREAD asyncOutput_.reset( new ThreadHandle( isIORank ) ); #else OPM_THROW(std::runtime_error,"Pthreads were not found, cannot enable async_output"); #endif } } } template inline void BlackoilOutputWriter:: initFromRestartFile( const PhaseUsage& phaseUsage, const Grid& grid, SimulationDataContainer& simulatorstate, WellState& wellstate, ExtraData& extra ) { std::vector solution_keys = {{"PRESSURE" , UnitSystem::measure::pressure}, {"SWAT" , UnitSystem::measure::identity}, {"SGAS" , UnitSystem::measure::identity}, {"TEMP" , UnitSystem::measure::temperature}, {"RS" , UnitSystem::measure::gas_oil_ratio}, {"RV" , UnitSystem::measure::oil_gas_ratio}, {"SOMAX", UnitSystem::measure::identity, false}, {"PCSWM_OW", UnitSystem::measure::identity, false}, {"KRNSW_OW", UnitSystem::measure::identity, false}, {"PCSWM_GO", UnitSystem::measure::identity, false}, {"KRNSW_GO", UnitSystem::measure::identity, false}}; std::vector extra_keys { {"OPMEXTRA" , UnitSystem::measure::identity, false} }; if (restart_double_si_) { // Avoid any unit conversions, treat restart input as SI units. for (auto& elem : solution_keys) { elem.dim = UnitSystem::measure::identity; } } // gives a dummy dynamic_list_econ_limited DynamicListEconLimited dummy_list_econ_limited; WellsManager wellsmanager(eclipseState_, schedule_, // The restart step value is used to identify wells present at the given time step. // Wells that are added at the same time step as RESTART is initiated will not be // present in a restart file. Use the previous time step to retrieve wells // that have information written to the restart file. std::max(eclipseState_.getInitConfig().getRestartStep() - 1, 0), Opm::UgGridHelpers::numCells(grid), Opm::UgGridHelpers::globalCell(grid), Opm::UgGridHelpers::cartDims(grid), Opm::UgGridHelpers::dimensions(grid), Opm::UgGridHelpers::cell2Faces(grid), Opm::UgGridHelpers::beginFaceCentroids(grid), dummy_list_econ_limited // We need to pass the optionaly arguments // as we get the following error otherwise // with c++ (Debian 4.9.2-10) 4.9.2 and -std=c++11 // converting to ‘const std::unordered_set >’ from initializer list would use explicit constructo , false, std::unordered_set()); const Wells* wells = wellsmanager.c_wells(); size_t numCells = Opm::UgGridHelpers::numCells(grid); wellstate.resize(wells, numCells, phaseUsage ); //Resize for restart step auto restart_values = eclIO_->loadRestart(solution_keys, extra_keys); solutionToSim( restart_values, phaseUsage, simulatorstate ); wellsToState( restart_values.wells, phaseUsage, wellstate ); if (restart_values.hasExtra("OPMEXTRA")) { const std::vector& opmextra = restart_values.getExtra("OPMEXTRA"); assert(opmextra.size() == 1); extra.suggested_step = opmextra[0]; } else { OpmLog::warning("Restart data is missing OPMEXTRA field, restart run may deviate from original run."); extra.suggested_step = -1.0; } } namespace detail { template void addToSimData( SimulationDataContainer& simData, const std::string& name, const V& vec ) { if (vec.size() == 0) { return; } typedef std::vector< double > OutputVectorType; // get data map auto& dataMap = simData.cellData(); // insert name,vector into data map dataMap.insert( std::make_pair( name, OutputVectorType( vec.data(), vec.data() + vec.size() ) ) ); } template void addToSimData( SimulationDataContainer& simData, const std::string& name, const AutoDiffBlock& adb ) { // forward value of ADB to output addToSimData( simData, name, adb.value() ); } // this method basically converts all Eigen vectors to std::vectors // stored in a SimulationDataContainer template SimulationDataContainer convertToSimulationDataContainer( const SimulatorData& sd, const SimulationDataContainer& localState, const Opm::PhaseUsage& phaseUsage ) { // copy local state and then add missing data SimulationDataContainer simData( localState ); //Get shorthands for water, oil, gas const int aqua_active = phaseUsage.phase_used[Opm::PhaseUsage::Aqua]; const int liquid_active = phaseUsage.phase_used[Opm::PhaseUsage::Liquid]; const int vapour_active = phaseUsage.phase_used[Opm::PhaseUsage::Vapour]; const int aqua_idx = phaseUsage.phase_pos[Opm::PhaseUsage::Aqua]; const int liquid_idx = phaseUsage.phase_pos[Opm::PhaseUsage::Liquid]; const int vapour_idx = phaseUsage.phase_pos[Opm::PhaseUsage::Vapour]; // WATER if( aqua_active ) { addToSimData( simData, "1OVERBW", sd.rq[aqua_idx].b ); addToSimData( simData, "WAT_DEN", sd.rq[aqua_idx].rho ); addToSimData( simData, "WAT_VISC", sd.rq[aqua_idx].mu ); addToSimData( simData, "WATKR", sd.rq[aqua_idx].kr ); } // OIL if( liquid_active ) { addToSimData( simData, "1OVERBO", sd.rq[liquid_idx].b ); addToSimData( simData, "OIL_DEN", sd.rq[liquid_idx].rho ); addToSimData( simData, "OIL_VISC", sd.rq[liquid_idx].mu ); addToSimData( simData, "OILKR", sd.rq[liquid_idx].kr ); } // GAS if( vapour_active ) { addToSimData( simData, "1OVERBG", sd.rq[vapour_idx].b ); addToSimData( simData, "GAS_DEN", sd.rq[vapour_idx].rho ); addToSimData( simData, "GAS_VISC", sd.rq[vapour_idx].mu ); addToSimData( simData, "GASKR", sd.rq[vapour_idx].kr ); } // RS and RV addToSimData( simData, "RSSAT", sd.rsSat ); addToSimData( simData, "RVSAT", sd.rvSat ); addToSimData( simData, "SOMAX", sd.soMax ); addToSimData( simData, "PBUB", sd.Pb ); addToSimData( simData, "PDEW", sd.Pd ); addToSimData( simData, "PCSWMDC_OW", sd.pcswmdc_ow ); addToSimData( simData, "KRNSWMDC_OW", sd.krnswdc_ow ); addToSimData( simData, "PCSWMDC_GO", sd.pcswmdc_go ); addToSimData( simData, "KRNSWMDC_GO", sd.krnswdc_go ); return simData; } // in case the data is already in a SimulationDataContainer no // conversion is needed inline SimulationDataContainer&& convertToSimulationDataContainer( SimulationDataContainer&& sd, const SimulationDataContainer& , const Opm::PhaseUsage& ) { return std::move( sd ); } /** * Returns the data requested in the restartConfig * NOTE: Since this function steals data from the SimulationDataContainer (std::move), * the variable sd becomes "invalid" after calling this function. */ template void getRestartData(data::Solution& output, SimulationDataContainer&& sd, const Opm::PhaseUsage& /* phaseUsage */, const Model& /* physicalModel */, const RestartConfig& restartConfig, const int reportStepNum, const bool log) { //Get the value of each of the keys for the restart keywords std::map rstKeywords = restartConfig.getRestartKeywords(reportStepNum); for (auto& keyValue : rstKeywords) { keyValue.second = restartConfig.getKeyword(keyValue.first, reportStepNum); } const bool aqua_active = sd.hasCellData("1OVERBW"); const bool liquid_active = sd.hasCellData("1OVERBO"); const bool vapour_active = sd.hasCellData("1OVERBG"); assert( aqua_active == (sd.hasCellData("WAT_DEN") && sd.hasCellData("WAT_VISC") && sd.hasCellData("WATKR") ) ); assert( liquid_active == (sd.hasCellData("OIL_DEN") && sd.hasCellData("OIL_VISC") && sd.hasCellData("OILKR") ) ); assert( vapour_active == (sd.hasCellData("GAS_DEN") && sd.hasCellData("GAS_VISC") && sd.hasCellData("GASKR") ) ); /** * Formation volume factors for water, oil, gas */ if (aqua_active && rstKeywords["BW"] > 0) { rstKeywords["BW"] = 0; output.insert("1OVERBW", Opm::UnitSystem::measure::water_inverse_formation_volume_factor, std::move( sd.getCellData("1OVERBW") ), data::TargetType::RESTART_AUXILIARY); } if (liquid_active && rstKeywords["BO"] > 0) { rstKeywords["BO"] = 0; output.insert("1OVERBO", Opm::UnitSystem::measure::oil_inverse_formation_volume_factor, std::move( sd.getCellData("1OVERBO") ), data::TargetType::RESTART_AUXILIARY); } if (vapour_active && rstKeywords["BG"] > 0) { rstKeywords["BG"] = 0; output.insert("1OVERBG", Opm::UnitSystem::measure::gas_inverse_formation_volume_factor, std::move( sd.getCellData("1OVERBG") ), data::TargetType::RESTART_AUXILIARY); } /** * Densities for water, oil gas */ if (rstKeywords["DEN"] > 0) { rstKeywords["DEN"] = 0; if (aqua_active) { output.insert("WAT_DEN", Opm::UnitSystem::measure::density, std::move( sd.getCellData("WAT_DEN") ), data::TargetType::RESTART_AUXILIARY); } if (liquid_active) { output.insert("OIL_DEN", Opm::UnitSystem::measure::density, std::move( sd.getCellData("OIL_DEN") ), data::TargetType::RESTART_AUXILIARY); } if (vapour_active) { output.insert("GAS_DEN", Opm::UnitSystem::measure::density, std::move( sd.getCellData("GAS_DEN") ), data::TargetType::RESTART_AUXILIARY); } } /** * Viscosities for water, oil gas */ { const bool has_vwat = (rstKeywords["VISC"] > 0) || (rstKeywords["VWAT"] > 0); const bool has_voil = (rstKeywords["VISC"] > 0) || (rstKeywords["VOIL"] > 0); const bool has_vgas = (rstKeywords["VISC"] > 0) || (rstKeywords["VGAS"] > 0); rstKeywords["VISC"] = 0; if (aqua_active && has_vwat) { output.insert("WAT_VISC", Opm::UnitSystem::measure::viscosity, std::move( sd.getCellData("WAT_VISC") ), data::TargetType::RESTART_AUXILIARY); rstKeywords["VWAT"] = 0; } if (liquid_active && has_voil) { output.insert("OIL_VISC", Opm::UnitSystem::measure::viscosity, std::move( sd.getCellData("OIL_VISC") ), data::TargetType::RESTART_AUXILIARY); rstKeywords["VOIL"] = 0; } if (vapour_active && has_vgas) { output.insert("GAS_VISC", Opm::UnitSystem::measure::viscosity, std::move( sd.getCellData("GAS_VISC") ), data::TargetType::RESTART_AUXILIARY); rstKeywords["VGAS"] = 0; } } /** * Relative permeabilities for water, oil, gas */ if (aqua_active && rstKeywords["KRW"] > 0) { auto& krWater = sd.getCellData("WATKR"); if (krWater.size() > 0) { rstKeywords["KRW"] = 0; output.insert("WATKR", // WAT_KR ??? Opm::UnitSystem::measure::identity, std::move( krWater ), data::TargetType::RESTART_AUXILIARY); } else { if ( log ) { Opm::OpmLog::warning("Empty:WATKR", "Not emitting empty Water Rel-Perm"); } } } if (liquid_active && rstKeywords["KRO"] > 0) { auto& krOil = sd.getCellData("OILKR"); if (krOil.size() > 0) { rstKeywords["KRO"] = 0; output.insert("OILKR", Opm::UnitSystem::measure::identity, std::move( krOil ), data::TargetType::RESTART_AUXILIARY); } else { if ( log ) { Opm::OpmLog::warning("Empty:OILKR", "Not emitting empty Oil Rel-Perm"); } } } if (vapour_active && rstKeywords["KRG"] > 0) { auto& krGas = sd.getCellData("GASKR"); if (krGas.size() > 0) { rstKeywords["KRG"] = 0; output.insert("GASKR", Opm::UnitSystem::measure::identity, std::move( krGas ), data::TargetType::RESTART_AUXILIARY); } else { if ( log ) { Opm::OpmLog::warning("Empty:GASKR", "Not emitting empty Gas Rel-Perm"); } } } /** * Vaporized and dissolved gas/oil ratio */ if (vapour_active && liquid_active && rstKeywords["RSSAT"] > 0) { rstKeywords["RSSAT"] = 0; output.insert("RSSAT", Opm::UnitSystem::measure::gas_oil_ratio, std::move( sd.getCellData("RSSAT") ), data::TargetType::RESTART_AUXILIARY); } if (vapour_active && liquid_active && rstKeywords["RVSAT"] > 0) { rstKeywords["RVSAT"] = 0; output.insert("RVSAT", Opm::UnitSystem::measure::oil_gas_ratio, std::move( sd.getCellData("RVSAT") ), data::TargetType::RESTART_AUXILIARY); } /** * Bubble point and dew point pressures */ if (vapour_active && liquid_active && rstKeywords["PBPD"] > 0) { rstKeywords["PBPD"] = 0; if (sd.hasCellData("PBUB")) { output.insert("PBUB", Opm::UnitSystem::measure::pressure, std::move( sd.getCellData("PBUB") ), data::TargetType::RESTART_AUXILIARY); } else if (log) { Opm::OpmLog::warning("Bubble point pressure unavailable", "Output of bubble point pressure requested but not available in this simulator. Ignoring."); } if (sd.hasCellData("PDEW")) { output.insert("PDEW", Opm::UnitSystem::measure::pressure, std::move( sd.getCellData("PDEW") ), data::TargetType::RESTART_AUXILIARY); } else if (log) { Opm::OpmLog::warning("Dew point pressure unavailable", "Output of dew point pressure requested but not available in this simulator. Ignoring."); } } if (sd.hasCellData("SOMAX")) { output.insert("SOMAX", Opm::UnitSystem::measure::identity, std::move( sd.getCellData("SOMAX") ), data::TargetType::RESTART_AUXILIARY); } if (sd.hasCellData("PCSWMDC_OW")) { output.insert("PCSWM_OW", //FIXME: Eight-long variable name Opm::UnitSystem::measure::identity, std::move( sd.getCellData("PCSWMDC_OW") ), data::TargetType::RESTART_AUXILIARY); } if (sd.hasCellData("KRNSWMDC_OW")) { output.insert("KRNSW_OW", Opm::UnitSystem::measure::identity, std::move( sd.getCellData("KRNSWMDC_OW") ), data::TargetType::RESTART_AUXILIARY); } if (sd.hasCellData("PCSWMDC_GO")) { output.insert("PCSWM_GO", //FIXME: Eight-long variable name Opm::UnitSystem::measure::identity, std::move( sd.getCellData("PCSWMDC_GO") ), data::TargetType::RESTART_AUXILIARY); } if (sd.hasCellData("KRNSWMDC_GO")) { output.insert("KRNSW_GO", Opm::UnitSystem::measure::identity, std::move( sd.getCellData("KRNSWMDC_GO") ), data::TargetType::RESTART_AUXILIARY); } //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 file."); Opm::OpmLog::warning("Unhandled output keyword", logstring); } } } } /** * Checks if the summaryConfig has a keyword with the standardized field, region, or block prefixes. */ inline bool hasFRBKeyword(const SummaryConfig& summaryConfig, const std::string keyword) { std::string field_kw = "F" + keyword; std::string region_kw = "R" + keyword; std::string block_kw = "B" + keyword; return summaryConfig.hasKeyword(field_kw) || summaryConfig.hasKeyword(region_kw) || summaryConfig.hasKeyword(block_kw); } /** * Returns the data as asked for in the summaryConfig */ template void getSummaryData(data::Solution& output, const Opm::PhaseUsage& phaseUsage, const Model& physicalModel, const SummaryConfig& summaryConfig) { typedef typename Model::FIPDataType FIPDataType; typedef typename FIPDataType::VectorType VectorType; FIPDataType fd = physicalModel.getFIPData(); //Get shorthands for water, oil, gas const int aqua_active = phaseUsage.phase_used[Opm::PhaseUsage::Aqua]; const int liquid_active = phaseUsage.phase_used[Opm::PhaseUsage::Liquid]; const int vapour_active = phaseUsage.phase_used[Opm::PhaseUsage::Vapour]; /** * Now process all of the summary config files */ // Water in place if (aqua_active && hasFRBKeyword(summaryConfig, "WIP")) { output.insert("WIP", Opm::UnitSystem::measure::volume, std::move( fd.fip[ FIPDataType::FIP_AQUA ] ), data::TargetType::SUMMARY ); } if (liquid_active) { const VectorType& oipl = fd.fip[FIPDataType::FIP_LIQUID]; VectorType oip ( oipl ); const size_t size = oip.size(); const VectorType& oipg = vapour_active ? fd.fip[FIPDataType::FIP_VAPORIZED_OIL] : VectorType(size, 0.0); if( vapour_active ) { // oip = oipl + oipg for( size_t i=0; i inline void BlackoilOutputWriter:: writeTimeStep(const SimulatorTimerInterface& timer, const SimulationDataContainer& localState, const WellStateFullyImplicitBlackoil& localWellState, const Model& physicalModel, const bool substep, const double nextstep, const SimulatorReport& simulatorReport) { data::Solution localCellData{}; const RestartConfig& restartConfig = eclipseState_.getRestartConfig(); const int reportStepNum = timer.reportStepNum(); bool logMessages = output_ && parallelOutput_->isIORank(); RestartValue::ExtraVector extraRestartData; std::map miscSummaryData; if( output_ ) { { // get all data that need to be included in output from the model // for flow_legacy and polymer this is a struct holding the data // while for flow_ebos a SimulationDataContainer is returned // this is addressed in the above specialized methods SimulationDataContainer sd = detail::convertToSimulationDataContainer( physicalModel.getSimulatorData(localState), localState, phaseUsage_ ); localCellData = simToSolution( sd, restart_double_si_, phaseUsage_); // Get "normal" data (SWAT, PRESSURE, ...); detail::getRestartData( localCellData, std::move(sd), phaseUsage_, physicalModel, restartConfig, reportStepNum, logMessages ); // sd will be invalid after getRestartData has been called } detail::getSummaryData( localCellData, phaseUsage_, physicalModel, summaryConfig_ ); assert(!localCellData.empty()); // Add suggested next timestep to extra data. extraRestartData.push_back({{"OPMEXTRA", UnitSystem::measure::identity}, std::vector(1, nextstep)}); // Add TCPU if simulatorReport is not defaulted. const double totalSolverTime = simulatorReport.solver_time; if (totalSolverTime != 0.0) { miscSummaryData["TCPU"] = totalSolverTime; } } writeTimeStepWithCellProperties(timer, localState, localCellData, physicalModel.wellModel().wellState(localWellState), miscSummaryData, extraRestartData, substep); } } #endif