Merge remote-tracking branch 'upstream/master' into opm-parser-integrate

This commit is contained in:
Joakim Hove 2013-12-02 15:02:30 +01:00
commit 0fc56949ef
15 changed files with 1736 additions and 619 deletions

View File

@ -37,10 +37,11 @@ list (APPEND MAIN_SOURCE_FILES
opm/core/grid/cpgpreprocess/geometry.c
opm/core/grid/cpgpreprocess/preprocess.c
opm/core/grid/cpgpreprocess/uniquepoints.c
opm/core/io/eclipse/BlackoilEclipseOutputWriter.cpp
opm/core/io/eclipse/EclipseGridInspector.cpp
opm/core/io/eclipse/EclipseGridParser.cpp
opm/core/io/eclipse/EclipseWriter.cpp
opm/core/io/eclipse/writeECLData.cpp
opm/core/io/OutputWriter.cpp
opm/core/io/vag/vag.cpp
opm/core/io/vtk/writeVtkData.cpp
opm/core/linalg/LinearSolverFactory.cpp
@ -98,6 +99,7 @@ list (APPEND MAIN_SOURCE_FILES
opm/core/simulator/BlackoilState.cpp
opm/core/simulator/SimulatorCompressibleTwophase.cpp
opm/core/simulator/SimulatorIncompTwophase.cpp
opm/core/simulator/SimulatorOutput.cpp
opm/core/simulator/SimulatorReport.cpp
opm/core/simulator/SimulatorState.cpp
opm/core/simulator/SimulatorTimer.cpp
@ -231,14 +233,15 @@ list (APPEND PUBLIC_HEADER_FILES
opm/core/grid/cpgpreprocess/grdecl.h
opm/core/grid/cpgpreprocess/preprocess.h
opm/core/grid/cpgpreprocess/uniquepoints.h
opm/core/io/eclipse/BlackoilEclipseOutputWriter.hpp
opm/core/io/eclipse/CornerpointChopper.hpp
opm/core/io/eclipse/EclipseGridInspector.hpp
opm/core/io/eclipse/EclipseGridParser.hpp
opm/core/io/eclipse/EclipseGridParserHelpers.hpp
opm/core/io/eclipse/EclipseUnits.hpp
opm/core/io/eclipse/EclipseWriter.hpp
opm/core/io/eclipse/SpecialEclipseFields.hpp
opm/core/io/eclipse/writeECLData.hpp
opm/core/io/OutputWriter.hpp
opm/core/io/vag/vag.hpp
opm/core/io/vtk/writeVtkData.hpp
opm/core/linalg/LinearSolverFactory.hpp
@ -306,6 +309,7 @@ list (APPEND PUBLIC_HEADER_FILES
opm/core/simulator/BlackoilState.hpp
opm/core/simulator/SimulatorCompressibleTwophase.hpp
opm/core/simulator/SimulatorIncompTwophase.hpp
opm/core/simulator/SimulatorOutput.hpp
opm/core/simulator/SimulatorReport.hpp
opm/core/simulator/SimulatorState.hpp
opm/core/simulator/SimulatorTimer.hpp
@ -375,6 +379,7 @@ list (APPEND PUBLIC_HEADER_FILES
opm/core/utility/parameters/tinyxml/tinystr.h
opm/core/utility/parameters/tinyxml/tinyxml.h
opm/core/utility/PropertySystem.hpp
opm/core/utility/share_obj.hpp
opm/core/wells/InjectionSpecification.hpp
opm/core/wells/ProductionSpecification.hpp
opm/core/wells/WellCollection.hpp

View File

@ -0,0 +1,96 @@
#include "OutputWriter.hpp"
#include <opm/core/io/eclipse/EclipseWriter.hpp>
#include <opm/core/utility/parameters/Parameter.hpp>
#include <opm/core/utility/parameters/ParameterGroup.hpp>
#include <forward_list>
#include <map>
#include <memory> // unique_ptr
using namespace std;
using namespace Opm;
using namespace Opm::parameter;
namespace {
/// Multiplexer over a list of output writers
struct MultiWriter : public OutputWriter {
/// Shorthand for a list of owned output writers
typedef forward_list <unique_ptr <OutputWriter> > writers_t;
typedef writers_t::iterator it_t;
typedef unique_ptr <writers_t> ptr_t;
/// Adopt a list of writers
MultiWriter (ptr_t writers) : writers_ (std::move (writers)) { }
/// Forward the call to all writers
virtual void writeInit(const SimulatorTimer &timer,
const SimulatorState& reservoirState,
const WellState& wellState) {
for (it_t it = writers_->begin (); it != writers_->end (); ++it) {
(*it)->writeInit (timer, reservoirState, wellState);
}
}
virtual void writeTimeStep(const SimulatorTimer& timer,
const SimulatorState& reservoirState,
const WellState& wellState) {
for (it_t it = writers_->begin (); it != writers_->end(); ++it) {
(*it)->writeTimeStep (timer, reservoirState, wellState);
}
}
private:
ptr_t writers_;
};
/// Psuedo-constructor, can appear in template
template <typename Format> unique_ptr <OutputWriter>
create (const ParameterGroup& params,
std::shared_ptr <const EclipseGridParser> parser,
std::shared_ptr <const UnstructuredGrid> grid) {
return unique_ptr <OutputWriter> (new Format (params, parser, grid));
}
/// Map between keyword in configuration and the corresponding
/// constructor function (type) that should be called when detected.
/// The writer must have a constructor which takes params and parser.
///
/// If you want to add more possible writer formats, just add them
/// to the list below!
typedef map <const char*, unique_ptr <OutputWriter> (*)(
const ParameterGroup&,
std::shared_ptr <const EclipseGridParser>,
std::shared_ptr <const UnstructuredGrid>)> map_t;
map_t FORMATS = {
{ "output_ecl", &create <EclipseWriter> },
};
} // anonymous namespace
unique_ptr <OutputWriter>
OutputWriter::create (const ParameterGroup& params,
std::shared_ptr <const EclipseGridParser> parser,
std::shared_ptr <const UnstructuredGrid> grid) {
// allocate a list which will be filled with writers. this list
// is initially empty (no output).
MultiWriter::ptr_t list (new MultiWriter::writers_t ());
// loop through the map and see if we can find the key that is
// specified there
typedef map_t::iterator map_it_t;
for (map_it_t it = FORMATS.begin (); it != FORMATS.end(); ++it) {
// keyword which would indicate that this format should be used
const std::string name (it->first);
// invoke the constructor for the type if we found the keyword
// and put the pointer to this writer onto the list
if (params.getDefault <bool> (name, false)) {
list->push_front (it->second (params, parser, grid));
}
}
// create a multiplexer from the list of formats we found
return unique_ptr <OutputWriter> (new MultiWriter (std::move (list)));
}

View File

@ -0,0 +1,117 @@
/*
Copyright (c) 2013 Uni Research AS
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 <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_OUTPUT_WRITER_HPP
#define OPM_OUTPUT_WRITER_HPP
#include <memory> // unique_ptr, shared_ptr
struct UnstructuredGrid;
namespace Opm {
// forward declaration
class EclipseGridParser;
namespace parameter { class ParameterGroup; }
class SimulatorState;
class SimulatorTimer;
class WellState;
/*!
* Interface for writing non-compositional (blackoil, two-phase) simulation
* state to files.
*
* Use the create() function to setup a chain of writer based on the
* configuration values, e.g.
*
* \example
* \code{.cpp}
* ParameterGroup params (argc, argv, false);
* auto parser = std::make_shared <EclipseGridParser> (
* params.get <string> ("deck_filename"));
*
* std::unique_ptr <OutputWriter> writer =
* OutputWriter::create (params, parser);
*
* // before the first timestep
* writer->writeInit (timer);
*
* // after each timestep
* writer->writeTimeStep (timer, state, wellState);
*
* \endcode
*/
class OutputWriter {
public:
/// Allow derived classes to be used in the unique_ptr that is returned
/// from the create() method. (Every class that should be delete'd should
/// have a proper constructor, and if the base class isn't virtual then
/// the compiler won't call the right one when the unique_ptr goes out of
/// scope).
virtual ~OutputWriter () { }
/**
* Write the static eclipse data (grid, PVT curves, etc) as well as the
* initial state to disk.
*
* This routine should be called before the first timestep (i.e. when
* timer.currentStepNum () == 0)
*/
virtual void writeInit(const SimulatorTimer &timer,
const SimulatorState& reservoirState,
const WellState& wellState) = 0;
/*!
* \brief Write a blackoil reservoir state to disk for later inspection with
* visualization tools like ResInsight
*
* \param[in] reservoirState The thermodynamic state of the reservoir
* \param[in] wellState The production/injection data for all wells
*
* This routine should be called after the timestep has been advanced,
* i.e. timer.currentStepNum () > 0.
*/
virtual void writeTimeStep(const SimulatorTimer& timer,
const SimulatorState& reservoirState,
const WellState& wellState) = 0;
/*!
* Create a suitable set of output formats based on configuration.
*
* @param params Configuration properties. This function will setup a
* multiplexer of applicable output formats based on the
* desired configuration values.
*
* @param parser Input deck used to set up the simulation. The lifetime
* of this object must exceed the lifetime of the writer
* that is returned.
*
* @return Pointer to a multiplexer to all applicable output formats.
*
* @see Opm::share_obj
*/
static std::unique_ptr <OutputWriter>
create (const parameter::ParameterGroup& params,
std::shared_ptr <const EclipseGridParser> parser,
std::shared_ptr <const UnstructuredGrid> grid);
};
} // namespace Opm
#endif /* OPM_OUTPUT_WRITER_HPP */

View File

@ -1,459 +0,0 @@
/*
Copyright 2013 Andreas Lauser
Copyright 2013 SINTEF ICT, Applied Mathematics.
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 <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include "BlackoilEclipseOutputWriter.hpp"
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/format.hpp>
#include <opm/core/simulator/BlackoilState.hpp>
#include <opm/core/io/eclipse/EclipseGridParser.hpp>
#include <opm/core/props/BlackoilPhases.hpp>
#include <opm/core/utility/Units.hpp>
#include <opm/core/utility/ErrorMacros.hpp>
#include <opm/core/utility/DataMap.hpp>
#ifdef HAVE_ERT
#include <ert/ecl/fortio.h>
#include <ert/ecl/ecl_grid.h>
#include <ert/ecl/ecl_kw_magic.h>
#include <ert/ecl/ecl_kw.h>
#include <ert/ecl/ecl_sum.h>
#include <ert/ecl/ecl_util.h>
#include <ert/ecl/ecl_init_file.h>
#include <ert/ecl/ecl_file.h>
#include <ert/ecl/ecl_rst_file.h>
#endif
namespace Opm {
void BlackoilEclipseOutputWriter::writeInitFile(const SimulatorTimer &timer)
{
tm tm = boost::posix_time::to_tm(timer.currentDateTime());
startTime_ = mktime(&tm);
#if HAVE_ERT
writeGridInitFile_(timer);
writeSummaryHeaderFile_(timer);
#else
OPM_THROW(std::runtime_error,
"The ERT libraries are required to write ECLIPSE output files.");
#endif // HAVE_ERT
}
void BlackoilEclipseOutputWriter::writeReservoirState(const BlackoilState& reservoirState, const SimulatorTimer& timer)
{
#if HAVE_ERT
ecl_file_enum file_type = ECL_UNIFIED_RESTART_FILE; // Alternatively ECL_RESTART_FILE for multiple restart files.
bool fmt_file = false;
char *fileName = ecl_util_alloc_filename(outputDir_.c_str(),
baseName_.c_str(),
/*file_type=*/ECL_UNIFIED_RESTART_FILE,
fmt_file,
timer.currentStepNum());
int phases = ECL_OIL_PHASE + ECL_GAS_PHASE + ECL_WATER_PHASE;
double days = Opm::unit::convert::to(timer.currentTime(), Opm::unit::day);
int nx = grid_.cartdims[0];
int ny = grid_.cartdims[1];
int nz = grid_.cartdims[2];
int nactive = grid_.number_of_cells;
ecl_rst_file_type* rst_file;
time_t curTime;
tm tm = boost::posix_time::to_tm(timer.currentDateTime());
curTime = mktime(&tm);
if (timer.currentStepNum() > 0 && file_type == ECL_UNIFIED_RESTART_FILE)
rst_file = ecl_rst_file_open_append(fileName);
else
rst_file = ecl_rst_file_open_write(fileName);
ecl_rst_file_fwrite_header(rst_file, timer.currentStepNum(), curTime, days, nx, ny, nz, nactive, phases);
ecl_rst_file_start_solution(rst_file);
{
// convert the pressures from Pascals to bar because eclipse
// seems to write bars
std::vector<double> pressureBar(reservoirState.pressure());
auto it = pressureBar.begin();
const auto &endIt = pressureBar.end();
for (; it != endIt; ++it)
(*it) /= 1e5;
ecl_kw_type* pressure_kw = newEclDoubleKeyword_("PRESSURE", pressureBar);
ecl_rst_file_add_kw(rst_file, pressure_kw);
ecl_kw_free(pressure_kw);
}
{
ecl_kw_type* swat_kw = newEclDoubleKeyword_("SWAT", reservoirState.saturation(), /*offset=*/0, /*stride=*/3);
ecl_rst_file_add_kw(rst_file, swat_kw);
ecl_kw_free(swat_kw);
}
{
ecl_kw_type* soil_kw = newEclDoubleKeyword_("SOIL", reservoirState.saturation(), /*offset=*/1, /*stride=*/3);
ecl_rst_file_add_kw(rst_file, soil_kw);
ecl_kw_free(soil_kw);
}
{
ecl_kw_type* sgas_kw = newEclDoubleKeyword_("SGAS", reservoirState.saturation(), /*offset=*/2, /*stride=*/3);
ecl_rst_file_add_kw(rst_file, sgas_kw);
ecl_kw_free(sgas_kw);
}
ecl_rst_file_end_solution(rst_file);
ecl_rst_file_close(rst_file);
free(fileName);
#else
OPM_THROW(std::runtime_error,
"The ERT libraries are required to write ECLIPSE output files.");
#endif // HAVE_ERT
}
void BlackoilEclipseOutputWriter::writeWellState(const WellState& wellState, const SimulatorTimer& timer)
{
#if HAVE_ERT
tm tm = boost::posix_time::to_tm(timer.currentDateTime());
time_t curTime = mktime(&tm);
// create a new timestep for the summary file (at least if the
// timer was advanced since the last call to writeWellState())
ecl_sum_tstep_type* tstep=
ecl_sum_add_tstep(sumWriter_,
timer.currentStepNum() + 1,
(curTime - startTime_)/(24*60*60));
int numWells = accumulatedProducedFluids_.size();
for (int wellIdx = 0; wellIdx < numWells; ++wellIdx) {
// set the value for the well oil production rate. For this,
// be aware that the rates in the well state are _surface_
// volume rates...
double woprValue = wellState.wellRates()[wellIdx*3 + BlackoilPhases::Liquid];
woprValue *= - 1 * (24 * 60 * 60); // convert m^3/s of injected fluid to m^3/d of produced fluid
woprValue = std::max(0.0, woprValue);
int woprIdx = smspec_node_get_params_index(woprSmspec_[wellIdx]);
ecl_sum_tstep_iset(tstep, woprIdx, woprValue);
// set the value for the well gas production rate
double wgprValue = wellState.wellRates()[wellIdx*3 + BlackoilPhases::Vapour];
wgprValue *= - 1 * (24 * 60 * 60); // convert m^3/s of injected fluid to m^3/d of produced fluid
wgprValue = std::max(0.0, wgprValue);
int wgprIdx = smspec_node_get_params_index(wgprSmspec_[wellIdx]);
ecl_sum_tstep_iset(tstep, wgprIdx, wgprValue);
// water injection rate
double wwirValue = wellState.wellRates()[wellIdx*3 + BlackoilPhases::Aqua];
wwirValue *= 1 * (24 * 60 * 60); // convert m^3/s to m^3/d
wwirValue = std::max(0.0, wwirValue);
int wwirIdx = smspec_node_get_params_index(wwirSmspec_[wellIdx]);
ecl_sum_tstep_iset(tstep, wwirIdx, wwirValue);
// gas injection rate
double wgirValue = wellState.wellRates()[wellIdx*3 + BlackoilPhases::Vapour];
wgirValue *= - 1 * (24 * 60 * 60); // convert m^3/s of injected fluid to m^3/d of produced fluid
wgirValue = std::max(0.0, wgirValue);
int wgirIdx = smspec_node_get_params_index(wgirSmspec_[wellIdx]);
ecl_sum_tstep_iset(tstep, wgirIdx, wgirValue);
// accumulate injected produced fluids
for (int phaseIdx = 0; phaseIdx < /*numPhases=*/3; ++phaseIdx) {
// accumulate the produced/injected surface volumes
double injectedVolume = wellState.wellRates()[wellIdx*3 + phaseIdx];
injectedVolume *= timer.currentStepLength();
if (injectedVolume < 0)
accumulatedProducedFluids_[wellIdx][phaseIdx] += -injectedVolume;
else
accumulatedInjectedFluids_[wellIdx][phaseIdx] += injectedVolume;
int woptIdx = smspec_node_get_params_index(woptSmspec_[wellIdx]);
ecl_sum_tstep_iset(tstep, woptIdx, accumulatedProducedFluids_[wellIdx][BlackoilPhases::Liquid]);
int wgptIdx = smspec_node_get_params_index(wgptSmspec_[wellIdx]);
ecl_sum_tstep_iset(tstep, wgptIdx, accumulatedProducedFluids_[wellIdx][BlackoilPhases::Vapour]);
int wwitIdx = smspec_node_get_params_index(wwitSmspec_[wellIdx]);
ecl_sum_tstep_iset(tstep, wwitIdx, accumulatedInjectedFluids_[wellIdx][BlackoilPhases::Aqua]);
int wgitIdx = smspec_node_get_params_index(wgitSmspec_[wellIdx]);
ecl_sum_tstep_iset(tstep, wgitIdx, accumulatedProducedFluids_[wellIdx][BlackoilPhases::Vapour]);
}
}
ecl_sum_fwrite(sumWriter_);
#else
OPM_THROW(std::runtime_error,
"The ERT libraries are required to write ECLIPSE output files.");
#endif // HAVE_ERT
}
#if HAVE_ERT
void BlackoilEclipseOutputWriter::writeGridInitFile_(const SimulatorTimer &timer)
{
int phases = ECL_OIL_PHASE + ECL_GAS_PHASE + ECL_WATER_PHASE;
bool endian_flip = true;//ECL_ENDIAN_FLIP;
bool fmt_file = false;
ecl_file_enum file_type = ECL_EGRID_FILE;
ecl_grid_type* ecl_grid = newEclGrid_();
char* gridFileName = ecl_util_alloc_filename(outputDir_.c_str(), baseName_.c_str(), file_type, fmt_file, timer.currentStepNum());
fortio_type* fortio;
ecl_grid_fwrite_EGRID(ecl_grid, gridFileName);
free(gridFileName);
char* initFileName = ecl_util_alloc_filename(outputDir_.c_str(), baseName_.c_str(), /*file_type=*/ECL_INIT_FILE, fmt_file, timer.currentStepNum());
if (!ecl_util_fmt_file(initFileName, &fmt_file)) {
OPM_THROW(std::runtime_error,
"Could not determine formatted/unformatted status of file:" << initFileName << " non-standard name?" << std::endl);
}
fortio = fortio_open_writer(initFileName, fmt_file, endian_flip);
{
time_t start_date;
{
boost::posix_time::ptime start_date_(timer.currentDateTime());
tm td_tm = boost::posix_time::to_tm(start_date_);
start_date = mktime(&td_tm);
}
ecl_kw_type* poro_kw = newEclDoubleKeyword_(PORO_KW, eclipseParser_.getFloatingPointValue("PORO"));
ecl_init_file_fwrite_header(fortio, ecl_grid, poro_kw, phases, start_date);
ecl_kw_free(poro_kw);
}
/* This collection of keywords is somewhat arbitrary and random. */
saveEclKeyword_(fortio, "PERMX", ECL_FLOAT_TYPE);
saveEclKeyword_(fortio, "PERMY", ECL_FLOAT_TYPE);
saveEclKeyword_(fortio, "PERMZ", ECL_FLOAT_TYPE);
fortio_fclose(fortio);
free(initFileName);
}
void BlackoilEclipseOutputWriter::writeSummaryHeaderFile_(const SimulatorTimer &timer)
{
std::string caseName;
if (!outputDir_.empty())
caseName += outputDir_ + "/";
caseName += baseName_;
if (sumWriter_)
ecl_sum_free(sumWriter_);
// allocate the data structure for the writer
sumWriter_ =
ecl_sum_alloc_writer(caseName.c_str(),
/*formattedOutput=*/false,
/*unifiedOutput=*/true,
/*joinString=*/":",
startTime_,
grid_.cartdims[0],grid_.cartdims[1],grid_.cartdims[2]);
// initialize the accumulated masses to zero
const auto &wellSpecs = eclipseParser_.getWELSPECS().welspecs;
int numWells = wellSpecs.size();
accumulatedProducedFluids_.resize(numWells);
accumulatedInjectedFluids_.resize(numWells);
for (int wellIdx = 0; wellIdx < numWells; ++wellIdx) {
for (int phaseIdx = 0; phaseIdx < /*numPhases=*/3; ++phaseIdx) {
accumulatedProducedFluids_[wellIdx][phaseIdx] = 0;
accumulatedInjectedFluids_[wellIdx][phaseIdx] = 0;
}
}
woprSmspec_.resize(numWells);
woptSmspec_.resize(numWells);
wgprSmspec_.resize(numWells);
wgptSmspec_.resize(numWells);
wwirSmspec_.resize(numWells);
wwitSmspec_.resize(numWells);
wgirSmspec_.resize(numWells);
wgitSmspec_.resize(numWells);
auto wellIt = wellSpecs.begin();
const auto &wellEndIt = wellSpecs.end();
for (int wellIdx = 0; wellIt != wellEndIt; ++wellIt, ++wellIdx) {
// add the variables which ought to be included in the summary
// file
woprSmspec_[wellIdx] = ecl_sum_add_var(sumWriter_,
/*varName=*/"WOPR",
/*wellGroupName=*/wellIt->name_.c_str(),
/*num=*/0,
/*unit=*/"SM3/DAY",
/*defaultValue=*/0.0);
woptSmspec_[wellIdx] = ecl_sum_add_var(sumWriter_,
/*varName=*/"WOPT",
/*wellGroupName=*/wellIt->name_.c_str(),
/*num=*/0,
/*unit=*/"SM3",
/*defaultValue=*/0.0);
wgprSmspec_[wellIdx] = ecl_sum_add_var(sumWriter_,
/*varName=*/"WGPR",
/*wellGroupName=*/wellIt->name_.c_str(),
/*num=*/0,
/*unit=*/"SM3/DAY",
/*defaultValue=*/0.0);
wgptSmspec_[wellIdx] = ecl_sum_add_var(sumWriter_,
/*varName=*/"WGPT",
/*wellGroupName=*/wellIt->name_.c_str(),
/*num=*/0,
/*unit=*/"SM3",
/*defaultValue=*/0.0);
wwirSmspec_[wellIdx] = ecl_sum_add_var(sumWriter_,
/*varName=*/"WWIR",
/*wellGroupName=*/wellIt->name_.c_str(),
/*num=*/0,
/*unit=*/"SM3/DAY",
/*defaultValue=*/0.0);
wwitSmspec_[wellIdx] = ecl_sum_add_var(sumWriter_,
/*varName=*/"WWIT",
/*wellGroupName=*/wellIt->name_.c_str(),
/*num=*/0,
/*unit=*/"SM3",
/*defaultValue=*/0.0);
wgirSmspec_[wellIdx] = ecl_sum_add_var(sumWriter_,
/*varName=*/"WGIR",
/*wellGroupName=*/wellIt->name_.c_str(),
/*num=*/0,
/*unit=*/"SM3/DAY",
/*defaultValue=*/0.0);
wgitSmspec_[wellIdx] = ecl_sum_add_var(sumWriter_,
/*varName=*/"WGIT",
/*wellGroupName=*/wellIt->name_.c_str(),
/*num=*/0,
/*unit=*/"SM3",
/*defaultValue=*/0.0);
}
ecl_sum_fwrite(sumWriter_);
}
ecl_grid_type* BlackoilEclipseOutputWriter::newEclGrid_()
{
if (eclipseParser_.hasField("DXV")) {
// make sure that the DYV and DZV keywords are present if the
// DXV keyword is used in the deck...
assert(eclipseParser_.hasField("DYV"));
assert(eclipseParser_.hasField("DZV"));
const auto &dxv = eclipseParser_.getFloatingPointValue("DXV");
const auto &dyv = eclipseParser_.getFloatingPointValue("DYV");
const auto &dzv = eclipseParser_.getFloatingPointValue("DZV");
// creating a C array out of std::vector like this is pretty
// hacky and might even be unportable. having said that, it
// probably works with all currently known STL
// implementations...
return ecl_grid_alloc_dxv_dyv_dzv(dxv.size(), dyv.size(), dzv.size(),
&dxv[0], &dyv[0], &dzv[0],
/*actnum=*/NULL);
}
if (eclipseParser_.hasField("ZCORN")) {
struct grdecl grdecl = eclipseParser_.get_grdecl();
ecl_kw_type * coord_kw = newEclDoubleKeyword_(COORD_KW, eclipseParser_.getFloatingPointValue("COORD"));
ecl_kw_type * zcorn_kw = newEclDoubleKeyword_(ZCORN_KW, eclipseParser_.getFloatingPointValue("ZCORN"));
ecl_kw_type * actnum_kw = newEclIntKeyword_(ACTNUM_KW, eclipseParser_.getIntegerValue("ACTNUM"));
ecl_kw_type * mapaxes_kw = NULL;
ecl_grid_type * grid ;
if (grdecl.mapaxes != NULL)
mapaxes_kw = newEclDoubleKeyword_(MAPAXES_KW, eclipseParser_.getFloatingPointValue("MAPAXES"));
grid = ecl_grid_alloc_GRDECL_kw(grdecl.dims[0], grdecl.dims[1], grdecl.dims[2], zcorn_kw, coord_kw, actnum_kw, mapaxes_kw);
ecl_kw_free(coord_kw);
ecl_kw_free(zcorn_kw);
ecl_kw_free(actnum_kw);
if (mapaxes_kw != NULL)
ecl_kw_free(mapaxes_kw);
return grid;
}
OPM_THROW(std::runtime_error,
"Can't create an ERT grid (no supported keywords found in deck)");
}
ecl_kw_type* BlackoilEclipseOutputWriter::newEclIntKeyword_(const std::string& kwName,
const std::vector<int> &data,
int offset,
int stride)
{
assert(offset >= 0 && offset < data.size());
assert(stride > 0 && stride < data.size() - offset);
ecl_kw_type* eclKw =
ecl_kw_alloc(kwName.c_str(),
grid_.number_of_cells, ECL_INT_TYPE);
for (int i=0; i < grid_.number_of_cells; i++)
ecl_kw_iset_float(eclKw, i, data[i*stride + offset]);
return eclKw;
}
ecl_kw_type* BlackoilEclipseOutputWriter::newEclDoubleKeyword_(const std::string& kwName,
const std::vector<double> &data,
int offset,
int stride)
{
assert(offset >= 0 && offset < data.size());
assert(stride > 0 && stride < data.size() - offset);
ecl_kw_type* eclKw =
ecl_kw_alloc(kwName.c_str(),
grid_.number_of_cells, ECL_FLOAT_TYPE);
for (int i=0; i < grid_.number_of_cells; i++)
ecl_kw_iset_float(eclKw, i, static_cast<float>(data[i*stride + offset]));
return eclKw;
}
void BlackoilEclipseOutputWriter::saveEclKeyword_(fortio_type* fortio, const std::string& kw, ecl_type_enum eclType)
{
ecl_kw_type* eclKw;
if (eclType == ECL_INT_TYPE)
eclKw = newEclIntKeyword_(kw, eclipseParser_.getIntegerValue(kw));
else if (eclType == ECL_FLOAT_TYPE)
eclKw = newEclDoubleKeyword_(kw, eclipseParser_.getFloatingPointValue(kw));
else
OPM_THROW(std::logic_error,
"Not implemented: ECL keywords of type " << ECL_FLOAT_TYPE);
if (eclKw != NULL) {
ecl_kw_fwrite(eclKw, fortio);
ecl_kw_free(eclKw);
}
}
#endif // HAVE_ERT
} // namespace Opm

View File

@ -1,154 +0,0 @@
/*
Copyright 2013 Andreas Lauser
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 <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_BLACKOIL_ECLIPSE_OUTPUT_WRITER_HPP
#define OPM_BLACKOIL_ECLIPSE_OUTPUT_WRITER_HPP
#include <opm/core/grid.h>
#include <opm/core/io/eclipse/EclipseGridParser.hpp>
#include <opm/core/simulator/BlackoilState.hpp>
#include <opm/core/simulator/SimulatorTimer.hpp>
#include <opm/core/simulator/WellState.hpp>
#include <list>
#include <string>
#include <array>
#include <vector>
#ifdef HAVE_ERT
#include <ert/ecl/fortio.h>
#include <ert/ecl/ecl_file.h>
#include <ert/ecl/ecl_grid.h>
#include <ert/ecl/ecl_init_file.h>
#include <ert/ecl/ecl_kw_magic.h>
#include <ert/ecl/ecl_kw.h>
#include <ert/ecl/ecl_sum.h>
#include <ert/ecl/ecl_util.h>
#endif
#include <string>
namespace Opm {
/*!
* \brief A class to write the reservoir state and the well state of a
* blackoil simulation to disk using the Eclipse binary format.
*
* This class only writes files if the 'write_output' parameter is set
* to 1. It needs the ERT libraries to write to disk, so if the
* 'write_output' parameter is set but ERT is not available, all
* methods throw a std::runtime_error.
*/
class BlackoilEclipseOutputWriter
{
public:
/*!
* \brief Sets the common attributes required to write eclipse
* binary files using ERT.
*/
BlackoilEclipseOutputWriter(const EclipseGridParser& eclipseParser,
const UnstructuredGrid& grid,
const std::string &outputDir,
const std::string &baseName)
: eclipseParser_(eclipseParser)
, grid_(grid)
, outputDir_(outputDir)
, baseName_(baseName)
{
#if HAVE_ERT
sumWriter_ = 0;
#endif
}
~BlackoilEclipseOutputWriter()
{
#if HAVE_ERT
if (sumWriter_) {
// clean after ourselfs
ecl_sum_free(sumWriter_);
}
#endif
}
/*!
* \brief Write the static eclipse data (grid, PVT curves, etc) to disk
*/
void writeInitFile(const SimulatorTimer &timer);
/*!
* \brief Write a blackoil reservoir state to disk for later inspection with
* visualization tools like ResInsight
*
* \param[in] reservoirState The thermodynamic state of the reservoir
*/
void writeReservoirState(const BlackoilState& reservoirState,
const SimulatorTimer& timer);
/*!
* \brief Write a well state to disk for later inspection with
* visualization tools
*
* \param[in] wellState The production/injection data for all wells
*/
void writeWellState(const WellState& wellState, const SimulatorTimer& timer);
private:
const EclipseGridParser& eclipseParser_;
const UnstructuredGrid& grid_;
std::string outputDir_;
std::string baseName_;
time_t startTime_;
#if HAVE_ERT
void writeSummaryHeaderFile_(const SimulatorTimer &timer);
void writeGridInitFile_(const SimulatorTimer &timer);
ecl_grid_type* newEclGrid_();
ecl_kw_type* newEclIntKeyword_(const std::string& kwName,
const std::vector<int> &data,
int offset = 0,
int stride = 1);
ecl_kw_type* newEclDoubleKeyword_(const std::string& kwName,
const std::vector<double> &data,
int offset = 0,
int stride = 1);
void saveEclKeyword_(fortio_type* fortio, const std::string& keyword, ecl_type_enum ecl_type);
// keyword handles per well each
std::vector<smspec_node_type*> woprSmspec_;
std::vector<smspec_node_type*> woptSmspec_;
std::vector<smspec_node_type*> wgprSmspec_;
std::vector<smspec_node_type*> wgptSmspec_;
std::vector<smspec_node_type*> wwirSmspec_;
std::vector<smspec_node_type*> wwitSmspec_;
std::vector<smspec_node_type*> wgirSmspec_;
std::vector<smspec_node_type*> wgitSmspec_;
ecl_sum_type* sumWriter_;
std::vector<std::array<double, /*numPhases=*/3> > accumulatedProducedFluids_;
std::vector<std::array<double, /*numPhases=*/3> > accumulatedInjectedFluids_;
#endif
};
} // namespace Opm
#endif // OPM_BLACKOIL_ECLIPSE_OUTPUT_WRITER_HPP

