Added functionality to save results in ECLIPSE format from ERT libraries.
This commit is contained in:
@@ -47,8 +47,18 @@
|
||||
#include <opm/core/eclipse/EclipseGridParserHelpers.hpp>
|
||||
#include <opm/core/eclipse/SpecialEclipseFields.hpp>
|
||||
#include <opm/core/utility/ErrorMacros.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <opm/core/utility/Units.hpp>
|
||||
#include <opm/core/grid/cpgpreprocess/preprocess.h>
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#ifdef HAVE_ERT
|
||||
#include <fortio.h>
|
||||
#include <ecl_grid.h>
|
||||
#include <ecl_kw_magic.h>
|
||||
#include <ecl_kw.h>
|
||||
#include <ecl_util.h>
|
||||
#include <ecl_init_file.h>
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -86,7 +96,7 @@ namespace EclipseKeywords
|
||||
string("MULTPV"), string("PRESSURE"), string("SGAS"),
|
||||
string("SWAT"), string("SOIL"), string("RS"),
|
||||
string("DXV"), string("DYV"), string("DZV"),
|
||||
string("DEPTHZ")
|
||||
string("DEPTHZ"), string("MAPAXES")
|
||||
};
|
||||
const int num_floating_fields = sizeof(floating_fields) / sizeof(floating_fields[0]);
|
||||
|
||||
@@ -114,7 +124,7 @@ namespace EclipseKeywords
|
||||
const int num_special_fields = sizeof(special_fields) / sizeof(special_fields[0]);
|
||||
|
||||
string ignore_with_data[] =
|
||||
{ string("MAPUNITS"), string("MAPAXES"), string("GRIDUNIT"),
|
||||
{ string("MAPUNITS"), string("GRIDUNIT"),
|
||||
string("NTG"), string("REGDIMS"), string("WELLDIMS"),
|
||||
string("NSTACK"), string("SATNUM"),
|
||||
string("RPTRST"), string("ROIP"), string("RWIP"),
|
||||
@@ -814,5 +824,248 @@ void EclipseGridParser::computeUnits()
|
||||
THROW("Unknown unit family " << unit_family);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct grdecl EclipseGridParser::get_grdecl() const {
|
||||
struct grdecl grdecl;
|
||||
|
||||
// Extract data from deck.
|
||||
const std::vector<double>& zcorn = getFloatingPointValue("ZCORN");
|
||||
const std::vector<double>& coord = getFloatingPointValue("COORD");
|
||||
const int* actnum = NULL;
|
||||
if (hasField("ACTNUM")) {
|
||||
actnum = &(getIntegerValue("ACTNUM")[0]);
|
||||
}
|
||||
|
||||
std::vector<int> dims;
|
||||
if (hasField("DIMENS")) {
|
||||
dims = getIntegerValue("DIMENS");
|
||||
} else if (hasField("SPECGRID")) {
|
||||
dims = getSPECGRID().dimensions;
|
||||
} else {
|
||||
THROW("Deck must have either DIMENS or SPECGRID.");
|
||||
}
|
||||
|
||||
// Collect in input struct for preprocessing.
|
||||
|
||||
grdecl.zcorn = &zcorn[0];
|
||||
grdecl.coord = &coord[0];
|
||||
grdecl.actnum = actnum;
|
||||
grdecl.dims[0] = dims[0];
|
||||
grdecl.dims[1] = dims[1];
|
||||
grdecl.dims[2] = dims[2];
|
||||
|
||||
if (hasField("MAPAXES")) {
|
||||
const std::vector<double> &mapaxes = getFloatingPointValue("MAPAXES");
|
||||
grdecl.mapaxes = &mapaxes[0];
|
||||
} else
|
||||
grdecl.mapaxes = NULL;
|
||||
|
||||
|
||||
return grdecl;
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_ERT
|
||||
/*
|
||||
This function will create a ecl_kw instance filled with the data
|
||||
from input argument @keyword. The ecl_kw will get it's own copy of
|
||||
the data.
|
||||
|
||||
If the input type ecl_type == ECL_INT_TYPE the function will use the
|
||||
getIntegerValue() method to get the keyword data, if ecl_type ==
|
||||
ECL_DOUBLE_TYPE || ECL_FLOAT_TYPE the getFloatingPointValue()
|
||||
function is invoked. If ecl_type == ECL_FLOAT_TYPE the data will be
|
||||
converted to when inserting into the ecl_kw.
|
||||
|
||||
When the ecl_kw instance is no longer needed it should be discarded
|
||||
with a call to ecl_kw_free( ).
|
||||
|
||||
If you are asking for a non-existent field the function will return NULL
|
||||
*/
|
||||
|
||||
ecl_kw_type * EclipseGridParser::newEclKW(const std::string &keyword , ecl_type_enum ecl_type) const {
|
||||
ecl_kw_type * ecl_kw = NULL;
|
||||
if (hasField(keyword)) {
|
||||
if (ecl_type == ECL_INT_TYPE) {
|
||||
std::vector<int> data = getIntegerValue( keyword );
|
||||
ecl_kw = ecl_kw_alloc( keyword.c_str() , data.size() , ecl_type );
|
||||
ecl_kw_set_memcpy_data( ecl_kw , &data[0]);
|
||||
} else {
|
||||
std::vector<double> data = getFloatingPointValue( keyword );
|
||||
if (ecl_type == ECL_DOUBLE_TYPE) {
|
||||
ecl_kw = ecl_kw_alloc( keyword.c_str() , data.size() , ecl_type );
|
||||
ecl_kw_set_memcpy_data( ecl_kw , &data[0]);
|
||||
} else if (ecl_type == ECL_FLOAT_TYPE) {
|
||||
ecl_kw = ecl_kw_alloc( keyword.c_str() , data.size() , ecl_type );
|
||||
for (int i=0; i < data.size(); i++)
|
||||
ecl_kw_iset_float( ecl_kw , i , data[i] );
|
||||
}
|
||||
}
|
||||
}
|
||||
return ecl_kw;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
This function will extract the COORD, ZCORN, ACTNUM and optionaly
|
||||
MAPAXES keywords from the eclipse deck and create an ecl_grid
|
||||
instance.
|
||||
|
||||
When you are finished working with the ecl_grid instance it should
|
||||
be disposed with ecl_grid_free( ).
|
||||
*/
|
||||
|
||||
ecl_grid_type * EclipseGridParser::newGrid( ) {
|
||||
struct grdecl grdecl = get_grdecl();
|
||||
ecl_kw_type * coord_kw = newEclKW( COORD_KW , ECL_FLOAT_TYPE );
|
||||
ecl_kw_type * zcorn_kw = newEclKW( ZCORN_KW , ECL_FLOAT_TYPE );
|
||||
ecl_kw_type * actnum_kw = newEclKW( ACTNUM_KW , ECL_INT_TYPE );
|
||||
ecl_kw_type * mapaxes_kw = NULL;
|
||||
|
||||
ecl_grid_type * grid ;
|
||||
if (grdecl.mapaxes != NULL)
|
||||
mapaxes_kw = newEclKW( MAPAXES_KW , ECL_FLOAT_TYPE );
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
This function will save an EGRID file based on the COORD, ZCORN,
|
||||
ACTNUM and optionally MAPAXES keywords included in the deck.
|
||||
|
||||
This function creates the EGRID file without going through a
|
||||
ecl_grid instance; this is obviously somewhat faster and less
|
||||
memory demanding. Alternatively you can create a ecl_grid instance
|
||||
and then subsequently store that grid as an EGRID file:
|
||||
|
||||
{
|
||||
ecl_grid_type * grid = newGRID( );
|
||||
ecl_grid_fwrite_EGRID( grid , filename );
|
||||
ecl_grid_free( grid );
|
||||
}
|
||||
*/
|
||||
|
||||
void EclipseGridParser::saveEGRID( const std::string & filename) {
|
||||
bool endian_flip = true;//ECL_ENDIAN_FLIP;
|
||||
bool fmt_file = ecl_util_fmt_file( filename.c_str() );
|
||||
struct grdecl grdecl = get_grdecl();
|
||||
fortio_type * fortio = fortio_open_writer( filename.c_str() , fmt_file , endian_flip );
|
||||
{
|
||||
float * mapaxes = NULL;
|
||||
if (grdecl.mapaxes != NULL) {
|
||||
mapaxes = new float[6];
|
||||
for (int i=0; i < 6; i++)
|
||||
mapaxes[i]= grdecl.mapaxes[i];
|
||||
}
|
||||
|
||||
ecl_grid_fwrite_EGRID_header( grdecl.dims , mapaxes , fortio );
|
||||
|
||||
if (grdecl.mapaxes != NULL)
|
||||
delete[] mapaxes;
|
||||
}
|
||||
{
|
||||
ecl_kw_type * coord_kw = newEclKW( COORD_KW , ECL_FLOAT_TYPE );
|
||||
ecl_kw_type * zcorn_kw = newEclKW( ZCORN_KW , ECL_FLOAT_TYPE );
|
||||
ecl_kw_type * actnum_kw = newEclKW( ACTNUM_KW , ECL_INT_TYPE );
|
||||
ecl_kw_type * endgrid_kw = ecl_kw_alloc( ENDGRID_KW , 0 , ECL_INT_TYPE );
|
||||
|
||||
ecl_kw_fwrite( coord_kw , fortio );
|
||||
ecl_kw_fwrite( zcorn_kw , fortio );
|
||||
ecl_kw_fwrite( actnum_kw , fortio );
|
||||
ecl_kw_fwrite( endgrid_kw , fortio );
|
||||
|
||||
ecl_kw_free( coord_kw );
|
||||
ecl_kw_free( zcorn_kw );
|
||||
ecl_kw_free( actnum_kw );
|
||||
ecl_kw_free( endgrid_kw );
|
||||
}
|
||||
fortio_fclose( fortio );
|
||||
}
|
||||
|
||||
/**
|
||||
Will query the deck for keyword @kw; and save it to the @fortio
|
||||
instance if the keyword can be found.
|
||||
*/
|
||||
void EclipseGridParser::save_kw( fortio_type * fortio , const std::string & kw , ecl_type_enum ecl_type) {
|
||||
ecl_kw_type * ecl_kw = newEclKW( kw , ecl_type );
|
||||
if (ecl_kw != NULL) {
|
||||
ecl_kw_fwrite( ecl_kw , fortio );
|
||||
ecl_kw_free( ecl_kw );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Will save an ECLIPSE INIT file to @filename. Observe that the main
|
||||
focus of this function is to store grid properties like PERMX and
|
||||
PORO, various tabular properties like e.g. relperm tables and
|
||||
thermodynamic properties are ignored.
|
||||
*/
|
||||
|
||||
void EclipseGridParser::saveINIT( const std::string & filename , const ecl_grid_type * ecl_grid) {
|
||||
int phases = ECL_OIL_PHASE + ECL_WATER_PHASE;
|
||||
bool fmt_file = ecl_util_fmt_file( filename.c_str() );
|
||||
bool endian_flip = true;//ECL_ENDIAN_FLIP;
|
||||
fortio_type * fortio = fortio_open_writer( filename.c_str() , fmt_file , endian_flip );
|
||||
{
|
||||
ecl_kw_type * poro_kw = newEclKW( PORO_KW , ECL_FLOAT_TYPE );
|
||||
time_t start_date;
|
||||
|
||||
{
|
||||
tm td_tm = to_tm( start_date_ );
|
||||
start_date = mktime( &td_tm );
|
||||
}
|
||||
|
||||
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. */
|
||||
save_kw( fortio , "PERMX" , ECL_FLOAT_TYPE);
|
||||
save_kw( fortio , "PERMY" , ECL_FLOAT_TYPE);
|
||||
save_kw( fortio , "PERMZ" , ECL_FLOAT_TYPE);
|
||||
|
||||
save_kw( fortio , "FIPNUM" , ECL_INT_TYPE);
|
||||
save_kw( fortio , "SATNUM" , ECL_INT_TYPE);
|
||||
save_kw( fortio , "EQLNUM" , ECL_INT_TYPE);
|
||||
|
||||
fortio_fclose( fortio );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
This is the main function used to save the state of the ECLIPSE
|
||||
deck in ECLIPSE format. The function will save an INIT file and an
|
||||
EGRID file.
|
||||
|
||||
The input arguments are the output directory to store files in, and
|
||||
the basename to use for the files; the function will build up a
|
||||
ECLIPSE standard filename internally.
|
||||
*/
|
||||
|
||||
void EclipseGridParser::saveEGRID_INIT( const std::string& output_dir , const std::string& basename, bool fmt_file) {
|
||||
ecl_grid_type * ecl_grid = newGrid();
|
||||
char * egrid_file = ecl_util_alloc_filename( output_dir.c_str() , basename.c_str() , ECL_EGRID_FILE , fmt_file , 0);
|
||||
char * init_file = ecl_util_alloc_filename( output_dir.c_str() , basename.c_str() , ECL_INIT_FILE , fmt_file , 0);
|
||||
|
||||
ecl_grid_fwrite_EGRID( ecl_grid , egrid_file );
|
||||
saveINIT( init_file , ecl_grid );
|
||||
|
||||
free( init_file );
|
||||
free( egrid_file );
|
||||
ecl_grid_free( ecl_grid );
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
@@ -45,6 +45,13 @@ along with OpenRS. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include <opm/core/eclipse/EclipseUnits.hpp>
|
||||
#include <opm/core/utility/Factory.hpp>
|
||||
|
||||
#include <opm/core/grid/cornerpoint_grid.h>
|
||||
#ifdef HAVE_ERT
|
||||
#include <ecl_kw.h>
|
||||
#include <ecl_grid.h>
|
||||
#endif
|
||||
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
@@ -191,7 +198,23 @@ public:
|
||||
/// The units specified by the eclipse file read.
|
||||
const EclipseUnits& units() const;
|
||||
|
||||
struct grdecl get_grdecl() const;
|
||||
|
||||
#ifdef HAVE_ERT
|
||||
void saveEGRID_INIT( const std::string& output_dir , const std::string& basename, bool fmt_file = false);
|
||||
void saveEGRID( const std::string & filename );
|
||||
void saveINIT( const std::string & filename , const ecl_grid_type * ecl_grid);
|
||||
ecl_grid_type * newGrid( );
|
||||
#endif
|
||||
|
||||
|
||||
private:
|
||||
|
||||
#ifdef HAVE_ERT
|
||||
ecl_kw_type * newEclKW(const std::string &keyword , ecl_type_enum ecl_type) const;
|
||||
void save_kw( fortio_type * fortio , const std::string & kw , ecl_type_enum ecl_type);
|
||||
#endif
|
||||
|
||||
SpecialFieldPtr createSpecialField(std::istream& is, const std::string& fieldname);
|
||||
SpecialFieldPtr cloneSpecialField(const std::string& fieldname,
|
||||
const std::tr1::shared_ptr<SpecialBase> original);
|
||||
|
||||
Reference in New Issue
Block a user