mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
Use commit 0e1e780fd6f18ce93119061e36a4fca9711bc020 Excluded multibuild folder, as this caused git issues
1561 lines
45 KiB
C++
1561 lines
45 KiB
C++
/*
|
|
Copyright (C) 2011 Equinor ASA, Norway.
|
|
|
|
The file 'ecl_util.c' is part of ERT - Ensemble based Reservoir Tool.
|
|
|
|
ERT 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.
|
|
|
|
ERT 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 at <http://www.gnu.org/licenses/gpl.html>
|
|
for more details.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <stdbool.h>
|
|
|
|
#include <ert/util/ert_api_config.hpp>
|
|
|
|
#include <ert/util/util.h>
|
|
#include <ert/util/hash.hpp>
|
|
#include <ert/util/stringlist.hpp>
|
|
#include <ert/util/parser.hpp>
|
|
|
|
#include <ert/ecl/ecl_util.hpp>
|
|
#include <ert/ecl/ecl_type.hpp>
|
|
|
|
|
|
#define ECL_PHASE_NAME_OIL "SOIL" // SHould match the keywords found in restart file
|
|
#define ECL_PHASE_NAME_WATER "SWAT"
|
|
#define ECL_PHASE_NAME_GAS "SGAS"
|
|
|
|
|
|
#define ECL_OTHER_FILE_FMT_PATTERN "*"
|
|
#define ECL_UNIFIED_RESTART_FMT_PATTERN "FUNRST"
|
|
#define ECL_UNIFIED_SUMMARY_FMT_PATTERN "FUNSMRY"
|
|
#define ECL_GRID_FMT_PATTERN "FGRID"
|
|
#define ECL_EGRID_FMT_PATTERN "FEGRID"
|
|
#define ECL_INIT_FMT_PATTERN "FINIT"
|
|
#define ECL_RFT_FMT_PATTERN "FRFT"
|
|
#define ECL_DATA_PATTERN "DATA"
|
|
|
|
#define ECL_OTHER_FILE_UFMT_PATTERN "*"
|
|
#define ECL_UNIFIED_RESTART_UFMT_PATTERN "UNRST"
|
|
#define ECL_UNIFIED_SUMMARY_UFMT_PATTERN "UNSMRY"
|
|
#define ECL_GRID_UFMT_PATTERN "GRID"
|
|
#define ECL_EGRID_UFMT_PATTERN "EGRID"
|
|
#define ECL_INIT_UFMT_PATTERN "INIT"
|
|
#define ECL_RFT_UFMT_PATTERN "RFT"
|
|
|
|
|
|
|
|
|
|
const char * ecl_util_get_phase_name( ecl_phase_enum phase ) {
|
|
switch( phase ) {
|
|
case( ECL_OIL_PHASE ):
|
|
return ECL_PHASE_NAME_OIL;
|
|
break;
|
|
case( ECL_WATER_PHASE ):
|
|
return ECL_PHASE_NAME_WATER;
|
|
break;
|
|
case( ECL_GAS_PHASE ):
|
|
return ECL_PHASE_NAME_GAS;
|
|
break;
|
|
default:
|
|
util_abort("%s: phase enum value:%d not recognized \n",__func__ , phase);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/*****************************************************************/
|
|
|
|
|
|
|
|
char * ecl_util_alloc_base_guess(const char * path) {
|
|
char * base = NULL;
|
|
stringlist_type * data_files = stringlist_alloc_new( );
|
|
stringlist_type * DATA_files = stringlist_alloc_new( );
|
|
stringlist_select_matching_files( data_files , path , "*.data");
|
|
stringlist_select_matching_files( DATA_files , path , "*.DATA");
|
|
|
|
if ((stringlist_get_size( data_files ) + stringlist_get_size( DATA_files)) == 1) {
|
|
const char * path_name;
|
|
|
|
if (stringlist_get_size( data_files ) == 1)
|
|
path_name = stringlist_iget( data_files , 0 );
|
|
else
|
|
path_name = stringlist_iget( DATA_files , 0 );
|
|
|
|
util_alloc_file_components( path_name , NULL , &base , NULL );
|
|
} // Else - found either 0 or more than 1 file with extension DATA - impossible to guess.
|
|
|
|
stringlist_free( data_files );
|
|
stringlist_free( DATA_files );
|
|
|
|
return base;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int ecl_util_filename_report_nr(const char *filename) {
|
|
int report_nr = -1;
|
|
ecl_util_get_file_type(filename, NULL, &report_nr);
|
|
return report_nr;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
We accept mixed lowercase/uppercase Eclipse file extensions even if Eclipse itself does not accept them.
|
|
*/
|
|
ecl_file_enum ecl_util_inspect_extension(const char * ext , bool *_fmt_file, int * _report_nr) {
|
|
ecl_file_enum file_type = ECL_OTHER_FILE;
|
|
bool fmt_file = true;
|
|
int report_nr = -1;
|
|
char* upper_ext = util_alloc_strupr_copy(ext);
|
|
if (strcmp(upper_ext , "UNRST") == 0) {
|
|
file_type = ECL_UNIFIED_RESTART_FILE;
|
|
fmt_file = false;
|
|
} else if (strcmp(upper_ext , "FUNRST") == 0) {
|
|
file_type = ECL_UNIFIED_RESTART_FILE;
|
|
fmt_file = true;
|
|
} else if (strcmp(upper_ext , "UNSMRY") == 0) {
|
|
file_type = ECL_UNIFIED_SUMMARY_FILE;
|
|
fmt_file = false;
|
|
} else if (strcmp(upper_ext , "FUNSMRY") == 0) {
|
|
file_type = ECL_UNIFIED_SUMMARY_FILE;
|
|
fmt_file = true;
|
|
} else if (strcmp(upper_ext , "SMSPEC") == 0) {
|
|
file_type = ECL_SUMMARY_HEADER_FILE;
|
|
fmt_file = false;
|
|
} else if (strcmp(upper_ext , "FSMSPEC") == 0) {
|
|
file_type = ECL_SUMMARY_HEADER_FILE;
|
|
fmt_file = true;
|
|
} else if (strcmp(upper_ext , "GRID") == 0) {
|
|
file_type = ECL_GRID_FILE;
|
|
fmt_file = false;
|
|
} else if (strcmp(upper_ext , "FGRID") == 0) {
|
|
file_type = ECL_GRID_FILE;
|
|
fmt_file = true;
|
|
} else if (strcmp(upper_ext , "EGRID") == 0) {
|
|
file_type = ECL_EGRID_FILE;
|
|
fmt_file = false;
|
|
} else if (strcmp(upper_ext , "FEGRID") == 0) {
|
|
file_type = ECL_EGRID_FILE;
|
|
fmt_file = true;
|
|
} else if (strcmp(upper_ext , "INIT") == 0) {
|
|
file_type = ECL_INIT_FILE;
|
|
fmt_file = false;
|
|
} else if (strcmp(upper_ext , "FINIT") == 0) {
|
|
file_type = ECL_INIT_FILE;
|
|
fmt_file = true;
|
|
} else if (strcmp(upper_ext , "FRFT") == 0) {
|
|
file_type = ECL_RFT_FILE;
|
|
fmt_file = true;
|
|
} else if (strcmp(upper_ext , "RFT") == 0) {
|
|
file_type = ECL_RFT_FILE;
|
|
fmt_file = false;
|
|
} else if (strcmp(upper_ext , "DATA") == 0) {
|
|
file_type = ECL_DATA_FILE;
|
|
fmt_file = true; /* Not really relevant ... */
|
|
} else {
|
|
switch (upper_ext[0]) {
|
|
case('X'):
|
|
file_type = ECL_RESTART_FILE;
|
|
fmt_file = false;
|
|
break;
|
|
case('F'):
|
|
file_type = ECL_RESTART_FILE;
|
|
fmt_file = true;
|
|
break;
|
|
case('S'):
|
|
file_type = ECL_SUMMARY_FILE;
|
|
fmt_file = false;
|
|
break;
|
|
case('A'):
|
|
file_type = ECL_SUMMARY_FILE;
|
|
fmt_file = true;
|
|
break;
|
|
default:
|
|
file_type = ECL_OTHER_FILE;
|
|
}
|
|
if (file_type != ECL_OTHER_FILE)
|
|
if (!util_sscanf_int(&upper_ext[1] , &report_nr))
|
|
file_type = ECL_OTHER_FILE;
|
|
}
|
|
|
|
if (_fmt_file != NULL)
|
|
*_fmt_file = fmt_file;
|
|
|
|
if (_report_nr != NULL)
|
|
*_report_nr = report_nr;
|
|
|
|
free( upper_ext );
|
|
return file_type;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
This function takes an eclipse filename as input - looks at the
|
|
extension, and uses that to determine the type of file. In addition
|
|
to the fundamental type, it is also determined whether the file is
|
|
formatted or not, and in the case of summary/restart files, which
|
|
report number this corresponds to.
|
|
*/
|
|
|
|
|
|
ecl_file_enum ecl_util_get_file_type(const char * filename, bool *fmt_file, int * report_nr) {
|
|
char *ext = (char*)strrchr(filename , '.');
|
|
if (ext == NULL)
|
|
return ECL_OTHER_FILE;
|
|
|
|
return ecl_util_inspect_extension( &ext[1] , fmt_file , report_nr);
|
|
}
|
|
|
|
static const char * ecl_util_get_file_pattern( ecl_file_enum file_type , bool fmt_file ) {
|
|
if (fmt_file) {
|
|
switch( file_type ) {
|
|
case( ECL_OTHER_FILE ):
|
|
return ECL_OTHER_FILE_FMT_PATTERN; /* '*' */
|
|
break;
|
|
case( ECL_UNIFIED_RESTART_FILE ):
|
|
return ECL_UNIFIED_RESTART_FMT_PATTERN;
|
|
break;
|
|
case( ECL_UNIFIED_SUMMARY_FILE ):
|
|
return ECL_UNIFIED_SUMMARY_FMT_PATTERN;
|
|
break;
|
|
case( ECL_GRID_FILE):
|
|
return ECL_GRID_FMT_PATTERN;
|
|
break;
|
|
case( ECL_EGRID_FILE ):
|
|
return ECL_EGRID_FMT_PATTERN;
|
|
break;
|
|
case( ECL_INIT_FILE ):
|
|
return ECL_INIT_FMT_PATTERN;
|
|
break;
|
|
case( ECL_RFT_FILE ):
|
|
return ECL_RFT_FMT_PATTERN;
|
|
break;
|
|
case( ECL_DATA_FILE ):
|
|
return ECL_DATA_PATTERN;
|
|
break;
|
|
default:
|
|
util_abort("%s: No pattern defined for til_type:%d \n",__func__ , file_type);
|
|
return NULL;
|
|
}
|
|
} else {
|
|
switch( file_type ) {
|
|
case( ECL_OTHER_FILE ):
|
|
return ECL_OTHER_FILE_UFMT_PATTERN; /* '*' */
|
|
break;
|
|
case( ECL_UNIFIED_RESTART_FILE ):
|
|
return ECL_UNIFIED_RESTART_UFMT_PATTERN;
|
|
break;
|
|
case( ECL_UNIFIED_SUMMARY_FILE ):
|
|
return ECL_UNIFIED_SUMMARY_UFMT_PATTERN;
|
|
break;
|
|
case( ECL_GRID_FILE):
|
|
return ECL_GRID_UFMT_PATTERN;
|
|
break;
|
|
case( ECL_EGRID_FILE ):
|
|
return ECL_EGRID_UFMT_PATTERN;
|
|
break;
|
|
case( ECL_INIT_FILE ):
|
|
return ECL_INIT_UFMT_PATTERN;
|
|
break;
|
|
case( ECL_RFT_FILE ):
|
|
return ECL_RFT_UFMT_PATTERN;
|
|
break;
|
|
default:
|
|
util_abort("%s: No pattern defined for til_type:%d \n",__func__ , file_type);
|
|
return NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
Takes an ecl_file_enum variable and returns string with a
|
|
descriptive name of this file type.
|
|
*/
|
|
const char * ecl_util_file_type_name( ecl_file_enum file_type ) {
|
|
switch (file_type) {
|
|
case(ECL_OTHER_FILE):
|
|
return "ECL_OTHER_FILE";
|
|
break;
|
|
case(ECL_RESTART_FILE):
|
|
return "ECL_RESTART_FILE";
|
|
break;
|
|
case(ECL_UNIFIED_RESTART_FILE):
|
|
return "ECL_UNIFIED_RESTART_FILE";
|
|
break;
|
|
case(ECL_SUMMARY_FILE):
|
|
return "ECL_SUMMARY_FILE";
|
|
break;
|
|
case(ECL_UNIFIED_SUMMARY_FILE):
|
|
return "ECL_UNIFIED_SUMMARY_FILE";
|
|
break;
|
|
case(ECL_SUMMARY_HEADER_FILE):
|
|
return "ECL_SUMMARY_HEADER_FILE";
|
|
break;
|
|
case(ECL_GRID_FILE):
|
|
return "ECL_GRID_FILE";
|
|
break;
|
|
case(ECL_EGRID_FILE):
|
|
return "ECL_EGRID_FILE";
|
|
break;
|
|
case(ECL_INIT_FILE):
|
|
return "ECL_INIT_FILE";
|
|
break;
|
|
case(ECL_RFT_FILE):
|
|
return "ECL_RFT_FILE";
|
|
break;
|
|
case(ECL_DATA_FILE):
|
|
return "ECL_DATA_FILE";
|
|
break;
|
|
default:
|
|
util_abort("%s: internal error type.%d not recognizxed \n",__func__ , file_type);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static bool valid_base(const char * input_base, bool * upper_case) {
|
|
bool upper = false;
|
|
bool lower = false;
|
|
const char * base = strrchr(input_base, UTIL_PATH_SEP_CHAR);
|
|
if (base == NULL)
|
|
base = input_base;
|
|
|
|
for (size_t i=0; i < strlen(base); i++) {
|
|
unsigned char c = base[i];
|
|
|
|
if (isupper(c))
|
|
upper = true;
|
|
|
|
if (islower(c))
|
|
lower = true;
|
|
|
|
}
|
|
|
|
if (upper_case)
|
|
*upper_case = upper;
|
|
return !(lower && upper);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
This function takes a path, along with a filetype as input and
|
|
allocates a new string with the filename. If path == NULL, the
|
|
filename is allocated without a leading path component.
|
|
|
|
If the flag 'must_exist' is set to true the function will check
|
|
with the filesystem if the file actually exists; if the file does
|
|
not exist NULL is returned.
|
|
*/
|
|
|
|
static char * ecl_util_alloc_filename_static(const char * path, const char * base , ecl_file_enum file_type , bool fmt_file, int report_nr, bool must_exist) {
|
|
bool upper_case;
|
|
if (!valid_base(base, &upper_case))
|
|
return NULL;
|
|
|
|
|
|
char * filename;
|
|
char * ext;
|
|
switch (file_type) {
|
|
case(ECL_RESTART_FILE):
|
|
if (fmt_file)
|
|
ext = util_alloc_sprintf("F%04d" , report_nr);
|
|
else
|
|
ext = util_alloc_sprintf("X%04d" , report_nr);
|
|
break;
|
|
|
|
case(ECL_UNIFIED_RESTART_FILE):
|
|
if (fmt_file)
|
|
ext = util_alloc_string_copy("FUNRST");
|
|
else
|
|
ext = util_alloc_string_copy("UNRST");
|
|
break;
|
|
|
|
case(ECL_SUMMARY_FILE):
|
|
if (fmt_file)
|
|
ext = util_alloc_sprintf("A%04d" , report_nr);
|
|
else
|
|
ext = util_alloc_sprintf("S%04d" , report_nr);
|
|
break;
|
|
|
|
case(ECL_UNIFIED_SUMMARY_FILE):
|
|
if (fmt_file)
|
|
ext = util_alloc_string_copy("FUNSMRY");
|
|
else
|
|
ext = util_alloc_string_copy("UNSMRY");
|
|
break;
|
|
|
|
case(ECL_SUMMARY_HEADER_FILE):
|
|
if (fmt_file)
|
|
ext = util_alloc_string_copy("FSMSPEC");
|
|
else
|
|
ext = util_alloc_string_copy("SMSPEC");
|
|
break;
|
|
|
|
case(ECL_GRID_FILE):
|
|
if (fmt_file)
|
|
ext = util_alloc_string_copy("FGRID");
|
|
else
|
|
ext = util_alloc_string_copy("GRID");
|
|
break;
|
|
|
|
case(ECL_EGRID_FILE):
|
|
if (fmt_file)
|
|
ext = util_alloc_string_copy("FEGRID");
|
|
else
|
|
ext = util_alloc_string_copy("EGRID");
|
|
break;
|
|
|
|
case(ECL_INIT_FILE):
|
|
if (fmt_file)
|
|
ext = util_alloc_string_copy("FINIT");
|
|
else
|
|
ext = util_alloc_string_copy("INIT");
|
|
break;
|
|
|
|
case(ECL_RFT_FILE):
|
|
if (fmt_file)
|
|
ext = util_alloc_string_copy("FRFT");
|
|
else
|
|
ext = util_alloc_string_copy("RFT");
|
|
break;
|
|
|
|
case(ECL_DATA_FILE):
|
|
ext = util_alloc_string_copy("DATA");
|
|
break;
|
|
|
|
default:
|
|
util_abort("%s: Invalid input file_type to ecl_util_alloc_filename - aborting \n",__func__);
|
|
/* Dummy to shut up compiler */
|
|
ext = NULL;
|
|
}
|
|
|
|
if (!upper_case) {
|
|
for (size_t i=0; i < strlen(ext); i++)
|
|
ext[i] = tolower(ext[i]);
|
|
}
|
|
|
|
filename = util_alloc_filename(path , base , ext);
|
|
free(ext);
|
|
|
|
if (must_exist) {
|
|
if (!util_file_exists( filename )) {
|
|
free(filename);
|
|
filename = NULL;
|
|
}
|
|
}
|
|
|
|
return filename;
|
|
}
|
|
|
|
|
|
char * ecl_util_alloc_filename(const char * path, const char * base , ecl_file_enum file_type , bool fmt_file, int report_nr) {
|
|
return ecl_util_alloc_filename_static(path , base , file_type ,fmt_file , report_nr , false);
|
|
}
|
|
|
|
|
|
|
|
char * ecl_util_alloc_exfilename(const char * path, const char * base , ecl_file_enum file_type , bool fmt_file, int report_nr) {
|
|
return ecl_util_alloc_filename_static(path , base , file_type ,fmt_file , report_nr , true);
|
|
}
|
|
|
|
|
|
/**
|
|
This function will first try if the 'fmt_file' file exists, and
|
|
then subsequently the !fmt_file version. If neither can be found it
|
|
will return NULL.
|
|
*/
|
|
|
|
char * ecl_util_alloc_exfilename_anyfmt(const char * path, const char * base , ecl_file_enum file_type , bool fmt_file_first , int report_nr) {
|
|
|
|
char * filename = ecl_util_alloc_filename( path , base , file_type , fmt_file_first , report_nr);
|
|
if (!util_file_exists( filename )) {
|
|
free( filename );
|
|
filename = ecl_util_alloc_filename( path , base , file_type , !fmt_file_first , report_nr);
|
|
}
|
|
|
|
if (! util_file_exists(filename)) {
|
|
free( filename );
|
|
filename = NULL;
|
|
}
|
|
|
|
return filename;
|
|
}
|
|
|
|
|
|
/**
|
|
This function assumes that:
|
|
|
|
o Both files are of the same type (i.e. both summary files) (this
|
|
is not checked for).
|
|
|
|
o Both files are of type WITH a nnnn number at the end, the
|
|
function will fail hard in ecl_util_filename_report_nr() if
|
|
this is not the case.
|
|
|
|
*/
|
|
|
|
|
|
int ecl_util_fname_report_cmp(const void *f1, const void *f2) {
|
|
|
|
int t1 = ecl_util_filename_report_nr( (const char *) f1 );
|
|
int t2 = ecl_util_filename_report_nr( (const char *) f2 );
|
|
|
|
if (t1 < t2)
|
|
return -1;
|
|
else if (t1 > t2)
|
|
return 1;
|
|
else
|
|
return 0;
|
|
|
|
}
|
|
|
|
/**
|
|
This function will scan the directory @path (or cwd if @path == NULL)
|
|
for all ECLIPSE files of type @file_type. If base == NULL it will use
|
|
'*' as pattern for basename. If file_type == ECL_OTHER_FILE it will
|
|
use '*' as pattern for the extension (as a consequence files which do
|
|
not originate from ECLIPSE will also be included).
|
|
|
|
The stringlist will be cleared before the actual matching process
|
|
starts.
|
|
*/
|
|
|
|
static bool numeric_extension_predicate(const char * filename, const char * base, const char leading_char) {
|
|
if (strncmp(filename, base, strlen(base)) != 0)
|
|
return false;
|
|
|
|
const char * ext_start = strrchr(filename, '.');
|
|
if (!ext_start)
|
|
return false;
|
|
|
|
if (strlen(ext_start) != 6)
|
|
return false;
|
|
|
|
if (ext_start[1] != leading_char)
|
|
return false;
|
|
|
|
for (int i=0; i < 4; i++)
|
|
if (!isdigit(ext_start[i+2]))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
static bool summary_UPPERCASE_ASCII(const char * filename, const void * base) {
|
|
return numeric_extension_predicate(filename, (const char*)base, 'A');
|
|
}
|
|
|
|
static bool summary_UPPERCASE_BINARY(const char * filename, const void * base) {
|
|
return numeric_extension_predicate(filename, (const char*)base, 'S');
|
|
}
|
|
|
|
static bool summary_lowercase_ASCII(const char * filename, const void * base) {
|
|
return numeric_extension_predicate(filename, (const char*)base, 'a');
|
|
}
|
|
|
|
static bool summary_lowercase_BINARY(const char * filename, const void * base) {
|
|
return numeric_extension_predicate(filename, (const char*)base, 's');
|
|
}
|
|
|
|
static bool restart_UPPERCASE_ASCII(const char * filename, const void * base) {
|
|
return numeric_extension_predicate(filename, (const char*)base, 'F');
|
|
}
|
|
|
|
static bool restart_UPPERCASE_BINARY(const char * filename, const void * base) {
|
|
return numeric_extension_predicate(filename, (const char*)base, 'X');
|
|
}
|
|
|
|
static bool restart_lowercase_ASCII(const char * filename, const void * base) {
|
|
return numeric_extension_predicate(filename, (const char*)base, 'f');
|
|
}
|
|
|
|
static bool restart_lowercase_BINARY(const char * filename, const void * base) {
|
|
return numeric_extension_predicate(filename, (const char*)base, 'x');
|
|
}
|
|
|
|
static int ecl_util_select_predicate_filelist(const char * path, const char * base, ecl_file_enum file_type, bool fmt_file, bool upper_case, stringlist_type * filelist) {
|
|
file_pred_ftype * predicate = NULL;
|
|
char * full_path = NULL;
|
|
char * pure_base = NULL;
|
|
{
|
|
char * tmp = util_alloc_filename(path, base, NULL);
|
|
util_alloc_file_components(tmp, &full_path, &pure_base, NULL);
|
|
free(tmp);
|
|
}
|
|
|
|
if (file_type == ECL_SUMMARY_FILE) {
|
|
if (fmt_file) {
|
|
if (upper_case)
|
|
predicate = summary_UPPERCASE_ASCII;
|
|
else
|
|
predicate = summary_lowercase_ASCII;
|
|
} else {
|
|
if (upper_case)
|
|
predicate = summary_UPPERCASE_BINARY;
|
|
else
|
|
predicate = summary_lowercase_BINARY;
|
|
}
|
|
} else if (file_type == ECL_RESTART_FILE) {
|
|
if (fmt_file) {
|
|
if (upper_case)
|
|
predicate = restart_UPPERCASE_ASCII;
|
|
else
|
|
predicate = restart_lowercase_ASCII;
|
|
} else {
|
|
if (upper_case)
|
|
predicate = restart_UPPERCASE_BINARY;
|
|
else
|
|
predicate = restart_lowercase_BINARY;
|
|
}
|
|
} else
|
|
util_abort("%s: internal error - method called with wrong file type: %d\n", __func__, file_type);
|
|
|
|
stringlist_select_files(filelist, full_path, predicate, pure_base);
|
|
stringlist_sort( filelist , ecl_util_fname_report_cmp );
|
|
free(pure_base);
|
|
free(full_path);
|
|
return stringlist_get_size(filelist);
|
|
}
|
|
|
|
|
|
int ecl_util_select_filelist( const char * path , const char * base , ecl_file_enum file_type , bool fmt_file , stringlist_type * filelist) {
|
|
bool valid_case = true;
|
|
bool upper_case = true;
|
|
stringlist_clear(filelist);
|
|
|
|
if (base)
|
|
valid_case = valid_base(base, &upper_case);
|
|
|
|
if (valid_case) {
|
|
if (file_type == ECL_SUMMARY_FILE || file_type == ECL_RESTART_FILE)
|
|
return ecl_util_select_predicate_filelist(path, base, file_type, fmt_file, upper_case, filelist);
|
|
|
|
char * ext_pattern = util_alloc_string_copy(ecl_util_get_file_pattern( file_type , fmt_file ));
|
|
char * file_pattern;
|
|
|
|
if (!upper_case) {
|
|
for (size_t i=0; i < strlen(ext_pattern); i++)
|
|
ext_pattern[i] = tolower(ext_pattern[i]);
|
|
}
|
|
|
|
if (base)
|
|
file_pattern = util_alloc_filename(NULL , base, ext_pattern);
|
|
else
|
|
file_pattern = util_alloc_filename(NULL, "*", ext_pattern);
|
|
|
|
stringlist_select_matching_files( filelist , path , file_pattern );
|
|
free( file_pattern );
|
|
free( ext_pattern );
|
|
}
|
|
return stringlist_get_size( filelist );
|
|
}
|
|
|
|
|
|
bool ecl_util_unified_file(const char *filename) {
|
|
int report_nr;
|
|
ecl_file_enum file_type;
|
|
bool fmt_file;
|
|
file_type = ecl_util_get_file_type(filename , &fmt_file , &report_nr);
|
|
|
|
if ((file_type == ECL_UNIFIED_RESTART_FILE) || (file_type == ECL_UNIFIED_SUMMARY_FILE))
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
|
|
bool ecl_util_fmt_file(const char *filename , bool * __fmt_file) {
|
|
/*const int min_size = 32768;*/
|
|
const int min_size = 256; /* Veeeery small */
|
|
|
|
int report_nr;
|
|
ecl_file_enum file_type;
|
|
bool status = true;
|
|
bool fmt_file = 0;
|
|
|
|
if (util_file_exists(filename)) {
|
|
file_type = ecl_util_get_file_type(filename , &fmt_file , &report_nr);
|
|
if (file_type == ECL_OTHER_FILE) {
|
|
if (util_file_size(filename) > min_size)
|
|
fmt_file = util_fmt_bit8(filename);
|
|
else
|
|
status = false; // Do not know ??
|
|
}
|
|
} else {
|
|
file_type = ecl_util_get_file_type(filename , &fmt_file , &report_nr);
|
|
if (file_type == ECL_OTHER_FILE)
|
|
status = false; // Do not know ??
|
|
}
|
|
|
|
*__fmt_file = fmt_file;
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************/
|
|
|
|
|
|
|
|
|
|
/**
|
|
This function copies size elements from _src_data to target_data. If
|
|
src_type == target_type the copy is a simple memcpy, otherwise the
|
|
appropriate numerical conversion is applied.
|
|
*/
|
|
|
|
void ecl_util_memcpy_typed_data(void *_target_data , const void * _src_data , ecl_data_type target_type , ecl_data_type src_type, int size) {
|
|
int i;
|
|
|
|
if (ecl_type_is_equal(target_type, src_type))
|
|
memcpy(_target_data , _src_data , size * ecl_type_get_sizeof_ctype(src_type));
|
|
else {
|
|
switch (ecl_type_get_type(target_type)) {
|
|
case(ECL_DOUBLE_TYPE):
|
|
{
|
|
double * target_data = (double *) _target_data;
|
|
switch(ecl_type_get_type(src_type)) {
|
|
case(ECL_FLOAT_TYPE):
|
|
util_float_to_double(target_data , (const float *) _src_data , size);
|
|
break;
|
|
case(ECL_INT_TYPE):
|
|
for (i = 0; i < size; i++)
|
|
target_data[i] = ((int *) _src_data)[i];
|
|
break;
|
|
default:
|
|
util_abort("%s: double type can only load from int/float/double - aborting \n",__func__);
|
|
}
|
|
break;
|
|
}
|
|
case(ECL_FLOAT_TYPE):
|
|
{
|
|
float * target_data = (float *) _target_data;
|
|
switch(ecl_type_get_type(src_type)) {
|
|
case(ECL_FLOAT_TYPE):
|
|
util_double_to_float(target_data , (const double *) _src_data , size);
|
|
break;
|
|
case(ECL_INT_TYPE):
|
|
for (i = 0; i < size; i++)
|
|
target_data[i] = ((int *) _src_data)[i];
|
|
break;
|
|
default:
|
|
util_abort("%s: float type can only load from int/float/double - aborting \n",__func__);
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
util_abort("%s con not convert %s -> %s \n",__func__ , ecl_type_alloc_name(src_type) , ecl_type_alloc_name(target_type));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
The stringlist will be cleared before the actual matching process
|
|
starts. Observe that in addition to the @path input parameter the
|
|
@base input can contain an embedded path component.
|
|
*/
|
|
|
|
void ecl_util_alloc_summary_data_files(const char * path , const char * base , bool fmt_file , stringlist_type * filelist) {
|
|
char * unif_data_file = ecl_util_alloc_exfilename(path , base , ECL_UNIFIED_SUMMARY_FILE , fmt_file , -1);
|
|
int files = ecl_util_select_filelist( path , base , ECL_SUMMARY_FILE , fmt_file , filelist);
|
|
|
|
if ((files > 0) && (unif_data_file != NULL)) {
|
|
/*
|
|
We have both a unified file AND a list of files: BASE.S0000,
|
|
BASE.S0001, BASE.S0002, ..., must check which is newest and
|
|
load accordingly.
|
|
*/
|
|
bool unified_newest = true;
|
|
int file_nr = 0;
|
|
while (unified_newest && (file_nr < files)) {
|
|
if (util_file_difftime( stringlist_iget(filelist , file_nr) , unif_data_file ) > 0)
|
|
unified_newest = false;
|
|
file_nr++;
|
|
}
|
|
|
|
if (unified_newest) {
|
|
stringlist_clear( filelist ); /* Clear out all the BASE.Snnnn selections. */
|
|
stringlist_append_copy( filelist , unif_data_file );
|
|
}
|
|
} else if (unif_data_file != NULL) {
|
|
/* Found a unified summary file : Clear out all the BASE.Snnnn selections. */
|
|
stringlist_clear( filelist ); /* Clear out all the BASE.Snnnn selections. */
|
|
stringlist_append_copy( filelist , unif_data_file );
|
|
}
|
|
free( unif_data_file );
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
This routine allocates summary header and data files from a
|
|
directory, and return them by reference; path and base are
|
|
input. If the function can not find BOTH a summary header file and
|
|
summary data it will return false and not update the reference
|
|
variables.
|
|
|
|
For the header file there are two possible files:
|
|
|
|
1. X.FSMSPEC
|
|
2. X.SMSPEEC
|
|
|
|
For the data there are four different possibilities:
|
|
|
|
1. X.A0001, X.A0002, X.A0003, ...
|
|
2. X.FUNSMRY
|
|
3. X.S0001, X.S0002, X.S0003, ...
|
|
4. X.UNSMRY
|
|
|
|
In principle a directory can contain all different (altough that is
|
|
probably not typical). The algorithm is a a two step algorithm:
|
|
|
|
1. Determine wether to use X.FSMSPEC or X.SMSPEC based on which
|
|
is the newest. This also implies a decision of wether to use
|
|
formatted, or unformatted filed.
|
|
|
|
2. Use formatted or unformatted files according to 1. above, and
|
|
then choose either a list of files or unified files according
|
|
to which is the newest.
|
|
|
|
This algorithm should work in most practical cases, but it is
|
|
surely possible to fool it.
|
|
*/
|
|
|
|
|
|
bool ecl_util_alloc_summary_files(const char * path , const char * _base , const char * ext , char ** _header_file , stringlist_type * filelist) {
|
|
bool fmt_input = false;
|
|
bool fmt_set = false;
|
|
bool fmt_file = true;
|
|
bool unif_input = false;
|
|
bool unif_set = false;
|
|
|
|
|
|
char * header_file = NULL;
|
|
char * base;
|
|
|
|
*_header_file = NULL;
|
|
|
|
/* 1: We start by inspecting the input extension and see if we can
|
|
learn anything about formatted/unformatted and
|
|
unified/non-unified from this. The input extension can be NULL,
|
|
in which case we learn nothing.
|
|
*/
|
|
|
|
if (_base == NULL)
|
|
base = ecl_util_alloc_base_guess(path);
|
|
else
|
|
base = (char *) _base;
|
|
|
|
if (ext != NULL) {
|
|
ecl_file_enum input_type;
|
|
|
|
{
|
|
char * test_name = util_alloc_filename( NULL , base, ext );
|
|
input_type = ecl_util_get_file_type( test_name , &fmt_input , NULL);
|
|
free( test_name );
|
|
}
|
|
|
|
if ((input_type != ECL_OTHER_FILE) && (input_type != ECL_DATA_FILE)) {
|
|
/*
|
|
The file has been recognized as a file type from which we can
|
|
at least infer formatted/unformatted inforamtion.
|
|
*/
|
|
fmt_set = true;
|
|
switch (input_type) {
|
|
case(ECL_SUMMARY_FILE):
|
|
case(ECL_RESTART_FILE):
|
|
unif_input = false;
|
|
unif_set = true;
|
|
break;
|
|
case(ECL_UNIFIED_SUMMARY_FILE):
|
|
case(ECL_UNIFIED_RESTART_FILE):
|
|
unif_input = true;
|
|
unif_set = true;
|
|
break;
|
|
default: /* Nothing wrong with this */
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
2: We continue by looking for header files.
|
|
*/
|
|
|
|
{
|
|
char * fsmspec_file = ecl_util_alloc_exfilename(path , base , ECL_SUMMARY_HEADER_FILE , true , -1);
|
|
char * smspec_file = ecl_util_alloc_exfilename(path , base , ECL_SUMMARY_HEADER_FILE , false , -1);
|
|
|
|
if ((fsmspec_file == NULL) && (smspec_file == NULL)) /* Neither file exists */
|
|
return false;
|
|
|
|
|
|
if (fmt_set) /* The question of formatted|unformatted has already been settled based on the input filename. */
|
|
fmt_file = fmt_input;
|
|
else {
|
|
if ((fsmspec_file != NULL) && (smspec_file != NULL)) { /* Both fsmspec and smspec exist - we take the newest. */
|
|
if (util_file_difftime(fsmspec_file , smspec_file) < 0)
|
|
fmt_file = true;
|
|
else
|
|
fmt_file = false;
|
|
} else { /* Only one of fsmspec / smspec exists */
|
|
if (fsmspec_file != NULL)
|
|
fmt_file = true;
|
|
else
|
|
fmt_file = false;
|
|
}
|
|
}
|
|
|
|
if (fmt_file) {
|
|
header_file = fsmspec_file;
|
|
free( smspec_file );
|
|
} else {
|
|
header_file = smspec_file;
|
|
free( fsmspec_file );
|
|
}
|
|
|
|
if (header_file == NULL)
|
|
return false; /* If you insist on e.g. unformatted and only fsmspec exists - no results for you. */
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
3: OK - we have found a SMSPEC / FMSPEC file - continue to look for
|
|
XXX.Snnnn / XXX.UNSMRY files.
|
|
*/
|
|
|
|
if (unif_set) { /* Based on the input file we have inferred whether to look for unified or
|
|
non-unified input files. */
|
|
|
|
if ( unif_input ) {
|
|
char * unif_data_file = ecl_util_alloc_exfilename(path , base , ECL_UNIFIED_SUMMARY_FILE , fmt_file , -1);
|
|
if (unif_data_file != NULL) {
|
|
stringlist_append_copy( filelist , unif_data_file );
|
|
free( unif_data_file );
|
|
}
|
|
} else
|
|
ecl_util_select_filelist( path , base , ECL_SUMMARY_FILE , fmt_file , filelist);
|
|
} else
|
|
ecl_util_alloc_summary_data_files( path , base , fmt_file , filelist );
|
|
|
|
if (_base == NULL)
|
|
free(base);
|
|
|
|
*_header_file = header_file;
|
|
|
|
return (stringlist_get_size(filelist) > 0) ? true : false;
|
|
}
|
|
|
|
|
|
|
|
|
|
//const char * ecl_util_get_extension( ecl_file_enum_type file_type , bool fmt_file) {
|
|
//
|
|
//}
|
|
//
|
|
//
|
|
///**
|
|
// Based on the ordinary util_alloc_file_components function, but if
|
|
// file_type is used specify the type file we know what extension to
|
|
// expect, and an optional "." can potentially be included as part of
|
|
// the filename.
|
|
//*/
|
|
//
|
|
//void ecl_util_alloc_file_components( const char * file, ecl_file_enum file_type , char **_path , char **_basename , char **_extension) {
|
|
//
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
void ecl_util_alloc_restart_files(const char * path , const char * _base , char *** _restart_files , int * num_restart_files , bool * _fmt_file , bool * _unified) {
|
|
|
|
util_exit("Function:%s currently not implemented - sorry \n",__func__);
|
|
|
|
//char * base = NULL;
|
|
//if (_base == NULL)
|
|
// base = ecl_util_alloc_base_guess(path);
|
|
//else
|
|
// base = (char *) _base;
|
|
//{
|
|
// int num_F_files;
|
|
// int num_X_files;
|
|
//
|
|
// char * unrst_file = ecl_util_alloc_filename(path , base , ECL_UNIFIED_RESTART_FILE , false , -1);
|
|
// char * funrst_file = ecl_util_alloc_filename(path , base , ECL_UNIFIED_RESTART_FILE , true , -1);
|
|
// char * unif_file = NULL;
|
|
//
|
|
// char ** F_files = ecl_util_alloc_scandir_filelist(path , base , ECL_RESTART_FILE , true , &num_F_files);
|
|
// char ** X_files = ecl_util_alloc_scandir_filelist(path , base , ECL_RESTART_FILE , false , &num_X_files);
|
|
// char * FX_file = NULL;
|
|
// char * final_file;
|
|
//
|
|
// /*
|
|
// Ok now we have formatted/unformatted unified and not
|
|
// unified: Time to check what exists in the filesystem, and which
|
|
// is the newest.
|
|
// */
|
|
// unif_file = util_newest_file(unrst_file , funrst_file);
|
|
//
|
|
// if (num_F_files > 0 || num_X_files > 0) {
|
|
// if (num_F_files > 0 && num_X_files > 0) {
|
|
// /*
|
|
// We have both a list of .Fnnnn and a list of .Xnnnn files; if
|
|
// the length of lists is not equal we take the longest,
|
|
// otherwise we compare the dates of the last files in the
|
|
// list.
|
|
// */
|
|
// if (num_F_files == num_X_files) {
|
|
// FX_file = util_newest_file( F_files[num_F_files - 1] , X_files[num_X_files - 1]);
|
|
// } else if (num_F_files > num_X_files)
|
|
// FX_file = F_files[num_F_files - 1];
|
|
// else
|
|
// FX_file = X_files[num_X_files - 1];
|
|
// } else if (num_F_files > 0)
|
|
// FX_file = F_files[num_F_files - 1];
|
|
// else
|
|
// FX_file = X_files[num_X_files - 1];
|
|
//
|
|
// if (unif_file != NULL)
|
|
// final_file = util_newest_file(unif_file , FX_file);
|
|
// else
|
|
// final_file = FX_file;
|
|
// } else
|
|
// final_file = unif_file;
|
|
//
|
|
//
|
|
// if (final_file == NULL)
|
|
// util_abort("%s: could not find any restart data in %s/%s \n",__func__ , path , base);
|
|
//
|
|
//
|
|
// /*
|
|
// Determine type of final_file. Thois block is where the return
|
|
// values are actually set.
|
|
// */
|
|
// {
|
|
// char ** restart_files;
|
|
// bool fmt_file , unified;
|
|
// ecl_file_enum file_type;
|
|
//
|
|
// ecl_util_get_file_type( final_file , &file_type , &fmt_file , NULL);
|
|
// if (file_type == ECL_UNIFIED_RESTART_FILE) {
|
|
// *num_restart_files = 1;
|
|
// restart_files = util_malloc(sizeof * restart_files, __func__);
|
|
// restart_files[0] = util_alloc_string_copy( final_file );
|
|
// unified = true;
|
|
// } else {
|
|
// restart_files = ecl_util_alloc_scandir_filelist( path , base , ECL_RESTART_FILE , fmt_file , num_restart_files);
|
|
// unified = false;
|
|
// }
|
|
// *_restart_files = restart_files;
|
|
//
|
|
// if (_fmt_file != NULL) *_fmt_file = fmt_file;
|
|
// if (_unified != NULL) *_unified = unified;
|
|
// }
|
|
//
|
|
// util_free_stringlist(F_files , num_F_files);
|
|
// util_free_stringlist(X_files , num_X_files);
|
|
// free(unrst_file);
|
|
// free(funrst_file);
|
|
//}
|
|
//
|
|
//if (_base == NULL)
|
|
// free(base);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
This little function escapes eclipse keyword names so that they can be
|
|
safely used as filenames, i.e for instance the substitution:
|
|
|
|
1/FVFGAS -> 1-FVFGAS
|
|
|
|
The escape process is done 'in-place' memory-wise.
|
|
*/
|
|
void ecl_util_escape_kw(char * kw) {
|
|
size_t index;
|
|
for (index = 0; index < strlen(kw); index++) {
|
|
switch (kw[index]) {
|
|
case('/'):
|
|
kw[index] = '-';
|
|
break;
|
|
case('\\'):
|
|
kw[index] = '-';
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
Will return -1 for an unrecognized month name.
|
|
*/
|
|
|
|
static int ecl_util_get_month_nr__(const char * _month_name) {
|
|
int month_nr = -1;
|
|
char * month_name = util_alloc_string_copy(_month_name);
|
|
util_strupr(month_name);
|
|
|
|
if (strncmp(month_name , "JAN" , 3) == 0)
|
|
month_nr = 1;
|
|
else if (strncmp(month_name , "FEB" , 3) == 0)
|
|
month_nr = 2;
|
|
else if (strncmp(month_name , "MAR" , 3) == 0)
|
|
month_nr = 3;
|
|
else if (strncmp(month_name , "APR" , 3) == 0)
|
|
month_nr = 4;
|
|
else if (strncmp(month_name , "MAI" , 3) == 0)
|
|
month_nr = 5;
|
|
else if (strncmp(month_name , "MAY" , 3) == 0)
|
|
month_nr = 5;
|
|
else if (strncmp(month_name , "JUN" , 3) == 0)
|
|
month_nr = 6;
|
|
else if (strncmp(month_name , "JUL" , 3) == 0)
|
|
month_nr = 7;
|
|
else if (strncmp(month_name , "JLY" , 3) == 0) /* ECLIPSE ambigus on July. */
|
|
month_nr = 7;
|
|
else if (strncmp(month_name , "AUG" , 3) == 0)
|
|
month_nr = 8;
|
|
else if (strncmp(month_name , "SEP" , 3) == 0)
|
|
month_nr = 9;
|
|
else if (strncmp(month_name , "OCT" , 3) == 0)
|
|
month_nr = 10;
|
|
else if (strncmp(month_name , "OKT" , 3) == 0)
|
|
month_nr = 10;
|
|
else if (strncmp(month_name , "NOV" , 3) == 0)
|
|
month_nr = 11;
|
|
else if (strncmp(month_name , "DEC" , 3) == 0)
|
|
month_nr = 12;
|
|
else if (strncmp(month_name , "DES" , 3) == 0)
|
|
month_nr = 12;
|
|
free(month_name);
|
|
return month_nr;
|
|
}
|
|
|
|
|
|
int ecl_util_get_month_nr(const char * month_name) {
|
|
int month_nr = ecl_util_get_month_nr__(month_name);
|
|
if (month_nr < 0)
|
|
util_abort("%s: %s not a valid month name - aborting \n",__func__ , month_name);
|
|
|
|
return month_nr;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
I have *intentionally* dived straight at the problem of extracting
|
|
the start_date; otherwise one might quite quickly end up with a
|
|
half-baked DATA-file parser. I think that path leads straight to an
|
|
asylum. But of course - not many points are awarded for pointing out
|
|
that this parsing is extremly ugly.
|
|
|
|
ECLIPSE100 has default date: 1. of january 1983.
|
|
ECLIPSE300 has default date: 1. of january 1990.
|
|
|
|
They don't have much style those fuckers at Schlum ...
|
|
*/
|
|
|
|
|
|
time_t ecl_util_get_start_date(const char * data_file) {
|
|
basic_parser_type * parser = basic_parser_alloc(" \t\r\n" , "\"\'" , NULL , NULL , "--" , "\n");
|
|
time_t start_date = -1;
|
|
FILE * stream = util_fopen(data_file , "r");
|
|
char * buffer;
|
|
|
|
if (!basic_parser_fseek_string( parser , stream , "START" , true , true)) /* Seeks case insensitive. */
|
|
util_abort("%s: sorry - could not find START in DATA file %s \n",__func__ , data_file);
|
|
|
|
{
|
|
long int start_pos = util_ftell( stream );
|
|
int buffer_size;
|
|
|
|
/* Look for terminating '/' */
|
|
if (!basic_parser_fseek_string( parser , stream , "/" , false , true))
|
|
util_abort("%s: sorry - could not find \"/\" termination of START keyword in data_file: \n",__func__ , data_file);
|
|
|
|
buffer_size = (util_ftell(stream) - start_pos) ;
|
|
buffer = (char*)util_calloc( buffer_size + 1 , sizeof * buffer );
|
|
util_fseek( stream , start_pos , SEEK_SET);
|
|
util_fread( buffer , sizeof * buffer , buffer_size ,stream , __func__);
|
|
buffer[buffer_size] = '\0';
|
|
}
|
|
|
|
|
|
{
|
|
stringlist_type * tokens = basic_parser_tokenize_buffer( parser , buffer , true );
|
|
int day, year, month_nr;
|
|
if ( util_sscanf_int( stringlist_iget( tokens , 0 ) , &day) && util_sscanf_int( stringlist_iget(tokens , 2) , &year)) {
|
|
month_nr = ecl_util_get_month_nr(stringlist_iget( tokens , 1));
|
|
start_date = ecl_util_make_date(day , month_nr , year );
|
|
} else
|
|
util_abort("%s: failed to parse DAY MONTH YEAR from : \"%s\" \n",__func__ , buffer);
|
|
stringlist_free( tokens );
|
|
}
|
|
|
|
free( buffer );
|
|
basic_parser_free( parser );
|
|
fclose(stream);
|
|
|
|
return start_date;
|
|
}
|
|
|
|
|
|
static int ecl_util_get_num_parallel_cpu__(basic_parser_type* parser, FILE* stream, const char * data_file) {
|
|
int num_cpu = 1;
|
|
char * buffer;
|
|
long int start_pos = util_ftell( stream );
|
|
int buffer_size;
|
|
|
|
/* Look for terminating '/' */
|
|
if (!basic_parser_fseek_string( parser , stream , "/" , false , true))
|
|
util_abort("%s: sorry - could not find \"/\" termination of PARALLEL keyword in data_file: \n",__func__ , data_file);
|
|
|
|
buffer_size = (util_ftell(stream) - start_pos) ;
|
|
buffer = (char*)util_calloc( buffer_size + 1 , sizeof * buffer );
|
|
util_fseek( stream , start_pos , SEEK_SET);
|
|
util_fread( buffer , sizeof * buffer , buffer_size ,stream , __func__);
|
|
buffer[buffer_size] = '\0';
|
|
|
|
{
|
|
stringlist_type * tokens = basic_parser_tokenize_buffer( parser , buffer , true );
|
|
|
|
if (stringlist_get_size( tokens ) > 0) {
|
|
const char * num_cpu_string = stringlist_iget( tokens , 0 );
|
|
if (!util_sscanf_int( num_cpu_string , &num_cpu))
|
|
fprintf(stderr,"** Warning: failed to interpret:%s as integer - assuming one CPU\n",num_cpu_string);
|
|
} else
|
|
fprintf(stderr,"** Warning: failed to load data for PARALLEL keyword - assuming one CPU\n");
|
|
|
|
stringlist_free( tokens );
|
|
}
|
|
free( buffer );
|
|
return num_cpu;
|
|
}
|
|
|
|
|
|
|
|
static int ecl_util_get_num_slave_cpu__(basic_parser_type* parser, FILE* stream, const char * data_file) {
|
|
int num_cpu = 0;
|
|
int linecount = 0;
|
|
|
|
basic_parser_fseek_string( parser , stream , "\n" , true , true); /* Go to next line after the SLAVES keyword*/
|
|
|
|
while (true) {
|
|
char * buffer = util_fscanf_alloc_line( stream , NULL);
|
|
++linecount;
|
|
if (linecount > 10)
|
|
util_abort("%s: Did not find ending \"/\" character after SLAVES keyword, aborting \n", __func__);
|
|
|
|
{
|
|
stringlist_type * tokens = basic_parser_tokenize_buffer( parser , buffer , true );
|
|
if (stringlist_get_size(tokens) > 0 ) {
|
|
|
|
const char * first_item = stringlist_iget(tokens, 0);
|
|
|
|
if (first_item[0] == '/') {
|
|
stringlist_free(tokens);
|
|
free(buffer);
|
|
break;
|
|
}
|
|
else{
|
|
int no_of_tokens = stringlist_get_size(tokens);
|
|
int no_of_slaves =0;
|
|
if(no_of_tokens == 6 && util_sscanf_int(stringlist_iget(tokens, 4), &no_of_slaves)){
|
|
num_cpu += no_of_slaves;
|
|
}else{
|
|
++num_cpu;
|
|
}
|
|
}
|
|
}
|
|
stringlist_free( tokens );
|
|
}
|
|
|
|
free( buffer );
|
|
}
|
|
|
|
if (0 == num_cpu)
|
|
util_abort("%s: Did not any CPUs after SLAVES keyword, aborting \n", __func__);
|
|
return num_cpu;
|
|
}
|
|
|
|
|
|
|
|
int ecl_util_get_num_cpu(const char * data_file) {
|
|
int num_cpu = 1;
|
|
basic_parser_type * parser = basic_parser_alloc(" \t\r\n" , "\"\'" , NULL , NULL , "--" , "\n");
|
|
FILE * stream = util_fopen(data_file , "r");
|
|
|
|
if (basic_parser_fseek_string( parser , stream , "PARALLEL" , true , true)) { /* Seeks case insensitive. */
|
|
num_cpu = ecl_util_get_num_parallel_cpu__(parser, stream, data_file);
|
|
} else if (basic_parser_fseek_string( parser , stream , "SLAVES" , true , true)) { /* Seeks case insensitive. */
|
|
num_cpu = ecl_util_get_num_slave_cpu__(parser, stream, data_file) + 1;
|
|
fprintf(stderr, "Information: \"SLAVES\" option found, returning %d number of CPUs", num_cpu);
|
|
}
|
|
|
|
basic_parser_free( parser );
|
|
fclose(stream);
|
|
return num_cpu;
|
|
}
|
|
|
|
|
|
ert_ecl_unit_enum ecl_util_get_unit_set(const char * data_file) {
|
|
ert_ecl_unit_enum units = ECL_METRIC_UNITS;
|
|
basic_parser_type * parser = basic_parser_alloc(" \t\r\n" , "\"\'" , NULL , NULL , "--" , "\n");
|
|
FILE * stream = util_fopen(data_file , "r");
|
|
|
|
if (basic_parser_fseek_string( parser , stream , "FIELD" , true , true)) { /* Seeks case insensitive. */
|
|
units = ECL_FIELD_UNITS;
|
|
} else if (basic_parser_fseek_string( parser , stream , "LAB" , true , true)) { /* Seeks case insensitive. */
|
|
units = ECL_LAB_UNITS;
|
|
}
|
|
|
|
basic_parser_free( parser );
|
|
fclose(stream);
|
|
return units;
|
|
}
|
|
|
|
|
|
/**
|
|
This function checks that all the characters in the input @basename
|
|
are either lowercase, or uppercase. If presented with a mixed-case
|
|
basename the multimillion $$ program ECLIPSE will die a horrible
|
|
death - impressive ehh?!
|
|
*/
|
|
|
|
|
|
bool ecl_util_valid_basename( const char * basename ) {
|
|
return valid_base(basename, NULL);
|
|
}
|
|
|
|
|
|
bool ecl_util_valid_basename_fmt(const char * basename_fmt)
|
|
{
|
|
bool valid;
|
|
|
|
char * eclbasename_fmt = util_split_alloc_filename(basename_fmt);
|
|
|
|
const char * percent_ptr = strchr(eclbasename_fmt, '%');
|
|
if (percent_ptr) {
|
|
percent_ptr++;
|
|
while (true)
|
|
{
|
|
if (*percent_ptr == 'd')
|
|
{
|
|
char * basename_instance = util_alloc_sprintf(eclbasename_fmt, 0);
|
|
valid = ecl_util_valid_basename(basename_instance);
|
|
free(basename_instance);
|
|
break;
|
|
} else if (!isdigit(*percent_ptr)) {
|
|
valid = false;
|
|
break;
|
|
} else
|
|
percent_ptr++;
|
|
}
|
|
} else
|
|
valid = ecl_util_valid_basename(eclbasename_fmt);
|
|
|
|
free(eclbasename_fmt);
|
|
|
|
return valid;
|
|
}
|
|
|
|
|
|
/*
|
|
Will append time_t values corresponding to the first day in every
|
|
month in the open interval (start_date , end_date). Iff start_date
|
|
corresponds to the first date in a month the list will start with
|
|
start_date, otherwise the list will start with the first day in the
|
|
month following after start_date.
|
|
|
|
If end_date corresponds to the first day of the month the list will
|
|
end with end_date, otherwise it will ende with the first day in the
|
|
month prior to end_date:
|
|
|
|
(1,1,2000) , (10,3,2000) => {(1,1,2000) , (1,2,2000) , (1,3,2000) }
|
|
(10,1,2000) , (1,4,2000) => {(1,2,2000) , (1,3,2000) , (1,4,2000) }
|
|
|
|
All time_t values added to the date list will be pure dates,
|
|
i.e. the time part will be 00:00:00; that also applies to start_date
|
|
and end_date where possible time parts will be normalized away prior
|
|
to insertion.
|
|
*/
|
|
|
|
|
|
|
|
|
|
void ecl_util_append_month_range( time_t_vector_type * date_list , time_t start_date , time_t end_date , bool force_append_end) {
|
|
start_date = util_make_pure_date_utc( start_date );
|
|
end_date = util_make_pure_date_utc( end_date );
|
|
|
|
if (util_is_first_day_in_month_utc( start_date))
|
|
time_t_vector_append( date_list , start_date );
|
|
|
|
{
|
|
time_t current_date = start_date;
|
|
while (true) {
|
|
int month,year;
|
|
util_set_date_values_utc( current_date , NULL , &month , &year);
|
|
if (month == 12) {
|
|
month = 1;
|
|
year += 1;
|
|
} else
|
|
month += 1;
|
|
|
|
current_date = ecl_util_make_date( 1 , month , year );
|
|
if (current_date < end_date)
|
|
time_t_vector_append( date_list , current_date );
|
|
else {
|
|
if (current_date == end_date)
|
|
time_t_vector_append( date_list , current_date );
|
|
else if (force_append_end)
|
|
time_t_vector_append( date_list , end_date );
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void ecl_util_init_month_range( time_t_vector_type * date_list , time_t start_date , time_t end_date) {
|
|
time_t_vector_reset( date_list );
|
|
if (!util_is_first_day_in_month_utc( start_date ))
|
|
time_t_vector_append( date_list , util_make_pure_date_utc(start_date));
|
|
|
|
ecl_util_append_month_range( date_list , start_date , end_date , true );
|
|
}
|
|
|
|
|
|
|
|
|
|
time_t ecl_util_make_date__(int mday , int month , int year, int * __year_offset) {
|
|
time_t date;
|
|
|
|
#ifdef ERT_TIME_T_64BIT_ACCEPT_PRE1970
|
|
*__year_offset = 0;
|
|
date = util_make_date_utc(mday , month , year);
|
|
#else
|
|
static bool offset_initialized = false;
|
|
static int year_offset = 0;
|
|
|
|
if (!offset_initialized) {
|
|
if (year < 1970) {
|
|
year_offset = 2000 - year;
|
|
fprintf(stderr,"Warning: all year values will be shifted %d years forward. \n", year_offset);
|
|
}
|
|
offset_initialized = true;
|
|
}
|
|
*__year_offset = year_offset;
|
|
date = util_make_date_utc(mday , month , year + year_offset);
|
|
#endif
|
|
|
|
return date;
|
|
}
|
|
|
|
|
|
time_t ecl_util_make_date(int mday , int month , int year) {
|
|
int year_offset;
|
|
return ecl_util_make_date__( mday , month , year , &year_offset);
|
|
}
|
|
|
|
|
|
|
|
void ecl_util_set_date_values(time_t t , int * mday , int * month , int * year) {
|
|
return util_set_date_values_utc(t,mday,month,year);
|
|
}
|
|
|
|
|
|
#ifdef ERT_HAVE_UNISTD
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
/*
|
|
This is a small function which tries to give a sensible answer to the
|
|
question: Do I have read access to this eclipse simulation? The ecl_case
|
|
argument can either be a directory or the full path to a file, the filename
|
|
need not exists. The approach is as follows:
|
|
|
|
1. If @ecl_case corresponds to an existing filesystem entry - just return
|
|
access(ecl_case, R_OK).
|
|
|
|
2. If @ecl_case corresponds to a non-existing entry:
|
|
|
|
a) If there is a directory part - return access(dir, R_OK).
|
|
b) No directory part - return access(cwd, R_OK);
|
|
|
|
For the case 2b) the situation is that we test for read access to CWD,
|
|
that could in principle be denied - but that is a highly contrived
|
|
situation and we just return true.
|
|
|
|
ecl_util_access_path("PATH") -> access("PATH", R_OK);
|
|
ecl_util_access_path("PATH/FILE_EXISTS") -> access("PATH/FILE_EXISTS", R_OK);
|
|
ecl_util_access_path("PATH/FILE_DOES_NOT_EXIST") -> access("PATH", R_OK);
|
|
ecl_util_access_path("PATH_DOES_NOT_EXIST") -> true
|
|
*/
|
|
|
|
bool ecl_util_path_access(const char * ecl_case) {
|
|
if (util_access(ecl_case, R_OK))
|
|
return true;
|
|
|
|
if (util_access(ecl_case, F_OK))
|
|
return false;
|
|
|
|
/* Check if the input argument corresponds to an existing directory and one
|
|
additional element, in that case we do an access check on the directory part. */
|
|
|
|
{
|
|
bool path_access;
|
|
char * dir_name;
|
|
const char * path_sep = strrchr(ecl_case, UTIL_PATH_SEP_CHAR);
|
|
|
|
if (!path_sep)
|
|
/* We are trying to access CWD - we return true without actually checking
|
|
access. */
|
|
return true;
|
|
|
|
|
|
dir_name = util_alloc_substring_copy(ecl_case, 0, path_sep - ecl_case);
|
|
path_access = util_access(dir_name, R_OK);
|
|
free(dir_name);
|
|
return path_access;
|
|
}
|
|
return false;
|
|
}
|