/* Copyright (c) 2019 Equinor ASA 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_IO_OUTPUTSTREAM_HPP_INCLUDED #define OPM_IO_OUTPUTSTREAM_HPP_INCLUDED #include #include #include #include #include #include #include namespace Opm { namespace EclIO { class EclOutput; }} // namespace Opm::EclIO namespace Opm { namespace EclIO { namespace OutputStream { struct Formatted { bool set; }; struct Unified { bool set; }; /// Abstract representation of an ECLIPSE-style result set. struct ResultSet { /// Output directory. Commonly "." or location of run's .DATA file. std::string outputDir; /// Base name of simulation run. std::string baseName; }; /// File manager for "init" output streams. class Init { public: /// Constructor. /// /// Opens file stream for writing. /// /// \param[in] rset Output directory and base name of output stream. /// /// \param[in] fmt Whether or not to create formatted output files. explicit Init(const ResultSet& rset, const Formatted& fmt); ~Init(); Init(const Init& rhs) = delete; Init(Init&& rhs); Init& operator=(const Init& rhs) = delete; Init& operator=(Init&& rhs); /// Write integer data to underlying output stream. /// /// \param[in] kw Name of output vector (keyword). /// /// \param[in] data Output values. void write(const std::string& kw, const std::vector& data); /// Write boolean data to underlying output stream. /// /// \param[in] kw Name of output vector (keyword). /// /// \param[in] data Output values. void write(const std::string& kw, const std::vector& data); /// Write single precision floating point data to underlying /// output stream. /// /// \param[in] kw Name of output vector (keyword). /// /// \param[in] data Output values. void write(const std::string& kw, const std::vector& data); /// Write double precision floating point data to underlying /// output stream. /// /// \param[in] kw Name of output vector (keyword). /// /// \param[in] data Output values. void write(const std::string& kw, const std::vector& data); private: /// Init file output stream. std::unique_ptr stream_; /// Open output stream. /// /// Writes to \c stream_. /// /// \param[in] fname Filename of new output stream. /// /// \param[in] formatted Whether or not to create a /// formatted output file. void open(const std::string& fname, const bool formatted); /// Access writable output stream. EclOutput& stream(); /// Implementation function for public \c write overload set. template void writeImpl(const std::string& kw, const std::vector& data); }; /// File manager for restart output streams. class Restart { public: /// Constructor. /// /// Opens file stream pertaining to restart of particular report /// step and also outputs a SEQNUM record in the case of a unified /// output stream. /// /// Must be called before accessing the stream object through the /// stream() member function. /// /// \param[in] rset Output directory and base name of output stream. /// /// \param[in] seqnum Sequence number of new report. One-based /// report step ID. /// /// \param[in] fmt Whether or not to create formatted output files. /// /// \param[in] unif Whether or not to create unified output files. explicit Restart(const ResultSet& rset, const int seqnum, const Formatted& fmt, const Unified& unif); ~Restart(); Restart(const Restart& rhs) = delete; Restart(Restart&& rhs); Restart& operator=(const Restart& rhs) = delete; Restart& operator=(Restart&& rhs); /// Generate a message string (keyword type 'MESS') in underlying /// output stream. /// /// \param[in] msg Message string (e.g., "STARTSOL"). void message(const std::string& msg); /// Write integer data to underlying output stream. /// /// \param[in] kw Name of output vector (keyword). /// /// \param[in] data Output values. void write(const std::string& kw, const std::vector& data); /// Write boolean data to underlying output stream. /// /// \param[in] kw Name of output vector (keyword). /// /// \param[in] data Output values. void write(const std::string& kw, const std::vector& data); /// Write single precision floating point data to underlying /// output stream. /// /// \param[in] kw Name of output vector (keyword). /// /// \param[in] data Output values. void write(const std::string& kw, const std::vector& data); /// Write double precision floating point data to underlying /// output stream. /// /// \param[in] kw Name of output vector (keyword). /// /// \param[in] data Output values. void write(const std::string& kw, const std::vector& data); /// Write unpadded string data to underlying output stream. /// /// \param[in] kw Name of output vector (keyword). /// /// \param[in] data Output values. void write(const std::string& kw, const std::vector& data); /// Write padded character data (8 characters per string) /// to underlying output stream. /// /// \param[in] kw Name of output vector (keyword). /// /// \param[in] data Output values. void write(const std::string& kw, const std::vector>& data); private: /// Restart output stream. std::unique_ptr stream_; /// Open unified output file and place stream's output indicator /// in appropriate location. /// /// Writes to \c stream_. /// /// \param[in] fname Filename of output stream. /// /// \param[in] formatted Whether or not to create a /// formatted output file. /// /// \param[in] seqnum Sequence number of new report. One-based /// report step ID. void openUnified(const std::string& fname, const bool formatted, const int seqnum); /// Open new output stream. /// /// Handles the case of separate output files or unified output file /// that does not already exist. Writes to \c stream_. /// /// \param[in] fname Filename of new output stream. /// /// \param[in] formatted Whether or not to create a /// formatted output file. void openNew(const std::string& fname, const bool formatted); /// Open existing output file and place stream's output indicator /// in appropriate location. /// /// Writes to \c stream_. /// /// \param[in] fname Filename of output stream. /// /// \param[in] writePos Position at which to place stream's output /// indicator. Use \code streampos{ streamoff{-1} } \endcode to /// place output indicator at end of file (i.e, simple append). void openExisting(const std::string& fname, const bool formatted, const std::streampos writePos); /// Access writable output stream. /// /// Must not be called prior to \c prepareStep. EclOutput& stream(); /// Implementation function for public \c write overload set. template void writeImpl(const std::string& kw, const std::vector& data); }; /// File manager for RFT output streams class RFT { public: struct OpenExisting { bool set; }; /// Constructor. /// /// Opens file stream for writing. /// /// \param[in] rset Output directory and base name of output stream. /// /// \param[in] fmt Whether or not to create formatted output files. /// /// \param[in] existing Whether or not to open an existing output file. explicit RFT(const ResultSet& rset, const Formatted& fmt, const OpenExisting& existing); ~RFT(); RFT(const RFT& rhs) = delete; RFT(RFT&& rhs); RFT& operator=(const RFT& rhs) = delete; RFT& operator=(RFT&& rhs); /// Write integer data to underlying output stream. /// /// \param[in] kw Name of output vector (keyword). /// /// \param[in] data Output values. void write(const std::string& kw, const std::vector& data); /// Write single precision floating point data to underlying /// output stream. /// /// \param[in] kw Name of output vector (keyword). /// /// \param[in] data Output values. void write(const std::string& kw, const std::vector& data); /// Write padded character data (8 characters per string) /// to underlying output stream. /// /// \param[in] kw Name of output vector (keyword). /// /// \param[in] data Output values. void write(const std::string& kw, const std::vector>& data); private: /// Init file output stream. std::unique_ptr stream_; /// Open output stream. /// /// Writes to \c stream_. /// /// \param[in] fname Filename of new output stream. /// /// \param[in] formatted Whether or not to create a /// formatted output file. /// /// \param[in] existing Whether or not to open an /// existing output file (mode ios_base::app). void open(const std::string& fname, const bool formatted, const bool existing); /// Access writable output stream. EclOutput& stream(); /// Implementation function for public \c write overload set. template void writeImpl(const std::string& kw, const std::vector& data); }; class SummarySpecification { public: using StartTime = std::chrono::system_clock::time_point; enum class UnitConvention { Metric = 1, Field = 2, Lab = 3, Pvt_M = 4, }; struct RestartSpecification { std::string root; int step; }; class Parameters { public: void add(const std::string& keyword, const std::string& wgname, const int num, const std::string& unit); friend class SummarySpecification; private: std::vector> keywords{}; std::vector> wgnames{}; std::vector nums{}; std::vector> units{}; }; explicit SummarySpecification(const ResultSet& rset, const Formatted& fmt, const UnitConvention uconv, const std::array& cartDims, const RestartSpecification& restart, const StartTime start); ~SummarySpecification(); SummarySpecification(const SummarySpecification& rhs) = delete; SummarySpecification(SummarySpecification&& rhs); SummarySpecification& operator=(const SummarySpecification& rhs) = delete; SummarySpecification& operator=(SummarySpecification&& rhs); void write(const Parameters& params); private: int unit_; int restartStep_; std::array cartDims_; StartTime startDate_; std::vector> restart_; /// Summary specification (SMSPEC) file output stream. std::unique_ptr stream_; void rewindStream(); void flushStream(); EclOutput& stream(); }; std::unique_ptr createSummaryFile(const ResultSet& rset, const int seqnum, const Formatted& fmt, const Unified& unif); /// Derive filename corresponding to output stream of particular result /// set, with user-specified file extension. /// /// Low-level string concatenation routine that does not know specific /// relations between base names and file extensions. Handles details /// of base name ending in a period (full stop) or having a name that /// might otherwise appear to contain a file extension (e.g., CASE.01). /// /// \param[in] rsetDescriptor Output directory and base name of result set. /// /// \param[in] ext Filename extension. /// /// \return outputDir/baseName.ext std::string outputFileName(const ResultSet& rsetDescriptor, const std::string& ext); }}} // namespace Opm::EclIO::OutputStream #endif // OPM_IO_OUTPUTSTREAM_HPP_INCLUDED