Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 13 additions & 12 deletions opm/grid/cpgrid/CpGrid.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1027,18 +1027,19 @@ void CpGrid::globalRefine (int refCount)
if (refCount < 0) {
OPM_THROW(std::logic_error, "Invalid argument. Provide a nonnegative integer for global refinement.");
}
// Throw if the grid has been already partially refined, i.e., there exist coarse cells with more than 6 faces.
// This is the case when a coarse cell has not been marked for refinement, but at least one of its neighboring cells
// got refined. Therefore, the coarse face that they share got replaced by refined-faces. In this case, we do not
// support yet global refinement.
if(this->maxLevel()) {
bool isOnlyGlobalRefined = true;
for (int level = 0; level < this->maxLevel(); ++level) {
// When the grid has been refined only via global refinement, i.e., each cell has been refined into 2x2x2 children cells,
// then the quotient between the total amount of two consecutive refined level grids is equal to 8 = 2x2x2.
isOnlyGlobalRefined = isOnlyGlobalRefined && ( (currentData()[level+1]->size(0)) / (currentData()[level]->size(0)) == 8 );
}
if (!isOnlyGlobalRefined) {

// Throw if partial refinement is detected (there exists at least one coarse cell with >6 faces).
if(this->maxLevel()) { // In particular, maxLevel()>=1
// Detect whether the grid has been globally refined before (via globalRefine(...)
// or autoRefine(...)) by comparing the logicalCartesianSize() of the level-0
// grid and the leaf grid.
//
// For strict local refinement, these sizes are identical. Global refinement
// results in a difference in at least one direction (x, y, or z).
bool sameNX = currentData().back()->logicalCartesianSize()[0] == currentData().front()->logicalCartesianSize()[0];
bool sameNY = currentData().back()->logicalCartesianSize()[1] == currentData().front()->logicalCartesianSize()[1];
bool sameNZ = currentData().back()->logicalCartesianSize()[2] == currentData().front()->logicalCartesianSize()[2];
if (sameNX && sameNY && sameNZ) {
OPM_THROW(std::logic_error, "Global refinement of a mixed grid with coarse and refined cells is not supported yet.");
}
}
Expand Down
198 changes: 186 additions & 12 deletions tests/cpgrid/lgr/autoRefine_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,18 @@
#define BOOST_TEST_MODULE AutoRefineTests
#include <boost/test/unit_test.hpp>

#include <opm/input/eclipse/Deck/Deck.hpp>
#include <opm/input/eclipse/Parser/Parser.hpp>
#include <opm/input/eclipse/EclipseState/EclipseState.hpp>
#include <opm/input/eclipse/EclipseState/Grid/AutoRefinement.hpp>
#include <opm/input/eclipse/EclipseState/Grid/AutoRefManager.hpp>
#include <opm/input/eclipse/EclipseState/Grid/readKeywordAutoRef.hpp>
#include <opm/input/eclipse/EclipseState/EclipseState.hpp>

#include <opm/grid/CpGrid.hpp>
#include <tests/cpgrid/lgr/LgrChecks.hpp>

#include <array>
#include <string>
#include <vector>

Expand All @@ -40,6 +49,43 @@ struct Fixture

BOOST_GLOBAL_FIXTURE(Fixture);

void checkReadFromDeckValues(const Opm::Deck& deck,
const std::array<int,3>& expected_nxnynz,
double expected_option)
{
const auto& autoref_keyword = deck["AUTOREF"][0];

Opm::AutoRefManager autoRefManager{};

Opm::readKeywordAutoRef(autoref_keyword.getRecord(0), autoRefManager);
const auto autoRef = autoRefManager.getAutoRef();

BOOST_CHECK_EQUAL( autoRef.NX(), expected_nxnynz[0]);
BOOST_CHECK_EQUAL( autoRef.NY(), expected_nxnynz[1]);
BOOST_CHECK_EQUAL( autoRef.NZ(), expected_nxnynz[2]);
BOOST_CHECK_EQUAL( autoRef.OPTION_TRANS_MULT(), expected_option);
}

void checkGridAfterAutoRefinement(const Dune::CpGrid& grid,
const std::array<int,3>& nxnynz)
{
// Extract the refined level grids name, excluding level zero grid name ("GLOBAL").
// Note: in this case there is only one refined level grid, storing the global
// refinement.
std::vector<std::string> lgrNames(grid.maxLevel());
for (const auto& [name, level] : grid.getLgrNameToLevel()) {
if (level==0) { // skip level zero grid name for the checks
continue;
}
lgrNames[level-1] = name; // Shift the index since level zero has been removed.
}
Opm::checkGridWithLgrs(grid,
/* cells_per_dim_vec = */ {nxnynz},
/* lgr_name_vec = */ lgrNames,
/* gridHasBeenGlobalRefined = */ true);
}


BOOST_AUTO_TEST_CASE(evenRefinementFactorThrows)
{
Dune::CpGrid grid;
Expand Down Expand Up @@ -74,18 +120,146 @@ BOOST_AUTO_TEST_CASE(autoRefine)
// nxnynz represents the refinement factors in x-,y-,and z-direction.
grid.autoRefine(/* nxnynz = */ {3,5,7});

// Extract the refined level grids name, excluding level zero grid name ("GLOBAL").
// Note: in this case there is only one refined level grid, storing the global
// refinement.
std::vector<std::string> lgrNames(grid.maxLevel());
for (const auto& [name, level] : grid.getLgrNameToLevel()) {
if (level==0) { // skip level zero grid name for the checks
continue;
checkGridAfterAutoRefinement(grid, {3,5,7});
}

BOOST_AUTO_TEST_CASE(readAutoref)
{

const std::string deck_string = R"(
RUNSPEC
AUTOREF
3 3 1 0. /
DIMENS
10 10 3 /
GRID
DX
300*1 /
DY
300*1 /
DZ
300*1 /
TOPS
100*1 /
PORO
300*0.15 /
)";

Opm::Parser parser;
Opm::Deck deck = parser.parseString(deck_string);

checkReadFromDeckValues(deck,
{3,3,1}, // expected_nxnynz
0.); // expected_option_trans_mult

Opm::EclipseState ecl_state(deck);
Opm::EclipseGrid ecl_grid = ecl_state.getInputGrid();

Dune::CpGrid grid;
grid.processEclipseFormat(&ecl_grid, &ecl_state, false, false, false);

if (grid.comm().size()>1) { // distribute level zero grid, in parallel
grid.loadBalance();
}

// nxnynz represents the refinement factors in x-,y-,and z-direction.
grid.autoRefine(/* nxnynz = */ {3,3,1});

checkGridAfterAutoRefinement(grid, /* nxnynz = */ {3,3,1});
}

BOOST_AUTO_TEST_CASE(firstAutoRefineSecondGlobalRefine_serial) {

const std::string deck_string = R"(
RUNSPEC
AUTOREF
3 3 1 0. /
DIMENS
4 3 3 /
GRID
DX
36*1 /
DY
36*1 /
DZ
36*1 /
TOPS
36*1 /
PORO
36*0.15 /
)";

Opm::Parser parser;
Opm::Deck deck = parser.parseString(deck_string);

checkReadFromDeckValues(deck,
{3,3,1}, // expected_nxnynz
0.); // expected_option_trans_mult

Opm::EclipseState ecl_state(deck);
Opm::EclipseGrid ecl_grid = ecl_state.getInputGrid();

Dune::CpGrid grid;
grid.processEclipseFormat(&ecl_grid, &ecl_state, false, false, false);

if (grid.comm().size() == 1 ) { // serial

// nxnynz represents the refinement factors in x-,y-,and z-direction.
grid.autoRefine(/* nxnynz = */ {3,3,1});

checkGridAfterAutoRefinement(grid, /* nxnynz = */ {3,3,1});

grid.globalRefine(2);
}
}


BOOST_AUTO_TEST_CASE(firstAutoRefineSecondAdapt_serial) {

const std::string deck_string = R"(
RUNSPEC
AUTOREF
3 3 1 0. /
DIMENS
4 3 3 /
GRID
DX
36*1 /
DY
36*1 /
DZ
36*1 /
TOPS
36*1 /
PORO
36*0.15 /
)";

Opm::Parser parser;
Opm::Deck deck = parser.parseString(deck_string);

checkReadFromDeckValues(deck,
{3,3,1}, // expected_nxnynz
0.); // expected_option_trans_mult

Opm::EclipseState ecl_state(deck);
Opm::EclipseGrid ecl_grid = ecl_state.getInputGrid();

Dune::CpGrid grid;
grid.processEclipseFormat(&ecl_grid, &ecl_state, false, false, false);

if (grid.comm().size() == 1 ) { // serial

// nxnynz represents the refinement factors in x-,y-,and z-direction.
grid.autoRefine(/* nxnynz = */ {3,3,1});

checkGridAfterAutoRefinement(grid, /* nxnynz = */ {3,3,1});

for (const auto& element : Dune::elements(grid.leafGridView())) {
grid.mark(1, element);
}
lgrNames[level-1] = name; // Shift the index since level zero has been removed.
grid.preAdapt();
grid.adapt();
grid.postAdapt();
}
Opm::checkGridWithLgrs(grid,
/* cells_per_dim_vec = */ {{3,5,7}},
/* lgr_name_vec = */ lgrNames,
/* gridHasBeenGlobalRefined = */ true);
}