From f46b6c5a0162913700011804aa14cb3033a4d87d Mon Sep 17 00:00:00 2001 From: Arne Morten Kvarving Date: Wed, 23 Aug 2023 09:25:09 +0200 Subject: [PATCH] changed: move simulator serialization to separate class more separation of concerns --- CMakeLists_files.cmake | 2 + .../SimulatorFullyImplicitBlackoilEbos.cpp | 73 ----- .../SimulatorFullyImplicitBlackoilEbos.hpp | 221 ++++----------- opm/simulators/flow/SimulatorSerializer.cpp | 255 ++++++++++++++++++ opm/simulators/flow/SimulatorSerializer.hpp | 99 +++++++ 5 files changed, 410 insertions(+), 240 deletions(-) create mode 100644 opm/simulators/flow/SimulatorSerializer.cpp create mode 100644 opm/simulators/flow/SimulatorSerializer.hpp diff --git a/CMakeLists_files.cmake b/CMakeLists_files.cmake index a07e6e63a..194ed6ef9 100644 --- a/CMakeLists_files.cmake +++ b/CMakeLists_files.cmake @@ -51,6 +51,7 @@ list (APPEND MAIN_SOURCE_FILES opm/simulators/flow/Main.cpp opm/simulators/flow/NonlinearSolverEbos.cpp opm/simulators/flow/SimulatorFullyImplicitBlackoilEbos.cpp + opm/simulators/flow/SimulatorSerializer.cpp opm/simulators/flow/ValidationFunctions.cpp opm/simulators/flow/partitionCells.cpp opm/simulators/linalg/ExtractParallelGridInformationToISTL.cpp @@ -442,6 +443,7 @@ list (APPEND PUBLIC_HEADER_FILES opm/simulators/flow/Main.hpp opm/simulators/flow/NonlinearSolverEbos.hpp opm/simulators/flow/SimulatorFullyImplicitBlackoilEbos.hpp + opm/simulators/flow/SimulatorSerializer.hpp opm/simulators/flow/KeywordValidation.hpp opm/simulators/flow/LogOutputHelper.hpp opm/simulators/flow/ValidationFunctions.hpp diff --git a/opm/simulators/flow/SimulatorFullyImplicitBlackoilEbos.cpp b/opm/simulators/flow/SimulatorFullyImplicitBlackoilEbos.cpp index 8674aee12..3f19a5b99 100644 --- a/opm/simulators/flow/SimulatorFullyImplicitBlackoilEbos.cpp +++ b/opm/simulators/flow/SimulatorFullyImplicitBlackoilEbos.cpp @@ -22,14 +22,12 @@ #include #include -#include #include #include #include -#include #include #include @@ -64,75 +62,4 @@ void outputTimestampFIP(const SimulatorTimer& timer, OpmLog::note(ss.str()); } -void checkSerializedCmdLine(const std::string& current, - const std::string& stored) -{ - auto filter_strings = [](const std::vector& input) - { - std::vector output; - output.reserve(input.size()); - std::copy_if(input.begin(), input.end(), std::back_inserter(output), - [](const std::string& line) - { - return line.compare(0, 11, "EclDeckFile") != 0 && - line.compare(0, 8, "LoadStep") != 0 && - line.compare(0, 9, "OutputDir") != 0 && - line.compare(0, 8, "SaveFile") != 0 && - line.compare(0, 8, "SaveStep") != 0; - }); - return output; - }; - - auto curr_strings = split_string(current, '\n'); - auto stored_strings = split_string(stored, '\n'); - std::sort(curr_strings.begin(), curr_strings.end()); - std::sort(stored_strings.begin(), stored_strings.end()); - curr_strings = filter_strings(curr_strings); - stored_strings = filter_strings(stored_strings); - - std::vector difference; - std::set_symmetric_difference(stored_strings.begin(), stored_strings.end(), - curr_strings.begin(), curr_strings.end(), - std::back_inserter(difference)); - - std::vector only_stored, only_curr; - if (!difference.empty()) { - for (std::size_t i = 0; i < difference.size(); ) { - auto stored_it = std::find(stored_strings.begin(), - stored_strings.end(), difference[i]); - auto pos = difference[i].find_first_of('='); - if (i < difference.size() - 1 && - difference[i].compare(0, pos, difference[i+1], 0, pos) == 0) { - if (stored_it == stored_strings.end()) { - std::swap(difference[i], difference[i+1]); - } - i += 2; - } else { - if (stored_it == stored_strings.end()) { - only_curr.push_back(difference[i]); - } else { - only_stored.push_back(difference[i]); - } - difference.erase(difference.begin() + i); - } - } - std::stringstream str; - str << "Differences:\n"; - for (std::size_t i = 0; i < difference.size(); ++i) { - str << '\t' << (i % 2 == 0 ? '-' : '+') << difference[i] << '\n'; - } - if (!only_stored.empty()) { - str << "Only in serialized parameters:\n"; - for (const std::string& line : only_stored) - str << '\t' << line << '\n'; - } - if (!only_curr.empty()) { - str << "Only in current parameters:\n"; - for (const std::string& line : only_curr) - str << '\t' << line << '\n'; - } - OpmLog::warning("Command line parameters mismatch:\n" + str.str()); - } -} - } // namespace Opm diff --git a/opm/simulators/flow/SimulatorFullyImplicitBlackoilEbos.hpp b/opm/simulators/flow/SimulatorFullyImplicitBlackoilEbos.hpp index 9d92932e4..c59a36ff7 100644 --- a/opm/simulators/flow/SimulatorFullyImplicitBlackoilEbos.hpp +++ b/opm/simulators/flow/SimulatorFullyImplicitBlackoilEbos.hpp @@ -22,15 +22,15 @@ #ifndef OPM_SIMULATORFULLYIMPLICITBLACKOILEBOS_HEADER_INCLUDED #define OPM_SIMULATORFULLYIMPLICITBLACKOILEBOS_HEADER_INCLUDED -#include #include +#include #include #include #include #include #include -#include +#include #include #include #include @@ -149,12 +149,10 @@ void outputReportStep(const SimulatorTimer& timer); void outputTimestampFIP(const SimulatorTimer& timer, const std::string& title, const std::string& version); -void checkSerializedCmdLine(const std::string& current, - const std::string& stored); /// a simulator for the blackoil model template -class SimulatorFullyImplicitBlackoilEbos +class SimulatorFullyImplicitBlackoilEbos : private SerializableSim { public: using Simulator = GetPropType; @@ -202,6 +200,13 @@ public: /// \param[in] threshold_pressures_by_face if nonempty, threshold pressures that inhibit flow SimulatorFullyImplicitBlackoilEbos(Simulator& ebosSimulator) : ebosSimulator_(ebosSimulator) + , serializer_(*this, + EclGenericVanguard::comm(), + ebosSimulator_.vanguard().eclState().getIOConfig(), + EWOMS_GET_PARAM(TypeTag, std::string, SaveStep), + EWOMS_GET_PARAM(TypeTag, int, LoadStep), + EWOMS_GET_PARAM(TypeTag, std::string, SaveFile), + EWOMS_GET_PARAM(TypeTag, std::string, LoadFile)) { phaseUsage_ = phaseUsageFromDeck(eclState()); @@ -214,36 +219,6 @@ public: OutputExtraConvergenceInfo), R"(OutputExtraConvergenceInfo (--output-extra-convergence-info))"); } - - const std::string saveSpec = EWOMS_GET_PARAM(TypeTag, std::string, SaveStep); - if (saveSpec == "all") { - saveStride_ = 1; - } else if (saveSpec == "last") { - saveStride_ = -1; - } else if (!saveSpec.empty() && saveSpec[0] == ':') { - saveStride_ = std::atoi(saveSpec.c_str()+1); - } else if (!saveSpec.empty()) { - saveStep_ = std::atoi(saveSpec.c_str()); - } - - loadStep_ = EWOMS_GET_PARAM(TypeTag, int, LoadStep); - - saveFile_ = EWOMS_GET_PARAM(TypeTag, std::string, SaveFile); - loadFile_ = EWOMS_GET_PARAM(TypeTag, std::string, LoadFile); - - if (loadFile_.empty() || saveFile_.empty()) { - const auto& ioconfig = ebosSimulator_.vanguard().eclState().getIOConfig(); - if (saveFile_.empty()) saveFile_ = ioconfig.fullBasePath() + ".OPMRST"; - if (loadFile_.empty()) loadFile_ = saveFile_; - if (loadStep_ != -1 && !std::filesystem::exists(loadFile_)) { - std::filesystem::path path(ioconfig.getInputDir() + "/"); - path.replace_filename(ioconfig.getBaseName() + ".OPMRST"); - loadFile_ = path; - if (!std::filesystem::exists(loadFile_)) { - OPM_THROW(std::runtime_error, "Error locating serialized restart file " + loadFile_); - } - } - } } ~SimulatorFullyImplicitBlackoilEbos() @@ -291,7 +266,7 @@ public: EWOMS_REGISTER_PARAM(TypeTag, std::string, LoadFile, "FileName for .OPMRST file used to load serialized state. " "If empty, CASENAME.OPMRST is used."); - EWOMS_HIDE_PARAM(TypeTag, LoadFile); + EWOMS_HIDE_PARAM(TypeTag, LoadFile); } /// Run the simulation. @@ -363,8 +338,8 @@ public: return false; } - if (loadStep_ > -1) { - loadTimerInfo(timer); + if (serializer_.shouldLoad()) { + serializer_.loadTimerInfo(timer); } // Report timestep. @@ -404,10 +379,9 @@ public: + schedule().seconds(timer.currentStepNum()), timer.currentStepLength()); ebosSimulator_.setEpisodeIndex(timer.currentStepNum()); - if (loadStep_> -1) { - wellModel_().prepareDeserialize(loadStep_ - 1); - loadSimulatorState(); - loadStep_ = -1; + if (serializer_.shouldLoad()) { + wellModel_().prepareDeserialize(serializer_.loadStep() - 1); + serializer_.loadState(); ebosSimulator_.model().invalidateAndUpdateIntensiveQuantities(/*timeIdx=*/0); } solver_->model().beginReportStep(); @@ -491,7 +465,7 @@ public: OpmLog::debug(msg); } - handleSave(timer); + serializer_.save(timer); return true; } @@ -530,6 +504,42 @@ public: { return solver_->model(); } protected: + //! \brief Load simulator state from hdf5 serializer. + void loadState([[maybe_unused]] HDF5Serializer& serializer, + [[maybe_unused]] const std::string& groupName) override + { +#if HAVE_HDF5 + serializer.read(*this, groupName, "simulator_data"); +#endif + } + + //! \brief Save simulator state using hdf5 serializer. + void saveState([[maybe_unused]] HDF5Serializer& serializer, + [[maybe_unused]] const std::string& groupName) const override + { +#if HAVE_HDF5 + serializer.write(*this, groupName, "simulator_data"); +#endif + } + + //! \brief Returns header data + std::array getHeader() const override + { + std::ostringstream str; + Parameters::printValues(str); + return {"OPM Flow", + moduleVersion(), + compileTimestamp(), + ebosSimulator_.vanguard().caseName(), + str.str()}; + } + + //! \brief Returns local-to-global cell mapping. + const std::vector& getCellMapping() const override + { + return ebosSimulator_.vanguard().globalCell(); + } + std::unique_ptr createSolver(WellModel& wellModel) { @@ -637,125 +647,6 @@ protected: this->convergenceOutputThread_->join(); } - //! \brief Serialization of simulator data to .OPMRST files at end of report steps. - void handleSave(SimulatorTimer& timer) - { - if (saveStride_ == 0 && saveStep_ == -1) { - return; - } - - OPM_BEGIN_PARALLEL_TRY_CATCH(); - - int nextStep = timer.currentStepNum(); - if ((saveStep_ != -1 && nextStep == saveStep_) || - (saveStride_ != 0 && (nextStep % saveStride_) == 0)) { -#if !HAVE_HDF5 - OpmLog::error("Saving of serialized state requested, but no HDF5 support available."); -#else - const std::string groupName = "/report_step/" + std::to_string(nextStep); - if (saveStride_ < 0 || nextStep == saveStride_ || nextStep == saveStep_) { - std::filesystem::remove(saveFile_); - } - HDF5Serializer writer(saveFile_, - HDF5File::OpenMode::APPEND, - EclGenericVanguard::comm()); - if (saveStride_ < 0 || nextStep == saveStride_ || nextStep == saveStep_) { - std::ostringstream str; - Parameters::printValues(str); - writer.writeHeader("OPM Flow", - moduleVersion(), - compileTimestamp(), - ebosSimulator_.vanguard().caseName(), - str.str(), - EclGenericVanguard::comm().size()); - - if (EclGenericVanguard::comm().size() > 1) { - const auto& cellMapping = ebosSimulator_.vanguard().globalCell(); - std::size_t hash = Dune::hash_range(cellMapping.begin(), cellMapping.end()); - writer.write(hash, "/", "grid_checksum"); - } - } - writer.write(*this, groupName, "simulator_data"); - writer.write(timer, groupName, "simulator_timer", - HDF5File::DataSetMode::ROOT_ONLY); - OpmLog::info("Serialized state written for report step " + std::to_string(nextStep)); -#endif - } - - OPM_END_PARALLEL_TRY_CATCH("Error saving serialized state: ", - EclGenericVanguard::comm()); - } - - //! \brief Load timer info from serialized state. - void loadTimerInfo([[maybe_unused]] SimulatorTimer& timer) - { -#if !HAVE_HDF5 - OpmLog::error("Loading of serialized state requested, but no HDF5 support available."); - loadStep_ = -1; -#else - OPM_BEGIN_PARALLEL_TRY_CATCH(); - - HDF5Serializer reader(loadFile_, - HDF5File::OpenMode::READ, - EclGenericVanguard::comm()); - - if (loadStep_ == 0) { - loadStep_ = reader.lastReportStep(); - } - - OpmLog::info("Loading serialized state for report step " + std::to_string(loadStep_)); - const std::string groupName = "/report_step/" + std::to_string(loadStep_); - reader.read(timer, groupName, "simulator_timer", HDF5File::DataSetMode::ROOT_ONLY); - - std::tuple,int> header; - reader.read(header, "/", "simulator_info", HDF5File::DataSetMode::ROOT_ONLY); - const auto& [strings, procs] = header; - - if (EclGenericVanguard::comm().size() != procs) { - throw std::runtime_error("Number of processes (procs=" + - std::to_string(EclGenericVanguard::comm().size()) + - ") does not match .OPMRST file (procs=" + - std::to_string(procs) + ")"); - } - - if (EclGenericVanguard::comm().size() > 1) { - std::size_t stored_hash; - reader.read(stored_hash, "/", "grid_checksum"); - const auto& cellMapping = ebosSimulator_.vanguard().globalCell(); - std::size_t hash = Dune::hash_range(cellMapping.begin(), cellMapping.end()); - if (hash != stored_hash) { - throw std::runtime_error("Grid hash mismatch, .OPMRST file cannot be used"); - } - } - - if (EclGenericVanguard::comm().rank() == 0) { - std::ostringstream str; - Parameters::printValues(str); - checkSerializedCmdLine(str.str(), strings[4]); - } - - OPM_END_PARALLEL_TRY_CATCH("Error loading serialized state: ", - EclGenericVanguard::comm()); -#endif - } - - //! \brief Load simulator state from serialized state. - void loadSimulatorState() - { -#if HAVE_HDF5 - OPM_BEGIN_PARALLEL_TRY_CATCH(); - - HDF5Serializer reader(loadFile_, - HDF5File::OpenMode::READ, - EclGenericVanguard::comm()); - const std::string groupName = "/report_step/" + std::to_string(loadStep_); - reader.read(*this, groupName, "simulator_data"); - - OPM_END_PARALLEL_TRY_CATCH("Error loading serialized state: ", - EclGenericVanguard::comm()); -#endif - } - // Data. Simulator& ebosSimulator_; @@ -779,11 +670,7 @@ protected: std::optional convergenceOutputObject_{}; std::optional convergenceOutputThread_{}; - int saveStride_ = 0; //!< Stride to save serialized state at, negative to only keep last - int saveStep_ = -1; //!< Specific step to save serialized state at - int loadStep_ = -1; //!< Step to load serialized state from - std::string saveFile_; //!< File to save serialized state to - std::string loadFile_; //!< File to load serialized state from + SimulatorSerializer serializer_; }; } // namespace Opm diff --git a/opm/simulators/flow/SimulatorSerializer.cpp b/opm/simulators/flow/SimulatorSerializer.cpp new file mode 100644 index 000000000..7a514e29b --- /dev/null +++ b/opm/simulators/flow/SimulatorSerializer.cpp @@ -0,0 +1,255 @@ +/* + Copyright 2023 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 . +*/ + +#include +#include + +#include + +#include +#include +#include + +#include + +#include +#include + +#if HAVE_HDF5 +#include +#endif + +#include +#include +#include + +namespace Opm { + +SimulatorSerializer::SimulatorSerializer(SerializableSim& simulator, + Parallel::Communication& comm, + const IOConfig& ioconfig, + const std::string& saveSpec, + int loadStep, + const std::string& saveFile, + const std::string& loadFile) + : simulator_(simulator) + , comm_(comm) + , loadStep_(loadStep) + , saveFile_(saveFile) + , loadFile_(loadFile) +{ + if (saveSpec == "all") { + saveStride_ = 1; + } else if (saveSpec == "last") { + saveStride_ = -1; + } else if (!saveSpec.empty() && saveSpec[0] == ':') { + saveStride_ = std::atoi(saveSpec.c_str()+1); + } else if (!saveSpec.empty()) { + saveStep_ = std::atoi(saveSpec.c_str()); + } + + if (loadFile_.empty() || saveFile_.empty()) { + if (saveFile_.empty()) saveFile_ = ioconfig.fullBasePath() + ".OPMRST"; + if (loadFile_.empty()) loadFile_ = saveFile_; + if (loadStep_ != -1 && !std::filesystem::exists(loadFile_)) { + std::filesystem::path path(ioconfig.getInputDir() + "/"); + path.replace_filename(ioconfig.getBaseName() + ".OPMRST"); + loadFile_ = path; + if (!std::filesystem::exists(loadFile_)) { + OPM_THROW(std::runtime_error, "Error locating serialized restart file " + loadFile_); + } + } + } +} + +void SimulatorSerializer::save(SimulatorTimer& timer) +{ + if (saveStride_ == 0 && saveStep_ == -1) { + return; + } + + OPM_BEGIN_PARALLEL_TRY_CATCH(); + + int nextStep = timer.currentStepNum(); + if ((saveStep_ != -1 && nextStep == saveStep_) || + (saveStride_ != 0 && (nextStep % saveStride_) == 0)) { +#if !HAVE_HDF5 + OpmLog::error("Saving of serialized state requested, but no HDF5 support available."); +#else + const std::string groupName = "/report_step/" + std::to_string(nextStep); + if (saveStride_ < 0 || nextStep == saveStride_ || nextStep == saveStep_) { + std::filesystem::remove(saveFile_); + } + HDF5Serializer writer(saveFile_, HDF5File::OpenMode::APPEND, comm_); + if (saveStride_ < 0 || nextStep == saveStride_ || nextStep == saveStep_) { + const auto data = simulator_.getHeader(); + writer.writeHeader(data[0], data[1], data[2], data[3], data[4], comm_.size()); + + if (comm_.size() > 1) { + const auto& cellMapping = simulator_.getCellMapping(); + std::size_t hash = Dune::hash_range(cellMapping.begin(), cellMapping.end()); + writer.write(hash, "/", "grid_checksum"); + } + } + simulator_.saveState(writer, groupName); + writer.write(timer, groupName, "simulator_timer", + HDF5File::DataSetMode::ROOT_ONLY); + OpmLog::info("Serialized state written for report step " + std::to_string(nextStep)); +#endif + } + + OPM_END_PARALLEL_TRY_CATCH("Error saving serialized state: ", comm_); +} + + //! \brief Load timer info from serialized state. +void SimulatorSerializer::loadTimerInfo([[maybe_unused]] SimulatorTimer& timer) +{ +#if !HAVE_HDF5 + OpmLog::error("Loading of serialized state requested, but no HDF5 support available."); + loadStep_ = -1; +#else + OPM_BEGIN_PARALLEL_TRY_CATCH(); + + HDF5Serializer reader(loadFile_, HDF5File::OpenMode::READ, comm_); + + if (loadStep_ == 0) { + loadStep_ = reader.lastReportStep(); + } + + OpmLog::info("Loading serialized state for report step " + std::to_string(loadStep_)); + const std::string groupName = "/report_step/" + std::to_string(loadStep_); + reader.read(timer, groupName, "simulator_timer", HDF5File::DataSetMode::ROOT_ONLY); + + std::tuple,int> header; + reader.read(header, "/", "simulator_info", HDF5File::DataSetMode::ROOT_ONLY); + const auto& [strings, procs] = header; + + if (comm_.size() != procs) { + throw std::runtime_error("Number of processes (procs=" + + std::to_string(comm_.size()) + + ") does not match .OPMRST file (procs=" + + std::to_string(procs) + ")"); + } + + if (comm_.size() > 1) { + std::size_t stored_hash; + reader.read(stored_hash, "/", "grid_checksum"); + const auto& cellMapping = simulator_.getCellMapping(); + std::size_t hash = Dune::hash_range(cellMapping.begin(), cellMapping.end()); + if (hash != stored_hash) { + throw std::runtime_error("Grid hash mismatch, .OPMRST file cannot be used"); + } + } + + if (comm_.rank() == 0) { + const auto& curr_header = simulator_.getHeader(); + checkSerializedCmdLine(curr_header[4], strings[4]); + } + + OPM_END_PARALLEL_TRY_CATCH("Error loading serialized state: ", comm_); +#endif +} + + //! \brief Load simulator state from serialized state. +void SimulatorSerializer::loadState() +{ +#if HAVE_HDF5 + OPM_BEGIN_PARALLEL_TRY_CATCH(); + + HDF5Serializer reader(loadFile_, HDF5File::OpenMode::READ, comm_); + const std::string groupName = "/report_step/" + std::to_string(loadStep_); + simulator_.loadState(reader, groupName); + + OPM_END_PARALLEL_TRY_CATCH("Error loading serialized state: ", comm_); +#endif + loadStep_ = -1; +} + +void SimulatorSerializer::checkSerializedCmdLine(const std::string& current, + const std::string& stored) +{ + auto filter_strings = [](const std::vector& input) + { + std::vector output; + output.reserve(input.size()); + std::copy_if(input.begin(), input.end(), std::back_inserter(output), + [](const std::string& line) + { + return line.compare(0, 11, "EclDeckFile") != 0 && + line.compare(0, 8, "LoadStep") != 0 && + line.compare(0, 9, "OutputDir") != 0 && + line.compare(0, 8, "SaveFile") != 0 && + line.compare(0, 8, "SaveStep") != 0; + }); + return output; + }; + + auto curr_strings = split_string(current, '\n'); + auto stored_strings = split_string(stored, '\n'); + std::sort(curr_strings.begin(), curr_strings.end()); + std::sort(stored_strings.begin(), stored_strings.end()); + curr_strings = filter_strings(curr_strings); + stored_strings = filter_strings(stored_strings); + + std::vector difference; + std::set_symmetric_difference(stored_strings.begin(), stored_strings.end(), + curr_strings.begin(), curr_strings.end(), + std::back_inserter(difference)); + + std::vector only_stored, only_curr; + if (!difference.empty()) { + for (std::size_t i = 0; i < difference.size(); ) { + auto stored_it = std::find(stored_strings.begin(), + stored_strings.end(), difference[i]); + auto pos = difference[i].find_first_of('='); + if (i < difference.size() - 1 && + difference[i].compare(0, pos, difference[i+1], 0, pos) == 0) { + if (stored_it == stored_strings.end()) { + std::swap(difference[i], difference[i+1]); + } + i += 2; + } else { + if (stored_it == stored_strings.end()) { + only_curr.push_back(difference[i]); + } else { + only_stored.push_back(difference[i]); + } + difference.erase(difference.begin() + i); + } + } + std::stringstream str; + str << "Differences:\n"; + for (std::size_t i = 0; i < difference.size(); ++i) { + str << '\t' << (i % 2 == 0 ? '-' : '+') << difference[i] << '\n'; + } + if (!only_stored.empty()) { + str << "Only in serialized parameters:\n"; + for (const std::string& line : only_stored) + str << '\t' << line << '\n'; + } + if (!only_curr.empty()) { + str << "Only in current parameters:\n"; + for (const std::string& line : only_curr) + str << '\t' << line << '\n'; + } + OpmLog::warning("Command line parameters mismatch:\n" + str.str()); + } +} + +} // namespace Opm diff --git a/opm/simulators/flow/SimulatorSerializer.hpp b/opm/simulators/flow/SimulatorSerializer.hpp new file mode 100644 index 000000000..71c6add71 --- /dev/null +++ b/opm/simulators/flow/SimulatorSerializer.hpp @@ -0,0 +1,99 @@ +/* + Copyright 2023 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_SIMULATOR_SERIALIZER_HEADER_INCLUDED +#define OPM_SIMULATOR_SERIALIZER_HEADER_INCLUDED + +#include + +#include +#include +#include + +namespace Opm { + +class HDF5Serializer; +class IOConfig; +class SimulatorTimer; + +//! \brief Abstract interface for simulator serialization ops. +struct SerializableSim { + //! \brief Load simulator state from file. + virtual void loadState(HDF5Serializer& serializer, + const std::string& groupName) = 0; + + //! \brief Save simulator state to file. + virtual void saveState(HDF5Serializer& serializer, + const std::string& groupName) const = 0; + + //! \brief Get header info to save to file. + virtual std::array getHeader() const = 0; + + //! \brief Obtain local-to-global cell mapping. + virtual const std::vector& getCellMapping() const = 0; +}; + +//! \brief Class handling simulator serialization. +class SimulatorSerializer { +public: + //! \brief Constructor inits parameters. + //! \param saveSpec Specification of steps to save + //! \param loadStep Step to load + //! \paramn saveFile File to save to + //! \param loadFile File to load from + SimulatorSerializer(SerializableSim& simulator, + Parallel::Communication& comm, + const IOConfig& ioconfig, + const std::string& saveSpec, + int loadStep, + const std::string& saveFile, + const std::string& loadFile); + + //! \brief Returns whether or not a state should be loaded. + bool shouldLoad() const { return loadStep_ > -1; } + + //! \brief Returns step to load. + int loadStep() const { return loadStep_; } + + //! \brief Save data to file if appropriate. + void save(SimulatorTimer& timer); + + //! \brief Loads time step info from file. + void loadTimerInfo(SimulatorTimer& timer); + + //! \brief Load state from file. + void loadState(); + +private: + //! \brief Checks for differences between command line parameters. + void checkSerializedCmdLine(const std::string& current, + const std::string& stored); + + SerializableSim& simulator_; //!< Reference to simulator to be use + Parallel::Communication& comm_; //!< Communication to use + int saveStride_ = 0; //!< Stride to save serialized state at, negative to only keep last + int saveStep_ = -1; //!< Specific step to save serialized state at + int loadStep_ = -1; //!< Step to load serialized state from + std::string saveFile_; //!< File to save serialized state to + std::string loadFile_; //!< File to load serialized state from +}; + +} // namespace Opm + +#endif // OPM_SIMULATOR_SERIALIZER_HEADER_INCLUDED