Files
opm-upscaling/examples/cpregularize.cpp
Arne Morten Kvarving e41517a68e bump required dune version to 2.6
remove compatiblity code for older versions
2020-02-06 16:29:35 +01:00

288 lines
10 KiB
C++

/*
Copyright 2010 SINTEF ICT, Applied Mathematics.
Copyright 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/>.
*/
/**
Program to regularize cornerpoint grids
Caveats:
- Only grids with vertical pillars
- CornerPointChopper can only chop along existing pillars. In case
your asked-for horizontal resolution does not divide the initial
number of pillars in x/y, you will not obtain a fully regular
grid, but still easier numerically.
- Be careful with non-flat top and bottom boundary.
*/
#include <config.h>
#include <opm/parser/eclipse/Parser/Parser.hpp>
#include <opm/parser/eclipse/Deck/Deck.hpp>
#include <opm/common/utility/platform_dependent/disable_warnings.h>
#include <dune/common/version.hh>
#include <dune/common/parallel/mpihelper.hh>
#include <opm/common/utility/platform_dependent/reenable_warnings.h>
#include <opm/parser/eclipse/Units/Units.hpp>
#include <opm/upscaling/CornerpointChopper.hpp>
#include <opm/output/eclipse/EclipseGridInspector.hpp>
#include <opm/porsol/common/setupBoundaryConditions.hpp>
#include <opm/upscaling/SinglePhaseUpscaler.hpp>
#include <ctime>
#include <fstream>
#include <iomanip>
#include <ios>
#include <iostream>
#include <sstream>
#include <sys/utsname.h>
int main(int argc, char** argv)
try
{
if (argc == 1) {
std::cout << "Usage: cpregularize gridfilename=filename.grdecl [ires=5] [jres=5] [zres=5] " << std::endl;
std::cout << " [imin=] [imax=] [jmin=] [jmax=] [zmin=] [zmax=] " << std::endl;
std::cout << " [minperm=1e-9] " << std::endl;
std::cout << " [resultgrid=regularizedgrid.grdecl]" << std::endl;
exit(1);
}
Dune::MPIHelper::instance(argc, argv);
Opm::ParameterGroup param(argc, argv);
std::string gridfilename = param.get<std::string>("gridfilename");
Opm::CornerPointChopper ch(gridfilename);
// The cells with i coordinate in [imin, imax) are included, similar for j.
// The z limits may be changed inside the chopper to match actual min/max z.
const int* dims = ch.dimensions();
int imin = param.getDefault("imin", 0);
int imax = param.getDefault("imax", dims[0]);
int jmin = param.getDefault("jmin", 0);
int jmax = param.getDefault("jmax", dims[1]);
double zmin = param.getDefault("zmin", ch.zLimits().first);
double zmax = param.getDefault("zmax", ch.zLimits().second);
int ires = param.getDefault("ires", 1);
int jres = param.getDefault("jres", 1);
int zres = param.getDefault("zres", 1);
std::string resultgrid = param.getDefault<std::string>("resultgrid", "regularizedgrid.grdecl");
if (param.has("z_tolerance")) {
std::cerr << "****** Warning: z_tolerance parameter is obsolete, use PINCH in deck input instead\n";
}
// Check for unused parameters (potential typos).
if (param.anyUnused()) {
std::cout << "***** WARNING: Unused parameters: *****\n";
param.displayUsage();
}
// Check that we do not have any user input
// that goes outside the coordinates described in
// the cornerpoint file (runtime-exception will be thrown in case of error)
// (ilen, jlen and zlen set to zero, does not apply here)
ch.verifyInscribedShoebox(imin, 0, imax,
jmin, 0, jmax,
zmin, 0, zmax);
// Storage for properties for regularized cells
std::vector<double> poro;
std::vector<double> permx;
std::vector<double> permy;
std::vector<double> permz;
// Original x/y resolution in terms of coordinate values (not indices)
Opm::Parser parser;
auto deck = parser.parseFile(gridfilename); // TODO: REFACTOR!!!! it is stupid to parse this again
Opm::EclipseGridInspector gridinspector(deck);
std::array<double, 6> gridlimits=gridinspector.getGridLimits();
double finegridxresolution = (gridlimits[1]-gridlimits[0])/dims[0];
double finegridyresolution = (gridlimits[3]-gridlimits[2])/dims[1];
// Construct mapping from coarse i and j indices to fine
// and COORDS values for regularized pillars.
std::vector<int> iidx_f, jidx_f;
std::vector<double> newcoords_x;
int finesprcoarse_i = floor(dims[0] / ires);
int remainder_i = dims[0] - ires*finesprcoarse_i;
for (int iidx_c=0; iidx_c < remainder_i+1; ++iidx_c) {
iidx_f.push_back(iidx_c*(finesprcoarse_i + 1)); // Spread remainder evenly
}
for (int iidx_c=remainder_i + 1; iidx_c < ires; ++iidx_c) {
iidx_f.push_back(iidx_c*finesprcoarse_i + remainder_i);
}
iidx_f.push_back(imax); // endpoint needed below
int finesprcoarse_j = floor(dims[1] / jres);
int remainder_j = dims[1] - jres*finesprcoarse_j;
for (int jidx_c=0; jidx_c < remainder_j+1; ++jidx_c) {
jidx_f.push_back(jidx_c*(finesprcoarse_j + 1)); // Spread remainder evenly
}
for (int jidx_c=remainder_j + 1; jidx_c < jres; ++jidx_c) {
jidx_f.push_back(jidx_c*finesprcoarse_j + remainder_j);
}
jidx_f.push_back(jmax); // endpoint needed below
// Construct new ZCORN for regular grid
std::vector<double> zcorn_c;
for (int zidx_c=0; zidx_c < zres; ++zidx_c) {
zcorn_c.push_back(zmin + zidx_c * (zmax-zmin)/zres);
}
zcorn_c.push_back(zmax);
// Run through the new regular grid to find its properties
for (int zidx_c=0; zidx_c < zres; ++zidx_c) {
for (int jidx_c=0; jidx_c < jres; ++jidx_c) {
for (int iidx_c=0; iidx_c < ires; ++iidx_c) {
ch.chop(iidx_f[iidx_c], iidx_f[iidx_c+1],
jidx_f[jidx_c], jidx_f[jidx_c+1],
zcorn_c[zidx_c], zcorn_c[zidx_c+1],
false);
OPM_THROW(std::logic_error, "Sub-decks not are not implemented by opm-parser. Refactor the calling code!?");
try {
auto subdeck = ch.subDeck();
double minperm = param.getDefault("minperm", 1e-9);
double minpermSI = Opm::unit::convert::from(minperm, Opm::prefix::milli*Opm::unit::darcy);
double residual_tolerance = param.getDefault("residual_tolerance", 1e-8);
double linsolver_verbosity = param.getDefault("linsolver_verbosity", 0);
double linsolver_type = param.getDefault("linsolver_type", 1);
Opm::SinglePhaseUpscaler upscaler;
upscaler.init(subdeck, Opm::SinglePhaseUpscaler::Fixed, minpermSI,
residual_tolerance, linsolver_verbosity, linsolver_type, false);
Opm::SinglePhaseUpscaler::permtensor_t upscaled_K = upscaler.upscaleSinglePhase();
upscaled_K *= (1.0/(Opm::prefix::milli*Opm::unit::darcy));
poro.push_back(upscaler.upscalePorosity());
permx.push_back(upscaled_K(0,0));
permy.push_back(upscaled_K(1,1));
permz.push_back(upscaled_K(2,2));
}
catch (...) {
std::cout << "Warning: Upscaling for cell failed to convert, values set to zero\n";
poro.push_back(0.0);
permx.push_back(0.0);
permy.push_back(0.0);
permz.push_back(0.0);
}
}
}
}
// Write regularized grid to outputfile
std::ofstream out(resultgrid.c_str());
if (!out) {
std::cerr << "Could not open file " << resultgrid << "\n";
throw std::runtime_error("Could not open output file.");
}
out << "SPECGRID\n" << ires << ' ' << jres << ' ' << zres
<< " 1 F\n/\n\n";
out << "COORD\n";
for (int j = 0; j <= jres; ++j) {
for (int i = 0; i <= ires; ++i) {
out << finegridxresolution*iidx_f[i] << " " << finegridyresolution*jidx_f[j] << " " << zmin << " "
<< finegridxresolution*iidx_f[i] << " " << finegridyresolution*jidx_f[j] << " " << zmax << "\n";
}
}
out << "/\n\n";
/*
Write ZCORN, that is the Z-coordinates along the pillars, specifying
the eight corners of each cell. Each corner is specified for each
cell, even though it is the same corner that is used in other
cells.
We loop over corners in each grid cell, directions: z, y, x (x innermost).
The code here *IS* redundant, but the grid is also very redundant
for a grid that is really regular..
*/
out << "ZCORN\n";
double zlen = zmax-zmin;
for (int zidx=0; zidx < zres; ++zidx) {
for (int j = 0; j < jres; ++j) {
for (int i = 0; i < ires; ++i) {
out << zlen/zres*zidx << " " << zlen/zres*zidx << " ";
}
out << "\n";
for (int i = 0; i < ires; ++i) {
out << zlen/zres*zidx << " " << zlen/zres*zidx << " ";
}
}
for (int j = 0; j < jres; ++j) {
for (int i = 0; i < ires; ++i) {
out << zlen/zres*(zidx+1) << " " << zlen/zres*(zidx+1) << " ";
}
out << "\n";
for (int i = 0; i < ires; ++i) {
out << zlen/zres*(zidx+1) << " " << zlen/zres*(zidx+1) << " ";
}
}
}
out << "/\n\n";
out << "PORO\n";
for (size_t idx=0; idx < (size_t)poro.size(); ++idx) {
out << poro[idx] << std::endl;
}
out << "/\n\n";
out << "PERMX\n";
for (size_t idx=0; idx < (size_t)permx.size(); ++idx) {
out << permx[idx] << std::endl;
}
out << "/\n\n";
out << "PERMY\n\n";
for (size_t idx=0; idx < (size_t)permy.size(); ++idx) {
out << permy[idx] << std::endl;
}
out << "/\n\n";
out << "PERMZ\n\n";
for (size_t idx=0; idx < (size_t)permz.size(); ++idx) {
out << permz[idx] << std::endl;
}
out << "/\n";
out.close();
}
catch (const std::exception &e) {
std::cerr << "Program threw an exception: " << e.what() << "\n";
throw;
}