mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
1088 lines
34 KiB
C++
1088 lines
34 KiB
C++
/*
|
|
Copyright (C) 2011 Statoil ASA, Norway.
|
|
|
|
The file 'ecl_file.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 <stdio.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
#include <errno.h>
|
|
#include <time.h>
|
|
|
|
#include <ert/util/hash.hpp>
|
|
#include <ert/util/util.h>
|
|
#include <ert/util/vector.hpp>
|
|
#include <ert/util/int_vector.hpp>
|
|
#include <ert/util/stringlist.hpp>
|
|
|
|
#include <ert/ecl/fortio.h>
|
|
#include <ert/ecl/ecl_kw.hpp>
|
|
#include <ert/ecl/ecl_file.hpp>
|
|
#include <ert/ecl/ecl_file_view.hpp>
|
|
#include <ert/ecl/ecl_endian_flip.hpp>
|
|
#include <ert/ecl/ecl_kw_magic.hpp>
|
|
#include <ert/ecl/ecl_rsthead.hpp>
|
|
#include <ert/ecl/ecl_file_kw.hpp>
|
|
#include <ert/ecl/ecl_type.hpp>
|
|
|
|
/**
|
|
This file implements functionality to load an ECLIPSE file in
|
|
ecl_kw format. The implementation works by first searching through
|
|
the complete file to create an index over all the keywords present
|
|
in the file. The actual keyword data is not loaded before they are
|
|
explicitly requested.
|
|
|
|
The ecl_file_type is the middle layer of abstraction in the libecl
|
|
hierarchy (see the file overview.txt in this directory); it works
|
|
with a collection of ecl_kw instances and has various query
|
|
functions, however it does not utilize knowledge of the
|
|
structure/content of the files in the way e.g. ecl_grid.c does[1].
|
|
|
|
The main datatype here is the ecl_file type, but in addition each
|
|
ecl_kw instance is wrapped in an ecl_file_kw (implemented in
|
|
ecl_file_kw.c) structure and all the indexing is implemented with
|
|
the ecl_file_view type. The ecl_file_view type is not used outside this file.
|
|
|
|
When the file is opened an index of all the keywords is created and
|
|
stored in the field global_map, and the field active_view is set to
|
|
point to global_map, i.e. all query/get operations on the ecl_file
|
|
will be based on the complete index:
|
|
|
|
In many cases (in particular for unified restart files) it is quite
|
|
painful to work with this large and unvieldy index, and it is
|
|
convenient to create a sub index based on a subset of the
|
|
keywords. The creation of these sub indices is based on identifying
|
|
a keyword from name and occurence number, and then including all
|
|
keywords up to the next occurence of the same keyword:
|
|
|
|
SEQHDR ---\
|
|
MINISTEP 0 |
|
|
PARAMS ..... |
|
|
MINISTEP 1 | Block 0
|
|
PARAMS ..... |
|
|
MINISTEP 2 |
|
|
PARAMS ..... |
|
|
SEQHDR ---+
|
|
MINISTEP 3 |
|
|
PARAMS ..... |
|
|
MINISTEP 4 | Block 1
|
|
PARAMS ..... |
|
|
MINISTEP 5 |
|
|
SEQHDR ---+
|
|
MINISTEP 6 | Block 2
|
|
PARAMS .... |
|
|
SEQHDR ---+
|
|
MINISTEP 7 |
|
|
PARAMS .... | Block 3
|
|
MINISTEP 8 |
|
|
PARAMS .... |
|
|
|
|
For the unified summary file depicted here e.g. the call
|
|
|
|
ecl_file_get_blockmap( ecl_file , "SEQHDR" , 2 )
|
|
|
|
Will create a sub-index consisting of the (three) keywords in what
|
|
is called 'Block 2' in the figure above. In particular for restart
|
|
files this abstraction is very convenient, because an extra layer
|
|
of functionality is required to get from natural time coordinates
|
|
(i.e. simulation time or report step) to the occurence number (see
|
|
ecl_rstfile for more details).
|
|
|
|
To select a subindex as the active index you use the
|
|
ecl_file_select_block() function, or alternatively you can use
|
|
ecl_file_open_block() to directly select the relevant block
|
|
immediately after the open() statement. Observe that when using a
|
|
sub index thorugh ecl_file_select_block() function the global_map
|
|
will still be present in the ecl_file instance, and subsequent
|
|
calls to create a new sub index will also use the global_map index
|
|
- i.e. the indexing is not recursive, a sub index is always created
|
|
based on the global_map, and not on the currently active map.
|
|
|
|
|
|
[1]: This is not entirely true - in the file ecl_rstfile.c; which
|
|
is included from this file are several specialized function
|
|
for working with restart files. However the restart files are
|
|
still treated as collections of ecl_kw instances, and not
|
|
internalized as in e.g. ecl_sum.
|
|
*/
|
|
|
|
|
|
|
|
#define ECL_FILE_ID 776107
|
|
|
|
|
|
|
|
|
|
|
|
struct ecl_file_struct {
|
|
UTIL_TYPE_ID_DECLARATION;
|
|
fortio_type * fortio; /* The source of all the keywords - must be retained
|
|
open for reading for the entire lifetime of the
|
|
ecl_file object. */
|
|
ecl_file_view_type * global_view; /* The index of all the ecl_kw instances in the file. */
|
|
ecl_file_view_type * active_view; /* The currently active index. */
|
|
bool read_only;
|
|
int flags;
|
|
vector_type * map_stack;
|
|
inv_map_type * inv_view;
|
|
};
|
|
|
|
|
|
/*
|
|
This illustrates the indexing. The ecl_file instance contains in
|
|
total 7 ecl_kw instances, the global index [0...6] is the internal
|
|
way to access the various keywords. The kw_index is a hash table
|
|
with entries 'SEQHDR', 'MINISTEP' and 'PARAMS'. Each entry in the
|
|
hash table is an integer vector which again contains the internal
|
|
index of the various occurences:
|
|
|
|
------------------
|
|
SEQHDR \
|
|
MINISTEP 0 |
|
|
PARAMS ..... |
|
|
MINISTEP 1 |
|
|
PARAMS ..... |
|
|
MINISTEP 2 |
|
|
PARAMS ..... /
|
|
------------------
|
|
|
|
kw_index = {"SEQHDR": [0], "MINISTEP": [1,3,5], "PARAMS": [2,4,6]} <== This is hash table.
|
|
kw_list = [SEQHDR , MINISTEP , PARAMS , MINISTEP , PARAMS , MINISTEP , PARAMS]
|
|
distinct_kw = [SEQHDR , MINISTEP , PARAMS]
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*****************************************************************/
|
|
/* Here comes the implementation of the ecl_file proper 'class'. */
|
|
|
|
|
|
UTIL_SAFE_CAST_FUNCTION( ecl_file , ECL_FILE_ID)
|
|
UTIL_IS_INSTANCE_FUNCTION( ecl_file , ECL_FILE_ID)
|
|
|
|
|
|
|
|
ecl_file_type * ecl_file_alloc_empty( int flags ) {
|
|
ecl_file_type * ecl_file = (ecl_file_type *)util_malloc( sizeof * ecl_file );
|
|
UTIL_TYPE_ID_INIT(ecl_file , ECL_FILE_ID);
|
|
ecl_file->map_stack = vector_alloc_new();
|
|
ecl_file->inv_view = inv_map_alloc( );
|
|
ecl_file->flags = flags;
|
|
return ecl_file;
|
|
}
|
|
|
|
|
|
/*****************************************************************/
|
|
/* fwrite functions */
|
|
|
|
void ecl_file_fwrite_fortio(const ecl_file_type * ecl_file , fortio_type * target, int offset) {
|
|
ecl_file_view_fwrite( ecl_file->active_view , target , offset );
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
Observe : if the filename is a standard filename which can be used
|
|
to infer formatted/unformatted automagically the fmt_file variable
|
|
is NOT consulted.
|
|
*/
|
|
|
|
void ecl_file_fwrite(const ecl_file_type * ecl_file , const char * filename, bool fmt_file) {
|
|
bool __fmt_file;
|
|
ecl_file_enum file_type;
|
|
|
|
file_type = ecl_util_get_file_type( filename , &__fmt_file , NULL);
|
|
if (file_type == ECL_OTHER_FILE)
|
|
__fmt_file = fmt_file;
|
|
|
|
{
|
|
fortio_type * target = fortio_open_writer( filename , __fmt_file , ECL_ENDIAN_FLIP);
|
|
ecl_file_fwrite_fortio( ecl_file , target , 0);
|
|
fortio_fclose( target );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************/
|
|
/**
|
|
Here comes several functions for querying the ecl_file instance, and
|
|
getting pointers to the ecl_kw content of the ecl_file. For getting
|
|
ecl_kw instances there are two principally different access methods:
|
|
|
|
* ecl_file_iget_named_kw(): This function will take a keyword
|
|
(char *) and an integer as input. The integer corresponds to the
|
|
ith occurence of the keyword in the file.
|
|
|
|
* ecl_file_iget_kw(): This function just takes an integer index as
|
|
input, and returns the corresponding ecl_kw instance - without
|
|
considering which keyword it is.
|
|
|
|
-------
|
|
|
|
In addition the functions ecl_file_get_num_distinct_kw() and
|
|
ecl_file_iget_distinct_kw() will return the number of distinct
|
|
keywords, and distinct keyword keyword nr i (as a const char *).
|
|
|
|
|
|
Possible usage pattern:
|
|
|
|
....
|
|
for (ikw = 0; ikw < ecl_file_get_num_distinct_kw(ecl_file); ikw++) {
|
|
const char * kw = ecl_file_iget_distinct_kw(ecl_file , ikw);
|
|
|
|
printf("The file contains: %d occurences of \'%s\' \n",ecl_file_get_num_named_kw( ecl_file , kw) , kw);
|
|
}
|
|
....
|
|
|
|
For the summary file showed in the top this code will produce:
|
|
|
|
The file contains 1 occurences of 'SEQHDR'
|
|
The file contains 3 occurences of 'MINISTEP'
|
|
The file contains 3 occurences of 'PARAMS'
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
This function will iterate through the ecl_file instance and search
|
|
for the ecl_kw instance @old_kw - the search is based on pointer
|
|
equality, i.e. the actual ecl_kw instance, and not on content
|
|
equality.
|
|
|
|
When @old_kw is found that keyword instance will be discarded with
|
|
ecl_kw_free() and the new keyword @new_kw will be inserted. If
|
|
@old_kw can not be found the function will fail hard - to verify
|
|
that @new_kw is indeed in the ecl_file instance you should use
|
|
ecl_file_has_kw_ptr() first.
|
|
|
|
The ecl_file function typically gives out references to the
|
|
internal ecl_kw instances via the ecl_file_iget_kw() function. Use
|
|
of ecl_file_replace_kw() might lead to invalidating ecl_kw
|
|
instances held by the calling scope:
|
|
|
|
|
|
....
|
|
ecl_file_type * restart_file = ecl_file_fread_alloc( "ECLIPSE.UNRST" );
|
|
ecl_kw_type * initial_pressure = ecl_file_iget_named_kw( ecl_file , "PRESSURE" , 0);
|
|
ecl_kw_type * faked_pressure = ecl_kw_alloc_copy( initial_pressure );
|
|
|
|
ecl_kw_scale( faked_pressure , 1.25 );
|
|
ecl_file_replace_kw( restart_file , initial_pressure , faked_pressure , false ); <--- This call will invalidate the inital_pressure reference
|
|
....
|
|
....
|
|
// This will fail horribly:
|
|
printf("The initial pressure in cell(0) was:%g \n",ecl_kw_iget_double( initial_pressure , 0 ));
|
|
/|\
|
|
|
|
|
+---------> Using initial_pressure => Crash and burn!
|
|
|
|
The ecl_file structure takes ownership of all the keywords, and
|
|
will also take ownership of the newly instered @new_kw instance; if
|
|
the boolean @insert_copy is set to true the function will insert a
|
|
copy of @new_kw, leaving the original reference untouched.
|
|
*/
|
|
|
|
|
|
|
|
void ecl_file_replace_kw( ecl_file_type * ecl_file , ecl_kw_type * old_kw , ecl_kw_type * new_kw , bool insert_copy) {
|
|
ecl_file_view_replace_kw( ecl_file->active_view , old_kw , new_kw , insert_copy );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ecl_kw_type * ecl_file_icopy_named_kw( const ecl_file_type * ecl_file , const char * kw, int ith) {
|
|
return ecl_kw_alloc_copy( ecl_file_iget_named_kw( ecl_file , kw , ith ));
|
|
}
|
|
|
|
|
|
/*
|
|
Will return the number of times a particular keyword occurs in a
|
|
ecl_file instance. Will return 0 if the keyword can not be found.
|
|
*/
|
|
|
|
int ecl_file_get_num_named_kw(const ecl_file_type * ecl_file , const char * kw) {
|
|
return ecl_file_view_get_num_named_kw( ecl_file->active_view , kw);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
This function does the following:
|
|
|
|
1. Takes an input index which goes in to the global kw_list vector.
|
|
2. Looks up the corresponding keyword.
|
|
3. Return the number of this particular keyword instance, among
|
|
the other instance with the same header.
|
|
|
|
With the example above we get:
|
|
|
|
ecl_file_iget_occurence(ecl_file , 2) -> 0; Global index 2 will
|
|
look up the first occurence of PARAMS.
|
|
|
|
ecl_file_iget_occurence(ecl_file , 5) -> 2; Global index 5 will
|
|
look up th third occurence of MINISTEP.
|
|
|
|
The enkf layer uses this funny functionality.
|
|
*/
|
|
|
|
|
|
int ecl_file_iget_occurence( const ecl_file_type * ecl_file , int index) {
|
|
return ecl_file_view_iget_occurence( ecl_file->active_view , index );
|
|
}
|
|
|
|
|
|
/**
|
|
Returns the total number of ecl_kw instances in the ecl_file
|
|
instance.
|
|
*/
|
|
int ecl_file_get_size( const ecl_file_type * ecl_file ){
|
|
return ecl_file_view_get_size( ecl_file->active_view );
|
|
}
|
|
|
|
|
|
/**
|
|
Returns true if the ecl_file instance has at-least one occurence of
|
|
ecl_kw 'kw'.
|
|
*/
|
|
bool ecl_file_has_kw( const ecl_file_type * ecl_file , const char * kw) {
|
|
return ecl_file_view_has_kw( ecl_file->active_view , kw );
|
|
}
|
|
|
|
|
|
int ecl_file_get_num_distinct_kw(const ecl_file_type * ecl_file) {
|
|
return ecl_file_view_get_num_distinct_kw( ecl_file->active_view );
|
|
}
|
|
|
|
|
|
const char * ecl_file_iget_distinct_kw(const ecl_file_type * ecl_file, int index) {
|
|
return ecl_file_view_iget_distinct_kw( ecl_file->active_view , index );
|
|
}
|
|
|
|
|
|
const char * ecl_file_get_src_file( const ecl_file_type * ecl_file ) {
|
|
return fortio_filename_ref( ecl_file->fortio );
|
|
}
|
|
|
|
|
|
void ecl_file_fprintf_kw_list( const ecl_file_type * ecl_file , FILE * stream ) {
|
|
ecl_file_view_fprintf_kw_list( ecl_file->active_view , stream );
|
|
}
|
|
|
|
|
|
/*****************************************************************/
|
|
|
|
ecl_file_kw_type * ecl_file_iget_file_kw( const ecl_file_type * file , int global_index) {
|
|
return ecl_file_view_iget_file_kw( file->active_view , global_index);
|
|
}
|
|
|
|
ecl_file_kw_type * ecl_file_iget_named_file_kw( const ecl_file_type * file , const char * kw, int ith) {
|
|
return ecl_file_view_iget_named_file_kw( file->active_view , kw, ith);
|
|
}
|
|
|
|
/* ---- */
|
|
|
|
ecl_kw_type * ecl_file_iget_kw( const ecl_file_type * file , int global_index) {
|
|
return ecl_file_view_iget_kw( file->active_view , global_index);
|
|
}
|
|
|
|
ecl_data_type ecl_file_iget_data_type( const ecl_file_type * file , int global_index) {
|
|
return ecl_file_view_iget_data_type( file->active_view , global_index);
|
|
}
|
|
|
|
int ecl_file_iget_size( const ecl_file_type * file , int global_index) {
|
|
return ecl_file_view_iget_size( file->active_view , global_index);
|
|
}
|
|
|
|
const char * ecl_file_iget_header( const ecl_file_type * file , int global_index) {
|
|
return ecl_file_view_iget_header( file->active_view , global_index);
|
|
}
|
|
|
|
/* ---------- */
|
|
|
|
/*
|
|
This function will return the ith occurence of 'kw' in
|
|
ecl_file. Will abort hard if the request can not be satisifed - use
|
|
query functions if you can not take that.
|
|
*/
|
|
|
|
ecl_kw_type * ecl_file_iget_named_kw( const ecl_file_type * file , const char * kw, int ith) {
|
|
return ecl_file_view_iget_named_kw( file->active_view , kw , ith);
|
|
}
|
|
|
|
void ecl_file_indexed_read(const ecl_file_type * file , const char * kw, int index, const int_vector_type * index_map, char* buffer) {
|
|
ecl_file_view_index_fload_kw(file->active_view, kw, index, index_map, buffer);
|
|
}
|
|
|
|
ecl_data_type ecl_file_iget_named_data_type( const ecl_file_type * file , const char * kw , int ith) {
|
|
return ecl_file_view_iget_named_data_type( file->active_view , kw , ith );
|
|
}
|
|
|
|
int ecl_file_iget_named_size( const ecl_file_type * file , const char * kw , int ith) {
|
|
return ecl_file_view_iget_named_size( file->active_view , kw , ith );
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************/
|
|
|
|
ecl_file_view_type * ecl_file_get_global_view( ecl_file_type * ecl_file ) {
|
|
return ecl_file->global_view;
|
|
}
|
|
|
|
// Very deprecated ...
|
|
ecl_file_view_type * ecl_file_get_active_view( ecl_file_type * ecl_file ) {
|
|
return ecl_file->active_view;
|
|
}
|
|
|
|
ecl_file_view_type * ecl_file_get_global_blockview( ecl_file_type * ecl_file , const char * kw , int occurence) {
|
|
ecl_file_view_type * view = ecl_file_view_add_blockview( ecl_file->global_view , kw , occurence );
|
|
return view;
|
|
}
|
|
|
|
|
|
ecl_file_view_type * ecl_file_alloc_global_blockview2( ecl_file_type * ecl_file , const char * start_kw , const char * end_kw, int occurence) {
|
|
ecl_file_view_type * view = ecl_file_view_alloc_blockview2( ecl_file->global_view , start_kw , end_kw, occurence );
|
|
return view;
|
|
}
|
|
|
|
|
|
ecl_file_view_type * ecl_file_alloc_global_blockview( ecl_file_type * ecl_file , const char * kw , int occurence) {
|
|
return ecl_file_alloc_global_blockview2( ecl_file , kw , kw , occurence );
|
|
}
|
|
|
|
|
|
ecl_file_view_type * ecl_file_get_restart_view( ecl_file_type * ecl_file , int input_index, int report_step , time_t sim_time, double sim_days) {
|
|
ecl_file_view_type * view = ecl_file_view_add_restart_view( ecl_file->global_view , input_index , report_step , sim_time , sim_days);
|
|
return view;
|
|
}
|
|
|
|
|
|
ecl_file_view_type * ecl_file_get_summary_view( ecl_file_type * ecl_file , int report_step ) {
|
|
ecl_file_view_type * view = ecl_file_view_add_summary_view( ecl_file->global_view , report_step );
|
|
return view;
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************/
|
|
/*
|
|
Different functions to open and close a file.
|
|
*/
|
|
|
|
/**
|
|
The ecl_file_scan() function will scan through the whole file and
|
|
build up an index of all the kewyords. The map created from this
|
|
scan will be stored under the 'global_view' field; and all
|
|
subsequent lookup operations will ultimately be based on the global
|
|
map.
|
|
*/
|
|
|
|
static bool ecl_file_scan( ecl_file_type * ecl_file ) {
|
|
bool scan_ok = false;
|
|
fortio_fseek( ecl_file->fortio , 0 , SEEK_SET );
|
|
{
|
|
ecl_kw_type * work_kw = ecl_kw_alloc_new("WORK-KW" , 0 , ECL_INT , NULL);
|
|
|
|
while (true) {
|
|
if (fortio_read_at_eof(ecl_file->fortio)) {
|
|
scan_ok = true;
|
|
break;
|
|
}
|
|
|
|
{
|
|
offset_type current_offset = fortio_ftell( ecl_file->fortio );
|
|
ecl_read_status_enum read_status = ecl_kw_fread_header( work_kw , ecl_file->fortio);
|
|
if (read_status == ECL_KW_READ_FAIL)
|
|
break;
|
|
|
|
if (read_status == ECL_KW_READ_OK) {
|
|
ecl_file_kw_type * file_kw = ecl_file_kw_alloc( work_kw , current_offset);
|
|
if (ecl_file_kw_fskip_data( file_kw , ecl_file->fortio ))
|
|
ecl_file_view_add_kw( ecl_file->global_view , file_kw );
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
ecl_kw_free( work_kw );
|
|
}
|
|
if (scan_ok)
|
|
ecl_file_view_make_index( ecl_file->global_view );
|
|
|
|
return scan_ok;
|
|
}
|
|
|
|
|
|
void ecl_file_select_global( ecl_file_type * ecl_file ) {
|
|
ecl_file->active_view = ecl_file->global_view;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
The fundamental open file function; all alternative open()
|
|
functions start by calling this one. This function will read
|
|
through the complete file, extract all the keyword headers and
|
|
create the map/index stored in the global_view field of the ecl_file
|
|
structure. No keyword data will be loaded from the file.
|
|
|
|
The ecl_file instance will retain an open fortio reference to the
|
|
file until ecl_file_close() is called.
|
|
*/
|
|
|
|
|
|
static fortio_type * ecl_file_alloc_fortio(const char * filename, int flags) {
|
|
fortio_type * fortio = NULL;
|
|
bool fmt_file;
|
|
|
|
ecl_util_fmt_file( filename , &fmt_file);
|
|
|
|
if (ecl_file_view_check_flags(flags , ECL_FILE_WRITABLE))
|
|
fortio = fortio_open_readwrite( filename , fmt_file , ECL_ENDIAN_FLIP);
|
|
else
|
|
fortio = fortio_open_reader( filename , fmt_file , ECL_ENDIAN_FLIP);
|
|
|
|
return fortio;
|
|
}
|
|
|
|
|
|
ecl_file_type * ecl_file_open( const char * filename , int flags) {
|
|
fortio_type * fortio = ecl_file_alloc_fortio(filename, flags);
|
|
|
|
if (fortio) {
|
|
ecl_file_type * ecl_file = ecl_file_alloc_empty( flags );
|
|
ecl_file->fortio = fortio;
|
|
ecl_file->global_view = ecl_file_view_alloc( ecl_file->fortio , &ecl_file->flags , ecl_file->inv_view , true );
|
|
|
|
if (ecl_file_scan( ecl_file )) {
|
|
ecl_file_select_global( ecl_file );
|
|
|
|
if (ecl_file_view_check_flags( ecl_file->flags , ECL_FILE_CLOSE_STREAM))
|
|
fortio_fclose_stream( ecl_file->fortio );
|
|
|
|
return ecl_file;
|
|
} else {
|
|
ecl_file_close( ecl_file );
|
|
return NULL;
|
|
}
|
|
} else
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int ecl_file_get_flags( const ecl_file_type * ecl_file ) {
|
|
return ecl_file->flags;
|
|
}
|
|
|
|
void ecl_file_set_flags( ecl_file_type * ecl_file, int flags ) {
|
|
ecl_file->flags = flags;
|
|
}
|
|
|
|
bool ecl_file_flags_set( const ecl_file_type * ecl_file , int flags) {
|
|
return ecl_file_view_check_flags( ecl_file->flags , flags );
|
|
}
|
|
|
|
bool ecl_file_writable( const ecl_file_type * ecl_file ) {
|
|
return ecl_file_view_check_flags( ecl_file->flags , ECL_FILE_WRITABLE );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
The ecl_file_close() function will close the fortio instance and
|
|
free all the data created by the ecl_file instance; this includes
|
|
the ecl_kw instances which have been loaded on demand.
|
|
*/
|
|
|
|
void ecl_file_close(ecl_file_type * ecl_file) {
|
|
if (ecl_file->fortio != NULL)
|
|
fortio_fclose( ecl_file->fortio );
|
|
|
|
if (ecl_file->global_view)
|
|
ecl_file_view_free( ecl_file->global_view );
|
|
|
|
inv_map_free( ecl_file->inv_view );
|
|
vector_free( ecl_file->map_stack );
|
|
free( ecl_file );
|
|
}
|
|
|
|
|
|
void ecl_file_close_fortio_stream(ecl_file_type * ecl_file) {
|
|
if (ecl_file->fortio != NULL) {
|
|
fortio_fclose_stream(ecl_file->fortio);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
This function will detach the current ecl_file instance from the
|
|
underlying fortio instance. The ecl_file instance can be used
|
|
further to access the ecl_kw instances which have been loaded
|
|
already, but if you try on-demand loading of a keyword you will get
|
|
crash-and-burn. To ensure that all keywords are in memory you can
|
|
call ecl_file_load_all() prior to the detach call.
|
|
*/
|
|
|
|
|
|
void ecl_file_fortio_detach( ecl_file_type * ecl_file ) {
|
|
fortio_fclose( ecl_file->fortio );
|
|
ecl_file->fortio = NULL;
|
|
}
|
|
|
|
|
|
bool ecl_file_load_all( ecl_file_type * ecl_file ) {
|
|
return ecl_file_view_load_all( ecl_file->active_view );
|
|
}
|
|
|
|
|
|
void ecl_file_free__(void * arg) {
|
|
ecl_file_close( ecl_file_safe_cast( arg ) );
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Functions specialized to work with restart files. */
|
|
|
|
/* Query functions. */
|
|
/**
|
|
Will look through all the INTEHEAD kw instances of the current
|
|
ecl_file and look for @sim_time. If the value is found true is
|
|
returned, otherwise false.
|
|
*/
|
|
|
|
bool ecl_file_has_sim_time( const ecl_file_type * ecl_file , time_t sim_time) {
|
|
return ecl_file_view_has_sim_time( ecl_file->active_view , sim_time );
|
|
}
|
|
|
|
|
|
/*
|
|
This function will determine the restart block corresponding to the
|
|
world time @sim_time; if @sim_time can not be found the function
|
|
will return 0.
|
|
|
|
The returned index is the 'occurence number' in the restart file,
|
|
i.e. in the (quite typical case) that not all report steps are
|
|
present the return value will not agree with report step.
|
|
|
|
The return value from this function can then be used to get a
|
|
corresponding solution field directly, or the file map can
|
|
restricted to this block.
|
|
|
|
Direct access:
|
|
|
|
int index = ecl_file_get_restart_index( ecl_file , sim_time );
|
|
if (index >= 0) {
|
|
ecl_kw_type * pressure_kw = ecl_file_iget_named_kw( ecl_file , "PRESSURE" , index );
|
|
....
|
|
}
|
|
|
|
|
|
Using block restriction:
|
|
|
|
int index = ecl_file_get_restart_index( ecl_file , sim_time );
|
|
if (index >= 0) {
|
|
ecl_file_iselect_rstblock( ecl_file , index );
|
|
{
|
|
ecl_kw_type * pressure_kw = ecl_file_iget_named_kw( ecl_file , "PRESSURE" , 0 );
|
|
....
|
|
}
|
|
}
|
|
|
|
Specially in the case of LGRs the block restriction should be used.
|
|
*/
|
|
|
|
int ecl_file_get_restart_index( const ecl_file_type * ecl_file , time_t sim_time) {
|
|
int active_index = ecl_file_view_find_sim_time( ecl_file->active_view , sim_time );
|
|
return active_index;
|
|
}
|
|
|
|
|
|
/**
|
|
Will look through all the SEQNUM kw instances of the current
|
|
ecl_file and look for @report_step. If the value is found true is
|
|
returned, otherwise false.
|
|
*/
|
|
|
|
bool ecl_file_has_report_step( const ecl_file_type * ecl_file , int report_step) {
|
|
return ecl_file_view_has_report_step( ecl_file->active_view , report_step );
|
|
}
|
|
|
|
|
|
/**
|
|
This function will look up the INTEHEAD keyword in a ecl_file_type
|
|
instance, and calculate simulation date from this instance.
|
|
|
|
Will return -1 if the requested INTEHEAD keyword can not be found.
|
|
*/
|
|
|
|
time_t ecl_file_iget_restart_sim_date( const ecl_file_type * restart_file , int index ) {
|
|
return ecl_file_view_iget_restart_sim_date( restart_file->active_view , index );
|
|
}
|
|
|
|
double ecl_file_iget_restart_sim_days( const ecl_file_type * restart_file , int index ) {
|
|
return ecl_file_view_iget_restart_sim_days( restart_file->active_view , index );
|
|
}
|
|
|
|
/*****************************************************************/
|
|
/* Two small lookup functions which consider the INTEHEAD keyword,
|
|
work equally well for both restart and INIT files. */
|
|
|
|
/*
|
|
The input @file must be either an INIT file or a restart file. Will
|
|
fail hard if an INTEHEAD kw can not be found - or if the INTEHEAD
|
|
keyword is not sufficiently large.
|
|
|
|
The eclipse files can distinguish between ECLIPSE300 ( value == 300)
|
|
and ECLIPSE300-Thermal option (value == 500). This function will
|
|
return ECLIPSE300 in both those cases.
|
|
*/
|
|
|
|
ecl_version_enum ecl_file_get_ecl_version( const ecl_file_type * file ) {
|
|
ecl_kw_type * intehead_kw = ecl_file_iget_named_kw( file , INTEHEAD_KW , 0 );
|
|
int int_value = ecl_kw_iget_int( intehead_kw , INTEHEAD_IPROG_INDEX );
|
|
|
|
if (int_value == INTEHEAD_ECLIPSE100_VALUE)
|
|
return ECLIPSE100;
|
|
|
|
if (int_value == INTEHEAD_ECLIPSE300_VALUE)
|
|
return ECLIPSE300;
|
|
|
|
if (int_value == INTEHEAD_ECLIPSE300THERMAL_VALUE)
|
|
return ECLIPSE300_THERMAL;
|
|
|
|
if (int_value == INTEHEAD_INTERSECT_VALUE)
|
|
return INTERSECT;
|
|
|
|
if (int_value == INTEHEAD_FRONTSIM_VALUE)
|
|
return FRONTSIM;
|
|
|
|
util_abort("%s: Simulator version value:%d not recognized \n",__func__ , int_value );
|
|
return (ecl_version_enum)0;
|
|
}
|
|
|
|
/*
|
|
1: Oil
|
|
2: Water
|
|
3: Oil + water
|
|
4: Gas
|
|
5: Gas + Oil
|
|
6: Gas + water
|
|
7: Gas + Water + Oil
|
|
*/
|
|
|
|
int ecl_file_get_phases( const ecl_file_type * init_file ) {
|
|
ecl_kw_type * intehead_kw = ecl_file_iget_named_kw( init_file , INTEHEAD_KW , 0 );
|
|
int phases = ecl_kw_iget_int( intehead_kw , INTEHEAD_PHASE_INDEX );
|
|
return phases;
|
|
}
|
|
|
|
|
|
/*
|
|
bool ecl_file_writable( const ecl_file_type * ecl_file ) {
|
|
return fortio_writable( ecl_file->fortio );
|
|
}
|
|
*/
|
|
|
|
/**
|
|
Checks if the ecl_file contains ecl_kw; this check is based on
|
|
pointer equality - i.e. we check if the ecl_file contains exactly
|
|
this keyword - not an arbitrary equivalent keyword.
|
|
|
|
This function can be called as a safeguard before calling
|
|
ecl_file_save_kw().
|
|
*/
|
|
|
|
bool ecl_file_has_kw_ptr( const ecl_file_type * ecl_file , const ecl_kw_type * ecl_kw) {
|
|
ecl_file_kw_type * file_kw = inv_map_get_file_kw( ecl_file->inv_view , ecl_kw );
|
|
if (file_kw == NULL)
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
|
|
|
|
/*
|
|
Will save the content of @ecl_kw to the on-disk file wrapped by the
|
|
ecl_file instance. This function is quite strict:
|
|
|
|
1. The actual keyword which should be updated is identified using
|
|
pointer comparison; i.e. the ecl_kw argument must be the actual
|
|
return value from an earlier ecl_file_get_kw() operation. To
|
|
check this you can call ecl_file_has_kw_ptr().
|
|
|
|
2. The header data of the ecl_kw must be unmodified; this is checked
|
|
by the ecl_file_kw_inplace_fwrite() function and crash-and-burn
|
|
will ensue if this is not satisfied.
|
|
|
|
3. The ecl_file must have been opened with one of the _writable()
|
|
open functions.
|
|
*/
|
|
|
|
bool ecl_file_save_kw( const ecl_file_type * ecl_file , const ecl_kw_type * ecl_kw) {
|
|
ecl_file_kw_type * file_kw = inv_map_get_file_kw( ecl_file->inv_view , ecl_kw ); // We just verify that the input ecl_kw points to an ecl_kw
|
|
if (file_kw != NULL) { // we manage; from then on we use the reference contained in
|
|
if (fortio_assert_stream_open( ecl_file->fortio )) { // the corresponding ecl_file_kw instance.
|
|
|
|
ecl_file_kw_inplace_fwrite( file_kw , ecl_file->fortio );
|
|
|
|
if (ecl_file_view_check_flags( ecl_file->flags , ECL_FILE_CLOSE_STREAM))
|
|
fortio_fclose_stream( ecl_file->fortio );
|
|
|
|
return true;
|
|
} else
|
|
return false;
|
|
} else {
|
|
util_abort("%s: keyword pointer:%p not found in ecl_file instance. \n",__func__ , ecl_kw);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
/* DEPRECATED */
|
|
void ecl_file_push_block( ecl_file_type * ecl_file ) {
|
|
vector_append_ref( ecl_file->map_stack , ecl_file->active_view );
|
|
}
|
|
|
|
void ecl_file_pop_block( ecl_file_type * ecl_file ) {
|
|
ecl_file->active_view = (ecl_file_view_type *)vector_pop_back( ecl_file->map_stack );
|
|
}
|
|
|
|
|
|
static ecl_file_view_type * ecl_file_get_relative_blockview( ecl_file_type * ecl_file , const char * kw , int occurence) {
|
|
ecl_file_view_type * view = ecl_file_view_add_blockview( ecl_file->active_view , kw , occurence );
|
|
return view;
|
|
}
|
|
|
|
|
|
|
|
bool ecl_file_subselect_block( ecl_file_type * ecl_file , const char * kw , int occurence) {
|
|
ecl_file_view_type * blockmap = ecl_file_get_relative_blockview( ecl_file , kw , occurence);
|
|
if (blockmap != NULL) {
|
|
ecl_file->active_view = blockmap;
|
|
return true;
|
|
} else
|
|
return false;
|
|
}
|
|
|
|
|
|
bool ecl_file_select_block( ecl_file_type * ecl_file , const char * kw , int occurence ) {
|
|
ecl_file_view_type * blockmap = ecl_file_get_global_blockview( ecl_file , kw , occurence);
|
|
if (blockmap != NULL) {
|
|
ecl_file->active_view = blockmap;
|
|
return true;
|
|
} else
|
|
return false;
|
|
}
|
|
|
|
|
|
/*
|
|
Will select restart block nr @seqnum_index - without considering
|
|
report_steps or simulation time.
|
|
*/
|
|
bool ecl_file_iselect_rstblock( ecl_file_type * ecl_file , int seqnum_index ) {
|
|
return ecl_file_select_block( ecl_file , SEQNUM_KW , seqnum_index );
|
|
}
|
|
|
|
|
|
bool ecl_file_select_rstblock_sim_time( ecl_file_type * ecl_file , time_t sim_time) {
|
|
int seqnum_index = ecl_file_view_seqnum_index_from_sim_time( ecl_file->global_view , sim_time );
|
|
|
|
if (seqnum_index >= 0)
|
|
return ecl_file_iselect_rstblock( ecl_file , seqnum_index);
|
|
else
|
|
return false;
|
|
}
|
|
|
|
|
|
bool ecl_file_select_rstblock_report_step( ecl_file_type * ecl_file , int report_step) {
|
|
int global_index = ecl_file_view_find_kw_value( ecl_file->global_view , SEQNUM_KW , &report_step);
|
|
if ( global_index >= 0) {
|
|
int seqnum_index = ecl_file_view_iget_occurence( ecl_file->global_view , global_index );
|
|
return ecl_file_iselect_rstblock( ecl_file , seqnum_index);
|
|
} else
|
|
return false;
|
|
}
|
|
|
|
|
|
/******************************************************************/
|
|
|
|
static ecl_file_type * ecl_file_open_rstblock_report_step__( const char * filename , int report_step , int flags) {
|
|
ecl_file_type * ecl_file = ecl_file_open( filename , flags );
|
|
if (ecl_file) {
|
|
if (!ecl_file_select_rstblock_report_step( ecl_file , report_step )) {
|
|
ecl_file_close( ecl_file );
|
|
ecl_file = NULL;
|
|
}
|
|
}
|
|
return ecl_file;
|
|
}
|
|
|
|
ecl_file_type * ecl_file_open_rstblock_report_step( const char * filename , int report_step , int flags) {
|
|
return ecl_file_open_rstblock_report_step__(filename , report_step , flags );
|
|
}
|
|
|
|
|
|
/******************************************************************/
|
|
|
|
static ecl_file_type * ecl_file_open_rstblock_sim_time__( const char * filename , time_t sim_time, int flags ) {
|
|
ecl_file_type * ecl_file = ecl_file_open( filename , flags );
|
|
if (ecl_file) {
|
|
if (!ecl_file_select_rstblock_sim_time( ecl_file , sim_time)) {
|
|
ecl_file_close( ecl_file );
|
|
ecl_file = NULL;
|
|
}
|
|
}
|
|
return ecl_file;
|
|
}
|
|
|
|
ecl_file_type * ecl_file_open_rstblock_sim_time( const char * filename , time_t sim_time, int flags) {
|
|
return ecl_file_open_rstblock_sim_time__( filename , sim_time , flags );
|
|
}
|
|
|
|
/******************************************************************/
|
|
|
|
static ecl_file_type * ecl_file_iopen_rstblock__( const char * filename , int seqnum_index, int flags ) {
|
|
ecl_file_type * ecl_file = ecl_file_open( filename , flags );
|
|
if (ecl_file) {
|
|
if (!ecl_file_iselect_rstblock( ecl_file , seqnum_index )) {
|
|
ecl_file_close( ecl_file );
|
|
ecl_file = NULL;
|
|
}
|
|
}
|
|
return ecl_file;
|
|
}
|
|
|
|
|
|
ecl_file_type * ecl_file_iopen_rstblock( const char * filename , int seqnum_index , int flags) {
|
|
return ecl_file_iopen_rstblock__(filename , seqnum_index , flags );
|
|
}
|
|
|
|
static bool ecl_file_index_valid0(const char * file_name, const char * index_file_name) {
|
|
if ( !util_file_exists( file_name ))
|
|
return false;
|
|
|
|
if (!util_file_exists (index_file_name))
|
|
return false;
|
|
|
|
if (util_file_difftime( file_name , index_file_name) > 0)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool ecl_file_index_valid1(const char * file_name, FILE * stream ) {
|
|
bool name_equal;
|
|
char * source_file = util_fread_alloc_string(stream);
|
|
char * input_name = util_split_alloc_filename( file_name );
|
|
|
|
name_equal = util_string_equal( source_file , input_name );
|
|
|
|
free( source_file );
|
|
free( input_name );
|
|
return name_equal;
|
|
}
|
|
|
|
bool ecl_file_index_valid(const char * file_name, const char * index_file_name) {
|
|
if (!ecl_file_index_valid0( file_name , index_file_name))
|
|
return false;
|
|
|
|
bool valid = false;
|
|
FILE * stream = fopen(index_file_name, "rb");
|
|
if (stream) {
|
|
valid = ecl_file_index_valid1( file_name , stream );
|
|
fclose( stream );
|
|
}
|
|
|
|
return valid;
|
|
}
|
|
|
|
|
|
bool ecl_file_write_index( const ecl_file_type * ecl_file , const char * index_filename) {
|
|
FILE * ostream = fopen(index_filename, "wb");
|
|
if (!ostream)
|
|
return false;
|
|
{
|
|
char * filename = util_split_alloc_filename( fortio_filename_ref(ecl_file->fortio));
|
|
util_fwrite_string( filename , ostream );
|
|
free( filename );
|
|
}
|
|
ecl_file_view_write_index( ecl_file->global_view , ostream );
|
|
fclose( ostream );
|
|
return true;
|
|
}
|
|
|
|
|
|
ecl_file_type * ecl_file_fast_open(const char * file_name, const char * index_file_name, int flags) {
|
|
if ( !ecl_file_index_valid0(file_name, index_file_name) )
|
|
return NULL;
|
|
|
|
FILE * istream = fopen(index_file_name, "rb");
|
|
if (!istream)
|
|
return NULL;
|
|
|
|
ecl_file_type * ecl_file = NULL;
|
|
|
|
if (ecl_file_index_valid1( file_name, istream)) {
|
|
fortio_type * fortio = ecl_file_alloc_fortio(file_name, flags);
|
|
if (fortio) {
|
|
ecl_file = ecl_file_alloc_empty( flags );
|
|
ecl_file->fortio = fortio;
|
|
ecl_file->global_view = ecl_file_view_fread_alloc( ecl_file->fortio , &ecl_file->flags , ecl_file->inv_view , istream );
|
|
if (ecl_file->global_view) {
|
|
ecl_file_select_global( ecl_file );
|
|
if (ecl_file_view_check_flags( ecl_file->flags , ECL_FILE_CLOSE_STREAM))
|
|
fortio_fclose_stream( ecl_file->fortio );
|
|
}
|
|
else {
|
|
ecl_file_close( ecl_file );
|
|
ecl_file = NULL;
|
|
}
|
|
}
|
|
}
|
|
fclose(istream);
|
|
return ecl_file;
|
|
}
|