added: EGrid class for reading GRID data from ECL files
This commit is contained in:
parent
46f2542487
commit
181eeffbdb
@ -164,6 +164,7 @@ if(ENABLE_ECL_INPUT)
|
||||
examples/test_util/EclFile.cpp
|
||||
examples/test_util/EclOutput.cpp
|
||||
examples/test_util/EclUtil.cpp
|
||||
examples/test_util/EGrid.cpp
|
||||
examples/test_util/summaryComparator.cpp
|
||||
examples/test_util/summaryIntegrationTest.cpp
|
||||
examples/test_util/summaryRegressionTest.cpp)
|
||||
@ -174,7 +175,8 @@ if(ENABLE_ECL_INPUT)
|
||||
# Add the tests
|
||||
set(_libs testutil opmcommon
|
||||
${Boost_UNIT_TEST_FRAMEWORK_LIBRARY})
|
||||
foreach(test test_compareSummary test_EclFilesComparator test_EclIO)
|
||||
foreach(test test_compareSummary test_EclFilesComparator test_EclIO
|
||||
test_EGrid)
|
||||
opm_add_test(${test} CONDITION ENABLE_ECL_INPUT
|
||||
LIBRARIES ${_libs}
|
||||
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/tests)
|
||||
|
@ -321,6 +321,7 @@ if(ENABLE_ECL_INPUT)
|
||||
list (APPEND TEST_DATA_FILES
|
||||
tests/ECLFILE.INIT
|
||||
tests/ECLFILE.FINIT
|
||||
tests/SPE1CASE1.EGRID
|
||||
)
|
||||
list (APPEND EXAMPLE_SOURCE_FILES
|
||||
examples/opmi.cpp
|
||||
|
186
examples/test_util/EGrid.cpp
Normal file
186
examples/test_util/EGrid.cpp
Normal file
@ -0,0 +1,186 @@
|
||||
/*
|
||||
Copyright 2019 Equinor 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 "EGrid.hpp"
|
||||
|
||||
#include <opm/common/ErrorMacros.hpp>
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
#include <sstream>
|
||||
#include <iterator>
|
||||
#include <iomanip>
|
||||
#include <algorithm>
|
||||
#include <numeric>
|
||||
|
||||
|
||||
EGrid::EGrid(const std::string &filename) : EclFile(filename)
|
||||
{
|
||||
EclFile file(filename);
|
||||
|
||||
auto gridhead = get<int>("GRIDHEAD");
|
||||
|
||||
nijk[0] = gridhead[1];
|
||||
nijk[1] = gridhead[2];
|
||||
nijk[2] = gridhead[3];
|
||||
|
||||
if (file.hasKey("ACTNUM")) {
|
||||
auto actnum = get<int>("ACTNUM");
|
||||
|
||||
nactive = 0;
|
||||
for (unsigned int i = 0; i < actnum.size(); i++) {
|
||||
if (actnum[i] > 0) {
|
||||
act_index.push_back(nactive);
|
||||
glob_index.push_back(i);
|
||||
nactive++;
|
||||
} else {
|
||||
act_index.push_back(-1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
int nCells = nijk[0] * nijk[1] * nijk[2];
|
||||
act_index.resize(nCells);
|
||||
glob_index.resize(nCells);
|
||||
std::iota(act_index.begin(), act_index.end(), 0);
|
||||
std::iota(glob_index.begin(), glob_index.end(), 0);
|
||||
}
|
||||
|
||||
coord_array = get<float>("COORD");
|
||||
zcorn_array = get<float>("ZCORN");
|
||||
}
|
||||
|
||||
|
||||
int EGrid::global_index(int i, int j, int k) const
|
||||
{
|
||||
if (i < 0 || i >= nijk[0] || j < 0 || j >= nijk[1] || k < 0 || k >= nijk[2]) {
|
||||
OPM_THROW(std::invalid_argument, "i, j or/and k out of range");
|
||||
}
|
||||
|
||||
return i + j * nijk[0] + k * nijk[0] * nijk[1];
|
||||
}
|
||||
|
||||
|
||||
int EGrid::active_index(int i, int j, int k) const
|
||||
{
|
||||
int n = i + j * nijk[0] + k * nijk[0] * nijk[1];
|
||||
|
||||
if (i < 0 || i >= nijk[0] || j < 0 || j >= nijk[1] || k < 0 || k >= nijk[2]) {
|
||||
OPM_THROW(std::invalid_argument, "i, j or/and k out of range");
|
||||
}
|
||||
|
||||
return act_index[n];
|
||||
}
|
||||
|
||||
|
||||
std::array<int, 3> EGrid::ijk_from_active_index(int actInd) const
|
||||
{
|
||||
if (actInd < 0 || actInd >= nactive) {
|
||||
OPM_THROW(std::invalid_argument, "active index out of range");
|
||||
}
|
||||
|
||||
int _glob = glob_index[actInd];
|
||||
|
||||
std::array<int, 3> result;
|
||||
result[2] = _glob / (nijk[0] * nijk[1]);
|
||||
|
||||
int rest = _glob % (nijk[0] * nijk[1]);
|
||||
|
||||
result[1] = rest / nijk[0];
|
||||
result[0] = rest % nijk[0];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
std::array<int, 3> EGrid::ijk_from_global_index(int globInd) const
|
||||
{
|
||||
if (globInd < 0 || globInd >= nijk[0] * nijk[1] * nijk[2]) {
|
||||
OPM_THROW(std::invalid_argument, "global index out of range");
|
||||
}
|
||||
|
||||
std::array<int, 3> result;
|
||||
result[2] = globInd / (nijk[0] * nijk[1]);
|
||||
|
||||
int rest = globInd % (nijk[0] * nijk[1]);
|
||||
|
||||
result[1] = rest / nijk[0];
|
||||
result[0] = rest % nijk[0];
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void EGrid::getCellCorners(const std::array<int, 3>& ijk,
|
||||
std::vector<double>& X,
|
||||
std::vector<double>& Y,
|
||||
std::vector<double>& Z) const
|
||||
{
|
||||
std::vector<int> zind;
|
||||
std::vector<int> pind;
|
||||
|
||||
if (X.size() < 8 || Y.size() < 8 || Z.size() < 8) {
|
||||
OPM_THROW(std::invalid_argument,
|
||||
"In routine cellConrner. X, Y and Z should be a vector of size 8");
|
||||
}
|
||||
|
||||
if (ijk[0] < 0 || ijk[0] >= nijk[0] || ijk[1] < 0 || ijk[1] >= nijk[1] || ijk[2] < 0 || ijk[2] >= nijk[2]) {
|
||||
OPM_THROW(std::invalid_argument, "i, j and/or k out of range");
|
||||
}
|
||||
|
||||
// calculate indices for grid pillars in COORD arrray
|
||||
pind.push_back(ijk[1]*(nijk[0]+1)*6 + ijk[0]*6);
|
||||
pind.push_back(pind[0] + 6);
|
||||
pind.push_back(pind[0] + (nijk[0]+1)*6);
|
||||
pind.push_back(pind[2] + 6);
|
||||
|
||||
// get depths from zcorn array in ZCORN array
|
||||
zind.push_back(ijk[2]*nijk[0]*nijk[1]*8 + ijk[1]*nijk[0]*4 + ijk[0]*2);
|
||||
zind.push_back(zind[0] + 1);
|
||||
zind.push_back(zind[0] + nijk[0]*2);
|
||||
zind.push_back(zind[2] + 1);
|
||||
|
||||
for (int n = 0; n < 4; n++) {
|
||||
zind.push_back(zind[n] + nijk[0]*nijk[1]*4);
|
||||
}
|
||||
|
||||
for (int n = 0; n< 8; n++){
|
||||
Z[n] = zcorn_array[zind[n]];
|
||||
}
|
||||
|
||||
for (int n = 0; n < 4; n++) {
|
||||
double xt = coord_array[pind[n]];
|
||||
double yt = coord_array[pind[n] + 1];
|
||||
double zt = coord_array[pind[n] + 2];
|
||||
|
||||
double xb = coord_array[pind[n] + 3];
|
||||
double yb = coord_array[pind[n] + 4];
|
||||
double zb = coord_array[pind[n]+5];
|
||||
|
||||
X[n] = xt + (xb-xt) / (zt-zb) * (zt - Z[n]);
|
||||
X[n+4] = xt + (xb-xt) / (zt-zb) * (zt-Z[n+4]);
|
||||
|
||||
Y[n] = yt+(yb-yt)/(zt-zb)*(zt-Z[n]);
|
||||
Y[n+4] = yt+(yb-yt)/(zt-zb)*(zt-Z[n+4]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void EGrid::getCellCorners(int globindex, std::vector<double>& X,
|
||||
std::vector<double>& Y, std::vector<double>& Z) const
|
||||
{
|
||||
return getCellCorners(ijk_from_global_index(globindex),X,Y,Z);
|
||||
}
|
62
examples/test_util/EGrid.hpp
Normal file
62
examples/test_util/EGrid.hpp
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
Copyright 2019 Equinor 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 EGRID_HPP
|
||||
#define EGRID_HPP
|
||||
|
||||
#include "EclFile.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
#include <ctime>
|
||||
#include <map>
|
||||
|
||||
|
||||
class EGrid : public EclFile
|
||||
{
|
||||
public:
|
||||
explicit EGrid(const std::string& filename);
|
||||
|
||||
int global_index(int i, int j, int k) const;
|
||||
int active_index(int i, int j, int k) const;
|
||||
|
||||
const std::array<int, 3>& dimension() const { return nijk; }
|
||||
|
||||
std::array<int, 3> ijk_from_active_index(int actInd) const;
|
||||
std::array<int, 3> ijk_from_global_index(int globInd) const;
|
||||
|
||||
void getCellCorners(int globindex, std::vector<double>& X, std::vector<double>& Y, std::vector<double>& Z) const;
|
||||
void getCellCorners(const std::array<int, 3>& ijk, std::vector<double>& X, std::vector<double>& Y, std::vector<double>& Z) const;
|
||||
|
||||
int activeCells() const { return nactive; }
|
||||
int totalNumberOfCells() const { return nijk[0] * nijk[1] * nijk[2]; }
|
||||
|
||||
private:
|
||||
std::array<int, 3> nijk;
|
||||
int nNNC, nactive;
|
||||
|
||||
std::vector<int> act_index;
|
||||
std::vector<int> glob_index;
|
||||
std::vector<float> coord_array;
|
||||
std::vector<float> zcorn_array;
|
||||
};
|
||||
|
||||
#endif
|
BIN
tests/SPE1CASE1.EGRID
Normal file
BIN
tests/SPE1CASE1.EGRID
Normal file
Binary file not shown.
181
tests/test_EGrid.cpp
Normal file
181
tests/test_EGrid.cpp
Normal file
@ -0,0 +1,181 @@
|
||||
/*
|
||||
+ Copyright 2019 Equinor 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 <iostream>
|
||||
#include <stdio.h>
|
||||
#include <iomanip>
|
||||
#include <math.h>
|
||||
#include <algorithm>
|
||||
#include <tuple>
|
||||
|
||||
#include <examples/test_util/EGrid.hpp>
|
||||
|
||||
#define BOOST_TEST_MODULE Test EGrid
|
||||
#include <boost/test/unit_test.hpp>
|
||||
|
||||
template<typename InputIterator1, typename InputIterator2>
|
||||
bool
|
||||
range_equal(InputIterator1 first1, InputIterator1 last1,
|
||||
InputIterator2 first2, InputIterator2 last2)
|
||||
{
|
||||
while(first1 != last1 && first2 != last2)
|
||||
{
|
||||
if(*first1 != *first2) return false;
|
||||
++first1;
|
||||
++first2;
|
||||
}
|
||||
return (first1 == last1) && (first2 == last2);
|
||||
}
|
||||
|
||||
bool compare_files(const std::string& filename1, const std::string& filename2)
|
||||
{
|
||||
std::ifstream file1(filename1);
|
||||
std::ifstream file2(filename2);
|
||||
|
||||
std::istreambuf_iterator<char> begin1(file1);
|
||||
std::istreambuf_iterator<char> begin2(file2);
|
||||
|
||||
std::istreambuf_iterator<char> end;
|
||||
|
||||
return range_equal(begin1, end, begin2, end);
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
bool operator==(const std::vector<T> & t1, const std::vector<T> & t2)
|
||||
{
|
||||
return std::equal(t1.begin(), t1.end(), t2.begin(), t2.end());
|
||||
}
|
||||
|
||||
// test is using SPE1CASE1, with minor modifications in order to test API for EGrid class
|
||||
// -> 6 cells made inactive, box: 5 7 5 6 1 1
|
||||
|
||||
// first pilar at x=0.0, y=0.0 and z=0.0
|
||||
// dx = 1000 ft, dy = 1000 ft. dz = 20 ft for layer 1, 30 ft for layer 2 and 50 ft for layer 3.
|
||||
// size of grid is 10x10x3
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(DimensAndIndices) {
|
||||
|
||||
std::string testFile="SPE1CASE1.EGRID";
|
||||
|
||||
EGrid grid1(testFile);
|
||||
|
||||
int nAct=grid1.activeCells();
|
||||
int nTot=grid1.totalNumberOfCells();
|
||||
|
||||
BOOST_CHECK_EQUAL(nAct,294);
|
||||
BOOST_CHECK_EQUAL(nTot,300);
|
||||
|
||||
auto dim = grid1.dimension();
|
||||
|
||||
BOOST_CHECK_EQUAL(dim[0],10);
|
||||
BOOST_CHECK_EQUAL(dim[1],10);
|
||||
BOOST_CHECK_EQUAL(dim[2],3);
|
||||
|
||||
int globInd = grid1.global_index(3, 2, 1);
|
||||
|
||||
BOOST_CHECK_EQUAL(globInd, 123); // 10*10*1 + 10*2 + 3 = 100+20+3 = 123
|
||||
|
||||
BOOST_CHECK_EQUAL(grid1.global_index(0, 0, 0), 0);
|
||||
BOOST_CHECK_EQUAL(grid1.global_index(dim[0] - 1, dim[1] - 1, dim[2] - 1), nTot - 1);
|
||||
|
||||
// check global_index valid range, should throw exception if outside
|
||||
|
||||
BOOST_CHECK_THROW(grid1.global_index(-1, -1, -1), std::invalid_argument);
|
||||
BOOST_CHECK_THROW(grid1.global_index(0, -1, 0), std::invalid_argument);
|
||||
BOOST_CHECK_THROW(grid1.global_index(0, 0, -1), std::invalid_argument);
|
||||
|
||||
BOOST_CHECK_THROW(grid1.global_index(dim[0], 0, 0), std::invalid_argument);
|
||||
BOOST_CHECK_THROW(grid1.global_index(dim[0], dim[1], 0), std::invalid_argument);
|
||||
BOOST_CHECK_THROW(grid1.global_index(dim[0], dim[1], dim[2]), std::invalid_argument);
|
||||
|
||||
// 6 inactive cells in first layer, actInd not same as glogInd
|
||||
// actInd and globInd are zero based indices
|
||||
|
||||
int actInd = grid1.active_index(3,2,1);
|
||||
|
||||
BOOST_CHECK_EQUAL(actInd, 117); // global index 123, - 6 inactive
|
||||
BOOST_CHECK_EQUAL(grid1.active_index(0, 0, 0), 0);
|
||||
BOOST_CHECK_EQUAL(grid1.active_index(dim[0] - 1, dim[1] - 1, dim[2] - 1), nAct - 1);
|
||||
|
||||
// check active_index valid range, should throw exception if outside
|
||||
|
||||
BOOST_CHECK_THROW(grid1.active_index(-1, 0, 0), std::invalid_argument);
|
||||
BOOST_CHECK_THROW(grid1.active_index(-1, -1, 0), std::invalid_argument);
|
||||
BOOST_CHECK_THROW(grid1.active_index(-1, -1, -1), std::invalid_argument);
|
||||
|
||||
BOOST_CHECK_THROW(grid1.active_index(dim[0], 0, 0), std::invalid_argument);
|
||||
BOOST_CHECK_THROW(grid1.active_index(dim[0], dim[1], 0), std::invalid_argument);
|
||||
BOOST_CHECK_THROW(grid1.active_index(dim[0], dim[1], dim[2]), std::invalid_argument);
|
||||
|
||||
auto res = grid1.ijk_from_active_index(actInd);
|
||||
|
||||
BOOST_CHECK_EQUAL(res[0], 3);
|
||||
BOOST_CHECK_EQUAL(res[1], 2);
|
||||
BOOST_CHECK_EQUAL(res[2], 1);
|
||||
|
||||
BOOST_CHECK_THROW(grid1.ijk_from_active_index(-1), std::invalid_argument);
|
||||
BOOST_CHECK_THROW(grid1.ijk_from_active_index(nAct), std::invalid_argument);
|
||||
|
||||
res = grid1.ijk_from_global_index(globInd);
|
||||
|
||||
BOOST_CHECK_EQUAL(res[0], 3);
|
||||
BOOST_CHECK_EQUAL(res[1], 2);
|
||||
BOOST_CHECK_EQUAL(res[2], 1);
|
||||
|
||||
BOOST_CHECK_THROW(grid1.ijk_from_global_index(-1), std::invalid_argument);
|
||||
BOOST_CHECK_THROW(grid1.ijk_from_global_index(nTot), std::invalid_argument);
|
||||
}
|
||||
|
||||
|
||||
BOOST_AUTO_TEST_CASE(getCellCorners) {
|
||||
|
||||
std::string testFile="SPE1CASE1.EGRID";
|
||||
|
||||
std::vector<double> ref_X = {3000,4000,3000,4000,3000,4000,3000,4000};
|
||||
std::vector<double> ref_Y = {2000,2000,3000,3000,2000,2000,3000,3000};
|
||||
std::vector<double> ref_Z = {8345,8345,8345,8345,8375,8375,8375,8375};
|
||||
|
||||
EGrid grid1(testFile);
|
||||
|
||||
std::vector<double> X(8,0.0);
|
||||
std::vector<double> Y(8,0.0);
|
||||
std::vector<double> Z(8,0.0);
|
||||
|
||||
// cell 4,3,2 => zero based 3,2,1
|
||||
grid1.getCellCorners({3, 2, 1}, X, Y, Z);
|
||||
|
||||
BOOST_CHECK_EQUAL(X == ref_X, true);
|
||||
BOOST_CHECK_EQUAL(Y == ref_Y, true);
|
||||
BOOST_CHECK_EQUAL(Z == ref_Z, true);
|
||||
|
||||
X.assign(8,0.0);
|
||||
Y.assign(8,0.0);
|
||||
Z.assign(8,0.0);
|
||||
|
||||
int globInd=grid1.global_index(3,2,1);
|
||||
|
||||
grid1.getCellCorners(globInd,X,Y,Z);
|
||||
|
||||
BOOST_CHECK_EQUAL(X == ref_X, true);
|
||||
BOOST_CHECK_EQUAL(Y == ref_Y, true);
|
||||
BOOST_CHECK_EQUAL(Z == ref_Z, true);
|
||||
}
|
Loading…
Reference in New Issue
Block a user