switch the EclWriter to the new tasklet infrastructure

This commit is contained in:
Andreas Lauser 2018-03-12 15:17:07 +01:00
parent 7b56e9e9df
commit 8f61fe03fa
2 changed files with 70 additions and 81 deletions

View File

@ -206,9 +206,14 @@ SET_BOOL_PROP(EclBaseProblem, EnableVtkOutput, false);
// ... but enable the ECL output by default // ... but enable the ECL output by default
SET_BOOL_PROP(EclBaseProblem, EnableEclOutput, true); SET_BOOL_PROP(EclBaseProblem, EnableEclOutput, true);
// Output single precision is default // If available, write the ECL output in a non-blocking manner
SET_BOOL_PROP(EclBaseProblem, EnableAsyncEclOutput, true);
// By default, use single precision for the ECL formated results
SET_BOOL_PROP(EclBaseProblem, EclOutputDoublePrecision, false); SET_BOOL_PROP(EclBaseProblem, EclOutputDoublePrecision, false);
// The default location for the ECL output files
SET_STRING_PROP(EclBaseProblem, EclOutputDir, ".");
// the cache for intensive quantities can be used for ECL problems and also yields a // the cache for intensive quantities can be used for ECL problems and also yields a
// decent speedup... // decent speedup...
@ -223,9 +228,6 @@ SET_TYPE_PROP(EclBaseProblem, FluxModule, Ewoms::EclTransFluxModule<TypeTag>);
// Use the dummy gradient calculator in order not to do unnecessary work. // Use the dummy gradient calculator in order not to do unnecessary work.
SET_TYPE_PROP(EclBaseProblem, GradientCalculator, Ewoms::EclDummyGradientCalculator<TypeTag>); SET_TYPE_PROP(EclBaseProblem, GradientCalculator, Ewoms::EclDummyGradientCalculator<TypeTag>);
// The default location for the ECL output files
SET_STRING_PROP(EclBaseProblem, EclOutputDir, ".");
// The frequency of writing restart (*.ers) files. This is the number of time steps // The frequency of writing restart (*.ers) files. This is the number of time steps
// between writing restart files // between writing restart files
SET_INT_PROP(EclBaseProblem, RestartWritingInterval, 0xffffff); // disable SET_INT_PROP(EclBaseProblem, RestartWritingInterval, 0xffffff); // disable

View File