View File

@ -1178,4 +1178,16 @@ void EclipseGridParser::getNumericErtFields(const string& filename)
#endif // HAVE_ERT
}
// specializations for those types that can be provided; attempts
// to access other types than these will result in linker error
template <> const std::vector<int>&
EclipseGridParser::getValue<int> (const std::string& keyword) const {
return this->getIntegerValue(keyword);
}
template <> const std::vector<double>&
EclipseGridParser::getValue<double> (const std::string& keyword) const {
return this->getFloatingPointValue(keyword);
}
} // namespace Opm

View File

@ -138,6 +138,15 @@ namespace Opm
/// corresponding to the given floating-point keyword.
const std::vector<double>& getFloatingPointValue(const std::string& keyword) const;
/// Returns a reference to a vector containing the values
/// corresponding to the given keyword of a type only known
/// indirectly (through a template)
///
/// \tparam T Type of the keyword's value. Currently only int
/// and double are supported.
template <typename T>
const std::vector<T>& getValue(const std::string& keyword) const;
typedef std::shared_ptr<SpecialBase> SpecialFieldPtr;
/// Returns a reference to a vector containing pointers to the values

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,102 @@
/*
Copyright (c) 2013 Andreas Lauser
Copyright (c) 2013 Uni Research AS
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 <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_ECLIPSE_WRITER_HPP
#define OPM_ECLIPSE_WRITER_HPP
#include <opm/core/io/OutputWriter.hpp>
#include <opm/core/props/BlackoilPhases.hpp>
#include <string>
#include <memory> // std::unique_ptr
struct UnstructuredGrid;
namespace Opm {
// forward declarations
class EclipseGridParser;
class SimulatorState;
class SimulatorTimer;
class WellState;
namespace parameter { class ParameterGroup; }
/*!
* \brief A class to write the reservoir state and the well state of a
* blackoil simulation to disk using the Eclipse binary format.
*
* This class only writes files if the 'write_output' parameter is set
* to 1. It needs the ERT libraries to write to disk, so if the
* 'write_output' parameter is set but ERT is not available, all
* methods throw a std::runtime_error.
*/
class EclipseWriter : public OutputWriter
{
public:
/*!
* \brief Sets the common attributes required to write eclipse
* binary files using ERT.
*/
EclipseWriter(const parameter::ParameterGroup& params,
std::shared_ptr <const EclipseGridParser> parser,
std::shared_ptr <const UnstructuredGrid> grid);
/**
* We need a destructor in the compilation unit to avoid the
* EclipseSummary being a complete type here.
*/
virtual ~EclipseWriter ();
/**
* Write the static eclipse data (grid, PVT curves, etc) as well as the
* initial state to disk.
*/
virtual void writeInit(const SimulatorTimer &timer,
const SimulatorState& reservoirState,
const WellState& wellState);
/*!
* \brief Write a blackoil reservoir state to disk for later inspection with
* visualization tools like ResInsight
*
* \param[in] reservoirState The thermodynamic state of the reservoir
* \param[in] wellState The production/injection data for all wells
*/
virtual void writeTimeStep(const SimulatorTimer& timer,
const SimulatorState& reservoirState,
const WellState& wellState);
private:
std::shared_ptr <const EclipseGridParser> parser_;
std::shared_ptr <const UnstructuredGrid> grid_;
std::string outputDir_;
std::string baseName_;
PhaseUsage uses_; // active phases in the input deck
/// Write solution field variables (pressure and saturation)
void writeSolution (const SimulatorTimer& timer,
const SimulatorState& reservoirState,
const WellState& wellState);
};
} // namespace Opm
#endif // OPM_ECLIPSE_WRITER_HPP

