diff --git a/opm/core/io/eclipse/EclipseWriter.cpp b/opm/core/io/eclipse/EclipseWriter.cpp
index 2ac553d5..c13aef46 100644
--- a/opm/core/io/eclipse/EclipseWriter.cpp
+++ b/opm/core/io/eclipse/EclipseWriter.cpp
@@ -1,5 +1,5 @@
- /*
- Copyright (c) 2013 Andreas Lauser
+/*
+ Copyright (c) 2013-2014 Andreas Lauser
Copyright (c) 2013 SINTEF ICT, Applied Mathematics.
Copyright (c) 2013 Uni Research AS
@@ -18,9 +18,7 @@
You should have received a copy of the GNU General Public License
along with OPM. If not, see .
*/
-#if HAVE_CONFIG_H
#include "config.h"
-#endif // HAVE_CONFIG_H
#include "EclipseWriter.hpp"
@@ -259,14 +257,6 @@ EclipseKeyword ::EclipseKeyword (
copyData (data, transf, offset, stride);
}
-/**
- * Extract the current time from a timer object into the C type used by ERT.
- */
-static time_t current (const SimulatorTimer& timer) {
- tm t = boost::posix_time::to_tm (timer.currentDateTime());
- return std::mktime(&t);
-}
-
/**
* Pointer to memory that holds the name to an Eclipse output file.
*/
@@ -274,7 +264,7 @@ struct EclipseFileName : public EclipseHandle {
EclipseFileName (const std::string& outputDir,
const std::string& baseName,
ecl_file_enum type,
- const SimulatorTimer& timer)
+ int outputStepIdx)
// filename formatting function returns a pointer to allocated
// memory that must be released with the free() function
@@ -283,7 +273,7 @@ struct EclipseFileName : public EclipseHandle {
baseName.c_str(),
type,
false, // formatted?
- timer.currentStepNum ()),
+ outputStepIdx),
freestr) { }
private:
/// Facade which allows us to free a const char*
@@ -325,7 +315,8 @@ static int phaseMask (const PhaseUsage uses) {
struct EclipseRestart : public EclipseHandle {
EclipseRestart (const std::string& outputDir,
const std::string& baseName,
- const SimulatorTimer& timer)
+ const SimulatorTimer& timer,
+ int outputStepIdx)
// notice the poor man's polymorphism of the allocation function
: EclipseHandle (
(timer.currentStepNum () > 0 ? ecl_rst_file_open_append
@@ -333,18 +324,19 @@ struct EclipseRestart : public EclipseHandle {
EclipseFileName (outputDir,
baseName,
ECL_UNIFIED_RESTART_FILE,
- timer)),
+ outputStepIdx)),
ecl_rst_file_close) { }
void writeHeader (const SimulatorTimer& timer,
+ int outputStepIdx,
const PhaseUsage uses,
const EclipseGridParser parser,
const int num_active_cells) {
const std::vector dim = parserDim (parser);
ecl_rst_file_fwrite_header (*this,
- timer.currentStepNum (),
- current (timer),
- Opm::unit::convert::to (timer.currentTime (),
+ outputStepIdx,
+ timer.currentPosixTime(),
+ Opm::unit::convert::to (timer.simulationTimeElapsed (),
Opm::unit::day),
dim[0],
dim[1],
@@ -458,12 +450,12 @@ struct EclipseGrid : public EclipseHandle {
*/
void write (const std::string& outputDir,
const std::string& baseName,
- const SimulatorTimer& timer) {
+ int outputStepIdx) {
ecl_grid_fwrite_EGRID (*this,
EclipseFileName (outputDir,
baseName,
ECL_EGRID_FILE,
- timer));
+ outputStepIdx));
}
// GCC 4.4 doesn't generate these constructors for us; provide the
@@ -500,7 +492,7 @@ private:
EclipseGrid (const int dims[],
const EclipseKeyword& zcorn,
const EclipseKeyword& coord,
- const EclipseKeyword& actnum,
+ const EclipseKeyword& actnum,
const EclipseKeyword& mapaxes)
: EclipseHandle (
ecl_grid_alloc_GRDECL_kw(dims[0],
@@ -524,11 +516,11 @@ struct EclipseInit : public EclipseHandle {
// constructor, so we'll have to do with a static wrapper)
static EclipseInit make (const std::string& outputDir,
const std::string& baseName,
- const SimulatorTimer& timer) {
+ int outputStepIdx) {
EclipseFileName initFileName (outputDir,
baseName,
ECL_INIT_FILE,
- timer);
+ outputStepIdx);
bool fmt_file;
if (!ecl_util_fmt_file(initFileName, &fmt_file)) {
OPM_THROW(std::runtime_error,
@@ -538,15 +530,15 @@ struct EclipseInit : public EclipseHandle {
}
void writeHeader (const EclipseGrid& grid,
- const SimulatorTimer& timer,
- const EclipseGridParser& parser,
- const PhaseUsage uses) {
+ const SimulatorTimer& timer,
+ const EclipseGridParser& parser,
+ const PhaseUsage uses) {
EclipseKeyword poro (PORO_KW, parser);
ecl_init_file_fwrite_header (*this,
grid,
poro,
phaseMask (uses),
- current (timer));
+ timer.currentPosixTime());
}
void writeKeyword (const std::string& keyword,
@@ -639,8 +631,7 @@ private:
EclipseTimeStep* tstep = new EclipseTimeStep (
ecl_sum_add_tstep (*this,
timer.currentStepNum (),
- // currentTime is always relative to start
- Opm::unit::convert::to (timer.currentTime (),
+ Opm::unit::convert::to (timer.simulationTimeElapsed (),
Opm::unit::day)));
return std::unique_ptr (tstep);
}
@@ -660,7 +651,7 @@ private:
false, /* formatted */
true, /* unified */
":", /* join string */
- current (timer),
+ timer.simulationTimeElapsed (),
dim[0],
dim[1],
dim[2]);
@@ -857,7 +848,8 @@ struct EclipseWellBhp : public EclipseWellReport {
inline void
EclipseSummary::writeTimeStep (const SimulatorTimer& timer,
- const WellState& wellState) {
+ const WellState& wellState)
+{
// internal view; do not move this code out of EclipseSummary!
std::unique_ptr tstep = makeTimeStep (timer);
// write all the variables
@@ -873,7 +865,8 @@ static WellType WELL_TYPES[] = { INJECTOR, PRODUCER };
inline void
EclipseSummary::addWells (const EclipseGridParser& parser,
- const PhaseUsage& uses) {
+ const PhaseUsage& uses)
+{
// TODO: Only create report variables that are requested with keywords
// (e.g. "WOPR") in the input files, and only for those wells that are
// mentioned in those keywords
@@ -957,12 +950,19 @@ namespace Opm {
void EclipseWriter::writeInit(const SimulatorTimer &timer,
const SimulatorState& reservoirState,
- const WellState& wellState) {
+ const WellState& wellState)
+{
+ // if we don't want to write anything, this method becomes a
+ // no-op...
+ if (!enableOutput_) {
+ return;
+ }
+
/* Grid files */
EclipseGrid ecl_grid = EclipseGrid::make (*parser_, *grid_);
- ecl_grid.write (outputDir_, baseName_, timer);
+ ecl_grid.write (outputDir_, baseName_, /*stepIdx=*/0);
- EclipseInit fortio = EclipseInit::make (outputDir_, baseName_, timer);
+ EclipseInit fortio = EclipseInit::make (outputDir_, baseName_, /*stepIdx=*/0);
fortio.writeHeader (ecl_grid,
timer,
*parser_,
@@ -973,7 +973,7 @@ void EclipseWriter::writeInit(const SimulatorTimer &timer,
fortio.writeKeyword ("PERMZ", *parser_, &toMilliDarcy);
/* Initial solution (pressure and saturation) */
- writeSolution (timer, reservoirState, wellState);
+ writeSolution_(timer, reservoirState);
/* Create summary object (could not do it at construction time,
since it requires knowledge of the start time). */
@@ -981,14 +981,16 @@ void EclipseWriter::writeInit(const SimulatorTimer &timer,
summary_->addWells (*parser_, uses_);
}
-void EclipseWriter::writeSolution (const SimulatorTimer& timer,
- const SimulatorState& reservoirState,
- const WellState& /*wellState*/) {
+void EclipseWriter::writeSolution_(const SimulatorTimer& timer,
+ const SimulatorState& reservoirState)
+{
// start writing to files
EclipseRestart rst (outputDir_,
baseName_,
- timer);
+ timer,
+ outputTimeStepIdx_);
rst.writeHeader (timer,
+ outputTimeStepIdx_,
uses_,
*parser_,
reservoirState.pressure ().size ());
@@ -997,9 +999,7 @@ void EclipseWriter::writeSolution (const SimulatorTimer& timer,
// write pressure and saturation fields (same as DataMap holds)
// convert the pressures from Pascals to bar because Eclipse
// seems to write bars
- sol.add (EclipseKeyword (reservoirState.pressure (),
- "PRESSURE",
- &toBar));
+ sol.add(EclipseKeyword(reservoirState.pressure(), "PRESSURE", &toBar));
for (int phase = 0; phase != BlackoilPhases::MaxNumPhases; ++phase) {
// Eclipse never writes the oil saturation, so all post-processors
@@ -1015,13 +1015,27 @@ void EclipseWriter::writeSolution (const SimulatorTimer& timer,
uses_.num_phases));
}
}
+
+ ++outputTimeStepIdx_;
}
void EclipseWriter::writeTimeStep(const SimulatorTimer& timer,
const SimulatorState& reservoirState,
- const WellState& wellState) {
+ const WellState& wellState)
+{
+ // if we don't want to write anything, this method becomes a
+ // no-op...
+ if (!enableOutput_) {
+ return;
+ }
+
+ // respected the output_interval parameter
+ if (timer.currentStepNum() % outputInterval_ != 0) {
+ return;
+ }
+
/* Field variables (pressure, saturation) */
- writeSolution (timer, reservoirState, wellState);
+ writeSolution_(timer, reservoirState);
/* Summary variables (well reporting) */
// TODO: instead of writing the header (smspec) every time, it should
@@ -1037,15 +1051,23 @@ void EclipseWriter::writeTimeStep(const SimulatorTimer& timer,
// called. This has been changed so that the final summary file
// will contain data from the whole simulation, instead of just
// the last step.
- summary_->writeTimeStep (timer, wellState);
+ summary_->writeTimeStep(timer, wellState);
}
+} // namespace Opm
#else
namespace Opm {
void EclipseWriter::writeInit(const SimulatorTimer&,
const SimulatorState&,
- const WellState&) {
+ const WellState&)
+ {
+ // if we don't want to write anything, this method becomes a
+ // no-op...
+ if (!enableOutput_) {
+ return;
+ }
+
OPM_THROW(std::runtime_error,
"The ERT libraries are required to write ECLIPSE output files.");
}
@@ -1053,20 +1075,35 @@ void EclipseWriter::writeInit(const SimulatorTimer&,
void EclipseWriter::writeTimeStep(
const SimulatorTimer&,
const SimulatorState&,
- const WellState&) {
+ const WellState&)
+{
+ // if we don't want to write anything, this method becomes a
+ // no-op...
+ if (!enableOutput_) {
+ return;
+ }
+
OPM_THROW(std::runtime_error,
"The ERT libraries are required to write ECLIPSE output files.");
}
+} // namespace Opm
+
#endif // HAVE_ERT
+namespace Opm {
+
EclipseWriter::EclipseWriter (
const ParameterGroup& params,
std::shared_ptr parser,
std::shared_ptr grid)
: parser_ (parser)
, grid_ (grid)
- , uses_ (phaseUsageFromDeck (*parser)) {
+ , uses_ (phaseUsageFromDeck (*parser))
+{
+ // set the index of the first time step written to 0...
+ outputTimeStepIdx_ = 0;
+
// get the base name from the name of the deck
using boost::filesystem::path;
@@ -1082,14 +1119,31 @@ EclipseWriter::EclipseWriter (
// of some of the files (.SMSPEC, .UNSMRY) and not others
baseName_ = boost::to_upper_copy (baseName_);
+ // retrieve the value of the "output" parameter
+ enableOutput_ = params.getDefault("output", /*defaultValue=*/true);
+
+ // retrieve the interval at which something should get written to
+ // disk (once every N timesteps)
+ outputInterval_ = params.getDefault("output_interval", /*defaultValue=*/1);
+
// store in current directory if not explicitly set
- if (params.has ("output_dir")) {
- outputDir_ = params.get ("output_dir");
- }
- else {
- // this is needed to prevent file names like "/FOO.INIT" which
- // lead to segfaults
- outputDir_ = ".";
+ outputDir_ = params.getDefault("output_dir", ".");
+
+ // set the index of the first time step written to 0...
+ outputTimeStepIdx_ = 0;
+
+ if (enableOutput_) {
+ // make sure that the output directory exists, if not try to create it
+ if (!boost::filesystem::exists(outputDir_)) {
+ std::cout << "Trying to create directory \"" << outputDir_ << "\" for the simulation output\n";
+ boost::filesystem::create_directories(outputDir_);
+ }
+
+ if (!boost::filesystem::is_directory(outputDir_)) {
+ OPM_THROW(std::runtime_error,
+ "The path specified as output directory '" << outputDir_
+ << "' is not a directory");
+ }
}
}
diff --git a/opm/core/io/eclipse/EclipseWriter.hpp b/opm/core/io/eclipse/EclipseWriter.hpp
index 5634a347..a3451ac3 100644
--- a/opm/core/io/eclipse/EclipseWriter.hpp
+++ b/opm/core/io/eclipse/EclipseWriter.hpp
@@ -88,15 +88,17 @@ public:
private:
std::shared_ptr parser_;
std::shared_ptr grid_;
+ bool enableOutput_;
+ int outputInterval_;
+ int outputTimeStepIdx_;
std::string outputDir_;
std::string baseName_;
PhaseUsage uses_; // active phases in the input deck
std::shared_ptr summary_;
/// Write solution field variables (pressure and saturation)
- void writeSolution (const SimulatorTimer& timer,
- const SimulatorState& reservoirState,
- const WellState& wellState);
+ void writeSolution_(const SimulatorTimer& timer,
+ const SimulatorState& reservoirState);
};
} // namespace Opm
diff --git a/opm/core/simulator/SimulatorCompressibleTwophase.cpp b/opm/core/simulator/SimulatorCompressibleTwophase.cpp
index a5760716..7284d8d4 100644
--- a/opm/core/simulator/SimulatorCompressibleTwophase.cpp
+++ b/opm/core/simulator/SimulatorCompressibleTwophase.cpp
@@ -498,13 +498,13 @@ namespace Opm
<< std::endl;
std::cout.precision(8);
- watercut.push(timer.currentTime() + timer.currentStepLength(),
+ watercut.push(timer.simulationTimeElapsed() + timer.currentStepLength(),
produced[0]/(produced[0] + produced[1]),
tot_produced[0]/tot_porevol_init);
if (wells_) {
wellreport.push(props_, *wells_,
state.pressure(), state.surfacevol(), state.saturation(),
- timer.currentTime() + timer.currentStepLength(),
+ timer.simulationTimeElapsed() + timer.currentStepLength(),
well_state.bhp(), well_state.perfRates());
}
sreport.total_time = step_timer.secsSinceStart();
diff --git a/opm/core/simulator/SimulatorIncompTwophase.cpp b/opm/core/simulator/SimulatorIncompTwophase.cpp
index 12871c76..271cc8fe 100644
--- a/opm/core/simulator/SimulatorIncompTwophase.cpp
+++ b/opm/core/simulator/SimulatorIncompTwophase.cpp
@@ -578,12 +578,12 @@ namespace Opm
dynamic_cast(*tsolver_)
.solveGravity(&initial_porevol[0], stepsize, state);
}
- watercut.push(timer.currentTime() + timer.currentStepLength(),
+ watercut.push(timer.simulationTimeElapsed() + timer.currentStepLength(),
produced[0]/(produced[0] + produced[1]),
tot_produced[0]/tot_porevol_init);
if (wells_) {
wellreport.push(props_, *wells_, state.saturation(),
- timer.currentTime() + timer.currentStepLength(),
+ timer.simulationTimeElapsed() + timer.currentStepLength(),
well_state.bhp(), well_state.perfRates());
}
}
diff --git a/opm/core/simulator/SimulatorOutput.cpp b/opm/core/simulator/SimulatorOutput.cpp
index fd7bf85b..ddb375af 100644
--- a/opm/core/simulator/SimulatorOutput.cpp
+++ b/opm/core/simulator/SimulatorOutput.cpp
@@ -72,7 +72,7 @@ SimulatorOutputBase::operator std::function () {
void
SimulatorOutputBase::writeOutput () {
- const int this_time = timer_->currentTime ();
+ const int this_time = timer_->simulationTimeElapsed ();
// if the simulator signals for timesteps that aren't reporting
// times, then ignore them
diff --git a/opm/core/simulator/SimulatorTimer.cpp b/opm/core/simulator/SimulatorTimer.cpp
index fddc3aa8..b672b613 100644
--- a/opm/core/simulator/SimulatorTimer.cpp
+++ b/opm/core/simulator/SimulatorTimer.cpp
@@ -113,8 +113,8 @@ namespace Opm
return timesteps_[current_step_ - 1];
}
- /// Current time.
- double SimulatorTimer::currentTime() const
+ /// time elapsed since the start of the simulation [s].
+ double SimulatorTimer::simulationTimeElapsed() const
{
if (timeMap_)
return timeMap_->getTimePassedUntil(current_step_);
@@ -122,6 +122,12 @@ namespace Opm
return current_time_;
}
+ /// time elapsed since the start of the POSIX epoch (Jan 1st, 1970) [s].
+ time_t SimulatorTimer::currentPosixTime() const
+ {
+ tm t = boost::posix_time::to_tm(currentDateTime());
+ return std::mktime(&t);
+ }
boost::posix_time::ptime SimulatorTimer::currentDateTime() const
{
@@ -161,7 +167,7 @@ namespace Opm
void SimulatorTimer::report(std::ostream& os) const
{
os << "\n\n--------------- Simulation step number " << currentStepNum() << " ---------------"
- << "\n Current time (days) " << Opm::unit::convert::to(currentTime(), Opm::unit::day)
+ << "\n Current time (days) " << Opm::unit::convert::to(simulationTimeElapsed(), Opm::unit::day)
<< "\n Current stepsize (days) " << Opm::unit::convert::to(currentStepLength(), Opm::unit::day)
<< "\n Total time (days) " << Opm::unit::convert::to(totalTime(), Opm::unit::day)
<< "\n" << std::endl;
diff --git a/opm/core/simulator/SimulatorTimer.hpp b/opm/core/simulator/SimulatorTimer.hpp
index 949859e5..ad49282f 100644
--- a/opm/core/simulator/SimulatorTimer.hpp
+++ b/opm/core/simulator/SimulatorTimer.hpp
@@ -79,8 +79,13 @@ namespace Opm
/// it is an error to call stepLengthTaken().
double stepLengthTaken () const;
- /// Current time.
- double currentTime() const;
+ /// Time elapsed since the start of the POSIX epoch (Jan 1st,
+ /// 1970) until the current time step begins [s].
+ time_t currentPosixTime() const;
+
+ /// Time elapsed since the start of the simulation until the
+ /// beginning of the current time step [s].
+ double simulationTimeElapsed() const;
/// Return the current time as a posix time object.
boost::posix_time::ptime currentDateTime() const;