2019-03-28 15:03:20 +01:00
# include <chrono>
# include <iomanip>
2019-05-02 15:01:20 +02:00
# include <iostream>
# include <tuple>
2019-07-18 17:55:34 +02:00
# include <getopt.h>
2022-10-31 14:58:10 +01:00
# include <filesystem>
2019-03-28 15:03:20 +01:00
2019-05-02 15:01:20 +02:00
# include <opm/io/eclipse/EclFile.hpp>
2019-07-18 17:55:34 +02:00
# include <opm/io/eclipse/ERst.hpp>
2019-05-02 15:01:20 +02:00
# include <opm/io/eclipse/EclOutput.hpp>
2019-03-28 15:03:20 +01:00
2019-05-24 15:26:01 +02:00
using namespace Opm : : EclIO ;
2020-03-24 08:05:34 +01:00
using EclEntry = EclFile : : EclEntry ;
2019-03-28 15:03:20 +01:00
2019-07-18 17:55:34 +02:00
template < typename T >
2019-03-28 15:03:20 +01:00
void write ( EclOutput & outFile , EclFile & file1 ,
const std : : string & name , int index )
{
auto vect = file1 . get < T > ( index ) ;
outFile . write ( name , vect ) ;
}
2019-07-18 17:55:34 +02:00
template < typename T >
void write ( EclOutput & outFile , ERst & file1 ,
2019-11-03 19:34:25 +01:00
const std : : string & name , int index , int reportStepNumber )
2019-07-18 17:55:34 +02:00
{
2020-11-25 10:55:22 +01:00
auto vect = file1 . getRestartData < T > ( index , reportStepNumber ) ;
2019-11-03 19:34:25 +01:00
outFile . write ( name , vect ) ;
}
2019-07-18 17:55:34 +02:00
2019-11-03 19:34:25 +01:00
template < typename T >
void write ( EclOutput & outFile , ERst & file1 ,
const std : : string & name , int index )
{
auto vect = file1 . get < T > ( index ) ;
2019-07-18 17:55:34 +02:00
outFile . write ( name , vect ) ;
}
2019-11-03 19:34:25 +01:00
2019-07-18 17:55:34 +02:00
template < typename T >
void writeArray ( std : : string name , eclArrType arrType , T & file1 , int index , EclOutput & outFile ) {
if ( arrType = = INTE ) {
write < int > ( outFile , file1 , name , index ) ;
} else if ( arrType = = REAL ) {
write < float > ( outFile , file1 , name , index ) ;
} else if ( arrType = = DOUB ) {
write < double > ( outFile , file1 , name , index ) ;
} else if ( arrType = = LOGI ) {
write < bool > ( outFile , file1 , name , index ) ;
} else if ( arrType = = CHAR ) {
write < std : : string > ( outFile , file1 , name , index ) ;
2020-11-02 22:14:49 +01:00
} else if ( arrType = = C0NN ) {
write < std : : string > ( outFile , file1 , name , index ) ;
2019-07-18 17:55:34 +02:00
} else if ( arrType = = MESS ) {
outFile . message ( name ) ;
} else {
std : : cout < < " unknown array type " < < std : : endl ;
exit ( 1 ) ;
}
}
2020-11-02 22:14:49 +01:00
2019-11-03 19:34:25 +01:00
template < typename T >
void writeArray ( std : : string name , eclArrType arrType , T & file1 , int index , int reportStepNumber , EclOutput & outFile ) {
if ( arrType = = INTE ) {
write < int > ( outFile , file1 , name , index , reportStepNumber ) ;
} else if ( arrType = = REAL ) {
write < float > ( outFile , file1 , name , index , reportStepNumber ) ;
} else if ( arrType = = DOUB ) {
write < double > ( outFile , file1 , name , index , reportStepNumber ) ;
} else if ( arrType = = LOGI ) {
write < bool > ( outFile , file1 , name , index , reportStepNumber ) ;
} else if ( arrType = = CHAR ) {
write < std : : string > ( outFile , file1 , name , index , reportStepNumber ) ;
} else if ( arrType = = MESS ) {
outFile . message ( name ) ;
} else {
std : : cout < < " unknown array type " < < std : : endl ;
exit ( 1 ) ;
}
}
2020-11-02 22:14:49 +01:00
void writeC0nnArray ( std : : string name , int elementSize , EclFile & file1 , int index , EclOutput & outFile )
{
auto vect = file1 . get < std : : string > ( index ) ;
outFile . write ( name , vect , elementSize ) ;
}
void writeArrayList ( std : : vector < EclEntry > & arrayList , std : : vector < int > & elementSizeList , EclFile file1 , EclOutput & outFile ) {
2019-07-18 17:55:34 +02:00
for ( size_t index = 0 ; index < arrayList . size ( ) ; index + + ) {
std : : string name = std : : get < 0 > ( arrayList [ index ] ) ;
eclArrType arrType = std : : get < 1 > ( arrayList [ index ] ) ;
2020-11-02 22:14:49 +01:00
if ( arrType = = Opm : : EclIO : : C0NN ) {
writeC0nnArray ( name , elementSizeList [ index ] , file1 , index , outFile ) ;
} else
writeArray ( name , arrType , file1 , index , outFile ) ;
2019-07-18 17:55:34 +02:00
}
}
void writeArrayList ( std : : vector < EclEntry > & arrayList , ERst file1 , int reportStepNumber , EclOutput & outFile ) {
for ( size_t index = 0 ; index < arrayList . size ( ) ; index + + ) {
std : : string name = std : : get < 0 > ( arrayList [ index ] ) ;
eclArrType arrType = std : : get < 1 > ( arrayList [ index ] ) ;
2019-11-03 19:34:25 +01:00
writeArray ( name , arrType , file1 , index , reportStepNumber , outFile ) ;
2019-07-18 17:55:34 +02:00
}
}
static void printHelp ( ) {
std : : cout < < " \n convertECL needs one argument which is the input file to be converted. If this is a binary file the output file will be formatted. If the input file is formatted the output will be binary. \n "
< < " \n In addition, the program takes these options (which must be given before the arguments): \n \n "
< < " -h Print help and exit. \n "
2020-11-02 22:14:49 +01:00
< < " -l List report step numbers in the selected restart file. \n "
2022-10-31 14:58:10 +01:00
< < " -g Convert file to grdecl format. \n "
< < " -o Specify output file name (only valid with grdecl option). \n "
2020-11-02 22:14:49 +01:00
< < " -i Enforce IX standard on output file. \n "
2022-10-29 00:05:49 +02:00
< < " -r Extract and convert a specific report time step number from a unified restart file. \n \n " ;
2019-07-18 17:55:34 +02:00
}
2022-10-31 14:58:10 +01:00
2023-01-04 11:22:59 +01:00
struct GrdeclDataFormatParams
2022-10-31 14:58:10 +01:00
{
int ncol ;
int w ;
int pre ;
2023-01-04 11:22:59 +01:00
bool is_string ;
bool is_int ;
} ;
template < typename T >
GrdeclDataFormatParams getFormat ( )
{
if constexpr ( std : : is_same < T , float > : : value ) {
return { 4 , 11 , 7 , false , false } ;
} else if constexpr ( std : : is_same < T , double > : : value ) {
return { 3 , 21 , 14 , false , false } ;
} else if constexpr ( std : : is_same < T , int > : : value ) {
return { 8 , 6 , - 1 , false , true } ;
} else if constexpr ( std : : is_same < T , std : : string > : : value ) {
return { 5 , - 1 , - 1 , true , false } ;
2022-10-31 14:58:10 +01:00
}
2023-01-04 11:22:59 +01:00
}
template < typename T >
void writeGrdeclData ( std : : ofstream & ofileH , const std : : string & name , const std : : vector < T > & array )
{
const auto p = getFormat < T > ( ) ;
2022-10-31 14:58:10 +01:00
int64_t data_size = static_cast < int64_t > ( array . size ( ) ) ;
ofileH < < " \n " < < name < < std : : endl ;
for ( int64_t n = 0 ; n < data_size ; n + + ) {
2023-01-04 11:22:59 +01:00
if ( p . is_string )
2022-10-31 14:58:10 +01:00
ofileH < < " " < < array [ n ] ;
2023-01-04 11:22:59 +01:00
else if ( p . is_int )
ofileH < < " " < < std : : setw ( p . w ) < < array [ n ] ;
2022-10-31 14:58:10 +01:00
else
2023-01-04 11:22:59 +01:00
ofileH < < " " < < std : : setw ( p . w ) < < std : : setprecision ( p . pre ) < < std : : scientific < < array [ n ] ;
2022-10-31 14:58:10 +01:00
2023-01-04 11:22:59 +01:00
if ( ( n + 1 ) % p . ncol = = 0 )
2022-10-31 14:58:10 +01:00
ofileH < < " \n " ;
}
ofileH < < " / \n " ;
}
void open_grdecl_output ( const std : : string & output_fname , const std : : string & input_file , std : : ofstream & ofileH )
{
if ( output_fname . empty ( ) ) {
std : : filesystem : : path inputfile ( input_file ) ;
std : : filesystem : : path rootName = inputfile . stem ( ) ;
std : : filesystem : : path path = inputfile . parent_path ( ) ;
std : : filesystem : : path grdeclfile ;
grdeclfile = path / rootName + = " .grdecl " ;
if ( std : : filesystem : : exists ( grdeclfile ) ) {
std : : cout < < " \n Error, cant make grdecl file " < < grdeclfile . string ( ) < < " . File exists \n " ;
exit ( 1 ) ;
}
ofileH . open ( grdeclfile , std : : ios : : out ) ;
} else {
std : : filesystem : : path grdeclfile ( output_fname ) ;
std : : filesystem : : path path = grdeclfile . parent_path ( ) ;
if ( ( path . empty ( ) ) | | ( std : : filesystem : : exists ( path ) ) ) {
if ( std : : filesystem : : exists ( grdeclfile ) ) {
std : : cout < < " \n Error, cant make grdecl file " < < grdeclfile . string ( ) < < " . File exists \n " ;
exit ( 1 ) ;
}
} else {
std : : cout < < " \n !Error, output directory : ' " < < path . string ( ) < < " ' doesn't exist \n " ;
exit ( 1 ) ;
}
ofileH . open ( grdeclfile . string ( ) , std : : ios : : out ) ;
}
}
2019-03-28 15:03:20 +01:00
int main ( int argc , char * * argv ) {
2019-07-18 17:55:34 +02:00
int c = 0 ;
int reportStepNumber = - 1 ;
bool specificReportStepNumber = false ;
bool listProperties = false ;
2020-11-02 22:14:49 +01:00
bool enforce_ix_output = false ;
2022-10-31 14:58:10 +01:00
bool to_grdecl = false ;
2019-07-18 17:55:34 +02:00
2022-10-31 14:58:10 +01:00
std : : map < std : : string , std : : string > to_formatted = { { " .EGRID " , " .FEGRID " } , { " .INIT " , " .FINIT " } , { " .SMSPEC " , " .FSMSPEC " } ,
{ " .UNSMRY " , " .FUNSMRY " } , { " .UNRST " , " .FUNRST " } , { " .RFT " , " .FRFT " } , { " .ESMRY " , " .FESMRY " } } ;
std : : map < std : : string , std : : string > to_binary = { { " .FEGRID " , " .EGRID " } , { " .FINIT " , " .INIT " } , { " .FSMSPEC " , " .SMSPEC " } ,
{ " .FUNSMRY " , " .UNSMRY " } , { " .FUNRST " , " .UNRST " } , { " .FRFT " , " .RFT " } , { " .FESMRY " , " .ESMRY " } } ;
std : : string output_fname ;
while ( ( c = getopt ( argc , argv , " hr:ligo: " ) ) ! = - 1 ) {
2019-07-18 17:55:34 +02:00
switch ( c ) {
case ' h ' :
printHelp ( ) ;
return 0 ;
case ' l ' :
listProperties = true ;
break ;
2022-10-31 14:58:10 +01:00
case ' g ' :
to_grdecl = true ;
break ;
2020-11-02 22:14:49 +01:00
case ' i ' :
enforce_ix_output = true ;
break ;
2019-07-18 17:55:34 +02:00
case ' r ' :
specificReportStepNumber = true ;
reportStepNumber = atoi ( optarg ) ;
break ;
2022-10-31 14:58:10 +01:00
case ' o ' :
output_fname = optarg ;
break ;
2019-07-18 17:55:34 +02:00
default :
return EXIT_FAILURE ;
}
2019-03-28 15:03:20 +01:00
}
2019-07-18 17:55:34 +02:00
int argOffset = optind ;
2022-10-31 14:58:10 +01:00
if ( ( ! output_fname . empty ( ) ) & & ( ! to_grdecl ) ) {
std : : cout < < " \n !Error, option -o only valid whit option -g \n \n " ;
exit ( 1 ) ;
}
2019-03-28 15:03:20 +01:00
// start reading
auto start = std : : chrono : : system_clock : : now ( ) ;
2019-07-18 17:55:34 +02:00
std : : string filename = argv [ argOffset ] ;
2019-03-28 15:03:20 +01:00
EclFile file1 ( filename ) ;
bool formattedOutput = file1 . formattedInput ( ) ? false : true ;
int p = filename . find_last_of ( " . " ) ;
int l = filename . length ( ) ;
std : : string rootN = filename . substr ( 0 , p ) ;
std : : string extension = filename . substr ( p , l - p ) ;
std : : string resFile ;
2022-10-31 14:58:10 +01:00
if ( to_grdecl ) {
auto array_list = file1 . getList ( ) ;
file1 . loadData ( ) ;
auto start_g = std : : chrono : : system_clock : : now ( ) ;
std : : ofstream ofileH ;
open_grdecl_output ( output_fname , filename , ofileH ) ;
for ( size_t n = 0 ; n < array_list . size ( ) ; n + + ) {
std : : string name = std : : get < 0 > ( array_list [ n ] ) ;
auto arr_type = std : : get < 1 > ( array_list [ n ] ) ;
if ( arr_type = = Opm : : EclIO : : REAL ) {
auto data = file1 . get < float > ( n ) ;
writeGrdeclData ( ofileH , name , data ) ;
} else if ( arr_type = = Opm : : EclIO : : DOUB ) {
auto data = file1 . get < double > ( n ) ;
writeGrdeclData ( ofileH , name , data ) ;
} else if ( arr_type = = Opm : : EclIO : : INTE ) {
auto data = file1 . get < int > ( n ) ;
writeGrdeclData ( ofileH , name , data ) ;
} else if ( arr_type = = Opm : : EclIO : : CHAR ) {
auto data = file1 . get < std : : string > ( n ) ;
writeGrdeclData ( ofileH , name , data ) ;
} else if ( arr_type = = Opm : : EclIO : : LOGI ) {
std : : cout < < " \n !Warning, skipping array ' " < < name < < " of type LOGI \n " ;
} else if ( arr_type = = Opm : : EclIO : : C0NN ) {
std : : cout < < " \n !Warning, skipping array ' " < < name < < " of type C0NN \n " ;
} else {
std : : cout < < " unknown data type for array " < < name < < std : : endl ;
exit ( 1 ) ;
}
}
auto end_g = std : : chrono : : system_clock : : now ( ) ;
std : : chrono : : duration < double > elapsed_seconds = end_g - start_g ;
std : : cout < < " \n runtime writing grdecl file : " < < elapsed_seconds . count ( ) < < " seconds \n " < < std : : endl ;
std : : cout < < std : : endl ;
return 0 ;
}
2019-07-18 17:55:34 +02:00
if ( listProperties ) {
if ( extension = = " .UNRST " ) {
ERst rst1 ( filename ) ;
rst1 . loadData ( " INTEHEAD " ) ;
std : : vector < int > reportStepList = rst1 . listOfReportStepNumbers ( ) ;
for ( auto seqn : reportStepList ) {
2020-11-25 10:55:22 +01:00
std : : vector < int > inteh = rst1 . getRestartData < int > ( " INTEHEAD " , seqn , 0 ) ;
2019-07-18 17:55:34 +02:00
std : : cout < < " Report step number: "
< < std : : setfill ( ' ' ) < < std : : setw ( 4 ) < < seqn < < " Date: " < < inteh [ 66 ] < < " / "
< < std : : setfill ( ' 0 ' ) < < std : : setw ( 2 ) < < inteh [ 65 ] < < " / "
< < std : : setfill ( ' 0 ' ) < < std : : setw ( 2 ) < < inteh [ 64 ] < < std : : endl ;
}
std : : cout < < std : : endl ;
} else {
std : : cout < < " \n !ERROR, option -l only only available for unified restart files (*.UNRST) " < < std : : endl ;
exit ( 1 ) ;
}
return 0 ;
}
2019-03-28 15:03:20 +01:00
if ( formattedOutput ) {
2020-05-10 11:05:55 +02:00
2019-09-16 15:02:21 +02:00
auto search = to_formatted . find ( extension ) ;
2020-05-10 11:05:55 +02:00
2019-09-16 15:02:21 +02:00
if ( search ! = to_formatted . end ( ) ) {
2020-05-10 11:05:55 +02:00
resFile = rootN + search - > second ;
2019-09-16 15:02:21 +02:00
} else if ( extension . substr ( 1 , 1 ) = = " X " ) {
2019-07-18 17:55:34 +02:00
resFile = rootN + " .F " + extension . substr ( 2 ) ;
} else if ( extension . substr ( 1 , 1 ) = = " S " ) {
resFile = rootN + " .A " + extension . substr ( 2 ) ;
} else {
2019-09-16 15:02:21 +02:00
std : : cout < < " \n !ERROR, unknown file type for input file ' " < < rootN + extension < < " ' \n " < < std : : endl ;
exit ( 1 ) ;
2019-07-18 17:55:34 +02:00
}
2019-03-28 15:03:20 +01:00
} else {
2020-05-10 11:05:55 +02:00
2019-09-16 15:02:21 +02:00
auto search = to_binary . find ( extension ) ;
if ( search ! = to_binary . end ( ) ) {
2020-05-10 11:05:55 +02:00
resFile = rootN + search - > second ;
2019-09-16 15:02:21 +02:00
} else if ( extension . substr ( 1 , 1 ) = = " F " ) {
2019-07-18 17:55:34 +02:00
resFile = rootN + " .X " + extension . substr ( 2 ) ;
} else if ( extension . substr ( 1 , 1 ) = = " A " ) {
resFile = rootN + " .S " + extension . substr ( 2 ) ;
} else {
2019-09-16 15:02:21 +02:00
std : : cout < < " \n !ERROR, unknown file type for input file ' " < < rootN + extension < < " ' \n " < < std : : endl ;
exit ( 1 ) ;
2019-07-18 17:55:34 +02:00
}
2019-03-28 15:03:20 +01:00
}
2019-07-18 17:55:34 +02:00
std : : cout < < " \033 [1;31m " < < " \n converting " < < argv [ argOffset ] < < " -> " < < resFile < < " \033 [0m \n " < < std : : endl ;
2019-03-28 15:03:20 +01:00
EclOutput outFile ( resFile , formattedOutput ) ;
2020-11-02 22:14:49 +01:00
if ( ( file1 . is_ix ( ) ) | | ( enforce_ix_output ) ) {
std : : cout < < " setting IX flag on output file \n " ;
outFile . set_ix ( ) ;
}
2019-07-18 17:55:34 +02:00
if ( specificReportStepNumber ) {
2019-03-28 15:03:20 +01:00
2019-07-18 17:55:34 +02:00
if ( extension ! = " .UNRST " ) {
std : : cout < < " \n !ERROR, option -r only can only be used with unified restart files (*.UNRST) " < < std : : endl ;
exit ( 1 ) ;
}
2019-03-28 15:03:20 +01:00
2019-07-18 17:55:34 +02:00
ERst rst1 ( filename ) ;
if ( ! rst1 . hasReportStepNumber ( reportStepNumber ) ) {
std : : cout < < " \n !ERROR, selected unified restart file doesn't have report step number " < < reportStepNumber < < " \n " < < std : : endl ;
2019-03-28 15:03:20 +01:00
exit ( 1 ) ;
}
2019-07-18 17:55:34 +02:00
rst1 . loadReportStepNumber ( reportStepNumber ) ;
auto arrayList = rst1 . listOfRstArrays ( reportStepNumber ) ;
writeArrayList ( arrayList , rst1 , reportStepNumber , outFile ) ;
} else {
file1 . loadData ( ) ;
auto arrayList = file1 . getList ( ) ;
2020-11-02 22:14:49 +01:00
std : : vector < int > elementSizeList = file1 . getElementSizeList ( ) ;
writeArrayList ( arrayList , elementSizeList , file1 , outFile ) ;
2019-03-28 15:03:20 +01:00
}
2019-09-16 15:02:21 +02:00
auto end = std : : chrono : : system_clock : : now ( ) ;
std : : chrono : : duration < double > elapsed_seconds = end - start ;
2019-07-18 17:55:34 +02:00
2019-09-16 15:02:21 +02:00
std : : cout < < " runtime : " < < argv [ argOffset ] < < " : " < < elapsed_seconds . count ( ) < < " seconds \n " < < std : : endl ;
2019-03-28 15:03:20 +01:00
return 0 ;
}