diff --git a/CMakeLists_files.cmake b/CMakeLists_files.cmake index 90343d178..d83d65a06 100644 --- a/CMakeLists_files.cmake +++ b/CMakeLists_files.cmake @@ -109,6 +109,7 @@ list (APPEND MAIN_SOURCE_FILES opm/simulators/flow/partitionCells.cpp opm/simulators/flow/RSTConv.cpp opm/simulators/flow/RegionPhasePVAverage.cpp + opm/simulators/flow/SimulatorConvergenceOutput.cpp opm/simulators/flow/SimulatorReportBanners.cpp opm/simulators/flow/SimulatorSerializer.cpp opm/simulators/flow/SolutionContainers.cpp @@ -843,6 +844,7 @@ list (APPEND PUBLIC_HEADER_FILES opm/simulators/flow/priVarsPacking.hpp opm/simulators/flow/RSTConv.hpp opm/simulators/flow/RegionPhasePVAverage.hpp + opm/simulators/flow/SimulatorConvergenceOutput.hpp opm/simulators/flow/SimulatorFullyImplicitBlackoil.hpp opm/simulators/flow/SimulatorReportBanners.hpp opm/simulators/flow/SimulatorSerializer.hpp diff --git a/opm/simulators/flow/SimulatorConvergenceOutput.cpp b/opm/simulators/flow/SimulatorConvergenceOutput.cpp new file mode 100644 index 000000000..a96028705 --- /dev/null +++ b/opm/simulators/flow/SimulatorConvergenceOutput.cpp @@ -0,0 +1,94 @@ +/* + Copyright 2013, 2015, 2020 SINTEF Digital, Mathematics and Cybernetics. + Copyright 2015 Andreas Lauser + Copyright 2017 IRIS + + 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 . +*/ +#include +#include + +#include +#include + +#include + +namespace Opm { + +void SimulatorConvergenceOutput:: +startThread(std::string_view convOutputOptions, + std::string_view optionName, + ConvergenceOutputThread::ComponentToPhaseName getPhaseName) +{ + const auto config = ConvergenceOutputConfiguration { + convOutputOptions, optionName + }; + + if (! config.want(ConvergenceOutputConfiguration::Option::Iterations)) { + return; + } + + auto convertTime = ConvergenceOutputThread::ConvertToTimeUnits { + [usys = eclState_.getUnits()](const double time) + { return usys.from_si(UnitSystem::measure::time, time); } + }; + + this->convergenceOutputQueue_.emplace(); + this->convergenceOutputObject_.emplace + (eclState_.getIOConfig().getOutputDir(), + eclState_.getIOConfig().getBaseName(), + std::move(getPhaseName), + std::move(convertTime), + config, *this->convergenceOutputQueue_); + + this->convergenceOutputThread_ + .emplace(&ConvergenceOutputThread::writeASynchronous, + &this->convergenceOutputObject_.value()); +} + +void SimulatorConvergenceOutput:: +write(const std::vector& reports) +{ + if (! this->convergenceOutputThread_.has_value()) { + return; + } + + auto new_reports = std::vector { + reports.begin() + this->already_reported_steps_, reports.end() + }; + + auto requests = std::vector{}; + requests.reserve(new_reports.size()); + + for (auto&& report : new_reports) { + requests.push_back({ report.report_step, report.current_step, std::move(report.report) }); + } + this->already_reported_steps_ = reports.size(); + + this->convergenceOutputQueue_->enqueue(std::move(requests)); +} + +void SimulatorConvergenceOutput::endThread() +{ + if (! this->convergenceOutputThread_.has_value()) { + return; + } + + this->convergenceOutputQueue_->signalLastOutputRequest(); + this->convergenceOutputThread_->join(); +} + +} // namespace Opm diff --git a/opm/simulators/flow/SimulatorConvergenceOutput.hpp b/opm/simulators/flow/SimulatorConvergenceOutput.hpp new file mode 100644 index 000000000..37aebe86c --- /dev/null +++ b/opm/simulators/flow/SimulatorConvergenceOutput.hpp @@ -0,0 +1,66 @@ +/* + Copyright 2013, 2015, 2020 SINTEF Digital, Mathematics and Cybernetics. + Copyright 2015 Andreas Lauser + Copyright 2017 IRIS + + 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_SIMULATOR_CONVERGENCE_OUTPUT_HEADER_INCLUDED +#define OPM_SIMULATOR_CONVERGENCE_OUTPUT_HEADER_INCLUDED + +#include + +#include +#include +#include +#include +#include + +namespace Opm { + +class EclipseState; +struct StepReport; + +/// Class handling convergence history output for a simulator. +class SimulatorConvergenceOutput +{ +public: + explicit SimulatorConvergenceOutput(const EclipseState& eclState) + : eclState_(eclState) + {} + + void startThread(std::string_view convOutputOptions, + std::string_view optionName, + ConvergenceOutputThread::ComponentToPhaseName getPhaseName); + + void write(const std::vector& reports); + + void endThread(); + +private: + const EclipseState& eclState_; + + std::size_t already_reported_steps_ = 0; + + std::optional convergenceOutputQueue_{}; + std::optional convergenceOutputObject_{}; + std::optional convergenceOutputThread_{}; +}; + +} // namespace Opm + +#endif // OPM_SIMULATOR_CONVERGENCE_OUTPUT_HEADER_INCLUDED diff --git a/opm/simulators/flow/SimulatorFullyImplicitBlackoil.hpp b/opm/simulators/flow/SimulatorFullyImplicitBlackoil.hpp index 14b663dc2..01ee43d34 100644 --- a/opm/simulators/flow/SimulatorFullyImplicitBlackoil.hpp +++ b/opm/simulators/flow/SimulatorFullyImplicitBlackoil.hpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -45,18 +46,15 @@ #include #endif -#include - -#include #include #include -#include #include #include -#include #include #include +#include + namespace Opm::Parameters { struct EnableAdaptiveTimeStepping { static constexpr bool value = true; }; @@ -117,8 +115,9 @@ public: /// \param[in] eclipse_state the object which represents an internalized ECL deck /// \param[in] output_writer /// \param[in] threshold_pressures_by_face if nonempty, threshold pressures that inhibit flow - SimulatorFullyImplicitBlackoil(Simulator& simulator) + explicit SimulatorFullyImplicitBlackoil(Simulator& simulator) : simulator_(simulator) + , convergence_output_(simulator_.vanguard().eclState()) , serializer_(*this, FlowGenericVanguard::comm(), simulator_.vanguard().eclState().getIOConfig(), @@ -134,15 +133,22 @@ public: if (this->grid().comm().rank() == 0) { this->terminalOutput_ = Parameters::Get(); - this->startConvergenceOutputThread(Parameters::Get(), - R"(OutputExtraConvergenceInfo (--output-extra-convergence-info))"); + auto getPhaseName = ConvergenceOutputThread::ComponentToPhaseName { + [compNames = typename Model::ComponentName{}](const int compIdx) + { return std::string_view { compNames.name(compIdx) }; } + }; + + convergence_output_. + startThread(Parameters::Get(), + R"(OutputExtraConvergenceInfo (--output-extra-convergence-info))", + getPhaseName); } } ~SimulatorFullyImplicitBlackoil() { // Safe to call on all ranks, not just the I/O rank. - this->endConvergenceOutputThread(); + convergence_output_.endThread(); } static void registerParameters() @@ -420,14 +426,7 @@ public: // Grab the step convergence reports that are new since last we // were here. const auto& reps = this->solver_->model().stepReports(); - - auto reports = std::vector { - reps.begin() + this->already_reported_steps_, reps.end() - }; - - this->writeConvergenceOutput(std::move(reports)); - - this->already_reported_steps_ = reps.size(); + convergence_output_.write(reps); } // Increment timer, remember well state. @@ -563,65 +562,6 @@ protected: const WellModel& wellModel_() const { return simulator_.problem().wellModel(); } - void startConvergenceOutputThread(std::string_view convOutputOptions, - std::string_view optionName) - { - const auto config = ConvergenceOutputConfiguration { - convOutputOptions, optionName - }; - if (! config.want(ConvergenceOutputConfiguration::Option::Iterations)) { - return; - } - - auto getPhaseName = ConvergenceOutputThread::ComponentToPhaseName { - [compNames = typename Model::ComponentName{}](const int compIdx) - { return std::string_view { compNames.name(compIdx) }; } - }; - - auto convertTime = ConvergenceOutputThread::ConvertToTimeUnits { - [usys = this->eclState().getUnits()](const double time) - { return usys.from_si(UnitSystem::measure::time, time); } - }; - - this->convergenceOutputQueue_.emplace(); - this->convergenceOutputObject_.emplace - (this->eclState().getIOConfig().getOutputDir(), - this->eclState().getIOConfig().getBaseName(), - std::move(getPhaseName), - std::move(convertTime), - config, *this->convergenceOutputQueue_); - - this->convergenceOutputThread_ - .emplace(&ConvergenceOutputThread::writeASynchronous, - &this->convergenceOutputObject_.value()); - } - - void writeConvergenceOutput(std::vector&& reports) - { - if (! this->convergenceOutputThread_.has_value()) { - return; - } - - auto requests = std::vector{}; - requests.reserve(reports.size()); - - for (auto&& report : reports) { - requests.push_back({ report.report_step, report.current_step, std::move(report.report) }); - } - - this->convergenceOutputQueue_->enqueue(std::move(requests)); - } - - void endConvergenceOutputThread() - { - if (! this->convergenceOutputThread_.has_value()) { - return; - } - - this->convergenceOutputQueue_->signalLastOutputRequest(); - this->convergenceOutputThread_->join(); - } - // Data. Simulator& simulator_; @@ -636,14 +576,11 @@ protected: bool terminalOutput_; SimulatorReport report_; - std::size_t already_reported_steps_ = 0; std::unique_ptr solverTimer_; std::unique_ptr totalTimer_; std::unique_ptr adaptiveTimeStepping_; - std::optional convergenceOutputQueue_{}; - std::optional convergenceOutputObject_{}; - std::optional convergenceOutputThread_{}; + SimulatorConvergenceOutput convergence_output_; SimulatorSerializer serializer_; };