mirror of
https://github.com/OPM/ResInsight.git
synced 2025-02-25 18:55:39 -06:00
454 lines
13 KiB
C++
454 lines
13 KiB
C++
/*
|
|
Copyright (C) 2011 Statoil ASA, Norway.
|
|
|
|
The file 'ecl_file_kw.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 <stdbool.h>
|
|
|
|
#include <ert/util/size_t_vector.hpp>
|
|
#include <ert/util/util.h>
|
|
|
|
#include <ert/ecl/ecl_util.hpp>
|
|
#include <ert/ecl/ecl_kw.hpp>
|
|
#include <ert/ecl/ecl_file_kw.hpp>
|
|
#include <ert/ecl/fortio.h>
|
|
|
|
/*
|
|
This file implements the datatype ecl_file_kw which is used to hold
|
|
header-information about an ecl_kw instance on file. When a
|
|
ecl_file_kw instance is created it is initialized with the header
|
|
information (name, size, type) for an ecl_kw instance and the offset
|
|
in a file actually containing the keyword.
|
|
|
|
If and when the keyword is actually queried for at a later stage the
|
|
ecl_file_kw_get_kw() method will seek to the keyword position in an
|
|
open fortio instance and call ecl_kw_fread_alloc() to instantiate
|
|
the keyword itself.
|
|
|
|
The ecl_file_kw datatype is mainly used by the ecl_file datatype;
|
|
whose index tables consists of ecl_file_kw instances.
|
|
*/
|
|
|
|
|
|
#define ECL_FILE_KW_TYPE_ID 646107
|
|
|
|
struct inv_map_struct {
|
|
size_t_vector_type * file_kw_ptr;
|
|
size_t_vector_type * ecl_kw_ptr;
|
|
bool sorted;
|
|
};
|
|
|
|
struct ecl_file_kw_struct {
|
|
UTIL_TYPE_ID_DECLARATION;
|
|
offset_type file_offset;
|
|
ecl_data_type data_type;
|
|
int kw_size;
|
|
int ref_count;
|
|
char * header;
|
|
ecl_kw_type * kw;
|
|
};
|
|
|
|
|
|
|
|
/*****************************************************************/
|
|
|
|
inv_map_type * inv_map_alloc() {
|
|
inv_map_type * map = (inv_map_type *)util_malloc( sizeof * map );
|
|
map->file_kw_ptr = size_t_vector_alloc( 0 , 0 );
|
|
map->ecl_kw_ptr = size_t_vector_alloc( 0 , 0 );
|
|
map->sorted = false;
|
|
return map;
|
|
}
|
|
|
|
void inv_map_free( inv_map_type * map ) {
|
|
size_t_vector_free( map->file_kw_ptr );
|
|
size_t_vector_free( map->ecl_kw_ptr );
|
|
free( map );
|
|
}
|
|
|
|
|
|
static void inv_map_assert_sort( inv_map_type * map ) {
|
|
if (!map->sorted) {
|
|
perm_vector_type * perm = size_t_vector_alloc_sort_perm( map->ecl_kw_ptr );
|
|
|
|
size_t_vector_permute( map->ecl_kw_ptr , perm );
|
|
size_t_vector_permute( map->file_kw_ptr , perm );
|
|
map->sorted = true;
|
|
|
|
free( perm );
|
|
}
|
|
}
|
|
|
|
static void inv_map_drop_kw( inv_map_type * map , const ecl_kw_type * ecl_kw) {
|
|
inv_map_assert_sort( map );
|
|
{
|
|
int index = size_t_vector_index_sorted( map->ecl_kw_ptr , (size_t) ecl_kw );
|
|
if (index == -1)
|
|
util_abort("%s: trying to drop non-existent kw \n",__func__);
|
|
|
|
size_t_vector_idel( map->ecl_kw_ptr , index );
|
|
size_t_vector_idel( map->file_kw_ptr , index );
|
|
map->sorted = false;
|
|
}
|
|
}
|
|
|
|
|
|
static void inv_map_add_kw( inv_map_type * map , const ecl_file_kw_type * file_kw , const ecl_kw_type * ecl_kw) {
|
|
size_t_vector_append( map->file_kw_ptr , (size_t) file_kw );
|
|
size_t_vector_append( map->ecl_kw_ptr , (size_t) ecl_kw );
|
|
map->sorted = false;
|
|
}
|
|
|
|
|
|
ecl_file_kw_type * inv_map_get_file_kw( inv_map_type * inv_map , const ecl_kw_type * ecl_kw ) {
|
|
inv_map_assert_sort( inv_map );
|
|
{
|
|
int index = size_t_vector_index_sorted( inv_map->ecl_kw_ptr , (size_t) ecl_kw );
|
|
if (index == -1)
|
|
/* ecl_kw ptr not found. */
|
|
return NULL;
|
|
else
|
|
return (ecl_file_kw_type * ) size_t_vector_iget( inv_map->file_kw_ptr , index );
|
|
}
|
|
}
|
|
|
|
|
|
/*****************************************************************/
|
|
|
|
static UTIL_SAFE_CAST_FUNCTION( ecl_file_kw , ECL_FILE_KW_TYPE_ID )
|
|
UTIL_IS_INSTANCE_FUNCTION( ecl_file_kw , ECL_FILE_KW_TYPE_ID )
|
|
|
|
|
|
|
|
ecl_file_kw_type * ecl_file_kw_alloc0( const char * header , ecl_data_type data_type , int size , offset_type offset) {
|
|
ecl_file_kw_type * file_kw = (ecl_file_kw_type *)util_malloc( sizeof * file_kw );
|
|
UTIL_TYPE_ID_INIT( file_kw , ECL_FILE_KW_TYPE_ID );
|
|
|
|
file_kw->header = util_alloc_string_copy( header );
|
|
memcpy(&file_kw->data_type, &data_type, sizeof data_type);
|
|
file_kw->kw_size = size;
|
|
file_kw->file_offset = offset;
|
|
file_kw->ref_count = 0;
|
|
file_kw->kw = NULL;
|
|
|
|
return file_kw;
|
|
}
|
|
|
|
/**
|
|
Create a new ecl_file_kw instance based on header information from
|
|
the input keyword. Typically only the header has been loaded from
|
|
the keyword.
|
|
|
|
Observe that it is the users responsability that the @offset
|
|
argument in ecl_file_kw_alloc() comes from the same fortio instance
|
|
as used when calling ecl_file_kw_get_kw() to actually instatiate
|
|
the ecl_kw. This is automatically assured when using ecl_file to
|
|
access the ecl_file_kw instances.
|
|
*/
|
|
|
|
ecl_file_kw_type * ecl_file_kw_alloc( const ecl_kw_type * ecl_kw , offset_type offset ) {
|
|
return ecl_file_kw_alloc0( ecl_kw_get_header( ecl_kw ) , ecl_kw_get_data_type( ecl_kw ) , ecl_kw_get_size( ecl_kw ) , offset );
|
|
}
|
|
|
|
|
|
/**
|
|
Does NOT copy the kw pointer which must be reloaded.
|
|
*/
|
|
ecl_file_kw_type * ecl_file_kw_alloc_copy( const ecl_file_kw_type * src ) {
|
|
return ecl_file_kw_alloc0( src->header , ecl_file_kw_get_data_type(src) , src->kw_size , src->file_offset );
|
|
}
|
|
|
|
|
|
|
|
|
|
void ecl_file_kw_free( ecl_file_kw_type * file_kw ) {
|
|
if (file_kw->kw != NULL) {
|
|
ecl_kw_free( file_kw->kw );
|
|
file_kw->kw = NULL;
|
|
}
|
|
free( file_kw->header );
|
|
free( file_kw );
|
|
}
|
|
|
|
|
|
void ecl_file_kw_free__( void * arg ) {
|
|
ecl_file_kw_type * file_kw = ecl_file_kw_safe_cast( arg );
|
|
ecl_file_kw_free( file_kw );
|
|
}
|
|
|
|
|
|
bool ecl_file_kw_equal( const ecl_file_kw_type * kw1 , const ecl_file_kw_type * kw2)
|
|
{
|
|
if (kw1->file_offset != kw2->file_offset)
|
|
return false;
|
|
|
|
if (kw1->kw_size != kw2->kw_size)
|
|
return false;
|
|
|
|
if (!ecl_type_is_equal( kw1->data_type, kw2->data_type))
|
|
return false;
|
|
|
|
return util_string_equal( kw1->header , kw2->header );
|
|
}
|
|
|
|
static void ecl_file_kw_assert_kw( const ecl_file_kw_type * file_kw ) {
|
|
if(!ecl_type_is_equal(
|
|
ecl_file_kw_get_data_type(file_kw),
|
|
ecl_kw_get_data_type(file_kw->kw)
|
|
))
|
|
util_abort("%s: type mismatch between header and file.\n",__func__);
|
|
|
|
if (file_kw->kw_size != ecl_kw_get_size( file_kw->kw ))
|
|
util_abort("%s: size mismatch between header and file.\n",__func__);
|
|
|
|
if (strcmp( file_kw->header , ecl_kw_get_header( file_kw->kw )) != 0 )
|
|
util_abort("%s: name mismatch between header and file.\n",__func__);
|
|
}
|
|
|
|
|
|
static void ecl_file_kw_drop_kw( ecl_file_kw_type * file_kw , inv_map_type * inv_map ) {
|
|
if (file_kw->kw != NULL) {
|
|
inv_map_drop_kw( inv_map , file_kw->kw );
|
|
ecl_kw_free( file_kw->kw );
|
|
file_kw->kw = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
static void ecl_file_kw_load_kw( ecl_file_kw_type * file_kw , fortio_type * fortio , inv_map_type * inv_map) {
|
|
if (fortio == NULL)
|
|
util_abort("%s: trying to load a keyword after the backing file has been detached.\n",__func__);
|
|
|
|
if (file_kw->kw != NULL)
|
|
ecl_file_kw_drop_kw( file_kw , inv_map );
|
|
|
|
{
|
|
fortio_fseek( fortio , file_kw->file_offset , SEEK_SET );
|
|
file_kw->kw = ecl_kw_fread_alloc( fortio );
|
|
ecl_file_kw_assert_kw( file_kw );
|
|
inv_map_add_kw( inv_map , file_kw , file_kw->kw );
|
|
}
|
|
}
|
|
|
|
/*
|
|
Calling scope will handle the NULL return value, and (optionally)
|
|
reopen the fortio stream and then call the ecl_file_kw_get_kw()
|
|
function.
|
|
*/
|
|
|
|
ecl_kw_type * ecl_file_kw_get_kw_ptr( ecl_file_kw_type * file_kw) {
|
|
if (file_kw->ref_count == 0)
|
|
return NULL;
|
|
|
|
file_kw->ref_count++;
|
|
return file_kw->kw;
|
|
}
|
|
|
|
/*
|
|
Will return the ecl_kw instance of this file_kw; if it is not
|
|
currently loaded the method will instantiate the ecl_kw instance
|
|
from the @fortio input handle.
|
|
|
|
After loading the keyword it will be kept in memory, so a possible
|
|
subsequent lookup will be served from memory.
|
|
|
|
The ecl_file layer maintains a pointer mapping between the
|
|
ecl_kw_type pointers and their ecl_file_kw_type containers; this
|
|
mapping needs the new_load return value from the
|
|
ecl_file_kw_get_kw() function.
|
|
*/
|
|
|
|
|
|
ecl_kw_type * ecl_file_kw_get_kw( ecl_file_kw_type * file_kw , fortio_type * fortio , inv_map_type * inv_map ) {
|
|
if (file_kw->ref_count == 0)
|
|
ecl_file_kw_load_kw( file_kw , fortio , inv_map);
|
|
|
|
if(file_kw->kw)
|
|
file_kw->ref_count++;
|
|
|
|
return file_kw->kw;
|
|
}
|
|
|
|
|
|
bool ecl_file_kw_ptr_eq( const ecl_file_kw_type * file_kw , const ecl_kw_type * ecl_kw) {
|
|
if (file_kw->kw == ecl_kw)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
void ecl_file_kw_replace_kw( ecl_file_kw_type * file_kw , fortio_type * target , ecl_kw_type * new_kw ) {
|
|
if (!ecl_type_is_equal(
|
|
ecl_file_kw_get_data_type(file_kw),
|
|
ecl_kw_get_data_type(new_kw)
|
|
))
|
|
util_abort("%s: sorry type mismatch between in-file keyword and new keyword \n",__func__);
|
|
if(file_kw->kw_size != ecl_kw_get_size(new_kw))
|
|
util_abort("%s: sorry size mismatch between in-file keyword and new keyword \n",__func__);
|
|
|
|
if (file_kw->kw != NULL)
|
|
ecl_kw_free( file_kw->kw );
|
|
|
|
file_kw->kw = new_kw;
|
|
fortio_fseek( target , file_kw->file_offset , SEEK_SET );
|
|
ecl_kw_fwrite( file_kw->kw , target );
|
|
}
|
|
|
|
|
|
|
|
const char * ecl_file_kw_get_header( const ecl_file_kw_type * file_kw ) {
|
|
return file_kw->header;
|
|
}
|
|
|
|
int ecl_file_kw_get_size( const ecl_file_kw_type * file_kw ) {
|
|
return file_kw->kw_size;
|
|
}
|
|
|
|
ecl_data_type ecl_file_kw_get_data_type(const ecl_file_kw_type * file_kw) {
|
|
return file_kw->data_type;
|
|
}
|
|
|
|
offset_type ecl_file_kw_get_offset(const ecl_file_kw_type * file_kw) {
|
|
return file_kw->file_offset;
|
|
}
|
|
|
|
bool ecl_file_kw_fskip_data( const ecl_file_kw_type * file_kw , fortio_type * fortio) {
|
|
return ecl_kw_fskip_data__( ecl_file_kw_get_data_type(file_kw) , file_kw->kw_size , fortio );
|
|
}
|
|
|
|
|
|
/**
|
|
This function will replace the file content of the keyword pointed
|
|
to by @file_kw, with the new content given by @ecl_kw. The new
|
|
@ecl_kw keyword must have identical header to the one already
|
|
present in the file.
|
|
*/
|
|
|
|
void ecl_file_kw_inplace_fwrite( ecl_file_kw_type * file_kw , fortio_type * fortio) {
|
|
ecl_file_kw_assert_kw( file_kw );
|
|
fortio_fseek( fortio , file_kw->file_offset , SEEK_SET );
|
|
ecl_kw_fskip_header( fortio );
|
|
fortio_fclean(fortio);
|
|
ecl_kw_fwrite_data( file_kw->kw , fortio );
|
|
}
|
|
|
|
|
|
void ecl_file_kw_fwrite( const ecl_file_kw_type * file_kw , FILE * stream ) {
|
|
int header_length = strlen( file_kw->header );
|
|
for (int i=0; i < ECL_STRING8_LENGTH; i++) {
|
|
if (i < header_length)
|
|
fputc( file_kw->header[i], stream );
|
|
else
|
|
fputc( ' ' , stream );
|
|
}
|
|
|
|
util_fwrite_int( file_kw->kw_size , stream );
|
|
util_fwrite_offset( file_kw->file_offset , stream );
|
|
util_fwrite_int( ecl_type_get_type( file_kw->data_type ) , stream );
|
|
util_fwrite_size_t( ecl_type_get_sizeof_iotype( file_kw->data_type ) , stream );
|
|
}
|
|
|
|
ecl_file_kw_type ** ecl_file_kw_fread_alloc_multiple( FILE * stream , int num) {
|
|
|
|
size_t file_kw_size = ECL_STRING8_LENGTH + 2 * sizeof(int) + sizeof(offset_type) + sizeof(size_t);
|
|
size_t buffer_size = num * file_kw_size;
|
|
char * buffer = (char*)util_malloc( buffer_size * sizeof * buffer );
|
|
size_t num_read = fread( buffer, 1 , buffer_size , stream);
|
|
|
|
if (num_read != buffer_size) {
|
|
free( buffer );
|
|
return NULL;
|
|
}
|
|
|
|
{
|
|
ecl_file_kw_type ** kw_list = (ecl_file_kw_type **)util_malloc( num * sizeof * kw_list );
|
|
for (int ikw = 0; ikw < num; ikw++) {
|
|
int buffer_offset = ikw * file_kw_size;
|
|
char header[ECL_STRING8_LENGTH + 1];
|
|
int kw_size;
|
|
offset_type file_offset;
|
|
ecl_type_enum ecl_type;
|
|
size_t type_size;
|
|
{
|
|
int index = 0;
|
|
while (true) {
|
|
if (buffer[index + buffer_offset] != ' ')
|
|
header[index] = buffer[index + buffer_offset];
|
|
else
|
|
break;
|
|
|
|
index++;
|
|
if (index == ECL_STRING8_LENGTH)
|
|
break;
|
|
}
|
|
header[index] = '\0';
|
|
buffer_offset += ECL_STRING8_LENGTH;
|
|
}
|
|
|
|
kw_size = *((int *) &buffer[ buffer_offset ]);
|
|
buffer_offset += sizeof kw_size;
|
|
|
|
file_offset = *((offset_type *) &buffer[ buffer_offset ]);
|
|
buffer_offset += sizeof file_offset;
|
|
|
|
ecl_type = *(( ecl_type_enum *) &buffer[ buffer_offset ]);
|
|
buffer_offset += sizeof ecl_type;
|
|
|
|
type_size = *((size_t *) &buffer[ buffer_offset ]);
|
|
buffer_offset += sizeof type_size;
|
|
|
|
kw_list[ikw] = ecl_file_kw_alloc0( header , ecl_type_create( ecl_type , type_size ), kw_size, file_offset );
|
|
}
|
|
|
|
free( buffer );
|
|
return kw_list;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
ecl_file_kw_type * ecl_file_kw_fread_alloc( FILE * stream ) {
|
|
ecl_file_kw_type * file_kw = NULL;
|
|
ecl_file_kw_type ** multiple = ecl_file_kw_fread_alloc_multiple( stream , 1 );
|
|
|
|
if (multiple) {
|
|
file_kw = multiple[0];
|
|
free( multiple );
|
|
}
|
|
|
|
return file_kw;
|
|
}
|
|
|
|
|
|
void ecl_file_kw_start_transaction(const ecl_file_kw_type * file_kw, int * ref_count) {
|
|
*ref_count = file_kw->ref_count;
|
|
}
|
|
|
|
|
|
void ecl_file_kw_end_transaction(ecl_file_kw_type * file_kw, int ref_count) {
|
|
if (ref_count == 0 && file_kw->ref_count > 0) {
|
|
ecl_kw_free(file_kw->kw);
|
|
file_kw->kw = NULL;
|
|
}
|
|
file_kw->ref_count = ref_count;
|
|
}
|