View File

@ -452,7 +452,7 @@ namespace Opm
std::string filename = output_dir_ + "/step_timing.param";
tstep_os.open(filename.c_str(), std::fstream::out | std::fstream::app);
}
for (; !timer.done(); ++timer) {
while (!timer.done()) {
// Report timestep and (optionally) write state to disk.
step_timer.start();
timer.report(*log_);
@ -605,6 +605,10 @@ namespace Opm
sreport.reportParam(tstep_os);
}
// advance the timer to the end of the timestep *before* notifying
// the client that the timestep is done
++timer;
// notify all clients that we are done with the timestep
callback_timer.start ();
timestep_completed_.signal ();

View File

@ -0,0 +1,106 @@
/*
Copyright (c) 2013 Uni Research AS
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 <http://www.gnu.org/licenses/>.
*/
#include "SimulatorOutput.hpp"
// we need complete definitions for these types
#include <opm/core/io/eclipse/EclipseGridParser.hpp>
#include <opm/core/io/OutputWriter.hpp>
#include <opm/core/simulator/SimulatorTimer.hpp>
#include <numeric> // partial_sum
using namespace Opm;
SimulatorOutputBase::SimulatorOutputBase (
const parameter::ParameterGroup& params,
std::shared_ptr <const EclipseGridParser> parser,
std::shared_ptr <const UnstructuredGrid> grid,
std::shared_ptr <const SimulatorTimer> timer,
std::shared_ptr <const SimulatorState> state,
std::shared_ptr <const WellState> wellState)
// store all parameters passed into the object, making them curried
// parameters to the writeOutput function.
: timer_ (timer )
, reservoirState_ (state )
, wellState_ (wellState)
// process parameters into a writer. we don't setup a new chain in
// every timestep!
, writer_ (std::move (OutputWriter::create (params, parser, grid)))
// always start from the first timestep
, next_ (0) {
// make a list of times to dump. since the original list are relative
// timesteps, we make a list of accumulated such to compare with
// current time. add an extra zero at the beginning so that the
// initial state is also written
const std::vector <double>& tstep = parser->getTSTEP ().tstep_;
times_.resize (tstep.size (), 0.);
std::partial_sum (tstep.begin(), tstep.end(), times_.begin());
// write the static initialization files, even before simulation starts
writer_->writeInit (*timer, *state, *wellState);
}
// default destructor is OK, just need to be defined
SimulatorOutputBase::~SimulatorOutputBase() { }
SimulatorOutputBase::operator std::function <void ()> () {
// return (a pointer to) the writeOutput() function as an object
// which can be passed to the event available from the simulator
return std::bind (&SimulatorOutputBase::writeOutput, std::ref (*this));
}
void
SimulatorOutputBase::writeOutput () {
const int this_time = timer_->currentTime ();
// if the simulator signals for timesteps that aren't reporting
// times, then ignore them
if (next_ < times_.size () && times_[next_] <= this_time) {
// uh-oh, the simulator has skipped reporting timesteps that
// occurred before this timestep (it doesn't honor the TSTEP setting)
while (next_ < times_.size () && times_[next_] < this_time) {
++next_;
}
// report this timestep if it matches
if (next_ < times_.size () && times_[next_] == this_time) {
// make sure the simulator has spilled all necessary internal
// state. notice that this calls *our* sync, which is overridden
// in the template companion to call the simulator
sync ();
// relay the request to the handlers (setup in the constructor
// from parameters)
writer_->writeTimeStep (*timer_, *reservoirState_, *wellState_);
// advance to the next reporting time
++next_;
}
}
}
void
SimulatorOutputBase::sync () {
// no-op in base class (overridden by simulator-specific template)
}

View File

@ -0,0 +1,195 @@
/*
Copyright (c) 2013 Uni Research AS
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 <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_SIMULATOR_OUTPUT_HPP
#define OPM_SIMULATOR_OUTPUT_HPP
// need complete def. of this since we use it in template
#include <opm/core/utility/Event.hpp>
#include <opm/core/utility/share_obj.hpp>
#include <memory> // unique_ptr, shared_ptr
#include <vector>
struct UnstructuredGrid;
namespace Opm {
// forward definitions
class EclipseGridParser;
class OutputWriter;
namespace parameter { class ParameterGroup; }
class SimulatorState;
class SimulatorTimer;
class WellState;
/**
* Encapsulate output writing from simulators. This is essentially
* a function object holding curried arguments to the writing backend
* which is used when invoked through the event handler (which passes
* on no arguments on it own).
*/
class SimulatorOutputBase {
protected:
/**
* Curry arguments for the output writer. These arguments are passed
* to the simulator, but is not passed on to the event handler so it
* need to pick them up from the object members.
*/
SimulatorOutputBase (const parameter::ParameterGroup& p,
std::shared_ptr <const EclipseGridParser> parser,
std::shared_ptr <const UnstructuredGrid> grid,
std::shared_ptr <const SimulatorTimer> timer,
std::shared_ptr <const SimulatorState> state,
std::shared_ptr <const WellState> wellState);
/**
* We need a destructor in the compilation unit to avoid the
* OutputWriter being a complete type here.
*/
virtual ~SimulatorOutputBase ();
/**
* Conversion operator which allows the object to be directly passed
* into an Event and used as a handler.
*
* @see Opm::SimulatorIncompTwophase::timestep_completed
*/
operator std::function <void ()> ();
/// Just hold a reference to these objects that are owned elsewhere.
std::shared_ptr <const SimulatorTimer> timer_;
std::shared_ptr <const SimulatorState> reservoirState_;
std::shared_ptr <const WellState> wellState_;
/// Created locally and destructed together with us
std::unique_ptr <OutputWriter> writer_;
/// Call the writers that were created based on the parameters
virtual void writeOutput ();
/// Make sure that the simulator state is up to date before writing
virtual void sync ();
private:
/// Index of the upcoming reporting time
std::vector <double>::size_type next_;
/// Array of times when to write report
std::vector <double> times_;
};
/**
* Create an output writer that is coupled to a simulator capable
* of reading Eclipse deck files. Output will be written only when
* specified in the deck file.
*
* @note
* This class is a template since there is no fixed interface for
* simulators, only an implied type class of common method signatures.
*
* @example
* @code{.cpp}
* // configuration
* ParameterGroup params (argc, argv, false);
*
* // input file
* auto deck = make_shared <EclipseGridParser> ( ... );
* const GridManager manager (*parser);
* auto grid = share_obj (*manager.c_grid ());
*
* // timestep ends up here
* auto timer = make_shared <SimulatorTimer> ();
*
* // state ends up here
* auto state = make_shared <TwophaseState> ();
* auto wellState = make_shared <WellState> ();
*
* // set up simulation
* auto sim = make_shared <SimulatorIncompTwophase> (params, *grid, ... );
*
* // use this to dump state to disk
* auto output = make_shared <SimulatorOutput> (
* params, deck, grid, timer, state, wellState, sim);
*
* // start simulation
* sim.run (timer, state, ... )
* @endcode
*
* @todo
* This functionality could be incorporated directly into a simulator
* object.
*/
template <typename Simulator>
struct SimulatorOutput : public SimulatorOutputBase {
SimulatorOutput (const parameter::ParameterGroup& params,
std::shared_ptr <const EclipseGridParser> parser,
std::shared_ptr <const UnstructuredGrid> grid,
std::shared_ptr <const SimulatorTimer> timer,
std::shared_ptr <const SimulatorState> state,
std::shared_ptr <const WellState> wellState,
std::shared_ptr <Simulator> sim)
// send all other parameters to base class
: SimulatorOutputBase (params, parser, grid, timer, state, wellState)
// store reference to simulator in derived class
, sim_ (sim) {
// connect simulation with output writer
sim->timestep_completed ().add (*this);
}
/**
* Compatibility constructor for clients written in C++03-style:
* The client provide an informal guarantee that the lifetime of
* the arguments passed exceeds the lifetime of this object.
*/
SimulatorOutput (const parameter::ParameterGroup& params,
const EclipseGridParser& parser,
const UnstructuredGrid& grid,
const SimulatorTimer& timer,
const SimulatorState& state,
const WellState& wellState,
Simulator& sim)
// send all other parameters to base class
: SimulatorOutputBase (params,
share_obj (parser),
share_obj (grid),
share_obj (timer),
share_obj (state),
share_obj (wellState))
// store reference to simulator in derived class
, sim_ (share_obj (sim)) {
// connect simulation with output writer
sim_->timestep_completed ().add (*this);
}
protected:
// forward this request to the simulator
virtual void sync () { sim_->sync (); }
private:
/// Reference to the simulator class; needed to ask it to synchronize
std::shared_ptr <Simulator> sim_;
};
}
#endif /* OPM_SIMULATOR_OUTPUT_HPP */

