diff --git a/examples/Makefile.am b/examples/Makefile.am index 145fbbdd..043a44c3 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -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 diff --git a/examples/import_rewrite.cpp b/examples/import_rewrite.cpp new file mode 100644 index 00000000..ef652f70 --- /dev/null +++ b/examples/import_rewrite.cpp @@ -0,0 +1,253 @@ +#if HAVE_CONFIG_H +#include "config.h" +#endif // HAVE_CONFIG_H + +#include + +#include + +#ifdef HAVE_ERT +#include +#include +#include +#include +#include +#include +#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); + } +} diff --git a/opm/core/eclipse/EclipseGridParser.cpp b/opm/core/eclipse/EclipseGridParser.cpp index 5e925bfe..5af1e2ec 100644 --- a/opm/core/eclipse/EclipseGridParser.cpp +++ b/opm/core/eclipse/EclipseGridParser.cpp @@ -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_vec; std::vector int_vec; for (int i=0; i