Remove files moved to opm-grid.
This commit is contained in:
parent
647e005297
commit
c7cc24385a
|
@ -34,17 +34,6 @@ list (APPEND MAIN_SOURCE_FILES
|
|||
opm/core/flowdiagnostics/FlowDiagnostics.cpp
|
||||
opm/core/flowdiagnostics/TofDiscGalReorder.cpp
|
||||
opm/core/flowdiagnostics/TofReorder.cpp
|
||||
opm/core/grid/GridHelpers.cpp
|
||||
opm/core/grid/GridManager.cpp
|
||||
opm/core/grid/GridUtilities.cpp
|
||||
opm/core/grid/cart_grid.c
|
||||
opm/core/grid/cornerpoint_grid.c
|
||||
opm/core/grid/cpgpreprocess/facetopology.c
|
||||
opm/core/grid/cpgpreprocess/geometry.c
|
||||
opm/core/grid/cpgpreprocess/preprocess.c
|
||||
opm/core/grid/cpgpreprocess/uniquepoints.c
|
||||
opm/core/grid/grid.c
|
||||
opm/core/grid/grid_equal.cpp
|
||||
opm/core/linalg/LinearSolverFactory.cpp
|
||||
opm/core/linalg/LinearSolverInterface.cpp
|
||||
opm/core/linalg/LinearSolverIstl.cpp
|
||||
|
@ -112,7 +101,6 @@ list (APPEND MAIN_SOURCE_FILES
|
|||
opm/core/utility/Event.cpp
|
||||
opm/core/utility/MonotCubicInterpolator.cpp
|
||||
opm/core/utility/NullStream.cpp
|
||||
opm/core/utility/StopWatch.cpp
|
||||
opm/core/utility/VelocityInterpolation.cpp
|
||||
opm/core/utility/WachspressCoord.cpp
|
||||
opm/core/utility/compressedToCartesian.cpp
|
||||
|
@ -150,7 +138,6 @@ list (APPEND TEST_SOURCE_FILES
|
|||
tests/test_nonuniformtablelinear.cpp
|
||||
tests/test_parallelistlinformation.cpp
|
||||
tests/test_sparsevector.cpp
|
||||
tests/test_sparsetable.cpp
|
||||
tests/test_velocityinterpolation.cpp
|
||||
tests/test_quadratures.cpp
|
||||
tests/test_uniformtablelinear.cpp
|
||||
|
@ -258,21 +245,6 @@ list (APPEND PUBLIC_HEADER_FILES
|
|||
opm/core/flowdiagnostics/FlowDiagnostics.hpp
|
||||
opm/core/flowdiagnostics/TofDiscGalReorder.hpp
|
||||
opm/core/flowdiagnostics/TofReorder.hpp
|
||||
opm/core/grid.h
|
||||
opm/core/grid/CellQuadrature.hpp
|
||||
opm/core/grid/ColumnExtract.hpp
|
||||
opm/core/grid/FaceQuadrature.hpp
|
||||
opm/core/grid/GridHelpers.hpp
|
||||
opm/core/grid/GridManager.hpp
|
||||
opm/core/grid/GridUtilities.hpp
|
||||
opm/core/grid/MinpvProcessor.hpp
|
||||
opm/core/grid/PinchProcessor.hpp
|
||||
opm/core/grid/cart_grid.h
|
||||
opm/core/grid/cornerpoint_grid.h
|
||||
opm/core/grid/cpgpreprocess/facetopology.h
|
||||
opm/core/grid/cpgpreprocess/geometry.h
|
||||
opm/core/grid/cpgpreprocess/preprocess.h
|
||||
opm/core/grid/cpgpreprocess/uniquepoints.h
|
||||
opm/core/linalg/LinearSolverFactory.hpp
|
||||
opm/core/linalg/LinearSolverInterface.hpp
|
||||
opm/core/linalg/LinearSolverIstl.hpp
|
||||
|
@ -383,9 +355,7 @@ list (APPEND PUBLIC_HEADER_FILES
|
|||
opm/core/utility/NullStream.hpp
|
||||
opm/core/utility/RegionMapping.hpp
|
||||
opm/core/utility/RootFinders.hpp
|
||||
opm/core/utility/SparseTable.hpp
|
||||
opm/core/utility/SparseVector.hpp
|
||||
opm/core/utility/StopWatch.hpp
|
||||
opm/core/utility/UniformTableLinear.hpp
|
||||
opm/core/utility/VelocityInterpolation.hpp
|
||||
opm/core/utility/WachspressCoord.hpp
|
||||
|
|
332
opm/core/grid.h
332
opm/core/grid.h
|
@ -1,332 +0,0 @@
|
|||
/*
|
||||
Copyright 2010, 2011, 2012 SINTEF ICT, Applied Mathematics.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef OPM_GRID_HEADER_INCLUDED
|
||||
#define OPM_GRID_HEADER_INCLUDED
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* \file
|
||||
*
|
||||
* Main OPM-Core grid data structure along with helper functions for
|
||||
* construction, destruction and reading a grid representation from disk.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
---- synopsis of grid.h ----
|
||||
|
||||
struct UnstructuredGrid
|
||||
{
|
||||
int dimensions;
|
||||
int number_of_cells;
|
||||
int number_of_faces;
|
||||
int number_of_nodes;
|
||||
int *face_nodes;
|
||||
int *face_nodepos;
|
||||
int *face_cells;
|
||||
int *cell_faces;
|
||||
int *cell_facepos;
|
||||
double *node_coordinates;
|
||||
double *face_centroids;
|
||||
double *face_areas;
|
||||
double *face_normals;
|
||||
double *cell_centroids;
|
||||
double *cell_volumes;
|
||||
int *global_cell;
|
||||
int cartdims[3];
|
||||
int *cell_facetag;
|
||||
};
|
||||
|
||||
void destroy_grid(struct UnstructuredGrid *g);
|
||||
|
||||
struct UnstructuredGrid *
|
||||
create_grid_empty(void);
|
||||
|
||||
struct UnstructuredGrid *
|
||||
allocate_grid(size_t ndims ,
|
||||
size_t ncells ,
|
||||
size_t nfaces ,
|
||||
size_t nfacenodes,
|
||||
size_t ncellfaces,
|
||||
size_t nnodes );
|
||||
|
||||
struct UnstructuredGrid *
|
||||
read_grid(const char *fname);
|
||||
|
||||
---- end of synopsis of grid.h ----
|
||||
*/
|
||||
|
||||
/**
|
||||
Data structure for an unstructured grid, unstructured meaning that
|
||||
any cell may have an arbitrary number of adjacent cells. The struct
|
||||
contains both topological and geometrical data.
|
||||
|
||||
The grid consists of a set of cells, which are assumed to partion
|
||||
the grid domain. A face is defined as the nonempty intersection of
|
||||
(the closure of) two grid cells (the grid is a cell complex).
|
||||
|
||||
The topology information is limited to some adjacency relations
|
||||
between cells, faces and nodes only. The data structure does not
|
||||
contain any information pertaining to edges (except in 2d, where
|
||||
edges are the same as faces).
|
||||
|
||||
The geometry information is limited to centroids, areas/volumes and
|
||||
normals.
|
||||
*/
|
||||
struct UnstructuredGrid
|
||||
{
|
||||
/**
|
||||
The topological and geometrical dimensionality of the
|
||||
grid. Note that we do not support grids that are embedded in
|
||||
higher-dimensional spaces, such as 2d grids embedded in 3d.
|
||||
This number must be 2 or 3.
|
||||
*/
|
||||
int dimensions;
|
||||
|
||||
/** The number of cells in the grid. */
|
||||
int number_of_cells;
|
||||
/** The number of faces in the grid. */
|
||||
int number_of_faces;
|
||||
/** The number of nodes in the grid. */
|
||||
int number_of_nodes;
|
||||
|
||||
/**
|
||||
Contains for each face, the indices of its adjacent nodes.
|
||||
The size of the array is equal to the sum over all faces of
|
||||
each face's number of adjacent nodes, which also is equal to
|
||||
face_nodepos[number_of_faces].
|
||||
*/
|
||||
int *face_nodes;
|
||||
/**
|
||||
For a face f, face_nodepos[f] contains the starting index
|
||||
for f's nodes in the face_nodes array.
|
||||
The size of the array is equal to (number_of_faces + 1).
|
||||
*/
|
||||
int *face_nodepos;
|
||||
/**
|
||||
For a face f, face_cells[2*f] and face_cells[2*f + 1] contain
|
||||
the cell indices of the cells adjacent to f. The number -1
|
||||
indicates the outer boundary.
|
||||
The order is significant, as it gives the orientation: if
|
||||
face_cells[2*f] == a and face_cells[2*f + 1] == b, f is
|
||||
oriented from a to b. The inverse of this mapping is stored in
|
||||
cell_faces and cell_facepos.
|
||||
The size of the array is equal to (2*number_of_faces).
|
||||
*/
|
||||
int *face_cells;
|
||||
|
||||
/**
|
||||
Contains for each cell, the indices of its adjacent faces.
|
||||
The size of the array is equal to the sum over all cells of
|
||||
each cell's number of adjacent faces, which also is equal to
|
||||
cell_facepos[number_of_cells].
|
||||
*/
|
||||
int *cell_faces;
|
||||
/**
|
||||
For a cell c, cell_facepos[c] contains the starting index
|
||||
for c's faces in the cell_faces array.
|
||||
The size of the array is equal to (number_of_cells + 1).
|
||||
*/
|
||||
int *cell_facepos;
|
||||
|
||||
/**
|
||||
Node coordinates, stored consecutively for each node. That is,
|
||||
for a node i, node_coordinates[dimensions*i + d] contains the
|
||||
d'th coordinate of node i.
|
||||
The size of the array is equal to (dimensions*number_of_nodes).
|
||||
*/
|
||||
double *node_coordinates;
|
||||
|
||||
/**
|
||||
Exact or approximate face centroids, stored consecutively for each face. That is,
|
||||
for a face f, face_centroids[dimensions*f + d] contains the
|
||||
d'th coordinate of f's centroid.
|
||||
The size of the array is equal to (dimensions*number_of_faces).
|
||||
*/
|
||||
double *face_centroids;
|
||||
/**
|
||||
Exact or approximate face areas.
|
||||
The size of the array is equal to number_of_faces.
|
||||
*/
|
||||
double *face_areas;
|
||||
/**
|
||||
Exact or approximate face normals, stored consecutively for
|
||||
each face. That is, for a face f, face_normals[dimensions*f + d]
|
||||
contains the d'th coordinate of f's normal.
|
||||
The size of the array is equal to (dimensions*number_of_faces).
|
||||
|
||||
IMPORTANT: the normals are not normalized to have unit length!
|
||||
They are assumed to always have length equal to the
|
||||
corresponding face's area.
|
||||
*/
|
||||
double *face_normals;
|
||||
|
||||
/**
|
||||
Exact or approximate cell centroids, stored consecutively for each cell. That is,
|
||||
for a cell c, cell_centroids[dimensions*c + d] contains the
|
||||
d'th coordinate of c's centroid.
|
||||
The size of the array is equal to (dimensions*number_of_cells).
|
||||
*/
|
||||
double *cell_centroids;
|
||||
/**
|
||||
Exact or approximate cell volumes.
|
||||
The size of the array is equal to number_of_cells.
|
||||
*/
|
||||
double *cell_volumes;
|
||||
|
||||
|
||||
/**
|
||||
If non-null, this array contains the logical cartesian indices
|
||||
(in a lexicographic ordering) of each cell.
|
||||
In that case, the array size is equal to number_of_cells.
|
||||
|
||||
This field is intended for grids that have a (possibly
|
||||
degenerate) logical cartesian structure, for example
|
||||
cornerpoint grids.
|
||||
|
||||
If null, this indicates that the element indices coincide
|
||||
with the logical cartesian indices, _or_ that the grid has
|
||||
no inherent Cartesian structure. Due to this ambiguity, this
|
||||
field should not be used to check if the grid is Cartesian.
|
||||
*/
|
||||
int *global_cell;
|
||||
|
||||
/**
|
||||
Contains the size of the logical cartesian structure (if any) of the grid.
|
||||
|
||||
This field is intended for grids that have a (possibly
|
||||
degenerate) logical cartesian structure, for example
|
||||
cornerpoint grids.
|
||||
|
||||
If the grid is unstructured (non-Cartesian), then at least one
|
||||
of the items in the (sub-)array cartdims[0..dimensions-1]
|
||||
_could_ have the value 0 to signal this.
|
||||
*/
|
||||
int cartdims[3];
|
||||
/**
|
||||
If non-null, this array contains a number for cell-face
|
||||
adjacency indicating the face's position with respect to the
|
||||
cell, in a logical cartesian sense. The tags are in [0, ..., 5]
|
||||
meaning [I-, I+, J-, J+, K-, K+], where I, J, K are the logical
|
||||
cartesian principal directions.
|
||||
The structure of this array is identical to cell_faces, and
|
||||
cell_facepos indices into cell_facetag as well.
|
||||
|
||||
If non-null, the array size is equal to
|
||||
cell_facepos[number_of_cells].
|
||||
|
||||
This field is intended for grids that have a (possibly
|
||||
degenerate) logical cartesian structure, for example
|
||||
cornerpoint grids.
|
||||
*/
|
||||
int *cell_facetag;
|
||||
|
||||
|
||||
/*
|
||||
This vector is retained to be able to construct an
|
||||
EclipseGrid representation of the Grid. If the grid
|
||||
processor actually modifies the elements of the zcorn
|
||||
vector from the input the modified version is stored here;
|
||||
otherwise we just use the default.
|
||||
*/
|
||||
double * zcorn;
|
||||
};
|
||||
|
||||
/**
|
||||
Destroy and deallocate an UnstructuredGrid and all its data.
|
||||
|
||||
This function assumes that all arrays of the UnstructuredGrid (if
|
||||
non-null) have been individually allocated by malloc(). They will
|
||||
be deallocated with free().
|
||||
*/
|
||||
void destroy_grid(struct UnstructuredGrid *g);
|
||||
|
||||
/**
|
||||
Allocate and initialise an empty UnstructuredGrid.
|
||||
|
||||
This is the moral equivalent of a C++ default constructor.
|
||||
|
||||
\return Fully formed UnstructuredGrid with all fields zero or
|
||||
<code>NULL</code> as appropriate. <code>NULL</code> in case of
|
||||
allocation failure.
|
||||
*/
|
||||
struct UnstructuredGrid *
|
||||
create_grid_empty(void);
|
||||
|
||||
/**
|
||||
Allocate and initialise an UnstructuredGrid where pointers are set
|
||||
to location with correct size.
|
||||
|
||||
\param[in] ndims Number of physical dimensions.
|
||||
\param[in] ncells Number of cells.
|
||||
\param[in] nfaces Number of faces.
|
||||
\param[in] nfacenodes Size of mapping from faces to nodes.
|
||||
\param[in] ncellfaces Size of mapping from cells to faces.
|
||||
(i.e., the number of `half-faces')
|
||||
\param[in] nnodes Number of Nodes.
|
||||
|
||||
\return Fully formed UnstructuredGrid with all fields except
|
||||
<code>global_cell</code> allocated, but not filled with meaningful
|
||||
values. <code>NULL</code> in case of allocation failure.
|
||||
*/
|
||||
struct UnstructuredGrid *
|
||||
allocate_grid(size_t ndims ,
|
||||
size_t ncells ,
|
||||
size_t nfaces ,
|
||||
size_t nfacenodes,
|
||||
size_t ncellfaces,
|
||||
size_t nnodes );
|
||||
|
||||
|
||||
/**
|
||||
Will allocate storage internally in the grid object to hold a copy
|
||||
of the zcorn data supplied in the second argument.
|
||||
*/
|
||||
void
|
||||
attach_zcorn_copy(struct UnstructuredGrid* G ,
|
||||
const double * zcorn);
|
||||
|
||||
|
||||
/**
|
||||
* Import a grid from a character representation stored in file.
|
||||
*
|
||||
* @param[in] fname File name.
|
||||
* @return Fully formed UnstructuredGrid with all fields allocated and filled.
|
||||
* Returns @c NULL in case of allocation failure.
|
||||
*/
|
||||
struct UnstructuredGrid *
|
||||
read_grid(const char *fname);
|
||||
|
||||
|
||||
|
||||
|
||||
bool
|
||||
grid_equal(const struct UnstructuredGrid * grid1 , const struct UnstructuredGrid * grid2);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* OPM_GRID_HEADER_INCLUDED */
|
|
@ -1,260 +0,0 @@
|
|||
/*
|
||||
Copyright 2012 SINTEF ICT, Applied Mathematics.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef OPM_CELLQUADRATURE_HEADER_INCLUDED
|
||||
#define OPM_CELLQUADRATURE_HEADER_INCLUDED
|
||||
|
||||
#include <opm/core/grid.h>
|
||||
#include <opm/common/ErrorMacros.hpp>
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
|
||||
namespace {
|
||||
/// Calculates the determinant of a 3 x 3 matrix, represented as
|
||||
/// three three-dimensional arrays.
|
||||
inline double determinantOf(const double* a0,
|
||||
const double* a1,
|
||||
const double* a2)
|
||||
{
|
||||
return
|
||||
a0[0] * (a1[1] * a2[2] - a2[1] * a1[2]) -
|
||||
a0[1] * (a1[0] * a2[2] - a2[0] * a1[2]) +
|
||||
a0[2] * (a1[0] * a2[1] - a2[0] * a1[1]);
|
||||
}
|
||||
|
||||
/// Computes the volume of a tetrahedron consisting of 4 vertices
|
||||
/// with 3-dimensional coordinates
|
||||
inline double tetVolume(const double* p0,
|
||||
const double* p1,
|
||||
const double* p2,
|
||||
const double* p3)
|
||||
{
|
||||
double a[3] = { p1[0] - p0[0], p1[1] - p0[1], p1[2] - p0[2] };
|
||||
double b[3] = { p2[0] - p0[0], p2[1] - p0[1], p2[2] - p0[2] };
|
||||
double c[3] = { p3[0] - p0[0], p3[1] - p0[1], p3[2] - p0[2] };
|
||||
return std::fabs(determinantOf(a, b, c) / 6.0);
|
||||
}
|
||||
|
||||
/// Calculates the area of a triangle consisting of 3 vertices
|
||||
/// with 2-dimensional coordinates
|
||||
inline double triangleArea2d(const double* p0,
|
||||
const double* p1,
|
||||
const double* p2)
|
||||
{
|
||||
double a[2] = { p1[0] - p0[0], p1[1] - p0[1] };
|
||||
double b[2] = { p2[0] - p0[0], p2[1] - p0[1] };
|
||||
double a_cross_b = a[0]*b[1] - a[1]*b[0];
|
||||
return 0.5*std::fabs(a_cross_b);
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
/// A class providing numerical quadrature for cells.
|
||||
/// In general: \int_{cell} g(x) dx = \sum_{i=0}^{n-1} w_i g(x_i).
|
||||
/// Note that this class does multiply weights by cell volume,
|
||||
/// so weights always sum to cell volume.
|
||||
///
|
||||
/// Degree 1 method:
|
||||
/// Midpoint (centroid) method.
|
||||
/// n = 1, w_0 = cell volume, x_0 = cell centroid
|
||||
///
|
||||
/// Degree 2 method for 2d (but see the note):
|
||||
/// Based on subdivision of the cell into triangles,
|
||||
/// with the centroid as a common vertex, and the triangle
|
||||
/// edge midpoint rule.
|
||||
/// Triangle i consists of the centroid C, nodes N_i and N_{i+1}.
|
||||
/// Its area is A_i.
|
||||
/// n = 2 * nn (nn = num nodes in face)
|
||||
/// For i = 0..(nn-1):
|
||||
/// w_i = 1/3 A_i.
|
||||
/// w_{nn+i} = 1/3 A_{i-1} + 1/3 A_i
|
||||
/// x_i = (N_i + N_{i+1})/2
|
||||
/// x_{nn+i} = (C + N_i)/2
|
||||
/// All N and A indices are interpreted cyclic, modulus nn.
|
||||
/// Note: for simplicity of implementation, we currently use
|
||||
/// n = 3 * nn
|
||||
/// For i = 0..(nn-1):
|
||||
/// w_{3*i + {0,1,2}} = 1/3 A_i
|
||||
/// x_{3*i} = (N_i + N_{i+1})/2
|
||||
/// x_{3*i + {1,2}} = (C + N_{i,i+1})/2
|
||||
/// This is simpler, because we can implement it easily
|
||||
/// based on iteration over faces without requiring any
|
||||
/// particular (cyclic) ordering.
|
||||
///
|
||||
/// Degree 2 method for 3d:
|
||||
/// Based on subdivision of each cell face into triangles
|
||||
/// with the face centroid as a common vertex, and then
|
||||
/// subdividing the cell into tetrahedra with the cell
|
||||
/// centroid as a common vertex. Then apply the tetrahedron
|
||||
/// rule with the following 4 nodes (uniform weights):
|
||||
/// a = 0.138196601125010515179541316563436
|
||||
/// x_i has all barycentric coordinates = a, except for
|
||||
/// the i'th coordinate which is = 1 - 3a.
|
||||
/// This rule is from http://nines.cs.kuleuven.be/ecf,
|
||||
/// it is the second degree 2 4-point rule for tets,
|
||||
/// referenced to Stroud(1971).
|
||||
/// The tetrahedra are numbered T_{i,j}, and are given by the
|
||||
/// cell centroid C, the face centroid FC_i, and two nodes
|
||||
/// of face i: FN_{i,j}, FN_{i,j+1}.
|
||||
class CellQuadrature
|
||||
{
|
||||
public:
|
||||
CellQuadrature(const UnstructuredGrid& grid,
|
||||
const int cell,
|
||||
const int degree)
|
||||
: grid_(grid), cell_(cell), degree_(degree)
|
||||
{
|
||||
if (grid.dimensions > 3) {
|
||||
OPM_THROW(std::runtime_error, "CellQuadrature only implemented for up to 3 dimensions.");
|
||||
}
|
||||
if (degree > 2) {
|
||||
OPM_THROW(std::runtime_error, "CellQuadrature exact for polynomial degrees > 1 not implemented.");
|
||||
}
|
||||
}
|
||||
|
||||
int numQuadPts() const
|
||||
{
|
||||
if (degree_ < 2 || grid_.dimensions == 1) {
|
||||
return 1;
|
||||
}
|
||||
// Degree 2 case.
|
||||
if (grid_.dimensions == 2) {
|
||||
return 3*(grid_.cell_facepos[cell_ + 1] - grid_.cell_facepos[cell_]);
|
||||
}
|
||||
assert(grid_.dimensions == 3);
|
||||
int sumnodes = 0;
|
||||
for (int hf = grid_.cell_facepos[cell_]; hf < grid_.cell_facepos[cell_ + 1]; ++hf) {
|
||||
const int face = grid_.cell_faces[hf];
|
||||
sumnodes += grid_.face_nodepos[face + 1] - grid_.face_nodepos[face];
|
||||
}
|
||||
return 4*sumnodes;
|
||||
}
|
||||
|
||||
void quadPtCoord(const int index, double* coord) const
|
||||
{
|
||||
const int dim = grid_.dimensions;
|
||||
const double* cc = grid_.cell_centroids + dim*cell_;
|
||||
if (degree_ < 2) {
|
||||
std::copy(cc, cc + dim, coord);
|
||||
return;
|
||||
}
|
||||
// Degree 2 case.
|
||||
if (dim == 2) {
|
||||
if (index % 3 == 0) {
|
||||
// Boundary midpoint. This is the face centroid.
|
||||
const int hface = grid_.cell_facepos[cell_] + index/3;
|
||||
const int face = grid_.cell_faces[hface];
|
||||
const double* fc = grid_.face_centroids + dim*face;
|
||||
std::copy(fc, fc + dim, coord);
|
||||
} else {
|
||||
// Interiour midpoint. This is the average of the
|
||||
// cell centroid and a face node (they should
|
||||
// always have two nodes in 2d).
|
||||
const int hface = grid_.cell_facepos[cell_] + index/3;
|
||||
const int face = grid_.cell_faces[hface];
|
||||
const int nodeoff = (index % 3) - 1; // == 0 or 1
|
||||
const int node = grid_.face_nodes[grid_.face_nodepos[face] + nodeoff];
|
||||
const double* nc = grid_.node_coordinates + dim*node;
|
||||
for (int dd = 0; dd < dim; ++dd) {
|
||||
coord[dd] = 0.5*(nc[dd] + cc[dd]);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
assert(dim == 3);
|
||||
int tetindex = index / 4;
|
||||
const int subindex = index % 4;
|
||||
const double* nc = grid_.node_coordinates;
|
||||
for (int hf = grid_.cell_facepos[cell_]; hf < grid_.cell_facepos[cell_ + 1]; ++hf) {
|
||||
const int face = grid_.cell_faces[hf];
|
||||
const int nfn = grid_.face_nodepos[face + 1] - grid_.face_nodepos[face];
|
||||
if (nfn <= tetindex) {
|
||||
// Our tet is not associated with this face.
|
||||
tetindex -= nfn;
|
||||
continue;
|
||||
}
|
||||
const double* fc = grid_.face_centroids + dim*face;
|
||||
const int* fnodes = grid_.face_nodes + grid_.face_nodepos[face];
|
||||
const int node0 = fnodes[tetindex];
|
||||
const int node1 = fnodes[(tetindex + 1) % nfn];
|
||||
const double* n0c = nc + dim*node0;
|
||||
const double* n1c = nc + dim*node1;
|
||||
const double a = 0.138196601125010515179541316563436;
|
||||
// Barycentric coordinates of our point in the tet.
|
||||
double baryc[4] = { a, a, a, a };
|
||||
baryc[subindex] = 1.0 - 3.0*a;
|
||||
for (int dd = 0; dd < dim; ++dd) {
|
||||
coord[dd] = baryc[0]*cc[dd] + baryc[1]*fc[dd] + baryc[2]*n0c[dd] + baryc[3]*n1c[dd];
|
||||
}
|
||||
return;
|
||||
}
|
||||
OPM_THROW(std::runtime_error, "Should never reach this point.");
|
||||
}
|
||||
|
||||
double quadPtWeight(const int index) const
|
||||
{
|
||||
if (degree_ < 2) {
|
||||
return grid_.cell_volumes[cell_];
|
||||
}
|
||||
// Degree 2 case.
|
||||
const int dim = grid_.dimensions;
|
||||
const double* cc = grid_.cell_centroids + dim*cell_;
|
||||
if (dim == 2) {
|
||||
const int hface = grid_.cell_facepos[cell_] + index/3;
|
||||
const int face = grid_.cell_faces[hface];
|
||||
const int* nptr = grid_.face_nodes + grid_.face_nodepos[face];
|
||||
const double* nc0 = grid_.node_coordinates + dim*nptr[0];
|
||||
const double* nc1 = grid_.node_coordinates + dim*nptr[1];
|
||||
return triangleArea2d(nc0, nc1, cc)/3.0;
|
||||
}
|
||||
assert(dim == 3);
|
||||
int tetindex = index / 4;
|
||||
const double* nc = grid_.node_coordinates;
|
||||
for (int hf = grid_.cell_facepos[cell_]; hf < grid_.cell_facepos[cell_ + 1]; ++hf) {
|
||||
const int face = grid_.cell_faces[hf];
|
||||
const int nfn = grid_.face_nodepos[face + 1] - grid_.face_nodepos[face];
|
||||
if (nfn <= tetindex) {
|
||||
// Our tet is not associated with this face.
|
||||
tetindex -= nfn;
|
||||
continue;
|
||||
}
|
||||
const double* fc = grid_.face_centroids + dim*face;
|
||||
const int* fnodes = grid_.face_nodes + grid_.face_nodepos[face];
|
||||
const int node0 = fnodes[tetindex];
|
||||
const int node1 = fnodes[(tetindex + 1) % nfn];
|
||||
const double* n0c = nc + dim*node0;
|
||||
const double* n1c = nc + dim*node1;
|
||||
return 0.25*tetVolume(cc, fc, n0c, n1c);
|
||||
}
|
||||
OPM_THROW(std::runtime_error, "Should never reach this point.");
|
||||
}
|
||||
|
||||
private:
|
||||
const UnstructuredGrid& grid_;
|
||||
const int cell_;
|
||||
const int degree_;
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif // OPM_CELLQUADRATURE_HEADER_INCLUDED
|
|
@ -1,122 +0,0 @@
|
|||
#include <opm/core/grid.h>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
|
||||
namespace Opm {
|
||||
|
||||
namespace {
|
||||
|
||||
/// Helper struct for extractColumn
|
||||
/// Compares the underlying k-index
|
||||
struct ExtractColumnCompare
|
||||
{
|
||||
ExtractColumnCompare(const UnstructuredGrid& g)
|
||||
: grid(g)
|
||||
{
|
||||
// empty
|
||||
}
|
||||
|
||||
bool operator()(const int i, const int j)
|
||||
{
|
||||
// Extract k-index
|
||||
int index_i = grid.global_cell ? grid.global_cell[i] : i;
|
||||
int k_i = index_i / grid.cartdims[0] / grid.cartdims[1];
|
||||
int index_j = grid.global_cell ? grid.global_cell[j] : j;
|
||||
int k_j = index_j / grid.cartdims[0] / grid.cartdims[1];
|
||||
|
||||
return k_i < k_j;
|
||||
}
|
||||
|
||||
const UnstructuredGrid& grid;
|
||||
};
|
||||
|
||||
|
||||
/// Neighbourhood query.
|
||||
/// \return true if two cells are neighbours.
|
||||
bool neighbours(const UnstructuredGrid& grid, const int c0, const int c1)
|
||||
{
|
||||
for (int hf = grid.cell_facepos[c0]; hf < grid.cell_facepos[c0 + 1]; ++hf) {
|
||||
const int f = grid.cell_faces[hf];
|
||||
if (grid.face_cells[2*f] == c1 || grid.face_cells[2*f+1] == c1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
/// Extract each column of the grid.
|
||||
/// \note Assumes the pillars of the grid are all vertically aligned.
|
||||
/// \param grid The grid from which to extract the columns.
|
||||
/// \param columns will for each (i, j) where (i, j) represents a non-empty column,
|
||||
//// contain the cell indices contained in the column
|
||||
/// centered at (i, j) in the second variable, and i+jN in the first variable.
|
||||
inline void extractColumn( const UnstructuredGrid& grid, std::vector<std::vector<int> >& columns )
|
||||
{
|
||||
const int* dims = grid.cartdims;
|
||||
|
||||
// Keeps track of column_index ---> index of vector
|
||||
std::map<int, int> global_to_local;
|
||||
for (int cell = 0; cell < grid.number_of_cells; ++cell) {
|
||||
// Extract Cartesian coordinates
|
||||
int index = grid.global_cell ? grid.global_cell[cell] : cell; // If null, assume mapping is identity.
|
||||
int i_cart = index % dims[0];
|
||||
int k_cart = index / dims[0] / dims[1];
|
||||
int j_cart = (index - k_cart*dims[0]*dims[1])/ dims[0];
|
||||
|
||||
int local_index;
|
||||
std::map<int, int>::iterator local_index_iterator = global_to_local.find(i_cart+j_cart*dims[0]);
|
||||
if (local_index_iterator != global_to_local.end()) {
|
||||
local_index = local_index_iterator->second;
|
||||
} else {
|
||||
local_index = columns.size();
|
||||
global_to_local[i_cart+j_cart*dims[0]] = local_index;
|
||||
columns.push_back(std::vector<int>());
|
||||
}
|
||||
columns[local_index].push_back(cell);
|
||||
}
|
||||
|
||||
int num_cols = columns.size();
|
||||
for (int col = 0; col < num_cols; ++col) {
|
||||
std::sort(columns[col].begin(), columns[col].end(), ExtractColumnCompare(grid));
|
||||
}
|
||||
|
||||
// At this point, a column may contain multiple disjoint sets of cells.
|
||||
// We must split these columns into connected parts.
|
||||
std::vector< std::vector<int> > new_columns;
|
||||
for (int col = 0; col < num_cols; ++col) {
|
||||
const int colsz = columns[col].size();
|
||||
int first_of_col = 0;
|
||||
for (int k = 1; k < colsz; ++k) {
|
||||
const int c0 = columns[col][k-1];
|
||||
const int c1 = columns[col][k];
|
||||
if (!neighbours(grid, c0, c1)) {
|
||||
// Must split. Move the cells [first_of_col, ... , k-1] to
|
||||
// a new column, known to be connected.
|
||||
new_columns.push_back(std::vector<int>());
|
||||
new_columns.back().assign(columns[col].begin() + first_of_col, columns[col].begin() + k);
|
||||
// The working column now starts with index k.
|
||||
first_of_col = k;
|
||||
}
|
||||
}
|
||||
if (first_of_col != 0) {
|
||||
// The column was split, the working part should be
|
||||
// the entire column. We erase the cells before first_of_col.
|
||||
// (Could be more efficient if we instead chop off end.)
|
||||
columns[col].erase(columns[col].begin(), columns[col].begin() + first_of_col);
|
||||
}
|
||||
}
|
||||
|
||||
// Must tack on the new columns to complete the set.
|
||||
const int num_cols_all = num_cols + new_columns.size();
|
||||
columns.resize(num_cols_all);
|
||||
for (int col = num_cols; col < num_cols_all; ++col) {
|
||||
columns[col].swap(new_columns[col - num_cols]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} // namespace Opm
|
|
@ -1,189 +0,0 @@
|
|||
/*
|
||||
Copyright 2012 SINTEF ICT, Applied Mathematics.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef OPM_FACEQUADRATURE_HEADER_INCLUDED
|
||||
#define OPM_FACEQUADRATURE_HEADER_INCLUDED
|
||||
|
||||
#include <opm/common/ErrorMacros.hpp>
|
||||
#include <opm/core/grid.h>
|
||||
#include <cmath>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
|
||||
namespace {
|
||||
/// Calculates the cross product of two 3-vectors, represented as
|
||||
/// 3-element arrays. Calculates res = a X b. The res array must
|
||||
/// already be allocated with room for 3 elements.
|
||||
inline void cross(const double* a, const double* b, double* res)
|
||||
{
|
||||
res[0] = a[1]*b[2] - a[2]*b[1];
|
||||
res[1] = a[2]*b[0] - a[0]*b[2];
|
||||
res[2] = a[0]*b[1] - a[1]*b[0];
|
||||
}
|
||||
|
||||
/// Calculates the area of a triangle consisting of 3 vertices
|
||||
/// with 3-dimensional coordinates
|
||||
inline double triangleArea3d(const double* p0,
|
||||
const double* p1,
|
||||
const double* p2)
|
||||
{
|
||||
double a[3] = { p1[0] - p0[0], p1[1] - p0[1], p1[2] - p0[2] };
|
||||
double b[3] = { p2[0] - p0[0], p2[1] - p0[1], p2[2] - p0[2] };
|
||||
double cr[3];
|
||||
cross(a, b, cr);
|
||||
return 0.5*std::sqrt(cr[0]*cr[0] + cr[1]*cr[1] + cr[2]*cr[2]);
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
/// A class providing numerical quadrature for faces.
|
||||
/// In general: \int_{face} g(x) dx = \sum_{i=0}^{n-1} w_i g(x_i).
|
||||
/// Note that this class does multiply weights by face area,
|
||||
/// so weights always sum to face area.
|
||||
///
|
||||
/// Degree 1 method:
|
||||
/// Midpoint (centroid) method.
|
||||
/// n = 1, w_0 = face area, x_0 = face centroid
|
||||
///
|
||||
/// Degree 2 method for 2d:
|
||||
/// Simpson's method (actually this is degree 3).
|
||||
///
|
||||
/// Degree 2 method for 3d:
|
||||
/// Based on subdivision of the face into triangles,
|
||||
/// with the centroid as a common vertex, and the triangle
|
||||
/// edge midpoint rule.
|
||||
/// Triangle i consists of the centroid C, nodes N_i and N_{i+1}.
|
||||
/// Its area is A_i.
|
||||
/// n = 2 * nn (nn = num nodes in face)
|
||||
/// For i = 0..(nn-1):
|
||||
/// w_i = 1/3 A_i.
|
||||
/// w_{nn+i} = 1/3 A_{i-1} + 1/3 A_i
|
||||
/// x_i = (N_i + N_{i+1})/2
|
||||
/// x_{nn+i} = (C + N_i)/2
|
||||
/// All N and A indices are interpreted cyclic, modulus nn.
|
||||
class FaceQuadrature
|
||||
{
|
||||
public:
|
||||
FaceQuadrature(const UnstructuredGrid& grid,
|
||||
const int face,
|
||||
const int degree)
|
||||
: grid_(grid), face_(face), degree_(degree)
|
||||
{
|
||||
if (grid_.dimensions > 3) {
|
||||
OPM_THROW(std::runtime_error, "FaceQuadrature only implemented for up to 3 dimensions.");
|
||||
}
|
||||
if (degree_ > 2) {
|
||||
OPM_THROW(std::runtime_error, "FaceQuadrature exact for polynomial degrees > 2 not implemented.");
|
||||
}
|
||||
}
|
||||
|
||||
int numQuadPts() const
|
||||
{
|
||||
if (degree_ < 2 || grid_.dimensions < 2) {
|
||||
return 1;
|
||||
}
|
||||
// Degree 2 case.
|
||||
if (grid_.dimensions == 2) {
|
||||
return 3;
|
||||
} else {
|
||||
return 2 * (grid_.face_nodepos[face_ + 1] - grid_.face_nodepos[face_]);
|
||||
}
|
||||
}
|
||||
|
||||
void quadPtCoord(const int index, double* coord) const
|
||||
{
|
||||
const int dim = grid_.dimensions;
|
||||
const double* fc = grid_.face_centroids + dim*face_;
|
||||
if (degree_ < 2 || dim < 2) {
|
||||
std::copy(fc, fc + dim, coord);
|
||||
return;
|
||||
}
|
||||
// Degree 2 case.
|
||||
const int nn = grid_.face_nodepos[face_ + 1] - grid_.face_nodepos[face_];
|
||||
const int* fnodes = grid_.face_nodes + grid_.face_nodepos[face_];
|
||||
const double* nc = grid_.node_coordinates;
|
||||
if (dim == 2) {
|
||||
assert(nn == 2);
|
||||
const double* pa[3] = { nc + dim*fnodes[0], fc, nc + dim*fnodes[1] };
|
||||
std::copy(pa[index], pa[index] + dim, coord);
|
||||
return;
|
||||
}
|
||||
assert(dim == 3);
|
||||
if (index < nn) {
|
||||
// Boundary edge midpoint.
|
||||
const int node0 = fnodes[index];
|
||||
const int node1 = fnodes[(index + 1)%nn];
|
||||
for (int dd = 0; dd < dim; ++dd) {
|
||||
coord[dd] = 0.5*(nc[dim*node0 + dd] + nc[dim*node1 + dd]);
|
||||
}
|
||||
} else {
|
||||
// Interiour edge midpoint.
|
||||
// Recall that index is now in [nn, 2*nn).
|
||||
const int node = fnodes[index - nn];
|
||||
for (int dd = 0; dd < dim; ++dd) {
|
||||
coord[dd] = 0.5*(nc[dim*node + dd] + fc[dd]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double quadPtWeight(const int index) const
|
||||
{
|
||||
if (degree_ < 2) {
|
||||
return grid_.face_areas[face_];
|
||||
}
|
||||
// Degree 2 case.
|
||||
const int dim = grid_.dimensions;
|
||||
if (dim == 2) {
|
||||
const double simpsonw[3] = { 1.0/6.0, 4.0/6.0, 1.0/6.0 };
|
||||
return grid_.face_areas[face_]*simpsonw[index];
|
||||
}
|
||||
assert(dim == 3);
|
||||
const double* fc = grid_.face_centroids + dim*face_;
|
||||
const int nn = grid_.face_nodepos[face_ + 1] - grid_.face_nodepos[face_];
|
||||
const int* fnodes = grid_.face_nodes + grid_.face_nodepos[face_];
|
||||
const double* nc = grid_.node_coordinates;
|
||||
if (index < nn) {
|
||||
// Boundary edge midpoint.
|
||||
const int node0 = fnodes[index];
|
||||
const int node1 = fnodes[(index + 1)%nn];
|
||||
const double area = triangleArea3d(nc + dim*node1, nc + dim*node0, fc);
|
||||
return area / 3.0;
|
||||
} else {
|
||||
// Interiour edge midpoint.
|
||||
// Recall that index is now in [nn, 2*nn).
|
||||
const int node0 = fnodes[(index - 1) % nn];
|
||||
const int node1 = fnodes[index - nn];
|
||||
const int node2 = fnodes[(index + 1) % nn];
|
||||
const double area0 = triangleArea3d(nc + dim*node1, nc + dim*node0, fc);
|
||||
const double area1 = triangleArea3d(nc + dim*node2, nc + dim*node1, fc);
|
||||
return (area0 + area1) / 3.0;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const UnstructuredGrid& grid_;
|
||||
const int face_;
|
||||
const int degree_;
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif // OPM_FACEQUADRATURE_HEADER_INCLUDED
|
|
@ -1,177 +0,0 @@
|
|||
/*
|
||||
Copyright 2014, 2015 Dr. Markus Blatt - HPC-Simulation-Software & Services.
|
||||
Copyright 2014 Statoil AS
|
||||
Copyright 2015 NTNU
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "config.h"
|
||||
#include <opm/core/grid/GridHelpers.hpp>
|
||||
namespace Opm
|
||||
{
|
||||
namespace UgGridHelpers
|
||||
{
|
||||
int numCells(const UnstructuredGrid& grid)
|
||||
{
|
||||
return grid.number_of_cells;
|
||||
}
|
||||
|
||||
int numFaces(const UnstructuredGrid& grid)
|
||||
{
|
||||
return grid.number_of_faces;
|
||||
}
|
||||
int dimensions(const UnstructuredGrid& grid)
|
||||
{
|
||||
return grid.dimensions;
|
||||
}
|
||||
int numCellFaces(const UnstructuredGrid& grid)
|
||||
{
|
||||
return grid.cell_facepos[grid.number_of_cells];
|
||||
}
|
||||
|
||||
const int* globalCell(const UnstructuredGrid& grid)
|
||||
{
|
||||
return grid.global_cell;
|
||||
}
|
||||
|
||||
const int* cartDims(const UnstructuredGrid& grid)
|
||||
{
|
||||
return grid.cartdims;
|
||||
}
|
||||
|
||||
const double* beginCellCentroids(const UnstructuredGrid& grid)
|
||||
{
|
||||
return grid.cell_centroids;
|
||||
}
|
||||
|
||||
double cellCenterDepth(const UnstructuredGrid& grid, int cell_index)
|
||||
{
|
||||
// This method is an alternative to the method cellCentroidCoordinate(...) below.
|
||||
// The cell center depth is computed as a raw average of cell corner depths.
|
||||
// For cornerpoint grids, this is likely to give slightly different depths that seem
|
||||
// to agree with eclipse.
|
||||
assert(grid.dimensions == 3);
|
||||
const int nd = 3; // Assuming 3-dimensional grid ...
|
||||
const int nv = 8; // Assuming 2*4 vertices ...
|
||||
double zz = 0.0;
|
||||
// Traverse the bottom and top cell-face
|
||||
for (int i=grid.cell_facepos[cell_index+1]-2; i<grid.cell_facepos[cell_index+1]; ++i) {
|
||||
// Traverse the vertices associated with each face
|
||||
assert(grid.face_nodepos[grid.cell_faces[i]+1] - grid.face_nodepos[grid.cell_faces[i]] == nv/2);
|
||||
for (int j=grid.face_nodepos[grid.cell_faces[i]]; j<grid.face_nodepos[grid.cell_faces[i]+1]; ++j) {
|
||||
zz += (grid.node_coordinates+nd*(grid.face_nodes[j]))[nd-1];
|
||||
}
|
||||
}
|
||||
return zz/nv;
|
||||
}
|
||||
|
||||
double cellCentroidCoordinate(const UnstructuredGrid& grid, int cell_index,
|
||||
int coordinate)
|
||||
{
|
||||
return grid.cell_centroids[grid.dimensions*cell_index+coordinate];
|
||||
}
|
||||
|
||||
const double*
|
||||
cellCentroid(const UnstructuredGrid& grid, int cell_index)
|
||||
{
|
||||
return grid.cell_centroids+(cell_index*grid.dimensions);
|
||||
}
|
||||
|
||||
const double* beginCellVolumes(const UnstructuredGrid& grid)
|
||||
{
|
||||
return grid.cell_volumes;
|
||||
}
|
||||
const double* endCellVolumes(const UnstructuredGrid& grid)
|
||||
{
|
||||
return grid.cell_volumes+numCells(grid);
|
||||
}
|
||||
|
||||
const double* beginFaceCentroids(const UnstructuredGrid& grid)
|
||||
{
|
||||
return grid.face_centroids;
|
||||
}
|
||||
|
||||
const double* faceCentroid(const UnstructuredGrid& grid, int face_index)
|
||||
{
|
||||
return grid.face_centroids+face_index*grid.dimensions;
|
||||
}
|
||||
|
||||
const double* faceNormal(const UnstructuredGrid& grid, int face_index)
|
||||
{
|
||||
return grid.face_normals+face_index*grid.dimensions;
|
||||
}
|
||||
|
||||
double faceArea(const UnstructuredGrid& grid, int face_index)
|
||||
{
|
||||
return grid.face_areas[face_index];
|
||||
}
|
||||
|
||||
int faceTag(const UnstructuredGrid& grid,
|
||||
boost::iterator_range<const int*>::const_iterator face)
|
||||
{
|
||||
return grid.cell_facetag[face-cell2Faces(grid)[0].begin()];
|
||||
}
|
||||
|
||||
SparseTableView cell2Faces(const UnstructuredGrid& grid)
|
||||
{
|
||||
return SparseTableView(grid.cell_faces, grid.cell_facepos, numCells(grid));
|
||||
}
|
||||
|
||||
SparseTableView face2Vertices(const UnstructuredGrid& grid)
|
||||
{
|
||||
return SparseTableView(grid.face_nodes, grid.face_nodepos, numFaces(grid));
|
||||
}
|
||||
|
||||
const double* vertexCoordinates(const UnstructuredGrid& grid, int index)
|
||||
{
|
||||
return grid.node_coordinates+dimensions(grid)*index;
|
||||
}
|
||||
|
||||
double cellVolume(const UnstructuredGrid& grid, int cell_index)
|
||||
{
|
||||
return grid.cell_volumes[cell_index];
|
||||
}
|
||||
|
||||
FaceCellTraits<UnstructuredGrid>::Type faceCells(const UnstructuredGrid& grid)
|
||||
{
|
||||
return FaceCellsProxy(grid);
|
||||
}
|
||||
|
||||
|
||||
Opm::EclipseGrid createEclipseGrid(const UnstructuredGrid& grid, const Opm::EclipseGrid& inputGrid ) {
|
||||
const int * dims = UgGridHelpers::cartDims( grid );
|
||||
|
||||
if ((inputGrid.getNX( ) == static_cast<size_t>(dims[0])) &&
|
||||
(inputGrid.getNY( ) == static_cast<size_t>(dims[1])) &&
|
||||
(inputGrid.getNZ( ) == static_cast<size_t>(dims[2]))) {
|
||||
std::vector<int> updatedACTNUM;
|
||||
const int* global_cell = UgGridHelpers::globalCell( grid );
|
||||
|
||||
if (global_cell) {
|
||||
updatedACTNUM.assign( inputGrid.getCartesianSize( ) , 0 );
|
||||
for (int c = 0; c < numCells( grid ); c++) {
|
||||
updatedACTNUM[global_cell[c]] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return Opm::EclipseGrid( inputGrid, grid.zcorn, updatedACTNUM );
|
||||
} else {
|
||||
throw std::invalid_argument("Size mismatch - dimensions of inputGrid argument and current UnstructuredGrid instance disagree");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,381 +0,0 @@
|
|||
/*
|
||||
Copyright 2014, 2015 Dr. Markus Blatt - HPC-Simulation-Software & Services
|
||||
Copyright 2014 Statoil AS
|
||||
Copyright 2015
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef OPM_CORE_GRIDHELPERS_HEADER_INCLUDED
|
||||
#define OPM_CORE_GRIDHELPERS_HEADER_INCLUDED
|
||||
|
||||
#include <opm/core/grid.h>
|
||||
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
|
||||
|
||||
#include <opm/common/utility/platform_dependent/disable_warnings.h>
|
||||
#include <boost/range/iterator_range.hpp>
|
||||
#include <opm/common/utility/platform_dependent/reenable_warnings.h>
|
||||
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
namespace UgGridHelpers
|
||||
{
|
||||
|
||||
/// \brief Allows viewing a sparse table consisting out of C-array
|
||||
///
|
||||
/// This class can be used to convert two int array (like they are
|
||||
/// in UnstructuredGrid for representing the cell to faces mapping
|
||||
/// as a sparse table object.
|
||||
class SparseTableView
|
||||
{
|
||||
public:
|
||||
class IntRange : public boost::iterator_range<const int*>
|
||||
{
|
||||
public:
|
||||
typedef boost::iterator_range<const int*> BaseRowType;
|
||||
typedef BaseRowType::size_type size_type;
|
||||
typedef int value_type;
|
||||
|
||||
IntRange(const int* start_arg, const int* end_arg)
|
||||
: BaseRowType(start_arg, end_arg)
|
||||
{}
|
||||
};
|
||||
/// \brief The type of the roww.
|
||||
typedef boost::iterator_range<const int*> row_type;
|
||||
|
||||
/// \brief Creates a sparse table view
|
||||
/// \param data The array with data of the table.
|
||||
/// \param offset The offsets of the rows. Row i starts
|
||||
/// at offset[i] and ends a offset[i+1]
|
||||
/// \param size The number of entries/rows of the table
|
||||
SparseTableView(int* data, int *offset, std::size_t size_arg)
|
||||
: data_(data), offset_(offset), size_(size_arg)
|
||||
{}
|
||||
|
||||
/// \brief Get a row of the the table.
|
||||
/// \param row The row index.
|
||||
/// \return The corresponding row.
|
||||
row_type operator[](std::size_t row) const
|
||||
{
|
||||
assert(row<=size());
|
||||
return row_type(data_ + offset_[row], data_ + offset_[row+1]);
|
||||
}
|
||||
|
||||
/// \brief Get the size of the table.
|
||||
/// \return the number rows.
|
||||
std::size_t size() const
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
|
||||
/// \brief Get the number of non-zero entries.
|
||||
std::size_t noEntries() const
|
||||
{
|
||||
return offset_[size_];
|
||||
}
|
||||
|
||||
private:
|
||||
/// \brief The array with data of the table.
|
||||
const int* data_;
|
||||
/// \brief offset The offsets of the rows.
|
||||
///
|
||||
/// Row i starts at offset[i] and ends a offset[i+1]
|
||||
const int* offset_;
|
||||
/// \brief The size, i.e. the number of rows.
|
||||
std::size_t size_;
|
||||
};
|
||||
|
||||
/// \brief Get the number of cells of a grid.
|
||||
int numCells(const UnstructuredGrid& grid);
|
||||
|
||||
/// \brief Get the number of faces of a grid.
|
||||
int numFaces(const UnstructuredGrid& grid);
|
||||
|
||||
/// \brief Get the dimensions of a grid
|
||||
int dimensions(const UnstructuredGrid& grid);
|
||||
|
||||
/// \brief Get the number of faces, where each face counts as many times as there are adjacent faces
|
||||
int numCellFaces(const UnstructuredGrid& grid);
|
||||
|
||||
/// \brief Get the cartesion dimension of the underlying structured grid.
|
||||
const int* cartDims(const UnstructuredGrid& grid);
|
||||
|
||||
/// \brief Get the local to global index mapping.
|
||||
///
|
||||
/// The global index is the index of the active cell
|
||||
/// in the underlying structured grid.
|
||||
const int* globalCell(const UnstructuredGrid& grid);
|
||||
|
||||
/// \brief Traits of the cell centroids of a grid.
|
||||
///
|
||||
/// This class exports two types: IteratorType, the type of the iterator
|
||||
/// over the cell centroids, and the ValueTpe, the type of the cell centroid.
|
||||
/// \tpatam G The type of the grid.
|
||||
template<class G>
|
||||
struct CellCentroidTraits
|
||||
{
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CellCentroidTraits<UnstructuredGrid>
|
||||
{
|
||||
typedef const double* IteratorType;
|
||||
typedef const double* ValueType;
|
||||
};
|
||||
|
||||
/// \brief Get an iterator over the cell centroids positioned at the first cell.
|
||||
///
|
||||
/// The return type needs to be usable with the functions increment, and
|
||||
/// getCoordinate.
|
||||
CellCentroidTraits<UnstructuredGrid>::IteratorType
|
||||
beginCellCentroids(const UnstructuredGrid& grid);
|
||||
|
||||
|
||||
/// \brief Get vertical position of cell center ("zcorn" average.)
|
||||
/// \brief grid The grid.
|
||||
/// \brief cell_index The index of the specific cell.
|
||||
double cellCenterDepth(const UnstructuredGrid& grid, int cell_index);
|
||||
|
||||
|
||||
/// \brief Get a coordinate of a specific cell centroid.
|
||||
/// \brief grid The grid.
|
||||
/// \brief cell_index The index of the specific cell.
|
||||
/// \breif coordinate The coordinate index.
|
||||
double cellCentroidCoordinate(const UnstructuredGrid& grid, int cell_index,
|
||||
int coordinate);
|
||||
|
||||
|
||||
/// \brief Get the centroid of a cell.
|
||||
/// \param grid The grid whose cell centroid we query.
|
||||
/// \param cell_index The index of the corresponding cell.
|
||||
const double* cellCentroid(const UnstructuredGrid& grid, int cell_index);
|
||||
|
||||
|
||||
/// \brief Get the volume of a cell.
|
||||
/// \param grid The grid the cell belongs to.
|
||||
/// \param cell_index The index of the cell.
|
||||
double cellVolume(const UnstructuredGrid& grid, int cell_index);
|
||||
|
||||
/// \brief The mapping of the grid type to type of the iterator over
|
||||
/// the cell volumes.
|
||||
///
|
||||
/// The value of the mapping is stored in nested type IteratorType
|
||||
/// \tparam T The type of the grid.
|
||||
template<class T>
|
||||
struct CellVolumeIteratorTraits
|
||||
{
|
||||
};
|
||||
|
||||
template<>
|
||||
struct CellVolumeIteratorTraits<UnstructuredGrid>
|
||||
{
|
||||
typedef const double* IteratorType;
|
||||
};
|
||||
|
||||
/**
|
||||
Will create an EclipseGrid representation (i.e. based on
|
||||
ZCORN and COORD) of the current UnstructuredGrid
|
||||
instance. When creating the UnstructuredGrid the detailed
|
||||
cornerpoint information is discarded, and it is difficult
|
||||
to go backwards to recreated ZCORN and COORD.
|
||||
|
||||
The current implementation is based on retaining a copy of the
|
||||
zcorn keyword after the Minpvprocessor has modified it.
|
||||
|
||||
We then create a new EclipseGrid instance based on the original
|
||||
input grid, but we "replace" the ZCORN and ACTNUM keywords with
|
||||
the updated versions.
|
||||
|
||||
If the tolerance in the call to create_grid_cornerpoint( ) is
|
||||
finite the grid processing code might collapse cells, the z
|
||||
coordinate transformations from this process will *not* be
|
||||
correctly represented in the EclipseGrid created by this
|
||||
method.
|
||||
*/
|
||||
|
||||
/// \brief Construct an EclipseGrid instance based on the inputGrid, with modifications to
|
||||
/// zcorn and actnum from the dune UnstructuredGrid.
|
||||
Opm::EclipseGrid createEclipseGrid(const UnstructuredGrid& grid, const Opm::EclipseGrid& inputGrid );
|
||||
|
||||
/// \brief Get an iterator over the cell volumes of a grid positioned at the first cell.
|
||||
const double* beginCellVolumes(const UnstructuredGrid& grid);
|
||||
|
||||
/// \brief Get an iterator over the cell volumes of a grid positioned after the last cell.
|
||||
const double* endCellVolumes(const UnstructuredGrid& grid);
|
||||
|
||||
|
||||
|
||||
/// \brief Traits of the face centroids of a grid.
|
||||
///
|
||||
/// This class exports two types: IteratorType, the type of the iterator
|
||||
/// over the face centroids, and the ValueTpe, the type of the face centroid.
|
||||
/// \tpatam G The type of the grid.
|
||||
template<class G>
|
||||
struct FaceCentroidTraits
|
||||
{
|
||||
};
|
||||
|
||||
template<>
|
||||
struct FaceCentroidTraits<UnstructuredGrid>
|
||||
{
|
||||
typedef const double* IteratorType;
|
||||
typedef const double* ValueType;
|
||||
};
|
||||
|
||||
/// \brief Get an iterator over the face centroids positioned at the first cell.
|
||||
FaceCentroidTraits<UnstructuredGrid>::IteratorType
|
||||
beginFaceCentroids(const UnstructuredGrid& grid);
|
||||
|
||||
/// \brief Get a coordinate of a specific face centroid.
|
||||
/// \param grid The grid.
|
||||
/// \param face_index The index of the specific face.
|
||||
FaceCentroidTraits<UnstructuredGrid>::ValueType
|
||||
faceCentroid(const UnstructuredGrid& grid, int face_index);
|
||||
|
||||
/// \brief Get the normal of a face.
|
||||
/// \param grid The grid that the face is part of.
|
||||
/// \param face_index The index of the face in the grid.
|
||||
const double* faceNormal(const UnstructuredGrid& grid, int face_index);
|
||||
|
||||
/// \brief Get the area of a face
|
||||
/// \param grid The grid that the face is part of.
|
||||
/// \param face_index The index of the face in the grid.
|
||||
double faceArea(const UnstructuredGrid& grid, int face_index);
|
||||
|
||||
/// \brief Get Eclipse Cartesian tag of a face
|
||||
/// \param grid The grid that the face is part of.
|
||||
/// \param cell_face The face attached to a cell as obtained from cell2Faces()
|
||||
/// \return 0, 1, 2, 3, 4, 5 for I-, I+, J-, J+, K-, K+
|
||||
int faceTag(const UnstructuredGrid& grid, boost::iterator_range<const int*>::const_iterator cell_face);
|
||||
|
||||
/// \brief Maps the grid type to the associated type of the cell to faces mapping.
|
||||
///
|
||||
/// Provides a type named Type.
|
||||
/// \tparam T The type of the grid.
|
||||
template<class T>
|
||||
struct Cell2FacesTraits
|
||||
{
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Cell2FacesTraits<UnstructuredGrid>
|
||||
{
|
||||
typedef SparseTableView Type;
|
||||
};
|
||||
|
||||
/// \brief Maps the grid type to the associated type of the face to vertices mapping.
|
||||
///
|
||||
/// Provides a type named Type.
|
||||
/// \tparam T The type of the grid.
|
||||
template<class T>
|
||||
struct Face2VerticesTraits
|
||||
{
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Face2VerticesTraits<UnstructuredGrid>
|
||||
{
|
||||
typedef SparseTableView Type;
|
||||
};
|
||||
|
||||
/// \brief Get the cell to faces mapping of a grid.
|
||||
Cell2FacesTraits<UnstructuredGrid>::Type
|
||||
cell2Faces(const UnstructuredGrid& grid);
|
||||
|
||||
/// \brief Get the face to vertices mapping of a grid.
|
||||
Face2VerticesTraits<UnstructuredGrid>::Type
|
||||
face2Vertices(const UnstructuredGrid& grid);
|
||||
|
||||
/// \brief Get the coordinates of a vertex of the grid.
|
||||
/// \param grid The grid the vertex is part of.
|
||||
/// \param index The index identifying the vertex.
|
||||
const double* vertexCoordinates(const UnstructuredGrid& grid, int index);
|
||||
|
||||
class FaceCellsProxy
|
||||
{
|
||||
public:
|
||||
FaceCellsProxy(const UnstructuredGrid& grid)
|
||||
: face_cells_(grid.face_cells)
|
||||
{}
|
||||
int operator()(int face_index, int local_index) const
|
||||
{
|
||||
return face_cells_[2*face_index+local_index];
|
||||
}
|
||||
private:
|
||||
const int* face_cells_;
|
||||
};
|
||||
|
||||
/// \brief Traits of the face to attached cell mappping of a grid.
|
||||
///
|
||||
/// Exports the type Type, the type of the mapping
|
||||
/// \tparam T The type of the grid
|
||||
template<class T>
|
||||
struct FaceCellTraits
|
||||
{};
|
||||
|
||||
template<>
|
||||
struct FaceCellTraits<UnstructuredGrid>
|
||||
{
|
||||
typedef FaceCellsProxy Type;
|
||||
};
|
||||
|
||||
/// \brief Get the face to cell mapping of a grid.
|
||||
FaceCellTraits<UnstructuredGrid>::Type faceCells(const UnstructuredGrid& grid);
|
||||
|
||||
/// \brief Increment an iterator over an array that reresents a dense row-major
|
||||
/// matrix with dims columns
|
||||
/// \param cc The iterator.
|
||||
/// \param i The nzumber of rows to increment
|
||||
/// \param dim The number of columns of the matrix.
|
||||
template<class T>
|
||||
T* increment(T* cc, int i, int dim)
|
||||
{
|
||||
return cc+(i*dim);
|
||||
}
|
||||
/// \brief Increment an iterator over an array that reresents a dense row-major
|
||||
/// matrix with dims columns
|
||||
/// \param cc The iterator.
|
||||
/// \param i The nzumber of rows to increment
|
||||
template<class T>
|
||||
T increment(const T& t, int i, int)
|
||||
{
|
||||
return t+i;
|
||||
}
|
||||
|
||||
/// \brief Get the i-th corrdinate of a centroid.
|
||||
/// \param cc The array with the coordinates.
|
||||
/// \param i The index of the coordinate.
|
||||
/// \tparam T The type of the coordinate of the centroid.
|
||||
template<class T>
|
||||
double getCoordinate(T* cc, int i)
|
||||
{
|
||||
return cc[i];
|
||||
}
|
||||
|
||||
/// \brief Get the i-th corrdinate of an array.
|
||||
/// \param t The iterator over the centroids
|
||||
/// \brief i The index of the coordinate.
|
||||
/// \tparam T The type of the iterator representing the centroid.
|
||||
/// Its value_type has to provide an operator[] to access the coordinates.
|
||||
template<class T>
|
||||
double getCoordinate(T t, int i)
|
||||
{
|
||||
return (*t)[i];
|
||||
}
|
||||
|
||||
} // end namespace UGGridHelpers
|
||||
} // end namespace OPM
|
||||
#endif
|
|
@ -1,233 +0,0 @@
|
|||
/*
|
||||
Copyright 2012 SINTEF ICT, Applied Mathematics.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <opm/core/grid/GridHelpers.hpp>
|
||||
#include <opm/core/grid/GridManager.hpp>
|
||||
#include <opm/core/grid.h>
|
||||
#include <opm/core/grid/cart_grid.h>
|
||||
#include <opm/core/grid/cornerpoint_grid.h>
|
||||
#include <opm/core/grid/MinpvProcessor.hpp>
|
||||
#include <opm/common/ErrorMacros.hpp>
|
||||
#include <opm/parser/eclipse/Deck/DeckItem.hpp>
|
||||
#include <opm/parser/eclipse/Deck/DeckKeyword.hpp>
|
||||
#include <opm/parser/eclipse/Deck/DeckRecord.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/EclipseState.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
/// Construct a 3d corner-point grid from a deck.
|
||||
GridManager::GridManager(const Opm::EclipseGrid& inputGrid)
|
||||
: ug_(0)
|
||||
{
|
||||
initFromEclipseGrid(inputGrid, std::vector<double>());
|
||||
}
|
||||
|
||||
|
||||
GridManager::GridManager(const Opm::EclipseGrid& inputGrid,
|
||||
const std::vector<double>& poreVolumes)
|
||||
: ug_(0)
|
||||
{
|
||||
initFromEclipseGrid(inputGrid, poreVolumes);
|
||||
}
|
||||
|
||||
|
||||
/// Construct a 2d cartesian grid with cells of unit size.
|
||||
GridManager::GridManager(int nx, int ny)
|
||||
{
|
||||
ug_ = create_grid_cart2d(nx, ny, 1.0, 1.0);
|
||||
if (!ug_) {
|
||||
OPM_THROW(std::runtime_error, "Failed to construct grid.");
|
||||
}
|
||||
}
|
||||
|
||||
GridManager::GridManager(int nx, int ny,double dx, double dy)
|
||||
{
|
||||
ug_ = create_grid_cart2d(nx, ny, dx, dy);
|
||||
if (!ug_) {
|
||||
OPM_THROW(std::runtime_error, "Failed to construct grid.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// Construct a 3d cartesian grid with cells of unit size.
|
||||
GridManager::GridManager(int nx, int ny, int nz)
|
||||
{
|
||||
ug_ = create_grid_cart3d(nx, ny, nz);
|
||||
if (!ug_) {
|
||||
OPM_THROW(std::runtime_error, "Failed to construct grid.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// Construct a 3d cartesian grid with cells of size [dx, dy, dz].
|
||||
GridManager::GridManager(int nx, int ny, int nz,
|
||||
double dx, double dy, double dz)
|
||||
{
|
||||
ug_ = create_grid_hexa3d(nx, ny, nz, dx, dy, dz);
|
||||
if (!ug_) {
|
||||
OPM_THROW(std::runtime_error, "Failed to construct grid.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// Construct a grid from an input file.
|
||||
/// The file format used is currently undocumented,
|
||||
/// and is therefore only suited for internal use.
|
||||
GridManager::GridManager(const std::string& input_filename)
|
||||
{
|
||||
ug_ = read_grid(input_filename.c_str());
|
||||
if (!ug_) {
|
||||
OPM_THROW(std::runtime_error, "Failed to read grid from file " << input_filename);
|
||||
}
|
||||
}
|
||||
|
||||
/// Destructor.
|
||||
GridManager::~GridManager()
|
||||
{
|
||||
destroy_grid(ug_);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/// Access the managed UnstructuredGrid.
|
||||
/// The method is named similarly to c_str() in std::string,
|
||||
/// to make it clear that we are returning a C-compatible struct.
|
||||
const UnstructuredGrid* GridManager::c_grid() const
|
||||
{
|
||||
return ug_;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Construct corner-point grid from EclipseGrid.
|
||||
void GridManager::initFromEclipseGrid(const Opm::EclipseGrid& inputGrid,
|
||||
const std::vector<double>& poreVolumes)
|
||||
{
|
||||
struct grdecl g;
|
||||
int cells_modified = 0;
|
||||
std::vector<int> actnum;
|
||||
std::vector<double> coord;
|
||||
std::vector<double> zcorn;
|
||||
std::vector<double> mapaxes;
|
||||
|
||||
g.dims[0] = inputGrid.getNX();
|
||||
g.dims[1] = inputGrid.getNY();
|
||||
g.dims[2] = inputGrid.getNZ();
|
||||
|
||||
inputGrid.exportMAPAXES( mapaxes );
|
||||
inputGrid.exportCOORD( coord );
|
||||
inputGrid.exportZCORN( zcorn );
|
||||
inputGrid.exportACTNUM( actnum );
|
||||
|
||||
g.coord = coord.data();
|
||||
g.zcorn = zcorn.data();
|
||||
g.actnum = actnum.data();
|
||||
g.mapaxes = mapaxes.data();
|
||||
|
||||
if (!poreVolumes.empty() && (inputGrid.getMinpvMode() != MinpvMode::ModeEnum::Inactive)) {
|
||||
MinpvProcessor mp(g.dims[0], g.dims[1], g.dims[2]);
|
||||
const double minpv_value = inputGrid.getMinpvValue();
|
||||
// Currently the pinchProcessor is not used and only opmfil is supported
|
||||
//bool opmfil = inputGrid.getMinpvMode() == MinpvMode::OpmFIL;
|
||||
bool opmfil = true;
|
||||
cells_modified = mp.process(poreVolumes, minpv_value, actnum, opmfil, zcorn.data());
|
||||
}
|
||||
|
||||
const double z_tolerance = inputGrid.isPinchActive() ? inputGrid.getPinchThresholdThickness() : 0.0;
|
||||
ug_ = create_grid_cornerpoint(&g, z_tolerance);
|
||||
if (!ug_) {
|
||||
OPM_THROW(std::runtime_error, "Failed to construct grid.");
|
||||
}
|
||||
|
||||
if (cells_modified > 0) {
|
||||
attach_zcorn_copy( ug_ , zcorn.data() );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GridManager::createGrdecl(const Opm::Deck& deck, struct grdecl &grdecl)
|
||||
{
|
||||
// Extract data from deck.
|
||||
const std::vector<double>& zcorn = deck.getKeyword("ZCORN").getSIDoubleData();
|
||||
const std::vector<double>& coord = deck.getKeyword("COORD").getSIDoubleData();
|
||||
const int* actnum = NULL;
|
||||
if (deck.hasKeyword("ACTNUM")) {
|
||||
actnum = &(deck.getKeyword("ACTNUM").getIntData()[0]);
|
||||
}
|
||||
|
||||
std::array<int, 3> dims;
|
||||
if (deck.hasKeyword("DIMENS")) {
|
||||
const auto& dimensKeyword = deck.getKeyword("DIMENS");
|
||||
dims[0] = dimensKeyword.getRecord(0).getItem(0).get< int >(0);
|
||||
dims[1] = dimensKeyword.getRecord(0).getItem(1).get< int >(0);
|
||||
dims[2] = dimensKeyword.getRecord(0).getItem(2).get< int >(0);
|
||||
} else if (deck.hasKeyword("SPECGRID")) {
|
||||
const auto& specgridKeyword = deck.getKeyword("SPECGRID");
|
||||
dims[0] = specgridKeyword.getRecord(0).getItem(0).get< int >(0);
|
||||
dims[1] = specgridKeyword.getRecord(0).getItem(1).get< int >(0);
|
||||
dims[2] = specgridKeyword.getRecord(0).getItem(2).get< int >(0);
|
||||
} else {
|
||||
OPM_THROW(std::runtime_error, "Deck must have either DIMENS or SPECGRID.");
|
||||
}
|
||||
|
||||
// Collect in input struct for preprocessing.
|
||||
|
||||
grdecl.zcorn = &zcorn[0];
|
||||
grdecl.coord = &coord[0];
|
||||
grdecl.actnum = actnum;
|
||||
grdecl.dims[0] = dims[0];
|
||||
grdecl.dims[1] = dims[1];
|
||||
grdecl.dims[2] = dims[2];
|
||||
|
||||
if (deck.hasKeyword("MAPAXES")) {
|
||||
const auto& mapaxesKeyword = deck.getKeyword("MAPAXES");
|
||||
const auto& mapaxesRecord = mapaxesKeyword.getRecord(0);
|
||||
|
||||
// memleak alert: here we need to make sure that C code
|
||||
// can properly take ownership of the grdecl.mapaxes
|
||||
// object. if it is not freed, it will result in a
|
||||
// memleak...
|
||||
double *cWtfMapaxes = static_cast<double*>(malloc(sizeof(double)*mapaxesRecord.size()));
|
||||
for (unsigned i = 0; i < mapaxesRecord.size(); ++i)
|
||||
cWtfMapaxes[i] = mapaxesRecord.getItem(i).getSIDouble(0);
|
||||
grdecl.mapaxes = cWtfMapaxes;
|
||||
} else
|
||||
grdecl.mapaxes = NULL;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace Opm
|
|
@ -1,98 +0,0 @@
|
|||
/*
|
||||
Copyright 2012 SINTEF ICT, Applied Mathematics.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef OPM_GRIDMANAGER_HEADER_INCLUDED
|
||||
#define OPM_GRIDMANAGER_HEADER_INCLUDED
|
||||
|
||||
#include <opm/parser/eclipse/Deck/Deck.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Grid/EclipseGrid.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
struct UnstructuredGrid;
|
||||
struct grdecl;
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
/// This class manages an Opm::UnstructuredGrid in the sense that it
|
||||
/// encapsulates creation and destruction of the grid.
|
||||
/// The following grid types can be constructed:
|
||||
/// - 3d corner-point grids (from deck input)
|
||||
/// - 3d tensor grids (from deck input)
|
||||
/// - 2d cartesian grids
|
||||
/// - 3d cartesian grids
|
||||
/// The resulting UnstructuredGrid is available through the c_grid() method.
|
||||
class GridManager
|
||||
{
|
||||
public:
|
||||
/// Construct a grid from an EclipseState::EclipseGrid instance.
|
||||
explicit GridManager(const Opm::EclipseGrid& inputGrid);
|
||||
|
||||
/// Construct a grid from an EclipseState::EclipseGrid instance,
|
||||
/// giving an explicit set of pore volumes to be used for MINPV
|
||||
/// considerations.
|
||||
/// \input[in] eclipseGrid encapsulates a corner-point grid given from a deck
|
||||
/// \input[in] poreVolumes one element per logical cartesian grid element
|
||||
GridManager(const Opm::EclipseGrid& inputGrid,
|
||||
const std::vector<double>& poreVolumes);
|
||||
|
||||
/// Construct a 2d cartesian grid with cells of unit size.
|
||||
GridManager(int nx, int ny);
|
||||
|
||||
/// Construct a 2d cartesian grid with cells of size [dx, dy].
|
||||
GridManager(int nx, int ny, double dx, double dy);
|
||||
|
||||
/// Construct a 3d cartesian grid with cells of unit size.
|
||||
GridManager(int nx, int ny, int nz);
|
||||
|
||||
/// Construct a 3d cartesian grid with cells of size [dx, dy, dz].
|
||||
GridManager(int nx, int ny, int nz,
|
||||
double dx, double dy, double dz);
|
||||
|
||||
/// Construct a grid from an input file.
|
||||
/// The file format used is currently undocumented,
|
||||
/// and is therefore only suited for internal use.
|
||||
explicit GridManager(const std::string& input_filename);
|
||||
|
||||
/// Destructor.
|
||||
~GridManager();
|
||||
|
||||
/// Access the managed UnstructuredGrid.
|
||||
/// The method is named similarly to c_str() in std::string,
|
||||
/// to make it clear that we are returning a C-compatible struct.
|
||||
const UnstructuredGrid* c_grid() const;
|
||||
|
||||
static void createGrdecl(const Opm::Deck& deck, struct grdecl &grdecl);
|
||||
|
||||
private:
|
||||
// Disable copying and assignment.
|
||||
GridManager(const GridManager& other);
|
||||
GridManager& operator=(const GridManager& other);
|
||||
|
||||
// Construct corner-point grid from EclipseGrid.
|
||||
void initFromEclipseGrid(const Opm::EclipseGrid& inputGrid,
|
||||
const std::vector<double>& poreVolumes);
|
||||
|
||||
// The managed UnstructuredGrid.
|
||||
UnstructuredGrid* ug_;
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif // OPM_GRIDMANAGER_HEADER_INCLUDED
|
|
@ -1,133 +0,0 @@
|
|||
/*
|
||||
Copyright 2014 SINTEF ICT, Applied Mathematics.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <opm/core/grid/GridUtilities.hpp>
|
||||
#include <opm/core/grid/GridHelpers.hpp>
|
||||
|
||||
#include <opm/common/utility/platform_dependent/disable_warnings.h>
|
||||
#include <boost/math/constants/constants.hpp>
|
||||
#include <opm/common/utility/platform_dependent/reenable_warnings.h>
|
||||
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
/// For each cell, find indices of all other cells sharing a vertex with it.
|
||||
/// \param[in] grid A grid object.
|
||||
/// \return A table of neighbour cell-indices by cell.
|
||||
SparseTable<int> cellNeighboursAcrossVertices(const UnstructuredGrid& grid)
|
||||
{
|
||||
// 1. Create vertex->cell mapping. We do this by iterating
|
||||
// over all faces, and adding both its cell neighbours
|
||||
// to each of its vertices' data.
|
||||
using namespace UgGridHelpers;
|
||||
const int num_vertices = grid.number_of_nodes;
|
||||
std::vector<std::set<int>> v2c(num_vertices);
|
||||
const int num_faces = numFaces(grid);
|
||||
const auto fc = faceCells(grid);
|
||||
for (int face = 0; face < num_faces; ++face) {
|
||||
for (int nodepos = grid.face_nodepos[face]; nodepos < grid.face_nodepos[face + 1]; ++nodepos) {
|
||||
const int vertex = grid.face_nodes[nodepos];
|
||||
for (int face_nb = 0; face_nb < 2; ++face_nb) {
|
||||
const int face_nb_cell = fc(face, face_nb);
|
||||
if (face_nb_cell >= 0) {
|
||||
v2c[vertex].insert(face_nb_cell);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. For each cell, iterate over its faces, iterate over
|
||||
// their vertices, and collect all those vertices' cell
|
||||
// neighbours. Add as row to sparse table.
|
||||
SparseTable<int> cell_nb;
|
||||
const int num_cells = numCells(grid);
|
||||
const auto c2f = cell2Faces(grid);
|
||||
// Reserve sufficient room for cartesian grids in 2 and 3
|
||||
// dimensions. Note that this is not a limit, just an
|
||||
// optimization similar to std::vector.
|
||||
cell_nb.reserve(num_cells, (dimensions(grid) == 2 ? 8 : 26) * num_cells);
|
||||
std::set<int> nb;
|
||||
for (int cell = 0; cell < num_cells; ++cell) {
|
||||
nb.clear();
|
||||
const auto cell_faces = c2f[cell];
|
||||
const int num_cell_faces = cell_faces.size();
|
||||
for (int local_face = 0; local_face < num_cell_faces; ++local_face) {
|
||||
const int face = cell_faces[local_face];
|
||||
for (int nodepos = grid.face_nodepos[face]; nodepos < grid.face_nodepos[face + 1]; ++nodepos) {
|
||||
const int vertex = grid.face_nodes[nodepos];
|
||||
nb.insert(v2c[vertex].begin(), v2c[vertex].end());
|
||||
}
|
||||
}
|
||||
nb.erase(cell);
|
||||
cell_nb.appendRow(nb.begin(), nb.end());
|
||||
}
|
||||
|
||||
// 3. Done. Return.
|
||||
return cell_nb;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// For each cell, order the (cell) neighbours counterclockwise.
|
||||
/// \param[in] grid A 2d grid object.
|
||||
/// \param[in, out] nb A cell-cell neighbourhood table, such as from cellNeighboursAcrossVertices().
|
||||
void orderCounterClockwise(const UnstructuredGrid& grid,
|
||||
SparseTable<int>& nb)
|
||||
{
|
||||
if (grid.dimensions != 2) {
|
||||
OPM_THROW(std::logic_error, "Cannot use orderCounterClockwise in " << grid.dimensions << " dimensions.");
|
||||
}
|
||||
const int num_cells = grid.number_of_cells;
|
||||
if (nb.size() != num_cells) {
|
||||
OPM_THROW(std::logic_error, "Inconsistent arguments for orderCounterClockwise().");
|
||||
}
|
||||
|
||||
// For each cell, compute each neighbour's angle with the x axis,
|
||||
// sort that to find the correct permutation of the neighbours.
|
||||
typedef std::pair<double, int> AngleAndPos;
|
||||
std::vector<AngleAndPos> angle_and_pos;
|
||||
std::vector<int> original;
|
||||
for (int cell = 0; cell < num_cells; ++cell) {
|
||||
const int num_nb = nb[cell].size();
|
||||
angle_and_pos.clear();
|
||||
angle_and_pos.resize(num_nb);
|
||||
for (int ii = 0; ii < num_nb; ++ii) {
|
||||
const int cell2 = nb[cell][ii];
|
||||
const double v[2] = { grid.cell_centroids[2*cell2] - grid.cell_centroids[2*cell],
|
||||
grid.cell_centroids[2*cell2 + 1] - grid.cell_centroids[2*cell + 1] };
|
||||
// The formula below gives an angle in [0, 2*pi] with the positive x axis.
|
||||
const double angle = boost::math::constants::pi<double>() - std::atan2(v[1], -v[0]);
|
||||
angle_and_pos[ii] = std::make_pair(angle, ii);
|
||||
}
|
||||
original.assign(nb[cell].begin(), nb[cell].end());
|
||||
std::sort(angle_and_pos.begin(), angle_and_pos.end());
|
||||
for (int ii = 0; ii < num_nb; ++ii) {
|
||||
nb[cell][ii] = original[angle_and_pos[ii].second];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Opm
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
Copyright 2014 SINTEF ICT, Applied Mathematics.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef OPM_GRIDUTILITIES_HEADER_INCLUDED
|
||||
#define OPM_GRIDUTILITIES_HEADER_INCLUDED
|
||||
|
||||
#include <opm/core/grid.h>
|
||||
#include <opm/core/utility/SparseTable.hpp>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
/// For each cell, find indices of all cells sharing a vertex with it.
|
||||
/// \param[in] grid A grid object.
|
||||
/// \return A table of neighbour cell-indices by cell.
|
||||
SparseTable<int> cellNeighboursAcrossVertices(const UnstructuredGrid& grid);
|
||||
|
||||
/// For each cell, order the (cell) neighbours counterclockwise.
|
||||
/// \param[in] grid A 2d grid object.
|
||||
/// \param[in, out] nb A cell-cell neighbourhood table, such as from vertexNeighbours().
|
||||
void orderCounterClockwise(const UnstructuredGrid& grid,
|
||||
SparseTable<int>& nb);
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif // OPM_GRIDUTILITIES_HEADER_INCLUDED
|
|
@ -1,176 +0,0 @@
|
|||
/*
|
||||
Copyright 2014 SINTEF ICT, Applied Mathematics.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef OPM_MINPVPROCESSOR_HEADER_INCLUDED
|
||||
#define OPM_MINPVPROCESSOR_HEADER_INCLUDED
|
||||
|
||||
|
||||
#include <opm/common/ErrorMacros.hpp>
|
||||
#include <array>
|
||||
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
/// \brief Transform a corner-point grid ZCORN field to account for MINPV processing.
|
||||
class MinpvProcessor
|
||||
{
|
||||
public:
|
||||
/// \brief Create a processor.
|
||||
/// \param[in] nx logical cartesian number of cells in I-direction
|
||||
/// \param[in] ny logical cartesian number of cells in J-direction
|
||||
/// \param[in] nz logical cartesian number of cells in K-direction
|
||||
MinpvProcessor(const int nx, const int ny, const int nz);
|
||||
/// Change zcorn so that it respects the minpv property.
|
||||
/// \param[in] pv pore volumes of all logical cartesian cells
|
||||
/// \param[in] minpv minimum pore volume to accept a cell
|
||||
/// \param[in] actnum active cells, inactive cells are not considered
|
||||
/// \param[in] mergeMinPVCells flag to determine whether cells below minpv
|
||||
/// should be included in the cell below
|
||||
/// \param[in, out] zcorn ZCORN array to be manipulated
|
||||
/// After processing, all cells that have lower pore volume than minpv
|
||||
/// will have the zcorn numbers changed so they are zero-thickness. Any
|
||||
/// cell below will be changed to include the deleted volume if mergeMinPCCells is true
|
||||
/// els the volume will be lost
|
||||
int process(const std::vector<double>& pv,
|
||||
const double minpv,
|
||||
const std::vector<int>& actnum,
|
||||
const bool mergeMinPVCells,
|
||||
double* zcorn) const;
|
||||
private:
|
||||
std::array<int,8> cornerIndices(const int i, const int j, const int k) const;
|
||||
std::array<double, 8> getCellZcorn(const int i, const int j, const int k, const double* z) const;
|
||||
void setCellZcorn(const int i, const int j, const int k, const std::array<double, 8>& cellz, double* z) const;
|
||||
std::array<int, 3> dims_;
|
||||
std::array<int, 3> delta_;
|
||||
};
|
||||
|
||||
inline MinpvProcessor::MinpvProcessor(const int nx, const int ny, const int nz) :
|
||||
dims_( {nx,ny,nz} ),
|
||||
delta_( {1 , 2*nx , 4*nx*ny} )
|
||||
{ }
|
||||
|
||||
|
||||
|
||||
inline int MinpvProcessor::process(const std::vector<double>& pv,
|
||||
const double minpv,
|
||||
const std::vector<int>& actnum,
|
||||
const bool mergeMinPVCells,
|
||||
double* zcorn) const
|
||||
{
|
||||
// Algorithm:
|
||||
// 1. Process each column of cells (with same i and j
|
||||
// coordinates) from top (low k) to bottom (high k).
|
||||
// 2. For each cell 'c' visited, check if its pore volume
|
||||
// pv[c] is less than minpv.
|
||||
// 3. If below the minpv threshold, move the lower four
|
||||
// zcorn associated with the cell c to coincide with
|
||||
// the upper four (so it becomes degenerate). If mergeMinPVcells
|
||||
// is true, the higher four zcorn associated with the cell below
|
||||
// is moved to these values (so it gains the deleted volume).
|
||||
|
||||
int cells_modified = 0;
|
||||
|
||||
// Check for sane input sizes.
|
||||
const size_t log_size = dims_[0] * dims_[1] * dims_[2];
|
||||
if (pv.size() != log_size) {
|
||||
OPM_THROW(std::runtime_error, "Wrong size of PORV input, must have one element per logical cartesian cell.");
|
||||
}
|
||||
if (!actnum.empty() && actnum.size() != log_size) {
|
||||
OPM_THROW(std::runtime_error, "Wrong size of ACTNUM input, must have one element per logical cartesian cell.");
|
||||
}
|
||||
|
||||
// Main loop.
|
||||
for (int kk = 0; kk < dims_[2]; ++kk) {
|
||||
for (int jj = 0; jj < dims_[1]; ++jj) {
|
||||
for (int ii = 0; ii < dims_[0]; ++ii) {
|
||||
const int c = ii + dims_[0] * (jj + dims_[1] * kk);
|
||||
if (pv[c] < minpv && (actnum.empty() || actnum[c])) {
|
||||
// Move deeper (higher k) coordinates to lower k coordinates.
|
||||
std::array<double, 8> cz = getCellZcorn(ii, jj, kk, zcorn);
|
||||
for (int count = 0; count < 4; ++count) {
|
||||
cz[count + 4] = cz[count];
|
||||
}
|
||||
setCellZcorn(ii, jj, kk, cz, zcorn);
|
||||
|
||||
|
||||
// optionally add removed volume to the cell below.
|
||||
if (mergeMinPVCells) {
|
||||
// Check if there is a cell below.
|
||||
if (pv[c] > 0.0 && kk < dims_[2] - 1) {
|
||||
// Set lower k coordinates of cell below to upper cells's coordinates.
|
||||
std::array<double, 8> cz_below = getCellZcorn(ii, jj, kk + 1, zcorn);
|
||||
for (int count = 0; count < 4; ++count) {
|
||||
cz_below[count] = cz[count];
|
||||
}
|
||||
setCellZcorn(ii, jj, kk + 1, cz_below, zcorn);
|
||||
}
|
||||
}
|
||||
++cells_modified;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return cells_modified;
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline std::array<int,8> MinpvProcessor::cornerIndices(const int i, const int j, const int k) const
|
||||
{
|
||||
const int ix = 2*(i*delta_[0] + j*delta_[1] + k*delta_[2]);
|
||||
std::array<int, 8> ixs = {{ ix, ix + delta_[0],
|
||||
ix + delta_[1], ix + delta_[1] + delta_[0],
|
||||
ix + delta_[2], ix + delta_[2] + delta_[0],
|
||||
ix + delta_[2] + delta_[1], ix + delta_[2] + delta_[1] + delta_[0] }};
|
||||
|
||||
return ixs;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Returns the eight z-values associated with a given cell.
|
||||
// The ordering is such that i runs fastest. That is, with
|
||||
// L = low and H = high:
|
||||
// {LLL, HLL, LHL, HHL, LLH, HLH, LHH, HHH }.
|
||||
inline std::array<double, 8> MinpvProcessor::getCellZcorn(const int i, const int j, const int k, const double* z) const
|
||||
{
|
||||
const std::array<int, 8> ixs = cornerIndices(i, j, k);
|
||||
std::array<double, 8> cellz;
|
||||
for (int count = 0; count < 8; ++count) {
|
||||
cellz[count] = z[ixs[count]];
|
||||
}
|
||||
return cellz;
|
||||
}
|
||||
|
||||
|
||||
|
||||
inline void MinpvProcessor::setCellZcorn(const int i, const int j, const int k, const std::array<double, 8>& cellz, double* z) const
|
||||
{
|
||||
const std::array<int, 8> ixs = cornerIndices(i, j, k);
|
||||
for (int count = 0; count < 8; ++count) {
|
||||
z[ixs[count]] = cellz[count];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif // OPM_MINPVPROCESSOR_HEADER_INCLUDED
|
|
@ -1,488 +0,0 @@
|
|||
/*
|
||||
Copyright 2015 Statoil ASA.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef OPM_PINCHPROCESSOR_HEADER_INCLUDED
|
||||
#define OPM_PINCHPROCESSOR_HEADER_INCLUDED
|
||||
|
||||
#include <opm/common/ErrorMacros.hpp>
|
||||
#include <opm/core/grid/GridHelpers.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Grid/NNC.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Grid/FaceDir.hpp>
|
||||
#include <opm/parser/eclipse/EclipseState/Grid/PinchMode.hpp>
|
||||
#include <opm/parser/eclipse/Units/Units.hpp>
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
#include <limits>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
template <class Grid>
|
||||
class PinchProcessor
|
||||
{
|
||||
public:
|
||||
/// \brief Create a Pinch processor.
|
||||
/// \param[in] minpvValue value in MINPV keyword
|
||||
/// \param[in] thickness item 2 in PINCH keyword
|
||||
/// \param[in] transMode item 4 in PINCH keyword
|
||||
/// \param[in] multzMode item 5 in PINCH keyword
|
||||
PinchProcessor(const double minpvValue,
|
||||
const double thickness,
|
||||
const PinchMode::ModeEnum transMode,
|
||||
const PinchMode::ModeEnum multzMode);
|
||||
/// Generate NNCs for cells which pv is less than MINPV.
|
||||
/// \param[in] Grid cpgrid or unstructured grid
|
||||
/// \param[in] htrans half cell transmissibility, size is number of cellfaces.
|
||||
/// \param[in] multz Z+ transmissibility multiplier for all active cells
|
||||
/// \param[in] pv pore volume for all the cartesian cells
|
||||
/// \param[in] nnc non-neighbor connection class
|
||||
/// Algorithm:
|
||||
/// 1. Mark all the cells which pv less than minpvValue.
|
||||
/// 2. Find out proper pinchouts column and associate top and bottom cells.
|
||||
/// 3. Compute transmissibility for nncs.
|
||||
/// 4. Apply multz due to different multz options.
|
||||
void process(const Grid& grid,
|
||||
const std::vector<double>& htrans,
|
||||
const std::vector<int>& actnum,
|
||||
const std::vector<double>& multz,
|
||||
const std::vector<double>& pv,
|
||||
NNC& nnc);
|
||||
|
||||
private:
|
||||
double minpvValue_;
|
||||
double thickness_;
|
||||
PinchMode::ModeEnum transMode_;
|
||||
PinchMode::ModeEnum multzMode_;
|
||||
|
||||
/// Mark minpved cells.
|
||||
std::vector<int> getMinpvCells_(const std::vector<int>& actnum,
|
||||
const std::vector<double>& pv);
|
||||
|
||||
/// Get the interface for two cells.
|
||||
int interface_(const Grid& grid,
|
||||
const int cellIdx1,
|
||||
const int cellIdx2);
|
||||
|
||||
/// Get the proper face for one cell.
|
||||
int interface_(const Grid& grid,
|
||||
const int cellIdx,
|
||||
const Opm::FaceDir::DirEnum& faceDir);
|
||||
|
||||
/// Get pinchouts column.
|
||||
std::vector<std::vector<int> >
|
||||
getPinchoutsColumn_(const Grid& grid,
|
||||
const std::vector<int>& actnum,
|
||||
const std::vector<double>& pv);
|
||||
|
||||
/// Get global cell index.
|
||||
int getGlobalIndex_(const int i, const int j, const int k, const int* dims);
|
||||
|
||||
/// Get cartesian index.
|
||||
std::array<int, 3> getCartIndex_(const int idx,
|
||||
const int* dims);
|
||||
|
||||
/// Compute transmissibility for nnc.
|
||||
std::vector<double> transCompute_(const Grid& grid,
|
||||
const std::vector<double>& htrans,
|
||||
const std::vector<int>& pinCells,
|
||||
const std::vector<int>& pinFaces);
|
||||
|
||||
/// Get map between half-trans index and the pair of face index and cell index.
|
||||
std::vector<int> getHfIdxMap_(const Grid& grid);
|
||||
|
||||
/// Get active cell index.
|
||||
int getActiveCellIdx_(const Grid& grid,
|
||||
const int globalIdx);
|
||||
|
||||
/// Item 4 in PINCH keyword.
|
||||
void transTopbot_(const Grid& grid,
|
||||
const std::vector<double>& htrans,
|
||||
const std::vector<int>& actnum,
|
||||
const std::vector<double>& multz,
|
||||
const std::vector<double>& pv,
|
||||
NNC& nnc);
|
||||
|
||||
/// Item 5 in PINCH keyword.
|
||||
std::unordered_multimap<int, double> multzOptions_(const Grid& grid,
|
||||
const std::vector<int>& pinCells,
|
||||
const std::vector<int>& pinFaces,
|
||||
const std::vector<double>& multz,
|
||||
const std::vector<std::vector<int> >& seg);
|
||||
|
||||
/// Apply multz vector to face transmissibility.
|
||||
void applyMultz_(std::vector<double>& trans,
|
||||
const std::unordered_multimap<int, double>& multzmap);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
template <class Grid>
|
||||
inline PinchProcessor<Grid>::PinchProcessor(const double minpv,
|
||||
const double thickness,
|
||||
const PinchMode::ModeEnum transMode,
|
||||
const PinchMode::ModeEnum multzMode)
|
||||
{
|
||||
minpvValue_ = minpv;
|
||||
thickness_ = thickness;
|
||||
transMode_ = transMode;
|
||||
multzMode_ = multzMode;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <class Grid>
|
||||
inline int PinchProcessor<Grid>::getGlobalIndex_(const int i, const int j, const int k, const int* dims)
|
||||
{
|
||||
return i + dims[0] * (j + dims[1] * k);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <class Grid>
|
||||
inline std::array<int, 3> PinchProcessor<Grid>::getCartIndex_(const int idx,
|
||||
const int* dims)
|
||||
{
|
||||
std::array<int, 3> ijk;
|
||||
ijk[0] = (idx % dims[0]);
|
||||
ijk[1] = ((idx / dims[0]) % dims[1]);
|
||||
ijk[2] = ((idx / dims[0]) / dims[1]);
|
||||
|
||||
return ijk;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class Grid>
|
||||
inline int PinchProcessor<Grid>::interface_(const Grid& grid,
|
||||
const int cellIdx1,
|
||||
const int cellIdx2)
|
||||
{
|
||||
const auto cell_faces = Opm::UgGridHelpers::cell2Faces(grid);
|
||||
int commonFace = -1;
|
||||
const int actCellIdx1 = getActiveCellIdx_(grid, cellIdx1);
|
||||
const int actCellIdx2 = getActiveCellIdx_(grid, cellIdx2);
|
||||
const auto cellFacesRange1 = cell_faces[actCellIdx1];
|
||||
const auto cellFacesRange2 = cell_faces[actCellIdx2];
|
||||
for (const auto& f1 : cellFacesRange1) {
|
||||
for (const auto& f2 : cellFacesRange2) {
|
||||
if (f1 == f2) {
|
||||
commonFace = f1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (commonFace == -1) {
|
||||
const auto dims = Opm::UgGridHelpers::cartDims(grid);
|
||||
const auto ijk1 = getCartIndex_(cellIdx1, dims);
|
||||
const auto ijk2 = getCartIndex_(cellIdx2, dims);
|
||||
|
||||
OPM_THROW(std::logic_error, "Couldn't find the common face for cell "
|
||||
<< cellIdx1<< "("<<ijk1[0]<<","<<ijk1[1]<<","<<ijk1[2]<<")"
|
||||
<< " and " << cellIdx2<<"("<<ijk2[0]<<","<<ijk2[1]<<","<<ijk2[2]<<")");
|
||||
}
|
||||
|
||||
return commonFace;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class Grid>
|
||||
inline int PinchProcessor<Grid>::interface_(const Grid& grid,
|
||||
const int cellIdx,
|
||||
const Opm::FaceDir::DirEnum& faceDir)
|
||||
{
|
||||
const auto actCellIdx = getActiveCellIdx_(grid, cellIdx);
|
||||
const auto cell_faces = Opm::UgGridHelpers::cell2Faces(grid);
|
||||
const auto cellFacesRange = cell_faces[actCellIdx];
|
||||
int faceIdx = -1;
|
||||
for (auto cellFaceIter = cellFacesRange.begin(); cellFaceIter != cellFacesRange.end(); ++cellFaceIter) {
|
||||
int tag = Opm::UgGridHelpers::faceTag(grid, cellFaceIter);
|
||||
if ( (faceDir == Opm::FaceDir::ZMinus && tag == 4) || (faceDir == Opm::FaceDir::ZPlus && tag == 5) ) {
|
||||
faceIdx = *cellFaceIter;
|
||||
}
|
||||
}
|
||||
|
||||
if (faceIdx == -1) {
|
||||
OPM_THROW(std::logic_error, "Couldn't find the face for cell ." << cellIdx);
|
||||
}
|
||||
|
||||
return faceIdx;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class Grid>
|
||||
inline std::vector<int> PinchProcessor<Grid>::getMinpvCells_(const std::vector<int>& actnum,
|
||||
const std::vector<double>& pv)
|
||||
{
|
||||
std::vector<int> minpvCells(pv.size(), 0);
|
||||
for (int idx = 0; idx < static_cast<int>(pv.size()); ++idx) {
|
||||
if (actnum[idx]) {
|
||||
if (pv[idx] < minpvValue_) {
|
||||
minpvCells[idx] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return minpvCells;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class Grid>
|
||||
inline std::vector<int> PinchProcessor<Grid>::getHfIdxMap_(const Grid& grid)
|
||||
{
|
||||
std::vector<int> hf_ix(2*Opm::UgGridHelpers::numFaces(grid), -1);
|
||||
const auto& f2c = Opm::UgGridHelpers::faceCells(grid);
|
||||
const auto& cf = Opm::UgGridHelpers::cell2Faces(grid);
|
||||
|
||||
for (int c = 0, i = 0; c < Opm::UgGridHelpers::numCells(grid); ++c) {
|
||||
for (const auto& f: cf[c]) {
|
||||
const auto off = 0 + (f2c(f, 0) != c);
|
||||
hf_ix[2*f + off] = i++;
|
||||
}
|
||||
}
|
||||
return hf_ix;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class Grid>
|
||||
inline int PinchProcessor<Grid>::getActiveCellIdx_(const Grid& grid,
|
||||
const int globalIdx)
|
||||
{
|
||||
const int nc = Opm::UgGridHelpers::numCells(grid);
|
||||
const int* global_cell = Opm::UgGridHelpers::globalCell(grid);
|
||||
int idx = -1;
|
||||
for (int i = 0; i < nc; ++i) {
|
||||
if (global_cell[i] == globalIdx) {
|
||||
idx = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class Grid>
|
||||
inline std::vector<double> PinchProcessor<Grid>::transCompute_(const Grid& grid,
|
||||
const std::vector<double>& htrans,
|
||||
const std::vector<int>& pinCells,
|
||||
const std::vector<int>& pinFaces)
|
||||
{
|
||||
const int nc = Opm::UgGridHelpers::numCells(grid);
|
||||
const int nf = Opm::UgGridHelpers::numFaces(grid);
|
||||
std::vector<double> trans(nf, 0);
|
||||
int cellFaceIdx = 0;
|
||||
auto cell_faces = Opm::UgGridHelpers::cell2Faces(grid);
|
||||
const auto& hfmap = getHfIdxMap_(grid);
|
||||
const auto& f2c = Opm::UgGridHelpers::faceCells(grid);
|
||||
for (int cellIdx = 0; cellIdx < nc; ++cellIdx) {
|
||||
auto cellFacesRange = cell_faces[cellIdx];
|
||||
for (auto cellFaceIter = cellFacesRange.begin(); cellFaceIter != cellFacesRange.end(); ++cellFaceIter, ++cellFaceIdx) {
|
||||
const int faceIdx = *cellFaceIter;
|
||||
const auto pos = std::find(pinFaces.begin(), pinFaces.end(), faceIdx);
|
||||
if (pos == pinFaces.end()) {
|
||||
trans[faceIdx] += 1. / htrans[cellFaceIdx];
|
||||
} else {
|
||||
const int idx1 = std::distance(std::begin(pinFaces), pos);
|
||||
int idx2;
|
||||
if (idx1 % 2 == 0) {
|
||||
idx2 = idx1 + 1;
|
||||
} else {
|
||||
idx2 = idx1 - 1;
|
||||
}
|
||||
const int f1 = hfmap[2*pinFaces[idx1] + (f2c(pinFaces[idx1], 0) != getActiveCellIdx_(grid, pinCells[idx1]))];
|
||||
const int f2 = hfmap[2*pinFaces[idx2] + (f2c(pinFaces[idx2], 0) != getActiveCellIdx_(grid, pinCells[idx2]))];
|
||||
trans[faceIdx] = (1. / htrans[f1] + 1. / htrans[f2]);
|
||||
trans[pinFaces[idx2]] = trans[faceIdx];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto f = 0; f < nf; ++f) {
|
||||
trans[f] = 1. / trans[f];
|
||||
}
|
||||
|
||||
return trans;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class Grid>
|
||||
inline std::vector<std::vector<int>> PinchProcessor<Grid>::getPinchoutsColumn_(const Grid& grid,
|
||||
const std::vector<int>& actnum,
|
||||
const std::vector<double>& pv)
|
||||
{
|
||||
const int* dims = Opm::UgGridHelpers::cartDims(grid);
|
||||
std::vector<int> minpvCells = getMinpvCells_(actnum, pv);
|
||||
std::vector<std::vector<int>> segment;
|
||||
for (int z = 0; z < dims[2]; ++z) {
|
||||
for (int y = 0; y < dims[1]; ++y) {
|
||||
for (int x = 0; x < dims[0]; ++x) {
|
||||
const int c = getGlobalIndex_(x, y, z, dims);
|
||||
std::vector<int> seg;
|
||||
if (minpvCells[c]) {
|
||||
seg.push_back(c);
|
||||
minpvCells[c] = 0;
|
||||
for (int zz = z+1; zz < dims[2]; ++zz) {
|
||||
const int cc = getGlobalIndex_(x, y, zz, dims);
|
||||
if (minpvCells[cc]) {
|
||||
seg.push_back(cc);
|
||||
minpvCells[cc] = 0;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
segment.push_back(seg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return segment;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class Grid>
|
||||
inline void PinchProcessor<Grid>::transTopbot_(const Grid& grid,
|
||||
const std::vector<double>& htrans,
|
||||
const std::vector<int>& actnum,
|
||||
const std::vector<double>& multz,
|
||||
const std::vector<double>& pv,
|
||||
NNC& nnc)
|
||||
{
|
||||
const int* dims = Opm::UgGridHelpers::cartDims(grid);
|
||||
std::vector<int> pinFaces;
|
||||
std::vector<int> pinCells;
|
||||
std::vector<std::vector<int> > newSeg;
|
||||
auto minpvSeg = getPinchoutsColumn_(grid, actnum, pv);
|
||||
for (auto& seg : minpvSeg) {
|
||||
std::array<int, 3> ijk1 = getCartIndex_(seg.front(), dims);
|
||||
std::array<int, 3> ijk2 = getCartIndex_(seg.back(), dims);
|
||||
auto tmp = seg;
|
||||
if ((ijk1[2]-1) >= 0 && (ijk2[2]+1) < dims[2]) {
|
||||
int topCell = getGlobalIndex_(ijk1[0], ijk1[1], ijk1[2]-1, dims);
|
||||
int botCell = getGlobalIndex_(ijk2[0], ijk2[1], ijk2[2]+1, dims);
|
||||
/// for any segments, we need to find the active top and bottom cells.
|
||||
/// if the original segment's top and bottom is inactive, we need to lookup
|
||||
/// the column until they're found otherwise just ignore this segment.
|
||||
if (!actnum[topCell]) {
|
||||
for (int topk = ijk1[2]-2; topk > 0; --topk) {
|
||||
topCell = getGlobalIndex_(ijk1[0], ijk1[1], topk, dims);
|
||||
if (actnum[topCell]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
pinFaces.push_back(interface_(grid, topCell, Opm::FaceDir::ZPlus));
|
||||
pinCells.push_back(topCell);
|
||||
|
||||
tmp.insert(tmp.begin(), topCell);
|
||||
newSeg.push_back(tmp);
|
||||
if (!actnum[botCell]) {
|
||||
for (int botk = ijk2[2]+2; botk < dims[2]; ++botk) {
|
||||
botCell = getGlobalIndex_(ijk2[0], ijk2[1], botk, dims);
|
||||
if (actnum[botCell]) {
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
pinFaces.push_back(interface_(grid, botCell, Opm::FaceDir::ZMinus));
|
||||
pinCells.push_back(botCell);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
auto faceTrans = transCompute_(grid, htrans, pinCells, pinFaces);
|
||||
auto multzmap = multzOptions_(grid, pinCells, pinFaces, multz, newSeg);
|
||||
applyMultz_(faceTrans, multzmap);
|
||||
for (int i = 0; i < static_cast<int>(pinCells.size())/2; ++i) {
|
||||
nnc.addNNC(static_cast<int>(pinCells[2*i]), static_cast<int>(pinCells[2*i+1]), faceTrans[pinFaces[2*i]]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template<class Grid>
|
||||
inline std::unordered_multimap<int, double> PinchProcessor<Grid>::multzOptions_(const Grid& grid,
|
||||
const std::vector<int>& pinCells,
|
||||
const std::vector<int>& pinFaces,
|
||||
const std::vector<double>& multz,
|
||||
const std::vector<std::vector<int> >& segs)
|
||||
{
|
||||
std::unordered_multimap<int, double> multzmap;
|
||||
if (multzMode_ == PinchMode::ModeEnum::TOP) {
|
||||
for (int i = 0; i < static_cast<int>(pinFaces.size())/2; ++i) {
|
||||
multzmap.insert(std::make_pair(pinFaces[2*i], multz[getActiveCellIdx_(grid, pinCells[2*i])]));
|
||||
multzmap.insert(std::make_pair(pinFaces[2*i+1],multz[getActiveCellIdx_(grid, pinCells[2*i])]));
|
||||
}
|
||||
} else if (multzMode_ == PinchMode::ModeEnum::ALL) {
|
||||
for (auto& seg : segs) {
|
||||
//find the min multz in seg cells.
|
||||
auto multzValue = std::numeric_limits<double>::max();
|
||||
for (auto& cellIdx : seg) {
|
||||
auto activeIdx = getActiveCellIdx_(grid, cellIdx);
|
||||
if (activeIdx != -1) {
|
||||
multzValue = std::min(multzValue, multz[activeIdx]);
|
||||
}
|
||||
}
|
||||
//find the right face.
|
||||
auto index = std::distance(std::begin(pinCells), std::find(pinCells.begin(), pinCells.end(), seg.front()));
|
||||
multzmap.insert(std::make_pair(pinFaces[index], multzValue));
|
||||
multzmap.insert(std::make_pair(pinFaces[index+1], multzValue));
|
||||
}
|
||||
}
|
||||
|
||||
return multzmap;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class Grid>
|
||||
inline void PinchProcessor<Grid>::applyMultz_(std::vector<double>& trans,
|
||||
const std::unordered_multimap<int, double>& multzmap)
|
||||
{
|
||||
for (auto& x : multzmap) {
|
||||
trans[x.first] *= x.second;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class Grid>
|
||||
inline void PinchProcessor<Grid>::process(const Grid& grid,
|
||||
const std::vector<double>& htrans,
|
||||
const std::vector<int>& actnum,
|
||||
const std::vector<double>& multz,
|
||||
const std::vector<double>& pv,
|
||||
NNC& nnc)
|
||||
{
|
||||
transTopbot_(grid, htrans, actnum, multz, pv, nnc);
|
||||
}
|
||||
|
||||
} // namespace Opm
|
||||
#endif // OPM_PINCHPROCESSOR_HEADER_INCLUDED
|
|
@ -1,708 +0,0 @@
|
|||
/*===========================================================================
|
||||
//
|
||||
// File: cart_grid.c
|
||||
//
|
||||
// Author: Jostein R. Natvig <Jostein.R.Natvig@sintef.no>
|
||||
//
|
||||
//==========================================================================*/
|
||||
|
||||
|
||||
/*
|
||||
Copyright 2011 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2011 Statoil ASA.
|
||||
|
||||
This file is part of the Open Porous Media Project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <opm/core/grid.h>
|
||||
#include <opm/core/grid/cornerpoint_grid.h>
|
||||
|
||||
#include <opm/core/grid/cart_grid.h>
|
||||
|
||||
static struct UnstructuredGrid *allocate_cart_grid_3d(int nx, int ny, int nz);
|
||||
static void fill_cart_topology_3d(struct UnstructuredGrid *G);
|
||||
static void fill_cart_geometry_3d(struct UnstructuredGrid *G,
|
||||
const double *x,
|
||||
const double *y,
|
||||
const double *z);
|
||||
static void
|
||||
fill_layered_geometry_3d(struct UnstructuredGrid *G,
|
||||
const double *x,
|
||||
const double *y,
|
||||
const double *z,
|
||||
const double *depthz);
|
||||
|
||||
struct UnstructuredGrid *
|
||||
create_grid_cart3d(int nx, int ny, int nz)
|
||||
{
|
||||
return create_grid_hexa3d(nx, ny, nz, 1.0, 1.0, 1.0);
|
||||
}
|
||||
|
||||
struct UnstructuredGrid *
|
||||
create_grid_hexa3d(int nx, int ny, int nz,
|
||||
double dx, double dy, double dz)
|
||||
{
|
||||
int i;
|
||||
double *x, *y, *z;
|
||||
struct UnstructuredGrid *G;
|
||||
|
||||
x = malloc((nx + 1) * sizeof *x);
|
||||
y = malloc((ny + 1) * sizeof *y);
|
||||
z = malloc((nz + 1) * sizeof *z);
|
||||
|
||||
if ((x == NULL) || (y == NULL) || (z == NULL)) {
|
||||
G = NULL;
|
||||
} else {
|
||||
for (i = 0; i < nx + 1; i++) { x[i] = i * dx; }
|
||||
for (i = 0; i < ny + 1; i++) { y[i] = i * dy; }
|
||||
for (i = 0; i < nz + 1; i++) { z[i] = i * dz; }
|
||||
|
||||
G = create_grid_tensor3d(nx, ny, nz, x, y, z,
|
||||
(const double *) NULL);
|
||||
}
|
||||
|
||||
free(z); free(y); free(x);
|
||||
|
||||
return G;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static struct UnstructuredGrid *allocate_cart_grid_2d(int nx, int ny);
|
||||
static void fill_cart_topology_2d(struct UnstructuredGrid *G);
|
||||
static void fill_cart_geometry_2d(struct UnstructuredGrid *G,
|
||||
const double *x,
|
||||
const double *y);
|
||||
|
||||
struct UnstructuredGrid*
|
||||
create_grid_cart2d(int nx, int ny, double dx, double dy)
|
||||
{
|
||||
int i;
|
||||
double *x, *y;
|
||||
struct UnstructuredGrid *G;
|
||||
|
||||
x = malloc((nx + 1) * sizeof *x);
|
||||
y = malloc((ny + 1) * sizeof *y);
|
||||
|
||||
if ((x == NULL) || (y == NULL)) {
|
||||
G = NULL;
|
||||
} else {
|
||||
|
||||
for (i = 0; i < nx + 1; i++) { x[i] = i*dx; }
|
||||
for (i = 0; i < ny + 1; i++) { y[i] = i*dy; }
|
||||
|
||||
G = create_grid_tensor2d(nx, ny, x, y);
|
||||
}
|
||||
|
||||
free(y); free(x);
|
||||
|
||||
return G;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
struct UnstructuredGrid *
|
||||
create_grid_tensor2d(int nx, int ny, const double *x, const double *y)
|
||||
{
|
||||
struct UnstructuredGrid *G;
|
||||
|
||||
G = allocate_cart_grid_2d(nx, ny);
|
||||
|
||||
if (G != NULL)
|
||||
{
|
||||
fill_cart_topology_2d(G);
|
||||
fill_cart_geometry_2d(G, x, y);
|
||||
}
|
||||
|
||||
return G;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
struct UnstructuredGrid *
|
||||
create_grid_tensor3d(int nx ,
|
||||
int ny ,
|
||||
int nz ,
|
||||
const double *x ,
|
||||
const double *y ,
|
||||
const double *z ,
|
||||
const double *depthz)
|
||||
{
|
||||
struct UnstructuredGrid *G;
|
||||
|
||||
G = allocate_cart_grid_3d(nx, ny, nz);
|
||||
|
||||
if (G != NULL)
|
||||
{
|
||||
fill_cart_topology_3d(G);
|
||||
|
||||
if (depthz == NULL) {
|
||||
fill_cart_geometry_3d(G, x, y, z);
|
||||
}
|
||||
else {
|
||||
fill_layered_geometry_3d(G, x, y, z, depthz);
|
||||
}
|
||||
}
|
||||
|
||||
return G;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
/* Static functions follow: */
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
|
||||
static struct UnstructuredGrid *
|
||||
allocate_cart_grid(size_t ndims ,
|
||||
size_t ncells,
|
||||
size_t nfaces,
|
||||
size_t nnodes)
|
||||
{
|
||||
size_t nfacenodes, ncellfaces;
|
||||
|
||||
nfacenodes = nfaces * (2 * (ndims - 1));
|
||||
ncellfaces = ncells * (2 * ndims);
|
||||
|
||||
return allocate_grid(ndims, ncells, nfaces,
|
||||
nfacenodes, ncellfaces, nnodes);
|
||||
}
|
||||
|
||||
|
||||
static struct UnstructuredGrid*
|
||||
allocate_cart_grid_3d(int nx, int ny, int nz)
|
||||
{
|
||||
struct UnstructuredGrid *G;
|
||||
int Nx, Ny, Nz;
|
||||
int nxf, nyf, nzf;
|
||||
|
||||
int ncells, nfaces, nnodes;
|
||||
|
||||
Nx = nx + 1;
|
||||
Ny = ny + 1;
|
||||
Nz = nz +1;
|
||||
|
||||
nxf = Nx * ny * nz;
|
||||
nyf = nx * Ny * nz;
|
||||
nzf = nx * ny * Nz;
|
||||
|
||||
ncells = nx * ny * nz ;
|
||||
nfaces = nxf + nyf + nzf;
|
||||
nnodes = Nx * Ny * Nz ;
|
||||
|
||||
G = allocate_cart_grid(3, ncells, nfaces, nnodes);
|
||||
|
||||
if (G != NULL)
|
||||
{
|
||||
G->dimensions = 3 ;
|
||||
G->cartdims[0] = nx;
|
||||
G->cartdims[1] = ny;
|
||||
G->cartdims[2] = nz;
|
||||
|
||||
G->number_of_cells = ncells;
|
||||
G->number_of_faces = nfaces;
|
||||
G->number_of_nodes = nnodes;
|
||||
}
|
||||
|
||||
return G;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
fill_cart_topology_3d(struct UnstructuredGrid *G)
|
||||
{
|
||||
int nx, ny, nz;
|
||||
int Nx, Ny;
|
||||
int nxf, nyf;
|
||||
int i,j,k;
|
||||
|
||||
int *cfaces, *cfacepos, *fnodes, *fnodepos, *fcells;
|
||||
|
||||
nx = G->cartdims[0];
|
||||
ny = G->cartdims[1];
|
||||
nz = G->cartdims[2];
|
||||
|
||||
Nx = nx+1;
|
||||
Ny = ny+1;
|
||||
|
||||
nxf = Nx*ny*nz;
|
||||
nyf = nx*Ny*nz;
|
||||
|
||||
cfaces = G->cell_faces;
|
||||
cfacepos = G->cell_facepos;
|
||||
cfacepos[0] = 0;
|
||||
for (k=0; k<nz; ++k) {
|
||||
for (j=0; j<ny; ++j) {
|
||||
for (i=0; i<nx; ++i) {
|
||||
*cfaces++ = i+ Nx*(j+ ny* k );
|
||||
*cfaces++ = i+1+Nx*(j+ ny* k );
|
||||
*cfaces++ = i+ nx*(j+ Ny* k ) +nxf;
|
||||
*cfaces++ = i+ nx*(j+1+Ny* k ) +nxf;
|
||||
*cfaces++ = i+ nx*(j+ ny* k ) +nxf+nyf;
|
||||
*cfaces++ = i+ nx*(j+ ny*(k+1)) +nxf+nyf;
|
||||
|
||||
cfacepos[1] = cfacepos[0]+6;
|
||||
++cfacepos;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (k = 0; k < nx * ny * nz; ++k) {
|
||||
for (i = 0; i < 6; ++i) {
|
||||
G->cell_facetag[k*6 + i] = i;
|
||||
}
|
||||
}
|
||||
|
||||
fnodes = G->face_nodes;
|
||||
fnodepos = G->face_nodepos;
|
||||
fcells = G->face_cells;
|
||||
fnodepos[0] = 0;
|
||||
|
||||
/* Faces with x-normal */
|
||||
for (k=0; k<nz; ++k) {
|
||||
for (j=0; j<ny; ++j) {
|
||||
for (i=0; i<nx+1; ++i) {
|
||||
*fnodes++ = i+Nx*(j + Ny * k );
|
||||
*fnodes++ = i+Nx*(j+1 + Ny * k );
|
||||
*fnodes++ = i+Nx*(j+1 + Ny *(k+1));
|
||||
*fnodes++ = i+Nx*(j + Ny *(k+1));
|
||||
fnodepos[1] = fnodepos[0] + 4;
|
||||
++fnodepos;
|
||||
if (i==0) {
|
||||
*fcells++ = -1;
|
||||
*fcells++ = i+nx*(j+ny*k);
|
||||
}
|
||||
else if (i == nx) {
|
||||
*fcells++ = i-1+nx*(j+ny*k);
|
||||
*fcells++ = -1;
|
||||
}
|
||||
else {
|
||||
*fcells++ = i-1 + nx*(j+ny*k);
|
||||
*fcells++ = i + nx*(j+ny*k);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Faces with y-normal */
|
||||
for (k=0; k<nz; ++k) {
|
||||
for (j=0; j<ny+1; ++j) {
|
||||
for (i=0; i<nx; ++i) {
|
||||
*fnodes++ = i+ Nx*(j + Ny * k );
|
||||
*fnodes++ = i + Nx*(j + Ny *(k+1));
|
||||
*fnodes++ = i+1 + Nx*(j + Ny *(k+1));
|
||||
*fnodes++ = i+1 + Nx*(j + Ny * k );
|
||||
fnodepos[1] = fnodepos[0] + 4;
|
||||
++fnodepos;
|
||||
if (j==0) {
|
||||
*fcells++ = -1;
|
||||
*fcells++ = i+nx*(j+ny*k);
|
||||
}
|
||||
else if (j == ny) {
|
||||
*fcells++ = i+nx*(j-1+ny*k);
|
||||
*fcells++ = -1;
|
||||
}
|
||||
else {
|
||||
*fcells++ = i+nx*(j-1+ny*k);
|
||||
*fcells++ = i+nx*(j+ny*k);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Faces with z-normal */
|
||||
for (k=0; k<nz+1; ++k) {
|
||||
for (j=0; j<ny; ++j) {
|
||||
for (i=0; i<nx; ++i) {
|
||||
*fnodes++ = i+ Nx*(j + Ny * k);
|
||||
*fnodes++ = i+1 + Nx*(j + Ny * k);
|
||||
*fnodes++ = i+1 + Nx*(j+1 + Ny * k);
|
||||
*fnodes++ = i+ Nx*(j+1 + Ny * k);
|
||||
fnodepos[1] = fnodepos[0] + 4;
|
||||
++fnodepos;
|
||||
if (k==0) {
|
||||
*fcells++ = -1;
|
||||
*fcells++ = i+nx*(j+ny*k);
|
||||
}
|
||||
else if (k == nz) {
|
||||
*fcells++ = i+nx*(j+ny*(k-1));
|
||||
*fcells++ = -1;
|
||||
}
|
||||
else {
|
||||
*fcells++ = i+nx*(j+ny*(k-1));
|
||||
*fcells++ = i+nx*(j+ny*k);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
fill_cart_geometry_3d(struct UnstructuredGrid *G,
|
||||
const double *x,
|
||||
const double *y,
|
||||
const double *z)
|
||||
{
|
||||
int nx, ny, nz;
|
||||
int i,j,k;
|
||||
|
||||
double dx, dy, dz;
|
||||
|
||||
double *coord, *ccentroids, *cvolumes;
|
||||
double *fnormals, *fcentroids, *fareas;
|
||||
|
||||
nx = G->cartdims[0];
|
||||
ny = G->cartdims[1];
|
||||
nz = G->cartdims[2];
|
||||
|
||||
ccentroids = G->cell_centroids;
|
||||
cvolumes = G->cell_volumes;
|
||||
for (k=0; k<nz; ++k) {
|
||||
for (j=0; j<ny; ++j) {
|
||||
for (i=0; i<nx; ++i) {
|
||||
*ccentroids++ = (x[i] + x[i + 1]) / 2.0;
|
||||
*ccentroids++ = (y[j] + y[j + 1]) / 2.0;
|
||||
*ccentroids++ = (z[k] + z[k + 1]) / 2.0;
|
||||
|
||||
dx = x[i + 1] - x[i];
|
||||
dy = y[j + 1] - y[j];
|
||||
dz = z[k + 1] - z[k];
|
||||
|
||||
*cvolumes++ = dx * dy * dz;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fnormals = G->face_normals;
|
||||
fcentroids = G->face_centroids;
|
||||
fareas = G->face_areas;
|
||||
|
||||
/* Faces with x-normal */
|
||||
for (k=0; k<nz; ++k) {
|
||||
for (j=0; j<ny; ++j) {
|
||||
for (i=0; i<nx+1; ++i) {
|
||||
dy = y[j + 1] - y[j];
|
||||
dz = z[k + 1] - z[k];
|
||||
|
||||
*fnormals++ = dy * dz;
|
||||
*fnormals++ = 0;
|
||||
*fnormals++ = 0;
|
||||
|
||||
*fcentroids++ = x[i];
|
||||
*fcentroids++ = (y[j] + y[j + 1]) / 2.0;
|
||||
*fcentroids++ = (z[k] + z[k + 1]) / 2.0;
|
||||
|
||||
*fareas++ = dy * dz;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Faces with y-normal */
|
||||
for (k=0; k<nz; ++k) {
|
||||
for (j=0; j<ny+1; ++j) {
|
||||
for (i=0; i<nx; ++i) {
|
||||
dx = x[i + 1] - x[i];
|
||||
dz = z[k + 1] - z[k];
|
||||
|
||||
*fnormals++ = 0;
|
||||
*fnormals++ = dx * dz;
|
||||
*fnormals++ = 0;
|
||||
|
||||
*fcentroids++ = (x[i] + x[i + 1]) / 2.0;
|
||||
*fcentroids++ = y[j];
|
||||
*fcentroids++ = (z[k] + z[k + 1]) / 2.0;
|
||||
|
||||
*fareas++ = dx * dz;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Faces with z-normal */
|
||||
for (k=0; k<nz+1; ++k) {
|
||||
for (j=0; j<ny; ++j) {
|
||||
for (i=0; i<nx; ++i) {
|
||||
dx = x[i + 1] - x[i];
|
||||
dy = y[j + 1] - y[j];
|
||||
|
||||
*fnormals++ = 0;
|
||||
*fnormals++ = 0;
|
||||
*fnormals++ = dx * dy;
|
||||
|
||||
*fcentroids++ = (x[i] + x[i + 1]) / 2.0;
|
||||
*fcentroids++ = (y[j] + y[j + 1]) / 2.0;
|
||||
*fcentroids++ = z[k];
|
||||
|
||||
*fareas++ = dx * dy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
coord = G->node_coordinates;
|
||||
for (k=0; k<nz+1; ++k) {
|
||||
for (j=0; j<ny+1; ++j) {
|
||||
for (i=0; i<nx+1; ++i) {
|
||||
*coord++ = x[i];
|
||||
*coord++ = y[j];
|
||||
*coord++ = z[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
fill_layered_geometry_3d(struct UnstructuredGrid *G,
|
||||
const double *x,
|
||||
const double *y,
|
||||
const double *z,
|
||||
const double *depthz)
|
||||
{
|
||||
int i , j , k ;
|
||||
int nx, ny, nz;
|
||||
|
||||
const double *depth;
|
||||
double *coord;
|
||||
|
||||
nx = G->cartdims[0]; ny = G->cartdims[1]; nz = G->cartdims[2];
|
||||
|
||||
coord = G->node_coordinates;
|
||||
for (k = 0; k < nz + 1; k++) {
|
||||
|
||||
depth = depthz;
|
||||
|
||||
for (j = 0; j < ny + 1; j++) {
|
||||
for (i = 0; i < nx + 1; i++) {
|
||||
*coord++ = x[i];
|
||||
*coord++ = y[j];
|
||||
*coord++ = z[k] + *depth++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
compute_geometry(G);
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static struct UnstructuredGrid*
|
||||
allocate_cart_grid_2d(int nx, int ny)
|
||||
{
|
||||
int nxf, nyf;
|
||||
int Nx , Ny ;
|
||||
|
||||
int ncells, nfaces, nnodes;
|
||||
|
||||
struct UnstructuredGrid *G;
|
||||
|
||||
Nx = nx + 1;
|
||||
Ny = ny + 1;
|
||||
|
||||
nxf = Nx * ny;
|
||||
nyf = nx * Ny;
|
||||
|
||||
ncells = nx * ny ;
|
||||
nfaces = nxf + nyf;
|
||||
nnodes = Nx * Ny ;
|
||||
|
||||
G = allocate_cart_grid(2, ncells, nfaces, nnodes);
|
||||
|
||||
if (G != NULL)
|
||||
{
|
||||
G->dimensions = 2 ;
|
||||
G->cartdims[0] = nx;
|
||||
G->cartdims[1] = ny;
|
||||
G->cartdims[2] = 1 ;
|
||||
|
||||
G->number_of_cells = ncells;
|
||||
G->number_of_faces = nfaces;
|
||||
G->number_of_nodes = nnodes;
|
||||
}
|
||||
|
||||
return G;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
fill_cart_topology_2d(struct UnstructuredGrid *G)
|
||||
{
|
||||
int i,j;
|
||||
int nx, ny;
|
||||
int nxf;
|
||||
int Nx;
|
||||
|
||||
int *fnodes, *fnodepos, *fcells, *cfaces, *cfacepos;
|
||||
|
||||
cfaces = G->cell_faces;
|
||||
cfacepos = G->cell_facepos;
|
||||
|
||||
nx = G->cartdims[0];
|
||||
ny = G->cartdims[1];
|
||||
Nx = nx + 1;
|
||||
nxf = Nx * ny;
|
||||
|
||||
cfacepos[0] = 0;
|
||||
for (j=0; j<ny; ++j) {
|
||||
for (i=0; i<nx; ++i) {
|
||||
*cfaces++ = i+ Nx*j;
|
||||
*cfaces++ = i+ nx*j +nxf;
|
||||
*cfaces++ = i+1+Nx*j;
|
||||
*cfaces++ = i+ nx*(j+1)+nxf;
|
||||
|
||||
cfacepos[1] = cfacepos[0]+4;
|
||||
++cfacepos;
|
||||
}
|
||||
}
|
||||
|
||||
for (j = 0; j < nx * ny; ++j) {
|
||||
G->cell_facetag[j*4 + 0] = 0;
|
||||
G->cell_facetag[j*4 + 1] = 2;
|
||||
G->cell_facetag[j*4 + 2] = 1;
|
||||
G->cell_facetag[j*4 + 3] = 3;
|
||||
}
|
||||
|
||||
|
||||
fnodes = G->face_nodes;
|
||||
fnodepos = G->face_nodepos;
|
||||
fcells = G->face_cells;
|
||||
fnodepos[0] = 0;
|
||||
|
||||
/* Faces with x-normal */
|
||||
for (j=0; j<ny; ++j) {
|
||||
for (i=0; i<nx+1; ++i) {
|
||||
*fnodes++ = i+Nx*j;
|
||||
*fnodes++ = i+Nx*(j+1);
|
||||
fnodepos[1] = fnodepos[0] + 2;
|
||||
++fnodepos;
|
||||
if (i==0) {
|
||||
*fcells++ = -1;
|
||||
*fcells++ = i+nx*j;
|
||||
}
|
||||
else if (i == nx) {
|
||||
*fcells++ = i-1+nx*j;
|
||||
*fcells++ = -1;
|
||||
}
|
||||
else {
|
||||
*fcells++ = i-1 + nx*j;
|
||||
*fcells++ = i + nx*j;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Faces with y-normal */
|
||||
for (j=0; j<ny+1; ++j) {
|
||||
for (i=0; i<nx; ++i) {
|
||||
*fnodes++ = i+1 + Nx*j;
|
||||
*fnodes++ = i+ Nx*j;
|
||||
fnodepos[1] = fnodepos[0] + 2;
|
||||
++fnodepos;
|
||||
if (j==0) {
|
||||
*fcells++ = -1;
|
||||
*fcells++ = i+nx*j;
|
||||
}
|
||||
else if (j == ny) {
|
||||
*fcells++ = i+nx*(j-1);
|
||||
*fcells++ = -1;
|
||||
}
|
||||
else {
|
||||
*fcells++ = i+nx*(j-1);
|
||||
*fcells++ = i+nx*j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
fill_cart_geometry_2d(struct UnstructuredGrid *G,
|
||||
const double *x,
|
||||
const double *y)
|
||||
{
|
||||
int i,j;
|
||||
int nx, ny;
|
||||
|
||||
double dx, dy;
|
||||
|
||||
double *coord, *ccentroids, *cvolumes;
|
||||
double *fnormals, *fcentroids, *fareas;
|
||||
|
||||
nx = G->cartdims[0];
|
||||
ny = G->cartdims[1];
|
||||
|
||||
ccentroids = G->cell_centroids;
|
||||
cvolumes = G->cell_volumes;
|
||||
|
||||
for (j=0; j<ny; ++j) {
|
||||
for (i=0; i<nx; ++i) {
|
||||
*ccentroids++ = (x[i] + x[i + 1]) / 2.0;
|
||||
*ccentroids++ = (y[j] + y[j + 1]) / 2.0;
|
||||
|
||||
dx = x[i + 1] - x[i];
|
||||
dy = y[j + 1] - y[j];
|
||||
|
||||
*cvolumes++ = dx * dy;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
fnormals = G->face_normals;
|
||||
fcentroids = G->face_centroids;
|
||||
fareas = G->face_areas;
|
||||
|
||||
/* Faces with x-normal */
|
||||
for (j=0; j<ny; ++j) {
|
||||
for (i=0; i<nx+1; ++i) {
|
||||
dy = y[j + 1] - y[j];
|
||||
|
||||
*fnormals++ = dy;
|
||||
*fnormals++ = 0;
|
||||
|
||||
*fcentroids++ = x[i];
|
||||
*fcentroids++ = (y[j] + y[j + 1]) / 2.0;
|
||||
|
||||
*fareas++ = dy;
|
||||
}
|
||||
}
|
||||
|
||||
/* Faces with y-normal */
|
||||
for (j=0; j<ny+1; ++j) {
|
||||
for (i=0; i<nx; ++i) {
|
||||
dx = x[i + 1] - x[i];
|
||||
|
||||
*fnormals++ = 0;
|
||||
*fnormals++ = dx;
|
||||
|
||||
*fcentroids++ = (x[i] + x[i + 1]) / 2.0;
|
||||
*fcentroids++ = y[j];
|
||||
|
||||
*fareas++ = dx;
|
||||
}
|
||||
}
|
||||
|
||||
coord = G->node_coordinates;
|
||||
for (j=0; j<ny+1; ++j) {
|
||||
for (i=0; i<nx+1; ++i) {
|
||||
*coord++ = x[i];
|
||||
*coord++ = y[j];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,172 +0,0 @@
|
|||
/*===========================================================================
|
||||
//
|
||||
// File: cart_grid.h
|
||||
//
|
||||
// Author: Jostein R. Natvig <Jostein.R.Natvig@sintef.no>
|
||||
//
|
||||
//==========================================================================*/
|
||||
|
||||
|
||||
/*
|
||||
Copyright 2011 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2011 Statoil ASA.
|
||||
|
||||
This file is part of the Open Porous Media Project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef OPM_CART_GRID_H_HEADER
|
||||
#define OPM_CART_GRID_H_HEADER
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Routines to construct fully formed grid structures from a simple Cartesian
|
||||
* (i.e., tensor product) description.
|
||||
*
|
||||
* The cells are lexicographically ordered with the @c i index cycling the most
|
||||
* rapidly, followed by the @c j index and then, in three space dimensions, the
|
||||
* @c k (`layer') index as the least rapidly cycling index.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Form geometrically Cartesian grid in two space dimensions with equally
|
||||
* sized cells.
|
||||
*
|
||||
* @param[in] nx Number of cells in @c x direction.
|
||||
* @param[in] ny Number of cells in @c y direction.
|
||||
* @param[in] dx Length, in meters, of each cell's @c x extent.
|
||||
* @param[in] dy Length, in meters, of each cell's @c y extent.
|
||||
*
|
||||
* @return Fully formed grid structure containing valid geometric primitives.
|
||||
* Must be destroyed using function destroy_grid().
|
||||
*/
|
||||
struct UnstructuredGrid *
|
||||
create_grid_cart2d(int nx, int ny, double dx, double dy);
|
||||
|
||||
|
||||
/**
|
||||
* Form geometrically Cartesian grid in three space dimensions with unit-sized
|
||||
* cells.
|
||||
*
|
||||
* @param[in] nx Number of cells in @c x direction.
|
||||
* @param[in] ny Number of cells in @c y direction.
|
||||
* @param[in] nz Number of cells in @c z direction.
|
||||
*
|
||||
* @return Fully formed grid structure containing valid geometric primitives.
|
||||
* Must be destroyed using function destroy_grid().
|
||||
*/
|
||||
struct UnstructuredGrid *
|
||||
create_grid_cart3d(int nx, int ny, int nz);
|
||||
|
||||
|
||||
/**
|
||||
* Form geometrically Cartesian grid in three space dimensions with equally
|
||||
* sized cells.
|
||||
*
|
||||
* Each cell has physical size (volume) \f$\mathit{dx}\times \mathit{dy}\times
|
||||
* \mathit{dz}\f$.
|
||||
*
|
||||
* @param[in] nx Number of cells in @c x direction.
|
||||
* @param[in] ny Number of cells in @c y direction.
|
||||
* @param[in] nz Number of cells in @c z direction.
|
||||
*
|
||||
* @param[in] dx Length, in meters, of each cell's @c x extent.
|
||||
* @param[in] dy Length, in meters, of each cell's @c y extent.
|
||||
* @param[in] dz Length, in meters, of each cell's @c z extent.
|
||||
*
|
||||
* @return Fully formed grid structure containing valid geometric primitives.
|
||||
* Must be destroyed using function destroy_grid().
|
||||
*/
|
||||
struct UnstructuredGrid *
|
||||
create_grid_hexa3d(int nx, int ny, int nz,
|
||||
double dx, double dy, double dz);
|
||||
|
||||
|
||||
/**
|
||||
* Form tensor product (Cartesian) grid in two space dimensions.
|
||||
*
|
||||
* The size (volume) of cell \f$(i,j)\f$ is
|
||||
* \f[
|
||||
* v_{ij} = (x_{i+1} - x_i)\cdot (y_{j+1} - y_j)
|
||||
* \f]
|
||||
* Similar relations hold for the cell and interface centroids as well as the
|
||||
* interface areas and normal vectors. In other words, cell \f$(i,j)\f$ is the
|
||||
* convex hull bounded by the tensor product of nodes \f$x_i\f$, \f$x_{i+1}\f$,
|
||||
* \f$y_j\f$, and \f$y_{j+1}\f$.
|
||||
*
|
||||
* @param[in] nx Number of cells in @c x direction.
|
||||
* @param[in] ny Number of cells in @c y direction.
|
||||
*
|
||||
* @param[in] x Position along @c x axis of each grid line with constant @c x
|
||||
* coordinate. Array of size <CODE>nx + 1</CODE>.
|
||||
* @param[in] y Position along @c y axis of each grid line with constant @c y
|
||||
* coordinate. Array of size <CODE>ny + 1</CODE>.
|
||||
*
|
||||
* @return Fully formed grid structure containing valid geometric primitives.
|
||||
* Must be destroyed using function destroy_grid().
|
||||
*/
|
||||
struct UnstructuredGrid *
|
||||
create_grid_tensor2d(int nx, int ny,
|
||||
const double *x , const double *y );
|
||||
|
||||
|
||||
/**
|
||||
* Form tensor product (i.e., topologically Cartesian) grid in three space
|
||||
* dimensions--possibly with a variable top-layer topography.
|
||||
*
|
||||
* If @c depthz is @c NULL, then geometric information such as volumes and
|
||||
* centroids is calculated from analytic expressions. Otherwise, these values
|
||||
* are computed using function compute_geometry().
|
||||
*
|
||||
* @param[in] nx Number of cells in @c x direction.
|
||||
* @param[in] ny Number of cells in @c y direction.
|
||||
* @param[in] nz Number of cells in @c z direction.
|
||||
*
|
||||
* @param[in] x Position along @c x axis of each grid line with constant @c x
|
||||
* coordinate. Array of size <CODE>nx + 1</CODE>.
|
||||
* @param[in] y Position along @c y axis of each grid line with constant @c y
|
||||
* coordinate. Array of size <CODE>ny + 1</CODE>.
|
||||
* @param[in] z Distance (depth) from top-layer measured along the @c z axis of
|
||||
* each grid line with constant @c z coordinate. Array of size
|
||||
* <CODE>nz + 1</CODE>.
|
||||
*
|
||||
* @param[in] depthz
|
||||
* Top-layer topography specification. If @c NULL, interpreted as
|
||||
* horizontal top-layer at <CODE>z=0</CODE>. Otherwise, must be
|
||||
* an array of size <CODE>(nx + 1) * (ny + 1)</CODE>, ordered
|
||||
* lexicographically, that defines the depth of each top-layer
|
||||
* pillar vertex.
|
||||
*
|
||||
* @return Fully formed grid structure containing valid geometric primitives.
|
||||
* Must be destroyed using function destroy_grid().
|
||||
*/
|
||||
struct UnstructuredGrid *
|
||||
create_grid_tensor3d(int nx ,
|
||||
int ny ,
|
||||
int nz ,
|
||||
const double *x ,
|
||||
const double *y ,
|
||||
const double *z ,
|
||||
const double *depthz);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif /* OPM_CART_GRID_H_HEADER */
|
|
@ -1,235 +0,0 @@
|
|||
/*===========================================================================
|
||||
//
|
||||
// File: cgridinterface.c
|
||||
//
|
||||
// Author: Jostein R. Natvig <Jostein.R.Natvig@sintef.no>
|
||||
//
|
||||
//==========================================================================*/
|
||||
|
||||
|
||||
/*
|
||||
Copyright 2011 SINTEF ICT, Applied Mathematics.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <opm/core/grid/cornerpoint_grid.h>
|
||||
#include <opm/core/grid/cpgpreprocess/geometry.h>
|
||||
#include <opm/core/grid/cpgpreprocess/preprocess.h>
|
||||
#include <opm/core/grid.h>
|
||||
|
||||
|
||||
static int
|
||||
fill_cell_topology(struct processed_grid *pg,
|
||||
struct UnstructuredGrid *g )
|
||||
{
|
||||
int f, c1, c2, tag;
|
||||
size_t c, nc, nhf;
|
||||
|
||||
nc = g->number_of_cells;
|
||||
|
||||
g->cell_facepos = malloc((nc + 1) * sizeof *g->cell_facepos);
|
||||
|
||||
if (g->cell_facepos != NULL) {
|
||||
/* Allocate and initialise compressed cell-to-face topology. */
|
||||
|
||||
for (c = 0; c < nc + 1; c++) { g->cell_facepos[c] = 0; }
|
||||
|
||||
for (f = 0; f < g->number_of_faces; f++) {
|
||||
c1 = g->face_cells[2*f + 0];
|
||||
c2 = g->face_cells[2*f + 1];
|
||||
|
||||
if (c1 >= 0) { g->cell_facepos[c1 + 1] += 1; }
|
||||
if (c2 >= 0) { g->cell_facepos[c2 + 1] += 1; }
|
||||
}
|
||||
|
||||
for (c = 1; c <= nc; c++) {
|
||||
g->cell_facepos[0] += g->cell_facepos[c];
|
||||
g->cell_facepos[c] = g->cell_facepos[0] - g->cell_facepos[c];
|
||||
}
|
||||
|
||||
nhf = g->cell_facepos[0];
|
||||
g->cell_facepos[0] = 0;
|
||||
|
||||
g->cell_faces = malloc(nhf * sizeof *g->cell_faces );
|
||||
g->cell_facetag = malloc(nhf * sizeof *g->cell_facetag);
|
||||
|
||||
if ((g->cell_faces == NULL) || (g->cell_facetag == NULL)) {
|
||||
free(g->cell_facetag); g->cell_facetag = NULL;
|
||||
free(g->cell_faces); g->cell_faces = NULL;
|
||||
free(g->cell_facepos); g->cell_facepos = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (g->cell_facepos != NULL) {
|
||||
/* Compute final cell-to-face mapping and half-face tags.
|
||||
*
|
||||
* Process relies on preprocess() producing neighbourship
|
||||
* definitions for which the normals point (logically) in the
|
||||
* positive I,J,K directions *and* from ->face_cells[2*f+0] to
|
||||
* ->face_cells[2*f+1] (i.e., from first to second cell of
|
||||
* interface 'f'--be it internal or outer).
|
||||
*
|
||||
* For instance, a "LEFT" connection (pg->face_tag==LEFT==0)
|
||||
* for which the normal points into the cell (i.e., when
|
||||
* ->face_cells[2*f+1] >= 0), is a half-face of type 0.
|
||||
*
|
||||
* Simlarly, a "TOP" connection (pg->face_tag==TOP==2) for
|
||||
* which the normal points out of the cell (i.e., when
|
||||
* ->face_cells[2*f+0] >= 0), is a half-face of type 5. */
|
||||
|
||||
for (f = 0; f < g->number_of_faces; f++) {
|
||||
tag = 2 * pg->face_tag[f]; /* [0, 2, 4] */
|
||||
c1 = g->face_cells[2*f + 0];
|
||||
c2 = g->face_cells[2*f + 1];
|
||||
|
||||
if (c1 >= 0) {
|
||||
g->cell_faces [ g->cell_facepos[c1 + 1] ] = f;
|
||||
g->cell_facetag [ g->cell_facepos[c1 + 1] ] = tag + 1;
|
||||
|
||||
g->cell_facepos[c1 + 1] += 1;
|
||||
}
|
||||
|
||||
if (c2 >= 0) {
|
||||
g->cell_faces [ g->cell_facepos[c2 + 1] ] = f;
|
||||
g->cell_facetag [ g->cell_facepos[c2 + 1] ] = tag + 0;
|
||||
|
||||
g->cell_facepos[c2 + 1] += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return g->cell_facepos != NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
allocate_geometry(struct UnstructuredGrid *g)
|
||||
{
|
||||
int ok;
|
||||
size_t nc, nf, nd;
|
||||
|
||||
assert (g->dimensions == 3);
|
||||
|
||||
nc = g->number_of_cells;
|
||||
nf = g->number_of_faces;
|
||||
nd = 3;
|
||||
|
||||
g->face_areas = malloc(nf * 1 * sizeof *g->face_areas);
|
||||
g->face_centroids = malloc(nf * nd * sizeof *g->face_centroids);
|
||||
g->face_normals = malloc(nf * nd * sizeof *g->face_normals);
|
||||
|
||||
g->cell_volumes = malloc(nc * 1 * sizeof *g->cell_volumes);
|
||||
g->cell_centroids = malloc(nc * nd * sizeof *g->cell_centroids);
|
||||
|
||||
ok = g->face_areas != NULL;
|
||||
ok += g->face_centroids != NULL;
|
||||
ok += g->face_normals != NULL;
|
||||
|
||||
ok += g->cell_volumes != NULL;
|
||||
ok += g->cell_centroids != NULL;
|
||||
|
||||
return ok == 5;
|
||||
}
|
||||
|
||||
|
||||
void compute_geometry(struct UnstructuredGrid *g)
|
||||
{
|
||||
assert (g != NULL);
|
||||
if (g!=NULL)
|
||||
{
|
||||
assert (g->face_centroids != NULL);
|
||||
assert (g->face_normals != NULL);
|
||||
assert (g->face_areas != NULL);
|
||||
assert (g->cell_centroids != NULL);
|
||||
assert (g->cell_volumes != NULL);
|
||||
|
||||
compute_face_geometry(g->dimensions , g->node_coordinates,
|
||||
g->number_of_faces, g->face_nodepos,
|
||||
g->face_nodes, g->face_normals,
|
||||
g->face_centroids, g->face_areas);
|
||||
|
||||
compute_cell_geometry(g->dimensions, g->node_coordinates,
|
||||
g->face_nodepos, g->face_nodes,
|
||||
g->face_cells, g->face_normals,
|
||||
g->face_centroids, g->number_of_cells,
|
||||
g->cell_facepos, g->cell_faces,
|
||||
g->cell_centroids, g->cell_volumes);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct UnstructuredGrid *
|
||||
create_grid_cornerpoint(const struct grdecl *in, double tol)
|
||||
{
|
||||
struct UnstructuredGrid *g;
|
||||
int ok;
|
||||
struct processed_grid pg;
|
||||
|
||||
g = create_grid_empty();
|
||||
if (g == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
process_grdecl(in, tol, &pg);
|
||||
|
||||
/*
|
||||
* Convert "struct processed_grid" to "struct UnstructuredGrid".
|
||||
*
|
||||
* In particular, convey resource ownership from 'pg' to 'g'.
|
||||
* Consequently, memory resources obtained in process_grdecl()
|
||||
* will be released in destroy_grid().
|
||||
*/
|
||||
g->dimensions = 3;
|
||||
|
||||
g->number_of_nodes = pg.number_of_nodes;
|
||||
g->number_of_faces = pg.number_of_faces;
|
||||
g->number_of_cells = pg.number_of_cells;
|
||||
|
||||
g->node_coordinates = pg.node_coordinates;
|
||||
|
||||
g->face_nodes = pg.face_nodes;
|
||||
g->face_nodepos = pg.face_ptr;
|
||||
g->face_cells = pg.face_neighbors;
|
||||
|
||||
/* Explicitly relinquish resource references conveyed to 'g'. This
|
||||
* is needed to avoid creating dangling references in the
|
||||
* free_processed_grid() call. */
|
||||
pg.node_coordinates = NULL;
|
||||
pg.face_nodes = NULL;
|
||||
pg.face_ptr = NULL;
|
||||
pg.face_neighbors = NULL;
|
||||
|
||||
/* allocate and fill g->cell_faces/g->cell_facepos and
|
||||
* g->cell_facetag as well as the geometry-related fields. */
|
||||
ok = fill_cell_topology(&pg, g);
|
||||
ok = ok && allocate_geometry(g);
|
||||
|
||||
if (!ok)
|
||||
{
|
||||
destroy_grid(g);
|
||||
g = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
compute_geometry(g);
|
||||
|
||||
g->cartdims[0] = pg.dimensions[0];
|
||||
g->cartdims[1] = pg.dimensions[1];
|
||||
g->cartdims[2] = pg.dimensions[2];
|
||||
|
||||
g->global_cell = pg.local_cell_index;
|
||||
|
||||
/* Explicitly relinquish resource references conveyed to 'g'.
|
||||
* This is needed to avoid creating dangling references in the
|
||||
* free_processed_grid() call. */
|
||||
pg.local_cell_index = NULL;
|
||||
}
|
||||
|
||||
free_processed_grid(&pg);
|
||||
|
||||
return g;
|
||||
}
|
|
@ -1,103 +0,0 @@
|
|||
/*===========================================================================
|
||||
//
|
||||
// File: preprocess.h
|
||||
//
|
||||
// Created: Fri Jun 19 08:43:04 2009
|
||||
//
|
||||
// Author: Jostein R. Natvig <Jostein.R.Natvig@sintef.no>
|
||||
//
|
||||
// $Date: 2010-08-27 19:12:16 +0200 (Fri, 27 Aug 2010) $
|
||||
//
|
||||
// $Revision: 930 $
|
||||
//
|
||||
//==========================================================================*/
|
||||
|
||||
/*
|
||||
Copyright 2010, 2011, 2012 SINTEF ICT, Applied Mathematics.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef OPM_CORNERPOINT_GRID_HEADER_INCLUDED
|
||||
#define OPM_CORNERPOINT_GRID_HEADER_INCLUDED
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Routines to form a complete UnstructuredGrid from a corner-point
|
||||
* specification.
|
||||
*/
|
||||
|
||||
#include <opm/core/grid.h>
|
||||
#include <opm/core/grid/cpgpreprocess/preprocess.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Construct grid representation from corner-point specification of a
|
||||
* particular geological model.
|
||||
*
|
||||
* Pinched cells will be removed irrespective of any explicit "active" map
|
||||
* in the geological model input specification. Geometric primitives such
|
||||
* as cell barycenters (i.e., centroids), volumes and interface areas are
|
||||
* computed internally using function compute_geometry(). The caller does
|
||||
* not need to compute this information separately.
|
||||
*
|
||||
* @param[in] in Corner-point specification. If "actnum" is NULL, then the
|
||||
* specification is interpreted as if all cells are initially
|
||||
* active.
|
||||
*
|
||||
* @param[in] tol Absolute tolerance of node-coincidence.
|
||||
*
|
||||
* @return Fully formed grid data structure that manages the grid defined by
|
||||
* the input corner-point specification. Must be destroyed using function
|
||||
* destroy_grid().
|
||||
*/
|
||||
struct UnstructuredGrid *
|
||||
create_grid_cornerpoint(const struct grdecl *in, double tol);
|
||||
|
||||
|
||||
/**
|
||||
* Compute derived geometric primitives in a grid.
|
||||
*
|
||||
* This function computes values for each of the following quantities
|
||||
* - Quantities pertaining to interfaces (connections, faces)
|
||||
* -# Barycenters (centroids), <CODE>g->dimensions</CODE> scalars per face
|
||||
* stored sequentially in <CODE>g->face_centroids</CODE>.
|
||||
* -# Areas, one scalar per face stored sequentially in
|
||||
* <CODE>g->face_areas</CODE>.
|
||||
* -# Normals, <CODE>g->dimensions</CODE> scalars per face stored
|
||||
* sequentially in <CODE>g->face_normals</CODE>. The Euclidian norm of
|
||||
* each normal is equal to the corresponding face's area.
|
||||
*
|
||||
* - Quantities pertaining to cells (volumes)
|
||||
* -# Barycenters (centroids), <CODE>g->dimensions</CODE> scalars per cell
|
||||
* stored sequentially in <CODE>g->cell_centroids</CODE>.
|
||||
* -# Volumes, one scalar per cell stored sequentially in
|
||||
* <CODE>g->cell_volumes</CODE>.
|
||||
*
|
||||
* These fields must be allocated prior to calling compute_geometry().
|
||||
*
|
||||
* @param[in,out] g Grid structure.
|
||||
*/
|
||||
void compute_geometry(struct UnstructuredGrid *g);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* OPM_CORNERPOINT_GRID_HEADER_INCLUDED */
|
|
@ -1,369 +0,0 @@
|
|||
/*===========================================================================
|
||||
//
|
||||
// File: facetopology.c
|
||||
//
|
||||
// Created: Fri Jun 19 08:46:53 2009
|
||||
//
|
||||
// Author: Jostein R. Natvig <Jostein.R.Natvig@sintef.no>
|
||||
//
|
||||
// $Date$
|
||||
//
|
||||
// $Revision$
|
||||
//
|
||||
//===========================================================================*/
|
||||
|
||||
/*
|
||||
Copyright 2009, 2010 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2009, 2010 Statoil ASA.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "preprocess.h"
|
||||
#include "facetopology.h"
|
||||
|
||||
/* No checking of input arguments in this code! */
|
||||
#define MIN(i,j) ((i)<(j) ? (i) : (j))
|
||||
#define MAX(i,j) ((i)>(j) ? (i) : (j))
|
||||
|
||||
#define DEBUG 1
|
||||
|
||||
/*------------------------------------------------------*/
|
||||
/* */
|
||||
/* */
|
||||
/* Find connections for each pair of pillars */
|
||||
/* */
|
||||
/* */
|
||||
/* */
|
||||
/*------------------------------------------------------*/
|
||||
|
||||
|
||||
/* Determine face topology first, then compute intersection. */
|
||||
/* All intersections that occur are present in the final face geometry.*/
|
||||
static int *
|
||||
computeFaceTopology(const int *a1, const int *a2,
|
||||
const int *b1, const int *b2,
|
||||
int intersect[4], int *faces)
|
||||
{
|
||||
int mask[8];
|
||||
int k;
|
||||
int *f;
|
||||
|
||||
for (k = 0; k < 8; k++) { mask[k] = -1; }
|
||||
|
||||
/* Which pillar points should we use? */
|
||||
if (a1[1] > b1[1]){ mask[0] = b1[1]; } else { mask[0] = a1[1]; }
|
||||
if (a2[1] > b2[1]){ mask[2] = b2[1]; } else { mask[2] = a2[1]; }
|
||||
if (a2[0] > b2[0]){ mask[4] = a2[0]; } else { mask[4] = b2[0]; }
|
||||
if (a1[0] > b1[0]){ mask[6] = a1[0]; } else { mask[6] = b1[0]; }
|
||||
|
||||
#if DEBUG
|
||||
/* Illegal situations */
|
||||
if (mask [0] == mask[2] ||
|
||||
mask [0] == mask[4] ||
|
||||
mask [2] == mask[6] ||
|
||||
mask [4] == mask[6]){
|
||||
fprintf(stderr, "Illegal Partial pinch!\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* Partial pinch of face */
|
||||
if (mask[0] == mask[6]){
|
||||
mask[6] = -1;
|
||||
}
|
||||
|
||||
|
||||
if (mask[2] == mask[4]){
|
||||
mask[4] = -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Get shape of face: */
|
||||
/* each new intersection will be part of the new face, */
|
||||
/* but not all pillar points. This is encoded in mask. */
|
||||
|
||||
|
||||
mask[1] = intersect[3]; /* top-top */
|
||||
mask[3] = -1;
|
||||
mask[5] = intersect[0]; /* bottom-bottom*/
|
||||
mask[7] = -1;
|
||||
|
||||
/* bottom-top */
|
||||
if (intersect[1] != -1){
|
||||
if(a1[0] > b1[1]){ /* intersection[1] left of (any) intersection[0] */
|
||||
mask[0] = -1;
|
||||
mask[6] = -1;
|
||||
mask[7] = intersect[1];
|
||||
}
|
||||
else{
|
||||
mask[2] = -1;
|
||||
mask[4] = -1;
|
||||
mask[3] = intersect[1];
|
||||
}
|
||||
}
|
||||
|
||||
/* top-bottom */
|
||||
if (intersect[2] != -1){
|
||||
if(a1[1] < b1[0]){ /* intersection[2] left of (any) intersection[3] */
|
||||
mask[0] = -1;
|
||||
mask[6] = -1;
|
||||
mask[7] = intersect[2];
|
||||
}
|
||||
else{
|
||||
mask[2] = -1;
|
||||
mask[4] = -1;
|
||||
mask[3] = intersect[2];
|
||||
}
|
||||
}
|
||||
f = faces;
|
||||
for (k=7; k>=0; --k){
|
||||
if(mask[k] != -1){
|
||||
*f++ = mask[k];
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG>1
|
||||
/* Check for repeated nodes:*/
|
||||
int i;
|
||||
fprintf(stderr, "face: ");
|
||||
for (i=0; i<8; ++i){
|
||||
fprintf(stderr, "%d ", mask[i]);
|
||||
for (k=0; k<8; ++k){
|
||||
if (i!=k && mask[i] != -1 && mask[i] == mask[k]){
|
||||
fprintf(stderr, "Repeated node in faulted face\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
|
||||
|
||||
return f;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* a) If we assume that the index increase when z increase for each
|
||||
pillar (but only separately), we can use only the point indices,
|
||||
since we only need to compare z-values on one pillar at a time.
|
||||
|
||||
b) We assume input is preprocessed such that no intersections occur
|
||||
on the first and last lines, for instance by padding the grid with
|
||||
extra cells. This is convenient in the identification of (unique)
|
||||
intersections.
|
||||
|
||||
*/
|
||||
|
||||
#define LINE_INTERSECTION(a1, a2, b1, b2) \
|
||||
(((a1 > b1) && (a2 < b2)) || \
|
||||
((a1 < b1) && (a2 > b2)))
|
||||
|
||||
static int
|
||||
faceintersection(const int *a1, const int *a2,
|
||||
const int *b1, const int *b2)
|
||||
{
|
||||
return
|
||||
MAX(a1[0], b1[0]) < MIN(a1[1], b1[1]) ||
|
||||
MAX(a2[0], b2[0]) < MIN(a2[1], b2[1]) ||
|
||||
LINE_INTERSECTION(a1[0], a2[0], b1[0], b2[0]) ||
|
||||
LINE_INTERSECTION(a1[1], a2[1], b1[1], b2[1]);
|
||||
}
|
||||
|
||||
|
||||
#define MEANINGFUL_FACE(i, j) \
|
||||
(! ((a1[i] == INT_MIN) && (b1[j] == INT_MIN)) && \
|
||||
! ((a1[i+1] == INT_MAX) && (b1[j+1] == INT_MAX)))
|
||||
|
||||
|
||||
/* work should be pointer to 2n ints initialised to zero . */
|
||||
void findconnections(int n, int *pts[4],
|
||||
int *intersectionlist,
|
||||
int *work,
|
||||
struct processed_grid *out)
|
||||
{
|
||||
/* vectors of point numbers for faces a(b) on pillar 1(2) */
|
||||
int *a1 = pts[0];
|
||||
int *a2 = pts[1];
|
||||
int *b1 = pts[2];
|
||||
int *b2 = pts[3];
|
||||
|
||||
/* Intersection record for top line and bottomline of a */
|
||||
int *itop = work;
|
||||
int *ibottom = work + n;
|
||||
int *f = out->face_nodes + out->face_ptr[out->number_of_faces];
|
||||
int *c = out->face_neighbors + 2*out->number_of_faces;
|
||||
|
||||
int k1 = 0;
|
||||
int k2 = 0;
|
||||
|
||||
int i,j=0;
|
||||
int intersect[4];
|
||||
int *tmp;
|
||||
/* for (i=0; i<2*n; work[i++]=-1); */
|
||||
|
||||
for (i = 0; i < 4; i++) { intersect[i] = -1; }
|
||||
|
||||
for (i = 0; i < n - 1; ++i) {
|
||||
|
||||
/* pinched a-cell */
|
||||
if ((a1[i] == a1[i + 1]) &&
|
||||
(a2[i] == a2[i + 1])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
while ((j < n-1) &&
|
||||
((b1[j] < a1[i + 1]) ||
|
||||
(b2[j] < a2[i + 1])))
|
||||
{
|
||||
/* pinched b-cell */
|
||||
if ((b1[j] == b1[j + 1]) &&
|
||||
(b2[j] == b2[j + 1])) {
|
||||
|
||||
itop[j+1] = itop[j];
|
||||
++j;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
/* --------------------------------------------------------- */
|
||||
/* face a(i,i+1) and face b(j,j+1) have nonzero intersection */
|
||||
/* --------------------------------------------------------- */
|
||||
if (faceintersection(a1+i, a2+i, b1+j, b2+j)){
|
||||
|
||||
|
||||
/* Completely matching faces */
|
||||
if (((a1[i] == b1[j]) && (a1[i+1] == b1[j+1])) &&
|
||||
((a2[i] == b2[j]) && (a2[i+1] == b2[j+1]))) {
|
||||
|
||||
if (MEANINGFUL_FACE(i, j)) {
|
||||
|
||||
int cell_a = i%2 != 0 ? (i-1)/2 : -1;
|
||||
int cell_b = j%2 != 0 ? (j-1)/2 : -1;
|
||||
|
||||
if (cell_a != -1 || cell_b != -1){
|
||||
*c++ = cell_a;
|
||||
*c++ = cell_b;
|
||||
|
||||
/* face */
|
||||
*f++ = a1[i];
|
||||
*f++ = a2[i];
|
||||
|
||||
/* avoid duplicating nodes in pinched faces */
|
||||
if (a2[i+1] != a2[i]) { *f++ = a2[i+1]; }
|
||||
if (a1[i+1] != a1[i]) { *f++ = a1[i+1]; }
|
||||
|
||||
out->face_ptr[++out->number_of_faces] = f - out->face_nodes;
|
||||
|
||||
}
|
||||
else{
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Non-matching faces */
|
||||
else{
|
||||
|
||||
/* Find new intersection */
|
||||
if (LINE_INTERSECTION(a1[i+1], a2[i+1],
|
||||
b1[j+1], b2[j+1])) {
|
||||
itop[j+1] = out->number_of_nodes++;
|
||||
|
||||
/* store point numbers of intersecting lines */
|
||||
*intersectionlist++ = a1[i+1];
|
||||
*intersectionlist++ = a2[i+1];
|
||||
*intersectionlist++ = b1[j+1];
|
||||
*intersectionlist++ = b2[j+1];
|
||||
|
||||
|
||||
}else{
|
||||
itop[j+1] = -1;
|
||||
}
|
||||
|
||||
/* Update intersection record */
|
||||
intersect[0] = ibottom[j ]; /* i x j */
|
||||
intersect[1] = ibottom[j+1]; /* i x j+1 */
|
||||
intersect[2] = itop[j ]; /* i+1 x j */
|
||||
intersect[3] = itop[j+1]; /* i+1 x j+1 */
|
||||
|
||||
|
||||
/* Add face to list of faces if no INT_MIN or
|
||||
* INT_MAX appear in a or b. */
|
||||
if (MEANINGFUL_FACE(i,j)) {
|
||||
|
||||
/*
|
||||
Even indices refer to space between cells,
|
||||
odd indices refer to cells
|
||||
*/
|
||||
int cell_a = i%2 != 0 ? (i-1)/2 : -1;
|
||||
int cell_b = j%2 != 0 ? (j-1)/2 : -1;
|
||||
|
||||
|
||||
|
||||
if (cell_a != -1 || cell_b != -1){
|
||||
*c++ = cell_a;
|
||||
*c++ = cell_b;
|
||||
|
||||
f = computeFaceTopology(a1+i, a2+i, b1+j, b2+j, intersect, f);
|
||||
|
||||
out->face_ptr[++out->number_of_faces] = f - out->face_nodes;
|
||||
}
|
||||
else{
|
||||
;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Update candidates for restart of j for in next i-iteration */
|
||||
if (b1[j] < a1[i+1]) { k1 = j; }
|
||||
if (b2[j] < a2[i+1]) { k2 = j; }
|
||||
|
||||
j = j+1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Swap intersection records: top line of a[i,i+1] is bottom
|
||||
* line of a[i+1,i+2] */
|
||||
tmp = itop; itop = ibottom; ibottom = tmp;
|
||||
|
||||
/* Zero out the "new" itop */
|
||||
for(j=0;j<n; ++j) { itop[j]=-1; }
|
||||
|
||||
/* Set j to appropriate start position for next i */
|
||||
j = MIN(k1, k2);
|
||||
}
|
||||
}
|
||||
|
||||
/* Local Variables: */
|
||||
/* c-basic-offset:4 */
|
||||
/* End: */
|
|
@ -1,48 +0,0 @@
|
|||
/*===========================================================================
|
||||
//
|
||||
// File: facetopology.h
|
||||
//
|
||||
// Created: Fri Jun 19 08:47:10 2009
|
||||
//
|
||||
// Author: Jostein R. Natvig <Jostein.R.Natvig@sintef.no>
|
||||
//
|
||||
// $Date$
|
||||
//
|
||||
// $Revision$
|
||||
//
|
||||
//===========================================================================*/
|
||||
|
||||
/*
|
||||
Copyright 2009, 2010 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2009, 2010 Statoil ASA.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef OPM_FACETOPOLOGY_HEADER
|
||||
#define OPM_FACETOPOLOGY_HEADER
|
||||
|
||||
|
||||
void findconnections(int n, int *pts[4],
|
||||
int *intersectionlist,
|
||||
int *work,
|
||||
struct processed_grid *out);
|
||||
|
||||
#endif /* OPM_FACETOPOLOGY_HEADER */
|
||||
|
||||
/* Local Variables: */
|
||||
/* c-basic-offset:4 */
|
||||
/* End: */
|
|
@ -1,460 +0,0 @@
|
|||
/*
|
||||
* Copyright 2010 (c) SINTEF ICT, Applied Mathematics.
|
||||
* Jostein R. Natvig <Jostein.R.Natvig at sintef.no>
|
||||
*/
|
||||
#include "config.h"
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include "geometry.h"
|
||||
#include <assert.h>
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
static void
|
||||
cross(const double u[3], const double v[3], double w[3])
|
||||
/* ------------------------------------------------------------------ */
|
||||
{
|
||||
w[0] = u[1]*v[2]-u[2]*v[1];
|
||||
w[1] = u[2]*v[0]-u[0]*v[2];
|
||||
w[2] = u[0]*v[1]-u[1]*v[0];
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
static double
|
||||
norm(const double w[3])
|
||||
/* ------------------------------------------------------------------ */
|
||||
{
|
||||
return sqrt(w[0]*w[0] + w[1]*w[1] + w[2]*w[2]);
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
static void
|
||||
compute_face_geometry_3d(double *coords, int nfaces,
|
||||
int *nodepos, int *facenodes, double *fnormals,
|
||||
double *fcentroids, double *fareas)
|
||||
/* ------------------------------------------------------------------ */
|
||||
{
|
||||
|
||||
/* Assume 3D for now */
|
||||
const int ndims = 3;
|
||||
int f;
|
||||
double x[3];
|
||||
double u[3];
|
||||
double v[3];
|
||||
double w[3];
|
||||
|
||||
int i,k;
|
||||
int node;
|
||||
|
||||
double cface[3] = {0};
|
||||
double n[3] = {0};
|
||||
double twothirds = 0.666666666666666666666666666667;
|
||||
double a;
|
||||
int num_face_nodes;
|
||||
double area;
|
||||
/*#pragma omp parallel for */
|
||||
|
||||
/*#pragma omp parallel for shared(fnormals,fcentroids,fareas)*/
|
||||
#pragma omp parallel for default(none) \
|
||||
private(f,x,u,v,w,i,k,node,cface,n,a,num_face_nodes,area) \
|
||||
shared(fnormals,fcentroids,fareas \
|
||||
,coords, nfaces, nodepos, facenodes, twothirds)
|
||||
for (f=0; f<nfaces; ++f)
|
||||
{
|
||||
for(i=0; i<ndims; ++i) x[i] = 0.0;
|
||||
for(i=0; i<ndims; ++i) n[i] = 0.0;
|
||||
for(i=0; i<ndims; ++i) cface[i] = 0.0;
|
||||
|
||||
/* average node */
|
||||
for(k=nodepos[f]; k<nodepos[f+1]; ++k)
|
||||
{
|
||||
node = facenodes[k];
|
||||
for (i=0; i<ndims; ++i) x[i] += coords[3*node+i];
|
||||
}
|
||||
num_face_nodes = nodepos[f+1] - nodepos[f];
|
||||
for(i=0; i<ndims; ++i) x[i] /= num_face_nodes;
|
||||
|
||||
|
||||
|
||||
/* compute first vector u (to the last node in the face) */
|
||||
node = facenodes[nodepos[f+1]-1];
|
||||
for(i=0; i<ndims; ++i) u[i] = coords[3*node+i] - x[i];
|
||||
|
||||
area=0.0;
|
||||
/* Compute triangular contrib. to face normal and face centroid*/
|
||||
for(k=nodepos[f]; k<nodepos[f+1]; ++k)
|
||||
{
|
||||
|
||||
|
||||
node = facenodes[k];
|
||||
for (i=0; i<ndims; ++i) v[i] = coords[3*node+i] - x[i];
|
||||
|
||||
cross(u,v,w);
|
||||
a = 0.5*norm(w);
|
||||
area += a;
|
||||
/* if(!(a>0))
|
||||
{
|
||||
fprintf(stderr, "Internal error in compute_face_geometry.");
|
||||
}
|
||||
*/
|
||||
/* face normal */
|
||||
for (i=0; i<ndims; ++i) n[i] += w[i];
|
||||
|
||||
/* face centroid */
|
||||
for (i=0; i<ndims; ++i)
|
||||
cface[i] += a*(x[i]+twothirds*0.5*(u[i]+v[i]));
|
||||
|
||||
/* Store v in u for next iteration */
|
||||
for (i=0; i<ndims; ++i) u[i] = v[i];
|
||||
}
|
||||
|
||||
/* Store face normal and face centroid */
|
||||
for (i=0; i<ndims; ++i)
|
||||
{
|
||||
/* normal is scaled with face area */
|
||||
fnormals [3*f+i] = 0.5*n[i];
|
||||
fcentroids[3*f+i] = cface[i]/area;
|
||||
}
|
||||
fareas[f] = area;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
static void
|
||||
compute_edge_geometry_2d(
|
||||
/* in */ double *node_coords,
|
||||
/* in */ int num_edges,
|
||||
/* in */ int *edge_node_pos,
|
||||
/* in */ int *edge_nodes,
|
||||
/* out */ double *edge_normals,
|
||||
/* out */ double *edge_midpoints,
|
||||
/* out */ double *edge_lengths)
|
||||
{
|
||||
const int num_dims = 2;
|
||||
|
||||
/* offsets to each of the nodes in a compacted edge */
|
||||
const int a_ofs = 0;
|
||||
const int b_ofs = 1;
|
||||
|
||||
/* offsets to each dimension is a compacted point */
|
||||
const int x_ofs = 0;
|
||||
const int y_ofs = 1;
|
||||
|
||||
int edge; /* edge index */
|
||||
int a_nod, b_nod; /* node indices */
|
||||
double a_x, a_y, b_x, b_y; /* node coordinates */
|
||||
double v_x, v_y; /* vector elements */
|
||||
|
||||
/* decompose each edge into a tuple (a,b) between two points and
|
||||
* compute properties for that face. hopefully the host has enough
|
||||
* cache pages to keep both input and output at the same time, and
|
||||
* registers for all the local variables */
|
||||
for (edge = 0; edge < num_edges; ++edge)
|
||||
{
|
||||
/* an edge in 2D can only have starting and ending point
|
||||
* check that there are exactly two nodes till the next edge */
|
||||
assert (edge_node_pos[edge + 1] - edge_node_pos[edge] == num_dims);
|
||||
|
||||
/* get the first and last point on the edge */
|
||||
a_nod = edge_nodes[edge_node_pos[edge] + a_ofs];
|
||||
b_nod = edge_nodes[edge_node_pos[edge] + b_ofs];
|
||||
|
||||
/* extract individual coordinates for the points */
|
||||
a_x = node_coords[a_nod * num_dims + x_ofs];
|
||||
a_y = node_coords[a_nod * num_dims + y_ofs];
|
||||
b_x = node_coords[b_nod * num_dims + x_ofs];
|
||||
b_y = node_coords[b_nod * num_dims + y_ofs];
|
||||
|
||||
/* compute edge center -- average of node coordinates */
|
||||
edge_midpoints[edge * num_dims + x_ofs] = (a_x + b_x) * 0.5;
|
||||
edge_midpoints[edge * num_dims + y_ofs] = (a_y + b_y) * 0.5;
|
||||
|
||||
/* vector from first to last point */
|
||||
v_x = b_x - a_x;
|
||||
v_y = b_y - a_y;
|
||||
|
||||
/* two-dimensional (unary) cross product analog that makes the
|
||||
* "triple" (dot-cross) product zero, i.e. it's a normal; the
|
||||
* direction of this vector is such that it will be pointing
|
||||
* inwards when enumerating nodes clock-wise */
|
||||
edge_normals[edge * num_dims + x_ofs] = +v_y;
|
||||
edge_normals[edge * num_dims + y_ofs] = -v_x;
|
||||
|
||||
/* Euclidian norm in two dimensions is magnitude of edge */
|
||||
edge_lengths[edge] = sqrt(v_x*v_x + v_y*v_y);
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
void
|
||||
compute_face_geometry(int ndims, double *coords, int nfaces,
|
||||
int *nodepos, int *facenodes, double *fnormals,
|
||||
double *fcentroids, double *fareas)
|
||||
/* ------------------------------------------------------------------ */
|
||||
{
|
||||
if (ndims == 3)
|
||||
{
|
||||
compute_face_geometry_3d(coords, nfaces, nodepos, facenodes,
|
||||
fnormals, fcentroids, fareas);
|
||||
}
|
||||
else if (ndims == 2)
|
||||
{
|
||||
/* two-dimensional interfaces are called 'edges' */
|
||||
compute_edge_geometry_2d(coords, nfaces, nodepos, facenodes,
|
||||
fnormals, fcentroids, fareas);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
static void
|
||||
compute_cell_geometry_3d(double *coords,
|
||||
int *nodepos, int *facenodes, int *neighbors,
|
||||
double *fnormals,
|
||||
double *fcentroids,
|
||||
int ncells, int *facepos, int *cellfaces,
|
||||
double *ccentroids, double *cvolumes)
|
||||
/* ------------------------------------------------------------------ */
|
||||
{
|
||||
const int ndims = 3;
|
||||
int i,k, f,c;
|
||||
int face,node;
|
||||
double x[3];
|
||||
double u[3];
|
||||
double v[3];
|
||||
double w[3];
|
||||
double xcell[3];
|
||||
double ccell[3];
|
||||
double cface[3] = {0};
|
||||
int num_faces;
|
||||
double volume;
|
||||
double tet_volume, subnormal_sign;
|
||||
double twothirds = 0.666666666666666666666666666667;
|
||||
#pragma omp parallel for default(none) \
|
||||
private(i,k,f,c,face,node,x,u,v,w,xcell \
|
||||
,ccell ,cface,num_faces,volume, tet_volume, subnormal_sign) \
|
||||
shared(coords,nodepos,facenodes,neighbors,twothirds, \
|
||||
fnormals,fcentroids,facepos,cellfaces,ccentroids,cvolumes) \
|
||||
firstprivate(ncells)
|
||||
for (c=0; c<ncells; ++c)
|
||||
{
|
||||
|
||||
|
||||
for(i=0; i<ndims; ++i) xcell[i] = 0.0;
|
||||
for(i=0; i<ndims; ++i) ccell[i] = 0.0;
|
||||
|
||||
|
||||
/*
|
||||
* Approximate cell center as average of face centroids
|
||||
*/
|
||||
for(f=facepos[c]; f<facepos[c+1]; ++f)
|
||||
{
|
||||
face = cellfaces[f];
|
||||
for (i=0; i<ndims; ++i) xcell[i] += fcentroids[3*face+i];
|
||||
}
|
||||
num_faces = facepos[c+1] - facepos[c];
|
||||
|
||||
for(i=0; i<ndims; ++i) xcell[i] /= num_faces;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* For all faces, add tetrahedron's volume and centroid to
|
||||
* 'cvolume' and 'ccentroid'.
|
||||
*/
|
||||
volume=0.0;
|
||||
for(f=facepos[c]; f<facepos[c+1]; ++f)
|
||||
{
|
||||
int num_face_nodes;
|
||||
|
||||
for(i=0; i<ndims; ++i) x[i] = 0.0;
|
||||
for(i=0; i<ndims; ++i) cface[i] = 0.0;
|
||||
|
||||
face = cellfaces[f];
|
||||
|
||||
/* average face node x */
|
||||
for(k=nodepos[face]; k<nodepos[face+1]; ++k)
|
||||
{
|
||||
node = facenodes[k];
|
||||
for (i=0; i<ndims; ++i) x[i] += coords[3*node+i];
|
||||
}
|
||||
num_face_nodes = nodepos[face+1] - nodepos[face];
|
||||
for(i=0; i<ndims; ++i) x[i] /= num_face_nodes;
|
||||
|
||||
|
||||
|
||||
/* compute first vector u (to the last node in the face) */
|
||||
node = facenodes[nodepos[face+1]-1];
|
||||
for(i=0; i<ndims; ++i) u[i] = coords[3*node+i] - x[i];
|
||||
|
||||
|
||||
/* Compute triangular contributions to face normal and face centroid */
|
||||
for(k=nodepos[face]; k<nodepos[face+1]; ++k)
|
||||
{
|
||||
|
||||
node = facenodes[k];
|
||||
for (i=0; i<ndims; ++i) v[i] = coords[3*node+i] - x[i];
|
||||
|
||||
cross(u,v,w);
|
||||
|
||||
|
||||
|
||||
tet_volume = 0.0;
|
||||
for(i=0; i<ndims; ++i){
|
||||
tet_volume += w[i]*(x[i]-xcell[i]);
|
||||
}
|
||||
tet_volume *= 0.5 / 3;
|
||||
|
||||
subnormal_sign=0.0;
|
||||
for(i=0; i<ndims; ++i){
|
||||
subnormal_sign += w[i]*fnormals[3*face+i];
|
||||
}
|
||||
|
||||
if(subnormal_sign < 0.0){
|
||||
tet_volume = -tet_volume;
|
||||
}
|
||||
if(!(neighbors[2*face+0]==c)){
|
||||
tet_volume = -tet_volume;
|
||||
}
|
||||
volume += tet_volume;
|
||||
/* face centroid of triangle */
|
||||
for (i=0; i<ndims; ++i) cface[i] = (x[i]+(twothirds)*0.5*(u[i]+v[i]));
|
||||
|
||||
/* Cell centroid */
|
||||
for (i=0; i<ndims; ++i) ccell[i] += tet_volume * 3/4.0*(cface[i] - xcell[i]);
|
||||
|
||||
|
||||
/* Store v in u for next iteration */
|
||||
for (i=0; i<ndims; ++i) u[i] = v[i];
|
||||
}
|
||||
}
|
||||
for (i=0; i<ndims; ++i) ccentroids[3*c+i] = xcell[i] + ccell[i]/volume;
|
||||
cvolumes[c] = volume;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
static void
|
||||
compute_cell_geometry_2d(
|
||||
/* in */ double *node_coords,
|
||||
/* in */ int *edge_node_pos,
|
||||
/* in */ int *edge_nodes,
|
||||
/* in */ double *edge_midpoints,
|
||||
/* in */ int num_cells,
|
||||
/* in */ int *cell_edge_pos,
|
||||
/* in */ int *cell_edges,
|
||||
/* out */ double *cell_centers,
|
||||
/* out */ double *cell_areas)
|
||||
{
|
||||
const int num_dims = 2;
|
||||
|
||||
/* offsets to each of the nodes in a compacted edge */
|
||||
const int a_ofs = 0;
|
||||
const int b_ofs = 1;
|
||||
|
||||
/* offsets to each dimension is a compacted point */
|
||||
const int x_ofs = 0;
|
||||
const int y_ofs = 1;
|
||||
|
||||
int cell; /* cell index */
|
||||
int num_nodes; /* number of vertices in current cell */
|
||||
int edge_ndx; /* relative edge index within cell */
|
||||
int edge; /* absolute cell index */
|
||||
double center_x; /* x-coordinate for cell barycenter */
|
||||
double center_y; /* y-coordinate for cell barycenter */
|
||||
double area; /* (accumulated) cell area */
|
||||
int a_nod, b_nod; /* node indices for edge start and end points */
|
||||
double a_x, a_y,
|
||||
b_x, b_y; /* vectors from center to edge points */
|
||||
|
||||
for (cell = 0; cell < num_cells; ++cell)
|
||||
{
|
||||
/* since the cell is a closed polygon, each point serves as the starting
|
||||
* point of one edge and the ending point of another; thus there is as
|
||||
* many vertices as there are edges */
|
||||
num_nodes = cell_edge_pos[cell + 1] - cell_edge_pos[cell];
|
||||
|
||||
/* to enumerate all vertices of a cell, we would have to expand the
|
||||
* edges and then remove duplicates. however, the centroid of each
|
||||
* edge contains half of the two vertices that are incident on it. if
|
||||
* we instead sum all the face centroids, we get the sum of all the
|
||||
* vertices */
|
||||
center_x = 0.;
|
||||
center_y = 0.;
|
||||
for (edge_ndx = cell_edge_pos[cell];
|
||||
edge_ndx < cell_edge_pos[cell + 1]; ++edge_ndx)
|
||||
{
|
||||
edge = cell_edges[edge_ndx];
|
||||
center_x += edge_midpoints[edge * num_dims + x_ofs];
|
||||
center_y += edge_midpoints[edge * num_dims + y_ofs];
|
||||
}
|
||||
center_x /= (double) num_nodes;
|
||||
center_y /= (double) num_nodes;
|
||||
cell_centers[cell * num_dims + x_ofs] = center_x;
|
||||
cell_centers[cell * num_dims + y_ofs] = center_y;
|
||||
|
||||
/* triangulate the polygon by introducing the cell center and then new
|
||||
* internal edges from this center to the vertices. the total area of
|
||||
* the cell is the sum of area of these sub-triangles */
|
||||
area = 0.;
|
||||
for (edge_ndx = cell_edge_pos[cell];
|
||||
edge_ndx < cell_edge_pos[cell + 1]; ++edge_ndx)
|
||||
{
|
||||
/* indirect lookup of edge index (from array that contains all the
|
||||
* edge indices for a certain cell) */
|
||||
edge = cell_edges[edge_ndx];
|
||||
|
||||
/* get the first and last point on the edge */
|
||||
a_nod = edge_nodes[edge_node_pos[edge] + a_ofs];
|
||||
b_nod = edge_nodes[edge_node_pos[edge] + b_ofs];
|
||||
|
||||
/* vector from center to each of the nodes */
|
||||
a_x = node_coords[a_nod * num_dims + x_ofs] - center_x;
|
||||
a_y = node_coords[a_nod * num_dims + y_ofs] - center_y;
|
||||
b_x = node_coords[b_nod * num_dims + x_ofs] - center_x;
|
||||
b_y = node_coords[b_nod * num_dims + y_ofs] - center_y;
|
||||
|
||||
/* two-dimensional (binary) cross product analog that has length
|
||||
* equal to the parallelogram spanned by the two vectors (but which
|
||||
* is a scalar). the sign tells us the orientation between the nodes
|
||||
* a and b, but we are not interested in that, just the area */
|
||||
area += fabs(a_x * b_y - a_y * b_x);
|
||||
}
|
||||
/* we summed parallelograms which are twice the size of the triangles
|
||||
* that make up the cell; divide out the half for all terms here */
|
||||
area *= 0.5;
|
||||
cell_areas[cell] = area;
|
||||
}
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
void
|
||||
compute_cell_geometry(int ndims, double *coords,
|
||||
int *nodepos, int *facenodes, int *neighbors,
|
||||
double *fnormals,
|
||||
double *fcentroids,
|
||||
int ncells, int *facepos, int *cellfaces,
|
||||
double *ccentroids, double *cvolumes)
|
||||
/* ------------------------------------------------------------------ */
|
||||
{
|
||||
if (ndims == 3)
|
||||
{
|
||||
compute_cell_geometry_3d(coords, nodepos, facenodes,
|
||||
neighbors, fnormals, fcentroids, ncells,
|
||||
facepos, cellfaces, ccentroids, cvolumes);
|
||||
}
|
||||
else if (ndims == 2)
|
||||
{
|
||||
compute_cell_geometry_2d(coords, nodepos, facenodes, fcentroids,
|
||||
ncells, facepos, cellfaces, ccentroids,
|
||||
cvolumes);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0);
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
/*
|
||||
* Copyright 2010 (c) SINTEF ICT, Applied Mathematics.
|
||||
* Jostein R. Natvig <Jostein.R.Natvig at sintef.no>
|
||||
*/
|
||||
#ifndef MRST_GEOMETRY_H_INCLUDED
|
||||
#define MRST_GEOMETRY_H_INCLUDED
|
||||
|
||||
void compute_face_geometry(int ndims, double *coords, int nfaces,
|
||||
int *nodepos, int *facenodes,
|
||||
double *fnormals, double *fcentroids,
|
||||
double *fareas);
|
||||
void compute_cell_geometry(int ndims, double *coords,
|
||||
int *nodepos, int *facenodes, int *neighbours,
|
||||
double *fnormals,
|
||||
double *fcentroids, int ncells,
|
||||
int *facepos, int *cellfaces,
|
||||
double *ccentroids, double *cvolumes);
|
||||
|
||||
#endif /* MRST_GEOMETRY_H_INCLUDED */
|
|
@ -1,956 +0,0 @@
|
|||
/*===========================================================================
|
||||
//
|
||||
// File: preprocess.c
|
||||
//
|
||||
// Created: Fri Jun 19 08:42:39 2009
|
||||
//
|
||||
// Author: Jostein R. Natvig <Jostein.R.Natvig@sintef.no>
|
||||
//
|
||||
// $Date$
|
||||
//
|
||||
// $Revision$
|
||||
//
|
||||
//==========================================================================*/
|
||||
|
||||
/*
|
||||
Copyright 2009, 2010, 2011, 2012 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2009, 2010, 2011, 2012 Statoil ASA.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <assert.h>
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "preprocess.h"
|
||||
#include "uniquepoints.h"
|
||||
#include "facetopology.h"
|
||||
|
||||
|
||||
#define MIN(i,j) ((i)<(j) ? (i) : (j))
|
||||
#define MAX(i,j) ((i)>(j) ? (i) : (j))
|
||||
|
||||
static void
|
||||
compute_cell_index(const int dims[3], int i, int j, int *neighbors, int len);
|
||||
|
||||
static int
|
||||
checkmemory(int nz, struct processed_grid *out, int **intersections);
|
||||
|
||||
static void
|
||||
process_vertical_faces(int direction,
|
||||
int **intersections,
|
||||
int *plist, int *work,
|
||||
struct processed_grid *out);
|
||||
|
||||
static void
|
||||
process_horizontal_faces(int **intersections,
|
||||
int *plist,
|
||||
struct processed_grid *out);
|
||||
|
||||
static int
|
||||
linearindex(const int dims[3], int i, int j, int k)
|
||||
{
|
||||
assert (0 <= i);
|
||||
assert (0 <= j);
|
||||
assert (0 <= k);
|
||||
|
||||
assert (i < dims[0]);
|
||||
assert (j < dims[1]);
|
||||
assert (k < dims[2]);
|
||||
|
||||
return i + dims[0]*(j + dims[1]*k);
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
Given a vector <field> with k index running faster than i running
|
||||
faster than j, and Cartesian dimensions <dims>, find pointers to the
|
||||
(i-1, j-1, 0), (i-1, j, 0), (i, j-1, 0) and (i, j, 0) elements of
|
||||
field. */
|
||||
static void
|
||||
igetvectors(int dims[3], int i, int j, int *field, int *v[])
|
||||
{
|
||||
int im = MAX(1, i ) - 1;
|
||||
int ip = MIN(dims[0], i+1) - 1;
|
||||
int jm = MAX(1, j ) - 1;
|
||||
int jp = MIN(dims[1], j+1) - 1;
|
||||
|
||||
v[0] = field + dims[2]*(im + dims[0]* jm);
|
||||
v[1] = field + dims[2]*(im + dims[0]* jp);
|
||||
v[2] = field + dims[2]*(ip + dims[0]* jm);
|
||||
v[3] = field + dims[2]*(ip + dims[0]* jp);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
Special purpose
|
||||
|
||||
Convert from k-index to Cartesian index i+nx*(j+ny*k) for every
|
||||
other element in neighbors.
|
||||
|
||||
*/
|
||||
static void
|
||||
compute_cell_index(const int dims[3], int i, int j,
|
||||
int *neighbors, int len)
|
||||
{
|
||||
int k;
|
||||
|
||||
if (((i < 0) || (i >= dims[0])) || /* 'i' outside [0, dims[0]) */
|
||||
((j < 0) || (j >= dims[1]))) { /* 'j' outside [0, dims[1]) */
|
||||
|
||||
for (k = 0; k < len; k += 2) {
|
||||
neighbors[k] = -1; /* Neighbour is outside domain */
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (k = 0; k < len; k += 2) {
|
||||
if (neighbors[k] != -1) {
|
||||
neighbors[k] = linearindex(dims, i, j, neighbors[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
Ensure there's sufficient memory */
|
||||
static int
|
||||
checkmemory(int nz, struct processed_grid *out, int **intersections)
|
||||
{
|
||||
int r, m, n, ok;
|
||||
|
||||
/* Ensure there is enough space to manage the (pathological) case
|
||||
* of every single cell on one side of a fault connecting to all
|
||||
* cells on the other side of the fault (i.e., an all-to-all cell
|
||||
* connectivity pairing). */
|
||||
r = (2*nz + 2) * (2*nz + 2);
|
||||
m = out->m;
|
||||
n = out->n;
|
||||
|
||||
if (out->number_of_faces + r > m) {
|
||||
m += MAX(m / 2, 2 * r);
|
||||
}
|
||||
if (out->face_ptr[out->number_of_faces] + 6*r > n) {
|
||||
n += MAX(n / 2, 12 * r);
|
||||
}
|
||||
|
||||
ok = m == out->m;
|
||||
if (! ok) {
|
||||
void *p1, *p2, *p3, *p4;
|
||||
|
||||
p1 = realloc(*intersections , 4*m * sizeof **intersections);
|
||||
p2 = realloc(out->face_neighbors, 2*m * sizeof *out->face_neighbors);
|
||||
p3 = realloc(out->face_ptr , (m+1) * sizeof *out->face_ptr);
|
||||
p4 = realloc(out->face_tag , 1*m * sizeof *out->face_tag);
|
||||
|
||||
if (p1 != NULL) { *intersections = p1; }
|
||||
if (p2 != NULL) { out->face_neighbors = p2; }
|
||||
if (p3 != NULL) { out->face_ptr = p3; }
|
||||
if (p4 != NULL) { out->face_tag = p4; }
|
||||
|
||||
ok = (p1 != NULL) && (p2 != NULL) && (p3 != NULL) && (p4 != NULL);
|
||||
|
||||
if (ok) { out->m = m; }
|
||||
}
|
||||
|
||||
if (ok && (n != out->n)) {
|
||||
void *p1;
|
||||
|
||||
p1 = realloc(out->face_nodes, n * sizeof *out->face_nodes);
|
||||
|
||||
ok = p1 != NULL;
|
||||
|
||||
if (ok) {
|
||||
out->face_nodes = p1;
|
||||
out->n = n;
|
||||
}
|
||||
}
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
For each vertical face (i.e. i or j constant),
|
||||
-find point numbers for the corners and
|
||||
-cell neighbors.
|
||||
-new points on faults defined by two intgersecting lines.
|
||||
|
||||
direction == 0 : constant-i faces.
|
||||
direction == 1 : constant-j faces.
|
||||
*/
|
||||
static void
|
||||
process_vertical_faces(int direction,
|
||||
int **intersections,
|
||||
int *plist, int *work,
|
||||
struct processed_grid *out)
|
||||
{
|
||||
int i,j;
|
||||
int *cornerpts[4];
|
||||
int d[3];
|
||||
int f;
|
||||
enum face_tag tag[] = { LEFT, BACK };
|
||||
int *tmp;
|
||||
int nx = out->dimensions[0];
|
||||
int ny = out->dimensions[1];
|
||||
int nz = out->dimensions[2];
|
||||
int startface;
|
||||
int num_intersections;
|
||||
int *ptr;
|
||||
int len;
|
||||
|
||||
assert ((direction == 0) || (direction == 1));
|
||||
|
||||
d[0] = 2 * (nx + 0);
|
||||
d[1] = 2 * (ny + 0);
|
||||
d[2] = 2 * (nz + 1);
|
||||
|
||||
for (j = 0; j < ny + direction; ++j) {
|
||||
for (i = 0; i < nx + (1 - direction); ++i) {
|
||||
|
||||
if (! checkmemory(nz, out, intersections)) {
|
||||
fprintf(stderr,
|
||||
"Could not allocate enough space in "
|
||||
"process_vertical_faces()\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* Vectors of point numbers */
|
||||
igetvectors(d, 2*i + direction, 2*j + (1 - direction),
|
||||
plist, cornerpts);
|
||||
|
||||
if (direction == 1) {
|
||||
/* 1 3 0 1 */
|
||||
/* ---> */
|
||||
/* 0 2 2 3 */
|
||||
/* rotate clockwise */
|
||||
tmp = cornerpts[1];
|
||||
cornerpts[1] = cornerpts[0];
|
||||
cornerpts[0] = cornerpts[2];
|
||||
cornerpts[2] = cornerpts[3];
|
||||
cornerpts[3] = tmp;
|
||||
}
|
||||
|
||||
/* int startface = ftab->position; */
|
||||
startface = out->number_of_faces;
|
||||
/* int num_intersections = *npoints - npillarpoints; */
|
||||
num_intersections = out->number_of_nodes -
|
||||
out->number_of_nodes_on_pillars;
|
||||
|
||||
/* Establish new connections (faces) along pillar pair. */
|
||||
findconnections(2*nz + 2, cornerpts,
|
||||
*intersections + 4*num_intersections,
|
||||
work, out);
|
||||
|
||||
/* Start of ->face_neighbors[] for this set of connections. */
|
||||
ptr = out->face_neighbors + 2*startface;
|
||||
|
||||
/* Total number of cells (both sides) connected by this
|
||||
* set of connections (faces). */
|
||||
len = 2*out->number_of_faces - 2*startface;
|
||||
|
||||
/* Derive inter-cell connectivity (i.e. ->face_neighbors)
|
||||
* of global (uncompressed) cells for this set of
|
||||
* connections (faces). */
|
||||
compute_cell_index(out->dimensions, i-1+direction, j-direction, ptr , len);
|
||||
compute_cell_index(out->dimensions, i , j , ptr + 1, len);
|
||||
|
||||
/* Tag the new faces */
|
||||
f = startface;
|
||||
for (; f < out->number_of_faces; ++f) {
|
||||
out->face_tag[f] = tag[direction];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
For each horizontal face (i.e. k constant),
|
||||
-find point numbers for the corners and
|
||||
-cell neighbors.
|
||||
|
||||
Also define map from logically Cartesian
|
||||
cell index to local cell index 0, ..., #<active cells>. Exclude
|
||||
cells that are have collapsed coordinates. (This includes cells with
|
||||
ACTNUM==0)
|
||||
|
||||
*/
|
||||
static void
|
||||
process_horizontal_faces(int **intersections,
|
||||
int *plist,
|
||||
struct processed_grid *out)
|
||||
{
|
||||
int i,j,k;
|
||||
|
||||
int nx = out->dimensions[0];
|
||||
int ny = out->dimensions[1];
|
||||
int nz = out->dimensions[2];
|
||||
|
||||
int *cell = out->local_cell_index;
|
||||
int cellno = 0;
|
||||
int *f, *n, *c[4];
|
||||
int prevcell, thiscell;
|
||||
int idx;
|
||||
|
||||
/* dimensions of plist */
|
||||
int d[3];
|
||||
d[0] = 2*nx;
|
||||
d[1] = 2*ny;
|
||||
d[2] = 2+2*nz;
|
||||
|
||||
|
||||
for(j=0; j<ny; ++j) {
|
||||
for (i=0; i<nx; ++i) {
|
||||
|
||||
|
||||
if (! checkmemory(nz, out, intersections)) {
|
||||
fprintf(stderr,
|
||||
"Could not allocate enough space in "
|
||||
"process_horizontal_faces()\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
f = out->face_nodes + out->face_ptr[out->number_of_faces];
|
||||
n = out->face_neighbors + 2*out->number_of_faces;
|
||||
|
||||
|
||||
/* Vectors of point numbers */
|
||||
igetvectors(d, 2*i+1, 2*j+1, plist, c);
|
||||
|
||||
prevcell = -1;
|
||||
|
||||
|
||||
for (k = 1; k<nz*2+1; ++k){
|
||||
|
||||
/* Skip if space between face k and face k+1 is collapsed. */
|
||||
/* Note that inactive cells (with ACTNUM==0) have all been */
|
||||
/* collapsed in finduniquepoints. */
|
||||
if (c[0][k] == c[0][k+1] && c[1][k] == c[1][k+1] &&
|
||||
c[2][k] == c[2][k+1] && c[3][k] == c[3][k+1]){
|
||||
|
||||
/* If the pinch is a cell: */
|
||||
if (k%2){
|
||||
idx = linearindex(out->dimensions, i,j,(k-1)/2);
|
||||
cell[idx] = -1;
|
||||
}
|
||||
}
|
||||
else{
|
||||
|
||||
if (k%2){
|
||||
/* Add face */
|
||||
*f++ = c[0][k];
|
||||
*f++ = c[2][k];
|
||||
*f++ = c[3][k];
|
||||
*f++ = c[1][k];
|
||||
|
||||
out->face_tag[ out->number_of_faces] = TOP;
|
||||
out->face_ptr[++out->number_of_faces] = f - out->face_nodes;
|
||||
|
||||
thiscell = linearindex(out->dimensions, i,j,(k-1)/2);
|
||||
*n++ = prevcell;
|
||||
*n++ = prevcell = thiscell;
|
||||
|
||||
cell[thiscell] = cellno++;
|
||||
|
||||
}
|
||||
else{
|
||||
if (prevcell != -1){
|
||||
/* Add face */
|
||||
*f++ = c[0][k];
|
||||
*f++ = c[2][k];
|
||||
*f++ = c[3][k];
|
||||
*f++ = c[1][k];
|
||||
|
||||
out->face_tag[ out->number_of_faces] = TOP;
|
||||
out->face_ptr[++out->number_of_faces] = f - out->face_nodes;
|
||||
|
||||
*n++ = prevcell;
|
||||
*n++ = prevcell = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
out->number_of_cells = cellno;
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
On input,
|
||||
L points to 4 ints that indirectly refers to points in c.
|
||||
c points to array of coordinates [x0,y0,z0,x1,y1,z1,...,xn,yn,zn].
|
||||
pt points to array of 3 doubles.
|
||||
|
||||
On output,
|
||||
pt holds coordinates to intersection between lines given by point
|
||||
numbers L[0]-L[1] and L[2]-L[3].
|
||||
*/
|
||||
static void approximate_intersection_pt(int *L, double *c, double *pt)
|
||||
{
|
||||
double a;
|
||||
double z0, z1, z2, z3;
|
||||
double b1, b2;
|
||||
double x1, y1;
|
||||
double x2, y2;
|
||||
double z;
|
||||
|
||||
/* no intersection on pillars expected here! */
|
||||
assert (L[0] != L[2]);
|
||||
assert (L[1] != L[3]);
|
||||
|
||||
z0 = c[3*L[0] + 2];
|
||||
z1 = c[3*L[1] + 2];
|
||||
z2 = c[3*L[2] + 2];
|
||||
z3 = c[3*L[3] + 2];
|
||||
|
||||
/* find parameter a where lines L0L1 and L2L3 have same
|
||||
* z-coordinate */
|
||||
if (fabs((z1 - z0) - (z3 - z2)) > 0.0) {
|
||||
|
||||
a = (z2 - z0) / ((z1 - z0) - (z3 - z2));
|
||||
|
||||
} else {
|
||||
|
||||
a = 0;
|
||||
|
||||
}
|
||||
|
||||
/* the corresponding z-coordinate is */
|
||||
z = z0*(1.0 - a) + z1*a;
|
||||
|
||||
|
||||
/* find point (x1, y1, z) on pillar 1 */
|
||||
b1 = (z2 - z) / (z2 - z0);
|
||||
b2 = (z - z0) / (z2 - z0);
|
||||
x1 = c[3*L[0] + 0]*b1 + c[3*L[2] + 0]*b2;
|
||||
y1 = c[3*L[0] + 1]*b1 + c[3*L[2] + 1]*b2;
|
||||
|
||||
/* find point (x2, y2, z) on pillar 2 */
|
||||
b1 = (z - z3) / (z1 - z3);
|
||||
b2 = (z1 - z) / (z1 - z3);
|
||||
x2 = c[3*L[1] + 0]*b1 + c[3*L[3] + 0]*b2;
|
||||
y2 = c[3*L[1] + 1]*b1 + c[3*L[3] + 1]*b2;
|
||||
|
||||
/* horizontal lines are by definition ON the bilinear surface
|
||||
spanned by L0, L1, L2 and L3. find point (x, y, z) on
|
||||
horizontal line between point (x1, y1, z) and (x2, y2, z).*/
|
||||
pt[0] = x1*(1.0 - a) + x2*a;
|
||||
pt[1] = y1*(1.0 - a) + y2*a;
|
||||
pt[2] = z;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
Compute x,y and z coordinates for points on each pillar. Then,
|
||||
append x,y and z coordinates for extra points on faults. */
|
||||
static void
|
||||
compute_intersection_coordinates(int *intersections,
|
||||
struct processed_grid *out)
|
||||
{
|
||||
int n = out->number_of_nodes;
|
||||
int np = out->number_of_nodes_on_pillars;
|
||||
int k;
|
||||
double *pt;
|
||||
int *itsct = intersections;
|
||||
/* Make sure the space allocated for nodes match the number of
|
||||
* node. */
|
||||
void *p = realloc (out->node_coordinates, 3*n*sizeof(double));
|
||||
if (p) {
|
||||
out->node_coordinates = p;
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "Could not allocate extra space for intersections\n");
|
||||
}
|
||||
|
||||
|
||||
/* Append intersections */
|
||||
pt = out->node_coordinates + 3*np;
|
||||
|
||||
for (k=np; k<n; ++k){
|
||||
approximate_intersection_pt(itsct, out->node_coordinates, pt);
|
||||
pt += 3;
|
||||
itsct += 4;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
static int*
|
||||
copy_and_permute_actnum(int nx, int ny, int nz, const int *in, int *out)
|
||||
/* ------------------------------------------------------------------ */
|
||||
{
|
||||
int i,j,k;
|
||||
int *ptr = out;
|
||||
|
||||
/* Permute actnum such that values of each vertical stack of cells
|
||||
* are adjacent in memory, i.e.,
|
||||
*
|
||||
* out = [in(0,0,:), in(1,0,:),..., in(nx-1, ny-1,:)]
|
||||
*
|
||||
* in MATLAB pseudo-code.
|
||||
*/
|
||||
if (in != NULL) {
|
||||
for (j = 0; j < ny; ++j) {
|
||||
for (i = 0; i < nx; ++i) {
|
||||
for (k = 0; k < nz; ++k) {
|
||||
*ptr++ = in[i + nx*(j + ny*k)];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* No explicit ACTNUM. Assume all cells active. */
|
||||
for (i = 0; i < nx * ny * nz; i++) {
|
||||
out[ i ] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
static double*
|
||||
copy_and_permute_zcorn(int nx, int ny, int nz, const double *in,
|
||||
double sign, double *out)
|
||||
/* ------------------------------------------------------------------ */
|
||||
{
|
||||
int i,j,k;
|
||||
double *ptr = out;
|
||||
/* Permute zcorn such that values of each vertical stack of cells
|
||||
* are adjacent in memory, i.e.,
|
||||
|
||||
out = [in(0,0,:), in(1,0,:),..., in(2*nx-1, 2*ny-1,:)]
|
||||
|
||||
in Matlab pseudo-code.
|
||||
*/
|
||||
for (j=0; j<2*ny; ++j){
|
||||
for (i=0; i<2*nx; ++i){
|
||||
for (k=0; k<2*nz; ++k){
|
||||
*ptr++ = sign * in[i+2*nx*(j+2*ny*k)];
|
||||
}
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
static int
|
||||
get_zcorn_sign(int nx, int ny, int nz, const int *actnum,
|
||||
const double *zcorn, int *error)
|
||||
/* ------------------------------------------------------------------ */
|
||||
{
|
||||
/* Ensure that zcorn (i.e., depth) is strictly nondecreasing in
|
||||
the k-direction. This is required by the processign algorithm.
|
||||
|
||||
1) if z(i,j,k) <= z(i,j,k+1) for all (i,j,k), return 1.0
|
||||
|
||||
2) if -z(i,j,k) <=-z(i,j,k+1) for all (i,j,k), return -1.0
|
||||
|
||||
3) if (1) and (2) fails, return -1.0, and set *error = 1.
|
||||
|
||||
*/
|
||||
int sign;
|
||||
int i, j, k;
|
||||
int c1, c2;
|
||||
double z1, z2;
|
||||
|
||||
for (sign = 1; sign>-2; sign = sign - 2)
|
||||
{
|
||||
*error = 0;
|
||||
|
||||
for (j=0; j<2*ny; ++j){
|
||||
for (i=0; i<2*nx; ++i){
|
||||
for (k=0; k<2*nz-1; ++k){
|
||||
z1 = sign*zcorn[i+2*nx*(j+2*ny*(k))];
|
||||
z2 = sign*zcorn[i+2*nx*(j+2*ny*(k+1))];
|
||||
|
||||
c1 = i/2 + nx*(j/2 + ny*(k/2));
|
||||
c2 = i/2 + nx*(j/2 + ny*((k+1)/2));
|
||||
|
||||
assert (c1 < (nx * ny * nz));
|
||||
assert (c2 < (nx * ny * nz));
|
||||
|
||||
if (((actnum == NULL) ||
|
||||
(actnum[c1] && actnum[c2]))
|
||||
&& (z2 < z1)) {
|
||||
|
||||
fprintf(stderr, "\nZCORN should be strictly "
|
||||
"nondecreasing along pillars!\n");
|
||||
*error = 1;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
if (!*error){
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (*error){
|
||||
fprintf(stderr, "Attempt to reverse sign in ZCORN failed.\n"
|
||||
"Grid definition may be broken\n");
|
||||
}
|
||||
|
||||
return sign;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
ind2sub(const size_t nx,
|
||||
const size_t ny,
|
||||
const size_t nz,
|
||||
size_t c ,
|
||||
size_t *i, size_t *j, size_t *k)
|
||||
{
|
||||
assert (c < (nx * ny * nz));
|
||||
|
||||
#if defined(NDEBUG)
|
||||
(void) nz;
|
||||
#endif
|
||||
|
||||
*i = c % nx; c /= nx;
|
||||
*j = c % ny;
|
||||
*k = c / ny;
|
||||
}
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
static double
|
||||
vert_size(const struct grdecl *in,
|
||||
const size_t c ,
|
||||
const size_t off[8])
|
||||
/* ---------------------------------------------------------------------- */
|
||||
{
|
||||
size_t i, j, k, nx, ny, start;
|
||||
double dz;
|
||||
const double *zcorn;
|
||||
|
||||
nx = in->dims[ 0 ];
|
||||
ny = in->dims[ 1 ];
|
||||
|
||||
ind2sub(nx, ny, in->dims[ 2 ], c, &i, &j, &k);
|
||||
|
||||
zcorn = in->zcorn;
|
||||
start = (2 * i) + (2 * nx)*((2 * j) + (2 * ny)*(2 * k));
|
||||
|
||||
for (k = 0, dz = 0.0; (! (fabs(dz) > 0)) && (k < 4); k++) {
|
||||
dz = zcorn[start + off[k + 4]] - zcorn[start + off[k]];
|
||||
}
|
||||
|
||||
return dz;
|
||||
}
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
static int
|
||||
is_lefthanded(const struct grdecl *in)
|
||||
/* ---------------------------------------------------------------------- */
|
||||
{
|
||||
int active, searching;
|
||||
size_t nx, ny, nz, c;
|
||||
size_t origin, imax, jmax;
|
||||
size_t off[8];
|
||||
double dx[2], dy[2], dz, triple;
|
||||
const double *pt_coord;
|
||||
|
||||
nx = in->dims[0];
|
||||
ny = in->dims[1];
|
||||
nz = in->dims[2];
|
||||
|
||||
off[0] = 0;
|
||||
off[1] = off[0] + 1;
|
||||
off[2] = off[0] + (2 * nx);
|
||||
off[3] = off[2] + 1;
|
||||
off[4] = off[0] + ((2 * nx) * (2 * ny));
|
||||
off[5] = off[4] + 1;
|
||||
off[6] = off[4] + (2 * nx);
|
||||
off[7] = off[6] + 1;
|
||||
|
||||
pt_coord = in->coord;
|
||||
|
||||
origin = 0;
|
||||
imax = (nx + 0) * 1 * (2 * 3);
|
||||
jmax = (nx + 1) * (ny + 0) * (2 * 3);
|
||||
|
||||
dx[0] = pt_coord[imax + 0] - pt_coord[origin + 0];
|
||||
dy[0] = pt_coord[imax + 1] - pt_coord[origin + 1];
|
||||
|
||||
dx[1] = pt_coord[jmax + 0] - pt_coord[origin + 0];
|
||||
dy[1] = pt_coord[jmax + 1] - pt_coord[origin + 1];
|
||||
|
||||
c = 0; dz = 0.0;
|
||||
do {
|
||||
active = (in->actnum == NULL) || (in->actnum[c] != 0);
|
||||
|
||||
if (active) {
|
||||
dz = vert_size(in, c, off);
|
||||
}
|
||||
|
||||
searching = ! (active && (fabs(dz) > 0.0));
|
||||
|
||||
c += 1;
|
||||
} while (searching && (c < (nx * ny * nz)));
|
||||
|
||||
assert (! searching); /* active && (fabs(dz) > 0) */
|
||||
|
||||
/* Compute vector triple product to distinguish left-handed (<0)
|
||||
* from right-handed (>0) coordinate systems. */
|
||||
triple = dz * (dx[0]*dy[1] - dx[1]*dy[0]);
|
||||
|
||||
assert (fabs(triple) > 0.0);
|
||||
|
||||
return triple < 0.0;
|
||||
}
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
static void
|
||||
reverse_face_nodes(struct processed_grid *out)
|
||||
/* ---------------------------------------------------------------------- */
|
||||
{
|
||||
int f, t, *i, *j;
|
||||
|
||||
for (f = 0; f < out->number_of_faces; f++) {
|
||||
i = out->face_nodes + (out->face_ptr[f + 0] + 0);
|
||||
j = out->face_nodes + (out->face_ptr[f + 1] - 1);
|
||||
|
||||
assert (i <= j);
|
||||
|
||||
while (i < j) {
|
||||
t = *i;
|
||||
*i = *j;
|
||||
*j = t;
|
||||
|
||||
i += 1;
|
||||
j -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
Public interface
|
||||
*/
|
||||
void process_grdecl(const struct grdecl *in,
|
||||
double tolerance,
|
||||
struct processed_grid *out)
|
||||
{
|
||||
struct grdecl g;
|
||||
|
||||
size_t i;
|
||||
int sign, error, left_handed;
|
||||
int cellnum;
|
||||
|
||||
int *actnum, *iptr;
|
||||
int *global_cell_index;
|
||||
|
||||
double *zcorn;
|
||||
|
||||
const size_t BIGNUM = 64;
|
||||
const int nx = in->dims[0];
|
||||
const int ny = in->dims[1];
|
||||
const int nz = in->dims[2];
|
||||
const size_t nc = ((size_t) nx) * ((size_t) ny) * ((size_t) nz);
|
||||
|
||||
/* internal work arrays */
|
||||
int *work;
|
||||
int *plist;
|
||||
int *intersections;
|
||||
|
||||
|
||||
|
||||
|
||||
/* -----------------------------------------------------------------*/
|
||||
/* Initialize output structure:
|
||||
1) allocate space for grid topology (which may need to be
|
||||
increased)
|
||||
2) set Cartesian imensions
|
||||
*/
|
||||
out->m = (int) (BIGNUM / 3);
|
||||
out->n = (int) BIGNUM;
|
||||
|
||||
out->face_neighbors = malloc( BIGNUM * sizeof *out->face_neighbors);
|
||||
out->face_nodes = malloc( out->n * sizeof *out->face_nodes);
|
||||
out->face_ptr = malloc((out->m + 1) * sizeof *out->face_ptr);
|
||||
out->face_tag = malloc( out->m * sizeof *out->face_tag);
|
||||
out->face_ptr[0] = 0;
|
||||
|
||||
out->dimensions[0] = in->dims[0];
|
||||
out->dimensions[1] = in->dims[1];
|
||||
out->dimensions[2] = in->dims[2];
|
||||
out->number_of_faces = 0;
|
||||
out->number_of_nodes = 0;
|
||||
out->number_of_cells = 0;
|
||||
|
||||
out->node_coordinates = NULL;
|
||||
out->local_cell_index = malloc(nc * sizeof *out->local_cell_index);
|
||||
|
||||
|
||||
|
||||
/* Do actual work here:*/
|
||||
|
||||
/* -----------------------------------------------------------------*/
|
||||
/* For each pillar, compare zcorn values for adjacent cells to
|
||||
* find the unique node z-coordinates specified by the input.
|
||||
* While here, enumerate unique points and assign point numbers
|
||||
* (in plist) for each cornerpoint cell. In other words, plist has
|
||||
* 8 node numbers for each cornerpoint cell.*/
|
||||
|
||||
/* initialize grdecl structure "g" that will be processd by
|
||||
* "finduniquepoints" */
|
||||
g.dims[0] = in->dims[0];
|
||||
g.dims[1] = in->dims[1];
|
||||
g.dims[2] = in->dims[2];
|
||||
|
||||
actnum = malloc (nc * sizeof *actnum);
|
||||
g.actnum = copy_and_permute_actnum(nx, ny, nz, in->actnum, actnum);
|
||||
|
||||
zcorn = malloc (nc * 8 * sizeof *zcorn);
|
||||
sign = get_zcorn_sign(nx, ny, nz, in->actnum, in->zcorn, &error);
|
||||
g.zcorn = copy_and_permute_zcorn(nx, ny, nz, in->zcorn, sign, zcorn);
|
||||
|
||||
g.coord = in->coord;
|
||||
|
||||
|
||||
/* allocate space for cornerpoint numbers plus INT_MIN (INT_MAX)
|
||||
* padding */
|
||||
plist = malloc(8 * (nc + ((size_t)nx)*((size_t)ny)) * sizeof *plist);
|
||||
|
||||
finduniquepoints(&g, plist, tolerance, out);
|
||||
|
||||
free (zcorn);
|
||||
free (actnum);
|
||||
|
||||
/* Determine if coordinate system is left handed or not. */
|
||||
left_handed = is_lefthanded(in);
|
||||
if (left_handed) {
|
||||
/* Reflect Y coordinates about XZ plane to create right-handed
|
||||
* coordinate system whilst processing intersections. */
|
||||
for (i = 1; i < ((size_t) 3) * out->number_of_nodes; i += 3) {
|
||||
out->node_coordinates[i] = -out->node_coordinates[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* -----------------------------------------------------------------*/
|
||||
/* Find face topology and face-to-cell connections */
|
||||
|
||||
/* internal */
|
||||
work = malloc(2 * ((size_t) (2*nz + 2)) * sizeof *work);
|
||||
for(i = 0; i < ((size_t)4) * (nz + 1); ++i) { work[i] = -1; }
|
||||
|
||||
/* internal array to store intersections */
|
||||
intersections = malloc(BIGNUM* sizeof(*intersections));
|
||||
|
||||
|
||||
|
||||
process_vertical_faces (0, &intersections, plist, work, out);
|
||||
process_vertical_faces (1, &intersections, plist, work, out);
|
||||
process_horizontal_faces ( &intersections, plist, out);
|
||||
|
||||
free (plist);
|
||||
free (work);
|
||||
|
||||
/* -----------------------------------------------------------------*/
|
||||
/* (re)allocate space for and compute coordinates of nodes that
|
||||
* arise from intersecting cells (faults) */
|
||||
compute_intersection_coordinates(intersections, out);
|
||||
|
||||
free (intersections);
|
||||
|
||||
/* -----------------------------------------------------------------*/
|
||||
/* Enumerate compressed cells:
|
||||
-make array [0...#cells-1] of global cell numbers
|
||||
-make [0...nx*ny*nz-1] array of local cell numbers,
|
||||
lexicographically ordered, used to remap out->face_neighbors
|
||||
*/
|
||||
global_cell_index = malloc(nc * sizeof *global_cell_index);
|
||||
cellnum = 0;
|
||||
for (i = 0; i < nc; ++i) {
|
||||
if (out->local_cell_index[i] != -1) {
|
||||
global_cell_index[cellnum] = (int) i;
|
||||
out->local_cell_index[i] = cellnum;
|
||||
cellnum++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Remap out->face_neighbors */
|
||||
iptr = out->face_neighbors;
|
||||
for (i = 0; i < ((size_t) 2) * out->number_of_faces; ++i, ++iptr) {
|
||||
if (*iptr != -1){
|
||||
*iptr = out->local_cell_index[*iptr];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
free(out->local_cell_index);
|
||||
out->local_cell_index = global_cell_index;
|
||||
|
||||
/* Reflect Y coordinate back to original position if left-handed
|
||||
* coordinate system was detected and handled earlier. */
|
||||
if (left_handed) {
|
||||
for (i = 1; i < ((size_t) 3) * out->number_of_nodes; i += 3) {
|
||||
out->node_coordinates[i] = -out->node_coordinates[i];
|
||||
}
|
||||
}
|
||||
|
||||
/* if sign==-1 in ZCORN preprocessing, the sign of the
|
||||
* z-coordinate need to change before we finish */
|
||||
if (sign == -1)
|
||||
{
|
||||
for (i = 2; i < ((size_t) 3) * out->number_of_nodes; i += 3)
|
||||
out->node_coordinates[i] *= sign;
|
||||
}
|
||||
|
||||
/* If an odd number of coordinate reflections were applied, the
|
||||
* processing routines--especially facetopology()--will produce
|
||||
* node orderings that lead to normals pointing from 2 to 1.
|
||||
* Reverse nodes to reestablish expected normal direction (and
|
||||
* positive cell volumes). */
|
||||
if (left_handed ^ (sign == -1)) {
|
||||
reverse_face_nodes(out);
|
||||
}
|
||||
}
|
||||
|
||||
/*-------------------------------------------------------*/
|
||||
void free_processed_grid(struct processed_grid *g)
|
||||
{
|
||||
if( g ){
|
||||
free ( g->face_nodes );
|
||||
free ( g->face_ptr );
|
||||
free ( g->face_tag );
|
||||
free ( g->face_neighbors );
|
||||
free ( g->node_coordinates );
|
||||
free ( g->local_cell_index );
|
||||
}
|
||||
}
|
||||
|
||||
/* Local Variables: */
|
||||
/* c-basic-offset:4 */
|
||||
/* End: */
|
|
@ -1,154 +0,0 @@
|
|||
/*===========================================================================
|
||||
//
|
||||
// File: preprocess.h
|
||||
//
|
||||
// Created: Fri Jun 19 08:43:04 2009
|
||||
//
|
||||
// Author: Jostein R. Natvig <Jostein.R.Natvig@sintef.no>
|
||||
//
|
||||
// $Date$
|
||||
//
|
||||
// $Revision$
|
||||
//
|
||||
//==========================================================================*/
|
||||
|
||||
/*
|
||||
Copyright 2009, 2010 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2009, 2010 Statoil ASA.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef OPM_PREPROCESS_HEADER
|
||||
#define OPM_PREPROCESS_HEADER
|
||||
|
||||
/**
|
||||
* \file
|
||||
* Low-level corner-point processing routines and supporting data structures.
|
||||
*
|
||||
* User code should typically employ higher-level routines such as
|
||||
* create_grid_cornerpoint() in order to construct fully formed UnstructuredGrid
|
||||
* data structures from a corner-point specification. Incidentally, the routines
|
||||
* provided by this module are used to implement function
|
||||
* create_grid_cornerpoint().
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Raw corner-point specification of a particular geological model.
|
||||
*/
|
||||
struct grdecl {
|
||||
int dims[3]; /**< Cartesian box dimensions. */
|
||||
const double *coord; /**< Pillar end-points. */
|
||||
const double *zcorn; /**< Corner-point depths. */
|
||||
const int *actnum; /**< Explicit "active" map. May be NULL.*/
|
||||
const double *mapaxes; /**< 6 Element rotation vector - can be NULL. */
|
||||
};
|
||||
|
||||
/**
|
||||
* Connection taxonomy.
|
||||
*/
|
||||
enum face_tag {
|
||||
LEFT, /**< Connection topologically parallel to J-K plane. */
|
||||
BACK, /**< Connection topologically parallel to I-K plane. */
|
||||
TOP /**< Connection topologically parallel to I-J plane. */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Result structure representing minimal derived topology and geometry of
|
||||
* a geological model in corner-point format.
|
||||
*/
|
||||
struct processed_grid {
|
||||
int m; /**< Upper bound on "number_of_faces". For internal use in
|
||||
function process_grid()'s memory management. */
|
||||
int n; /**< Upper bound on "number_of_nodes". For internal use in
|
||||
function process_grid()'s memory management. */
|
||||
|
||||
int dimensions[3]; /**< Cartesian box dimensions. */
|
||||
|
||||
int number_of_faces; /**< Total number of unique grid faces
|
||||
(i.e., connections). */
|
||||
int *face_nodes; /**< Node (vertex) numbers of each face,
|
||||
stored sequentially. */
|
||||
int *face_ptr; /**< Start position for each face's
|
||||
`face_nodes'. */
|
||||
int *face_neighbors; /**< Global cell numbers. Two elements per
|
||||
face, stored sequentially. */
|
||||
enum face_tag *face_tag; /**< Classification of grid's individual
|
||||
connections (faces). */
|
||||
|
||||
int number_of_nodes; /**< Number of unique grid vertices. */
|
||||
int number_of_nodes_on_pillars; /**< Total number of unique cell
|
||||
vertices that lie on pillars. */
|
||||
double *node_coordinates; /**< Vertex coordinates. Three doubles
|
||||
(\f$x\f$, \f$y\f$, \f$z\f$) per vertex,
|
||||
stored sequentially. */
|
||||
|
||||
int number_of_cells; /**< Number of active grid cells. */
|
||||
int *local_cell_index; /**< Deceptively named local-to-global cell
|
||||
index mapping. */
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Construct a prototypical grid representation from a corner-point
|
||||
* specification.
|
||||
*
|
||||
* Pinched cells will be removed irrespective of any explicit "active" map
|
||||
* in the geological model input specification. On input, the result
|
||||
* structure "out" must point to a valid management structure. In other
|
||||
* words, the result structure must point to a region of memory that is
|
||||
* typically backed by automatic or allocated (dynamic) storage duration.
|
||||
*
|
||||
* @param[in] g Corner-point specification. If "actnum" is NULL, then
|
||||
* the specification is interpreted as if all cells are
|
||||
* initially active.
|
||||
* @param[in] tol Absolute tolerance of node-coincidence.
|
||||
* @param[in,out] out Minimal grid representation featuring face-to-cell
|
||||
* neighbourship definition, vertex geometry, face's
|
||||
* constituent vertices, and local-to-global cell
|
||||
* mapping.
|
||||
*/
|
||||
void process_grdecl(const struct grdecl *g ,
|
||||
double tol,
|
||||
struct processed_grid *out);
|
||||
|
||||
/**
|
||||
* Release memory resources acquired in previous grid processing using
|
||||
* function process_grdecl().
|
||||
*
|
||||
* Note: This function releases the resources associated to the individual
|
||||
* fields of the processed_grid, but does not free() the structure itself.
|
||||
*
|
||||
* @param[in,out] g Prototypical grid representation obtained in an earlier
|
||||
* call to function process_grdecl().
|
||||
*/
|
||||
void free_processed_grid(struct processed_grid *g);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* OPM_PREPROCESS_HEADER */
|
||||
|
||||
|
||||
/* Local Variables: */
|
||||
/* c-basic-offset:4 */
|
||||
/* End: */
|
|
@ -1,383 +0,0 @@
|
|||
/*===========================================================================
|
||||
//
|
||||
// File: uniquepoints.c
|
||||
//
|
||||
// Created: Fri Jun 19 08:46:05 2009
|
||||
//
|
||||
// Author: Jostein R. Natvig <Jostein.R.Natvig@sintef.no>
|
||||
//
|
||||
// $Date$
|
||||
//
|
||||
// $Revision$
|
||||
//
|
||||
//==========================================================================*/
|
||||
|
||||
/*
|
||||
Copyright 2009, 2010 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2009, 2010 Statoil ASA.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <assert.h>
|
||||
#include <float.h>
|
||||
#include <limits.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#include "preprocess.h"
|
||||
#include "uniquepoints.h"
|
||||
|
||||
#define MIN(i,j) (((i) < (j)) ? (i) : (j))
|
||||
#define MAX(i,j) (((i) > (j)) ? (i) : (j))
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
Compare function passed to qsortx */
|
||||
static int compare(const void *a, const void *b)
|
||||
{
|
||||
const double a0 = *(const double*) a;
|
||||
const double b0 = *(const double*) b;
|
||||
|
||||
/* { -1, a < b
|
||||
* compare(a,b) = { 0, a = b
|
||||
* { 1, a > b */
|
||||
return (a0 > b0) - (a0 < b0);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
Creat sorted list of z-values in zcorn with actnum==1x */
|
||||
static int createSortedList(double *list, int n, int m,
|
||||
const double *z[], const int *a[])
|
||||
{
|
||||
int i,j;
|
||||
double *ptr = list;
|
||||
for (i=0; i<n; ++i){
|
||||
for (j=0; j<m; ++j){
|
||||
if (a[j][i/2]) *ptr++ = z[j][i];
|
||||
/* else fprintf(stderr, "skipping point in inactive cell\n"); */
|
||||
}
|
||||
}
|
||||
|
||||
qsort(list, ptr-list, sizeof(double), compare);
|
||||
return ptr-list;
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
Remove points less than <tolerance> apart in <list> of increasing
|
||||
doubles. */
|
||||
static int uniquify(int n, double *list, double tolerance)
|
||||
{
|
||||
int i;
|
||||
int pos;
|
||||
double val;
|
||||
|
||||
assert (!(tolerance < 0.0));
|
||||
|
||||
if (n<1) return 0;
|
||||
pos = 0;
|
||||
val = list[pos++];/* Keep first value */
|
||||
|
||||
for (i=1; i<n; ++i){
|
||||
if (val + tolerance < list [i]){
|
||||
val = list[i];
|
||||
list[pos++] = val;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Preserve outer z-boundary.
|
||||
|
||||
This operation is a no-op in the case
|
||||
|
||||
list[pos-2] + tolerance < list[n-1].
|
||||
|
||||
If, however, the second to last point is less than <tolerance>
|
||||
away from the last point (list[n-1]), we remove this
|
||||
second-to-last point as it cannot be distinguished from "final"
|
||||
point.
|
||||
*/
|
||||
list[pos-1] = list[n-1];
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
Along single pillar: */
|
||||
static int assignPointNumbers(int begin,
|
||||
int end,
|
||||
const double *zlist,
|
||||
int n,
|
||||
const double *zcorn,
|
||||
const int *actnum,
|
||||
int *plist,
|
||||
double tolerance)
|
||||
{
|
||||
/* n - number of cells */
|
||||
/* zlist - list of len unique z-values */
|
||||
/* start - number of unique z-values processed before. */
|
||||
|
||||
int i, k;
|
||||
/* All points should now be within tolerance of a listed point. */
|
||||
|
||||
|
||||
const double *z = zcorn;
|
||||
const int *a = actnum;
|
||||
int *p = plist;
|
||||
|
||||
k = begin;
|
||||
*p++ = INT_MIN; /* Padding to ease processing of faults */
|
||||
for (i=0; i<n; ++i){
|
||||
|
||||
/* Skip inactive cells */
|
||||
if (!a[i/2]) {
|
||||
p[0] = p[-1]; /* Inactive cells are collapsed leaving
|
||||
* void space.*/
|
||||
++p;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Find next k such that zlist[k] < z[i] < zlist[k+1] */
|
||||
while ((k < end) && (zlist[k] + tolerance < z[i])){
|
||||
k++;
|
||||
}
|
||||
|
||||
/* assert (k < len && z[i] - zlist[k] <= tolerance) */
|
||||
if ((k == end) || ( zlist[k] + tolerance < z[i])){
|
||||
fprintf(stderr, "Cannot associate zcorn values with given list\n");
|
||||
fprintf(stderr, "of z-coordinates to given tolerance\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
*p++ = k;
|
||||
}
|
||||
*p++ = INT_MAX;/* Padding to ease processing of faults */
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/* ---------------------------------------------------------------------- */
|
||||
static void
|
||||
vector_positions(const int dims[3] ,
|
||||
const int i ,
|
||||
const int j ,
|
||||
size_t start[4])
|
||||
/* ---------------------------------------------------------------------- */
|
||||
{
|
||||
size_t im, ip, jm, jp;
|
||||
|
||||
im = MAX(1, i ) - 1;
|
||||
jm = MAX(1, j ) - 1;
|
||||
ip = MIN(dims[0], i+1) - 1;
|
||||
jp = MIN(dims[1], j+1) - 1;
|
||||
|
||||
start[ 0 ] = dims[2] * (im + dims[0]*jm);
|
||||
start[ 1 ] = dims[2] * (im + dims[0]*jp);
|
||||
start[ 2 ] = dims[2] * (ip + dims[0]*jm);
|
||||
start[ 3 ] = dims[2] * (ip + dims[0]*jp);
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
Given a vector <field> with k index running faster than i running
|
||||
faster than j, and Cartesian dimensions <dims>, find pointers to the
|
||||
(i-1, j-1, 0), (i-1, j, 0), (i, j-1, 0) and (i, j, 0) elements of
|
||||
field. */
|
||||
static void igetvectors(const int dims[3], int i, int j,
|
||||
const int *field, const int *v[])
|
||||
{
|
||||
size_t p, start[4];
|
||||
|
||||
vector_positions(dims, i, j, start);
|
||||
|
||||
for (p = 0; p < 4; p++) {
|
||||
v[p] = field + start[p];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
Given a vector <field> with k index running faster than i running
|
||||
faster than j, and Cartesian dimensions <dims>, find pointers to the
|
||||
(i-1, j-1, 0), (i-1, j, 0), (i, j-1, 0) and (i, j, 0) elements of
|
||||
field. */
|
||||
static void dgetvectors(const int dims[3], int i, int j,
|
||||
const double *field, const double *v[])
|
||||
{
|
||||
size_t p, start[4];
|
||||
|
||||
vector_positions(dims, i, j, start);
|
||||
|
||||
for (p = 0; p < 4; p++) {
|
||||
v[p] = field + start[p];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
Given a z coordinate, find x and y coordinates on line defined by
|
||||
coord. Coord points to a vector of 6 doubles [x0,y0,z0,x1,y1,z1].
|
||||
*/
|
||||
static void interpolate_pillar(const double *coord, double *pt)
|
||||
{
|
||||
double a;
|
||||
|
||||
if (fabs(coord[5] - coord[2]) > 0) {
|
||||
|
||||
a = (pt[2] - coord[2]) / (coord[5] - coord[2]);
|
||||
|
||||
} else {
|
||||
|
||||
a = 0;
|
||||
|
||||
}
|
||||
|
||||
#if 0
|
||||
pt[0] = coord[0] + a*(coord[3]-coord[0]);
|
||||
pt[1] = coord[1] + a*(coord[4]-coord[1]);
|
||||
#else
|
||||
pt[0] = (1.0 - a)*coord[0] + a*coord[3];
|
||||
pt[1] = (1.0 - a)*coord[1] + a*coord[4];
|
||||
#endif
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
Assign point numbers p such that "zlist(p)==zcorn". Assume that
|
||||
coordinate number is arranged in a sequence such that the natural
|
||||
index is (k,i,j) */
|
||||
int finduniquepoints(const struct grdecl *g,
|
||||
/* return values: */
|
||||
int *plist, /* list of point numbers on
|
||||
* each pillar*/
|
||||
double tolerance,
|
||||
struct processed_grid *out)
|
||||
|
||||
{
|
||||
|
||||
const int nx = out->dimensions[0];
|
||||
const int ny = out->dimensions[1];
|
||||
const int nz = out->dimensions[2];
|
||||
const int nc = g->dims[0]*g->dims[1]*g->dims[2];
|
||||
|
||||
|
||||
/* zlist may need extra space temporarily due to simple boundary
|
||||
* treatement */
|
||||
int npillarpoints = 8*(nx+1)*(ny+1)*nz;
|
||||
int npillars = (nx+1)*(ny+1);
|
||||
|
||||
double *zlist = malloc(npillarpoints*sizeof *zlist);
|
||||
int *zptr = malloc((npillars+1)*sizeof *zptr);
|
||||
|
||||
|
||||
|
||||
|
||||
int i,j,k;
|
||||
|
||||
int d1[3];
|
||||
int len = 0;
|
||||
double *zout = zlist;
|
||||
int pos = 0;
|
||||
double *pt;
|
||||
const double *z[4];
|
||||
const int *a[4];
|
||||
int *p;
|
||||
int pix, cix;
|
||||
int zix;
|
||||
|
||||
const double *coord = g->coord;
|
||||
|
||||
d1[0] = 2*g->dims[0];
|
||||
d1[1] = 2*g->dims[1];
|
||||
d1[2] = 2*g->dims[2];
|
||||
|
||||
out->node_coordinates = malloc (3*8*nc*sizeof(*out->node_coordinates));
|
||||
|
||||
zptr[pos++] = zout - zlist;
|
||||
|
||||
pt = out->node_coordinates;
|
||||
|
||||
/* Loop over pillars, find unique points on each pillar */
|
||||
for (j=0; j < g->dims[1]+1; ++j){
|
||||
for (i=0; i < g->dims[0]+1; ++i){
|
||||
|
||||
/* Get positioned pointers for actnum and zcorn data */
|
||||
igetvectors(g->dims, i, j, g->actnum, a);
|
||||
dgetvectors(d1, 2*i, 2*j, g->zcorn, z);
|
||||
|
||||
len = createSortedList( zout, d1[2], 4, z, a);
|
||||
len = uniquify (len, zout, tolerance);
|
||||
|
||||
/* Assign unique points */
|
||||
for (k=0; k<len; ++k){
|
||||
pt[2] = zout[k];
|
||||
interpolate_pillar(coord, pt);
|
||||
pt += 3;
|
||||
}
|
||||
|
||||
/* Increment pointer to sparse table of unique zcorn
|
||||
* values */
|
||||
zout = zout + len;
|
||||
zptr[pos++] = zout - zlist;
|
||||
|
||||
coord += 6;
|
||||
}
|
||||
}
|
||||
out->number_of_nodes_on_pillars = zptr[pos-1];
|
||||
out->number_of_nodes = zptr[pos-1];
|
||||
|
||||
/* Loop over all vertical sets of zcorn values, assign point
|
||||
* numbers */
|
||||
p = plist;
|
||||
for (j=0; j < 2*g->dims[1]; ++j){
|
||||
for (i=0; i < 2*g->dims[0]; ++i){
|
||||
|
||||
/* pillar index */
|
||||
pix = (i+1)/2 + (g->dims[0]+1)*((j+1)/2);
|
||||
|
||||
/* cell column position */
|
||||
cix = g->dims[2]*((i/2) + (j/2)*g->dims[0]);
|
||||
|
||||
/* zcorn column position */
|
||||
zix = 2*g->dims[2]*(i+2*g->dims[0]*j);
|
||||
|
||||
if (!assignPointNumbers(zptr[pix], zptr[pix+1], zlist,
|
||||
2*g->dims[2],
|
||||
g->zcorn + zix, g->actnum + cix,
|
||||
p, tolerance)){
|
||||
fprintf(stderr, "Something went wrong in assignPointNumbers");
|
||||
return 0;
|
||||
}
|
||||
|
||||
p += 2 + 2*g->dims[2];
|
||||
}
|
||||
}
|
||||
|
||||
free(zptr);
|
||||
free(zlist);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Local Variables: */
|
||||
/* c-basic-offset:4 */
|
||||
/* End: */
|
|
@ -1,47 +0,0 @@
|
|||
/*===========================================================================
|
||||
//
|
||||
// File: uniquepoints.h
|
||||
//
|
||||
// Created: Fri Jun 19 08:46:30 2009
|
||||
//
|
||||
// Author: Jostein R. Natvig <Jostein.R.Natvig@sintef.no>
|
||||
//
|
||||
// $Date$
|
||||
//
|
||||
// $Revision$
|
||||
//
|
||||
//==========================================================================*/
|
||||
|
||||
/*
|
||||
Copyright 2009, 2010 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2009, 2010 Statoil ASA.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef OPM_UNIQUEPOINTS_HEADER
|
||||
#define OPM_UNIQUEPOINTS_HEADER
|
||||
|
||||
int finduniquepoints(const struct grdecl *g, /* input */
|
||||
int *p, /* for each z0 in zcorn, z0 = z[p0] */
|
||||
double t, /* tolerance*/
|
||||
struct processed_grid *out);
|
||||
|
||||
#endif /* OPM_UNIQUEPOINTS_HEADER */
|
||||
|
||||
/* Local Variables: */
|
||||
/* c-basic-offset:4 */
|
||||
/* End: */
|
|
@ -1,562 +0,0 @@
|
|||
/*
|
||||
Copyright 2012 SINTEF ICT, Applied Mathematics.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <opm/core/grid.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
|
||||
void
|
||||
destroy_grid(struct UnstructuredGrid *g)
|
||||
{
|
||||
if (g!=NULL)
|
||||
{
|
||||
free(g->face_nodes);
|
||||
free(g->face_nodepos);
|
||||
free(g->face_cells);
|
||||
free(g->cell_facepos);
|
||||
free(g->cell_faces);
|
||||
|
||||
free(g->node_coordinates);
|
||||
free(g->face_centroids);
|
||||
free(g->face_areas);
|
||||
free(g->face_normals);
|
||||
free(g->cell_centroids);
|
||||
free(g->cell_volumes);
|
||||
|
||||
free(g->global_cell);
|
||||
free(g->cell_facetag);
|
||||
|
||||
free(g->zcorn);
|
||||
}
|
||||
|
||||
free(g);
|
||||
}
|
||||
|
||||
|
||||
struct UnstructuredGrid *
|
||||
create_grid_empty(void)
|
||||
{
|
||||
struct UnstructuredGrid *G, g = { 0 };
|
||||
|
||||
G = malloc(1 * sizeof *G);
|
||||
|
||||
if (G != NULL) {
|
||||
*G = g;
|
||||
}
|
||||
|
||||
return G;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
attach_zcorn_copy(struct UnstructuredGrid* G , const double * zcorn)
|
||||
{
|
||||
size_t zcorn_elements = G->cartdims[0] * G->cartdims[1] * G->cartdims[2] * 8;
|
||||
double * new_zcorn = realloc(G->zcorn , zcorn_elements * sizeof * G->zcorn );
|
||||
if (new_zcorn) {
|
||||
G->zcorn = new_zcorn;
|
||||
memcpy(G->zcorn , zcorn , zcorn_elements * sizeof * G->zcorn );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct UnstructuredGrid *
|
||||
allocate_grid(size_t ndims ,
|
||||
size_t ncells ,
|
||||
size_t nfaces ,
|
||||
size_t nfacenodes,
|
||||
size_t ncellfaces,
|
||||
size_t nnodes )
|
||||
{
|
||||
size_t nel;
|
||||
struct UnstructuredGrid *G;
|
||||
|
||||
G = create_grid_empty();
|
||||
|
||||
if (G != NULL) {
|
||||
/* zcorn cache - only for output. */
|
||||
G->zcorn = NULL;
|
||||
|
||||
/* Grid fields ---------------------------------------- */
|
||||
G->dimensions = ndims;
|
||||
G->number_of_cells = ncells;
|
||||
G->number_of_faces = nfaces;
|
||||
G->number_of_nodes = nnodes;
|
||||
|
||||
/* Node fields ---------------------------------------- */
|
||||
nel = nnodes * ndims;
|
||||
G->node_coordinates = malloc(nel * sizeof *G->node_coordinates);
|
||||
|
||||
/* Face fields ---------------------------------------- */
|
||||
nel = nfacenodes;
|
||||
G->face_nodes = malloc(nel * sizeof *G->face_nodes);
|
||||
|
||||
nel = nfaces + 1;
|
||||
G->face_nodepos = malloc(nel * sizeof *G->face_nodepos);
|
||||
|
||||
nel = 2 * nfaces;
|
||||
G->face_cells = malloc(nel * sizeof *G->face_cells);
|
||||
|
||||
nel = nfaces * ndims;
|
||||
G->face_centroids = malloc(nel * sizeof *G->face_centroids);
|
||||
|
||||
nel = nfaces * ndims;
|
||||
G->face_normals = malloc(nel * sizeof *G->face_normals);
|
||||
|
||||
nel = nfaces * 1;
|
||||
G->face_areas = malloc(nel * sizeof *G->face_areas);
|
||||
|
||||
|
||||
/* Cell fields ---------------------------------------- */
|
||||
nel = ncellfaces;
|
||||
G->cell_faces = malloc(nel * sizeof *G->cell_faces);
|
||||
|
||||
G->cell_facetag = malloc(nel * sizeof *G->cell_facetag);
|
||||
|
||||
nel = ncells + 1;
|
||||
G->cell_facepos = malloc(nel * sizeof *G->cell_facepos);
|
||||
|
||||
nel = ncells * ndims;
|
||||
G->cell_centroids = malloc(nel * sizeof *G->cell_centroids);
|
||||
|
||||
nel = ncells * 1;
|
||||
G->cell_volumes = malloc(nel * sizeof *G->cell_volumes);
|
||||
|
||||
if ((G->node_coordinates == NULL) ||
|
||||
(G->face_nodes == NULL) ||
|
||||
(G->face_nodepos == NULL) ||
|
||||
(G->face_cells == NULL) ||
|
||||
(G->face_centroids == NULL) ||
|
||||
(G->face_normals == NULL) ||
|
||||
(G->face_areas == NULL) ||
|
||||
(G->cell_faces == NULL) ||
|
||||
(G->cell_facetag == NULL) ||
|
||||
(G->cell_facepos == NULL) ||
|
||||
(G->cell_centroids == NULL) ||
|
||||
(G->cell_volumes == NULL) )
|
||||
{
|
||||
destroy_grid(G);
|
||||
G = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return G;
|
||||
}
|
||||
|
||||
|
||||
#define GRID_NMETA 6
|
||||
#define GRID_NDIMS 0
|
||||
#define GRID_NCELLS 1
|
||||
#define GRID_NFACES 2
|
||||
#define GRID_NNODES 3
|
||||
#define GRID_NFACENODES 4
|
||||
#define GRID_NCELLFACES 5
|
||||
|
||||
|
||||
static void
|
||||
input_error(FILE *fp, const char * const err)
|
||||
{
|
||||
int save_errno = errno;
|
||||
|
||||
if (ferror(fp)) {
|
||||
fprintf(stderr, "%s: %s\n", err, strerror(save_errno));
|
||||
clearerr(fp);
|
||||
}
|
||||
else if (feof(fp)) {
|
||||
fprintf(stderr, "%s: End-of-file\n", err);
|
||||
}
|
||||
|
||||
errno = save_errno;
|
||||
}
|
||||
|
||||
|
||||
static struct UnstructuredGrid *
|
||||
allocate_grid_from_file(FILE *fp, int *has_tag, int *has_indexmap)
|
||||
{
|
||||
struct UnstructuredGrid *G;
|
||||
|
||||
int save_errno;
|
||||
unsigned long tmp;
|
||||
size_t dimens[GRID_NMETA], i;
|
||||
|
||||
save_errno = errno;
|
||||
|
||||
i = 0;
|
||||
while ((i < GRID_NMETA) && (fscanf(fp, " %lu", &tmp) == 1)) {
|
||||
dimens[i] = tmp;
|
||||
|
||||
i += 1;
|
||||
}
|
||||
|
||||
if (i == GRID_NMETA) {
|
||||
if (fscanf(fp, "%d %d", has_tag, has_indexmap) == 2) {
|
||||
G = allocate_grid(dimens[GRID_NDIMS] ,
|
||||
dimens[GRID_NCELLS] ,
|
||||
dimens[GRID_NFACES] ,
|
||||
dimens[GRID_NFACENODES],
|
||||
dimens[GRID_NCELLFACES],
|
||||
dimens[GRID_NNODES] );
|
||||
|
||||
if (G != NULL) {
|
||||
if (! *has_tag) {
|
||||
free(G->cell_facetag);
|
||||
G->cell_facetag = NULL;
|
||||
}
|
||||
|
||||
if (*has_indexmap) {
|
||||
G->global_cell =
|
||||
malloc(dimens[GRID_NCELLS] * sizeof *G->global_cell);
|
||||
|
||||
/* Allocation failure checked elsewhere. */
|
||||
}
|
||||
|
||||
G->number_of_cells = (int) dimens[GRID_NCELLS];
|
||||
G->number_of_faces = (int) dimens[GRID_NFACES];
|
||||
G->number_of_nodes = (int) dimens[GRID_NNODES];
|
||||
G->dimensions = (int) dimens[GRID_NDIMS];
|
||||
|
||||
i = 0;
|
||||
while ((i < dimens[GRID_NDIMS]) &&
|
||||
(fscanf(fp, "%d", & G->cartdims[ i ]) == 1)) {
|
||||
i += 1;
|
||||
}
|
||||
|
||||
if (i < dimens[GRID_NDIMS]) {
|
||||
input_error(fp, "Unable to read Cartesian dimensions");
|
||||
|
||||
destroy_grid(G);
|
||||
G = NULL;
|
||||
}
|
||||
else {
|
||||
/* Account for dimens[GRID_DIMS] < 3 */
|
||||
size_t n = (sizeof G->cartdims) / (sizeof G->cartdims[0]);
|
||||
for (; i < n; i++) { G->cartdims[ i ] = 1; }
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
input_error(fp, "Unable to read grid predicates");
|
||||
|
||||
G = NULL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
input_error(fp, "Unable to read grid dimensions");
|
||||
|
||||
G = NULL;
|
||||
}
|
||||
|
||||
errno = save_errno;
|
||||
|
||||
return G;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
read_grid_nodes(FILE *fp, struct UnstructuredGrid *G)
|
||||
{
|
||||
int save_errno;
|
||||
size_t i, n;
|
||||
|
||||
save_errno = errno;
|
||||
|
||||
n = G->dimensions;
|
||||
n *= G->number_of_nodes;
|
||||
|
||||
i = 0;
|
||||
while ((i < n) &&
|
||||
(fscanf(fp, " %lf", & G->node_coordinates[ i ]) == 1)) {
|
||||
i += 1;
|
||||
}
|
||||
|
||||
if (i < n) {
|
||||
input_error(fp, "Unable to read node coordinates");
|
||||
}
|
||||
|
||||
errno = save_errno;
|
||||
|
||||
return i == n;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
read_grid_faces(FILE *fp, struct UnstructuredGrid *G)
|
||||
{
|
||||
int save_errno, ok;
|
||||
size_t nf, nfn, i;
|
||||
|
||||
save_errno = errno;
|
||||
|
||||
nf = G->number_of_faces;
|
||||
|
||||
/* G->face_nodepos */
|
||||
i = 0;
|
||||
while ((i < nf + 1) &&
|
||||
(fscanf(fp, " %d", & G->face_nodepos[ i ]) == 1)) {
|
||||
i += 1;
|
||||
}
|
||||
ok = i == nf + 1;
|
||||
|
||||
if (! ok) {
|
||||
input_error(fp, "Unable to read node indirection array");
|
||||
}
|
||||
else {
|
||||
/* G->face_nodes */
|
||||
nfn = G->face_nodepos[ nf ];
|
||||
|
||||
i = 0;
|
||||
while ((i < nfn) && (fscanf(fp, " %d", & G->face_nodes[ i ]) == 1)) {
|
||||
i += 1;
|
||||
}
|
||||
|
||||
ok = i == nfn;
|
||||
if (! ok) {
|
||||
input_error(fp, "Unable to read face-nodes");
|
||||
}
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
/* G->face_cells */
|
||||
i = 0;
|
||||
while ((i < 2 * nf) && (fscanf(fp, " %d", & G->face_cells[ i ]) == 1)) {
|
||||
i += 1;
|
||||
}
|
||||
|
||||
ok = i == 2 * nf;
|
||||
if (! ok) {
|
||||
input_error(fp, "Unable to read neighbourship");
|
||||
}
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
/* G->face_areas */
|
||||
i = 0;
|
||||
while ((i < nf) && (fscanf(fp, " %lf", & G->face_areas[ i ]) == 1)) {
|
||||
i += 1;
|
||||
}
|
||||
|
||||
ok = i == nf;
|
||||
if (! ok) {
|
||||
input_error(fp, "Unable to read face areas");
|
||||
}
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
/* G->face_centroids */
|
||||
size_t n;
|
||||
|
||||
n = G->dimensions;
|
||||
n *= nf;
|
||||
|
||||
i = 0;
|
||||
while ((i < n) && (fscanf(fp, " %lf", & G->face_centroids[ i ]) == 1)) {
|
||||
i += 1;
|
||||
}
|
||||
|
||||
ok = i == n;
|
||||
if (! ok) {
|
||||
input_error(fp, "Unable to read face centroids");
|
||||
}
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
/* G->face_normals */
|
||||
size_t n;
|
||||
|
||||
n = G->dimensions;
|
||||
n *= nf;
|
||||
|
||||
i = 0;
|
||||
while ((i < n) && (fscanf(fp, " %lf", & G->face_normals[ i ]) == 1)) {
|
||||
i += 1;
|
||||
}
|
||||
|
||||
ok = i == n;
|
||||
if (! ok) {
|
||||
input_error(fp, "Unable to read face normals");
|
||||
}
|
||||
}
|
||||
|
||||
errno = save_errno;
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
read_grid_cells(FILE *fp, int has_tag, int has_indexmap,
|
||||
struct UnstructuredGrid *G)
|
||||
{
|
||||
int save_errno, ok;
|
||||
size_t nc, ncf, i;
|
||||
|
||||
save_errno = errno;
|
||||
|
||||
nc = G->number_of_cells;
|
||||
|
||||
/* G->cell_facepos */
|
||||
i = 0;
|
||||
while ((i < nc + 1) && (fscanf(fp, " %d", & G->cell_facepos[ i ]) == 1)) {
|
||||
i += 1;
|
||||
}
|
||||
ok = i == nc + 1;
|
||||
|
||||
if (! ok) {
|
||||
input_error(fp, "Unable to read face indirection array");
|
||||
}
|
||||
else {
|
||||
/* G->cell_faces (and G->cell_facetag if applicable) */
|
||||
ncf = G->cell_facepos[ nc ];
|
||||
i = 0;
|
||||
|
||||
if (has_tag) {
|
||||
assert (G->cell_facetag != NULL);
|
||||
|
||||
while ((i < ncf) &&
|
||||
(fscanf(fp, " %d %d",
|
||||
& G->cell_faces [ i ],
|
||||
& G->cell_facetag[ i ]) == 2)) {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
while ((i < ncf) &&
|
||||
(fscanf(fp, " %d", & G->cell_faces[ i ]) == 1)) {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
ok = i == ncf;
|
||||
if (! ok) {
|
||||
input_error(fp, "Unable to read cell-faces");
|
||||
}
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
/* G->global_cell if applicable */
|
||||
if (has_indexmap) {
|
||||
i = 0;
|
||||
|
||||
if (G->global_cell != NULL) {
|
||||
while ((i < nc) &&
|
||||
(fscanf(fp, " %d", & G->global_cell[ i ]) == 1)) {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
int discard;
|
||||
|
||||
while ((i < nc) && (fscanf(fp, " %d", & discard) == 1)) {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert (G->global_cell == NULL);
|
||||
i = nc;
|
||||
}
|
||||
|
||||
ok = i == nc;
|
||||
if (! ok) {
|
||||
input_error(fp, "Unable to read global cellmap");
|
||||
}
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
/* G->cell_volumes */
|
||||
i = 0;
|
||||
while ((i < nc) && (fscanf(fp, " %lf", & G->cell_volumes[ i ]) == 1)) {
|
||||
i += 1;
|
||||
}
|
||||
|
||||
ok = i == nc;
|
||||
if (! ok) {
|
||||
input_error(fp, "Unable to read cell volumes");
|
||||
}
|
||||
}
|
||||
|
||||
if (ok) {
|
||||
/* G->cell_centroids */
|
||||
size_t n;
|
||||
|
||||
n = G->dimensions;
|
||||
n *= nc;
|
||||
|
||||
i = 0;
|
||||
while ((i < n) && (fscanf(fp, " %lf", & G->cell_centroids[ i ]) == 1)) {
|
||||
i += 1;
|
||||
}
|
||||
|
||||
ok = i == n;
|
||||
if (! ok) {
|
||||
input_error(fp, "Unable to read cell centroids");
|
||||
}
|
||||
}
|
||||
|
||||
errno = save_errno;
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
|
||||
struct UnstructuredGrid *
|
||||
read_grid(const char *fname)
|
||||
{
|
||||
struct UnstructuredGrid *G;
|
||||
FILE *fp;
|
||||
|
||||
int save_errno;
|
||||
int has_tag, has_indexmap, ok;
|
||||
|
||||
save_errno = errno;
|
||||
|
||||
fp = fopen(fname, "rt");
|
||||
if (fp != NULL) {
|
||||
G = allocate_grid_from_file(fp, & has_tag, & has_indexmap);
|
||||
|
||||
ok = G != NULL;
|
||||
|
||||
if (ok) { ok = read_grid_nodes(fp, G); }
|
||||
if (ok) { ok = read_grid_faces(fp, G); }
|
||||
if (ok) { ok = read_grid_cells(fp, has_tag, has_indexmap, G); }
|
||||
|
||||
if (! ok) {
|
||||
destroy_grid(G);
|
||||
G = NULL;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
else {
|
||||
G = NULL;
|
||||
}
|
||||
|
||||
errno = save_errno;
|
||||
|
||||
return G;
|
||||
}
|
||||
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
#include <string.h> // C string.h to get memcmp()
|
||||
|
||||
#include <opm/common/util/numeric/cmp.hpp>
|
||||
|
||||
#include <opm/core/grid.h>
|
||||
|
||||
/*
|
||||
The grid_equal() function is separated out into a separate file to
|
||||
ensure that it is compiled with a C++ compiler, so that the
|
||||
namespace features used in the opm/common/util/numeric/cmp.cpp
|
||||
implementation compiles.
|
||||
*/
|
||||
|
||||
|
||||
bool
|
||||
grid_equal(const struct UnstructuredGrid * grid1 , const struct UnstructuredGrid * grid2) {
|
||||
if ((grid1->dimensions == grid2->dimensions) &&
|
||||
(grid1->number_of_cells == grid2->number_of_cells) &&
|
||||
(grid1->number_of_faces == grid2->number_of_faces) &&
|
||||
(grid1->number_of_nodes == grid2->number_of_nodes)) {
|
||||
|
||||
// Exact integer comparisons
|
||||
{
|
||||
if (memcmp(grid1->face_nodepos , grid2->face_nodepos , (grid1->number_of_faces + 1) * sizeof * grid1->face_nodepos) != 0)
|
||||
return false;
|
||||
|
||||
if (memcmp(grid1->face_nodes , grid2->face_nodes , grid1->face_nodepos[grid1->number_of_faces] * sizeof * grid1->face_nodes) != 0)
|
||||
return false;
|
||||
|
||||
if (memcmp(grid1->face_cells , grid2->face_cells , 2 * grid1->number_of_faces * sizeof * grid1->face_cells) != 0)
|
||||
return false;
|
||||
|
||||
if (memcmp(grid1->cell_faces , grid2->cell_faces , grid1->cell_facepos[grid1->number_of_cells] * sizeof * grid1->cell_faces) != 0)
|
||||
return false;
|
||||
|
||||
if (memcmp(grid1->cell_facepos , grid2->cell_facepos , (grid1->number_of_cells + 1) * sizeof * grid1->cell_facepos) != 0)
|
||||
return false;
|
||||
|
||||
if (grid1->global_cell && grid2->global_cell) {
|
||||
if (memcmp(grid1->global_cell , grid2->global_cell , grid1->number_of_cells * sizeof * grid1->global_cell) != 0)
|
||||
return false;
|
||||
} else if (grid1->global_cell != grid2->global_cell)
|
||||
return false;
|
||||
|
||||
if (grid1->cell_facetag && grid2->cell_facetag) {
|
||||
if (memcmp(grid1->cell_facetag , grid2->cell_facetag , grid1->cell_facepos[grid1->number_of_cells] * sizeof * grid1->cell_facetag) != 0)
|
||||
return false;
|
||||
} else if (grid1->cell_facetag != grid2->cell_facetag)
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Floating point comparisons.
|
||||
{
|
||||
if (!Opm::cmp::array_equal<double>( grid1->node_coordinates , grid2->node_coordinates , static_cast<size_t>(grid1->dimensions * grid1->number_of_nodes)))
|
||||
return false;
|
||||
|
||||
if (!Opm::cmp::array_equal<double>( grid1->face_centroids , grid2->face_centroids , static_cast<size_t>(grid1->dimensions * grid1->number_of_faces)))
|
||||
return false;
|
||||
|
||||
if (!Opm::cmp::array_equal<double>( grid1->face_areas , grid2->face_areas , static_cast<size_t>(grid1->number_of_faces)))
|
||||
return false;
|
||||
|
||||
if (!Opm::cmp::array_equal<double>( grid1->face_normals , grid2->face_normals , static_cast<size_t>(grid1->dimensions * grid1->number_of_faces)))
|
||||
return false;
|
||||
|
||||
if (!Opm::cmp::array_equal<double>( grid1->cell_centroids , grid2->cell_centroids , static_cast<size_t>(grid1->dimensions * grid1->number_of_cells)))
|
||||
return false;
|
||||
|
||||
if (!Opm::cmp::array_equal<double>( grid1->cell_volumes , grid2->cell_volumes , static_cast<size_t>(grid1->number_of_cells)))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
|
@ -1,244 +0,0 @@
|
|||
//===========================================================================
|
||||
//
|
||||
// File: SparseTable.hpp
|
||||
//
|
||||
// Created: Fri Apr 24 09:50:27 2009
|
||||
//
|
||||
// Author(s): Atgeirr F Rasmussen <atgeirr@sintef.no>
|
||||
//
|
||||
// $Date$
|
||||
//
|
||||
// $Revision$
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
/*
|
||||
Copyright 2009, 2010 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2009, 2010 Statoil ASA.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef OPM_SPARSETABLE_HEADER
|
||||
#define OPM_SPARSETABLE_HEADER
|
||||
|
||||
#include <vector>
|
||||
#include <numeric>
|
||||
#include <algorithm>
|
||||
#include <boost/range/iterator_range.hpp>
|
||||
#include <opm/common/ErrorMacros.hpp>
|
||||
|
||||
#include <ostream>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
/// A SparseTable stores a table with rows of varying size
|
||||
/// as efficiently as possible.
|
||||
/// It is supposed to behave similarly to a vector of vectors.
|
||||
/// Its behaviour is similar to compressed row sparse matrices.
|
||||
template <typename T>
|
||||
class SparseTable
|
||||
{
|
||||
public:
|
||||
/// Default constructor. Yields an empty SparseTable.
|
||||
SparseTable()
|
||||
{
|
||||
}
|
||||
|
||||
/// A constructor taking all the data for the table and row sizes.
|
||||
/// \param data_beg The start of the table data.
|
||||
/// \param data_end One-beyond-end of the table data.
|
||||
/// \param rowsize_beg The start of the row length data.
|
||||
/// \param rowsize_end One beyond the end of the row length data.
|
||||
template <typename DataIter, typename IntegerIter>
|
||||
SparseTable(DataIter data_beg, DataIter data_end,
|
||||
IntegerIter rowsize_beg, IntegerIter rowsize_end)
|
||||
: data_(data_beg, data_end)
|
||||
{
|
||||
setRowStartsFromSizes(rowsize_beg, rowsize_end);
|
||||
}
|
||||
|
||||
|
||||
/// Sets the table to contain the given data, organized into
|
||||
/// rows as indicated by the given row sizes.
|
||||
/// \param data_beg The start of the table data.
|
||||
/// \param data_end One-beyond-end of the table data.
|
||||
/// \param rowsize_beg The start of the row length data.
|
||||
/// \param rowsize_end One beyond the end of the row length data.
|
||||
template <typename DataIter, typename IntegerIter>
|
||||
void assign(DataIter data_beg, DataIter data_end,
|
||||
IntegerIter rowsize_beg, IntegerIter rowsize_end)
|
||||
{
|
||||
data_.assign(data_beg, data_end);
|
||||
setRowStartsFromSizes(rowsize_beg, rowsize_end);
|
||||
}
|
||||
|
||||
|
||||
/// Request storage for table of given size.
|
||||
/// \param rowsize_beg Start of row size data.
|
||||
/// \param rowsize_end One beyond end of row size data.
|
||||
template <typename IntegerIter>
|
||||
void allocate(IntegerIter rowsize_beg, IntegerIter rowsize_end)
|
||||
{
|
||||
typedef typename std::vector<T>::size_type sz_t;
|
||||
|
||||
sz_t ndata = std::accumulate(rowsize_beg, rowsize_end, sz_t(0));
|
||||
data_.resize(ndata);
|
||||
setRowStartsFromSizes(rowsize_beg, rowsize_end);
|
||||
}
|
||||
|
||||
|
||||
/// Appends a row to the table.
|
||||
template <typename DataIter>
|
||||
void appendRow(DataIter row_beg, DataIter row_end)
|
||||
{
|
||||
data_.insert(data_.end(), row_beg, row_end);
|
||||
if (row_start_.empty()) {
|
||||
row_start_.reserve(2);
|
||||
row_start_.push_back(0);
|
||||
}
|
||||
row_start_.push_back(data_.size());
|
||||
}
|
||||
|
||||
/// True if the table contains no rows.
|
||||
bool empty() const
|
||||
{
|
||||
return row_start_.empty();
|
||||
}
|
||||
|
||||
/// Returns the number of rows in the table.
|
||||
int size() const
|
||||
{
|
||||
return empty() ? 0 : row_start_.size() - 1;
|
||||
}
|
||||
|
||||
/// Allocate storage for table of expected size
|
||||
void reserve(int exptd_nrows, int exptd_ndata)
|
||||
{
|
||||
row_start_.reserve(exptd_nrows + 1);
|
||||
data_.reserve(exptd_ndata);
|
||||
}
|
||||
|
||||
/// Swap contents for other SparseTable<T>
|
||||
void swap(SparseTable<T>& other)
|
||||
{
|
||||
row_start_.swap(other.row_start_);
|
||||
data_.swap(other.data_);
|
||||
}
|
||||
|
||||
/// Returns the number of data elements.
|
||||
int dataSize() const
|
||||
{
|
||||
return data_.size();
|
||||
}
|
||||
|
||||
/// Returns the size of a table row.
|
||||
int rowSize(int row) const
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
OPM_ERROR_IF(row < 0 || row >= size(), "Row index " << row << " is out of range");
|
||||
#endif
|
||||
return row_start_[row + 1] - row_start_[row];
|
||||
}
|
||||
|
||||
/// Makes the table empty().
|
||||
void clear()
|
||||
{
|
||||
data_.clear();
|
||||
row_start_.clear();
|
||||
}
|
||||
|
||||
/// Defining the row type, returned by operator[].
|
||||
typedef boost::iterator_range<const T*> row_type;
|
||||
typedef boost::iterator_range<T*> mutable_row_type;
|
||||
|
||||
/// Returns a row of the table.
|
||||
row_type operator[](int row) const
|
||||
{
|
||||
assert(row >= 0 && row < size());
|
||||
const T* start_ptr = data_.empty() ? 0 : &data_[0];
|
||||
return row_type(start_ptr + row_start_[row], start_ptr + row_start_[row + 1]);
|
||||
}
|
||||
|
||||
/// Returns a mutable row of the table.
|
||||
mutable_row_type operator[](int row)
|
||||
{
|
||||
assert(row >= 0 && row < size());
|
||||
T* start_ptr = data_.empty() ? 0 : &data_[0];
|
||||
return mutable_row_type(start_ptr + row_start_[row], start_ptr + row_start_[row + 1]);
|
||||
}
|
||||
|
||||
/// Equality.
|
||||
bool operator==(const SparseTable& other) const
|
||||
{
|
||||
return data_ == other.data_ && row_start_ == other.row_start_;
|
||||
}
|
||||
|
||||
template<class charT, class traits>
|
||||
void print(std::basic_ostream<charT, traits>& os) const
|
||||
{
|
||||
os << "Number of rows: " << size() << '\n';
|
||||
|
||||
os << "Row starts = [";
|
||||
std::copy(row_start_.begin(), row_start_.end(),
|
||||
std::ostream_iterator<int>(os, " "));
|
||||
os << "\b]\n";
|
||||
|
||||
os << "Data values = [";
|
||||
std::copy(data_.begin(), data_.end(),
|
||||
std::ostream_iterator<T>(os, " "));
|
||||
os << "\b]\n";
|
||||
}
|
||||
const T data(int i)const {
|
||||
return data_[i];
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<T> data_;
|
||||
// Like in the compressed row sparse matrix format,
|
||||
// row_start_.size() is equal to the number of rows + 1.
|
||||
std::vector<int> row_start_;
|
||||
|
||||
template <class IntegerIter>
|
||||
void setRowStartsFromSizes(IntegerIter rowsize_beg, IntegerIter rowsize_end)
|
||||
{
|
||||
// Since we do not store the row sizes, but cumulative row sizes,
|
||||
// we have to create the cumulative ones.
|
||||
int num_rows = rowsize_end - rowsize_beg;
|
||||
if (num_rows < 1) {
|
||||
OPM_THROW(std::runtime_error, "Must have at least one row. Got " << num_rows << " rows.");
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
if (*std::min_element(rowsize_beg, rowsize_end) < 0) {
|
||||
OPM_THROW(std::runtime_error, "All row sizes must be at least 0.");
|
||||
}
|
||||
#endif
|
||||
row_start_.resize(num_rows + 1);
|
||||
row_start_[0] = 0;
|
||||
std::partial_sum(rowsize_beg, rowsize_end, row_start_.begin() + 1);
|
||||
// Check that data_ and row_start_ match.
|
||||
if (int(data_.size()) != row_start_.back()) {
|
||||
OPM_THROW(std::runtime_error, "End of row start indices different from data size.");
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
|
||||
#endif // OPM_SPARSETABLE_HEADER
|
|
@ -1,106 +0,0 @@
|
|||
//===========================================================================
|
||||
//
|
||||
// File: StopWatch.cpp
|
||||
//
|
||||
// Created: Thu Jul 2 23:04:51 2009
|
||||
//
|
||||
// Author(s): Atgeirr F Rasmussen <atgeirr@sintef.no>
|
||||
//
|
||||
// $Date$
|
||||
//
|
||||
// $Revision$
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
/*
|
||||
Copyright 2009, 2010 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2009, 2010 Statoil ASA.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <opm/core/utility/StopWatch.hpp>
|
||||
#include <opm/common/ErrorMacros.hpp>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
namespace time
|
||||
{
|
||||
|
||||
StopWatch::StopWatch()
|
||||
: state_(UnStarted)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void StopWatch::start()
|
||||
{
|
||||
start_time_ = boost::posix_time::microsec_clock::local_time();
|
||||
last_time_ = start_time_;
|
||||
state_ = Running;
|
||||
}
|
||||
|
||||
void StopWatch::stop()
|
||||
{
|
||||
if (state_ != Running) {
|
||||
OPM_THROW(std::runtime_error, "Called stop() on a StopWatch that was not running.");
|
||||
}
|
||||
stop_time_ = boost::posix_time::microsec_clock::local_time();
|
||||
state_ = Stopped;
|
||||
}
|
||||
|
||||
double StopWatch::secsSinceLast()
|
||||
{
|
||||
boost::posix_time::ptime run_time;
|
||||
if (state_ == Running) {
|
||||
run_time = boost::posix_time::microsec_clock::local_time();
|
||||
} else if (state_ == Stopped) {
|
||||
run_time = stop_time_;
|
||||
} else {
|
||||
assert(state_ == UnStarted);
|
||||
OPM_THROW(std::runtime_error, "Called secsSinceLast() on a StopWatch that had not been started.");
|
||||
}
|
||||
boost::posix_time::time_duration dur = run_time - last_time_;
|
||||
last_time_ = run_time;
|
||||
return double(dur.total_microseconds())/1000000.0;
|
||||
}
|
||||
|
||||
double StopWatch::secsSinceStart()
|
||||
{
|
||||
boost::posix_time::ptime run_time;
|
||||
if (state_ == Running) {
|
||||
run_time = boost::posix_time::microsec_clock::local_time();
|
||||
} else if (state_ == Stopped) {
|
||||
run_time = stop_time_;
|
||||
} else {
|
||||
assert(state_ == UnStarted);
|
||||
OPM_THROW(std::runtime_error, "Called secsSinceStart() on a StopWatch that had not been started.");
|
||||
}
|
||||
boost::posix_time::time_duration dur = run_time - start_time_;
|
||||
return double(dur.total_microseconds())/1000000.0;
|
||||
}
|
||||
|
||||
} // namespace time
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
|
||||
|
|
@ -1,81 +0,0 @@
|
|||
//===========================================================================
|
||||
//
|
||||
// File: StopWatch.hpp
|
||||
//
|
||||
// Created: Thu Jul 2 23:04:17 2009
|
||||
//
|
||||
// Author(s): Atgeirr F Rasmussen <atgeirr@sintef.no>
|
||||
//
|
||||
// $Date$
|
||||
//
|
||||
// $Revision$
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
/*
|
||||
Copyright 2009, 2010 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2009, 2010 Statoil ASA.
|
||||
|
||||
This file is part of the Open Porous Media project (OPM).
|
||||
|
||||
OPM 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.
|
||||
|
||||
OPM 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OPM. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef OPM_STOPWATCH_HEADER
|
||||
#define OPM_STOPWATCH_HEADER
|
||||
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
|
||||
namespace Opm
|
||||
{
|
||||
|
||||
namespace time
|
||||
{
|
||||
|
||||
class StopWatch
|
||||
{
|
||||
public:
|
||||
/// Default constructor. Before the StopWatch is start()-ed,
|
||||
/// it is an error to call anything other than start().
|
||||
StopWatch();
|
||||
|
||||
/// Starts the StopWatch. It is always legal to call
|
||||
/// start(), even if not stop()-ped.
|
||||
void start();
|
||||
/// Stops the StopWatch. The watch no longer runs, until
|
||||
/// restarted by a call to start().
|
||||
void stop();
|
||||
|
||||
/// \return the number of running seconds that have passed
|
||||
/// since last call to start(), secsSinceLast() or
|
||||
/// secsSinceStart()
|
||||
double secsSinceLast();
|
||||
/// \return the number of running seconds that have passed
|
||||
/// since last call to start().
|
||||
double secsSinceStart();
|
||||
|
||||
private:
|
||||
enum StopWatchState { UnStarted, Running, Stopped };
|
||||
|
||||
StopWatchState state_;
|
||||
boost::posix_time::ptime start_time_;
|
||||
boost::posix_time::ptime last_time_;
|
||||
boost::posix_time::ptime stop_time_;
|
||||
};
|
||||
|
||||
} // namespace time
|
||||
|
||||
} // namespace Opm
|
||||
|
||||
#endif // OPM_STOPWATCH_HEADER
|
|
@ -1,132 +0,0 @@
|
|||
//===========================================================================
|
||||
//
|
||||
// File: test_sparsetable.cpp
|
||||
//
|
||||
// Created: Thu May 28 10:01:46 2009
|
||||
//
|
||||
// Author(s): Atgeirr F Rasmussen <atgeirr@sintef.no>
|
||||
// Bård Skaflestad <bard.skaflestad@sintef.no>
|
||||
//
|
||||
// $Date$
|
||||
//
|
||||
// $Revision$
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
/*
|
||||
Copyright 2009, 2010 SINTEF ICT, Applied Mathematics.
|
||||
Copyright 2009, 2010 Statoil ASA.
|
||||
|
||||
This file is part of The Open Reservoir Simulator Project (OpenRS).
|
||||
|
||||
OpenRS 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.
|
||||
|
||||
OpenRS 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 for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with OpenRS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if HAVE_DYNAMIC_BOOST_TEST
|
||||
#define BOOST_TEST_DYN_LINK
|
||||
#endif
|
||||
#define NVERBOSE // to suppress our messages when throwing
|
||||
|
||||
#define BOOST_TEST_MODULE SparseTableTest
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
#include <opm/core/utility/SparseTable.hpp>
|
||||
|
||||
using namespace Opm;
|
||||
|
||||
BOOST_AUTO_TEST_CASE(construction_and_queries)
|
||||
{
|
||||
const SparseTable<int> st1;
|
||||
BOOST_CHECK(st1.empty());
|
||||
BOOST_CHECK_EQUAL(st1.size(), 0);
|
||||
BOOST_CHECK_EQUAL(st1.dataSize(), 0);
|
||||
|
||||
// This should be getting us a table like this:
|
||||
// ----------------
|
||||
// 0
|
||||
// <empty row>
|
||||
// 1 2
|
||||
// 3 4 5 6
|
||||
// 7 8 9
|
||||
// ----------------
|
||||
const int num_elem = 10;
|
||||
const int elem[num_elem] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
|
||||
const int num_rows = 5;
|
||||
const int rowsizes[num_rows] = { 1, 0, 2, 4, 3 };
|
||||
const SparseTable<int> st2(elem, elem + num_elem, rowsizes, rowsizes + num_rows);
|
||||
BOOST_CHECK(!st2.empty());
|
||||
BOOST_CHECK_EQUAL(st2.size(), num_rows);
|
||||
BOOST_CHECK_EQUAL(st2.dataSize(), num_elem);
|
||||
BOOST_CHECK_EQUAL(st2[0][0], 0);
|
||||
BOOST_CHECK_EQUAL(st2.rowSize(0), 1);
|
||||
BOOST_CHECK(st2[1].empty());
|
||||
BOOST_CHECK_EQUAL(st2.rowSize(1), 0);
|
||||
BOOST_CHECK_EQUAL(st2[3][1], 4);
|
||||
BOOST_CHECK_EQUAL(st2[4][2], 9);
|
||||
BOOST_CHECK(int(st2[4].size()) == rowsizes[4]);
|
||||
const SparseTable<int> st2_again(elem, elem + num_elem, rowsizes, rowsizes + num_rows);
|
||||
BOOST_CHECK(st2 == st2_again);
|
||||
SparseTable<int> st2_byassign;
|
||||
st2_byassign.assign(elem, elem + num_elem, rowsizes, rowsizes + num_rows);
|
||||
BOOST_CHECK(st2 == st2_byassign);
|
||||
const int last_row_size = rowsizes[num_rows - 1];
|
||||
SparseTable<int> st2_append(elem, elem + num_elem - last_row_size, rowsizes, rowsizes + num_rows - 1);
|
||||
BOOST_CHECK_EQUAL(st2_append.dataSize(), num_elem - last_row_size);
|
||||
st2_append.appendRow(elem + num_elem - last_row_size, elem + num_elem);
|
||||
BOOST_CHECK(st2 == st2_append);
|
||||
SparseTable<int> st2_append2;
|
||||
st2_append2.appendRow(elem, elem + 1);
|
||||
st2_append2.appendRow(elem + 1, elem + 1);
|
||||
st2_append2.appendRow(elem + 1, elem + 3);
|
||||
st2_append2.appendRow(elem + 3, elem + 7);
|
||||
st2_append2.appendRow(elem + 7, elem + 10);
|
||||
BOOST_CHECK(st2 == st2_append2);
|
||||
st2_append2.clear();
|
||||
SparseTable<int> st_empty;
|
||||
BOOST_CHECK(st2_append2 == st_empty);
|
||||
|
||||
SparseTable<int> st2_allocate;
|
||||
st2_allocate.allocate(rowsizes, rowsizes + num_rows);
|
||||
BOOST_CHECK_EQUAL(st2_allocate.size(), num_rows);
|
||||
BOOST_CHECK_EQUAL(st2_allocate.dataSize(), num_elem);
|
||||
int s = 0;
|
||||
for (int i = 0; i < num_rows; ++i) {
|
||||
SparseTable<int>::mutable_row_type row = st2_allocate[i];
|
||||
for (int j = 0; j < rowsizes[i]; ++j, ++s)
|
||||
row[j] = elem[s];
|
||||
}
|
||||
BOOST_CHECK(st2 == st2_allocate);
|
||||
|
||||
// One element too few.
|
||||
BOOST_CHECK_THROW(const SparseTable<int> st3(elem, elem + num_elem - 1, rowsizes, rowsizes + num_rows), std::exception);
|
||||
|
||||
// A few elements too many.
|
||||
BOOST_CHECK_THROW(const SparseTable<int> st4(elem, elem + num_elem, rowsizes, rowsizes + num_rows - 1), std::exception);
|
||||
|
||||
// Need at least one row.
|
||||
BOOST_CHECK_THROW(const SparseTable<int> st5(elem, elem + num_elem, rowsizes, rowsizes), std::exception);
|
||||
|
||||
// Tests that only run in debug mode.
|
||||
#ifndef NDEBUG
|
||||
// Do not ask for wrong row numbers.
|
||||
BOOST_CHECK_THROW(st1.rowSize(0), std::exception);
|
||||
BOOST_CHECK_THROW(st2.rowSize(-1), std::exception);
|
||||
BOOST_CHECK_THROW(st2.rowSize(st2.size()), std::exception);
|
||||
// No negative row sizes.
|
||||
const int err_rs[num_rows] = { 1, 0, -1, 7, 3 };
|
||||
BOOST_CHECK_THROW(const SparseTable<int> st6(elem, elem + num_elem, err_rs, err_rs + num_rows), std::exception);
|
||||
#endif
|
||||
}
|
Loading…
Reference in New Issue
Block a user