Files
ResInsight/ThirdParty/Ert/lib/geometry/geo_surface.cpp

424 lines
12 KiB
C++

/*
Copyright (C) 2011 Statoil ASA, Norway.
The file 'geo_surface.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 <math.h>
#include <stdlib.h>
#include <stdbool.h>
#include <ert/util/util.hpp>
#include <ert/util/type_macros.hpp>
#include <ert/geometry/geo_pointset.hpp>
#include <ert/geometry/geo_surface.hpp>
#define __PI 3.14159265
#define GEO_SURFACE_TYPE_ID 111743
struct geo_surface_struct {
UTIL_TYPE_ID_DECLARATION;
// Irap data:
int nx,ny;
double rot_angle; // Radians
double origo[2];
double cell_size[2];
double vec1[2];
double vec2[2];
geo_pointset_type * pointset;
};
static void geo_surface_copy_header( const geo_surface_type * src , geo_surface_type * target) {
target->nx = src->nx;
target->ny = src->ny;
target->rot_angle = src->rot_angle;
{
int i;
for (i = 0; i < 2; i++) {
target->origo[i] = src->origo[i];
target->cell_size[i] = src->cell_size[i];
target->vec1[i] = src->vec1[i];
target->vec2[i] = src->vec2[i];
}
}
}
static geo_surface_type * geo_surface_alloc_empty( bool internal_z ) {
geo_surface_type * surface = (geo_surface_type*)util_malloc( sizeof * surface );
UTIL_TYPE_ID_INIT( surface , GEO_SURFACE_TYPE_ID )
surface->pointset = geo_pointset_alloc( internal_z );
return surface;
}
static UTIL_SAFE_CAST_FUNCTION( geo_surface , GEO_SURFACE_TYPE_ID )
static void geo_surface_init_regular( geo_surface_type * surface , const double * zcoord) {
int zstride_nx = 1;
int zstride_ny = surface->nx;
int ix,iy;
for (iy=0; iy < surface->ny; iy++) {
for (ix=0; ix < surface->nx; ix++) {
double x = surface->origo[0] + ix*surface->vec1[0] + iy*surface->vec2[0];
double y =surface-> origo[1] + ix*surface->vec1[1] + iy*surface->vec2[1];
if (zcoord != NULL) {
int z_index = ix*zstride_nx + iy*zstride_ny;
geo_pointset_add_xyz( surface->pointset , x,y, zcoord[ z_index ]);
} else
geo_pointset_add_xyz( surface->pointset , x , y, 0 );
}
}
}
static bool geo_surface_fscanf_zcoord( const geo_surface_type * surface , FILE * stream , double * zcoord) {
int index = 0;
while (true) {
if (fscanf(stream , "%lg" , &zcoord[index]) == 1)
index++;
else
return false; // File is too short
if (index == surface->nx * surface->ny) {
double extra_value;
int fscanf_return = fscanf( stream , "%lg" , &extra_value);
return (fscanf_return == EOF); // no more data dangling at the end of the file.
}
}
}
static void geo_surface_fprintf_irap_header( const geo_surface_type * surface , FILE * stream ) {
const char * float_fmt = "%12.4f\n";
const char * int_fmt = "%d\n";
fprintf(stream , int_fmt , -996);
fprintf(stream , int_fmt , surface->ny);
fprintf(stream , float_fmt , surface->cell_size[0]);
fprintf(stream , float_fmt , surface->cell_size[1]);
fprintf(stream , float_fmt , surface->origo[0]);
fprintf(stream , float_fmt , surface->origo[0] + surface->cell_size[0] * (surface->nx - 1));
fprintf(stream , float_fmt , surface->origo[1]);
fprintf(stream , float_fmt , surface->origo[1] + surface->cell_size[1] * (surface->ny - 1));
fprintf(stream , int_fmt , surface->nx);
fprintf(stream , float_fmt , surface->rot_angle * 180 / __PI );
fprintf(stream , float_fmt , surface->origo[0]);
fprintf(stream , float_fmt , surface->origo[1]);
fprintf(stream , "0 0 0 0 0 0 0 \n");
}
static void geo_surface_fprintf_zcoord( const geo_surface_type * surface , FILE * stream , const double * zcoord ) {
int num_columns = 6;
const char * fmt = "%12.4f ";
int i;
for (i=0; i < geo_surface_get_size( surface ); i++) {
fprintf(stream , fmt , zcoord[i]);
if (((i + 1) % num_columns) == 0)
fprintf(stream , "\n");
}
}
static void geo_surface_fprintf_irap__( const geo_surface_type * surface, const char * filename , const double * zcoord) {
FILE * stream = util_mkdir_fopen( filename , "w");
{
geo_surface_fprintf_irap_header( surface , stream );
geo_surface_fprintf_zcoord( surface , stream, zcoord );
}
fclose( stream );
}
void geo_surface_fprintf_irap( const geo_surface_type * surface, const char * filename ) {
const double * zcoord = geo_pointset_get_zcoord( surface->pointset );
geo_surface_fprintf_irap__( surface , filename , zcoord );
}
void geo_surface_fprintf_irap_external_zcoord( const geo_surface_type * surface, const char * filename , const double * zcoord) {
geo_surface_fprintf_irap__( surface , filename , zcoord );
}
geo_surface_type * geo_surface_alloc_new( int nx, int ny,
double xinc, double yinc,
double xstart, double ystart,
double angle ) {
geo_surface_type * surface = geo_surface_alloc_empty( true );
surface->origo[0] = xstart;
surface->origo[1] = ystart;
surface->rot_angle = angle * __PI / 180.0;
surface->nx = nx;
surface->ny = ny;
surface->vec1[0] = xinc * cos( surface->rot_angle ) ;
surface->vec1[1] = xinc * sin( surface->rot_angle ) ;
surface->vec2[0] = -yinc * sin( surface->rot_angle ) ;
surface->vec2[1] = yinc * cos( surface->rot_angle );
surface->cell_size[0] = xinc;
surface->cell_size[1] = yinc;
geo_surface_init_regular( surface, NULL );
return surface;
}
static void geo_surface_fload_irap_header( geo_surface_type * surface, FILE * stream ) {
int const996;
int ny,nx;
double xinc, yinc,xstart, xend,ystart,yend,angle;
if (fscanf(stream , "%d %d %lg %lg %lg %lg %lg %lg %d %lg",
&const996 ,
&ny ,
&xinc ,
&yinc ,
&xstart ,
&xend ,
&ystart ,
&yend ,
&nx ,
&angle) == 10)
{
{
// Some information is rewritten/not used.
double d;
int i;
if (fscanf(stream , "%lg %lg %d %d %d %d %d %d %d " , &d , &d , &i, &i, &i, &i, &i, &i, &i) != 9)
util_abort("%s: reading irap header failed \n",__func__ );
}
surface->origo[0] = xstart;
surface->origo[1] = ystart;
surface->rot_angle = angle * __PI / 180.0;
surface->nx = nx;
surface->ny = ny;
surface->vec1[0] = xinc * cos( surface->rot_angle ) ;
surface->vec1[1] = xinc * sin( surface->rot_angle ) ;
surface->vec2[0] = -yinc * sin( surface->rot_angle ) ;
surface->vec2[1] = yinc * cos( surface->rot_angle );
surface->cell_size[0] = xinc;
surface->cell_size[1] = yinc;
} else
util_abort("%s: reading irap header failed\n",__func__ );
}
static bool geo_surface_fload_irap( geo_surface_type * surface , const char * filename , bool loadz) {
bool read_ok = true;
{
FILE * stream = util_fopen( filename , "r");
geo_surface_fload_irap_header( surface , stream );
{
double * zcoord = NULL;
if (loadz) {
zcoord = (double*)util_calloc( surface->nx * surface->ny , sizeof * zcoord );
read_ok = geo_surface_fscanf_zcoord( surface , stream , zcoord );
}
if (read_ok)
geo_surface_init_regular( surface , zcoord );
util_safe_free( zcoord );
}
fclose( stream );
}
return read_ok;
}
bool geo_surface_equal_header( const geo_surface_type * surface1 , const geo_surface_type * surface2 ) {
bool equal = true;
equal = equal && (surface1->nx == surface2->nx);
equal = equal && (surface1->ny == surface2->ny);
equal = equal && (util_double_approx_equal(surface1->rot_angle, surface2->rot_angle));
{
int i;
for (i = 0; i < 2; i++) {
equal = equal && (util_double_approx_equal(surface1->origo[i], surface2->origo[i]));
equal = equal && (util_double_approx_equal(surface1->cell_size[i], surface2->cell_size[i]));
equal = equal && (util_double_approx_equal(surface1->vec1[i], surface2->vec1[i]));
equal = equal && (util_double_approx_equal(surface1->vec2[i], surface2->vec2[i]));
}
}
return equal;
}
/**
The loading will fail hard if the header of surface does not agree
with the header found in file.
*/
bool geo_surface_fload_irap_zcoord( const geo_surface_type * surface, const char * filename, double *zcoord) {
FILE * stream = util_fopen__( filename , "r");
if (stream) {
bool loadOK = true;
{
geo_surface_type * tmp_surface = geo_surface_alloc_empty( false );
geo_surface_fload_irap_header( tmp_surface , stream );
loadOK = geo_surface_equal_header( surface , tmp_surface );
geo_surface_free( tmp_surface );
}
if (loadOK)
loadOK = geo_surface_fscanf_zcoord( surface , stream , zcoord);
fclose( stream );
return loadOK;
} else
return false;
}
geo_surface_type * geo_surface_fload_alloc_irap( const char * filename , bool loadz) {
geo_surface_type * surface = geo_surface_alloc_empty( loadz );
bool load_ok = geo_surface_fload_irap( surface , filename , loadz );
if (!load_ok) {
geo_surface_free( surface );
surface = NULL;
}
return surface;
}
geo_surface_type * geo_surface_alloc_copy( const geo_surface_type * src , bool copy_zdata) {
geo_surface_type * target = geo_surface_alloc_empty( true );
geo_surface_copy_header( src , target );
if (!geo_surface_equal_header( src , target ))
util_abort("%s: headers not equal after copy \n",__func__);
geo_pointset_memcpy( src->pointset , target->pointset , copy_zdata );
return target;
}
void geo_surface_free( geo_surface_type * surface ) {
geo_pointset_free( surface->pointset );
free( surface );
}
void geo_surface_free__( void * arg) {
geo_surface_type * surface = geo_surface_safe_cast( arg );
geo_surface_free( surface );
}
geo_pointset_type * geo_surface_get_pointset( const geo_surface_type * surface ) {
return surface->pointset;
}
void geo_surface_iget_xy( const geo_surface_type* surface, int index, double* x, double* y) {
const geo_pointset_type* pointset = geo_surface_get_pointset(surface);
geo_pointset_iget_xy(pointset, index, x, y);
}
int geo_surface_get_size( const geo_surface_type * surface ) {
return geo_pointset_get_size( surface->pointset );
}
int geo_surface_get_nx( const geo_surface_type * surface ) {
return surface->nx;
}
int geo_surface_get_ny( const geo_surface_type * surface ) {
return surface->ny;
}
bool geo_surface_equal( const geo_surface_type * surface1 , const geo_surface_type * surface2) {
if (geo_surface_equal_header(surface1 , surface2))
return geo_pointset_equal( surface1->pointset , surface2->pointset);
else
return false;
}
double geo_surface_iget_zvalue(const geo_surface_type * surface, int index) {
return geo_pointset_iget_z( surface->pointset , index );
}
void geo_surface_iset_zvalue(geo_surface_type * surface, int index , double value) {
return geo_pointset_iset_z( surface->pointset , index , value );
}
void geo_surface_assign_value( const geo_surface_type * src , double value) {
geo_pointset_assign_z( src->pointset , value );
}
void geo_surface_shift( const geo_surface_type * src , double value) {
geo_pointset_shift_z( src->pointset , value );
}
void geo_surface_scale( const geo_surface_type * src , double value) {
geo_pointset_scale_z( src->pointset , value );
}
void geo_surface_iadd( geo_surface_type * self , const geo_surface_type * other) {
if (geo_surface_equal_header(self, other))
geo_pointset_iadd( self->pointset , other->pointset);
else
util_abort("%s: tried to combine incompatible surfaces\n",__func__);
}
void geo_surface_isub( geo_surface_type * self , const geo_surface_type * other) {
if (geo_surface_equal_header(self, other))
geo_pointset_isub( self->pointset , other->pointset);
else
util_abort("%s: tried to combine incompatible surfaces\n",__func__);
}
void geo_surface_imul( geo_surface_type * self , const geo_surface_type * other) {
if (geo_surface_equal_header(self, other))
geo_pointset_imul( self->pointset , other->pointset);
else
util_abort("%s: tried to combine incompatible surfaces\n",__func__);
}
void geo_surface_isqrt( geo_surface_type * surface ) {
geo_pointset_isqrt( surface->pointset );
}