// -*- 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 namespace { template void logUniqueFailedCells(const std::string& messageTag, std::string_view prefix, const std::size_t maxNumCellsFaillog, const std::vector& cells, IJKString&& ijkString) { if (cells.empty()) { return; } std::vector sorted(cells); std::sort(sorted.begin(), sorted.end()); auto u = std::unique(sorted.begin(), sorted.end()); const auto numFailed = static_cast (std::distance(sorted.begin(), u)); std::ostringstream errlog; errlog << prefix << " failed for " << numFailed << " cell" << ((numFailed != std::size_t{1}) ? "s" : "") << " [" << ijkString(cells[0]); const auto maxElems = std::min(maxNumCellsFaillog, numFailed); for (auto i = 1 + 0*maxElems; i < maxElems; ++i) { errlog << ", " << ijkString(cells[i]); } if (numFailed > maxNumCellsFaillog) { errlog << ", ..."; } errlog << ']'; Opm::OpmLog::warning(messageTag, errlog.str()); } std::string injectorCModeToString(const Opm::WellInjectorCMode cmode) { auto cmodeStr = std::string{}; // CMODE_UNDEFINED => "" if (cmode != Opm::WellInjectorCMode::CMODE_UNDEFINED) { cmodeStr = Opm::WellInjectorCMode2String(cmode); } return cmodeStr; } std::string producerCModeToString(const Opm::WellProducerCMode cmode) { auto cmodeStr = std::string{}; // NONE && CMODE_UNDEFINED => "" if ((cmode != Opm::WellProducerCMode::NONE) && (cmode != Opm::WellProducerCMode::CMODE_UNDEFINED)) { cmodeStr = Opm::WellProducerCMode2String(cmode); } return cmodeStr; } template std::string formatBorder(const Array& widths) { std::string ss; ss = " "; std::for_each(widths.begin(), widths.end(), [&ss](const auto w) { ss += fmt::format(":{:->{}}", "", w); }); ss += ':'; return ss; } template std::string formatTextRow(const std::array& widths, const std::array& entries) { std::string ss = " "; std::for_each(widths.begin(), widths.end(), [&entries, &ss, i = 0](const auto w) mutable { ss += fmt::format(":{:^{}}", entries[i++], w); }); ss += ":\n"; return ss; } double conn_value_or_zero(const Opm::SummaryState& st, const std::string& wname, const std::string& name, const std::size_t gindex) { return st.has_conn_var(wname, name, gindex) ? st.get_conn_var(wname, name, gindex) : 0.0; } } // Namespace anonymous namespace Opm { template LogOutputHelper::ConnData::ConnData(const Connection& conn) : I(conn.getI() + 1) , J(conn.getJ() + 1) , K(conn.getK() + 1) {} template LogOutputHelper::LogOutputHelper(const EclipseState& eclState, const Schedule& schedule, const SummaryState& summaryState, const std::string& moduleVersionName) : eclState_(eclState) , schedule_(schedule) , summaryState_(summaryState) , flowVersionName_(moduleVersionName) {} template void LogOutputHelper:: cumulative(const std::size_t reportStepNum, const bool withConns) const { this->beginCumulativeReport_(); using Ix = typename WellCumDataType::WCId; const auto& st = summaryState_; for (const auto& gname : this->schedule_.groupNames()) { std::vector values(WellCumDataType::numWCValues); std::vector names(WellCumDataType::numWCNames); names[Ix::WellName] = gname; const auto isField = gname == "FIELD"; values[Ix::OilProd] = isField ? st.get("FOPT", 0.0) : st.get_group_var(gname, "GOPT", 0.0); values[Ix::WaterProd] = isField ? st.get("FWPT", 0.0) : st.get_group_var(gname, "GWPT", 0.0); values[Ix::GasProd] = isField ? st.get("FGPT", 0.0) : st.get_group_var(gname, "GGPT", 0.0); values[Ix::FluidResVolProd] = isField ? st.get("FVPT", 0.0) : st.get_group_var(gname, "GVPT", 0.0); values[Ix::OilInj] = isField ? st.get("FOIT", 0.0) : st.get_group_var(gname, "GOIT", 0.0); values[Ix::WaterInj] = isField ? st.get("FWIT", 0.0) : st.get_group_var(gname, "GWIT", 0.0); values[Ix::GasInj] = isField ? st.get("FGIT", 0.0) : st.get_group_var(gname, "GGIT", 0.0); values[Ix::FluidResVolInj] = isField ? st.get("FVIT", 0.0) : st.get_group_var(gname, "GVIT", 0.0); this->outputCumulativeReportRecord_(values, names, {}); } for (const auto& wname : this->schedule_[reportStepNum].well_order()) { const auto& well = this->schedule_[reportStepNum].wells.get(wname); std::vector values(WellCumDataType::numWCValues); std::vector names(WellCumDataType::numWCNames); names[Ix::WellName] = wname; if (well.isInjector()) { const auto& controls = well.injectionControls(st); const auto ctlMode = controls.cmode; names[Ix::WellType] = "INJ"; if (ctlMode != Well::InjectorCMode::RATE) { names[Ix::WellCTRL] = injectorCModeToString(ctlMode); } else { const auto injType = controls.injector_type; if (injType == InjectorType::OIL) { names[Ix::WellCTRL] = "ORAT"; } else if (injType == InjectorType::WATER) { names[Ix::WellCTRL] = "WRAT"; } else if (injType == InjectorType::GAS) { names[Ix::WellCTRL] = "GRAT"; } } } else if (well.isProducer()) { const auto cmode = well.productionControls(st).cmode; names[Ix::WellType] = "PROD"; names[Ix::WellCTRL] = producerCModeToString(cmode); } values[Ix::WellLocationi] = well.getHeadI() + 1; values[Ix::WellLocationj] = well.getHeadJ() + 1; values[Ix::OilProd] = st.get_well_var(wname, "WOPT", 0.0); values[Ix::WaterProd] = st.get_well_var(wname, "WWPT", 0.0); values[Ix::GasProd] = st.get_well_var(wname, "WGPT", 0.0); values[Ix::FluidResVolProd] = st.get_well_var(wname, "WVPT", 0.0); values[Ix::OilInj] = st.get_well_var(wname, "WOIT", 0.0); values[Ix::WaterInj] = st.get_well_var(wname, "WWIT", 0.0); values[Ix::GasInj] = st.get_well_var(wname, "WGIT", 0.0); values[Ix::FluidResVolInj] = st.get_well_var(wname, "WVIT", 0.0); std::vector connData; if (withConns) { for (const auto& connection : well.getConnections()) { ConnData& conn = connData.emplace_back(connection); conn.data.resize(WellCumDataType::numWCValues); const auto gindex = connection.global_index() + 1; conn.data[Ix::OilProd] = conn_value_or_zero(st, wname, "COPT", gindex); conn.data[Ix::WaterProd] = conn_value_or_zero(st, wname, "CWPT", gindex); conn.data[Ix::GasProd] = conn_value_or_zero(st, wname, "CGPT", gindex); conn.data[Ix::FluidResVolProd] = conn_value_or_zero(st, wname, "CVPT", gindex); conn.data[Ix::OilInj] = conn_value_or_zero(st, wname, "COIT", gindex); conn.data[Ix::WaterInj] = conn_value_or_zero(st, wname, "CWIT", gindex); conn.data[Ix::GasInj] = conn_value_or_zero(st, wname, "CGIT", gindex); conn.data[Ix::FluidResVolInj] = conn_value_or_zero(st, wname, "CVIT", gindex); } } this->outputCumulativeReportRecord_(values, names, connData); } this->endCumulativeReport_(); } template void LogOutputHelper:: error(const std::vector& failedCellsPbub, const std::vector& failedCellsPdew) const { auto ijkString = [this](const std::size_t globalIndex) { const auto ijk = this->eclState_.gridDims().getIJK(globalIndex); return fmt::format("({},{},{})", ijk[0] + 1, ijk[1] + 1, ijk[2] + 1); }; constexpr auto maxNumCellsFaillog = static_cast(20); logUniqueFailedCells("Bubble point numerical problem", "Finding the bubble point pressure", maxNumCellsFaillog, failedCellsPbub, ijkString); logUniqueFailedCells("Dew point numerical problem", "Finding the dew point pressure", maxNumCellsFaillog, failedCellsPdew, ijkString); } template void LogOutputHelper:: fip(const Inplace& inplace, const Inplace& initialInplace, const std::string& name) const { auto iget = [&name](const Inplace& ip, Inplace::Phase phase, std::size_t idx) { if (name.empty()) { return ip.get(phase); } return ip.get(name, phase, idx); }; for (std::size_t reg = 1; reg <= (name.empty() ? 1 : inplace.max_region(name)); ++reg) { std::unordered_map initial_values; std::unordered_map current_values; for (const auto& phase : Inplace::phases()) { initial_values[phase] = iget(initialInplace, phase, reg); current_values[phase] = iget(inplace, phase, reg); } current_values[Inplace::Phase::DynamicPoreVolume] = iget(inplace, Inplace::Phase::DynamicPoreVolume, reg); this->fipUnitConvert_(initial_values); this->fipUnitConvert_(current_values); Scalar regHydroCarbonPoreVolumeAveragedPressure = detail::pressureAverage(iget(inplace, Inplace::Phase::PressureHydroCarbonPV, reg), iget(inplace, Inplace::Phase::HydroCarbonPV, reg), iget(inplace, Inplace::Phase::PressurePV, reg), iget(inplace, Inplace::Phase::DynamicPoreVolume, reg), true); this->pressureUnitConvert_(regHydroCarbonPoreVolumeAveragedPressure); this->outputRegionFluidInPlace_(std::move(initial_values), std::move(current_values), regHydroCarbonPoreVolumeAveragedPressure, name, name.empty() ? 0 : reg); } } template void LogOutputHelper:: fipResv(const Inplace& inplace, const std::string& name) const { { std::unordered_map current_values; for (const auto& phase : Inplace::phases()) { current_values[phase] = inplace.get(phase); } Scalar field_dyn_pv = 0.0; for (auto nreg = inplace.max_region(name), reg = 0*nreg + 1; reg <= nreg; ++reg) { field_dyn_pv = field_dyn_pv + inplace.get(name, Inplace::Phase::DynamicPoreVolume, reg); } current_values[Inplace::Phase::DynamicPoreVolume] = field_dyn_pv; this->fipUnitConvert_(current_values); this->outputResvFluidInPlace_(current_values, 0); } for (auto nreg = inplace.max_region(), reg = 0*nreg + 1; reg <= nreg; ++reg) { std::unordered_map current_values; for (const auto& phase : Inplace::phases()) { if (reg <= inplace.max_region(name)) { current_values[phase] = inplace.get(name, phase, reg); } else { current_values[phase] = 0.0; } } if (reg <= inplace.max_region(name)) { current_values[Inplace::Phase::DynamicPoreVolume] = inplace.get(name, Inplace::Phase::DynamicPoreVolume, reg); } else { current_values[Inplace::Phase::DynamicPoreVolume] = 0.0; } this->fipUnitConvert_(current_values); this->outputResvFluidInPlace_(current_values, reg); } OpmLog::note(fmt::format(" {:=^91}", "")); } template void LogOutputHelper:: csv_header(std::ostringstream& ss) const { ss << "RegName,RegNum" << ",OilLiquid,OilVapour,Oil,GasFree,GasDissolved,Gas,Water" << ",TotalPoreVolume,PoreVolumeOil,PoreVolumeWater,PoreVolumeGas,PoreVolumeHC" << "\n"; } template void LogOutputHelper:: fip_csv(std::ostringstream& ss, const Inplace& initial_inplace, const std::string& name) const { for (size_t n = 0; n < initial_inplace.max_region(name); n++) { ss << name << "," << n+1 << fmt::format(",{:4.2f}", initial_inplace.get(name, Inplace::Phase::OilInLiquidPhase, n+1)) << fmt::format(",{:4.2f}", initial_inplace.get(name, Inplace::Phase::OilInGasPhase, n+1)) << fmt::format(",{:4.2f}", initial_inplace.get(name, Inplace::Phase::OIL, n+1)) << fmt::format(",{:4.2f}", initial_inplace.get(name, Inplace::Phase::GasInGasPhase, n+1)) << fmt::format(",{:4.2f}", initial_inplace.get(name, Inplace::Phase::GasInLiquidPhase, n+1)) << fmt::format(",{:4.2f}", initial_inplace.get(name, Inplace::Phase::GAS, n+1)) << fmt::format(",{:4.2f}", initial_inplace.get(name, Inplace::Phase::WATER, n+1)) << fmt::format(",{:4.2f}", initial_inplace.get(name, Inplace::Phase::DynamicPoreVolume, n+1)) << fmt::format(",{:4.2f}", initial_inplace.get(name, Inplace::Phase::OilResVolume, n+1)) << fmt::format(",{:4.2f}", initial_inplace.get(name, Inplace::Phase::WaterResVolume, n+1)) << fmt::format(",{:4.2f}", initial_inplace.get(name, Inplace::Phase::GasResVolume, n+1)); auto hvpv = initial_inplace.get(name, Inplace::Phase::OilResVolume, n+1) + initial_inplace.get(name, Inplace::Phase::GasResVolume, n+1); ss << fmt::format(",{:4.2f}", hvpv) << "\n"; } } template void LogOutputHelper:: timeStamp(const std::string& lbl, double elapsed, int rstep, boost::posix_time::ptime currentDate) const { std::ostringstream ss; boost::posix_time::time_facet* facet = new boost::posix_time::time_facet("%d %b %Y"); ss.imbue(std::locale(std::locale::classic(), facet)); ss << "\n **************************************************************************\n" << " " << std::left << std::setw(9) << lbl << "AT" << std::right << std::setw(10) << (double)unit::convert::to(elapsed, unit::day) << " DAYS" << " *" << std::setw(30) << eclState_.getTitle() << " *\n" << " REPORT " << std::setw(4) << rstep << " " << currentDate << " * Flow version " << std::setw(11) << flowVersionName_ << " *\n" << " **************************************************************************\n"; OpmLog::note(ss.str()); } template void LogOutputHelper:: injection(const std::size_t reportStepNum, const std::map, double>& block_pressures) const { this->beginInjectionReport_(); using Ix = typename WellInjDataType::WIId; const auto& st = this->summaryState_; for (const auto& gname : this->schedule_.groupNames()) { std::vector values(WellInjDataType::numWIValues); std::vector names(WellInjDataType::numWINames); names[Ix::WellName] = gname; const auto isField = gname == "FIELD"; values[Ix::OilRate] = isField ? st.get("FOIR", 0.0) : st.get_group_var(gname, "GOIR", 0.0); values[Ix::WaterRate] = isField ? st.get("FWIR", 0.0) : st.get_group_var(gname, "GWIR", 0.0); values[Ix::GasRate] = isField ? st.get("FGIR", 0.0) : st.get_group_var(gname, "GGIR", 0.0); values[Ix::FluidResVol] = isField ? st.get("FVIR", 0.0) : st.get_group_var(gname, "GVIR", 0.0); this->outputInjectionReportRecord_(values, names, {}); } for (const auto& wname : this->schedule_[reportStepNum].well_order()) { const auto& well = this->schedule_[reportStepNum].wells.get(wname); // Ignore production wells for the injection report. if (well.isProducer()) { continue; } std::vector values(WellInjDataType::numWIValues); std::vector names(WellInjDataType::numWINames); names[Ix::WellName] = wname; const auto& controls = well.injectionControls(st); const auto ctlMode = controls.cmode; const auto injType = controls.injector_type; const auto isRate = ctlMode == Well::InjectorCMode::RATE; if (injType == InjectorType::OIL) { names[Ix::CTRLModeOil] = isRate ? "ORAT" : injectorCModeToString(ctlMode); } else if (injType == InjectorType::WATER) { names[Ix::CTRLModeWat] = isRate ? "WRAT" : injectorCModeToString(ctlMode); } else if (injType == InjectorType::GAS) { names[Ix::CTRLModeGas] = isRate ? "GRAT" : injectorCModeToString(ctlMode); } values[Ix::WellLocationi] = well.getHeadI() + 1; values[Ix::WellLocationj] = well.getHeadJ() + 1; values[Ix::OilRate] = st.get_well_var(wname, "WOIR", 0.0); values[Ix::WaterRate] = st.get_well_var(wname, "WWIR", 0.0); values[Ix::GasRate] = st.get_well_var(wname, "WGIR", 0.0); values[Ix::FluidResVol] = st.get_well_var(wname, "WVIR", 0.0); values[Ix::BHP] = st.get_well_var(wname, "WBHP", 0.0); values[Ix::THP] = st.get_well_var(wname, "WTHP", 0.0); // values[Ix::SteadyStateII] = 0; std::vector connData; if (!block_pressures.empty()) { const auto& units = this->eclState_.getUnits(); for (const auto& connection : well.getConnections()) { const auto gindex = connection.global_index() + 1; const auto bpr_it = block_pressures.find({"BPR", gindex}); const auto bpr = bpr_it == block_pressures.end() ? 0.0 : units.from_si(UnitSystem::measure::pressure, bpr_it->second); ConnData& conn = connData.emplace_back(connection); conn.data.resize(WellInjDataType::numWIValues); conn.data[Ix::OilRate] = conn_value_or_zero(st, wname, "COIR", gindex); conn.data[Ix::WaterRate] = conn_value_or_zero(st, wname, "CWIR", gindex); conn.data[Ix::GasRate] = conn_value_or_zero(st, wname, "CGIR", gindex); conn.data[Ix::FluidResVol] = conn_value_or_zero(st, wname, "CVIR", gindex); conn.data[Ix::CPR] = conn_value_or_zero(st, wname, "CPR", gindex); conn.data[Ix::BPR] = bpr; } } this->outputInjectionReportRecord_(values, names, connData); } this->endInjectionReport_(); } template void LogOutputHelper:: msw(const std::size_t reportStepNum) const { const auto& sched = this->schedule_[reportStepNum]; auto msWells = std::vector>{}; for (const auto& wname : sched.well_order()) { if (const auto& well = sched.wells.get(wname); well.isMultiSegment()) { msWells.push_back(std::cref(well)); } } if (msWells.empty()) { return; } this->beginMSWReport_(); std::for_each(msWells.begin(), msWells.end(), [this](const Well& well) { this->outputMSWReportRecord_(well); }); this->endMSWReport_(); } template void LogOutputHelper:: production(const std::size_t reportStepNum, const std::map,double>& block_pressures) const { this->beginProductionReport_(); using Ix = typename WellProdDataType::WPId; const auto& st = this->summaryState_; for (const auto& gname : this->schedule_.groupNames()) { std::vector values(WellProdDataType::numWPValues); std::vector names(WellProdDataType::numWPNames); names[0] = gname; const auto isField = gname == "FIELD"; values[Ix::OilRate] = isField ? st.get("FOPR", 0.0) : st.get_group_var(gname, "GOPR", 0.0); values[Ix::WaterRate] = isField ? st.get("FWPR", 0.0) : st.get_group_var(gname, "GWPR", 0.0); values[Ix::GasRate] = isField ? st.get("FGPR", 0.0) : st.get_group_var(gname, "GGPR", 0.0); values[Ix::FluidResVol] = isField ? st.get("FVPR", 0.0) : st.get_group_var(gname, "GVPR", 0.0); values[Ix::WaterCut] = isField ? st.get("FWCT", 0.0) : st.get_group_var(gname, "GWCT", 0.0); values[Ix::GasOilRatio] = isField ? st.get("FGOR", 0.0) : st.get_group_var(gname, "GGOR", 0.0); if (values[Ix::WaterRate] == 0.0) { values[Ix::WatGasRatio] = 0; } else if (values[Ix::GasRate] != 0.0) { values[Ix::WatGasRatio] = values[Ix::WaterRate] / values[Ix::GasRate]; } else { values[Ix::WatGasRatio] = 0.0; } this->outputProductionReportRecord_(values, names, {}); } for (const auto& wname : this->schedule_[reportStepNum].well_order()) { const auto& well = this->schedule_[reportStepNum].wells.get(wname); // Ignore injection wells for the production report. if (well.isInjector()) { continue; } std::vector values(WellProdDataType::numWPValues); std::vector names(WellProdDataType::numWPNames); names[Ix::WellName] = wname; names[Ix::CTRLMode] = producerCModeToString(well.productionControls(st).cmode); values[Ix::WellLocationi] = well.getHeadI() + 1; values[Ix::WellLocationj] = well.getHeadJ() + 1; values[Ix::OilRate] = st.get_well_var(wname, "WOPR", 0.0); values[Ix::WaterRate] = st.get_well_var(wname, "WWPR", 0.0); values[Ix::GasRate] = st.get_well_var(wname, "WGPR", 0.0); values[Ix::FluidResVol] = st.get_well_var(wname, "WVPR", 0.0); values[Ix::WaterCut] = st.get_well_var(wname, "WWCT", 0.0); values[Ix::GasOilRatio] = st.get_well_var(wname, "WGOR", 0.0); values[Ix::BHP] = st.get_well_var(wname, "WBHP", 0.0); values[Ix::THP] = st.get_well_var(wname, "WTHP", 0.0); // values[Ix::SteadyStatePI] = 0; auto calc_vat_rate = [](auto& v) { if (v[Ix::WaterRate] == 0.0) { v[Ix::WatGasRatio] = 0.0; } else if (v[Ix::GasRate] != 0.0) { v[Ix::WatGasRatio] = v[Ix::WaterRate] / v[Ix::GasRate]; } else { v[Ix::WatGasRatio] = 0.0; } }; calc_vat_rate(values); std::vector connData; if (!block_pressures.empty()) { const auto& units = this->eclState_.getUnits(); for (const auto& connection : well.getConnections()) { const auto gindex = connection.global_index() + 1; const auto bpr_it = block_pressures.find({"BPR", gindex}); const auto bpr = bpr_it == block_pressures.end() ? 0.0 : units.from_si(UnitSystem::measure::pressure, bpr_it->second); ConnData& conn = connData.emplace_back(connection); conn.data.resize(WellProdDataType::numWPValues); conn.data[Ix::OilRate] = conn_value_or_zero(st, wname, "COPR", gindex); conn.data[Ix::WaterRate] = conn_value_or_zero(st, wname, "CWPR", gindex); conn.data[Ix::GasRate] = conn_value_or_zero(st, wname, "CGPR", gindex); conn.data[Ix::FluidResVol] = conn_value_or_zero(st, wname, "CVPR", gindex); conn.data[Ix::WaterCut] = conn_value_or_zero(st, wname, "CWCT", gindex); conn.data[Ix::GasOilRatio] = conn_value_or_zero(st, wname, "CGOR", gindex); conn.data[Ix::CPR] = conn_value_or_zero(st, wname, "CPR", gindex); conn.data[Ix::BPR] = bpr; calc_vat_rate(conn.data); } } this->outputProductionReportRecord_(values, names, connData); } this->endProductionReport_(); } template void LogOutputHelper:: wellSpecification(const std::vector& changedWells, const bool changedWellLists, const std::size_t reportStepNum) const { std::ostringstream ss; auto blockDepth = PrtFile::Reports::BlockDepthCallback { [&grid = this->eclState_.getInputGrid()] (const std::size_t globalCellIndex) { return grid.getCellDepth(globalCellIndex); } }; PrtFile::Reports::wellSpecification(changedWells, changedWellLists, reportStepNum, this->schedule_, blockDepth, ss); OpmLog::note(ss.str()); } template void LogOutputHelper::beginCumulativeReport_() const { const auto& units = this->eclState_.getUnits(); const auto widths = std::array{8, 11, 8, 4, 11, 11, 11, 11, 11, 11, 11, 11}; using namespace std::string_view_literals; auto oil_unit = [utype = units.getType()]() { switch (utype) { case UnitSystem::UnitType::UNIT_TYPE_METRIC: return "MSCM"sv; case UnitSystem::UnitType::UNIT_TYPE_FIELD: return "MSTB"sv; case UnitSystem::UnitType::UNIT_TYPE_LAB: return "MSCC"sv; default: return "unsupp"sv; } }; auto wat_unit = [utype = units.getType()]() { switch (utype) { case UnitSystem::UnitType::UNIT_TYPE_METRIC: return "MSCM"sv; case UnitSystem::UnitType::UNIT_TYPE_FIELD: return "MSTB"sv; case UnitSystem::UnitType::UNIT_TYPE_LAB: return "MSCC"sv; default: return "unsupp"sv; } }; auto gas_unit = [utype = units.getType()]() { switch (utype) { case UnitSystem::UnitType::UNIT_TYPE_METRIC: return "MMSCM"sv; case UnitSystem::UnitType::UNIT_TYPE_FIELD: return "MMSCF"sv; case UnitSystem::UnitType::UNIT_TYPE_LAB: return "MMSCC"sv; default: return "unsupp"sv; } }; auto res_unit = [utype = units.getType()]() { switch (utype) { case UnitSystem::UnitType::UNIT_TYPE_METRIC: return "MRCM"sv; case UnitSystem::UnitType::UNIT_TYPE_FIELD: return "MRB"sv; case UnitSystem::UnitType::UNIT_TYPE_LAB: return "MRCC"sv; default: return "unsupp"sv; } }; const auto unitStrings = std::array{ ""sv, ""sv, ""sv, ""sv, oil_unit(), wat_unit(), gas_unit(), res_unit(), oil_unit(), wat_unit(), gas_unit(), res_unit(), }; std::ostringstream ss; ss << fmt::format("\n{:=^132}\n", " CUMULATIVE PRODUCTION/INJECTION TOTALS ") << formatTextRow(widths, std::array{ "WELL"sv, "LOCATION"sv, "WELL"sv, "CTRL"sv, "OIL"sv, "WATER"sv, "GAS"sv, "Prod"sv, "OIL"sv, "WATER"sv, "GAS"sv, "INJ"sv, }) << formatTextRow(widths, std::array{ "NAME"sv, "(I,J,K)"sv, "TYPE"sv, "MODE"sv, "PROD"sv, "PROD"sv, "PROD"sv, "RES.VOL."sv, "INJ"sv, "INJ"sv, "INJ"sv, "RES.VOL."sv, }) << formatTextRow(widths, unitStrings) << fmt::format("{:=>132}", ""); OpmLog::note(ss.str()); } template void LogOutputHelper::endCumulativeReport_() const { const auto widths = std::array{8, 11, 8, 4, 11, 11, 11, 11, 11, 11, 11, 11}; OpmLog::note(formatBorder(widths)); } template void LogOutputHelper:: outputCumulativeReportRecord_(const std::vector& wellCum, const std::vector& wellCumNames, const std::vector& connData) const { std::ostringstream ss; ss << fmt::format(":{:<8}:", wellCumNames[WellCumDataType::WellName]); if (wellCum[WellCumDataType::WellLocationi] < 1) { ss << fmt::format("{:11}:", ""); } else { ss << fmt::format("{:>3},{:>3} {:>3}:", wellCum[WellCumDataType::WellLocationi], wellCum[WellCumDataType::WellLocationj], ""); } auto scaledValue = [](const auto& wc, const auto quantity) { // Unit M* return wc[quantity] / 1000.0; }; auto scaledGasValue = [](const auto& wc, const auto quantity) { // Unit MM* return wc[quantity] / (1000.0 * 1000.0); }; ss << fmt::format("{:>8}:{:>4}:{:>11.1f}:{:>11.1f}:{:>11.1f}:{:>11.1f}:" "{:>11.1f}:{:>11.1f}:{:>11.1f}:{:>11.1f}:", wellCumNames[WellCumDataType::WCId::WellType], wellCumNames[WellCumDataType::WCId::WellCTRL], scaledValue(wellCum, WellCumDataType::WCId::OilProd), scaledValue(wellCum, WellCumDataType::WCId::WaterProd), scaledGasValue(wellCum, WellCumDataType::WCId::GasProd), scaledValue(wellCum, WellCumDataType::WCId::FluidResVolProd), scaledValue(wellCum, WellCumDataType::WCId::OilInj), scaledValue(wellCum, WellCumDataType::WCId::WaterInj), scaledGasValue(wellCum, WellCumDataType::WCId::GasInj), scaledValue(wellCum, WellCumDataType::WCId::FluidResVolInj)); for (const auto& conn : connData) { ss << fmt::format("\n: BLOCK :{0:>3},{1:>3},{2:>3}:{3:>8}:{3:>4}:", conn.I, conn.J, conn.K, "") << fmt::format("{:>11.1f}:{:>11.1f}:{:>11.1f}:{:>11.1f}:" "{:>11.1f}:{:>11.1f}:{:>11.1f}:{:>11.1f}:", scaledValue(conn.data, WellCumDataType::WCId::OilProd), scaledValue(conn.data, WellCumDataType::WCId::WaterProd), scaledGasValue(conn.data, WellCumDataType::WCId::GasProd), scaledValue(conn.data, WellCumDataType::WCId::FluidResVolProd), scaledValue(conn.data, WellCumDataType::WCId::OilInj), scaledValue(conn.data, WellCumDataType::WCId::WaterInj), scaledGasValue(conn.data, WellCumDataType::WCId::GasInj), scaledValue(conn.data, WellCumDataType::WCId::FluidResVolInj)); } OpmLog::note(ss.str()); } template void LogOutputHelper::beginInjectionReport_() const { const auto& units = this->eclState_.getUnits(); const auto widths = std::array{8, 11, 6, 6, 6, 11, 11, 11, 11, 8, 8}; using namespace std::string_view_literals; auto oil_rate = [utype = units.getType()]() { switch (utype) { case UnitSystem::UnitType::UNIT_TYPE_METRIC: return "SCM/DAY"sv; case UnitSystem::UnitType::UNIT_TYPE_FIELD: return "STB/DAY"sv; case UnitSystem::UnitType::UNIT_TYPE_LAB: return "SCC/HR"sv; default: return "unsupp"sv; } }; auto wat_rate = [utype = units.getType()]() { switch (utype) { case UnitSystem::UnitType::UNIT_TYPE_METRIC: return "SCM/DAY"sv; case UnitSystem::UnitType::UNIT_TYPE_FIELD: return "STB/DAY"sv; case UnitSystem::UnitType::UNIT_TYPE_LAB: return "SCC/HR"sv; default: return "unsupp"sv; } }; auto gas_rate = [utype = units.getType()]() { switch (utype) { case UnitSystem::UnitType::UNIT_TYPE_METRIC: return "SCM/DAY"sv; case UnitSystem::UnitType::UNIT_TYPE_FIELD: return "MSCF/DAY"sv; case UnitSystem::UnitType::UNIT_TYPE_LAB: return "SCC/HR"sv; default: return "unsupp"sv; } }; auto res_vol = [utype = units.getType()]() { switch (utype) { case UnitSystem::UnitType::UNIT_TYPE_METRIC: return "RCM/DAY"sv; case UnitSystem::UnitType::UNIT_TYPE_FIELD: return "RB/DAY"sv; case UnitSystem::UnitType::UNIT_TYPE_LAB: return "RCC/HR"sv; default: return "unsupp"sv; } }; const auto unitStrings = std::array{ ""sv, ""sv, "OIL"sv, "WAT"sv, "GAS"sv, oil_rate(), wat_rate(), gas_rate(), res_vol(), std::string_view{units.name(UnitSystem::measure::pressure)}, std::string_view{units.name(UnitSystem::measure::pressure)}, }; std::ostringstream ss; ss << fmt::format("\n{:=^109}\n", " INJECTION REPORT ") << formatTextRow(widths, std::array{ "WELL"sv, "LOCATION"sv, "CTRL"sv, "CTRL"sv, "CTRL"sv, "OIL"sv, "WATER"sv, "GAS"sv, "FLUID"sv, "BHP OR"sv, "THP OR"sv, }) << formatTextRow(widths, std::array{ "NAME"sv, "(I,J,K)"sv, "MODE"sv, "MODE"sv, "MODE"sv, "RATE"sv, "RATE"sv, "RATE"sv, "RES.VOL."sv, "CON.PR."sv, "BLK.PR."sv, }) << formatTextRow(widths, unitStrings) << fmt::format("{:=>109}", ""); OpmLog::note(ss.str()); } template void LogOutputHelper::endInjectionReport_() const { const auto widths = std::array{8, 11, 6, 6, 6, 11, 11, 11, 11, 8, 8}; OpmLog::note(formatBorder(widths)); } template void LogOutputHelper:: outputInjectionReportRecord_(const std::vector& wellInj, const std::vector& wellInjNames, const std::vector& connData) const { const auto isWellRecord = wellInj[WellProdDataType::WellLocationi] >= 1; std::ostringstream ss; ss << fmt::format(":{:<8}:", wellInjNames[WellInjDataType::WellName]); if (! isWellRecord) { ss << fmt::format("{:11}:", ""); } else { ss << fmt::format("{:>3},{:>3} {:>3}:", wellInj[WellInjDataType::WellLocationi], wellInj[WellInjDataType::WellLocationj], ""); } ss << fmt::format("{:>6}:{:>6}:{:>6}:{:>11.1f}:{:>11.1f}:{:>11.1f}:{:>11.1f}:", wellInjNames[WellInjDataType::CTRLModeOil], wellInjNames[WellInjDataType::CTRLModeWat], wellInjNames[WellInjDataType::CTRLModeGas], wellInj[WellInjDataType::OilRate], wellInj[WellInjDataType::WaterRate], wellInj[WellInjDataType::GasRate], wellInj[WellInjDataType::FluidResVol]); if (! isWellRecord) { ss << fmt::format("{0:8}:{0:8}:", ""); } else { ss << fmt::format("{:>8.1f}:{:>8.1f}:", wellInj[WellInjDataType::BHP], wellInj[WellInjDataType::THP]); } for (const auto& conn : connData) { ss << fmt::format("\n: BLOCK :{0:>3},{1:>3},{2:>3}:" "{3:>6}:{3:>6}:{3:>6}:", conn.I, conn.J, conn.K, "") << fmt::format("{:>11.1f}:{:>11.1f}:{:>11.1f}:{:>11.1f}:{:>8.1f}:{:>8.1f}:", conn.data[WellInjDataType::OilRate], conn.data[WellInjDataType::WaterRate], conn.data[WellInjDataType::GasRate], conn.data[WellInjDataType::FluidResVol], conn.data[WellInjDataType::CPR], conn.data[WellInjDataType::BPR]); } OpmLog::note(ss.str()); } template void LogOutputHelper::beginMSWReport_() const { const auto& units = this->eclState_.getUnits(); const auto widths = std::array{10, 5, 5, 11, 11, 11, 9, 16, 9, 8, 8, 8}; const auto widths2 = std::array{10, 5, 5, 11, 11, 11, 9, 16, 9, 26}; using namespace std::string_view_literals; std::ostringstream ss; ss << fmt::format("\n{:=^124}\n", " MULTI-SEGMENT WELL REPORT ") << formatTextRow(widths2, std::array{ "WELL"sv, "BRN"sv, "SEG"sv, "OIL"sv, "WATER"sv, "GAS"sv, "MIXTURE"sv, "HOLDUP FRACTION"sv, "PRESSURE"sv, "PRESSURE HEAD LOSSES"sv, }) << formatTextRow(widths, std::array{ "NAME"sv, "NO."sv, "NO."sv, "FLOW"sv, "FLOW"sv, "FLOW"sv, "VELOCITY"sv, "OIL WAT GAS"sv, ""sv, "H-STATIC"sv, "FRICTION"sv, "ACCELRTN"sv, }) << formatTextRow(widths, std::array{ ""sv, ""sv, ""sv, std::string_view{units.name(UnitSystem::measure::liquid_surface_rate)}, std::string_view{units.name(UnitSystem::measure::liquid_surface_rate)}, std::string_view{units.name(UnitSystem::measure::gas_surface_rate)}, std::string_view{units.name(UnitSystem::measure::pipeflow_velocity)}, ""sv, std::string_view{units.name(UnitSystem::measure::pressure)}, std::string_view{units.name(UnitSystem::measure::pressure_drop)}, std::string_view{units.name(UnitSystem::measure::pressure_drop)}, std::string_view{units.name(UnitSystem::measure::pressure_drop)}, }) << fmt::format("{:=>124}", ""); OpmLog::note(ss.str()); } template void LogOutputHelper::endMSWReport_() const { const auto widths = std::array{10, 5, 5, 11, 11, 11, 9, 16, 9, 8, 8, 8}; OpmLog::note(formatBorder(widths)); } template void LogOutputHelper:: outputMSWReportRecord_(const Well& well) const { const auto& st = this->summaryState_; using namespace std::string_view_literals; auto clampToZero = [](const auto& number) { return std::fabs(number) > 1e-6 ? number : 0.0; }; auto get_phase_values = [&st, &clampToZero, &wname = well.name()](const int segmentNumber, const std::array& fields) { std::array result; for (std::size_t p = 0; p < 3; ++p) { const auto value = st.has_segment_var(wname, std::string{fields[p]}, segmentNumber) ? st.get_segment_var(wname, std::string{fields[p]}, segmentNumber) : 0.0; result[p] = clampToZero(value); } return result; }; std::ostringstream ss; ss << fmt::format(": {:<9}:", well.name()); for (int i = 1; i <= well.maxBranchID(); ++i) { if (i != 1) { ss << fmt::format(": {:<9}:", ""); } ss << fmt::format("{:^5}:", i); const auto& segments = well.getSegments().branchSegments(i); bool first = true; for (const auto& segment : segments) { if (!first) { ss << fmt::format("\n:{0:>10}:{0:>5}:", ""); } const auto rates = get_phase_values(segment.segmentNumber(), std::array{"SOFR"sv, "SWFR"sv, "SGFR"sv}); const auto holdups = get_phase_values(segment.segmentNumber(), std::array{"SOHF"sv, "SWHF"sv, "SGHF"sv}); const auto velocities = get_phase_values(segment.segmentNumber(), std::array{"SOFV"sv, "SWFV"sv, "SGFV"sv}); const auto press_drop = get_phase_values(segment.segmentNumber(), std::array{"SPRDH"sv, "SPRDF"sv, "SPRDA"sv}); const auto mixture_vel = std::inner_product(holdups.begin(), holdups.end(), velocities.begin(), 0.0); ss << fmt::format("{:^5}:{:>11.1f}:{:>11.1f}:{:>11.1f}:{:>9.3f}:" " {:>3.2f} {:>3.2f} {:>3.2f} :" "{:>9.1f}:{:>8.3f}:{:>8.3f}:{:>8.3f}:", segment.segmentNumber(), rates[0], rates[1], rates[2], mixture_vel, holdups[0], holdups[1], holdups[2], clampToZero(st.has_segment_var(well.name(), "SPR", segment.segmentNumber()) ? st.get_segment_var(well.name(), "SPR", segment.segmentNumber()) : 0.0 ), press_drop[0], press_drop[1], press_drop[2]); first = false; } } OpmLog::note(ss.str()); } template void LogOutputHelper::beginProductionReport_() const { const auto& units = this->eclState_.getUnits(); const auto widths = std::array{8, 11, 4, 11, 11, 11, 11, 11, 10, 12, 8, 8}; using namespace std::string_view_literals; auto oil_rate = [utype = units.getType()]() { switch (utype) { case UnitSystem::UnitType::UNIT_TYPE_METRIC: return "SCM/DAY"sv; case UnitSystem::UnitType::UNIT_TYPE_FIELD: return "STB/DAY"sv; case UnitSystem::UnitType::UNIT_TYPE_LAB: return "SCC/HR"sv; default: return "unsupp"sv; } }; auto wat_rate = [utype = units.getType()]() { switch (utype) { case UnitSystem::UnitType::UNIT_TYPE_METRIC: return "SCM/DAY"sv; case UnitSystem::UnitType::UNIT_TYPE_FIELD: return "STB/DAY"sv; case UnitSystem::UnitType::UNIT_TYPE_LAB: return "SCC/HR"sv; default: return "unsupp"sv; } }; auto gas_rate = [utype = units.getType()]() { switch (utype) { case UnitSystem::UnitType::UNIT_TYPE_METRIC: return "RCM/DAY"sv; case UnitSystem::UnitType::UNIT_TYPE_FIELD: return "MSCF/DAY"sv; case UnitSystem::UnitType::UNIT_TYPE_LAB: return "RCC"sv; default: return "unsupp"sv; } }; auto res_vol = [utype = units.getType()]() { switch (utype) { case UnitSystem::UnitType::UNIT_TYPE_METRIC: return "SCM/SCM"sv; case UnitSystem::UnitType::UNIT_TYPE_FIELD: return "RB/DAY"sv; case UnitSystem::UnitType::UNIT_TYPE_LAB: return "SCC/SCC"sv; default: return "unsupp"sv; } }; auto water_cut = [utype = units.getType()]() { switch (utype) { case UnitSystem::UnitType::UNIT_TYPE_METRIC: return "SCM/SCM"sv; case UnitSystem::UnitType::UNIT_TYPE_FIELD: return ""sv; case UnitSystem::UnitType::UNIT_TYPE_LAB: return "SCC/SCC"sv; default: return "unsupp"sv; } }; auto gas_oil_rate = [utype = units.getType()]() { switch (utype) { case UnitSystem::UnitType::UNIT_TYPE_METRIC: return "SCM/SCM"sv; case UnitSystem::UnitType::UNIT_TYPE_FIELD: return "MSCF/STB"sv; case UnitSystem::UnitType::UNIT_TYPE_LAB: return "SCC/SCC"sv; default: return "unsupp"sv; } }; auto wat_gas_rate = [utype = units.getType()]() { switch (utype) { case UnitSystem::UnitType::UNIT_TYPE_METRIC: return "SCM/SCM"sv; case UnitSystem::UnitType::UNIT_TYPE_FIELD: return "STB/MSCF"sv; case UnitSystem::UnitType::UNIT_TYPE_LAB: return "SCC/SCC"sv; default: return "unsupp"sv; } }; const auto unitStrings = std::array{ ""sv, ""sv, ""sv, oil_rate(), wat_rate(), gas_rate(), res_vol(), water_cut(), gas_oil_rate(), wat_gas_rate(), std::string_view{units.name(UnitSystem::measure::pressure)}, std::string_view{units.name(UnitSystem::measure::pressure)}, }; std::ostringstream ss; ss << fmt::format("\n{:=^129}\n", " PRODUCTION REPORT ") << formatTextRow(widths, std::array{ "WELL"sv, "LOCATION"sv, "CTRL"sv, "OIL"sv, "WATER"sv, "GAS"sv, "FLUID"sv, "WATER"sv, "GAS/OIL"sv, "WAT/GAS"sv, "BHP OR"sv, "THP OR"sv, }) << formatTextRow(widths, std::array{ "NAME"sv, "(I,J,K)"sv, "MODE"sv, "RATE"sv, "RATE"sv, "RATE"sv, "RES.VOL."sv, "CUT"sv, "RATIO"sv, "RATIO"sv, "CON.PR."sv, "BLK.PR."sv, }) << formatTextRow(widths, unitStrings) << fmt::format("{:=>129}", ""); OpmLog::note(ss.str()); } template void LogOutputHelper::endProductionReport_() const { const auto widths = std::array{8, 11, 4, 11, 11, 11, 11, 11, 10, 12, 8, 8}; OpmLog::note(formatBorder(widths)); } template void LogOutputHelper:: outputProductionReportRecord_(const std::vector& wellProd, const std::vector& wellProdNames, const std::vector& connData) const { const auto isWellRecord = wellProd[WellProdDataType::WellLocationi] >= 1; std::ostringstream ss; ss << fmt::format(":{:<8}:", wellProdNames[WellProdDataType::WellName]); if (! isWellRecord) { ss << fmt::format("{:11}:", ""); } else { ss << fmt::format("{:>3},{:>3} {:>3}:", wellProd[WellProdDataType::WellLocationi] , wellProd[WellProdDataType::WellLocationj], ""); } ss << fmt::format("{:>4}:{:>11.1f}:{:>11.1f}:{:>11.1f}:{:>11.1f}:{:>11.3f}:{:>10.2f}:{:>12.4f}:", wellProdNames[WellProdDataType::CTRLMode], wellProd[WellProdDataType::OilRate], wellProd[WellProdDataType::WaterRate], wellProd[WellProdDataType::GasRate], wellProd[WellProdDataType::FluidResVol], wellProd[WellProdDataType::WaterCut], wellProd[WellProdDataType::GasOilRatio], wellProd[WellProdDataType::WatGasRatio]); if (! isWellRecord) { ss << fmt::format("{0:8}:{0:8}:", ""); } else { ss << fmt::format("{:>8.1f}:{:>8.1f}:", wellProd[WellProdDataType::BHP], wellProd[WellProdDataType::THP]); } for (const auto& conn : connData) { ss << fmt::format("\n: BLOCK :{0:>3},{1:>3},{2:>3}:{3:>4}:", conn.I, conn.J, conn.K, "") << fmt::format("{:>11.1f}:{:>11.1f}:{:>11.1f}:{:>11.1f}:" "{:>11.3f}:{:>10.2f}:{:>12.4f}:{:>8.1f}:{:>8.1f}:", conn.data[WellProdDataType::OilRate], conn.data[WellProdDataType::WaterRate], conn.data[WellProdDataType::GasRate], conn.data[WellProdDataType::FluidResVol], conn.data[WellProdDataType::WaterCut], conn.data[WellProdDataType::GasOilRatio], conn.data[WellProdDataType::WatGasRatio], conn.data[WellProdDataType::CPR], conn.data[WellProdDataType::BPR]); } OpmLog::note(ss.str()); } template void LogOutputHelper:: outputRegionFluidInPlace_(std::unordered_map oip, std::unordered_map cip, const Scalar pav, const std::string& name, const int reg) const { // don't output FIPNUM report if the region has no porv. if (! (cip[Inplace::Phase::PoreVolume] > Scalar{0})) { return; } const UnitSystem& units = eclState_.getUnits(); const auto widths = std::array{25, 43, 16, 43}; auto topEntry = [&units](const char* text, const Scalar value, const UnitSystem::measure m) { return fmt::format(" {0: >52}:{0: >8}{1:<5}={2:>14.0f} {3:<18}:\n", "", text, value, units.name(m)); }; auto topLabel = [](const char* text) { return fmt::format(" {: >52}: {:^47}:\n", "", text); }; auto formatEntry = [](auto& fip, std::string_view label) { return fmt::format(" :{:<25}:{:^15.0f}{:^14.0f}{:^14.0f}:{:^16.0f}:" "{:^15.0f}{:^14.0f}{:^14.0f}:\n", label, fip[Inplace::Phase::OilInLiquidPhase], fip[Inplace::Phase::OilInGasPhase], fip[Inplace::Phase::OIL], fip[Inplace::Phase::WATER], fip[Inplace::Phase::GasInGasPhase], fip[Inplace::Phase::GasInLiquidPhase], fip[Inplace::Phase::GAS]); }; std::ostringstream ss; ss << fmt::format("\n {0: >52}{0:=>50}\n", ""); if (reg == 0) { ss << fmt::format(" {0: >52}:{1:^48}:\n", "", "FIELD TOTALS"); } else { ss << fmt::format(" {0: >52}:{1:>20} REPORT REGION {2:>{3}}{0: ^11}:\n", "", name, reg, 8 - name.size()); } ss << topEntry("PAV", pav, UnitSystem::measure::pressure) << topEntry("PORV", cip[Inplace::Phase::PoreVolume], UnitSystem::measure::volume); if (!reg) { ss << topLabel("Pressure is weighted by hydrocarbon pore volume") << topLabel("Pore volumes are taken at reference conditions"); } ss << fmt::format(" {0: >26}:{0:->15} OIL {1:>4} {0:->18}:" "-- WAT{0: >2} {1:>4} --:{0:->14} GAS{0: >3} {2:>4} {0:-^15}:\n", "", units.name(UnitSystem::measure::liquid_surface_volume), units.name(UnitSystem::measure::gas_surface_volume)) << fmt::format(" {0: >26}:{1:^15}{2:^14}{3:^14}:{3:^16}:{4:^15}{5:^14}{3:^14}:\n", "", "LIQUID", "VAPOUR", "TOTAL", "FREE", "DISSOLVED") << formatBorder(widths) << '\n' << formatEntry(cip, "CURRENTLY IN PLACE") << formatBorder(widths) << '\n' << formatEntry(oip, "ORIGINALLY IN PLACE"); if (reg != 0) { ss << formatBorder(widths) << '\n'; } ss << fmt::format(" {:=^132}\n\n", ""); OpmLog::note(ss.str()); } template void LogOutputHelper:: outputResvFluidInPlace_(std::unordered_map cipr, const int reg) const { const UnitSystem& units = eclState_.getUnits(); using namespace std::string_view_literals; std::ostringstream ss; if (reg == 0) { const auto widths = std::array{9, 15, 15, 15, 15, 15}; ss << fmt::format("\n {0: >52}{0:=>35}", "") << fmt::format("\n {0: >52}: RESERVOIR VOLUMES {1:^13}:\n", "", units.name(UnitSystem::measure::volume)) << formatBorder(widths) << '\n' << formatTextRow(widths, std::array{ "REGION"sv, "TOTAL PORE"sv, "PORE VOLUME"sv, "PORE VOLUME"sv, "PORE VOLUME"sv, "PORE VOLUME"sv, }) << formatTextRow(widths, std::array{ ""sv, "VOLUME"sv, "CONTAINING"sv, "CONTAINING"sv, "CONTAINING"sv, "CONTAINING"sv, }) << formatTextRow(widths, std::array{ ""sv, ""sv, "OIL"sv, "WATER"sv, "GAS"sv, "HYDRO-CARBON"sv, }) << formatBorder(widths) << '\n' << fmt::format(" :{:<9}:", "FIELD"); } else { ss << fmt::format(" :{:<9}:", reg); } ss << fmt::format("{0:>15.0f}:{1:>15.0f}:{2:>15.0f}:{3:>15.0f}:{4:>15.0f}:", cipr[Inplace::Phase::DynamicPoreVolume], cipr[Inplace::Phase::OilResVolume], cipr[Inplace::Phase::WaterResVolume], cipr[Inplace::Phase::GasResVolume], cipr[Inplace::Phase::OilResVolume] + cipr[Inplace::Phase::GasResVolume]); OpmLog::note(ss.str()); } template void LogOutputHelper:: fipUnitConvert_(std::unordered_map& fip) const { const UnitSystem& units = eclState_.getUnits(); using M = UnitSystem::measure; const auto unit_map = std::unordered_map { {Inplace::Phase::WATER, M::liquid_surface_volume}, {Inplace::Phase::OIL, M::liquid_surface_volume}, {Inplace::Phase::OilInLiquidPhase, M::liquid_surface_volume}, {Inplace::Phase::OilInGasPhase, M::liquid_surface_volume}, {Inplace::Phase::GAS, M::gas_surface_volume}, {Inplace::Phase::GasInLiquidPhase, M::gas_surface_volume}, {Inplace::Phase::GasInGasPhase, M::gas_surface_volume}, {Inplace::Phase::PoreVolume, M::volume}, {Inplace::Phase::DynamicPoreVolume, M::volume}, {Inplace::Phase::WaterResVolume, M::volume}, {Inplace::Phase::OilResVolume, M::volume}, {Inplace::Phase::GasResVolume, M::volume}, {Inplace::Phase::SALT, M::mass}, {Inplace::Phase::CO2InWaterPhase, M::moles}, {Inplace::Phase::CO2InGasPhaseInMob, M::moles}, {Inplace::Phase::CO2InGasPhaseMob, M::moles}, {Inplace::Phase::CO2InGasPhaseInMobKrg, M::moles}, {Inplace::Phase::CO2InGasPhaseMobKrg, M::moles}, {Inplace::Phase::WaterInWaterPhase, M::liquid_surface_volume}, {Inplace::Phase::WaterInGasPhase, M::liquid_surface_volume}, {Inplace::Phase::WaterMass, M::mass}, {Inplace::Phase::CO2Mass, M::mass}, {Inplace::Phase::CO2MassInWaterPhase, M::mass}, {Inplace::Phase::CO2MassInGasPhase, M::mass}, {Inplace::Phase::CO2MassInGasPhaseInMob, M::mass}, {Inplace::Phase::CO2MassInGasPhaseMob, M::mass}, {Inplace::Phase::CO2MassInGasPhaseInMobKrg, M::mass}, {Inplace::Phase::CO2MassInGasPhaseMobKrg, M::mass}, {Inplace::Phase::CO2MassInGasPhaseEffectiveTrapped, M::mass}, {Inplace::Phase::CO2MassInGasPhaseEffectiveUnTrapped, M::mass}, {Inplace::Phase::CO2MassInGasPhaseMaximumTrapped, M::mass}, {Inplace::Phase::CO2MassInGasPhaseMaximumUnTrapped, M::mass}, }; for (auto& [phase, value] : fip) { auto unitPos = unit_map.find(phase); if (unitPos != unit_map.end()) { value = units.from_si(unitPos->second, value); } } } template void LogOutputHelper:: pressureUnitConvert_(Scalar& pav) const { pav = eclState_.getUnits() .from_si(UnitSystem::measure::pressure, pav); } template class LogOutputHelper; #if FLOW_INSTANTIATE_FLOAT template class LogOutputHelper; #endif } // namespace Opm