Merge pull request #77 from joakim-hove/IMPORT

Small utility examples/import_rewrite to update ECLIPSE deck to use IMPORT keywords
This commit is contained in:
Bård Skaflestad 2012-10-23 05:21:56 -07:00
commit 0efcf9e806
4 changed files with 438 additions and 161 deletions

View File

@ -1,13 +1,13 @@
# Build-time flags needed to form example programs
ERT_INCLUDE_PATH = $(ERT_ROOT)/include
AM_CPPFLAGS = \
-I$(top_srcdir) \
-I$(ERT_INCLUDE_PATH) \
AM_CPPFLAGS = \
-I$(top_srcdir) \
-I$(ERT_INCLUDE_PATH) \
$(OPM_BOOST_CPPFLAGS)
# All targets link to the library
LDADD = \
LDADD = \
$(top_builddir)/lib/libopmcore.la
# Convenience definition for targets that use Boost.Filesystem directly.
@ -19,9 +19,9 @@ $(top_builddir)/lib/libopmcore.la
# Additional details at
# https://fedoraproject.org/wiki/UnderstandingDSOLinkChange
#
LINK_BOOST_FILESYSTEM = \
$(OPM_BOOST_LDFLAGS) \
$(BOOST_FILESYSTEM_LIB) \
LINK_BOOST_FILESYSTEM = \
$(OPM_BOOST_LDFLAGS) \
$(BOOST_FILESYSTEM_LIB) \
$(BOOST_SYSTEM_LIB)
# ----------------------------------------------------------------------
@ -29,14 +29,20 @@ $(BOOST_SYSTEM_LIB)
#
# Please keep the list sorted.
noinst_PROGRAMS = \
compute_tof \
refine_wells \
scaneclipsedeck \
sim_2p_comp_reorder \
sim_2p_incomp_reorder \
sim_wateroil \
wells_example
noinst_PROGRAMS = \
compute_tof \
refine_wells \
scaneclipsedeck \
sim_2p_comp_reorder \
sim_2p_incomp_reorder \
sim_wateroil \
wells_example
if HAVE_ERT
noinst_PROGRAMS += import_rewrite
endif
# ----------------------------------------------------------------------
# Product constituents. Must be specified for every product that's
@ -47,8 +53,14 @@ wells_example
compute_tof_SOURCES = compute_tof.cpp
compute_tof_LDADD = $(LDADD) $(LINK_BOOST_FILESYSTEM)
refine_wells_SOURCES = refine_wells.cpp
if HAVE_ERT
import_rewrite_SOURCES = import_rewrite.cpp
import_rewrite_LDADD = $(LDADD) $(LINK_BOOST_FILESYSTEM)
endif
sim_2p_comp_reorder_SOURCES = sim_2p_comp_reorder.cpp
sim_2p_comp_reorder_LDADD = $(LDADD) $(LINK_BOOST_FILESYSTEM)
@ -67,8 +79,8 @@ if UMFPACK
noinst_PROGRAMS += spu_2p
spu_2p_SOURCES = spu_2p.cpp
spu_2p_LDADD = \
$(LDADD) \
$(LINK_BOOST_FILESYSTEM) \
spu_2p_LDADD = \
$(LDADD) \
$(LINK_BOOST_FILESYSTEM) \
$(LAPACK_LIBS) $(BLAS_LIBS) $(LIBS)
endif

253
examples/import_rewrite.cpp Normal file
View File