View File

@ -89,6 +89,12 @@ namespace Opm
return timesteps_[current_step_];
}
double SimulatorTimer::stepLengthTaken() const
{
assert(current_step_ > 0);
return timesteps_[current_step_ - 1];
}
/// Current time.
double SimulatorTimer::currentTime() const
{

View File

@ -50,16 +50,29 @@ namespace Opm
/// Total number of steps.
int numSteps() const;
/// Current step number.
/// Current step number. This is the number of timesteps that
/// has been completed from the start of the run. The time
/// after initialization but before the simulation has started
/// is timestep number zero.
int currentStepNum() const;
/// Set current step number.
void setCurrentStepNum(int step);
/// Current step length.
/// Note: if done(), it is an error to call currentStepLength().
/// Current step length. This is the length of the step
/// the simulator will take in the next iteration.
///
/// @note if done(), it is an error to call currentStepLength().
double currentStepLength() const;
/// Previous step length. This is the length of the step that
/// was taken to arrive at this time.
///
/// @note if no increments have been done (i.e. the timer is
/// still in its constructed state and currentStepNum() == 0),
/// it is an error to call stepLengthTaken().
double stepLengthTaken () const;
/// Current time.
double currentTime() const;

View File

@ -0,0 +1,49 @@
/*
Copyright (c) 2013 Uni Research AS
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 <http://www.gnu.org/licenses/>.
*/
#ifndef OPM_SHARE_OBJ_HPP
#define OPM_SHARE_OBJ_HPP
#include <memory> // shared_ptr
namespace Opm {
/// Custom deleter that does nothing
inline void no_delete (void const *) { }
/*!
* Share pointer of a local object.
*
* Use this wrapper when an interface needs a shared_ptr, but you
* want to pass an object that has local storage (and you know
* that the shared_ptr client doesn't need it outside of the scope).
*
* \example
* \code{.cpp}
* Foo obj;
* std::shared_ptr <Foo> ptr = share_obj (obj);
* \endcode
*/
template <typename T> std::shared_ptr <T> share_obj (T& t) {
return std::shared_ptr <T> (&t, no_delete);
}
} // namespace Opm
#endif /* OPM_SHARE_OBJ_HPP */