/* Copyright 2022 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 EXTRA_CONVERGENCE_OUTPUT_THREAD_HPP #define EXTRA_CONVERGENCE_OUTPUT_THREAD_HPP #include #include #include #include #include #include #include namespace Opm { class ConvergenceOutputConfiguration; } // namespace Opm /// \file System for outputting additional convergence information, such as /// material balance and CNV values, at each non-linear iteration. /// /// Supports an asynchronous protocol that assumes there is a single thread /// dedicated to per-iteration file output. Synchronous file output is /// available for debugging and development purposes. namespace Opm { /// Forward declaration so that Queue may declare this type its 'friend'. class ConvergenceOutputThread; /// Communication channel between thread creating output requests and /// consumer thread writing those requests to a file. /// /// Output thread has access to internal state. Producer thread uses public /// interface. Producer thread creates an object of this type and launches /// the output thread with a reference to that queue object. class ConvergenceReportQueue { public: /// Single output request. /// /// Associates non-linear iteration convergence information to single /// report and timestep. struct OutputRequest { /// Current report step int reportStep{-1}; /// Current timestep within \c reportStep. Expected to be a small /// integer. int currentStep{-1}; /// Convergence metrics for each non-linear ieration in the \c /// currentStep. std::vector reports{}; }; /// Push sequence of output requests, typically all substeps whether /// converged or not, of a single report step. /// /// \param[in] requests Output request sequence. Queue takes ownership. void enqueue(std::vector&& requests); /// Signal end of output request stream. /// /// No additional requests should be added to queue following a call to /// this member function. Output thread detects this signal, completes /// any pending output requests, and shuts down afterwards. void signalLastOutputRequest(); friend class ConvergenceOutputThread; private: /// Mutex for critical sections protecting 'requests_'. std::mutex mtx_{}; /// Condition variable for threads waiting on changes to 'requests_'. std::condition_variable cv_{}; /// Pending convergence output requests. std::vector requests_{}; }; /// Encapsulating object for thread processing producer's convergence output /// requests. class ConvergenceOutputThread { public: /// Protocol for converting a phase/component ID into a human readable /// phase/component name. using ComponentToPhaseName = std::function; /// Protocol for converting an SI elapsed time value into an equivalent /// time value in the run's output conventions. /// /// Will typically use \code UnitSystem::from_si() \endcode. using ConvertToTimeUnits = std::function; /// Constructor. /// /// \param[in] outputDir -- Name of run's output directory. Any file /// output will be written to this directory. /// /// \param[in] baseName -- Run's base name. Output files will have this /// name and a type-specific file extension. /// /// \param[in] getPhaseName -- Callable object for converting component /// indices into human readable component names. /// /// \param[in] convertTime -- Callable object for converting SI elapsed /// time values into equivalent elapsed time /// values using run's time conventions. /// /// \param[in] config -- Convergence output configuration options. /// Determines whether to output additional /// convergence information and, if so, what /// information to output. /// /// \param[in] queue -- Communication channel between producer thread /// and this output thread. User must form a /// valid queue prior to creating the output /// thread object. explicit ConvergenceOutputThread(std::string_view outputDir, std::string_view baseName, ComponentToPhaseName getPhaseName, ConvertToTimeUnits convertTime, ConvergenceOutputConfiguration config, ConvergenceReportQueue& queue); /// Deleted copy constructor. ConvergenceOutputThread(const ConvergenceOutputThread& src) = delete; /// Move constructor. ConvergenceOutputThread(ConvergenceOutputThread&& src); /// Deleted assignment operator. ConvergenceOutputThread& operator=(const ConvergenceOutputThread& src) = delete; /// Deleted move-assignment operator. ConvergenceOutputThread& operator=(ConvergenceOutputThread&& src) = delete; /// Destructor. /// /// Needed for pimpl idiom. ~ConvergenceOutputThread(); /// Perform synchronous file output of a sequence of requests. /// /// Mostly for development and debugging purposes. /// /// \param[in] requests Output request sequence. Thread takes ownership. void writeSynchronous(std::vector&& requests); /// Output thread worker function /// /// This is the endpoint that users should associate to a \code /// std::thread \endcode object. /// /// Returns once last pending output request is written (cf. \code /// ConvergenceReportQueue::signalLastOutputRequest() \endcode.) void writeASynchronous(); private: /// Private implementation class. class Impl; /// Pointer to implementation. std::unique_ptr pImpl_; }; } // namespace Opm #endif // EXTRA_CONVERGENCE_OUTPUT_THREAD_HPP