@ -0,0 +1,253 @@
#if HAVE_CONFIG_H
#include "config.h"
#endif // HAVE_CONFIG_H
#include <opm/core/eclipse/EclipseGridParser.hpp>
#include <boost/filesystem/convenience.hpp>
#ifdef HAVE_ERT
#include <opm/core/utility/writeECLData.hpp>
#include <util.h>
#include <ecl_util.h>
#include <ecl_kw.h>
#include <ecl_endian_flip.h>
#include <fortio.h>
#endif
/*
Small utility to read through an ECLIPSE input deck and replace
occurences of (large) numerical fields like COORD and ZCORN with
IMPORT statements of a binary versions of the relevant keywords. The
program will follow INCLUDE statements.
Usage: import_rewrite eclipse_case.data
*/
/*
The numerical keywords in the ECLIPSE datafile like e.g. PORO and
COORD are not annoted with type information; however when read and
written in binary form they are of type float. If the updated
datafile should be used with ECLIPSE these float values must be
exported as float; this is achieved by setting the outputFloatType
variable to ECL_FLOAT_TYPE.
In OPM all numerical fields are treated as double, hence if the OPM
EclipseParser meets an import of a float keyword it will be
converted to double. If the output from this little utility will
only be used from OPM the output can be saved as double directly by
setting the outputFloatType to ECL_DOUBLE_TYPE.
*/
const ecl_type_enum outputFloatType = ECL_DOUBLE_TYPE;
/*
Only keywords which have more >= minImportSize elements are
converted to binary form. This is to avoid convertion short keywords
like MAPAXES and TABDIMS.
*/
const int minImportSize = 10;
using namespace Opm;
static void skipKeyword( std::ifstream& is) {
std::string keyword;
EclipseGridParser::readKeyword( is , keyword );
while (true) {
std::ios::pos_type pos = is.tellg();
if (EclipseGridParser::readKeyword( is , keyword )) {
is.seekg( pos ); // Repos to start of keyword for next read.
break;
} else
is >> ignoreLine;
if (!is.good()) {
is.clear();
is.seekg( 0 , std::ios::end );
break;
}
}
}
static void copyKeyword( std::ifstream& is , std::ofstream& os) {
std::ios::pos_type start_pos = is.tellg();
skipKeyword( is );
{
std::ios::pos_type end_pos = is.tellg();
long length = end_pos - start_pos;
{
char * buffer = new char[length];
{
is.seekg( start_pos );
is.read( buffer , length );
}
os.write( buffer , length );
delete[] buffer;
}
}
}
static ecl_kw_type * loadFromcstdio( const std::string& filename , std::ios::pos_type& offset , ecl_type_enum ecl_type) {
ecl_kw_type * ecl_kw;
FILE * cstream = util_fopen( filename.c_str() , "r");
fseek( cstream , offset , SEEK_SET);
ecl_kw = ecl_kw_fscanf_alloc_current_grdecl( cstream , ecl_type );
offset = ftell( cstream );
fclose( cstream );
return ecl_kw;
}
static bool convertKeyword( const std::string& inputFile , const std::string& outputPath , std::ifstream& is , FieldType fieldType , std::ofstream& os ) {
bool convert = true;
ecl_type_enum ecl_type;
ecl_kw_type * ecl_kw;
if (fieldType == Integer)
ecl_type = ECL_INT_TYPE;
else
ecl_type = outputFloatType;
{
std::ios::pos_type inputPos = is.tellg();
ecl_kw_type * ecl_kw = loadFromcstdio( inputFile , inputPos , ecl_type );
if (ecl_kw_get_size( ecl_kw ) >= minImportSize) {
{
std::string outputFile = outputPath + "/" + ecl_kw_get_header( ecl_kw );
fortio_type * fortio = fortio_open_writer( outputFile.c_str() , false , ECL_ENDIAN_FLIP );
ecl_kw_fwrite( ecl_kw , fortio );
fortio_fclose( fortio );
os << "IMPORT" << std::endl << " '" << outputFile << "' /" << std::endl << std::endl;
}
is.seekg( inputPos );
} else {
copyKeyword( is , os );
convert = false;
}
ecl_kw_free( ecl_kw );
}
return convert;
}
bool parseFile(const std::string& inputFile, std::string& outputFile, const std::string& indent = "") {
bool updateFile = false;
std::cout << indent << "Parsing " << inputFile << "\n";
{
std::ifstream is(inputFile.c_str());
if (is) {
std::ofstream os;
std::string keyword;
std::string path;
{
boost::filesystem::path inputPath(inputFile);
path = inputPath.parent_path().string();
}
{
std::string basename;
std::string extension;
outputFile = inputFile;
size_t ext_pos = inputFile.rfind(".");
if (ext_pos == std::string::npos) {
basename = outputFile.substr();
extension = "";
} else {
basename = outputFile.substr(0,ext_pos);
extension = outputFile.substr(ext_pos);
}
outputFile = basename + "_import" + extension;
}
os.open( outputFile.c_str() );
while(is.good()) {
is >> ignoreWhitespace;
{
std::ios::pos_type start_pos = is.tellg();
if (EclipseGridParser::readKeyword( is , keyword )) {
FieldType fieldType = EclipseGridParser::classifyKeyword( keyword );
switch (fieldType) {
case(Integer):
case(FloatingPoint):
{
is.seekg( start_pos );
if (convertKeyword( inputFile , path , is , fieldType , os )) {
std::cout << indent + " " << "Writing binary file: " << path << "/" << keyword << std::endl;
updateFile = true;
}
break;
}
case(Include):
{
std::string includeFile = readString(is);
if (!path.empty()) {
includeFile = path + '/' + includeFile;
}
{
std::string __outputFile;
bool updateInclude = parseFile( includeFile , __outputFile , indent + " ");
if (updateInclude) {
is.seekg( start_pos );
skipKeyword( is );
os << "INCLUDE" << std::endl << " '" << __outputFile << "' /" << std::endl << std::endl;
}
updateFile |= updateInclude;
}
break;
}
default:
{
is.seekg( start_pos );
copyKeyword( is , os);
break;
}
}
} else
is >> ignoreLine; // Not at a valid keyword
}
}
os.close();
is.close();
if (updateFile)
std::cout << indent << "Written updated include file: " << outputFile << std::endl;
else
remove( outputFile.c_str() );
} else
std::cerr << indent << "** WARNING: Failed to open include file: " << inputFile << " for reading **" << std::endl;
}
return updateFile;
}
int
main(int argc, char** argv)
{
if (argc != 2)
THROW("Need the name of ECLIPSE file on command line");
{
std::string outputFile;
parseFile(argv[1] , outputFile);
}
}

