From 59c8fb83d457904b5fe1f01b0e4a88e78066a17d Mon Sep 17 00:00:00 2001 From: Andreas Lauser Date: Thu, 26 Mar 2015 17:33:00 +0100 Subject: [PATCH 1/3] write out the cell temperature field I used "TEMP" as the name of the field of the UNRST files, but that is just a guess. (I don't have access to any results of a thermal run of the "It Defines The Truth (TM)" simulator.) --- opm/core/io/eclipse/EclipseWriter.cpp | 16 ++++++++++++++-- opm/core/io/eclipse/EclipseWriter.hpp | 2 ++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/opm/core/io/eclipse/EclipseWriter.cpp b/opm/core/io/eclipse/EclipseWriter.cpp index 3ba6d1bc..d4213ac8 100644 --- a/opm/core/io/eclipse/EclipseWriter.cpp +++ b/opm/core/io/eclipse/EclipseWriter.cpp @@ -95,10 +95,10 @@ void restrictAndReorderToActiveCells(std::vector &data, } // convert the units of an array -void convertFromSiTo(std::vector &siValues, double toSiConversionFactor) +void convertFromSiTo(std::vector &siValues, double toSiConversionFactor, double toSiOffset = 0) { for (size_t curIdx = 0; curIdx < siValues.size(); ++curIdx) { - siValues[curIdx] = unit::convert::to(siValues[curIdx], toSiConversionFactor); + siValues[curIdx] = unit::convert::to(siValues[curIdx] - toSiOffset, toSiConversionFactor); } } @@ -1149,6 +1149,12 @@ void EclipseWriter::writeTimeStep(const SimulatorTimerInterface& timer, sol.add(EclipseWriterDetails::Keyword("PRESSURE", pressure)); + // write the cell temperature + std::vector temperature = reservoirState.temperature(); + EclipseWriterDetails::convertFromSiTo(temperature, deckToSiTemperatureFactor_, deckToSiTemperatureOffset_); + EclipseWriterDetails::restrictAndReorderToActiveCells(temperature, gridToEclipseIdx_.size(), gridToEclipseIdx_.data()); + sol.add(EclipseWriterDetails::Keyword("TEMP", temperature)); + std::vector saturation_water; std::vector saturation_gas; @@ -1266,6 +1272,12 @@ EclipseWriter::EclipseWriter(const parameter::ParameterGroup& params, deckToSiPressure_ = eclipseState->getDeckUnitSystem()->parse("Pressure")->getSIScaling(); + // factor and offset from the temperature values given in the deck to Kelvin + deckToSiTemperatureFactor_ = + eclipseState->getDeckUnitSystem()->parse("Temperature")->getSIScaling(); + deckToSiTemperatureOffset_ = + eclipseState->getDeckUnitSystem()->parse("Temperature")->getSIOffset(); + init(params); } diff --git a/opm/core/io/eclipse/EclipseWriter.hpp b/opm/core/io/eclipse/EclipseWriter.hpp index 22670ee4..0c1e3d77 100644 --- a/opm/core/io/eclipse/EclipseWriter.hpp +++ b/opm/core/io/eclipse/EclipseWriter.hpp @@ -112,6 +112,8 @@ private: const int* compressedToCartesianCellIdx_; std::vector< int > gridToEclipseIdx_; double deckToSiPressure_; + double deckToSiTemperatureFactor_; + double deckToSiTemperatureOffset_; bool enableOutput_; int outputInterval_; int writeStepIdx_; From e03334a2f5a04f13a97e4ffdebe76592d661020f Mon Sep 17 00:00:00 2001 From: Andreas Lauser Date: Thu, 26 Mar 2015 17:33:02 +0100 Subject: [PATCH 2/3] use deck units for the summary output or more accurately: "use FIELD or METRIC units", LAB and PVT-M units are still unsupported, but they seem to be pretty exotic and are also not supported by opm-parser either... note that this patch requires an API change (with the usual consequences for all downstream modules which use this class) because the deck needs to be passed to EclipseWriter. If somebody knows a canonical way to get the names of the written units from EclipseState, this is API change is not required. --- opm/core/io/OutputWriter.cpp | 6 +- opm/core/io/OutputWriter.hpp | 2 + opm/core/io/eclipse/EclipseWriter.cpp | 131 +++++++++++++++++++++---- opm/core/io/eclipse/EclipseWriter.hpp | 2 + opm/core/simulator/SimulatorOutput.cpp | 3 +- opm/core/simulator/SimulatorOutput.hpp | 6 +- tests/test_EclipseWriteRFTHandler.cpp | 1 + tests/test_EclipseWriter.cpp | 1 + tests/test_writenumwells.cpp | 1 + 9 files changed, 133 insertions(+), 20 deletions(-) diff --git a/opm/core/io/OutputWriter.cpp b/opm/core/io/OutputWriter.cpp index 1431ad46..11b574bc 100644 --- a/opm/core/io/OutputWriter.cpp +++ b/opm/core/io/OutputWriter.cpp @@ -47,10 +47,12 @@ private: /// Psuedo-constructor, can appear in template template unique_ptr create (const ParameterGroup& params, + std::shared_ptr deck, std::shared_ptr eclipseState, const Opm::PhaseUsage &phaseUsage, std::shared_ptr grid) { return unique_ptr (new Format (params, + deck, eclipseState, phaseUsage, grid->number_of_cells, @@ -65,6 +67,7 @@ create (const ParameterGroup& params, /// to the list below! typedef map (*)( const ParameterGroup&, + std::shared_ptr deck, std::shared_ptr eclipseState, const Opm::PhaseUsage &phaseUsage, std::shared_ptr )> map_t; @@ -76,6 +79,7 @@ map_t FORMATS = { unique_ptr OutputWriter::create (const ParameterGroup& params, + std::shared_ptr deck, std::shared_ptr eclipseState, const Opm::PhaseUsage &phaseUsage, std::shared_ptr grid) { @@ -93,7 +97,7 @@ OutputWriter::create (const ParameterGroup& params, // invoke the constructor for the type if we found the keyword // and put the pointer to this writer onto the list if (params.getDefault (name, false)) { - list->push_front (it->second (params, eclipseState, phaseUsage, grid)); + list->push_front (it->second (params, deck, eclipseState, phaseUsage, grid)); } } diff --git a/opm/core/io/OutputWriter.hpp b/opm/core/io/OutputWriter.hpp index 27f4dd3b..ccfec23d 100644 --- a/opm/core/io/OutputWriter.hpp +++ b/opm/core/io/OutputWriter.hpp @@ -21,6 +21,7 @@ #define OPM_OUTPUT_WRITER_HPP #include // unique_ptr, shared_ptr +#include #include struct UnstructuredGrid; @@ -107,6 +108,7 @@ public: */ static std::unique_ptr create (const parameter::ParameterGroup& params, + std::shared_ptr deck, std::shared_ptr eclipseState, const Opm::PhaseUsage &phaseUsage, std::shared_ptr grid); diff --git a/opm/core/io/eclipse/EclipseWriter.cpp b/opm/core/io/eclipse/EclipseWriter.cpp index d4213ac8..86cfd99e 100644 --- a/opm/core/io/eclipse/EclipseWriter.cpp +++ b/opm/core/io/eclipse/EclipseWriter.cpp @@ -443,7 +443,8 @@ public: // on the classes defined in the following. // add rate variables for each of the well in the input file - void addAllWells(Opm::EclipseStateConstPtr eclipseState, + void addAllWells(Opm::DeckConstPtr deck, + Opm::EclipseStateConstPtr eclipseState, const PhaseUsage& uses); void writeTimeStep(int writeStepIdx, const SimulatorTimerInterface& timer, @@ -612,6 +613,8 @@ public: { return ertHandle_; } protected: + + void updateTimeStepWellIndex_(const std::map& nameToIdxMap) { const std::string& wellName = well_->name(); @@ -724,7 +727,8 @@ public: Opm::WellConstPtr well, PhaseUsage uses, BlackoilPhases::PhaseIndex phase, - WellType type) + WellType type, + bool useFieldUnits) : WellReport(summary, eclipseState, well, @@ -732,8 +736,9 @@ public: phase, type, 'R', - "SM3/DAY" /* surf. cub. m. per day */) - { } + handleUnit_(phase, useFieldUnits)) + { + } virtual double retrieveValue(const int /* writeStepIdx */, const SimulatorTimerInterface& timer, @@ -755,8 +760,40 @@ public: // TODO: Why only positive rates? using namespace Opm::unit; return convert::to(std::max(0., rate(wellState)), - cubic(meter)/day); + targetRateToSiConversionFactor_); } + +private: + const std::string handleUnit_(BlackoilPhases::PhaseIndex phase, bool useField) { + using namespace Opm::unit; + if (phase == BlackoilPhases::Liquid || phase == BlackoilPhases::Aqua) { + if (useField) { + unitName_ = "STB/DAY"; + targetRateToSiConversionFactor_ = stb/day; // m^3/s -> STB/day + } + else { + unitName_ = "SM3/DAY"; + targetRateToSiConversionFactor_ = cubic(meter)/day; // m^3/s -> m^3/day + } + } + else if (phase == BlackoilPhases::Vapour) { + if (useField) { + unitName_ = "MSCF/DAY"; + targetRateToSiConversionFactor_ = 1000*cubic(feet)/day; // m^3/s -> MSCF^3/day + } + else { + unitName_ = "SM3/DAY"; + targetRateToSiConversionFactor_ = cubic(meter)/day; // m^3/s -> m^3/day + } + } + else + OPM_THROW(std::logic_error, + "Unexpected phase " << phase); + return unitName_; + } + + const char* unitName_; + double targetRateToSiConversionFactor_; }; /// Monitors the total production in a well. @@ -768,7 +805,8 @@ public: Opm::WellConstPtr well, PhaseUsage uses, BlackoilPhases::PhaseIndex phase, - WellType type) + WellType type, + bool useFieldUnits) : WellReport(summary, eclipseState, well, @@ -776,7 +814,7 @@ public: phase, type, 'T', - "SM3" /* surface cubic meter */ ) + handleUnit_(phase, useFieldUnits)) // nothing produced when the reporting starts , total_(0.) { } @@ -812,10 +850,41 @@ public: // add this timesteps production to the total total_ += intg; // report the new production total - return total_; + return unit::convert::to(total_, targetRateToSiConversionFactor_); } private: + const std::string handleUnit_(BlackoilPhases::PhaseIndex phase, bool useField) { + using namespace Opm::unit; + if (phase == BlackoilPhases::Liquid || phase == BlackoilPhases::Aqua) { + if (useField) { + unitName_ = "STB/DAY"; + targetRateToSiConversionFactor_ = stb/day; // m^3/s -> STB/day + } + else { + unitName_ = "SM3/DAY"; + targetRateToSiConversionFactor_ = cubic(meter)/day; // m^3/s -> m^3/day + } + } + else if (phase == BlackoilPhases::Vapour) { + if (useField) { + unitName_ = "MSCF/DAY"; + targetRateToSiConversionFactor_ = 1000*cubic(feet)/day; // m^3/s -> MSCF^3/day + } + else { + unitName_ = "SM3/DAY"; + targetRateToSiConversionFactor_ = cubic(meter)/day; // m^3/s -> m^3/day + } + } + else + OPM_THROW(std::logic_error, + "Unexpected phase " << phase); + return unitName_; + } + + const char* unitName_; + double targetRateToSiConversionFactor_; + /// Aggregated value of the course of the simulation double total_; }; @@ -829,7 +898,8 @@ public: Opm::WellConstPtr well, PhaseUsage uses, BlackoilPhases::PhaseIndex phase, - WellType type) + WellType type, + bool useFieldUnits) : WellReport(summary, eclipseState, well, @@ -837,7 +907,7 @@ public: phase, type, 'B', - "Pascal") + handleUnit_(phase, useFieldUnits)) { } virtual double retrieveValue(const int /* writeStepIdx */, @@ -856,8 +926,27 @@ public: return 0.0; } - return bhp(wellState); + return unit::convert::to(bhp(wellState), targetRateToSiConversionFactor_); } + +private: + const std::string handleUnit_(BlackoilPhases::PhaseIndex phase, bool useField) { + using namespace Opm::unit; + + if (useField) { + unitName_ = "PSIA"; + targetRateToSiConversionFactor_ = psia; // Pa -> PSI + } + else { + unitName_ = "BARSA"; + targetRateToSiConversionFactor_ = barsa; // Pa -> bar + } + + return unitName_; + } + + const char* unitName_; + double targetRateToSiConversionFactor_; }; // no inline implementation of this since it depends on the @@ -891,10 +980,13 @@ void Summary::writeTimeStep(int writeStepIdx, ecl_sum_fwrite(ertHandle()); } -void Summary::addAllWells(Opm::EclipseStateConstPtr eclipseState, +void Summary::addAllWells(Opm::DeckConstPtr deck, + Opm::EclipseStateConstPtr eclipseState, const PhaseUsage& uses) { eclipseState_ = eclipseState; + bool useFieldUnits = !deck->hasKeyword("METRIC"); + // TODO: Only create report variables that are requested with keywords // (e.g. "WOPR") in the input files, and only for those wells that are // mentioned in those keywords @@ -919,7 +1011,8 @@ void Summary::addAllWells(Opm::EclipseStateConstPtr eclipseState, wells[wellIdx], uses, ertPhaseIdx, - wellType))); + wellType, + useFieldUnits))); // W{O,G,W}{I,P}T addWell(std::unique_ptr ( new WellTotal(*this, @@ -927,7 +1020,8 @@ void Summary::addAllWells(Opm::EclipseStateConstPtr eclipseState, wells[wellIdx], uses, ertPhaseIdx, - wellType))); + wellType, + useFieldUnits))); } } } @@ -949,7 +1043,8 @@ void Summary::addAllWells(Opm::EclipseStateConstPtr eclipseState, wells[wellIdx], uses, ertPhaseIdx, - WELL_TYPES[0]))); + WELL_TYPES[0], + useFieldUnits))); } } } // end namespace EclipseWriterDetails @@ -1064,7 +1159,7 @@ void EclipseWriter::writeInit(const SimulatorTimerInterface &timer) eclGrid->getNX(), eclGrid->getNY(), eclGrid->getNZ())); - summary_->addAllWells(eclipseState_, phaseUsage_); + summary_->addAllWells(deck_, eclipseState_, phaseUsage_); } // implementation of the writeTimeStep method @@ -1231,11 +1326,13 @@ void EclipseWriter::writeTimeStep(const SimulatorTimerInterface& timer, EclipseWriter::EclipseWriter(const parameter::ParameterGroup& params, + Opm::DeckConstPtr deck, Opm::EclipseStateConstPtr eclipseState, const Opm::PhaseUsage &phaseUsage, int numCells, const int* compressedToCartesianCellIdx) - : eclipseState_(eclipseState) + : deck_(deck) + , eclipseState_(eclipseState) , numCells_(numCells) , compressedToCartesianCellIdx_(compressedToCartesianCellIdx) , gridToEclipseIdx_(numCells, int(-1) ) diff --git a/opm/core/io/eclipse/EclipseWriter.hpp b/opm/core/io/eclipse/EclipseWriter.hpp index 0c1e3d77..7dd03e4c 100644 --- a/opm/core/io/eclipse/EclipseWriter.hpp +++ b/opm/core/io/eclipse/EclipseWriter.hpp @@ -65,6 +65,7 @@ public: * binary files using ERT. */ EclipseWriter(const parameter::ParameterGroup& params, + Opm::DeckConstPtr deck, Opm::EclipseStateConstPtr eclipseState, const Opm::PhaseUsage &phaseUsage, int numCells, @@ -106,6 +107,7 @@ public: static ert_ecl_unit_enum convertUnitTypeErtEclUnitEnum(UnitSystem::UnitType unit); private: + Opm::DeckConstPtr deck_; Opm::EclipseStateConstPtr eclipseState_; int numCells_; std::array cartesianSize_; diff --git a/opm/core/simulator/SimulatorOutput.cpp b/opm/core/simulator/SimulatorOutput.cpp index 40606c30..4e833b8d 100644 --- a/opm/core/simulator/SimulatorOutput.cpp +++ b/opm/core/simulator/SimulatorOutput.cpp @@ -30,6 +30,7 @@ using namespace Opm; SimulatorOutputBase::SimulatorOutputBase ( const parameter::ParameterGroup& params, + std::shared_ptr deck, std::shared_ptr eclipseState, const Opm::PhaseUsage &phaseUsage, std::shared_ptr grid, @@ -45,7 +46,7 @@ SimulatorOutputBase::SimulatorOutputBase ( // process parameters into a writer. we don't setup a new chain in // every timestep! - , writer_ (std::move (OutputWriter::create (params, eclipseState, phaseUsage, grid))) + , writer_ (std::move (OutputWriter::create (params, deck, eclipseState, phaseUsage, grid))) // always start from the first timestep , next_ (0) { diff --git a/opm/core/simulator/SimulatorOutput.hpp b/opm/core/simulator/SimulatorOutput.hpp index 6b0ce5a0..8b9acea7 100644 --- a/opm/core/simulator/SimulatorOutput.hpp +++ b/opm/core/simulator/SimulatorOutput.hpp @@ -56,6 +56,7 @@ protected: * need to pick them up from the object members. */ SimulatorOutputBase (const parameter::ParameterGroup& p, + std::shared_ptr deck, std::shared_ptr eclipseState, const Opm::PhaseUsage &phaseUsage, std::shared_ptr grid, @@ -145,6 +146,7 @@ private: template struct SimulatorOutput : public SimulatorOutputBase { SimulatorOutput (const parameter::ParameterGroup& params, + std::shared_ptr deck, std::shared_ptr eclipseState, const Opm::PhaseUsage &phaseUsage, std::shared_ptr grid, @@ -153,7 +155,7 @@ struct SimulatorOutput : public SimulatorOutputBase { std::shared_ptr wellState, std::shared_ptr sim) // send all other parameters to base class - : SimulatorOutputBase (params, eclipseState, phaseUsage, + : SimulatorOutputBase (params, deck, eclipseState, phaseUsage, grid, timer, state, wellState) // store reference to simulator in derived class @@ -169,6 +171,7 @@ struct SimulatorOutput : public SimulatorOutputBase { * the arguments passed exceeds the lifetime of this object. */ SimulatorOutput (const parameter::ParameterGroup& params, + const Deck& deck, const EclipseState& eclipseState, const Opm::PhaseUsage &phaseUsage, const UnstructuredGrid& grid, @@ -178,6 +181,7 @@ struct SimulatorOutput : public SimulatorOutputBase { Simulator& sim) // send all other parameters to base class : SimulatorOutputBase (params, + share_obj (deck), share_obj (eclipseState), phaseUsage, share_obj (grid), diff --git a/tests/test_EclipseWriteRFTHandler.cpp b/tests/test_EclipseWriteRFTHandler.cpp index d557574a..41eb18d3 100755 --- a/tests/test_EclipseWriteRFTHandler.cpp +++ b/tests/test_EclipseWriteRFTHandler.cpp @@ -136,6 +136,7 @@ std::shared_ptr createEclipseWriter(std::shared_ptrc_grid(); std::shared_ptr eclipseWriter = std::make_shared(params, + deck, eclipseState, phaseUsage, ourFinerUnstructuredGrid.number_of_cells, diff --git a/tests/test_EclipseWriter.cpp b/tests/test_EclipseWriter.cpp index 0dd9635d..255d4219 100644 --- a/tests/test_EclipseWriter.cpp +++ b/tests/test_EclipseWriter.cpp @@ -85,6 +85,7 @@ void createEclipseWriter(const char *deckString) Opm::PhaseUsage phaseUsage = Opm::phaseUsageFromDeck(deck); eclWriter.reset(new Opm::EclipseWriter(params, + deck, eclipseState, phaseUsage, ourFinerUnstructuredGrid.number_of_cells, diff --git a/tests/test_writenumwells.cpp b/tests/test_writenumwells.cpp index 7fb16bcd..2a7c1715 100644 --- a/tests/test_writenumwells.cpp +++ b/tests/test_writenumwells.cpp @@ -151,6 +151,7 @@ Opm::EclipseWriterPtr createEclipseWriter(Opm::DeckConstPtr deck, const Opm::PhaseUsage phaseUsage = Opm::phaseUsageFromDeck(deck); Opm::EclipseWriterPtr eclWriter(new Opm::EclipseWriter(params, + deck, eclipseState, phaseUsage, eclipseState->getEclipseGrid()->getCartesianSize(), From 126827d16637dc2822b3533abacda4bfe3182eec Mon Sep 17 00:00:00 2001 From: Andreas Lauser Date: Thu, 26 Mar 2015 17:33:07 +0100 Subject: [PATCH 3/3] summary writer: fix up the absolute times --- opm/core/io/eclipse/EclipseWriter.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/opm/core/io/eclipse/EclipseWriter.cpp b/opm/core/io/eclipse/EclipseWriter.cpp index 86cfd99e..86593e12 100644 --- a/opm/core/io/eclipse/EclipseWriter.cpp +++ b/opm/core/io/eclipse/EclipseWriter.cpp @@ -1,5 +1,5 @@ /* - Copyright (c) 2013-2014 Andreas Lauser + Copyright (c) 2013-2015 Andreas Lauser Copyright (c) 2013 SINTEF ICT, Applied Mathematics. Copyright (c) 2013 Uni Research AS Copyright (c) 2015 IRIS AS @@ -417,11 +417,17 @@ public: boost::filesystem::path casePath(outputDir); casePath /= boost::to_upper_copy(baseName); + // convert the start time to seconds since 1970-1-1@00:00:00 + boost::posix_time::ptime startTime + = timer.startDateTime(); + tm t = boost::posix_time::to_tm(startTime); + double secondsSinceEpochStart = std::mktime(&t); + ertHandle_ = ecl_sum_alloc_writer(casePath.string().c_str(), false, /* formatted */ true, /* unified */ ":", /* join string */ - timer.simulationTimeElapsed(), + secondsSinceEpochStart, nx, ny, nz);