@ -33,7 +33,7 @@
#include <ewoms/disc/ecfv/ecfvdiscretization.hh> #include <ewoms/disc/ecfv/ecfvdiscretization.hh>
#include <ewoms/io/baseoutputwriter.hh> #include <ewoms/io/baseoutputwriter.hh>
#include <ebos/threadhandle.hh> #include <ewoms/parallel/tasklets.hh>
#if HAVE_ECL_OUTPUT #if HAVE_ECL_OUTPUT
#include <opm/output/eclipse/EclipseIO.hpp> #include <opm/output/eclipse/EclipseIO.hpp>
@ -51,6 +51,7 @@
namespace Ewoms { namespace Ewoms {
namespace Properties { namespace Properties {
NEW_PROP_TAG(EnableEclOutput); NEW_PROP_TAG(EnableEclOutput);
NEW_PROP_TAG(EnableAsyncEclOutput);
NEW_PROP_TAG(EclOutputDoublePrecision); NEW_PROP_TAG(EclOutputDoublePrecision);
} }
@ -93,11 +94,16 @@ class EclWriter
typedef std::vector<Scalar> ScalarBuffer; typedef std::vector<Scalar> ScalarBuffer;
public: public:
static void registerParameters()
{
EWOMS_REGISTER_PARAM(TypeTag, bool, EnableAsyncEclOutput,
"Write the ECL-formated results in a non-blocking way (i.e., using a separate thread).");
}
EclWriter(const Simulator& simulator) EclWriter(const Simulator& simulator)
: simulator_(simulator) : simulator_(simulator)
, collectToIORank_(simulator_.vanguard()) , collectToIORank_(simulator_.vanguard())
, eclOutputModule_(simulator, collectToIORank_) , eclOutputModule_(simulator, collectToIORank_)
, asyncOutput_()
{ {
globalGrid_ = simulator_.vanguard().grid(); globalGrid_ = simulator_.vanguard().grid();
globalGrid_.switchToGlobalView(); globalGrid_.switchToGlobalView();
@ -108,22 +114,9 @@ public:
// create output thread if enabled and rank is I/O rank // create output thread if enabled and rank is I/O rank
// async output is enabled by default if pthread are enabled // async output is enabled by default if pthread are enabled
#if HAVE_PTHREAD bool enableAsyncOutput = EWOMS_GET_PARAM(TypeTag, bool, EnableAsyncEclOutput);
const bool asyncOutputDefault = true; bool createOutputThread = enableAsyncOutput && collectToIORank_.isIORank();
#else taskletRunner_.reset(new TaskletRunner(createOutputThread));
const bool asyncOutputDefault = false;
#endif
// TODO Add param
const bool isIORank = collectToIORank_.isParallel() && collectToIORank_.isIORank();
if( asyncOutputDefault && isIORank )
{
#if HAVE_PTHREAD
asyncOutput_.reset( new Opm::ThreadHandle( isIORank ) );
#else
throw std::runtime_error("Pthreads were not found, cannot enable async_output");
#endif
}
} }
~EclWriter() ~EclWriter()
@ -190,7 +183,6 @@ public:
// write output on I/O rank // write output on I/O rank
if (collectToIORank_.isIORank()) { if (collectToIORank_.isIORank()) {
std::map<std::string, std::vector<double>> extraRestartData; std::map<std::string, std::vector<double>> extraRestartData;
// Add suggested next timestep to extra data. // Add suggested next timestep to extra data.
@ -198,40 +190,37 @@ public:
extraRestartData["OPMEXTRA"] = std::vector<double>(1, nextstep); extraRestartData["OPMEXTRA"] = std::vector<double>(1, nextstep);
// Add TCPU // Add TCPU
if (totalSolverTime != 0.0) { if (totalSolverTime != 0.0)
miscSummaryData["TCPU"] = totalSolverTime; miscSummaryData["TCPU"] = totalSolverTime;
}
bool enableDoublePrecisionOutput = EWOMS_GET_PARAM(TypeTag, bool, EclOutputDoublePrecision); bool enableDoublePrecisionOutput = EWOMS_GET_PARAM(TypeTag, bool, EclOutputDoublePrecision);
const Opm::data::Solution& cellData = collectToIORank_.isParallel() ? collectToIORank_.globalCellData() : localCellData; const Opm::data::Solution& cellData = collectToIORank_.isParallel() ? collectToIORank_.globalCellData() : localCellData;
const Opm::data::Wells& wellData = collectToIORank_.isParallel() ? collectToIORank_.globalWellData() : localWellData; const Opm::data::Wells& wellData = collectToIORank_.isParallel() ? collectToIORank_.globalWellData() : localWellData;
const std::map<std::pair<std::string, int>, double>& blockData = collectToIORank_.isParallel() ? collectToIORank_.globalBlockData() : eclOutputModule_.getBlockData(); const std::map<std::pair<std::string, int>, double>& blockData
= collectToIORank_.isParallel()
? collectToIORank_.globalBlockData()
: eclOutputModule_.getBlockData();
if( asyncOutput_ ) { // first, create a tasklet to write the data for the current time step to disk
// dispatch the write call to the extra thread auto eclWriteTasklet = std::make_shared<EclWriteTasklet>(*eclIO_,
asyncOutput_->dispatch( WriterCall(*eclIO_, episodeIdx,
episodeIdx, substep,
substep, t,
t, cellData,
cellData, wellData,
wellData, miscSummaryData,
miscSummaryData, regionData,
regionData, blockData,
blockData, extraRestartData,
extraRestartData, enableDoublePrecisionOutput);
enableDoublePrecisionOutput ) );
} else { // then, make sure that the previous I/O request has been completed and the
eclIO_->writeTimeStep(episodeIdx, // number of incomplete tasklets does not increase between time steps
substep, taskletRunner_->barrier();
t,
cellData, // finally, start a new output writing job
wellData, taskletRunner_->dispatch(eclWriteTasklet);
miscSummaryData,
regionData,
blockData,
extraRestartData,
enableDoublePrecisionOutput);
}
} }
#endif #endif
} }
@ -429,12 +418,12 @@ private:
return nnc; return nnc;
} }
struct EclWriteTasklet
struct WriterCall : public Opm::ThreadHandle :: ObjectInterface : public TaskletInterface
{ {
Opm::EclipseIO& eclIO_; Opm::EclipseIO& eclIO_;
int episodeIdx_; int episodeIdx_;
bool isSubstep_; bool isSubStep_;
double secondsElapsed_; double secondsElapsed_;
Opm::data::Solution cellData_; Opm::data::Solution cellData_;
Opm::data::Wells wellData_; Opm::data::Wells wellData_;
@ -444,38 +433,36 @@ private:
std::map<std::string, std::vector<double>> extraRestartData_; std::map<std::string, std::vector<double>> extraRestartData_;
bool writeDoublePrecision_; bool writeDoublePrecision_;
explicit WriterCall( explicit EclWriteTasklet(Opm::EclipseIO& eclIO,
Opm::EclipseIO& eclIO, int episodeIdx,
int episodeIdx, bool isSubStep,
bool isSubstep, double secondsElapsed,
double secondsElapsed, Opm::data::Solution cellData,
Opm::data::Solution cellData, Opm::data::Wells wellData,
Opm::data::Wells wellData, const std::map<std::string, double>& singleSummaryValues,
const std::map<std::string, double>& singleSummaryValues, const std::map<std::string, std::vector<double>>& regionSummaryValues,
const std::map<std::string, std::vector<double>>& regionSummaryValues, const std::map<std::pair<std::string, int>, double>& blockSummaryValues,
const std::map<std::pair<std::string, int>, double>& blockSummaryValues, const std::map<std::string, std::vector<double>>& extraRestartData,
const std::map<std::string, std::vector<double>>& extraRestartData, bool writeDoublePrecision)
bool writeDoublePrecision) : eclIO_(eclIO)
: eclIO_(eclIO), , episodeIdx_(episodeIdx)
episodeIdx_(episodeIdx), , isSubStep_(isSubStep)
isSubstep_(isSubstep), , secondsElapsed_(secondsElapsed)
secondsElapsed_(secondsElapsed), , cellData_(cellData)
cellData_(cellData), , wellData_(wellData)
wellData_(wellData), , singleSummaryValues_(singleSummaryValues)
singleSummaryValues_(singleSummaryValues), , regionSummaryValues_(regionSummaryValues)
regionSummaryValues_(regionSummaryValues), , blockSummaryValues_(blockSummaryValues)
blockSummaryValues_(blockSummaryValues), , extraRestartData_(extraRestartData)
extraRestartData_(extraRestartData), , writeDoublePrecision_(writeDoublePrecision)
writeDoublePrecision_(writeDoublePrecision) { }
{
}
// callback to eclIO serial writeTimeStep method // callback to eclIO serial writeTimeStep method
void run () void run ()
{ {
// write data // write data
eclIO_.writeTimeStep(episodeIdx_, eclIO_.writeTimeStep(episodeIdx_,
isSubstep_, isSubStep_,
secondsElapsed_, secondsElapsed_,
cellData_, cellData_,
wellData_, wellData_,
@ -495,7 +482,7 @@ private:
EclOutputBlackOilModule<TypeTag> eclOutputModule_; EclOutputBlackOilModule<TypeTag> eclOutputModule_;
std::unique_ptr<Opm::EclipseIO> eclIO_; std::unique_ptr<Opm::EclipseIO> eclIO_;
Grid globalGrid_; Grid globalGrid_;
std::unique_ptr< Opm::ThreadHandle > asyncOutput_; std::unique_ptr<TaskletRunner> taskletRunner_;
}; };