View File

@ -160,42 +160,6 @@ namespace EclipseKeywords
namespace {
enum FieldType {
Integer,
FloatingPoint,
Timestepping,
SpecialField,
IgnoreWithData,
IgnoreNoData,
Include,
Import,
Unknown
};
inline FieldType classifyKeyword(const string& keyword)
{
using namespace EclipseKeywords;
if (count(integer_fields, integer_fields + num_integer_fields, keyword)) {
return Integer;
} else if (count(floating_fields, floating_fields + num_floating_fields, keyword)) {
return FloatingPoint;
} else if (keyword == "TSTEP" || keyword == "DATES") {
return Timestepping;
} else if (count(special_fields, special_fields + num_special_fields, keyword)) {
return SpecialField;
} else if (count(ignore_with_data, ignore_with_data + num_ignore_with_data, keyword)) {
return IgnoreWithData;
} else if (count(ignore_no_data, ignore_no_data + num_ignore_no_data, keyword)) {
return IgnoreNoData;
} else if (count(include_keywords, include_keywords + num_include_keywords, keyword)) {
return Include;
} else if (count(import_keywords, import_keywords + num_import_keywords, keyword)) {
return Import;
} else {
return Unknown;
}
}
inline std::string upcase(const std::string& s)
{
std::string us(s);
@ -208,71 +172,7 @@ namespace {
return us;
}
inline bool readKeyword(std::istream& is, std::string& keyword)
{
char buf[9];
int i, j;
char c;
/* Clear buf */
for (i=0; i<9; ++i) {
buf[i] = '\0';
}
/* Read first character and check if it is uppercase*/
//buf[0] = fgetc(fp);
is.get(buf[0]);
if ( !isupper( buf[0] ) ) {
is.unget();
return false; /* NOT VALID CHARACTER */
}
/* Scan as much as possible possible keyword, 8 characters long */
i = 1;
is.get(c);
while ( (is.good()) &&
(c != EOF ) &&
(!isblank(c) ) &&
(isupper(c) || isdigit(c)) &&
(c != '\n' ) &&
(c != '/' ) &&
(i < 8 )) {
buf[i++] = c;
is.get(c);
}
/* Skip rest of line */
if (c != '\n'){
is.get(c);
while ( (is.good()) &&
(c != EOF ) &&
(c != '\n' )) {
is.get(c);
}
}
if(c == '\n') {
is.unget();
}
/* Find first non-uppercase or non-digit character */
for (i=0; i<8; ++i) {
if ( !(isupper(buf[i]) || isdigit(buf[i])) ) {
break;
}
}
/* Check if remaining characters are blank */
for (j = i; j<8; ++j) {
if(!isspace(buf[j]) && buf[j] != '\0') {
return false; /* CHARACTER AFTER SPACE OR INVALID CHARACTER */
}
buf[j] = '\0';
}
keyword = std::string(buf);
std::string::size_type end = keyword.find_last_of('\0');
if(end != keyword.npos)
keyword = keyword.substr(0, end+1);
return true;
}
} // anon namespace
@ -315,6 +215,98 @@ EclipseGridParser::EclipseGridParser(const string& filename, bool convert_to_SI)
}
FieldType EclipseGridParser::classifyKeyword(const string& keyword)
{
using namespace EclipseKeywords;
if (count(integer_fields, integer_fields + num_integer_fields, keyword)) {
return Integer;
} else if (count(floating_fields, floating_fields + num_floating_fields, keyword)) {
return FloatingPoint;
} else if (keyword == "TSTEP" || keyword == "DATES") {
return Timestepping;
} else if (count(special_fields, special_fields + num_special_fields, keyword)) {
return SpecialField;
} else if (count(ignore_with_data, ignore_with_data + num_ignore_with_data, keyword)) {
return IgnoreWithData;
} else if (count(ignore_no_data, ignore_no_data + num_ignore_no_data, keyword)) {
return IgnoreNoData;
} else if (count(include_keywords, include_keywords + num_include_keywords, keyword)) {
return Include;
} else if (count(import_keywords, import_keywords + num_import_keywords, keyword)) {
return Import;
} else {
return Unknown;
}
}
bool EclipseGridParser::readKeyword(std::istream& is, std::string& keyword)
{
char buf[9];
int i, j;
char c;
/* Clear buf */
for (i=0; i<9; ++i) {
buf[i] = '\0';
}
/* Read first character and check if it is uppercase*/
//buf[0] = fgetc(fp);
is.get(buf[0]);
if ( !isupper( buf[0] ) ) {
is.unget();
return false; /* NOT VALID CHARACTER */
}
/* Scan as much as possible possible keyword, 8 characters long */
i = 1;
is.get(c);
while ( (is.good()) &&
(c != EOF ) &&
(!isblank(c) ) &&
(isupper(c) || isdigit(c)) &&
(c != '\n' ) &&
(c != '/' ) &&
(i < 8 )) {
buf[i++] = c;
is.get(c);
}
/* Skip rest of line */
if (c != '\n'){
is.get(c);
while ( (is.good()) &&
(c != EOF ) &&
(c != '\n' )) {
is.get(c);
}
}
if(c == '\n') {
is.unget();
}
/* Find first non-uppercase or non-digit character */
for (i=0; i<8; ++i) {
if ( !(isupper(buf[i]) || isdigit(buf[i])) ) {
break;
}
}
/* Check if remaining characters are blank */
for (j = i; j<8; ++j) {
if(!isspace(buf[j]) && buf[j] != '\0') {
return false; /* CHARACTER AFTER SPACE OR INVALID CHARACTER */
}
buf[j] = '\0';
}
keyword = std::string(buf);
std::string::size_type end = keyword.find_last_of('\0');
if(end != keyword.npos)
keyword = keyword.substr(0, end+1);
return true;
}
/// Read the given stream, overwriting any previous data.
//---------------------------------------------------------------------------
void EclipseGridParser::read(istream& is, bool convert_to_SI)
@ -1086,47 +1078,47 @@ void EclipseGridParser::getNumericErtFields(const string& filename)
std::vector<double> double_vec;
std::vector<int> int_vec;
for (int i=0; i<num_kw; ++i) {
ecl_kw_type * ecl_kw = ecl_file_iget_kw(ecl_file, i);
const char* keyword = ecl_kw_get_header(ecl_kw);
FieldType field_type = classifyKeyword(keyword);
if (field_type == Unknown) {
ignored_fields_.insert(keyword);
cout << "*** Warning: keyword " << keyword << " is unknown." << endl;
continue;
} else {
ecl_kw_type * ecl_kw = ecl_file_iget_kw(ecl_file, i);
const char* keyword = ecl_kw_get_header(ecl_kw);
FieldType field_type = classifyKeyword(keyword);
if (field_type == Unknown) {
ignored_fields_.insert(keyword);
cout << "*** Warning: keyword " << keyword << " is unknown." << endl;
continue;
} else {
#ifdef VERBOSE
cout << "Imported keyword found: " << keyword << endl;
cout << "Imported keyword found: " << keyword << endl;
#endif
}
ecl_type_enum ecl_type = ecl_kw_get_type(ecl_kw);
int data_size = ecl_kw_get_size(ecl_kw);
switch(ecl_type) {
case ECL_FLOAT_TYPE : {
double_vec.resize(data_size);
ecl_kw_get_data_as_double(ecl_kw, &double_vec[0]);
floating_field_map_[keyword] = double_vec;
break;
}
case ECL_DOUBLE_TYPE : {
double_vec.resize(data_size);
ecl_kw_get_memcpy_double_data(ecl_kw, &double_vec[0]);
floating_field_map_[keyword] = double_vec;
break;
}
case ECL_INT_TYPE : {
int_vec.resize(data_size);
ecl_kw_get_memcpy_int_data(ecl_kw, &int_vec[0]);
integer_field_map_[keyword] = int_vec;
break;
}
default: {
std::cout << "Ignored non-numeric type in file: " << filename << " Keyword="
<< keyword << " Size=" << ecl_kw_get_size(ecl_kw)
<< " Type=" << ecl_util_get_type_name(ecl_kw_get_type(ecl_kw))
<< std::endl;
break;
}
}
}
ecl_type_enum ecl_type = ecl_kw_get_type(ecl_kw);
int data_size = ecl_kw_get_size(ecl_kw);
switch(ecl_type) {
case ECL_FLOAT_TYPE : {
double_vec.resize(data_size);
ecl_kw_get_data_as_double(ecl_kw, &double_vec[0]);
floating_field_map_[keyword] = double_vec;
break;
}
case ECL_DOUBLE_TYPE : {
double_vec.resize(data_size);
ecl_kw_get_memcpy_double_data(ecl_kw, &double_vec[0]);
floating_field_map_[keyword] = double_vec;
break;
}
case ECL_INT_TYPE : {
int_vec.resize(data_size);
ecl_kw_get_memcpy_int_data(ecl_kw, &int_vec[0]);
integer_field_map_[keyword] = int_vec;
break;
}
default: {
std::cout << "Ignored non-numeric type in file: " << filename << " Keyword="
<< keyword << " Size=" << ecl_kw_get_size(ecl_kw)
<< " Type=" << ecl_util_get_type_name(ecl_kw_get_type(ecl_kw))
<< std::endl;
break;
}
}
}
ecl_file_close(ecl_file);
#else

View File

@ -71,9 +71,23 @@ namespace Opm
*/
class EclipseGridParser
{
public:
enum FieldType {
Integer,
FloatingPoint,
Timestepping,
SpecialField,
IgnoreWithData,
IgnoreNoData,
Include,
Import,
Unknown
};
class EclipseGridParser
{
public:
/// Default constructor.
EclipseGridParser();
/// Constructor taking an eclipse filename. Unless the second
@ -81,6 +95,11 @@ public:
/// converted to SI units.
explicit EclipseGridParser(const std::string& filename, bool convert_to_SI = true);
static FieldType classifyKeyword(const std::string& keyword);
static bool readKeyword(std::istream& is, std::string& keyword);
/// Read the given stream, overwriting any previous data. Unless
/// the second argument 'convert_to_SI' is false, all fields will
/// be converted to SI units.
@ -240,6 +259,7 @@ private:
};
} // namespace Opm
#endif // SINTEF_ECLIPSEGRIDPARSER_HEADER