opm-simulators/opm/models/io/restart.hh
2020-06-10 13:49:42 +02:00

276 lines
8.4 KiB
C++

// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
// vi: set et ts=4 sw=4 sts=4:
/*
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 2 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 <http://www.gnu.org/licenses/>.
Consult the COPYING file in the top-level source directory of this
module for the precise wording of the license and the list of
copyright holders.
*/
/*!
* \file
* \copydoc Opm::Restart
*/
#ifndef EWOMS_RESTART_HH
#define EWOMS_RESTART_HH
#include <string>
#include <fstream>
#include <iostream>
#include <sstream>
namespace Opm {
/*!
* \brief Load or save a state of a problem to/from the harddisk.
*/
class Restart
{
/*!
* \brief Create a magic cookie for restart files, so that it is
* unlikely to load a restart file for an incorrectly.
*/
template <class GridView>
static const std::string magicRestartCookie_(const GridView& gridView)
{
static const std::string gridName = "blubb"; // gridView.grid().name();
static const int dim = GridView::dimension;
int numVertices = gridView.size(dim);
int numElements = gridView.size(0);
int numEdges = gridView.size(dim - 1);
int numCPUs = gridView.comm().size();
int rank = gridView.comm().rank();
std::ostringstream oss;
oss << "eWoms restart file: "
<< "gridName='" << gridName << "' "
<< "numCPUs=" << numCPUs << " "
<< "myRank=" << rank << " "
<< "numElements=" << numElements << " "
<< "numEdges=" << numEdges << " "
<< "numVertices=" << numVertices;
return oss.str();
}
/*!
* \brief Return the restart file name.
*/
template <class GridView, class Scalar>
static const std::string restartFileName_(const GridView& gridView,
const std::string& outputDir,
const std::string& simName,
Scalar t)
{
std::string dir = outputDir;
if (dir == ".")
dir = "";
else if (!dir.empty() && dir.back() != '/')
dir += "/";
int rank = gridView.comm().rank();
std::ostringstream oss;
oss << dir << simName << "_time=" << t << "_rank=" << rank << ".ers";
return oss.str();
}
public:
/*!
* \brief Returns the name of the file which is (de-)serialized.
*/
const std::string& fileName() const
{ return fileName_; }
/*!
* \brief Write the current state of the model to disk.
*/
template <class Simulator>
void serializeBegin(Simulator& simulator)
{
const std::string magicCookie = magicRestartCookie_(simulator.gridView());
fileName_ = restartFileName_(simulator.gridView(),
simulator.problem().outputDir(),
simulator.problem().name(),
simulator.time());
// open output file and write magic cookie
outStream_.open(fileName_.c_str());
outStream_.precision(20);
serializeSectionBegin(magicCookie);
serializeSectionEnd();
}
/*!
* \brief The output stream to write the serialized data.
*/
std::ostream& serializeStream()
{ return outStream_; }
/*!
* \brief Start a new section in the serialized output.
*/
void serializeSectionBegin(const std::string& cookie)
{ outStream_ << cookie << "\n"; }
/*!
* \brief End of a section in the serialized output.
*/
void serializeSectionEnd()
{ outStream_ << "\n"; }
/*!
* \brief Serialize all leaf entities of a codim in a gridView.
*
* The actual work is done by Serializer::serialize(Entity)
*/
template <int codim, class Serializer, class GridView>
void serializeEntities(Serializer& serializer, const GridView& gridView)
{
std::ostringstream oss;
oss << "Entities: Codim " << codim;
std::string cookie = oss.str();
serializeSectionBegin(cookie);
// write element data
using Iterator = typename GridView::template Codim<codim>::Iterator;
Iterator it = gridView.template begin<codim>();
const Iterator& endIt = gridView.template end<codim>();
for (; it != endIt; ++it) {
serializer.serializeEntity(outStream_, *it);
outStream_ << "\n";
}
serializeSectionEnd();
}
/*!
* \brief Finish the restart file.
*/
void serializeEnd()
{ outStream_.close(); }
/*!
* \brief Start reading a restart file at a certain simulated
* time.
*/
template <class Simulator, class Scalar>
void deserializeBegin(Simulator& simulator, Scalar t)
{
fileName_ = restartFileName_(simulator.gridView(), simulator.problem().outputDir(), simulator.problem().name(), t);
// open input file and read magic cookie
inStream_.open(fileName_.c_str());
if (!inStream_.good()) {
throw std::runtime_error("Restart file '"+fileName_+"' could not be opened properly");
}
// make sure that we don't open an empty file
inStream_.seekg(0, std::ios::end);
auto pos = inStream_.tellg();
if (pos == 0) {
throw std::runtime_error("Restart file '"+fileName_+"' is empty");
}
inStream_.seekg(0, std::ios::beg);
const std::string magicCookie = magicRestartCookie_(simulator.gridView());
deserializeSectionBegin(magicCookie);
deserializeSectionEnd();
}
/*!
* \brief The input stream to read the data which ought to be
* deserialized.
*/
std::istream& deserializeStream()
{ return inStream_; }
/*!
* \brief Start reading a new section of the restart file.
*/
void deserializeSectionBegin(const std::string& cookie)
{
if (!inStream_.good())
throw std::runtime_error("Encountered unexpected EOF in restart file.");
std::string buf;
std::getline(inStream_, buf);
if (buf != cookie)
throw std::runtime_error("Could not start section '"+cookie+"'");
}
/*!
* \brief End of a section in the serialized output.
*/
void deserializeSectionEnd()
{
std::string dummy;
std::getline(inStream_, dummy);
for (unsigned i = 0; i < dummy.length(); ++i) {
if (!std::isspace(dummy[i])) {
throw std::logic_error("Encountered unread values while deserializing");
}
}
}
/*!
* \brief Deserialize all leaf entities of a codim in a grid.
*
* The actual work is done by Deserializer::deserialize(Entity)
*/
template <int codim, class Deserializer, class GridView>
void deserializeEntities(Deserializer& deserializer, const GridView& gridView)
{
std::ostringstream oss;
oss << "Entities: Codim " << codim;
std::string cookie = oss.str();
deserializeSectionBegin(cookie);
std::string curLine;
// read entity data
using Iterator = typename GridView::template Codim<codim>::Iterator;
Iterator it = gridView.template begin<codim>();
const Iterator& endIt = gridView.template end<codim>();
for (; it != endIt; ++it) {
if (!inStream_.good()) {
throw std::runtime_error("Restart file is corrupted");
}
std::getline(inStream_, curLine);
std::istringstream curLineStream(curLine);
deserializer.deserializeEntity(curLineStream, *it);
}
deserializeSectionEnd();
}
/*!
* \brief Stop reading the restart file.
*/
void deserializeEnd()
{ inStream_.close(); }
private:
std::string fileName_;
std::ifstream inStream_;
std::ofstream outStream_;
};
} // namespace Opm
#endif