From a4f0ced06fd878a537d0d02791e7c32083e54f12 Mon Sep 17 00:00:00 2001 From: Antonella Ritorto Date: Tue, 28 Apr 2026 09:45:51 +0200 Subject: [PATCH 1/3] LGRs and Faults, computing intersection of segments approach --- CMakeLists_files.cmake | 5 +- opm/grid/cpgrid/CpGrid.cpp | 31 +- opm/grid/cpgrid/CpGridData.cpp | 179 +- opm/grid/cpgrid/CpGridData.hpp | 47 +- opm/grid/cpgrid/LgrFaultHelpers.cpp | 1235 ++++++++++++ opm/grid/cpgrid/LgrFaultHelpers.hpp | 650 +++++++ opm/grid/cpgrid/LgrHelpers.cpp | 1343 +++++++------ opm/grid/cpgrid/LgrHelpers.hpp | 261 ++- ...ices_of_overlapping_intersections_test.cpp | 1679 +++++++++++++++++ ...gr1_corner_idx_by_lgr2_corner_idx_test.cpp | 304 --- ...ce_lgr1_face_idx_by_lgr2_face_idx_test.cpp | 259 --- 11 files changed, 4467 insertions(+), 1526 deletions(-) create mode 100644 opm/grid/cpgrid/LgrFaultHelpers.cpp create mode 100644 opm/grid/cpgrid/LgrFaultHelpers.hpp create mode 100644 tests/cpgrid/lgr/compute_new_vertices_of_overlapping_intersections_test.cpp delete mode 100644 tests/cpgrid/lgr/replace_lgr1_corner_idx_by_lgr2_corner_idx_test.cpp delete mode 100644 tests/cpgrid/lgr/replace_lgr1_face_idx_by_lgr2_face_idx_test.cpp diff --git a/CMakeLists_files.cmake b/CMakeLists_files.cmake index 0d31c27e3..b7a51130c 100644 --- a/CMakeLists_files.cmake +++ b/CMakeLists_files.cmake @@ -37,6 +37,7 @@ list(APPEND MAIN_SOURCE_FILES opm/grid/cpgrid/GridHelpers.cpp opm/grid/cpgrid/Iterators.cpp opm/grid/cpgrid/Indexsets.cpp + opm/grid/cpgrid/LgrFaultHelpers.cpp opm/grid/cpgrid/LgrHelpers.cpp opm/grid/cpgrid/LgrOutputHelpers.cpp opm/grid/cpgrid/NestedRefinementUtilities.cpp @@ -112,14 +113,13 @@ list(APPEND TEST_SOURCE_FILES tests/cpgrid/lgr/addLgrs_in_allActiveCartesianGrid_test.cpp tests/cpgrid/lgr/addLgrsOnDistributedGrid_test.cpp tests/cpgrid/lgr/autoRefine_test.cpp + tests/cpgrid/lgr/compute_new_vertices_of_overlapping_intersections_test.cpp tests/cpgrid/lgr/global_refine_test.cpp tests/cpgrid/lgr/id_entity_entityrep_test.cpp tests/cpgrid/lgr/level_and_grid_cartesianIndexMappers_test.cpp tests/cpgrid/lgr/lgrs_sharing_faces_test.cpp tests/cpgrid/lgr/logicalCartesianSize_and_refinement_test.cpp tests/cpgrid/lgr/nested_refinement_test.cpp - tests/cpgrid/lgr/replace_lgr1_corner_idx_by_lgr2_corner_idx_test.cpp - tests/cpgrid/lgr/replace_lgr1_face_idx_by_lgr2_face_idx_test.cpp ) if(USE_OPM_COMMON) @@ -211,6 +211,7 @@ list(APPEND PUBLIC_HEADER_FILES opm/grid/cpgrid/Indexsets.hpp opm/grid/cpgrid/Intersection.hpp opm/grid/cpgrid/Iterators.hpp + opm/grid/cpgrid/LgrFaultHelpers.hpp opm/grid/cpgrid/LgrHelpers.hpp opm/grid/cpgrid/LgrOutputHelpers.hpp opm/grid/cpgrid/ElementMarkHandle.hpp diff --git a/opm/grid/cpgrid/CpGrid.cpp b/opm/grid/cpgrid/CpGrid.cpp index a77084222..60080e135 100644 --- a/opm/grid/cpgrid/CpGrid.cpp +++ b/opm/grid/cpgrid/CpGrid.cpp @@ -2004,8 +2004,13 @@ bool CpGrid::refineAndUpdateGrid(bool throwOnFailure, // In entry 'level cell index', we store 'leafview cell index', or -1 when the cell vanished. preAdapt_level_to_leaf_cells_vec[preAdaptLevel].resize(data[preAdaptLevel]->size(0), -1); } + + std::vector cellRefsBoundaryInfo(currentLeafData().size(0)); // if a cell has been refined, then + // its cell-refinement info is stored in gridCellRefinements[ element.index() ] + + bool withoutFaults = true; // Ignore marked aquifer cells/connections in globalRefine()/adapt(); throw in addLgrsUpdateLeafView()/autoRef(). - Opm::Lgr::filterMarkedAquiferCellsAndConnections(*this, throwOnFailure); + Opm::Lgr::filterMarkedAquiferCellsAndConnections(*this, throwOnFailure); Opm::Lgr::refineAndProvideMarkedRefinedRelations( *this, /* Marked elements parameters */ markedElem_to_itsLgr, @@ -2025,7 +2030,9 @@ bool CpGrid::refineAndUpdateGrid(bool throwOnFailure, cell_count, preAdapt_level_to_leaf_cells_vec, /* Additional parameters */ - cells_per_dim_vec); + cells_per_dim_vec, + cellRefsBoundaryInfo, + withoutFaults); #if HAVE_MPI auto global_markedElem_count = comm().sum(markedElem_count); @@ -2095,7 +2102,9 @@ bool CpGrid::refineAndUpdateGrid(bool throwOnFailure, assignRefinedLevel, cornerInMarkedElemWithEquivRefinedCorner, faceInMarkedElemAndRefinedFaces, - cells_per_dim_vec); + cells_per_dim_vec, + cellRefsBoundaryInfo, + withoutFaults); // --- Adapted corners and PreAdapt corners relations --- std::map,int> elemLgrAndElemLgrCorner_to_adaptedCorner; @@ -2114,7 +2123,9 @@ bool CpGrid::refineAndUpdateGrid(bool throwOnFailure, cornerInMarkedElemWithEquivRefinedCorner, vanishedRefinedCorner_to_itsLastAppearance, faceInMarkedElemAndRefinedFaces, - cells_per_dim_vec); + cells_per_dim_vec, + cellRefsBoundaryInfo, + withoutFaults); // FACES // Stablish relationships between PreAdapt faces and refined or adapted ones --- @@ -2131,7 +2142,7 @@ bool CpGrid::refineAndUpdateGrid(bool throwOnFailure, markedElem_to_itsLgr, assignRefinedLevel, faceInMarkedElemAndRefinedFaces, - cells_per_dim_vec); + cellRefsBoundaryInfo); // --- Adapted faces and PreAdapt faces relations --- std::map< std::array, int > elemLgrAndElemLgrFace_to_adaptedFace; @@ -2139,14 +2150,13 @@ bool CpGrid::refineAndUpdateGrid(bool throwOnFailure, // Integer to count adapted faces (mixed between faces from pre-refined-leaf faces not involved in LGRs and new-born refined faces). int face_count = 0; Opm::Lgr::identifyLeafGridFaces(currentLeafData(), - preAdaptMaxLevel, elemLgrAndElemLgrFace_to_adaptedFace, adaptedFace_to_elemLgrAndElemLgrFace, face_count, markedElem_to_itsLgr, assignRefinedLevel, faceInMarkedElemAndRefinedFaces, - cells_per_dim_vec); + cellRefsBoundaryInfo); // Set refined level grids geometries // --- Refined corners --- @@ -2183,11 +2193,10 @@ bool CpGrid::refineAndUpdateGrid(bool throwOnFailure, elemLgrAndElemLgrCorner_to_refinedLevelAndRefinedCorner, vanishedRefinedCorner_to_itsLastAppearance, markedElem_to_itsLgr, - assignRefinedLevel, preAdaptMaxLevel, markedElemAndEquivRefinedCorn_to_corner, cornerInMarkedElemWithEquivRefinedCorner, - cells_per_dim_vec); + cellRefsBoundaryInfo); // Update leaf grid geometries // --- Adapted corners --- @@ -2226,11 +2235,9 @@ bool CpGrid::refineAndUpdateGrid(bool throwOnFailure, elemLgrAndElemLgrCorner_to_adaptedCorner, vanishedRefinedCorner_to_itsLastAppearance, markedElem_to_itsLgr, - assignRefinedLevel, markedElemAndEquivRefinedCorn_to_corner, cornerInMarkedElemWithEquivRefinedCorner, - cells_per_dim_vec, - preAdaptMaxLevel); + cellRefsBoundaryInfo); for (int level = 0; level < levels; ++level) { const int refinedLevelGridIdx = level + preAdaptMaxLevel +1; diff --git a/opm/grid/cpgrid/CpGridData.cpp b/opm/grid/cpgrid/CpGridData.cpp index 259028696..27edc7feb 100644 --- a/opm/grid/cpgrid/CpGridData.cpp +++ b/opm/grid/cpgrid/CpGridData.cpp @@ -1,3 +1,5 @@ + + #include"config.h" #include #include @@ -10,6 +12,7 @@ #include"ElementMarkHandle.hpp" #include"Intersection.hpp" #include"Entity.hpp" +#include "LgrFaultHelpers.hpp" #include "LgrHelpers.hpp" #include"OrientedEntityTable.hpp" #include"Indexsets.hpp" @@ -1781,113 +1784,83 @@ bool CpGridData::hasNNCs(const std::vector& cellIndices) const return hasNNC; } -std::tuple< const std::shared_ptr, - const std::vector>> // parent_to_refined_corners(~boundary_old_to_new_corners) -CpGridData::refineSingleCell(const std::array& cells_per_dim, - const int& parent_idx, +std::pair, Opm::Lgr::CellRefinementBoundaryInfo> +CpGridData::refineSingleCell(const std::array& cells_per_dim, int parent_idx, std::vector>>>& faceInMarkedElemAndRefinedFaces) const { - // To store the LGR/refined-grid. - std::vector> refined_data; - std::shared_ptr refined_grid_ptr = std::make_shared(refined_data); // ccobj_ - auto& refined_grid = *refined_grid_ptr; - DefaultGeometryPolicy& refined_geometries = refined_grid.geometry_; - std::vector>& refined_cell_to_point = refined_grid.cell_to_point_; - cpgrid::OrientedEntityTable<0,1>& refined_cell_to_face = refined_grid.cell_to_face_; - Opm::SparseTable& refined_face_to_point = refined_grid.face_to_point_; - cpgrid::OrientedEntityTable<1,0>& refined_face_to_cell = refined_grid.face_to_cell_; - cpgrid::EntityVariable& refined_face_tags = refined_grid.face_tag_; - cpgrid::SignedEntityVariable,1>& refined_face_normals = refined_grid.face_normals_; - - const auto& parent_to_point = this->cell_to_point_[parent_idx]; - Opm::Lgr::containsEightDifferentCorners(parent_to_point); // refinement supported only for hexahedron - - // Refine parent cell + const auto& parentCellToPoint = this->cell_to_point_[parent_idx]; + Opm::Lgr::containsEightDifferentCorners(parentCellToPoint); // refinement supported only for hexahedron + + std::vector> cellRef_data; + std::shared_ptr cellRefGrid_ptr = std::make_shared(cellRef_data); // ccobj_ + auto& cellRefGrid = *cellRefGrid_ptr; + Opm::Lgr::GeomData cellRefGeomData(cellRefGrid); + + // Refine parent cell - not taking into account multiple faces of the same type (same tag and same orientation). const auto parentCellElem = Entity<0>(*this, parent_idx, true); const cpgrid::Geometry<3,3>& parentCellGeom = (*(geometry_.geomVector(std::integral_constant())))[parentCellElem]; - parentCellGeom.refineCellifiedPatch(cells_per_dim, refined_geometries, refined_cell_to_point, refined_cell_to_face, - refined_face_to_point, refined_face_to_cell, refined_face_tags, refined_face_normals, - {1,1,1}, /*widthX, lengthY, heightZ*/ {1.}, {1.}, {1.}); - - const std::vector>& parent_to_refined_corners{ - // corIdx (J*(cells_per_dim[0]+1)*(cells_per_dim[2]+1)) + (I*(cells_per_dim[2]+1)) +K - // replacing parent-cell corner '0' {0,0,0} - {parent_to_point[0], 0}, - // replacing parent-cell corner '1' {cells_per_dim[0], 0, 0} - {parent_to_point[1], cells_per_dim[0]*(cells_per_dim[2]+1)}, - // replacing parent-cell corner '2' {0, cells_perd_dim[1], 0} - {parent_to_point[2], cells_per_dim[1]*(cells_per_dim[0]+1)*(cells_per_dim[2]+1)}, - // replacing parent-cell corner '3' {cells_per_dim[0], cells_per_dim[1], 0} - {parent_to_point[3], (cells_per_dim[1]*(cells_per_dim[0]+1)*(cells_per_dim[2]+1)) + (cells_per_dim[0]*(cells_per_dim[2]+1))}, - // replacing parent-cell corner '4' {0, 0, cells_per_dim[2]} - {parent_to_point[4], cells_per_dim[2]}, - // replacing parent-cell corner '5' {cells_per_dim[0], 0, cells_per_dim[2]} - {parent_to_point[5], (cells_per_dim[0]*(cells_per_dim[2]+1)) + cells_per_dim[2]}, - // replacing parent-cell corner '6' {0, cells_per_dim[1], cells_per_dim[2]} - {parent_to_point[6], (cells_per_dim[1]*(cells_per_dim[0]+1)*(cells_per_dim[2]+1)) + cells_per_dim[2]}, - // replacing parent-cell corner '7' {cells_per_dim[0], cells_per_dim[1], cells_per_dim[2]} - {parent_to_point[7], (cells_per_dim[1]*(cells_per_dim[0]+1)*(cells_per_dim[2]+1)) + (cells_per_dim[0]*(cells_per_dim[2]+1)) - + cells_per_dim[2]}}; - - const auto& parent_cell_to_face = (this-> cell_to_face_[parentCellElem]); - // To store relation old-face to new-born-faces (children faces). - std::vector>> parent_to_children_faces; - parent_to_children_faces.reserve(6); - // Auxiliary integers to simplify new-born-face-index notation. - const int& k_faces = cells_per_dim[0]*cells_per_dim[1]*(cells_per_dim[2]+1); - const int& i_faces = (cells_per_dim[0]+1)*cells_per_dim[1]*cells_per_dim[2]; - // Populate parent_to_children_faces - for (const auto& face : parent_cell_to_face) { - // Check face tag to identify the type of face (bottom, top, left, right, front, or back). - const auto& parent_face_tag = (this-> face_tag_[Dune::cpgrid::EntityRep<1>(face.index(), true)]); - // To store the new born faces for each face. - std::vector children_faces; // Cannot reserve/resize "now", it depends of the type of face. - // K_FACES - if (parent_face_tag == face_tag::K_FACE) { - children_faces.reserve(cells_per_dim[0]*cells_per_dim[1]); - for (int j = 0; j < cells_per_dim[1]; ++j) { - for (int i = 0; i < cells_per_dim[0]; ++i) { - int child_face; - if (!face.orientation()) // false -> BOTTOM FACE -> k=0 - child_face = (j*cells_per_dim[0]) + i; - else // true -> TOP FACE -> k=cells_per_dim[2] - child_face = (cells_per_dim[2]*cells_per_dim[0]*cells_per_dim[1]) +(j*cells_per_dim[0]) + i; - children_faces.push_back(child_face); - } // i-for-lopp - } //j-for-loop - } // if-K_FACE - // I_FACES - if (parent_face_tag == face_tag::I_FACE) { - children_faces.reserve(cells_per_dim[1]*cells_per_dim[2]); - for (int k = 0; k < cells_per_dim[2]; ++k) { - for (int j = 0; j < cells_per_dim[1]; ++j) { - int child_face; - if (!face.orientation()) // false -> LEFT FACE -> i=0 - child_face = k_faces + (k*cells_per_dim[1]) + j; - else // true -> RIGHT FACE -> i=cells_per_dim[0] - child_face = k_faces + (cells_per_dim[0]*cells_per_dim[1]*cells_per_dim[2]) + (k*cells_per_dim[1]) + j; - children_faces.push_back(child_face); - } // j-for-loop - } // k-for-loop - } // if-I_FACE - // J_FACES - if (parent_face_tag == face_tag::J_FACE) { - children_faces.reserve(cells_per_dim[0]*cells_per_dim[2]); - for (int i = 0; i < cells_per_dim[0]; ++i) { - for (int k = 0; k < cells_per_dim[2]; ++k) { - int child_face; - if (!face.orientation()) // false -> FRONT FACE -> j=0 - child_face = k_faces + i_faces + (i*cells_per_dim[2]) + k; - else // true -> BACK FACE -> j=cells_per_dim[1] - child_face = k_faces + i_faces + (cells_per_dim[1]*cells_per_dim[0]*cells_per_dim[2]) - + (i*cells_per_dim[2]) + k; - children_faces.push_back(child_face); - } // k-for-loop - } // i-for-loop - } // if-J_FACE - faceInMarkedElemAndRefinedFaces[face.index()].push_back(std::make_pair(parentCellElem.index(), children_faces)); - } - return {refined_grid_ptr, parent_to_refined_corners}; + parentCellGeom.refineCellifiedPatch(cells_per_dim, cellRefGeomData.geometries, cellRefGeomData.cell_to_point, + cellRefGeomData.cell_to_face, cellRefGeomData.face_to_point, + cellRefGeomData.face_to_cell, cellRefGeomData.face_tags, + cellRefGeomData.face_normals, /* block/patch-dimensions = */ {1,1,1}, + /* widthX, lengthY, heightZ*/ {1.}, {1.}, {1.}); + + Opm::Lgr::CellRefinementBoundaryInfo cellRefinementBoundaryInfo{}; + + const auto classifiedParentCellFaces = Opm::Lgr::groupFaceIndicesByType(*this, parentCellElem); + cellRefinementBoundaryInfo.parentCellhasSingleFacePerType = Opm::Lgr::hasAtMostOneFacePerGroup(classifiedParentCellFaces); + // In cellRefGrid, corner indices look like: (j*(cells_per_dim[0]+1)*(cells_per_dim[2]+1)) + (i*(cells_per_dim[2]+1)) + k + // parent-cell corner '0'<-> i = 0, j = 0, k =0 + // parent-cell corner '1'<-> i = cells_per_dim[0], j = 0, k = 0 + // parent-cell corner '2'<-> i = 0, j = cells_per_dim[1], k = 0 + // parent-cell corner '4'<-> i = 0, j = 0, k = cells_per_dim[2] + // parent-cell corner '5'<-> i = cells_per_dim[0], j = 0, k = cells_per_dim[2] + // parent-cell corner '6'<-> i = 0, j = cells_per_dim[1], k = cells_per_dim[2] + // parent-cell corner '7'<-> i = cells_per_dim[0], j = cells_per_dim[1], k = cells_per_dim[2] + cellRefinementBoundaryInfo.parentVertexIdx_to_boundaryRefinedVertexIdx = { + {parentCellToPoint[0], 0}, + {parentCellToPoint[1], cells_per_dim[0]*(cells_per_dim[2]+1)}, + {parentCellToPoint[3], (cells_per_dim[1]*(cells_per_dim[0]+1)*(cells_per_dim[2]+1)) + (cells_per_dim[0]*(cells_per_dim[2]+1))}, + {parentCellToPoint[2], cells_per_dim[1]*(cells_per_dim[0]+1)*(cells_per_dim[2]+1)}, + {parentCellToPoint[4], cells_per_dim[2]}, + {parentCellToPoint[5], (cells_per_dim[0]*(cells_per_dim[2]+1)) + cells_per_dim[2]}, + {parentCellToPoint[6], (cells_per_dim[1]*(cells_per_dim[0]+1)*(cells_per_dim[2]+1)) + cells_per_dim[2]}, + {parentCellToPoint[7], (cells_per_dim[1]*(cells_per_dim[0]+1)*(cells_per_dim[2]+1)) + (cells_per_dim[0]*(cells_per_dim[2]+1)) + + cells_per_dim[2]} + }; + + if(cellRefinementBoundaryInfo.parentCellhasSingleFacePerType) { + + cellRefinementBoundaryInfo.boundaryRefinedFaceIdx_to_parentFaceIdx.resize(cellRefGrid.numFaces(), /* invalidIdx = */ -1); + Opm::Lgr::provideRefinementParentFaceIdxRelations(classifiedParentCellFaces, + /* parentGrid */ *this, + parentCellElem, + cells_per_dim, + cellRefinementBoundaryInfo, + faceInMarkedElemAndRefinedFaces); + + Opm::Lgr::populateBoundaryRefVertexCoincidesWithParentVertex(cellRefGrid_ptr->size(3), cellRefinementBoundaryInfo); + + return {cellRefGrid_ptr, cellRefinementBoundaryInfo}; + } + else { // Make cell-refinement aware of multiple parent-cell-faces of the same type (same tag and same orientation). + std::vector> correctedCellRefGridData; + std::shared_ptr correctedCellRefGrid_ptr = std::make_shared(correctedCellRefGridData); // ccobj_ + auto& correctedCellRefGrid = *correctedCellRefGrid_ptr; + Opm::Lgr::GeomData correctedCellRefGridGeomData(correctedCellRefGrid); + + Opm::Lgr::makeCellRefinementParentFaceAware(classifiedParentCellFaces, + /* parentGrid */ *this, + parentCellElem, + cellRefGrid, + correctedCellRefGrid, + correctedCellRefGridGeomData, + cellRefinementBoundaryInfo, + faceInMarkedElemAndRefinedFaces, + cells_per_dim); + + return {correctedCellRefGrid_ptr, cellRefinementBoundaryInfo}; + } } bool CpGridData::mark(int refCount, const cpgrid::Entity<0>& element, bool throwOnFailure) diff --git a/opm/grid/cpgrid/CpGridData.hpp b/opm/grid/cpgrid/CpGridData.hpp index 1e51d0c35..bf3453957 100644 --- a/opm/grid/cpgrid/CpGridData.hpp +++ b/opm/grid/cpgrid/CpGridData.hpp @@ -79,7 +79,13 @@ namespace Opm { class EclipseState; + +namespace Lgr{ +struct GeomData; +struct CellRefinementBoundaryInfo; +} } + namespace Dune { class CpGrid; @@ -122,6 +128,7 @@ class CpGridData friend class Dune::cpgrid::IndexSet; friend class Dune::cpgrid::IdSet; friend class Dune::cpgrid::LevelGlobalIdSet; + friend struct Opm::Lgr::GeomData; friend void ::refine_and_check(const Dune::cpgrid::Geometry<3, 3>&, @@ -347,6 +354,11 @@ class CpGridData return face_to_cell_[faceRep].size(); } + auto faceToCell(int face) const { + Dune::cpgrid::EntityRep<1> faceRep(face, true); + return face_to_cell_[faceRep]; + } + auto faceTag(int faceIdx) const { Dune::cpgrid::EntityRep<1> faceRep(faceIdx, true); @@ -492,31 +504,22 @@ class CpGridData return level_to_leaf_cells_[level_cell_idx]; } - /// @brief Refine a single cell and return a shared pointer of CpGridData type. + /// @brief Refine a single cell into a structured set of cells. /// - /// refineSingleCell() takes a cell and refines it in a chosen amount of cells (per direction); creating the - /// geometries, topological relations, etc. Stored in a CpGridData object. Additionally, containers for - /// parent-to-new-born entities are buil, as well as, new-born-to-parent. Maps() to detect parent - /// faces or cells are also provided. (Cell with 6 faces required). + /// Refines the specified parent cell according to cells_per_dim and constructs + /// the corresponding geometry and topology in a new CpGridData object. /// - /// @param [in] cells_per_dim Number of (refined) cells in each direction that each parent cell should be refined to. - /// @param [in] parent_idx Parent cell index, cell to be refined. - /// @param [out] faceInMarkedElemAndRefinedFaces For each original (parent grid) face, stores marked element indices where it appears - /// (<=2) and their refined face indices in each single-cell-refinement (of each parent - /// cell where the face/intersection appears). + /// @param[in] cells_per_dim Number of subdivisions in each coordinate direction. + /// @param[in] parentCellIdx Index of the parent cell to refine. The cell must have six faces. + /// @param[out] faceInMarkedElemAndRefinedFaces + /// For each parent-grid face, stores the marked parent-element indices where + /// the face occurs (at most two) and the corresponding refined face indices + /// for each affected parent cell. /// - /// @return refined_grid_ptr Shared pointer pointing at refined_grid. - /// @return parent_to_refined_corners For each corner of the parent cell, we store the index of the - /// refined corner that coincides with the old one. - /// We assume they are ordered 0,1,..7 - /// 6---7 - /// 2---3 | | TOP FACE - /// | | 4---5 - /// 0---1 BOTTOM FACE - std::tuple< const std::shared_ptr, - const std::vector>> // parent_to_refined_corners(~boundary_old_to_new_corners) - refineSingleCell(const std::array& cells_per_dim, - const int& parent_idx, + /// @return A pair containing the refined grid data and the boundary information + /// relating the parent cell to its refined entities. + std::pair, Opm::Lgr::CellRefinementBoundaryInfo> + refineSingleCell(const std::array& cells_per_dim, int parentCellIdx, std::vector>>>& faceInMarkedElemAndRefinedFaces) const; // @breif Compute center of an entity/element/cell in the Eclipse way: diff --git a/opm/grid/cpgrid/LgrFaultHelpers.cpp b/opm/grid/cpgrid/LgrFaultHelpers.cpp new file mode 100644 index 000000000..773d56620 --- /dev/null +++ b/opm/grid/cpgrid/LgrFaultHelpers.cpp @@ -0,0 +1,1235 @@ +/* + Copyright 2026 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 . +*/ +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include // for std::max +#include +#include +#include +#include +#include +#include +#include // for std::integral_constant +#include +#include // for std::pair +#include + +namespace Opm +{ +namespace Lgr +{ + +std::array,6> groupFaceIndicesByType(const Dune::cpgrid::CpGridData& gridData, + const Dune::cpgrid::Entity<0>& element) +{ + std::array,6> faceIdxsByType{}; + const auto& cellToFace = gridData.cellToFace(element.index()); + + for (const auto& face : cellToFace) { + + const auto faceIdx = face.index(); + const auto tag = gridData.faceTag(faceIdx); + + if ((tag == I_FACE) || (tag == J_FACE) || (tag == K_FACE)) { + faceIdxsByType[faceGroupIndex(tag, face.orientation())].push_back(faceIdx); + } + else { + OPM_THROW(std::logic_error, "Face " + std::to_string(faceIdx) + + " has an invalid classification: expected one of +/-I, +/-J, or +/-K"); + } + } + return faceIdxsByType; +} + +bool hasAtMostOneFacePerGroup(const std::array,6>& classifiedFaces) +{ + for (const auto& faces : classifiedFaces) { + if (faces.size()> 1) + return false; + } + return true; +} + +std::tuple, double, Dune::FieldVector> +computeFaceCenterAreaNormal(const std::vector>& faceToCoord) +{ + assert(faceToCoord.size() == 4); // for now, only quadrilateral face + + Dune::FieldVector faceCenter = {0., 0.,0.}; + for (const auto& coord : faceToCoord) { + faceCenter += coord; + } + faceCenter /= 4.; + + // Calculate face area by adding the 4 areas of the triangles partitioning the face. + double faceArea = 0.0; + for (std::size_t i = 0; i < 4; ++i) { + const auto& p0 = faceToCoord[i]; + const auto& p1 = faceToCoord[(i + 1) % 4]; + + Dune::cpgrid::Geometry<0,3>::GlobalCoordinate trianCorners[3] = {p0, p1, faceCenter}; + faceArea += std::abs(Dune::area(trianCorners)); + } + + Dune::FieldVector faceNormal = {0., 0.,0.}; + // Construct two vectors that lie on the face, e.g. difference of two conners with the face center. + // then obtain an orthogonal vector to both of them. Finally, normalize. + Dune::cpgrid::Geometry<0,3>::GlobalCoordinate v0 = faceToCoord[0] - faceCenter; + Dune::cpgrid::Geometry<0,3>::GlobalCoordinate v1 = faceToCoord[1] - faceCenter; + faceNormal = Dune::FMatrixHelp::Impl::crossProduct(v0, v1); + + assert(faceNormal.two_norm()>0); + faceNormal /= faceNormal.two_norm(); + + return {faceCenter, faceArea, faceNormal}; +} + +std::optional, Dune::FieldVector>> +computeSegmentIntersection(const Dune::FieldVector& startA, const Dune::FieldVector& endA, + const Dune::FieldVector& startB, const Dune::FieldVector& endB, + bool& isInteriorInA, + bool& isInteriorInB) +{ + constexpr double eps = 1e-10; + + isInteriorInA = false; + isInteriorInB = false; + + const auto dA = endA - startA; // directionA + const auto dB = endB - startB; // directionB + + const double lenA2 = Dune::dot(dA,dA); + const double lenB2 = Dune::dot(dB,dB); + // Degenerate A: startA + t*directionA, t in [0,1] + if (lenA2 < eps) { + if (isVertexInSegmentInterior(startA, startB, endB)) { + isInteriorInB = Dune::dot(startA-startB,dB)/lenB2 > eps && + Dune::dot(startA-startB,dB)/lenB2 < 1-eps; + return {{startA,startA}}; + } + return std::nullopt; + } + + // Degenerate B: startB + s*directionB, s in [0,1] + if (lenB2 < eps) { + if (isVertexInSegmentInterior(startB, startA, endA)) { + isInteriorInA = Dune::dot(startB-startA,dA)/lenA2 > eps && + Dune::dot(startB-startA,dA)/lenA2 < 1-eps; + return {{startB,startB}}; + } + return std::nullopt; + } + + const auto c = Dune::FMatrixHelp::Impl::crossProduct(dA,dB); + const double c2 = Dune::dot(c,c); + + // Parallel + if (c2 < eps) {// not collinear + const auto offset = Dune::FMatrixHelp::Impl::crossProduct(startB-startA,dA); + + if (offset.two_norm() > eps) + return std::nullopt; + + // project B onto A + auto paramA = [&](const auto& p) { + return Dune::dot(p-startA,dA)/lenA2; + }; + + double t0 = paramA(startB); + double t1 = paramA(endB); + + if (t0 > t1) + std::swap(t0,t1); + + const double lo = std::max(0.0,t0); + const double hi = std::min(1.0,t1); + + if (lo > hi + eps) + return std::nullopt; + + auto p0 = startA + lo*dA; + auto p1 = startA + hi*dA; + + isInteriorInA = (lo > eps && lo < 1-eps) || (hi > eps && hi < 1-eps); + + double s0 = Dune::dot(p0-startB,dB)/lenB2; + double s1 = Dune::dot(p1-startB,dB)/lenB2; + + isInteriorInB = (s0 > eps && s0 < 1-eps) || (s1 > eps && s1 < 1-eps); + + return {{p0,p1}}; + } + + // Non-parallel + const auto r = startB-startA; + // Compute intersection point + // + // X denotes the crossProduct and <,> the dot: + // startA + t*dirA = startB + s*dirB + // t*dirA = startB - startA + s*dirB + // (t*dirA)X dirB = (startB - startA + s*dirB)X dirB + // t*(dirA X dirB) = (startSegmentB - startSegmentA)X dirB + s*(dirB X dirB) + // t*c = (startSegmentB - startSegmentA)X dirB + s*0 + // = <(startSegmentB - startSegmentA)X dirB, c> + // t = <(startSegmentB - startSegmentA)X dirB, c> + const double t = Dune::dot(Dune::FMatrixHelp::Impl::crossProduct(r,dB), c) / c2; + const double s = Dune::dot(Dune::FMatrixHelp::Impl::crossProduct(r,dA), c) / c2; + + if ((t < -eps) || (t > 1+eps) || (s < -eps) || (s > 1+eps)) + return std::nullopt; + + isInteriorInA = t > eps && t < 1-eps; + isInteriorInB = s > eps && s < 1-eps; + + const auto p = startA + t*dA; + + return {{p,p}}; +} + +std::vector> createEdges(const auto& faceToPoint) +{ + std::vector> edges{}; + edges.reserve(faceToPoint.size()); + for (std::size_t i = 0; i < faceToPoint.size(); ++i) { + edges.push_back(std::array{ faceToPoint[i], faceToPoint[(i+1)%faceToPoint.size()]}); + } + return edges; +} + +bool inSemiplane(const Dune::FieldVector& vertex, + const Dune::FieldVector& faceVertex, + const Dune::FieldVector& faceNormal, + const Dune::FieldVector& directionEdge) +{ + const double eps = 1e-8; + // 1. Check if vertex lies on the plane + const auto v = vertex - faceVertex; + if (std::fabs(Dune::dot(faceNormal, v)) > eps) + return false; + + // 2. Compute in-plane perpendicular vector + const auto u = Dune::FMatrixHelp::Impl::crossProduct(faceNormal, directionEdge); + + // 3. Check side + return Dune::dot(u, v) >= -eps*directionEdge.two_norm(); +} + +bool isVertexInsideFace(const Dune::FieldVector& vertex, + const Dune::cpgrid::CpGridData& face_gridData, + const std::vector>& face_edges, + const Dune::FieldVector& face_normal) +{ + assert(face_edges.size()); + for (const auto& edge : face_edges) { + const auto edge0 = Dune::cpgrid::Entity<3>(face_gridData, edge[0], true).geometry().center(); + const auto edge1 = Dune::cpgrid::Entity<3>(face_gridData, edge[1], true).geometry().center(); + + if (!inSemiplane(vertex, edge0, face_normal, edge1-edge0)) + return false; + } + return true; +} + + +bool isVertexInSegmentInterior(const Dune::FieldVector& vertex, + const Dune::FieldVector& startSegment, + const Dune::FieldVector& endSegment) +{ + constexpr double tol = 1e-12; + // segment(t) = (endSegment - startSegment)*t + startSegment, t in [0,1] + const double segLen2 = (endSegment - startSegment).two_norm2(); + + // Degenerate segment + if (segLen2 < tol) + return false; + + // Check collinearity + const auto cp = Dune::FMatrixHelp::Impl::crossProduct(vertex - startSegment, + endSegment - startSegment); + + // Scale tolerance with segment length (if collinear, d*vertex ~ cp -> d^2 vertex.two_norm ~) + if (cp.two_norm2() > tol * tol * segLen2) + return false; + + // Position along the segment + const double t = Dune::dot(vertex - startSegment, endSegment - startSegment) / segLen2; + + return (t > tol) && (t < 1.0 - tol); + +} + +std::vector isVertexInElementFaceEdge(const Dune::FieldVector& vertex, + int elemIdx, + const Dune::cpgrid::CpGridData& gridData) +{ + std::vector isInFace{}; + + const auto& cellToPoint = gridData.cellToPoint(elemIdx); + + bool isInAtLeastOneEdge = false; + for (const auto& face : gridData.cellToFace(elemIdx)) { + const auto edges = createEdges(gridData.faceToPoint(face.index())); + for (const auto& edge : edges) { + + bool isNotCellEdge = std::find(cellToPoint.begin(), cellToPoint.end(), edge[0]) == cellToPoint.end() || + std::find(cellToPoint.begin(), cellToPoint.end(), edge[1]) == cellToPoint.end(); + + if (!isNotCellEdge) + continue; + + const auto edge0 = Dune::cpgrid::Entity<3>(gridData, edge[0], true).geometry().center(); + const auto edge1 = Dune::cpgrid::Entity<3>(gridData, edge[1], true).geometry().center(); + isInAtLeastOneEdge = isInAtLeastOneEdge || isVertexInSegmentInterior(vertex, edge0, edge1); + if (isVertexInSegmentInterior(vertex, edge0, edge1)) + isInFace.push_back(face.index()); + } + } + return isInFace; +} + +std::vector isVertexInElementEdge(const Dune::FieldVector& vertex, + int elemIdx, + const Dune::cpgrid::CpGridData& gridData) +{ + std::vector isInEdge{}; + + const auto& cellToPoint = gridData.cellToPoint(elemIdx); + + bool isInAtLeastOneEdge = false; + for (const auto& face : gridData.cellToFace(elemIdx)) { + const auto edges = createEdges(gridData.faceToPoint(face.index())); + for (const auto& edge : edges) { + + bool edgeHasNoCellVertex = std::find(cellToPoint.begin(), cellToPoint.end(), edge[0]) == cellToPoint.end() && + std::find(cellToPoint.begin(), cellToPoint.end(), edge[1]) == cellToPoint.end(); + + if (edgeHasNoCellVertex) + continue; + + const auto edge0 = Dune::cpgrid::Entity<3>(gridData, edge[0], true).geometry().center(); + const auto edge1 = Dune::cpgrid::Entity<3>(gridData, edge[1], true).geometry().center(); + isInAtLeastOneEdge = isInAtLeastOneEdge || isVertexInSegmentInterior(vertex, edge0, edge1); + if (isVertexInSegmentInterior(vertex, edge0, edge1)) + isInEdge.push_back(face.index()); + } + } + return isInEdge; +} + +void addFaceVerticesCoordinatesToIndex(const Dune::cpgrid::CpGridData& grid, + int faceIndex, + std::map, int, FieldVectorLess>& pointMap) +{ + for (const auto& pointIndex : grid.faceToPoint(faceIndex)) { + const auto pointPosition = Dune::cpgrid::Entity<3>(grid, pointIndex, true).geometry().center(); + pointMap[pointPosition] = pointIndex; + } +} + +std::map, int, FieldVectorLess> +buildExtendedCellPointVertexMap(const Dune::cpgrid::CpGridData& grid, + int cellIndex) +{ + std::map, int, FieldVectorLess> pointMap; + + for (const auto& face : grid.cellToFace(cellIndex)) { + addFaceVerticesCoordinatesToIndex(grid, face.index(), pointMap); + } + + return pointMap; +} + +void collectNewVertices(const Dune::cpgrid::CpGridData& parentGridData, + const Dune::cpgrid::Entity<0>& parentElem, + const std::array,6>& classifiedParentCellFaces, + const Dune::cpgrid::CpGridData& cellRefinementData, + const Dune::cpgrid::Entity<0>& refinedElem, + BoundaryFaceInfo& boundaryFaceInfo) +{ + const auto& refinedCellToFace = cellRefinementData.cellToFace(refinedElem.index()); + const auto& parentCellToFace = parentGridData.cellToFace(parentElem.index()); + + for (const auto& parentFace : parentCellToFace) { + // skip if face type is not repeated (i.e. there is only one face of type {face_tag, face_orientation}) + const auto parentFaceIdx = parentFace.index(); + if (classifiedParentCellFaces[faceGroupIndex(parentGridData.faceTag(parentFaceIdx), parentFace.orientation())].size() == 1) + continue; + + for (const auto& refinedFace : refinedCellToFace) { + const auto refinedFaceIdx = refinedFace.index(); + // Skip face if it is not on the boundary of the single cell refinement grid + if (cellRefinementData.faceToCellSize(refinedFaceIdx) != 1) + continue; + + addFaceVerticesCoordinatesToIndex(cellRefinementData, refinedFaceIdx, + boundaryFaceInfo.boundaryVertexCoordinates_to_vertexIdx); + + bool refinedFaceFullyContainedInParentFace = false; + const auto newFace = computeFaceOverlapVertices(parentFace, // face1 + parentGridData, // gridData1 + refinedFace, // face2 + cellRefinementData, // gridData2 + boundaryFaceInfo.foundNewVertices, + refinedFaceFullyContainedInParentFace); // face2FullyContainedInFace1 + + if (refinedFaceFullyContainedInParentFace){ + boundaryFaceInfo.face_fullyContainedIn_otherGridFaceIdx[refinedFaceIdx] = parentFaceIdx; + } + + if (newFace.has_value() && !newFace.value().empty()) { + // Save face vertices/coordinates as one of the overlapping refined faces with the parent cell + auto it = boundaryFaceInfo.otherGridFaceIdx_to_newFacesToCoords.find(parentFaceIdx); + if (it != boundaryFaceInfo.otherGridFaceIdx_to_newFacesToCoords.end()) { + auto& collectedFaces = *it; + collectedFaces.second.push_back(newFace.value()); + } + else { + auto& collectedFaces = boundaryFaceInfo.otherGridFaceIdx_to_newFacesToCoords[parentFaceIdx]; + collectedFaces.push_back(newFace.value()); + } + + if (!refinedFaceFullyContainedInParentFace) { + boundaryFaceInfo.vanishedFaceIdx_to_otherGridFaceIdxAndNewFaceToCoords[refinedFaceIdx].push_back(std::make_pair(parentFaceIdx, newFace.value())); + } + } + } + } +} + +std::vector> +orderFaceVertices(int faceTag, + const std::set,FieldVectorLess>& faceVertices) +{ + assert( (faceTag >= 0) && (faceTag < 3)); + std::vector> orderedVertices{}; + + if (!faceVertices.empty()) { + constexpr double eps = 1e-8; // tolerance + assert(faceVertices.size() == 4); // for general face, do sth else... + orderedVertices.resize(faceVertices.size()); + + // Box bounds (I -> yz box, J-> xz box, K-> xy box) + double minA = std::numeric_limits::max(); + double maxA = std::numeric_limits::lowest(); + + double minB = std::numeric_limits::max(); + double maxB = std::numeric_limits::lowest(); + + for (const auto& vertex : faceVertices) { + minA = std::min(minA, vertex[(faceTag+1)%3]); + maxA = std::max(maxA, vertex[(faceTag+1)%3]); + minB = std::min(minB, vertex[(faceTag+2)%3]); + maxB = std::max(maxB, vertex[(faceTag+2)%3]); + } + if (faceTag < 2) { // Vertex order + // 0-> I_FACE: jk, (j+1)k, (j+1)(k+1), j(k+1) + // 1-> J_FACE: (i+1)k, ik, i(k+1), (i+1)(k+1) + for (const auto& vertex : faceVertices) { + const auto a = vertex[(faceTag+1)%3]; + const auto b = vertex[(faceTag+2)%3]; + if (b-minB, 6>& classifiedParentCellFaces, + const Dune::cpgrid::CpGridData& parentGridData, + const Dune::cpgrid::Entity<0>& parentElem, + const std::array& cells_per_dim, + CellRefinementBoundaryInfo& cellRefBoundaryInfo, + std::vector>>>& faceInMarkedElemAndRefinedFaces, + const std::vector>& oldGridFaceIdx_to_newGridFaceIdxList, + const std::vector>& parentFaceIdx_to_newGridFaceIdxList, + const std::vector& oldGridFaceIdx_fullyContainedIn_parentFaceIdx) +{ + bool hasOnlyOneFacePerType = cellRefBoundaryInfo.parentCellhasSingleFacePerType; + + auto addChildFace = [&](int newChildFaceIdx, int parentFaceIdx, std::vector& children_faces) + { + children_faces.push_back(newChildFaceIdx); + cellRefBoundaryInfo.boundaryRefinedFaceIdx_to_parentFaceIdx[newChildFaceIdx] = parentFaceIdx; + }; + + auto assignCorrectChildFace = [&](int oldChildFaceIdx, int parentFaceIdx, int faceType_count, std::vector& children_faces) + { + if (hasOnlyOneFacePerType) { + addChildFace(oldChildFaceIdx, parentFaceIdx, children_faces); + return; + } + + const auto& newFaceIdxList = oldGridFaceIdx_to_newGridFaceIdxList[oldChildFaceIdx]; + + if ((faceType_count == 1) || (oldGridFaceIdx_fullyContainedIn_parentFaceIdx[oldChildFaceIdx] == parentFaceIdx)) { + for (int newChildFaceIdx : newFaceIdxList) + addChildFace(newChildFaceIdx, parentFaceIdx, children_faces); + return; + } + + if (newFaceIdxList.size()>1) { + for (int newChildFaceIdx : parentFaceIdx_to_newGridFaceIdxList[parentFaceIdx]) { + if (std::find(newFaceIdxList.begin(), newFaceIdxList.end(), newChildFaceIdx) != newFaceIdxList.end()) + addChildFace(newChildFaceIdx, parentFaceIdx, children_faces); + } + } + }; + + const int k_faces = cells_per_dim[0]*cells_per_dim[1]*(cells_per_dim[2]+1); + const int i_faces = (cells_per_dim[0]+1)*cells_per_dim[1]*cells_per_dim[2]; + const int offSet = cells_per_dim[0]*cells_per_dim[1]*cells_per_dim[2]; + + for (const auto& face : parentGridData.cellToFace(parentElem.index())) { + + const int parentFaceIdx = face.index(); + const auto parentFaceTag = parentGridData.faceTag(parentFaceIdx); + const auto faceType_count = classifiedParentCellFaces[faceGroupIndex(parentFaceTag, face.orientation())].size(); + + std::vector newFaceIdxList{}; + + if (parentFaceTag == face_tag::K_FACE) { + for (int j = 0; j < cells_per_dim[1]; ++j) { + for (int i = 0; i < cells_per_dim[0]; ++i) { + + int oldChildFaceIdx = (j*cells_per_dim[0]) + i + (face.orientation()*offSet); + assignCorrectChildFace(oldChildFaceIdx, parentFaceIdx, faceType_count, newFaceIdxList); + } + } + } + else if (parentFaceTag == face_tag::I_FACE) { + for (int k = 0; k < cells_per_dim[2]; ++k) { + for (int j = 0; j < cells_per_dim[1]; ++j) { + + int oldChildFaceIdx = k_faces + (k*cells_per_dim[1]) + j + (face.orientation()*offSet); + assignCorrectChildFace(oldChildFaceIdx, parentFaceIdx, faceType_count, newFaceIdxList); + } + } + } + else if (parentFaceTag == face_tag::J_FACE) { + for (int i = 0; i < cells_per_dim[0]; ++i) { + for (int k = 0; k < cells_per_dim[2]; ++k) { + + int oldChildFaceIdx = k_faces + i_faces + (i*cells_per_dim[2]) + k + (face.orientation()*offSet); + assignCorrectChildFace(oldChildFaceIdx, parentFaceIdx, faceType_count, newFaceIdxList); + } + } + } + newFaceIdxList.shrink_to_fit(); + faceInMarkedElemAndRefinedFaces[face.index()].push_back(std::make_pair(parentElem.index(), newFaceIdxList)); + } +} + +void populateVertexData(const Dune::cpgrid::CpGridData& oldGrid, + const std::map& parentCellFaceIdx_to_boundaryFaceInfo, + GeomData& newGridGeomData, + std::map, int, FieldVectorLess>& newGridVertexCoordinates_to_newGridVertexIdx, + std::unordered_map& newGridBoundaryVertexIdx_to_parentFaceIdx, + std::vector& newGridBoundaryVertexCoincidesWithParentVertex) +{ + int numVertices = oldGrid.size(3); + const auto& oldGridVertices = *(oldGrid.getGeometry().geomVector(std::integral_constant())); + Dune::cpgrid::EntityVariableBase>& newGridVertices = *(newGridGeomData.geometries.geomVector(std::integral_constant())); + + int newVerticesCount = 0; + for (const auto& [_, boundInfo] : parentCellFaceIdx_to_boundaryFaceInfo) { + newVerticesCount += boundInfo.foundNewVertices.size(); + } + newGridVertices.resize(numVertices + newVerticesCount); + + // add the "old" vertices (the parent-cell-face-aware are includeed here) + for (int i = 0; i < oldGrid.size(3); ++i) { + newGridVertices[i] = oldGridVertices.get(i); + } + + for (const auto& [parentFaceIdx, boundFaceInfo] : parentCellFaceIdx_to_boundaryFaceInfo) { + for (const auto& vertex : boundFaceInfo.foundNewVertices) { + + newGridVertexCoordinates_to_newGridVertexIdx[vertex] = numVertices; + newGridVertices[numVertices] = Dune::cpgrid::Geometry<0, 3>(vertex); + newGridBoundaryVertexIdx_to_parentFaceIdx[numVertices] = parentFaceIdx; + + ++numVertices; + } + } + newGridBoundaryVertexCoincidesWithParentVertex.resize(numVertices, false); // false is used to initialized the new entries, old entries stay the same +} + +void populateVertexData(const Dune::cpgrid::CpGridData& oldGrid, + const std::map, int, FieldVectorLess>& extendedParentCellToPointVertexMap, + const std::set, FieldVectorLess>& foundNewVertices, // boundaryFaceInfo + GeomData& newGridGeomData, + std::map, int, FieldVectorLess>& newGridVertexCoordinates_to_newGridVertexIdx, // boundaryFaceInfo + std::vector>& parentBoundaryVertexIdx_to_newGridBoundaryVertexIdx) +{ + int numVertices = oldGrid.size(3); + const auto& oldGridVertices = *(oldGrid.getGeometry().geomVector(std::integral_constant())); + Dune::cpgrid::EntityVariableBase>& newGridVertices = *(newGridGeomData.geometries.geomVector(std::integral_constant())); + newGridVertices.resize(numVertices + foundNewVertices.size()); + + auto addParentBoundaryVertexMapping = [&](Dune::FieldVector vertex, int i) + { + auto it = extendedParentCellToPointVertexMap.find(vertex); + + if (it == extendedParentCellToPointVertexMap.end()) { + return; + } + + const auto parentGridVertexIdx = it->second; + + auto iit = std::find_if(parentBoundaryVertexIdx_to_newGridBoundaryVertexIdx.begin(), + parentBoundaryVertexIdx_to_newGridBoundaryVertexIdx.end(), + [parentGridVertexIdx](const std::array& arr) { + return arr[0] == parentGridVertexIdx; + }); + + if (iit == parentBoundaryVertexIdx_to_newGridBoundaryVertexIdx.end()) { + parentBoundaryVertexIdx_to_newGridBoundaryVertexIdx.push_back( {parentGridVertexIdx, i} ); + } + }; + + for (int i = 0; i < oldGrid.size(3); ++i) { + addParentBoundaryVertexMapping(oldGridVertices.get(i).center(), i); + + newGridVertices[i] = oldGridVertices.get(i); + } + + for (const auto& vertex : foundNewVertices) { + addParentBoundaryVertexMapping(vertex, numVertices); + + newGridVertexCoordinates_to_newGridVertexIdx[vertex] = numVertices; + newGridVertices[numVertices] = Dune::cpgrid::Geometry<0, 3>(vertex); + + ++numVertices; + } +} + +bool isAtGridBoundary(const Dune::cpgrid::CpGridData& grid, + const Dune::cpgrid::Entity<0>& element) +{ + for (const auto& face : grid.cellToFace(element.index())) { + if (grid.faceToCellSize(face.index()) == 1) + return true; + } + return false; +} + +void populateFaceData(int oldGridNumFaces, + const Dune::cpgrid::CpGridData& oldGrid, + GridModificationMapping& modificationMapps, + GeomData& newGridGeomData, + const BoundaryFaceInfo& boundaryFaceInfo, + std::vector>& parentGridFaceIdx_to_newGridFaceIdxList, + std::unordered_map& newGridBoundaryVertexIdx_to_parentGridFaceIdx) +{ + modificationMapps.oldGridFaceIdx_to_newGridFaceIdxList.resize(oldGridNumFaces); + + Dune::cpgrid::EntityVariableBase>& newGridFaces = + *(newGridGeomData.geometries.geomVector(std::integral_constant())); + Dune::cpgrid::EntityVariableBase& mutable_newGrid_face_tags = newGridGeomData.face_tags; + Dune::cpgrid::EntityVariableBase>& mutable_newGrid_face_normals = newGridGeomData.face_normals; + + int upperBoundFaceSize = oldGridNumFaces; // total faces before correcting the data + for (const auto& [_, overlapFacesInfo] : boundaryFaceInfo.otherGridFaceIdx_to_newFacesToCoords) { + upperBoundFaceSize += overlapFacesInfo.size(); + } + newGridFaces.resize(upperBoundFaceSize); // maybe larger than needed + mutable_newGrid_face_tags.resize(upperBoundFaceSize); + mutable_newGrid_face_normals.resize(upperBoundFaceSize); + + std::vector> aux_newGrid_face_to_point{}; + aux_newGrid_face_to_point.resize(upperBoundFaceSize); + + int newGrid_num_points = 0; + int newGrid_face_count = 0; + + auto registerFace = [&](int oldFaceIdx, int newFaceIdx, int parentGridFaceIdx, + auto&& faceToPoint, auto&& geometry, auto&& normal, auto tag) + { + modificationMapps.oldGridFaceIdx_to_newGridFaceIdxList[oldFaceIdx].push_back(newFaceIdx); + + if (parentGridFaceIdx != -1) { + parentGridFaceIdx_to_newGridFaceIdxList[parentGridFaceIdx].push_back(newGrid_face_count); + } + + newGridFaces[newFaceIdx] = geometry; + mutable_newGrid_face_tags[newFaceIdx] = tag; + mutable_newGrid_face_normals[newFaceIdx] = normal; + + aux_newGrid_face_to_point[newGrid_face_count] = std::vector(faceToPoint.begin(), faceToPoint.end()); + newGrid_num_points += faceToPoint.size(); + + const auto faceToCell = oldGrid.faceToCell(oldFaceIdx); + newGridGeomData.face_to_cell.appendRow(faceToCell.begin(), faceToCell.end()); + + ++newGrid_face_count; + }; + + for (int i = 0; i < oldGrid.numFaces(); ++i) { + const auto& newFacesInfo = boundaryFaceInfo.vanishedFaceIdx_to_otherGridFaceIdxAndNewFaceToCoords[i]; + const int parentGrid_containerFaceIdx = boundaryFaceInfo.face_fullyContainedIn_otherGridFaceIdx[i]; + + if ( newFacesInfo.empty() || (parentGrid_containerFaceIdx != -1 /* invalidIdx */)) { + + const auto face = Dune::cpgrid::EntityRep<1>(i, true); + const auto faceToPoint = oldGrid.faceToPoint(i); + + registerFace(i, newGrid_face_count, parentGrid_containerFaceIdx, faceToPoint, + (*oldGrid.getGeometry().geomVector(std::integral_constant()))[face], + oldGrid.faceNormals(i), oldGrid.faceTag(i)); + } + else { + std::vector newFaceIndices{}; + + for (const auto& [parentGridFaceIdx, newFaceToCoord] : newFacesInfo) { + + newFaceIndices.push_back(newGrid_face_count); + + const auto [faceCenter, faceArea, faceNormal] = computeFaceCenterAreaNormal(newFaceToCoord); + const auto faceToPoint = modifyFaceToPoint(newFaceToCoord, + modificationMapps, + boundaryFaceInfo, + parentGridFaceIdx, + &newGridBoundaryVertexIdx_to_parentGridFaceIdx); + + registerFace(i, newGrid_face_count, parentGridFaceIdx, faceToPoint, + Dune::cpgrid::Geometry<2,3>(faceCenter, faceArea), + faceNormal, oldGrid.faceTag(i)); + } + } + } + populateFaceToPoint(newGrid_face_count, newGrid_num_points, aux_newGrid_face_to_point, newGridGeomData); +} + +void populateFaceToPoint(int face_count, + int num_points, + const std::vector>& face_to_point, + GeomData& geomData) +{ + geomData.face_to_point.reserve(face_count, num_points); + for (int face = 0; face < face_count; ++face) { + geomData.face_to_point.appendRow(face_to_point[face].begin(), face_to_point[face].end()); + } +} + +std::vector modifyFaceToPoint(const std::vector>& newFaceToCoord, + const GridModificationMapping& modificationMap, + const BoundaryFaceInfo& boundaryFaceInfo, + int parentGridFaceIdx, + std::unordered_map* newGridBoundaryVertexIdx_to_parentGridFaceIdx) +{ + std::vector faceToPoint; + + for (const auto& vertex : newFaceToCoord) { + int vertexIdx = -1; + // Check if the vertex is new (e.g., added when modifying the grid) + auto newIt = modificationMap.newGridVertexCoordinates_to_newGridVertexIdx.find(vertex); + if (newIt != modificationMap.newGridVertexCoordinates_to_newGridVertexIdx.end()) { + vertexIdx = newIt->second; + } + else { // Vertex already existed in the original grid () + auto oldIt = boundaryFaceInfo.boundaryVertexCoordinates_to_vertexIdx.find(vertex); + assert(oldIt != boundaryFaceInfo.boundaryVertexCoordinates_to_vertexIdx.end()); + + vertexIdx = oldIt->second; + } + if ((parentGridFaceIdx != -1 /* invalid-index */) && (newGridBoundaryVertexIdx_to_parentGridFaceIdx != nullptr)) { + (*newGridBoundaryVertexIdx_to_parentGridFaceIdx)[vertexIdx] = parentGridFaceIdx; + } + assert(vertexIdx >= 0); + faceToPoint.push_back(vertexIdx); + } + + return faceToPoint; +} + +void populateFaceData(int oldGridNumFaces, + const Dune::cpgrid::CpGridData& oldGrid, + GridModificationMapping& modificationMap, + GeomData& newGridGeomData, + const std::map& boundaryFacesInfo, + std::vector& newGridFaceIdx_to_parentFaceIdx) +{ + int invalidIdx = -1; + modificationMap.oldGridFaceIdx_to_newGridFaceIdxList.resize(oldGridNumFaces); + + Dune::cpgrid::EntityVariableBase>& newGridFaces = *(newGridGeomData.geometries.geomVector(std::integral_constant())); + Dune::cpgrid::EntityVariableBase& mutable_newGridFaceTags = newGridGeomData.face_tags; + Dune::cpgrid::EntityVariableBase>& mutable_newGridFaceNormals = newGridGeomData.face_normals; + + // Estimate new size of total number of faces in correctedGridData1 + int upperBoundFaceSize = oldGridNumFaces; // total faces before correcting the data + for (const auto& [unused_parentFaceIdx, boundaryFaceInfo] : boundaryFacesInfo) { + for (const auto& [unsused_neighborGrid_faceIdx, overlapFacesInfo] : boundaryFaceInfo.otherGridFaceIdx_to_newFacesToCoords) { + upperBoundFaceSize += overlapFacesInfo.size(); + } + } + newGridFaces.resize(upperBoundFaceSize); // maybe larger than needed + mutable_newGridFaceTags.resize(upperBoundFaceSize); + mutable_newGridFaceNormals.resize(upperBoundFaceSize); + + modificationMap.newGridFaceIdx_to_oldGridFaceIdx.resize(upperBoundFaceSize, invalidIdx); + + // intentional copy + const auto hasParent = newGridFaceIdx_to_parentFaceIdx; + newGridFaceIdx_to_parentFaceIdx.resize(upperBoundFaceSize, invalidIdx); + + std::vector> aux_newGrid_face_to_point{}; + aux_newGrid_face_to_point.resize(upperBoundFaceSize); + + int newGrid_num_points = 0; + int newGrid_face_count = 0; + + auto registerFace = [&](int oldFaceIdx, int newFaceIdx, int parentFaceIdx, + auto&& faceToPoint, auto&& geometry, auto&& normal, auto tag) + { + modificationMap.oldGridFaceIdx_to_newGridFaceIdxList[oldFaceIdx].push_back(newFaceIdx); + modificationMap.newGridFaceIdx_to_oldGridFaceIdx[newFaceIdx] = oldFaceIdx; + + if (parentFaceIdx != -1) { + newGridFaceIdx_to_parentFaceIdx[newFaceIdx] = parentFaceIdx; + } + + newGridFaces[newFaceIdx] = geometry; + mutable_newGridFaceTags[newFaceIdx] = tag; + mutable_newGridFaceNormals[newFaceIdx] = normal; + + aux_newGrid_face_to_point[newGrid_face_count] = std::vector(faceToPoint.begin(), faceToPoint.end()); + newGrid_num_points += faceToPoint.size(); + + const auto faceToCell = oldGrid.faceToCell(oldFaceIdx); + newGridGeomData.face_to_cell.appendRow(faceToCell.begin(), faceToCell.end()); + + ++newGrid_face_count; + }; + + for (int i = 0; i < oldGrid.numFaces(); ++i) { + + const auto face = Dune::cpgrid::EntityRep<1>(i, true); + int parentFaceIdx = hasParent[i]; + auto itP = boundaryFacesInfo.find(parentFaceIdx); + + if ((parentFaceIdx == -1) || (itP == boundaryFacesInfo.end()) || + (itP != boundaryFacesInfo.end() && (itP->second.faceFullyContainedInNeighbor[i]))) { + + const auto faceToPoint = oldGrid.faceToPoint(i); + + registerFace(i, newGrid_face_count, parentFaceIdx, faceToPoint, + (*oldGrid.getGeometry().geomVector(std::integral_constant()))[face], + oldGrid.faceNormals(i), oldGrid.faceTag(i)); + } + else { + const auto& boundaryFaceInfo = itP->second; + const auto& newFacesInfo = boundaryFaceInfo.vanishedFaceIdx_to_otherGridFaceIdxAndNewFaceToCoords[i]; + + if (!newFacesInfo.empty()) { + for (const auto& [grid2_faceIdx, newFaceToCoord] : newFacesInfo) { + + const auto faceToPoint = modifyFaceToPoint(newFaceToCoord, + modificationMap, + boundaryFaceInfo); + + const auto [faceCenter, faceArea, faceNormal] = computeFaceCenterAreaNormal(newFaceToCoord); + + registerFace(i, newGrid_face_count, parentFaceIdx, faceToPoint, + Dune::cpgrid::Geometry<2,3>(faceCenter, faceArea), + faceNormal, oldGrid.faceTag(i)); + } + } + } + } + populateFaceToPoint(newGrid_face_count, newGrid_num_points, aux_newGrid_face_to_point, newGridGeomData); +} + +void populateCellData(const Dune::cpgrid::CpGridData& sourceGrid, + GeomData& geomData) +{ + Dune::cpgrid::EntityVariableBase>& cells = *(geomData.geometries.geomVector(std::integral_constant())); + cells.resize(sourceGrid.size(0)); + geomData.cell_to_point.resize(sourceGrid.size(0)); + + for (int i = 0; i < sourceGrid.size(0); ++i) { + + geomData.cell_to_point[i] = sourceGrid.cellToPoint(i); + int* indices_storage_ptr = geomData.cell_to_point[i].data(); + + const auto element = Dune::cpgrid::Entity<0>(sourceGrid, i, true); + + cells[i] = Dune::cpgrid::Geometry<3,3>(element.geometry().center(), element.geometry().volume(), + geomData.geometries.geomVector(std::integral_constant()), + indices_storage_ptr); + } + geomData.face_to_cell.makeInverseRelation(geomData.cell_to_face); +} + +void populateBoundaryRefVertexCoincidesWithParentVertex(int numVertices, + CellRefinementBoundaryInfo& cellRefBoundaryInfo) +{ + cellRefBoundaryInfo.boundaryRefinedVertexCoincidesWithParentVertex.resize(numVertices, false); + for (const auto& [_, equivRefVertexIdx] : cellRefBoundaryInfo.parentVertexIdx_to_boundaryRefinedVertexIdx) { + cellRefBoundaryInfo.boundaryRefinedVertexCoincidesWithParentVertex[equivRefVertexIdx] = true; + } +} + +void makeCellRefinementParentFaceAware(const std::array,6>& classifiedParentCellFaces, + const Dune::cpgrid::CpGridData& parentGrid, + const Dune::cpgrid::Entity<0>& parentCellElem, + const Dune::cpgrid::CpGridData& cellRefGrid, + Dune::cpgrid::CpGridData& correctedCellRefGrid, + GeomData& correctedCellRefGeomData, + CellRefinementBoundaryInfo& cellRefBoundaryInfo, + std::vector>>>& faceInMarkedElemAndRefinedFaces, + const std::array& cells_per_dim) +{ + int numFaces = cellRefGrid.numFaces(); + BoundaryFaceInfo boundaryFaceInfo{}; + boundaryFaceInfo.vanishedFaceIdx_to_otherGridFaceIdxAndNewFaceToCoords.resize(numFaces); + boundaryFaceInfo.face_fullyContainedIn_otherGridFaceIdx.resize(numFaces, /*invalidIdx */-1); + + for (int i = 0; i < cellRefGrid.size(0); ++i) { + + const auto refinedElem = Dune::cpgrid::Entity<0>(cellRefGrid, i, true); + if (!isAtGridBoundary(cellRefGrid, refinedElem)) + continue; + + collectNewVertices(parentGrid, + parentCellElem, + classifiedParentCellFaces, + cellRefGrid, + refinedElem, + boundaryFaceInfo); + } + + GridModificationMapping modificationMapps{}; + + const auto& extendedParentCellToPointVertexMap = buildExtendedCellPointVertexMap(parentGrid, parentCellElem.index());; + populateVertexData(cellRefGrid, + extendedParentCellToPointVertexMap, + boundaryFaceInfo.foundNewVertices, + correctedCellRefGeomData, + modificationMapps.newGridVertexCoordinates_to_newGridVertexIdx, + cellRefBoundaryInfo.parentVertexIdx_to_boundaryRefinedVertexIdx); + + std::vector> parentFaceIdx_to_correctedFaceIdxList{}; // empty entry for face not affected, is it better std::unordered_map? only few entries are populated... + parentFaceIdx_to_correctedFaceIdxList.resize(parentGrid.numFaces()); + + populateFaceData(numFaces, + cellRefGrid, + modificationMapps, + correctedCellRefGeomData, + boundaryFaceInfo, + parentFaceIdx_to_correctedFaceIdxList, + cellRefBoundaryInfo.boundaryRefinedVertexIdx_to_parentFaceIdx); + + populateCellData(cellRefGrid, correctedCellRefGeomData); + + cellRefBoundaryInfo.boundaryRefinedFaceIdx_to_parentFaceIdx.resize(correctedCellRefGrid.numFaces(), /* invalidIdx */ -1); + provideRefinementParentFaceIdxRelations(classifiedParentCellFaces, + parentGrid, + parentCellElem, + cells_per_dim, + cellRefBoundaryInfo, + faceInMarkedElemAndRefinedFaces, + modificationMapps.oldGridFaceIdx_to_newGridFaceIdxList, + parentFaceIdx_to_correctedFaceIdxList, + boundaryFaceInfo.face_fullyContainedIn_otherGridFaceIdx); + + populateBoundaryRefVertexCoincidesWithParentVertex(correctedCellRefGrid.size(3), cellRefBoundaryInfo); +} + + +void computeNewRefinedGeometriesOnSharedCoarseFace(const std::vector& refinedFaces1, + const Dune::cpgrid::CpGridData& parentFaceAwareCellRefinement1, + BoundaryFaceInfo& boundaryFaceInfo, + const std::vector& refinedFaces2, + const Dune::cpgrid::CpGridData& parentFaceAwareCellRefinement2) +{ + for (const auto& refinedFace1 : refinedFaces1) { + const auto face1 = Dune::cpgrid::EntityRep<1>(refinedFace1, true); + + addFaceVerticesCoordinatesToIndex(parentFaceAwareCellRefinement1, refinedFace1, + boundaryFaceInfo.boundaryVertexCoordinates_to_vertexIdx); + + for (const auto& refinedFace2 : refinedFaces2) { + const auto face2 = Dune::cpgrid::EntityRep<1>(refinedFace2, true); + + bool face1FullyContainedInFace2 = false; + const auto newFace = computeFaceOverlapVertices(face2, + parentFaceAwareCellRefinement2, + face1, + parentFaceAwareCellRefinement1, + boundaryFaceInfo.foundNewVertices, + face1FullyContainedInFace2); + + boundaryFaceInfo.faceFullyContainedInNeighbor[refinedFace1] = boundaryFaceInfo.faceFullyContainedInNeighbor[refinedFace1] || face1FullyContainedInFace2; + + if (face1FullyContainedInFace2){ + boundaryFaceInfo.face_fullyContainedIn_otherGridFaceIdx[refinedFace1] = refinedFace2; + } + + if (newFace.has_value() && !newFace.value().empty()) { + // Save face vertices/coordinates as one of the overlapping refined faces with the parent cell + auto it1 = boundaryFaceInfo.otherGridFaceIdx_to_newFacesToCoords.find(refinedFace2); + if (it1 != boundaryFaceInfo.otherGridFaceIdx_to_newFacesToCoords.end()) { + auto& collectedFaces = *it1; + collectedFaces.second.push_back(newFace.value()); + } + else { + auto& collectedFaces = boundaryFaceInfo.otherGridFaceIdx_to_newFacesToCoords[refinedFace2]; + collectedFaces.push_back(newFace.value()); + } + if (!face1FullyContainedInFace2) { + boundaryFaceInfo.vanishedFaceIdx_to_otherGridFaceIdxAndNewFaceToCoords[refinedFace1].push_back(std::make_pair(refinedFace2, newFace.value())); + } + } + } + } +} + +std::pair, GridModificationMapping> +makeCellRefinementNeighborsAware(const Dune::cpgrid::Entity<0>& parentCell, + const std::vector>& cellRefs, // to get neighbor information + const Dune::cpgrid::CpGridData& parentGrid, + const Dune::cpgrid::CpGridData& cellRefGrid, + CellRefinementBoundaryInfo& cellRefGridBoundaryInfo, + std::vector>>>& faceInMarkedElemAndRefinedFaces) // needs to be updated +{ + std::map boundaryFacesInfo{}; + int numFaces = cellRefGrid.numFaces(); + + for (const auto& parentFace : parentGrid.cellToFace(parentCell.index())) { + + const auto faceToCell = parentGrid.faceToCell(parentFace.index()); + + if ((faceToCell.size() == 1) || (faceInMarkedElemAndRefinedFaces[parentFace.index()].size()<=1)){ + continue; // face at parent grid boundary does need to be corrected (cell refinement is already parentCellFaces aware). + } + + assert(faceToCell.size() == 2); + assert(faceInMarkedElemAndRefinedFaces[parentFace.index()].size() == 2); + + const auto& [p1, refinedFaces1] = faceInMarkedElemAndRefinedFaces[parentFace.index()][0]; + const auto& [p2, refinedFaces2] = faceInMarkedElemAndRefinedFaces[parentFace.index()][1]; + + int neighborCellRefIdx = (p1 == parentCell.index())? p2 : p1; + + const auto& cellRefFaces = (p1 == parentCell.index())? refinedFaces1 : refinedFaces2; + const auto& neighborCellRefFaces = (p1 == parentCell.index())? refinedFaces2 : refinedFaces1; + + auto& boundaryFaceInfo = boundaryFacesInfo[parentFace.index()]; + boundaryFaceInfo.faceFullyContainedInNeighbor.resize(numFaces, false); + boundaryFaceInfo.face_fullyContainedIn_otherGridFaceIdx.resize(numFaces, -1); + boundaryFaceInfo.vanishedFaceIdx_to_otherGridFaceIdxAndNewFaceToCoords.resize(numFaces); + + computeNewRefinedGeometriesOnSharedCoarseFace(cellRefFaces, + cellRefGrid, + boundaryFaceInfo, + neighborCellRefFaces, + *cellRefs[neighborCellRefIdx]); + } + + std::vector> neighborAwareCellRefData; + std::shared_ptr neighborAwareCellRef_ptr = std::make_shared(neighborAwareCellRefData); // ccobj_ + auto& neighborAwareCellRef = *neighborAwareCellRef_ptr; + GeomData neighborAwareGeomData(neighborAwareCellRef); + + GridModificationMapping modificationMap{}; + + populateVertexData(cellRefGrid, + boundaryFacesInfo, + neighborAwareGeomData, + modificationMap.newGridVertexCoordinates_to_newGridVertexIdx, + cellRefGridBoundaryInfo.boundaryRefinedVertexIdx_to_parentFaceIdx, + cellRefGridBoundaryInfo.boundaryRefinedVertexCoincidesWithParentVertex); + + populateFaceData(numFaces, + cellRefGrid, + modificationMap, + neighborAwareGeomData, + boundaryFacesInfo, + cellRefGridBoundaryInfo.boundaryRefinedFaceIdx_to_parentFaceIdx); + + populateCellData(cellRefGrid, neighborAwareGeomData); + + return {neighborAwareCellRef_ptr, modificationMap}; +} + +void makeCellRefinementsNeighborsAware(std::vector>& cellRefs, // to get neighbor information + std::vector& cellRefsBoundaryInfo, + const Dune::cpgrid::CpGridData& parentGrid, + std::vector>>>& faceInMarkedElemAndRefinedFaces, + std::vector& modificationMapps) // needs to be updated +{ + const auto cellRefsBeforeCorrection = cellRefs; // copy on propose + + for (int elemIdx = 0; elemIdx < parentGrid.size(0); ++elemIdx) { + auto& cellRef = cellRefs[elemIdx]; + if (cellRef == nullptr) + continue; + + const auto& parentCell = Dune::cpgrid::Entity<0>(parentGrid, elemIdx, true); + + auto [correctedCellRef, correctedModificationMap] = makeCellRefinementNeighborsAware(parentCell, + cellRefsBeforeCorrection, // to get neighbor information + parentGrid, + *cellRef, + cellRefsBoundaryInfo[elemIdx], + faceInMarkedElemAndRefinedFaces); + cellRefs[elemIdx] = correctedCellRef; + modificationMapps[elemIdx] = correctedModificationMap; + } + + for (std::size_t faceIdx = 0; faceIdx < faceInMarkedElemAndRefinedFaces.size(); ++faceIdx) { + + for (std::size_t cellRefCount = 0; cellRefCount < faceInMarkedElemAndRefinedFaces[faceIdx].size(); ++cellRefCount) { + + auto& [parentCell, refinedFaces] = faceInMarkedElemAndRefinedFaces[faceIdx][cellRefCount]; + const auto& oldToNewList = modificationMapps[parentCell].oldGridFaceIdx_to_newGridFaceIdxList; + + if (oldToNewList.empty()) + continue; + + std::vector updatedFaceIndices{}; + + for (const auto& oldIdx : refinedFaces) { + for (const auto& newIdx : oldToNewList[oldIdx]) { + assert(newIdx>=0); + updatedFaceIndices.push_back(newIdx); + } + } + faceInMarkedElemAndRefinedFaces[faceIdx][cellRefCount] = {parentCell, updatedFaceIndices}; + } + } +} + +bool areClose(const Dune::FieldVector& v, + const Dune::FieldVector& w) +{ + return (std::abs(v[0] - w[0]) < 1e-12) && (std::abs(v[1] - w[1]) < 1e-12) && (std::abs(v[2] - w[2])< 1e-12); +} + +std::optional findVertexIdxInFaces(const Dune::cpgrid::CpGridData& grid, + const std::vector& candidateFaces, + const Dune::FieldVector& targetVertex) +{ + for (const auto& faceIdx : candidateFaces) { + const auto matchingVertexIdx = findMatchingVertexIdx(grid, faceIdx, targetVertex); + + if (matchingVertexIdx) + return matchingVertexIdx; + } + return std::nullopt; +} + +std::optional findMatchingVertexIdx(const Dune::cpgrid::CpGridData& grid, + int faceIndex, + const Dune::FieldVector& targetVertex) +{ + const auto& facePoints = grid.faceToPoint(faceIndex); + + for (const auto& pointIndex : facePoints) { + const auto& pointPosition = Dune::cpgrid::Entity<3>(grid, pointIndex, true).geometry().center(); + + if (areClose(pointPosition, targetVertex)) + return pointIndex; + } + return std::nullopt; +} + +std::vector> getFaceVertexCoordinates(const Dune::cpgrid::CpGridData& grid, + int faceIdx) +{ + std::vector> faceCoords{}; + + for (const auto& vertexIdx : grid.faceToPoint(faceIdx)){ + faceCoords.push_back(Dune::cpgrid::Entity<3>(grid, vertexIdx, true).geometry().center()); + } + return faceCoords; +} + +std::optional findMatchingFaceIdx(const Dune::cpgrid::CpGridData& targetGrid, + const std::vector& candidateFaces, + const Dune::cpgrid::CpGridData& sourceGrid, + int sourceFaceIdx) +{ + const auto& sourceFaceCoords = getFaceVertexCoordinates(sourceGrid, sourceFaceIdx); + + for (const auto& candidateFaceIdx : candidateFaces) { + + const auto& candidateFaceCoords = getFaceVertexCoordinates(targetGrid, candidateFaceIdx); + + if (sourceFaceCoords.size() != candidateFaceCoords.size()) + continue; + + bool matchingFaceFound = std::all_of(sourceFaceCoords.begin(), sourceFaceCoords.end(), + [&](const auto& v) { + return std::any_of(candidateFaceCoords.begin(), candidateFaceCoords.end(), + [&](const auto& w) { + return areClose(v, w); + }); + }); + if (matchingFaceFound) { + return candidateFaceIdx; + } + } + return std::nullopt; +} + +} // namespace Lgr +} // namespace Opm diff --git a/opm/grid/cpgrid/LgrFaultHelpers.hpp b/opm/grid/cpgrid/LgrFaultHelpers.hpp new file mode 100644 index 000000000..ddbdf7d21 --- /dev/null +++ b/opm/grid/cpgrid/LgrFaultHelpers.hpp @@ -0,0 +1,650 @@ +/* + Copyright 2026 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 . +*/ + +#ifndef OPM_GRID_CPGRID_LGRFAULTHELPERS_HEADER_INCLUDED +#define OPM_GRID_CPGRID_LGRFAULTHELPERS_HEADER_INCLUDED + + +#include +#include +#include +#include +#include + + +#include +#include +#include + + +#include +#include +#include +#include +#include +#include +#include +#include +#include // for std::pair +#include + +namespace Dune +{ +namespace cpgrid +{ +class CpGridData; +class DefaultGeometryPolicy; +} +} + +namespace Opm +{ + +template class LevelCartesianIndexMapper; + +namespace Lgr +{ + + +// Warning: GeomData has reference members which +// make the struct non-default-constructible and non-assignable. +struct GeomData +{ + GeomData(Dune::cpgrid::CpGridData& gridData) + : + geometries(gridData.geometry_), + cell_to_point(gridData.cell_to_point_), + cell_to_face(gridData.cell_to_face_), + face_to_point(gridData.face_to_point_), + face_to_cell(gridData.face_to_cell_), + face_tags(gridData.face_tag_), + face_normals(gridData.face_normals_) + {} + + Dune::cpgrid::DefaultGeometryPolicy& geometries; + std::vector>& cell_to_point; + Dune::cpgrid::OrientedEntityTable<0,1>& cell_to_face; + Opm::SparseTable& face_to_point; + Dune::cpgrid::OrientedEntityTable<1,0>& face_to_cell; + Dune::cpgrid::EntityVariable& face_tags; + Dune::cpgrid::SignedEntityVariable,1>& face_normals; +}; + + +struct CellRefinementBoundaryInfo +{ + std::vector> parentVertexIdx_to_boundaryRefinedVertexIdx{}; + std::unordered_map boundaryRefinedVertexIdx_to_parentFaceIdx{}; + std::vector boundaryRefinedVertexCoincidesWithParentVertex{}; + + std::vector boundaryRefinedFaceIdx_to_parentFaceIdx{}; // invalid index = -1, if not boundary-face + + bool parentCellhasSingleFacePerType = true; // types: I-,I+,J-,J+,K-,K+ + + +}; + +struct FieldVectorLess { + bool operator()(const Dune::FieldVector& v, + const Dune::FieldVector& w) const + { + for (int i = 0; i < 3; ++i) { + if (v[i] < w[i]) return true; + if (v[i] > w[i]) return false; + } + return false; + } +}; + +struct BoundaryFaceInfo +{ + std::set, FieldVectorLess> foundNewVertices{}; + std::map, int, FieldVectorLess> boundaryVertexCoordinates_to_vertexIdx{}; + + std::map>>> otherGridFaceIdx_to_newFacesToCoords{}; // maybe remove? + std::vector>>>> vanishedFaceIdx_to_otherGridFaceIdxAndNewFaceToCoords{}; + std::vector face_fullyContainedIn_otherGridFaceIdx{}; // invalid index -1, if not + + std::vector faceFullyContainedInNeighbor{}; // to be deleted +}; + +struct GridModificationMapping +{ + std::map, int, FieldVectorLess> newGridVertexCoordinates_to_newGridVertexIdx{}; + std::vector newGridFaceIdx_to_oldGridFaceIdx{}; // invalidIdx = -1, if face does not exist in old grid + + std::vector> oldGridFaceIdx_to_newGridFaceIdxList{}; +}; + + +/// @brief Computes the index of a face group from its tag and orientation. +/// +/// Maps a face tag and orientation pair to one of six face-group indices: +/// - 0: I-face, orientation == false +/// - 1: I-face, orientation == true +/// - 2: J-face, orientation == false +/// - 3: J-face, orientation == true +/// - 4: K-face, orientation == false +/// - 5: K-face, orientation == true +/// +/// @param [in] tag Face tag (I_FACE, J_FACE, or K_FACE). +/// @param [in] orientation Face orientation. +/// +/// @return Index in the range [0, 5] corresponding to the face group. +/// +/// @note Assumes that the face tags are encoded as +/// I_FACE == 0, J_FACE == 1, and K_FACE == 2. +constexpr int faceGroupIndex(int tag, bool orientation) +{ + return 2*tag + static_cast(orientation); +} + +/// @brief Groups the face indices of an element by face type and orientation. +/// +/// Collects the indices of all faces incident to the given element and +/// groups them into six categories corresponding to the face tag +/// (I, J, or K) and orientation (false or true). +/// +/// The returned array is organized as follows: +/// - [0]: I-face, orientation == false +/// - [1]: I-face, orientation == true +/// - [2]: J-face, orientation == false +/// - [3]: J-face, orientation == true +/// - [4]: K-face, orientation == false +/// - [5]: K-face, orientation == true +/// +/// @param [in] gridData Grid data containing face connectivity and face tags. +/// @param [in] element Element whose incident faces are to be grouped. +/// +/// @return An array containing the face indices grouped by face tag and orientation. +/// +/// @throws std::logic_error If a face has an invalid tag and cannot be +/// classified as an I-, J-, or K-face. +std::array,6> groupFaceIndicesByType(const Dune::cpgrid::CpGridData& gridData, + const Dune::cpgrid::Entity<0>& element); + +/// @brief Checks whether each face group contains at most one face. +/// +/// The face groups correspond to the six combinations of face tag +/// (I, J, K) and orientation (false, true). The function returns +/// true if no group contains more than one face index. +/// +/// @param classifiedFaces Face indices grouped by face tag and orientation. +/// +/// @return true if every face group contains at most one face; otherwise false. +bool hasAtMostOneFacePerGroup(const std::array,6>& classifiedFaces); + +/// @brief Computes the center, area, and unit normal of a quadrilateral face. +/// +/// The face center is computed as the arithmetic mean of the four face +/// vertices. The face area is obtained by partitioning the face into four +/// triangles formed by the face center and each face edge and summing their +/// areas. The face normal is computed as the normalized cross product of two +/// vectors spanning the face. +/// +/// @param [in] faceToCoord Coordinates of the four face vertices. +/// +/// @return A tuple containing: +/// - std::get<0>(result): face center. +/// - std::get<1>(result): face area. +/// - std::get<2>(result): unit face normal. +/// +/// @note The function currently assumes a quadrilateral face (faceToCoord.size() == 4). +/// @note The orientation of the returned normal depends on the ordering of the face vertices. +std::tuple, double, Dune::FieldVector> +computeFaceCenterAreaNormal(const std::vector>& faceToCoord); + +/// @brief Computes the intersection of two 3D line segments. +/// +/// Determines whether two line segments intersect and returns the +/// intersection geometry if it exists. +/// +/// The function handles the following cases: +/// - Non-parallel segments intersecting at a single point. +/// - Parallel but disjoint segments. +/// - Colinear segments with a single-point contact. +/// - Colinear segments with an overlapping segment. +/// - Skew (non-coplanar) segments. +/// +/// The returned pair represents the intersection geometry: +/// - (p, p) for a single-point intersection. +/// - (p0, p1) for an overlapping segment. +/// - std::nullopt if the segments do not intersect. +/// +/// @param [in] startA Start point of segment A. +/// @param [in] endA End point of segment A. +/// @param [in] startB Start point of segment B. +/// @param [in] endB End point of segment B. +/// @param[out] isInteriorInA +/// Set to true if the intersection lies in the interior of +/// segment A (i.e. not only at an endpoint). For overlapping +/// segments, indicates whether part of the overlap is interior +/// to segment A. +/// @param[out] isInteriorInB +/// Set to true if the intersection lies in the interior of +/// segment B (i.e. not only at an endpoint). For overlapping +/// segments, indicates whether part of the overlap is interior +/// to segment B. +/// +/// @return +/// - std::nullopt if the segments do not intersect. +/// - std::pair{p, p} if the intersection consists of a single point. +/// - std::pair{p0, p1} if the intersection is an overlapping segment +/// with endpoints p0 and p1. +/// +/// @note Segments are considered parallel or coplanar using a tolerance +/// of approximately 1e-8. +/// @note Degenerate segments (near-zero length) are treated as +/// non-intersecting. +std::optional, Dune::FieldVector>> +computeSegmentIntersection(const Dune::FieldVector& startA, const Dune::FieldVector& endA, + const Dune::FieldVector& startB, const Dune::FieldVector& endB, + bool& isInteriorInA, + bool& isInteriorInB); + +/// @brief Creates the edge list of a polygon from its ordered vertex indices. +/// +/// Given a sequence of point/vertex indices describing a face boundary, +/// this function generates one edge for each consecutive pair of vertices. +/// The last vertex is automatically connected back to the first vertex, +/// producing a closed polygonal loop. +/// +/// @param faceToPoint Container of vertex indices defining the face in +/// boundary order. Must support size() and operator[]. +/// +/// @return A vector of edges, where each edge is represented as +/// std::array{startVertexIdx, endVertexIdx}. +std::vector> createEdges(const auto& faceToPoint); + +/// @brief Determines whether a point lies in the half-plane defined by a face edge. +/// +/// The half-plane is bounded by the line passing through faceVertex in the +/// direction directionEdge and oriented according to faceNormal. The point +/// must lie on the face plane and on the non-negative side of the boundary +/// line to be considered inside the half-plane. +/// +/// @param [in] vertex Point to test. +/// @param [in] faceVertex A point on the boundary line. +/// @param [in] faceNormal Normal vector of the face plane. +/// @param [in] directionEdge Direction vector of the boundary line. +/// +/// @return true if vertex lies in the half-plane; false otherwise. +bool inSemiplane(const Dune::FieldVector& vertex, + const Dune::FieldVector& faceVertex, + const Dune::FieldVector& faceNormal, + const Dune::FieldVector& directionEdge); + +/// @brief Determines whether a point lies inside or on the boundary of a face. +/// +/// The test is performed by constructing a half-plane for each face edge +/// using the face normal and verifying that the point lies within all +/// corresponding half-planes. +/// Assumes that the face is planar and convex. For more general faces, +/// an alternative approach may be required, for example by mapping to a +/// reference element, performing the computation in reference +/// coordinates, and transforming the result back to global coordinates. +/// +/// @param [in] vertex +/// Point to test. Typically a Dune::FieldVector. +/// +/// @param [in] face_gridData +/// CpGridData instance to which the face belongs. +/// +/// @param [in] face_edges +/// Vector of corner-index pairs defining the edges of the face. +/// The indices refer to corners stored in face_gridData. +/// +/// @param [in] face_normal +/// Normal vector of the face. Used to construct the edge half-planes. +/// +/// @return true if the point lies inside the face or on its boundary; false otherwise. +bool isVertexInsideFace(const Dune::FieldVector& vertex, + const Dune::cpgrid::CpGridData& face_gridData, + const std::vector>& face_edges, + const Dune::FieldVector& face_normal); + +bool isVertexInSegmentInterior(const Dune::FieldVector& vertex, + const Dune::FieldVector& startSegment, + const Dune::FieldVector& endSegment); + +// face indices where the vertex appear interior of an edge +std::vector isVertexInElementFaceEdge(const Dune::FieldVector& vertex, + int elemIdx, + const Dune::cpgrid::CpGridData& gridData); + +// edges form only by the 8 vertices of the element +std::vector isVertexInElementEdge(const Dune::FieldVector& vertex, + int elemIdx, + const Dune::cpgrid::CpGridData& gridData); + + +/// @brief Orders the vertices of a (quadrilateral) face according to its face tag. +/// +/// Returns the four face vertices in a "canonical" ordering that depends on +/// the face tag (I_FACE, J_FACE, or K_FACE). The ordering is chosen to be +/// consistent with the logical grid directions associated with the face. +/// +/// @param [in] faceTag Face tag (I_FACE, J_FACE, or K_FACE). +/// @param [in] faceVertices Set containing the four face vertices. +/// +/// @return The face vertices ordered according to the convention of the +/// specified face tag. +/// +/// @note The function currently assumes a quadrilateral face and requires +/// exactly four vertices. +/// @note The returned ordering differs for I-, J-, and K-faces. +std::vector> +orderFaceVertices(int faceTag, + const std::set,FieldVectorLess>& faceVertices); + +/// @brief Computes the vertices defining the overlap polygon between two +/// geometrically coincident faces. +/// +/// The function identifies existing and newly created vertices that +/// contribute to the overlap region between face1 and face2, including +/// vertices generated by edge-edge intersections. It also detects the +/// special case where face2 is fully contained in face1. +/// +/// Only faces with matching face tags and orientations are considered. +/// If no valid overlap polygon can be constructed, std::nullopt is +/// returned. +/// +/// @param [in] face1 +/// @param [in] face2 +/// @param [in] face1_gridData +/// CpGridData instance to which face1 belongs. +/// +/// @param [in] face2_gridData +/// CpGridData instance to which face2 belongs. +/// +/// @param [out] foundNewVertices +/// Set used to collect newly created vertices that do not already exist +/// in either face1_gridData or face2_gridData. Such vertices may be +/// generated, for example, when two edges intersect at an interior point. +/// +/// @param [out] face1ExistingVertex_to_face1GridCornerIdx +/// Maps the coordinates of an existing vertex in face1 to its corner +/// index in face1_gridData. +/// +/// @param [out] face2ExistingVertex_to_face2GridCornerIdx +/// Maps the coordinates of an existing vertex in face2 to its corner +/// index in face2_gridData. +/// +/// @param [out] face2FullyContainedInFace1 +/// Set to true if all vertices of face2 lie on face1. +/// +/// @return +/// An optional containing the coordinates of the vertices that delimit +/// the overlap region between the two faces. Returns std::nullopt if +/// no overlap exists. +template +std::optional>> +computeFaceOverlapVertices(const Face& face1, + const Dune::cpgrid::CpGridData& gridData1, + const Face& face2, + const Dune::cpgrid::CpGridData& gridData2, + std::set,FieldVectorLess>& foundNewVertices, + bool& face2FullyContainedInFace1) +{ + const auto face1_tag = gridData1.faceTag(face1.index()); + const auto face2_tag = gridData2.faceTag(face2.index()); + + // The orientation may differ when the grid data objects correspond + // to neighboring single-cell refinements rather than a parent grid + // and its associated single-cell refinement. Therefore, we only verify + // that the face tags are identical, regardless of their orientation. + if (face1_tag != face2_tag) + return std::nullopt; + + const auto& face1_to_point = gridData1.faceToPoint(face1.index()); + const auto& face2_to_point = gridData2.faceToPoint(face2.index()); + + // Used to create semi-planes to determine whether a vertex of face2 + // lies inside face1. + const auto face1_edges = createEdges(face1_to_point); + const auto& face1_normal = gridData1.faceNormals(face1.index()); + + std::set,FieldVectorLess> overlapFaceVertices{}; + + // Case 1: face2 is fully contained in face1 + for (std::size_t i = 0; i < face2_to_point.size(); ++i) { + const auto currentPoint = Dune::cpgrid::Entity<3>(gridData2, face2_to_point[i], true).geometry().center(); + if (isVertexInsideFace(currentPoint, gridData1, face1_edges, face1_normal)) { + overlapFaceVertices.insert(currentPoint); + } + } + if (overlapFaceVertices.size() == face2_to_point.size()) { + face2FullyContainedInFace1 = true; + const auto ordered = orderFaceVertices(face1_tag, overlapFaceVertices); + + return std::make_optional>>(ordered); + } + // Case 2: Intersection/overlap area between face1 and face2 is not trivial (new vertices!) + for (const auto& face1_edge : face1_edges) { + + const auto edge0 = Dune::cpgrid::Entity<3>(gridData1, face1_edge[0], true).geometry().center(); + const auto edge1 = Dune::cpgrid::Entity<3>(gridData1, face1_edge[1], true).geometry().center(); + + for (std::size_t i = 0; i < face2_to_point.size(); ++i) { + + const auto currentPoint = Dune::cpgrid::Entity<3>(gridData2, face2_to_point[i], true).geometry().center(); + const auto previousPoint = Dune::cpgrid::Entity<3>(gridData2, face2_to_point[(i-1)%face2_to_point.size()], true).geometry().center(); + + bool isInteriorInFace1Edge{}; + bool isInteriorInFace2Edge{}; + + const auto segmentInter = computeSegmentIntersection(edge0, edge1, + previousPoint, currentPoint, + isInteriorInFace1Edge, isInteriorInFace2Edge); + + bool currentPointInSemiplaneEdge = inSemiplane(currentPoint, edge0, face1_normal, edge1-edge0); + bool previousPointInSemiplaneEdge = inSemiplane(previousPoint, edge0, face1_normal, edge1-edge0); + + if (currentPointInSemiplaneEdge) { + if (!previousPointInSemiplaneEdge) { + if (segmentInter.has_value()) { + const auto& [p0,p1] = segmentInter.value(); + if (isInteriorInFace2Edge) { + foundNewVertices.insert(p0); + foundNewVertices.insert(p1); // if p0 and p1 coincide, no problem->it's a set + } + overlapFaceVertices.insert(p0); + overlapFaceVertices.insert(p1); + face2FullyContainedInFace1 = false; + } + overlapFaceVertices.insert(currentPoint); + face2FullyContainedInFace1 = false; + } + } + else if (previousPointInSemiplaneEdge){ + if (segmentInter.has_value()) { + const auto& [p0,p1] = segmentInter.value(); + if (isInteriorInFace2Edge) { + foundNewVertices.insert(p0); + foundNewVertices.insert(p1); + } + overlapFaceVertices.insert(p0); + overlapFaceVertices.insert(p1); + } + overlapFaceVertices.insert(previousPoint); + face2FullyContainedInFace1 = false; + } + } // end-for-refinedFaceToPoint-loop + } // end-for-edges-loop + if (overlapFaceVertices.size() != 4) { // faces might share only an edge, which does not create a new face + return std::nullopt; + } + // Make sure all points forming the new face are actually ("inside") lying on face1 + bool allPointsInsideFace1 = true; + for (const auto& vertex : overlapFaceVertices) { + allPointsInsideFace1 = allPointsInsideFace1 && isVertexInsideFace(vertex, gridData1, face1_edges, face1_normal); + if (!allPointsInsideFace1) { + return std::nullopt; + } + } + const auto ordered = orderFaceVertices(face1_tag, overlapFaceVertices); + return std::make_optional>>(ordered); +} + +void collectNewVertices(const Dune::cpgrid::CpGridData& parentGridData, + const Dune::cpgrid::Entity<0>& parentElem, + const std::array,6>& classifiedParentCellFaces, + const Dune::cpgrid::CpGridData& cellRefinementData, + const Dune::cpgrid::Entity<0>& refinedElem, + BoundaryFaceInfo& boundaryFaceInfo); + +void provideRefinementParentFaceIdxRelations(const std::array, 6>& classifiedParentCellFaces, + const Dune::cpgrid::CpGridData& parentGridData, + const Dune::cpgrid::Entity<0>& parentElem, + const std::array& cells_per_dim, + CellRefinementBoundaryInfo& cellRefBoundaryInfo, + std::vector>>>& faceInMarkedElemAndRefinedFaces, + const std::vector>& oldGridFaceIdx_to_newGridFaceIdxList = std::vector>{}, + const std::vector>& parentFaceIdx_to_newGridFaceIdxList = std::vector>{}, + const std::vector& oldGridFaceIdx_fullyContainedIn_parentFaceIdx = std::vector{}); + +void populateBoundaryRefVertexCoincidesWithParentVertex(int numVertices, CellRefinementBoundaryInfo& cellRefBoundaryInfo); + +void makeCellRefinementParentFaceAware(const std::array, 6>& classifiedParentCellFaces, + const Dune::cpgrid::CpGridData& parentGrid, + const Dune::cpgrid::Entity<0>& parentCellElem, + const Dune::cpgrid::CpGridData& cellRefGrid, + Dune::cpgrid::CpGridData& correctedCellRefGrid, + GeomData& correctedCellRefGridGeomData, + CellRefinementBoundaryInfo& cellRefBoundaryInfo, + std::vector>>>& faceInMarkedElemAndCorrectedCellRefGridFaces, + const std::array& cells_per_dim); + +void computeNewRefinedGeometriesOnSharedCoarseFace(const std::vector& refinedFaces1, + const Dune::cpgrid::CpGridData& parentFaceAwareCellRefinement1, + BoundaryFaceInfo& boundaryFaceInfo, + const std::vector& refinedFaces2, + const Dune::cpgrid::CpGridData& parentFaceAwareCellRefinement2); + +/// Checks whether the specified cell is located at the grid boundary by +/// verifying if any of its faces is connected to only one cell. +bool isAtGridBoundary(const Dune::cpgrid::CpGridData& grid, + const Dune::cpgrid::Entity<0>& element); + +void addFaceVerticesCoordinatesToIndex(const Dune::cpgrid::CpGridData& grid, + int faceIndex, + std::map, int, FieldVectorLess>& pointMap); + +/// Builds a map from grid point coordinates to point indices for all points +/// on the cell boundary, including the eight corner points ("cell_to_point") +/// and additional face points resulting from present of multiple faces of the same +/// type (same tag - I,J, or K, same orientation +/-, e.g.: a cell with 2 I+ faces). +std::map, int, FieldVectorLess> +buildExtendedCellPointVertexMap(const Dune::cpgrid::CpGridData& grid, + int cellIndex); + +/// Checks whether two 3D vectors have matching coordinates within a given tolerance (1e-12). +bool areClose(const Dune::FieldVector& v, + const Dune::FieldVector& w); + +/// Returns a face index on the specified grid faces so that one of the face vertex coordinates +/// match those of the target vertex. +std::optional findVertexIdxInFaces(const Dune::cpgrid::CpGridData& grid, + const std::vector& candidateFaces, + const Dune::FieldVector& targetVertex); + +/// Returns the index of the vertex on the specified face whose coordinates +/// match the specified target vertex. +std::optional findMatchingVertexIdx(const Dune::cpgrid::CpGridData& grid, + int faceIndex, + const Dune::FieldVector& targetVertex); + +/// Returns the coordinates of all vertices defining a face. +std::vector> getFaceVertexCoordinates(const Dune::cpgrid::CpGridData& gridData, + int faceIdx); + +/// Returns the face index on the specified target grid faces +/// whose vertex coordinates match those of the specified source face. +std::optional findMatchingFaceIdx(const Dune::cpgrid::CpGridData& targetGrid, + const std::vector& candidateFaces, + const Dune::cpgrid::CpGridData& sourceGrid, + int sourceFaceIdx); + + +void populateVertexData(const Dune::cpgrid::CpGridData& oldGrid, + const std::map, int, FieldVectorLess>& extendedParentCellToPointVertexMap, + const std::set, FieldVectorLess>& foundNewVertices, + GeomData& newGridGeomData, + std::map, int, FieldVectorLess>& newGridVertexCoordinates_to_newGridVertexIdx, + std::vector>& parentBoundaryVertexIdx_to_newGridBoundaryVertexIdx); + +void populateVertexData(const Dune::cpgrid::CpGridData& oldGrid, + const std::map& parentCellFaceIdx_to_boundaryFaceInfo, + GeomData& newGridGeomData, + std::map, int, FieldVectorLess>& newGridVertexCoordinates_to_newGridVertexIdx, + std::unordered_map& newGridBoundaryVertexIdx_to_parentGridFaceIdx, // otherGridFaceIdx + std::vector& newGridBoundaryVertexCoincidesWithParentVertex);// OtherGridVertex + +void populateFaceToPoint(int face_count, + int num_points, + const std::vector>& face_to_point, + GeomData& geomData); + +/// Resolves each vertex coordinate of the face to its corresponding 'updated' point index, +/// using either the newly created vertices or the existing boundary vertices. +std::vector modifyFaceToPoint(const std::vector>& newFaceToCoord, + const GridModificationMapping& modificationMap, + const BoundaryFaceInfo& boundaryFaceInfo, + int parentGridFaceIdx = -1, + std::unordered_map* newGridBoundaryVertexIdx_to_parentGridFaceIdx = nullptr); + +void populateFaceData(int oldGridNumFaces, + const Dune::cpgrid::CpGridData& oldGrid, + GridModificationMapping& modificationMapps, + GeomData& newGridGeomData, + const BoundaryFaceInfo& boundaryFaceInfo, + std::vector>& parentFaceIdx_to_newGridFaceIdxList, + std::unordered_map& newGridBoundaryVertexIdx_to_parentGridFaceIdx); + +void populateFaceData(int oldGridNumFaces, + const Dune::cpgrid::CpGridData& oldGrid, + GridModificationMapping& modificationMap, + GeomData& newGridGeomData, + const std::map& boundaryFacesInfo, + std::vector& oldGridFaceIdx_to_parentFaceIdx); + +/// Populates cell geometry data, cell-to-point connectivity, and inverse +/// face-to-cell relations using cells from the specified source grid. +void populateCellData(const Dune::cpgrid::CpGridData& sourceGrid, + GeomData& geomData); + +std::pair, GridModificationMapping> +makeCellRefinementNeighborsAware(const Dune::cpgrid::Entity<0>& parentCell, + const std::vector>& cellRefs, // to get neighbor information + const Dune::cpgrid::CpGridData& parentGrid, + const Dune::cpgrid::CpGridData& cellRefGrid, + CellRefinementBoundaryInfo& cellRefGridBoundaryInfo, + std::vector>>>& faceInMarkedElemAndRefinedFaces); + +void makeCellRefinementsNeighborsAware(std::vector>& cellRefs, // to get neighbor information + std::vector& cellRefsBoundaryInfo, + const Dune::cpgrid::CpGridData& parentGrid, + std::vector>>>& faceInMarkedElemAndRefinedFaces, + std::vector& modificationMapps); + +} // namespace Lgr +} // namespace Opm + + +#endif // OPM_GRID_CPGRID_LGRFAUTLHELPERS_HEADER_INCLUDED diff --git a/opm/grid/cpgrid/LgrHelpers.cpp b/opm/grid/cpgrid/LgrHelpers.cpp index 31739e428..f408d4751 100644 --- a/opm/grid/cpgrid/LgrHelpers.cpp +++ b/opm/grid/cpgrid/LgrHelpers.cpp @@ -20,10 +20,13 @@ #include #include +#include #include #include +#include #include #include +#include #include #include // for std::max @@ -93,16 +96,20 @@ void refineAndProvideMarkedRefinedRelations(const Dune::CpGrid& grid, /* Marked int& cell_count, std::vector>& preAdapt_level_to_leaf_cells_vec, /* Additional parameters */ - const std::vector>& cells_per_dim_vec) + const std::vector>& cells_per_dim_vec, + std::vector& cellRefinementsInfo, + bool& withoutFaults) { // Each marked element for refinement (mark equal to 1), will be refined individuality, creating its own Lgr. The element index will // be also used to identify its lgr. Even though, in the end, all the refined entities will belong to a unique level grid. // For this reason, we associate "-1" with those elements that are not involved in any refinement and will appear // as "coarse" cells in the leaf-grid-view (adapted-grid). + std::vector modificationMapps(grid.currentLeafData().size(0)); + // Max level before calling adapt. const int& preAdaptMaxLevel = grid.maxLevel(); - + for (const auto& element : Dune::elements(grid.leafGridView())) { // When the element is not involved in any LGR, it will appear in the updated leaf grid // with same geometrical features (center, volume). @@ -121,12 +128,15 @@ void refineAndProvideMarkedRefinedRelations(const Dune::CpGrid& grid, /* Marked // Shift the markedElemRefinedLevel to access data containers const auto& shiftedLevel = markedElemLevel - preAdaptMaxLevel-1; // Build auxiliary LGR for the refinement of this element - const auto& [elemLgr_ptr, - parentCorners_to_equivalentRefinedCorners] + const auto& [elemLgr_ptr, cellRefinementInfo] = grid.currentLeafData().refineSingleCell(cells_per_dim_vec[shiftedLevel], element.index(), faceInMarkedElemAndRefinedFaces); + markedElem_to_itsLgr[ element.index() ] = elemLgr_ptr; + cellRefinementsInfo[ element.index() ] = cellRefinementInfo; + + withoutFaults = withoutFaults && cellRefinementInfo.parentCellhasSingleFacePerType; // false if faults const int childrenCount = cells_per_dim_vec[shiftedLevel][0]*cells_per_dim_vec[shiftedLevel][1]*cells_per_dim_vec[shiftedLevel][2]; std::vector refinedChildrenList(childrenCount); @@ -147,12 +157,20 @@ void refineAndProvideMarkedRefinedRelations(const Dune::CpGrid& grid, /* Marked } preAdapt_parent_to_children_cells_vec[element.level()][element.getLevelElem().index()] = std::make_pair( markedElemLevel, refinedChildrenList); - for (const auto& [markedCorner, lgrEquivCorner] : parentCorners_to_equivalentRefinedCorners) { + for (const auto& [markedCorner, lgrEquivCorner] : cellRefinementInfo.parentVertexIdx_to_boundaryRefinedVertexIdx) { cornerInMarkedElemWithEquivRefinedCorner[markedCorner].push_back({element.index(), lgrEquivCorner}); markedElemAndEquivRefinedCorn_to_corner[ {element.index(), lgrEquivCorner}] = markedCorner; } } // end-if-elemMark==1 } // end-elem-for-loop + + if (!withoutFaults && (markedElem_count>1)) { + makeCellRefinementsNeighborsAware(markedElem_to_itsLgr, // to get neighbor information + cellRefinementsInfo, + grid.currentLeafData(), + faceInMarkedElemAndRefinedFaces, + modificationMapps); + } } std::tuple>>, std::vector>, std::vector>, std::vector> @@ -273,11 +291,18 @@ void identifyRefinedCornersPerLevel(const Dune::cpgrid::CpGridData& current_data const std::vector& assignRefinedLevel, const std::vector>>& cornerInMarkedElemWithEquivRefinedCorner, const std::vector>>>& faceInMarkedElemAndRefinedFaces, - const std::vector>& cells_per_dim_vec) + const std::vector>& cells_per_dim_vec, + const std::vector& cellRefinementsInfo, + bool withoutFaults) { - // Max level before calling adapt. - // const int& preAdaptMaxLevel = grid.maxLevel(); - + std::vector> visited{}; + visited.resize(current_data.size(0)); + for (int elemIdx = 0; elemIdx < current_data.size(0); ++elemIdx) { + if (markedElem_to_itsLgr.at(elemIdx)!= nullptr) { + visited[elemIdx].resize(markedElem_to_itsLgr[elemIdx]->size(3), false); + } + } + // Step 1. Replace the corners from the preAdapt grid involved in LGR by the equivalent ones, born in LGRs. // In this case, we avoid repetition considering the last appearance of the preAdapt corner // in the LGRs. @@ -301,6 +326,8 @@ void identifyRefinedCornersPerLevel(const Dune::cpgrid::CpGridData& current_data std::array{lastAppearanceLgrLevel, refined_corner_count_vec[shiftedLevel]}, // keyB refined_corner_count_vec[shiftedLevel]); // counter + visited[lastAppearanceLgr][lastAppearanceLgrCorner] = true; + if (cornerInMarkedElemWithEquivRefinedCorner[corner].size()>1) { for (const auto& [elemLgr, elemLgrCorner] : cornerInMarkedElemWithEquivRefinedCorner[corner]) { const auto& elemLgrLevel = assignRefinedLevel[elemLgr]; @@ -312,141 +339,178 @@ void identifyRefinedCornersPerLevel(const Dune::cpgrid::CpGridData& current_data std::array{elemLgr, elemLgrCorner}, // keyA std::array{elemLgrLevel, refined_corner_count_vec[shiftedElemLgrLevel]}, // keyB refined_corner_count_vec[shiftedElemLgrLevel]); // counter - } + + visited[elemLgr][elemLgrCorner] = true; + } } } } } // end corner-forloop - for (int elemIdx = 0; elemIdx < current_data.size(0); ++elemIdx) { - if (markedElem_to_itsLgr.at(elemIdx)!= nullptr) { - const auto& level = assignRefinedLevel[elemIdx]; - assert(level>0); + if (!withoutFaults) { + + for (int elemIdx = 0; elemIdx < current_data.size(0); ++elemIdx) { + if (markedElem_to_itsLgr.at(elemIdx)!= nullptr) { + const auto& level = assignRefinedLevel[elemIdx]; + assert(level>0); + // To access containers with refined level grid information + const auto shiftedLevel = level - preAdaptMaxLevel -1; + + processLevelInteriorCorners(elemIdx, + level, + markedElem_to_itsLgr[elemIdx], + refined_corner_count_vec[shiftedLevel], + elemLgrAndElemLgrCorner_to_refinedLevelAndRefinedCorner, // map a_to_b + refinedLevelAndRefinedCorner_to_elemLgrAndElemLgrCorner, // map b_to_a + cells_per_dim_vec[shiftedLevel], + visited); + } + } + + for (int coarseFaceIdx = 0; coarseFaceIdx < current_data.numFaces(); ++coarseFaceIdx) { + + if (faceInMarkedElemAndRefinedFaces[coarseFaceIdx].empty()) + continue; + + const auto& [firstRef, firstFaces] = faceInMarkedElemAndRefinedFaces[coarseFaceIdx].front(); + const auto& [maxLast, lastFaces] = faceInMarkedElemAndRefinedFaces[coarseFaceIdx].back(); + bool multipleAppearances = (firstRef != maxLast); + + int firstRefLevel = assignRefinedLevel[firstRef]; + int maxLastLevel = assignRefinedLevel[maxLast]; + int shiftedMaxLastLevel = maxLastLevel - preAdaptMaxLevel -1; + // To access containers with refined level grid information - const auto& shiftedLevel = level - preAdaptMaxLevel -1; - for (int corner = 0; corner < markedElem_to_itsLgr.at(elemIdx) ->size(3); ++corner) { - // Discard marked corners. Store (new born) refined corners - - // INTERIOR - if (isRefinedCornerInInteriorLgr(cells_per_dim_vec[shiftedLevel], corner)) { // It's a refined interior corner, so we store it. - // In this case, the corner is a new born refined corner that does not - // coincide with any corner from the GLOBAL grid (level 0). Therefore, - // it has to be stored. - insertBidirectional(elemLgrAndElemLgrCorner_to_refinedLevelAndRefinedCorner, // map a_to_b - refinedLevelAndRefinedCorner_to_elemLgrAndElemLgrCorner, // map b_to_a - std::array{elemIdx, corner}, // keyA - std::array{level, refined_corner_count_vec[shiftedLevel]}, // keyB - refined_corner_count_vec[shiftedLevel]); // counter - } + const auto& shiftedLevel = firstRefLevel - preAdaptMaxLevel -1; + const auto& singleCellRef = markedElem_to_itsLgr[firstRef]; + + + for (const auto& refFace : firstFaces) { + for (const auto& point : singleCellRef->faceToPoint(refFace)) { + + const auto vertex = Dune::cpgrid::Entity<3>(*singleCellRef, point, true).geometry().center(); + + if (visited[firstRef][point] || cellRefinementsInfo[firstRef].boundaryRefinedVertexCoincidesWithParentVertex[point]) + continue; + + if (auto it = cellRefinementsInfo[firstRef].boundaryRefinedVertexIdx_to_parentFaceIdx.find(point); + it != cellRefinementsInfo[firstRef].boundaryRefinedVertexIdx_to_parentFaceIdx.end() && + it->second != coarseFaceIdx) { + continue; + } - // LYING ON EDGES - // - // Refined corners lying on edges - Refined edge has a 'coarse' parent edge (line between 2 corners of the parent cell) - // To avoid repetition, we distinguish the case where the refined corner lies on an edge of its parent cell. - // We detect the two coarse faces involved (Notice that the extremes of the parent cell have been stored previously). - // When the marked faces appears only once, we store the corner now. Otherwise, we store the refined corner on its - // last appearence associated with one of these parent faces, taking also into account the elemLgr. For example, when - // the refined corners lie on an edge connecting I_FACE false and K_FACE true of the parent cell, let's say iFaceIdx, - // kFaceIdx, with each of those faces appearing twice (maximum) : - // iFaceIdx appearing in current "elem" and elemLgr1 - // kFaceIdx appearing in current "elem" and elemLgr2 - // Then, we take the max(elemLgr1, elemLgr2) and store the refined corner only if this maximum equals elem. - if (newRefinedCornerLiesOnEdge(cells_per_dim_vec[shiftedLevel], corner)) { - const auto& markedFacesTouchingEdge = getParentFacesAssocWithNewRefinedCornLyingOnEdge(current_data, - cells_per_dim_vec[shiftedLevel], - corner, - elemIdx); - const auto& [markedFace1, markedFace2] = markedFacesTouchingEdge; - - int lastAppearanceMarkedFace1 = faceInMarkedElemAndRefinedFaces[markedFace1].back().first; // elemLgr1 - int lastAppearanceMarkedFace2 = faceInMarkedElemAndRefinedFaces[markedFace2].back().first; // elemLgr2 - - int maxLastAppearance = std::max(lastAppearanceMarkedFace1, lastAppearanceMarkedFace2); - int faceAtMaxLastAppearance = (maxLastAppearance == lastAppearanceMarkedFace1) ? markedFace1 : markedFace2; - - // Save the relationship between the vanished refined corner and its last appearance - const auto& maxLastAppearanceLevel = assignRefinedLevel[maxLastAppearance]; - const auto& maxLastAppearanceLevelShifted = assignRefinedLevel[maxLastAppearance] - preAdaptMaxLevel -1; - - bool atLeastOneFaceAppearsTwice = (faceInMarkedElemAndRefinedFaces[markedFace1].size()>1) || - (faceInMarkedElemAndRefinedFaces[markedFace2].size()>1); - if (atLeastOneFaceAppearsTwice && (maxLastAppearance != elemIdx)) { - const auto& neighboringLgrCornerIdx = replaceLgr1CornerIdxByLgr2CornerIdx(current_data, - cells_per_dim_vec[shiftedLevel], - corner, elemIdx, faceAtMaxLastAppearance, - cells_per_dim_vec[maxLastAppearanceLevelShifted]); - vanishedRefinedCorner_to_itsLastAppearance[{elemIdx, corner}] = {maxLastAppearance, neighboringLgrCornerIdx}; - // Notice that, when we use these container to locate vanished corners, we might need a while-loop, - // since {elem, corner} leads to {lastMaxAppearance, neighboringLgrCornerIdx}, which can also vanish. - // So we need something like: - // if (elemLgrAndElemLgrCorner_to_adapted/refinedCorner.count({elem, corner}) == 0) - // int updateElemLgr = vanishedRefinedCorner_to_itsLastAppearance[{elem, corner}][0]; - // int updateElemLgrCorner = vanishedRefinedCorner_to_itsLastAppearance[{elem, corner}][1]; - // while (elemLgrAndElemLgrCorner_to_adapted/refinedCorner.count({updateElemLgr, updateElemLgCorner}) == 0) - // int tempElemLgr = updateElemLgr; - // int tempElemLgrCorner = updateElemLgrCorner; - // updateElemLgr = vanishedRefinedCorner_to_itsLastAppearance[{ tempElemLgr , tempElemLgrCorner}][0]; - // updateElemLgrCorner = vanishedRefinedCorner_to_itsLastAppearance[{ tempElemLgr , tempElemLgrCorner}][1]; - // Then, use the lastest update to search for the corner in teh refined/adapted grid (which would be the one that - // gives elemLgrAndElemLgrCorner_to_adapted/refinedCorner.count({updateElemLgr, updateElemLgCorner}) == 1). + if (multipleAppearances && !visited[firstRef][point]) { + visited[firstRef][point] = true; + + const auto neighborVertexIdx = findVertexIdxInFaces(*markedElem_to_itsLgr[maxLast], + lastFaces, + vertex); + + assert(neighborVertexIdx.has_value()); + + int neighborCorner = neighborVertexIdx.value(); + + markVanishedCorner({firstRef, point}, {maxLast, neighborCorner}, + vanishedRefinedCorner_to_itsLastAppearance); + + visited[maxLast][neighborCorner] = true; + insertBidirectional(elemLgrAndElemLgrCorner_to_refinedLevelAndRefinedCorner, // map a_to_b + refinedLevelAndRefinedCorner_to_elemLgrAndElemLgrCorner, // map b_to_a + std::array{maxLast, neighborCorner}, // keyA + std::array{maxLastLevel, refined_corner_count_vec[shiftedMaxLastLevel]},// keyB + refined_corner_count_vec[shiftedMaxLastLevel]); // counter + + if (maxLastLevel != firstRefLevel) { + + visited[firstRef][point] = true; + insertBidirectional(elemLgrAndElemLgrCorner_to_refinedLevelAndRefinedCorner, // map a_to_b + refinedLevelAndRefinedCorner_to_elemLgrAndElemLgrCorner, // map b_to_a + std::array{firstRef, point}, // keyA + std::array{firstRefLevel, refined_corner_count_vec[shiftedLevel]}, // keyB + refined_corner_count_vec[shiftedLevel]); // counter + + } } - if ((maxLastAppearance == elemIdx) || (level!= maxLastAppearanceLevel)) { - // Store the refined corner in its last appearence - to avoid repetition. - insertBidirectional(elemLgrAndElemLgrCorner_to_refinedLevelAndRefinedCorner, // map a_to_b - refinedLevelAndRefinedCorner_to_elemLgrAndElemLgrCorner, // map b_to_a - std::array{elemIdx, corner}, // keyA - std::array{level, refined_corner_count_vec[shiftedLevel]}, // keyB - refined_corner_count_vec[shiftedLevel]); // counter + else { + visited[firstRef][point] = true; + insertBidirectional(elemLgrAndElemLgrCorner_to_refinedLevelAndRefinedCorner, // map a_to_b + refinedLevelAndRefinedCorner_to_elemLgrAndElemLgrCorner, // map b_to_a + std::array{firstRef, point}, // keyA + std::array{firstRefLevel, refined_corner_count_vec[shiftedLevel]}, // keyB + refined_corner_count_vec[shiftedLevel]); // counter } } + } + } + } - // LYING ON BOUNDARY LGR - NOT ON AN EDGE - NOT COINCIDING WITH A MARKED CORNER - // - // If the refined corner lies on the boundary of the LGR, e.i., it was born on one of the faces - // of the marked element that got refined, then, we have two cases: - // - the marked face appears only in one marked element -> then, we store this corner now. - // - the marked face appears twice (maximum times) in two marked elements -> we store it later. - if ( isRefinedNewBornCornerOnLgrBoundary(cells_per_dim_vec[shiftedLevel], corner) && - !newRefinedCornerLiesOnEdge(cells_per_dim_vec[shiftedLevel], corner)) { - // Get the index of the marked face where the refined corner was born. - const auto& markedFace = getParentFaceWhereNewRefinedCornerLiesOn(current_data, - cells_per_dim_vec[shiftedLevel], - corner, elemIdx); - // check how many times marked face appearn - // Get the last LGR (marked element) where the marked face appeared. - int lastLgrWhereMarkedFaceAppeared = faceInMarkedElemAndRefinedFaces[markedFace].back().first; - - const auto& lastLgrLevel = assignRefinedLevel[lastLgrWhereMarkedFaceAppeared ]; - const auto& lastLgrLevelShifted = lastLgrLevel - preAdaptMaxLevel -1; - // Save the relationship between the vanished refined corner and its last appearance - if ((faceInMarkedElemAndRefinedFaces[markedFace].size()>1) && (lastLgrWhereMarkedFaceAppeared != elemIdx)) { - const auto& neighboringLgrCornerIdx = replaceLgr1CornerIdxByLgr2CornerIdx(cells_per_dim_vec[shiftedLevel], corner, - cells_per_dim_vec[lastLgrLevelShifted]); - vanishedRefinedCorner_to_itsLastAppearance[{elemIdx, corner}] = {lastLgrWhereMarkedFaceAppeared, neighboringLgrCornerIdx}; - } + if (withoutFaults) { + for (int elemIdx = 0; elemIdx < current_data.size(0); ++elemIdx) { + if (markedElem_to_itsLgr.at(elemIdx)!= nullptr) { + const auto& level = assignRefinedLevel[elemIdx]; + assert(level>0); + // To access containers with refined level grid information + const auto& shiftedLevel = level - preAdaptMaxLevel -1; + + const auto& singleCellRef = markedElem_to_itsLgr[elemIdx]; + + processLevelInteriorCorners(elemIdx, + level, + singleCellRef, + refined_corner_count_vec[shiftedLevel], + elemLgrAndElemLgrCorner_to_refinedLevelAndRefinedCorner, // map a_to_b + refinedLevelAndRefinedCorner_to_elemLgrAndElemLgrCorner, // map b_to_a + cells_per_dim_vec[shiftedLevel], + visited); + + + processLevelEdgeCorners(elemIdx, + level, + singleCellRef, + refined_corner_count_vec[shiftedLevel], + elemLgrAndElemLgrCorner_to_refinedLevelAndRefinedCorner, // map a_to_b + refinedLevelAndRefinedCorner_to_elemLgrAndElemLgrCorner, // map b_to_a + vanishedRefinedCorner_to_itsLastAppearance, + current_data, + assignRefinedLevel, + faceInMarkedElemAndRefinedFaces, + cellRefinementsInfo[elemIdx].boundaryRefinedVertexCoincidesWithParentVertex, + markedElem_to_itsLgr); - if ((lastLgrWhereMarkedFaceAppeared == elemIdx) || (lastLgrLevel != level)) { - // Store the refined corner in its last appearence - to avoid repetition. - insertBidirectional(elemLgrAndElemLgrCorner_to_refinedLevelAndRefinedCorner, // map a_to_b + // LYING ON BOUNDARY LGR - NOT ON AN EDGE - NOT COINCIDING WITH A MARKED CORNER + processLevelBoundaryCorners(elemIdx, + level, + shiftedLevel, + singleCellRef, + refined_corner_count_vec[shiftedLevel], + elemLgrAndElemLgrCorner_to_refinedLevelAndRefinedCorner, // map a_to_b refinedLevelAndRefinedCorner_to_elemLgrAndElemLgrCorner, // map b_to_a - std::array{elemIdx, corner}, // keyA - std::array{level, refined_corner_count_vec[shiftedLevel]}, // keyB - refined_corner_count_vec[shiftedLevel]); // counter - } - } - } // end-corner-for-loop + vanishedRefinedCorner_to_itsLastAppearance, + current_data, + assignRefinedLevel, + faceInMarkedElemAndRefinedFaces, + cells_per_dim_vec, + cellRefinementsInfo[elemIdx].boundaryRefinedVertexIdx_to_parentFaceIdx, + cellRefinementsInfo[elemIdx].boundaryRefinedVertexCoincidesWithParentVertex, + markedElem_to_itsLgr); + } } // end-if-nullptr } // end-elem-for-loop } -bool isRefinedCornerInInteriorLgr(const std::array& cells_per_dim, int cornerIdxInLgr) +bool isRefinedCornerInInteriorLgr(const std::array& cells_per_dim, + int cornerIdxInLgr) { - assert(cells_per_dim[0]>0); - assert(cells_per_dim[1]>0); - assert(cells_per_dim[2]>0); + assert(cells_per_dim[0]*cells_per_dim[1]*cells_per_dim[2]>0); + const int total_naive_corners = (cells_per_dim[0] +1)*(cells_per_dim[1]+1)*(cells_per_dim[2]+1); - const auto& ijk = getRefinedCornerIJK(cells_per_dim, cornerIdxInLgr); - return ((ijk[0]%cells_per_dim[0] > 0) && (ijk[1]%cells_per_dim[1]>0) && (ijk[2]%cells_per_dim[2]>0)); + if (total_naive_corners<= cornerIdxInLgr) { + return false; + } + else { + const auto& ijk = getRefinedCornerIJK(cells_per_dim, cornerIdxInLgr); + return ((ijk[0]%cells_per_dim[0] > 0) && (ijk[1]%cells_per_dim[1]>0) && (ijk[2]%cells_per_dim[2]>0)); + } } std::array getRefinedCornerIJK(const std::array& cells_per_dim, int cornerIdxInLgr) @@ -467,129 +531,25 @@ std::array getRefinedCornerIJK(const std::array& cells_per_dim, in return ijk; } -bool newRefinedCornerLiesOnEdge(const std::array& cells_per_dim, int cornerIdxInLgr) -{ - const auto& ijk = getRefinedCornerIJK(cells_per_dim, cornerIdxInLgr); - // Edges laying on bottom face - bool isNewBornOnEdge01 = (ijk[0] % cells_per_dim[0] != 0) && (ijk[1] == 0) && (ijk[2] == 0); - bool isNewBornOnEdge23 = (ijk[0] % cells_per_dim[0] != 0) && (ijk[1] == cells_per_dim[1]) && ( ijk[2] == 0); - bool isNewBornOnEdge02 = (ijk[0] == 0) && (ijk[1] % cells_per_dim[1] != 0) && (ijk[2] == 0); - bool isNewBornOnEdge13 = (ijk[0] == cells_per_dim[0]) && (ijk[1] % cells_per_dim[1] != 0) && (ijk[2] == 0); - - // Edges connecting bottom and top faces - bool isNewBornOnEdge04 = (ijk[0] == 0) && (ijk[1] == 0) && (ijk[2] % cells_per_dim[2] != 0); - bool isNewBornOnEdge26 = (ijk[0] == 0) && (ijk[1] == cells_per_dim[1]) && (ijk[2] % cells_per_dim[2] != 0); - bool isNewBornOnEdge15 = (ijk[0] == cells_per_dim[0]) && (ijk[1] == 0) && (ijk[2] % cells_per_dim[2] != 0); - bool isNewBornOnEdge37 = (ijk[0] == cells_per_dim[0]) && (ijk[1] == cells_per_dim[1]) && (ijk[2] % cells_per_dim[2] != 0); - - // Edges laying on top face - bool isNewBornOnEdge45 = (ijk[0] % cells_per_dim[0] != 0) && (ijk[1] == 0) && (ijk[2] == cells_per_dim[2]); - bool isNewBornOnEdge67 = (ijk[0] % cells_per_dim[0] != 0) && (ijk[1] == cells_per_dim[1]) && ( ijk[2] == cells_per_dim[2]); - bool isNewBornOnEdge46 = (ijk[0] == 0) && (ijk[1] % cells_per_dim[1] != 0) && (ijk[2] == cells_per_dim[2]); - bool isNewBornOnEdge57 = (ijk[0] == cells_per_dim[0]) && (ijk[1] % cells_per_dim[1] != 0) && (ijk[2] == cells_per_dim[2]); - - bool isOnEdge = isNewBornOnEdge01 || isNewBornOnEdge23 || isNewBornOnEdge02 || isNewBornOnEdge13 || - isNewBornOnEdge04 || isNewBornOnEdge26 || isNewBornOnEdge15 || isNewBornOnEdge37 || - isNewBornOnEdge45 || isNewBornOnEdge67 || isNewBornOnEdge46 || isNewBornOnEdge57; - - return isOnEdge; -} - -std::array getParentFacesAssocWithNewRefinedCornLyingOnEdge(const Dune::cpgrid::CpGridData& current_data, - const std::array& cells_per_dim, - int cornerIdxInLgr, - int elemLgr) -{ - assert(newRefinedCornerLiesOnEdge(cells_per_dim, cornerIdxInLgr)); - - const auto& parentCell_to_face = current_data.cellToFace(elemLgr); - if(parentCell_to_face.size()>6){ - OPM_THROW(std::logic_error, "The associted parent cell has more than six faces. Refinment/Adaptivity not supported yet."); - } - // Corners Order defined in Geometry::refine (j*(cells_per_dim[0]+1)*(cells_per_dim[2]+1)) + (i*(cells_per_dim[2]+1)) + k - const auto& ijk = getRefinedCornerIJK(cells_per_dim, cornerIdxInLgr); - // Edges laying on bottom face - bool isNewBornOnEdge01 = (ijk[0] % cells_per_dim[0] != 0) && (ijk[1] == 0) && (ijk[2] == 0); - bool isNewBornOnEdge23 = (ijk[0] % cells_per_dim[0] != 0) && (ijk[1] == cells_per_dim[1]) && ( ijk[2] == 0); - bool isNewBornOnEdge02 = (ijk[0] == 0) && (ijk[1] % cells_per_dim[1] != 0) && (ijk[2] == 0); - bool isNewBornOnEdge13 = (ijk[0] == cells_per_dim[0]) && (ijk[1] % cells_per_dim[1] != 0) && (ijk[2] == 0); - - // Edges connecting bottom and top faces - bool isNewBornOnEdge04 = (ijk[0] == 0) && (ijk[1] == 0) && (ijk[2] % cells_per_dim[2] != 0); - bool isNewBornOnEdge26 = (ijk[0] == 0) && (ijk[1] == cells_per_dim[1]) && (ijk[2] % cells_per_dim[2] != 0); - bool isNewBornOnEdge15 = (ijk[0] == cells_per_dim[0]) && (ijk[1] == 0) && (ijk[2] % cells_per_dim[2] != 0); - bool isNewBornOnEdge37 = (ijk[0] == cells_per_dim[0]) && (ijk[1] == cells_per_dim[1]) && (ijk[2] % cells_per_dim[2] != 0); - - // Edges laying on top face - bool isNewBornOnEdge45 = (ijk[0] % cells_per_dim[0] != 0) && (ijk[1] == 0) && (ijk[2] == cells_per_dim[2]); - bool isNewBornOnEdge67 = (ijk[0] % cells_per_dim[0] != 0) && (ijk[1] == cells_per_dim[1]) && ( ijk[2] == cells_per_dim[2]); - bool isNewBornOnEdge46 = (ijk[0] == 0) && (ijk[1] % cells_per_dim[1] != 0) && (ijk[2] == cells_per_dim[2]); - bool isNewBornOnEdge57 = (ijk[0] == cells_per_dim[0]) && (ijk[1] % cells_per_dim[1] != 0) && (ijk[2] == cells_per_dim[2]); - - std::vector auxFaces; - auxFaces.reserve(2); - - for (const auto& face : parentCell_to_face) { - const auto& faceTag = current_data.faceTag(face.index()); - // Add I_FACE false - bool addIfalse = isNewBornOnEdge02 || isNewBornOnEdge04 || isNewBornOnEdge26 || isNewBornOnEdge46; - if( addIfalse && (faceTag == 0) && (!face.orientation())) { - auxFaces.push_back(face.index()); - } - // Add J_FACE false - bool addJfalse = isNewBornOnEdge01 || isNewBornOnEdge04 || isNewBornOnEdge15 || isNewBornOnEdge45; - if( addJfalse && (faceTag == 1) && (!face.orientation())) { - auxFaces.push_back(face.index()); - } - // Add K_FACE false - bool addKfalse = isNewBornOnEdge01 || isNewBornOnEdge13 || isNewBornOnEdge23 || isNewBornOnEdge02; - if( addKfalse && (faceTag == 2) && (!face.orientation())) { - auxFaces.push_back(face.index()); - } - // Add I_FACE true - bool addItrue = isNewBornOnEdge13 || isNewBornOnEdge15 || isNewBornOnEdge37 || isNewBornOnEdge57; - if( addItrue && (faceTag == 0) && (face.orientation())) { - auxFaces.push_back(face.index()); - } - // Add J_FACE true - bool addJtrue = isNewBornOnEdge23|| isNewBornOnEdge26 || isNewBornOnEdge37 || isNewBornOnEdge67; - if( addJtrue && (faceTag == 1) && (face.orientation())) { - auxFaces.push_back(face.index()); - } - // Add K_FACE true - bool addKtrue = isNewBornOnEdge45 || isNewBornOnEdge67 || isNewBornOnEdge46 || isNewBornOnEdge57; - if(addKtrue && (faceTag == 2) && (face.orientation())) { - auxFaces.push_back(face.index()); - } - } - return {auxFaces[0], auxFaces[1]}; -} - -bool isRefinedNewBornCornerOnLgrBoundary(const std::array& cells_per_dim, int cornerIdxInLgr) -{ - const auto& ijk = getRefinedCornerIJK(cells_per_dim, cornerIdxInLgr); - bool isOnParentCell_I_FACEfalse_and_newBornCorn = ( (ijk[0] == 0) && ((ijk[1] % cells_per_dim[1] != 0) || (ijk[2] % cells_per_dim[2] !=0) )); - bool isOnParentCell_I_FACEtrue_and_newBornCorn = ( (ijk[0] == cells_per_dim[0]) && ((ijk[1] % cells_per_dim[1] != 0) || (ijk[2] % cells_per_dim[2] !=0) )); - bool isOnParentCell_J_FACEfalse_and_newBornCorn = ( (ijk[1] == 0) && ((ijk[0] % cells_per_dim[0] != 0) || (ijk[2] % cells_per_dim[2] !=0) )); - bool isOnParentCell_J_FACEtrue_and_newBornCorn = ( (ijk[1] == cells_per_dim[1]) && ((ijk[0] % cells_per_dim[0] != 0) || (ijk[2] % cells_per_dim[2] !=0) )); - bool isOnParentCell_K_FACEfalse_and_newBornCorn = ( (ijk[2] == 0) && ((ijk[1] % cells_per_dim[1] != 0) || (ijk[0] % cells_per_dim[0] !=0) )); - bool isOnParentCell_K_FACEtrue_and_newBornCorn = ( (ijk[2] == cells_per_dim[2]) && ((ijk[1] % cells_per_dim[1] != 0) || (ijk[0] % cells_per_dim[0] !=0) )); - bool isOnParentCell_I_FACE = isOnParentCell_I_FACEfalse_and_newBornCorn || isOnParentCell_I_FACEtrue_and_newBornCorn; - bool isOnParentCell_J_FACE = isOnParentCell_J_FACEfalse_and_newBornCorn || isOnParentCell_J_FACEtrue_and_newBornCorn; - bool isOnParentCell_K_FACE = isOnParentCell_K_FACEfalse_and_newBornCorn || isOnParentCell_K_FACEtrue_and_newBornCorn; - return (isOnParentCell_I_FACE || isOnParentCell_J_FACE || isOnParentCell_K_FACE); -} - int getParentFaceWhereNewRefinedCornerLiesOn(const Dune::cpgrid::CpGridData& current_data, const std::array& cells_per_dim, - int cornerIdxInLgr, int elemLgr) + int cornerIdxInLgr, + int elemLgr, + const std::unordered_map& extraRefCornIdx_to_parentFaceIdx) { - assert(isRefinedNewBornCornerOnLgrBoundary(cells_per_dim, cornerIdxInLgr)); - - const auto& parentCell_to_face = current_data.cellToFace(elemLgr); - if(parentCell_to_face.size()>6){ - OPM_THROW(std::logic_error, "The associted parent cell has more than six faces. Refinment/Adaptivity not supported yet."); + assert(!isRefinedCornerInInteriorLgr(cells_per_dim, cornerIdxInLgr)); + const auto total_naive_corners = (cells_per_dim[0] +1)*(cells_per_dim[1]+1)*(cells_per_dim[2]+1); + + if (total_naive_corners<= cornerIdxInLgr) { // "extra corners lying on boundary of single-cell-refinement have larger indices" + assert(!extraRefCornIdx_to_parentFaceIdx.empty()); + auto it = extraRefCornIdx_to_parentFaceIdx.find(cornerIdxInLgr); + if (it != extraRefCornIdx_to_parentFaceIdx.end()) { + auto faceIdx = it->second; + return faceIdx; + } } + + const auto& parentCell_to_face = current_data.cellToFace(elemLgr); const auto& ijk = getRefinedCornerIJK(cells_per_dim, cornerIdxInLgr); bool isOnParentCell_I_FACEfalse_and_newBornCorn = ( (ijk[0] == 0) && ((ijk[1] % cells_per_dim[1] != 0) || (ijk[2] % cells_per_dim[2] !=0) )); @@ -623,120 +583,50 @@ int getParentFaceWhereNewRefinedCornerLiesOn(const Dune::cpgrid::CpGridData& cur OPM_THROW(std::logic_error, "Cannot find parent face index where new refined corner lays on."); } - -int replaceLgr1CornerIdxByLgr2CornerIdx(const std::array& cells_per_dim_lgr1, - int cornerIdxLgr1, - const std::array& cells_per_dim_lgr2) +void markVanishedCorner(const std::array& vanished, + const std::array& lastAppearance, + std::map, std::array>& vanishedRefinedCorner_to_itsLastAppearance) { - const auto& ijkLgr1 = getRefinedCornerIJK(cells_per_dim_lgr1, cornerIdxLgr1); - // Order defined in Geometry::refine - // (j*(cells_per_dim[0]+1)*(cells_per_dim[2]+1)) + (i*(cells_per_dim[2]+1)) + k - - // On a parallel run, no symmetry between neighboring elements should be assumed. Therefore, all the six cases - // (i = 0, cells_per_dim[0], j = 0, cells_per_dim[1], and k = 0, cells_per_dim[2]) have to be taken into account. - // On a serial run, it would be enough to consider i = cells_per_dim[0], j = cells_per_dim[1], and k = cells_per_dim[2]. - // To cover all possible scenarios, serial and parallel, we consider the six cases. - - if (ijkLgr1[0] == cells_per_dim_lgr1[0]) { // same j, k, but i = 0 - return (ijkLgr1[1]*(cells_per_dim_lgr2[0]+1)*(cells_per_dim_lgr2[2]+1)) + ijkLgr1[2]; - } - if (ijkLgr1[1] == cells_per_dim_lgr1[1]) { // same i,k, but j = 0 - return (ijkLgr1[0]*(cells_per_dim_lgr2[2]+1)) + ijkLgr1[2]; - } - if (ijkLgr1[2] == cells_per_dim_lgr1[2]) { // same i,j, but k = 0 - return (ijkLgr1[1]*(cells_per_dim_lgr2[0]+1)*(cells_per_dim_lgr2[2]+1)) + (ijkLgr1[0]*(cells_per_dim_lgr2[2]+1)); - } - if (ijkLgr1[0] == 0) { // same j,k, but i = cells_per_dim[0] - return (ijkLgr1[1]*(cells_per_dim_lgr2[0]+1)*(cells_per_dim_lgr2[2]+1)) + (cells_per_dim_lgr2[0]*(cells_per_dim_lgr2[2]+1))+ ijkLgr1[2]; - } - if (ijkLgr1[1] == 0) { // same i,k, but j = cells_per_Dim[1] - return (cells_per_dim_lgr2[1]*(cells_per_dim_lgr2[0]+1)*(cells_per_dim_lgr2[2]+1)) + (ijkLgr1[0]*(cells_per_dim_lgr2[2]+1)) + ijkLgr1[2]; - } - if (ijkLgr1[2] == 0) { // same i,j, but k = cells_per_dim[2] - return (ijkLgr1[1]*(cells_per_dim_lgr2[0]+1)*(cells_per_dim_lgr2[2]+1)) + (ijkLgr1[0]*(cells_per_dim_lgr2[2]+1)) + cells_per_dim_lgr2[2]; - } - else { - const auto& message = "Cannot convert corner index from one LGR to its neighboring LGR."; - OPM_THROW(std::logic_error, message); - } + vanishedRefinedCorner_to_itsLastAppearance[vanished] = lastAppearance; } - -int replaceLgr1CornerIdxByLgr2CornerIdx(const Dune::cpgrid::CpGridData& current_data, - const std::array& cells_per_dim_lgr1, - int cornerIdxLgr1, - int elemLgr1, - int parentFaceLastAppearanceIdx, - const std::array& cells_per_dim_lgr2) +void processLevelInteriorCorners(int parentCellIdx, + int level, + const std::shared_ptr& singleCellRefinement, + int& level_corner_count, + std::map,std::array>& elemLgrAndElemLgrCorner_to_refinedLevelAndRefinedCorner, + std::map,std::array>& refinedLevelAndRefinedCorner_to_elemLgrAndElemLgrCorner, + const std::array& level_cells_per_dim, + std::vector>& visited) { -#ifndef NDEBUG - assert(newRefinedCornerLiesOnEdge(cells_per_dim_lgr1, cornerIdxLgr1)); - const auto& faces = getParentFacesAssocWithNewRefinedCornLyingOnEdge(current_data, cells_per_dim_lgr1, cornerIdxLgr1, elemLgr1); - assert( (faces[0] == parentFaceLastAppearanceIdx) || (faces[1] == parentFaceLastAppearanceIdx)); -#endif - - const auto& ijkLgr1 = getRefinedCornerIJK(cells_per_dim_lgr1, cornerIdxLgr1); - const auto& parentCell_to_face = current_data.cellToFace(elemLgr1); - - if(parentCell_to_face.size()>6){ - OPM_THROW(std::logic_error, "The associated parent cell has more than six faces. Refinement/Adaptivity not supported yet."); - } - - // Order defined in Geometry::refine - // (j*(cells_per_dim[0]+1)*(cells_per_dim[2]+1)) + (i*(cells_per_dim[2]+1)) + k - - for (const auto& face : parentCell_to_face) { - const auto& faceTag = current_data.faceTag(face.index()); - if (parentFaceLastAppearanceIdx == face.index()) { - if ( face.orientation() ){ - if (faceTag == 0) { // I_FACE true. The same new born refined corner will have equal j and k, but i == 0. - return (ijkLgr1[1]*(cells_per_dim_lgr2[0]+1)*(cells_per_dim_lgr2[2]+1)) + ijkLgr1[2]; - } - if (faceTag == 1) {// J_FACE true. The same new born refined corner will have equal i and k, but j == 0. - return (ijkLgr1[0]*(cells_per_dim_lgr2[2]+1)) + ijkLgr1[2]; - } - if (faceTag == 2) {// K_FACE true. The same new born refined corner will have equal i and j, but k == 0. - return (ijkLgr1[1]*(cells_per_dim_lgr2[0]+1)*(cells_per_dim_lgr2[2]+1)) + (ijkLgr1[0]*(cells_per_dim_lgr2[2]+1)); - } - } - if(!face.orientation()) { - if (faceTag == 0) {// I_FACE false. The same new born refined corner will have equal values of j and k, but i == cells_per_dim[0]. - return (ijkLgr1[1]*(cells_per_dim_lgr2[0]+1)*(cells_per_dim_lgr2[2]+1)) + - (cells_per_dim_lgr2[0]*(cells_per_dim_lgr2[2]+1)) +ijkLgr1[2]; - } - if (faceTag == 1) {// J_FACE false. The same new born refined corner will have equal i and k, but j == cells_per_dim[1]. - return (cells_per_dim_lgr2[1]*(cells_per_dim_lgr2[0]+1)*(cells_per_dim_lgr2[2]+1)) - + (ijkLgr1[0]*(cells_per_dim_lgr2[2]+1)) + ijkLgr1[2]; - } - if (faceTag == 2) {// K_FACE false. The same new born refined corner will have equal i and j, but k == cells_per_dim[2]. - return (ijkLgr1[1]*(cells_per_dim_lgr2[0]+1)*(cells_per_dim_lgr2[2]+1)) + (ijkLgr1[0]*(cells_per_dim_lgr2[2]+1)) - + cells_per_dim_lgr2[2]; - } - } + // These corners are fully inside a single-cell-refinement and do not coincide with any starting grid corner. + // They are always stored as new corners in the level grid. + for (int corner = 0; corner < singleCellRefinement->size(3); ++corner) { + if (isRefinedCornerInInteriorLgr(level_cells_per_dim, corner)) { + visited[parentCellIdx][corner] = true; + insertBidirectional(elemLgrAndElemLgrCorner_to_refinedLevelAndRefinedCorner, // map a_to_b + refinedLevelAndRefinedCorner_to_elemLgrAndElemLgrCorner, // map b_to_a + std::array{parentCellIdx, corner}, // keyA + std::array{level, level_corner_count}, // keyB + level_corner_count); } } - OPM_THROW(std::logic_error, "Cannot convert corner index from one LGR to its neighboring LGR."); } -void markVanishedCorner(const std::array& vanished, - const std::array& lastAppearance, - std::map, std::array>& vanishedRefinedCorner_to_itsLastAppearance) -{ - vanishedRefinedCorner_to_itsLastAppearance[vanished] = lastAppearance; -} - -void processInteriorCorners(int elemIdx, int shiftedLevel, - const std::shared_ptr& lgr, - int& corner_count, - std::map,int>& elemLgrAndElemLgrCorner_to_adaptedCorner, - std::unordered_map>& adaptedCorner_to_elemLgrAndElemLgrCorner, - const std::vector>& cells_per_dim_vec) +void processLeafInteriorCorners(int elemIdx, + int shiftedLevel, + const std::shared_ptr& lgr, + int& corner_count, + std::map,int>& elemLgrAndElemLgrCorner_to_adaptedCorner, + std::unordered_map>& adaptedCorner_to_elemLgrAndElemLgrCorner, + const std::vector>& cells_per_dim_vec, + std::vector>& visited) { - // Interior refined corners - // These corners are fully inside an LGR and do not coincide with any starting grid (global/level 0) corner. - // They are always stored as new corners in the adapted grid. + // These corners are fully inside a single-cell-refinement and do not coincide with any starting grid corner. + // They are always stored as new corners in the updated leaf grid. for (int corner = 0; corner < lgr->size(3); ++corner) { if (isRefinedCornerInInteriorLgr(cells_per_dim_vec[shiftedLevel], corner)) { + visited[elemIdx][corner] = true; insertBidirectional(elemLgrAndElemLgrCorner_to_adaptedCorner, // map a_to_b adaptedCorner_to_elemLgrAndElemLgrCorner, // unordered_map b_to_a std::array{elemIdx, corner}, // keyA @@ -745,17 +635,18 @@ void processInteriorCorners(int elemIdx, int shiftedLevel, } } -void processEdgeCorners(int elemIdx, int shiftedLevel, - const std::shared_ptr& lgr, - int& corner_count, - std::map,int>& elemLgrAndElemLgrCorner_to_adaptedCorner, - std::unordered_map>& adaptedCorner_to_elemLgrAndElemLgrCorner, - std::map, std::array>& vanishedRefinedCorner_to_itsLastAppearance, - const Dune::cpgrid::CpGridData& current_data, - int preAdaptMaxLevel, - const std::vector& assignRefinedLevel, - const std::vector>>>& faceInMarkedElemAndRefinedFaces, - const std::vector>& cells_per_dim_vec) +void processLevelEdgeCorners(int elemIdx, + int level, + const std::shared_ptr& lgr, + int& level_corner_count, + std::map,std::array>& elemLgrAndElemLgrCorner_to_refinedLevelAndRefinedCorner, + std::map,std::array>& refinedLevelAndRefinedCorner_to_elemLgrAndElemLgrCorner, + std::map, std::array>& vanishedRefinedCorner_to_itsLastAppearance, + const Dune::cpgrid::CpGridData& current_data, + const std::vector& assignRefinedLevel, + const std::vector>>>& faceInMarkedElemAndRefinedFaces, + const std::vector& coincideWithCoarseCorner, + const std::vector>& markedElem_to_itsLgr) { // Refined corners lying on edges // Corners on edges of a parent cell. Each edge connects two coarse parent corners. @@ -763,83 +654,268 @@ void processEdgeCorners(int elemIdx, int shiftedLevel, // - If the two parent faces appear only once, store immediately. // - Otherwise, store the corner at its last appearance among these faces, considering elemLgr. for (int corner = 0; corner < lgr->size(3); ++corner) { - if (!newRefinedCornerLiesOnEdge(cells_per_dim_vec[shiftedLevel], corner)) continue; + const auto vertex = Dune::cpgrid::Entity<3>(*lgr, corner, true).geometry().center(); + + const auto facesWhereVertexAppear = Opm::Lgr::isVertexInElementEdge(vertex, elemIdx, current_data); + bool isVertexInParentEdgeInterior = facesWhereVertexAppear.size()>0; + + if ((!isVertexInParentEdgeInterior) || coincideWithCoarseCorner[corner]) + continue; + + int maxLast = -1; + std::vector lastFaces{}; + int faceAtMax = -1; + + bool multipleAppearances = false; + + for (const auto face : facesWhereVertexAppear) { + const auto& markedFaces = faceInMarkedElemAndRefinedFaces[face]; - const auto& [face1, face2] = getParentFacesAssocWithNewRefinedCornLyingOnEdge(current_data, - cells_per_dim_vec[shiftedLevel], - corner, elemIdx); + if (markedFaces.size() > 1) { + multipleAppearances = true; + } - int last1 = faceInMarkedElemAndRefinedFaces[face1].back().first; - int last2 = faceInMarkedElemAndRefinedFaces[face2].back().first; - int maxLast = std::max(last1, last2); - int faceAtMax = (maxLast == last1) ? face1 : face2; + if (!markedFaces.empty() && markedFaces.back().first > maxLast) { + maxLast = markedFaces.back().first; + lastFaces = markedFaces.back().second; + faceAtMax = face; + } + } + assert(maxLast >= 0); int maxLastLevel = assignRefinedLevel[maxLast]; - bool multipleAppearances = faceInMarkedElemAndRefinedFaces[face1].size() > 1 || - faceInMarkedElemAndRefinedFaces[face2].size() > 1; + if (multipleAppearances && (maxLast != elemIdx)) { + assert(faceInMarkedElemAndRefinedFaces[faceAtMax].size() == 2); + const auto neighborVertexIdx = findVertexIdxInFaces(*markedElem_to_itsLgr[maxLast], + lastFaces, + vertex); + + assert(neighborVertexIdx.has_value()); - if ((multipleAppearances && maxLast != elemIdx) || (maxLastLevel != assignRefinedLevel[elemIdx])) { - int maxShifted = maxLastLevel - preAdaptMaxLevel - 1; - int neighborCorner = replaceLgr1CornerIdxByLgr2CornerIdx(current_data, - cells_per_dim_vec[shiftedLevel], - corner, elemIdx, faceAtMax, - cells_per_dim_vec[maxShifted]); + int neighborCorner = neighborVertexIdx.value(); + markVanishedCorner({elemIdx, corner}, {maxLast, neighborCorner}, vanishedRefinedCorner_to_itsLastAppearance); } - if (maxLast == elemIdx) { - insertBidirectional(elemLgrAndElemLgrCorner_to_adaptedCorner, // map a_to_b - adaptedCorner_to_elemLgrAndElemLgrCorner, // unordered_map b_to_a - std::array{elemIdx, corner}, // keyA - corner_count); // counter (keyB) + if ((maxLast == elemIdx) || (level!= maxLastLevel)) { + + insertBidirectional(elemLgrAndElemLgrCorner_to_refinedLevelAndRefinedCorner, // map a_to_b + refinedLevelAndRefinedCorner_to_elemLgrAndElemLgrCorner, // map b_to_a + std::array{elemIdx, corner}, // keyA + std::array{level, level_corner_count}, // keyB + level_corner_count); // counter } } } -void processBoundaryCorners(int elemIdx, int shiftedLevel, +void processLeafEdgeCorners(int elemIdx, const std::shared_ptr& lgr, int& corner_count, std::map,int>& elemLgrAndElemLgrCorner_to_adaptedCorner, std::unordered_map>& adaptedCorner_to_elemLgrAndElemLgrCorner, std::map, std::array>& vanishedRefinedCorner_to_itsLastAppearance, const Dune::cpgrid::CpGridData& current_data, - int preAdaptMaxLevel, const std::vector& assignRefinedLevel, const std::vector>>>& faceInMarkedElemAndRefinedFaces, - const std::vector>& cells_per_dim_vec) + const std::vector& coincideWithCoarseCorner, + const std::vector>& markedElem_to_itsLgr) { - // Refined corners on LGR boundaries (not on edges) - // Corners born on a face of a marked element that got refined. - // Storage rules: - // - If the parent face appears only once, store immediately. - // - If the face appears in multiple LGRs, store at its last appearance to avoid duplicates. + // Refined corners lying on edges + // Corners on edges of a parent cell. Each edge connects two coarse parent corners. + // To avoid duplicates: + // - If the two parent faces appear only once, store immediately. + // - Otherwise, store the corner at its last appearance among these faces, considering elemLgr. for (int corner = 0; corner < lgr->size(3); ++corner) { - if (!isRefinedNewBornCornerOnLgrBoundary(cells_per_dim_vec[shiftedLevel], corner) || - newRefinedCornerLiesOnEdge(cells_per_dim_vec[shiftedLevel], corner)) continue; + const auto vertex = Dune::cpgrid::Entity<3>(*lgr, corner, true).geometry().center(); + + const auto facesWhereVertexAppear = Opm::Lgr::isVertexInElementEdge(vertex, + elemIdx, + current_data); + + bool isVertexInParentEdgeInterior = facesWhereVertexAppear.size()>0; + if ((!isVertexInParentEdgeInterior)|| coincideWithCoarseCorner[corner]) + continue; + + int maxLastt = -1; + int faceAtMax = -1; + + bool multipleAppearances = false; + + for (const auto face : facesWhereVertexAppear) { + const auto& markedFaces = faceInMarkedElemAndRefinedFaces[face]; + + if (markedFaces.size() > 1) { + multipleAppearances = true; + } - const auto& face = getParentFaceWhereNewRefinedCornerLiesOn(current_data, - cells_per_dim_vec[shiftedLevel], - corner, elemIdx); - int lastLgr = faceInMarkedElemAndRefinedFaces[face].back().first; - int lastLevel = assignRefinedLevel[lastLgr]; - int lastShifted = lastLevel - preAdaptMaxLevel - 1; - - if (faceInMarkedElemAndRefinedFaces[face].size() > 1 && lastLgr != elemIdx) { - int neighborCorner = replaceLgr1CornerIdxByLgr2CornerIdx(cells_per_dim_vec[shiftedLevel], - corner, - cells_per_dim_vec[lastShifted]); - markVanishedCorner({elemIdx, corner}, {lastLgr, neighborCorner}, + if (!markedFaces.empty() && markedFaces.back().first > maxLastt) { + maxLastt = markedFaces.back().first; + faceAtMax = face; + } + } + assert(maxLastt >= 0); + const auto& [maxLast, lastFaces] = faceInMarkedElemAndRefinedFaces[faceAtMax].back(); + int maxLastLevel = assignRefinedLevel[maxLast]; + + if ((multipleAppearances && (maxLast != elemIdx)) || (maxLastLevel != assignRefinedLevel[elemIdx])) { + //int maxShifted = maxLastLevel - preAdaptMaxLevel - 1; + assert(faceInMarkedElemAndRefinedFaces[faceAtMax].size() == 2); + + const auto neighborVertexIdx = findVertexIdxInFaces(*markedElem_to_itsLgr[maxLast], + lastFaces, + vertex); + assert(neighborVertexIdx.has_value()); + + int neighborCorner = neighborVertexIdx.value(); + + markVanishedCorner({elemIdx, corner}, {maxLast, neighborCorner}, vanishedRefinedCorner_to_itsLastAppearance); } - if (lastLgr == elemIdx) { + if (maxLast == elemIdx) { insertBidirectional(elemLgrAndElemLgrCorner_to_adaptedCorner, // map a_to_b adaptedCorner_to_elemLgrAndElemLgrCorner, // unordered_map b_to_a std::array{elemIdx, corner}, // keyA corner_count); // counter (keyB) } } + +} + +void processLevelBoundaryCorners(int elemIdx, + int level, + int shiftedLevel, + const std::shared_ptr& lgr, + int& level_corner_count, + std::map,std::array>& elemLgrAndElemLgrCorner_to_refinedLevelAndRefinedCorner, + std::map,std::array>& refinedLevelAndRefinedCorner_to_elemLgrAndElemLgrCorner, + std::map, std::array>& vanishedRefinedCorner_to_itsLastAppearance, + const Dune::cpgrid::CpGridData& current_data, + const std::vector& assignRefinedLevel, + const std::vector>>>& faceInMarkedElemAndRefinedFaces, + const std::vector>& cells_per_dim_vec, + const std::unordered_map& boundaryRefinedVertex_to_parentFace, + const std::vector& boundaryRefinedVertexCoincidesWithParentVertex, + const std::vector>& markedElem_to_itsLgr) + +{ + // Refined corners on LGR boundaries (not on edges) + // Corners born on a face of a marked element that got refined. + // Storage rules: + // - If the parent face appears only once, store immediately. + // - If the face appears in multiple LGRs, store at its last appearance to avoid duplicates. + for (int corner = 0; corner < lgr->size(3); ++corner) { + const auto vertex = Dune::cpgrid::Entity<3>(*lgr, corner, true).geometry().center(); + + const auto uniqueTypeFacesVertexIsIn = Opm::Lgr::isVertexInElementEdge(vertex, + elemIdx, + current_data); + bool isVertexInParentEdgeInterior = uniqueTypeFacesVertexIsIn.size()>0; + + if (boundaryRefinedVertexCoincidesWithParentVertex[corner] || + isRefinedCornerInInteriorLgr(cells_per_dim_vec[shiftedLevel], corner)|| + isVertexInParentEdgeInterior) continue; + + const auto face = getParentFaceWhereNewRefinedCornerLiesOn(current_data, + cells_per_dim_vec[shiftedLevel], + corner, + elemIdx, + boundaryRefinedVertex_to_parentFace); + + int maxLast = -1; + std::vector lastFaces{}; + bool multipleAppearances = false; + + const auto& markedFaces = faceInMarkedElemAndRefinedFaces[face]; + + if (markedFaces.size() > 1) { + multipleAppearances = true; + } + + if (!markedFaces.empty() && markedFaces.back().first > maxLast) { + maxLast = markedFaces.back().first; + lastFaces = markedFaces.back().second; + } + assert(maxLast >= 0); + int maxLastLevel = assignRefinedLevel[maxLast]; + + if (multipleAppearances && (maxLast != elemIdx)) { + + const auto neighborVertexIdx = findVertexIdxInFaces(*markedElem_to_itsLgr[maxLast], + lastFaces, + vertex); + assert(neighborVertexIdx.has_value()); + + markVanishedCorner({elemIdx, corner}, {maxLast, neighborVertexIdx.value()}, + vanishedRefinedCorner_to_itsLastAppearance); + } + if ((maxLast == elemIdx) || (maxLastLevel != level)) { + insertBidirectional(elemLgrAndElemLgrCorner_to_refinedLevelAndRefinedCorner, // map a_to_b + refinedLevelAndRefinedCorner_to_elemLgrAndElemLgrCorner, // map b_to_a + std::array{elemIdx, corner}, // keyA + std::array{level, level_corner_count}, // keyB + level_corner_count); // counter + } + } +} + +void processLeafBoundaryCorners(int elemIdx, int shiftedLevel, + const std::shared_ptr& lgr, + int& corner_count, + std::map,int>& elemLgrAndElemLgrCorner_to_adaptedCorner, + std::unordered_map>& adaptedCorner_to_elemLgrAndElemLgrCorner, + std::map, std::array>& vanishedRefinedCorner_to_itsLastAppearance, + const Dune::cpgrid::CpGridData& current_data, + const std::vector>>>& faceInMarkedElemAndRefinedFaces, + const std::vector>& cells_per_dim_vec, + const std::unordered_map& boundaryRefinedVertex_to_parentFace, + const std::vector& boundaryRefinedVertexCoincidesWithParentVertex, + const std::vector>& markedElem_to_itsLgr) +{ + // Refined corners on LGR boundaries (not on edges) + // Corners born on a face of a marked element that got refined. + // Storage rules: + // - If the parent face appears only once, store immediately. + // - If the face appears in multiple LGRs, store at its last appearance to avoid duplicates. + for (int corner = 0; corner < lgr->size(3); ++corner) { + + const auto vertex = Dune::cpgrid::Entity<3>(*lgr, corner, true).geometry().center(); + const auto facesWithEdgeContainingVertex = Opm::Lgr::isVertexInElementEdge(vertex, + elemIdx, + current_data); + + if (boundaryRefinedVertexCoincidesWithParentVertex[corner] || + isRefinedCornerInInteriorLgr(cells_per_dim_vec[shiftedLevel], corner) || + facesWithEdgeContainingVertex.size()) continue; + + const auto& face = getParentFaceWhereNewRefinedCornerLiesOn(current_data, + cells_per_dim_vec[shiftedLevel], + corner, + elemIdx, + boundaryRefinedVertex_to_parentFace); + + bool multipleAppearances = faceInMarkedElemAndRefinedFaces[face].size() >1; + const auto& [lastLgr, lastFaces] = faceInMarkedElemAndRefinedFaces[face].back(); + + if (multipleAppearances && (lastLgr != elemIdx)) { + + const auto neighborVertexIdx = findVertexIdxInFaces(*markedElem_to_itsLgr[lastLgr], + lastFaces, + vertex); + assert(neighborVertexIdx.has_value()); + + markVanishedCorner({elemIdx, corner}, {lastLgr, neighborVertexIdx.value()}, + vanishedRefinedCorner_to_itsLastAppearance); + } + if (lastLgr == elemIdx) { + + insertBidirectional(elemLgrAndElemLgrCorner_to_adaptedCorner, // map a_to_b + adaptedCorner_to_elemLgrAndElemLgrCorner, // unordered_map b_to_a + std::array{elemIdx, corner}, // keyA + corner_count); // counter (keyB) + } + } } void identifyLeafGridCorners(const Dune::cpgrid::CpGridData& current_data, @@ -852,8 +928,19 @@ void identifyLeafGridCorners(const Dune::cpgrid::CpGridData& current_data, const std::vector>>& cornerInMarkedElemWithEquivRefinedCorner, std::map, std::array>& vanishedRefinedCorner_to_itsLastAppearance, const std::vector>>>& faceInMarkedElemAndRefinedFaces, - const std::vector>& cells_per_dim_vec) + const std::vector>& cells_per_dim_vec, + const std::vector& cellRefinementsInfo, + bool withoutFaults) { + std::vector> visited{}; + visited.resize(current_data.size(0)); + for (int elemIdx = 0; elemIdx < current_data.size(0); ++elemIdx) { + if (markedElem_to_itsLgr.at(elemIdx)!= nullptr) { + visited[elemIdx].resize(markedElem_to_itsLgr[elemIdx]->size(3), false); + } + } + + // Step 1: Handle starting grid corners const int numCorners = current_data.size(3); for (int corner = 0; corner < numCorners; ++corner) { @@ -870,35 +957,124 @@ void identifyLeafGridCorners(const Dune::cpgrid::CpGridData& current_data, adaptedCorner_to_elemLgrAndElemLgrCorner, // unordered_map b_to_a std::array{lgr, lgrCorner}, // keyA corner_count); // counter (keyB) + visited[lgr][lgrCorner] = true; } } + + if (!withoutFaults) { - // Step 2: Handle refined grid corners - for (int elemIdx = 0; elemIdx < current_data.size(0); ++elemIdx) { - if (!markedElem_to_itsLgr[elemIdx]) continue; - int level = assignRefinedLevel[elemIdx]; - int shiftedLevel = level - preAdaptMaxLevel - 1; - - const auto& lgr = markedElem_to_itsLgr[elemIdx]; - processInteriorCorners(elemIdx, shiftedLevel, lgr, corner_count, - elemLgrAndElemLgrCorner_to_adaptedCorner, - adaptedCorner_to_elemLgrAndElemLgrCorner, - cells_per_dim_vec); - - processEdgeCorners(elemIdx, shiftedLevel, lgr, corner_count, - elemLgrAndElemLgrCorner_to_adaptedCorner, - adaptedCorner_to_elemLgrAndElemLgrCorner, - vanishedRefinedCorner_to_itsLastAppearance, - current_data, preAdaptMaxLevel, assignRefinedLevel, faceInMarkedElemAndRefinedFaces, - cells_per_dim_vec); - - processBoundaryCorners(elemIdx, shiftedLevel, lgr, corner_count, - elemLgrAndElemLgrCorner_to_adaptedCorner, - adaptedCorner_to_elemLgrAndElemLgrCorner, - vanishedRefinedCorner_to_itsLastAppearance, - current_data, preAdaptMaxLevel, - assignRefinedLevel, faceInMarkedElemAndRefinedFaces, - cells_per_dim_vec); + for (int elemIdx = 0; elemIdx < current_data.size(0); ++elemIdx) { + if (markedElem_to_itsLgr.at(elemIdx)!= nullptr) { + int level = assignRefinedLevel[elemIdx]; + int shiftedLevel = level - preAdaptMaxLevel - 1; + + const auto& lgr = markedElem_to_itsLgr[elemIdx]; + + processLeafInteriorCorners(elemIdx, shiftedLevel, lgr, corner_count, + elemLgrAndElemLgrCorner_to_adaptedCorner, + adaptedCorner_to_elemLgrAndElemLgrCorner, + cells_per_dim_vec, + visited); + } + } + + for (int coarseFaceIdx = 0; coarseFaceIdx < current_data.numFaces(); ++coarseFaceIdx) { + + if (faceInMarkedElemAndRefinedFaces[coarseFaceIdx].empty()) + continue; + + const auto& [firstRef, firstFaces] = faceInMarkedElemAndRefinedFaces[coarseFaceIdx].front(); + const auto& [maxLast, lastFaces] = faceInMarkedElemAndRefinedFaces[coarseFaceIdx].back(); + bool multipleAppearances = (faceInMarkedElemAndRefinedFaces[coarseFaceIdx].size() == 2); + + const auto& singleCellRef = markedElem_to_itsLgr[firstRef]; + + for (const auto& refFace : firstFaces) { + for (const auto& point : singleCellRef->faceToPoint(refFace)) { + + if (visited[firstRef][point] || cellRefinementsInfo[firstRef].boundaryRefinedVertexCoincidesWithParentVertex[point]) + continue; + + if (auto it = cellRefinementsInfo[firstRef].boundaryRefinedVertexIdx_to_parentFaceIdx.find(point); + it != cellRefinementsInfo[firstRef].boundaryRefinedVertexIdx_to_parentFaceIdx.end() && + it->second != coarseFaceIdx) { + continue; + } + + const auto vertex = Dune::cpgrid::Entity<3>(*singleCellRef, point, true).geometry().center(); + + if (multipleAppearances) { + + visited[firstRef][point] = true; + + const auto neighborVertexIdx = findVertexIdxInFaces(*markedElem_to_itsLgr[maxLast], + lastFaces, + vertex); + + assert(neighborVertexIdx.has_value()); + + int neighborCorner = neighborVertexIdx.value(); + + markVanishedCorner({firstRef, point}, {maxLast, neighborCorner}, + vanishedRefinedCorner_to_itsLastAppearance); + + if (maxLast != firstRef) { + visited[maxLast][neighborCorner] = true; + + insertBidirectional(elemLgrAndElemLgrCorner_to_adaptedCorner, // map a_to_b + adaptedCorner_to_elemLgrAndElemLgrCorner, // unordered_map b_to_a + std::array{maxLast, neighborCorner}, // keyA + corner_count); // counter (keyB) + } + } + else if (!multipleAppearances) { + visited[firstRef][point] = true; + + insertBidirectional(elemLgrAndElemLgrCorner_to_adaptedCorner, // map a_to_b + adaptedCorner_to_elemLgrAndElemLgrCorner, // unordered_map b_to_a + std::array{firstRef, point}, // keyA + corner_count); // counter (keyB) + } + } + } + } + } + + if (withoutFaults) { + + // Step 2: Handle refined grid corners + for (int elemIdx = 0; elemIdx < current_data.size(0); ++elemIdx) { + if (!markedElem_to_itsLgr[elemIdx]) continue; + int level = assignRefinedLevel[elemIdx]; + int shiftedLevel = level - preAdaptMaxLevel - 1; + + const auto& lgr = markedElem_to_itsLgr[elemIdx]; + processLeafInteriorCorners(elemIdx, shiftedLevel, lgr, corner_count, + elemLgrAndElemLgrCorner_to_adaptedCorner, + adaptedCorner_to_elemLgrAndElemLgrCorner, + cells_per_dim_vec, + visited); + + processLeafEdgeCorners(elemIdx, + lgr, corner_count, + elemLgrAndElemLgrCorner_to_adaptedCorner, + adaptedCorner_to_elemLgrAndElemLgrCorner, + vanishedRefinedCorner_to_itsLastAppearance, + current_data, assignRefinedLevel, faceInMarkedElemAndRefinedFaces, + cellRefinementsInfo[elemIdx].boundaryRefinedVertexCoincidesWithParentVertex, + markedElem_to_itsLgr); + + processLeafBoundaryCorners(elemIdx, shiftedLevel, lgr, corner_count, + elemLgrAndElemLgrCorner_to_adaptedCorner, + adaptedCorner_to_elemLgrAndElemLgrCorner, + vanishedRefinedCorner_to_itsLastAppearance, + current_data, + faceInMarkedElemAndRefinedFaces, + cells_per_dim_vec, + cellRefinementsInfo[elemIdx].boundaryRefinedVertexIdx_to_parentFaceIdx, + cellRefinementsInfo[elemIdx].boundaryRefinedVertexCoincidesWithParentVertex, + markedElem_to_itsLgr); + } } } @@ -910,7 +1086,7 @@ void identifyRefinedFacesPerLevel(const Dune::cpgrid::CpGridData& current_data, const std::vector>& markedElem_to_itsLgr, const std::vector& assignRefinedLevel, const std::vector>>>& faceInMarkedElemAndRefinedFaces, - const std::vector>& cells_per_dim_vec) + const std::vector& cellRefinements) { for (int elemIdx = 0; elemIdx < current_data.size(0); ++elemIdx) { if (!markedElem_to_itsLgr[elemIdx]) continue; // skip elements not involved in refinement @@ -920,10 +1096,11 @@ void identifyRefinedFacesPerLevel(const Dune::cpgrid::CpGridData& current_data, // To access containers with refined level grid information const int shiftedLevel = level - preAdaptMaxLevel - 1; - // Loop over refined faces of the auxiliary single-cell-refinement of the current element (with index elemIdx) + // Loop over refined faces of the auxiliary single-cell-refinement of the current element (with index elemIdx) for (int face = 0; face < markedElem_to_itsLgr[elemIdx]->numFaces(); ++face) { - bool isInterior = !isRefinedFaceOnLgrBoundary(cells_per_dim_vec[shiftedLevel], - face, markedElem_to_itsLgr[elemIdx]); + bool isInterior = !isRefinedFaceOnLgrBoundary(face, + markedElem_to_itsLgr[elemIdx]); + // Store new born refined faces (do not have a "parent face" from the parent cell with index elemIdx) if (isInterior) { // Case 1: Interior refined face -> store immediately @@ -942,12 +1119,14 @@ void identifyRefinedFacesPerLevel(const Dune::cpgrid::CpGridData& current_data, // - If the marked face appears only in one marked element -> then, we store this face now. // - If the marked face appears in two marked elements -> we distinguish between // both marked elements sharing that face belonging to the same level, or not. - int markedFace = getParentFaceWhereNewRefinedFaceLiesOn(current_data, cells_per_dim_vec[shiftedLevel], - face, markedElem_to_itsLgr[elemIdx], elemIdx); - + const auto markedFace = getParentFaceWhereNewRefinedFaceLiesOn(face, + markedElem_to_itsLgr[elemIdx], + cellRefinements[elemIdx].boundaryRefinedFaceIdx_to_parentFaceIdx); + assert(!faceInMarkedElemAndRefinedFaces[markedFace].empty()); if (faceInMarkedElemAndRefinedFaces[markedFace].size() == 1) { + // The marked face appears only in one marked element -> then, we store this face now. #ifndef NDEBUG int lastElemIdxWithMarkedFace = faceInMarkedElemAndRefinedFaces[markedFace].back().first; @@ -993,14 +1172,13 @@ void identifyRefinedFacesPerLevel(const Dune::cpgrid::CpGridData& current_data, } void identifyLeafGridFaces(const Dune::cpgrid::CpGridData& current_data, - int preAdaptMaxLevel, std::map,int>& elemLgrAndElemLgrFace_to_adaptedFace, std::unordered_map>& adaptedFace_to_elemLgrAndElemLgrFace, int& face_count, const std::vector>& markedElem_to_itsLgr, const std::vector& assignRefinedLevel, const std::vector>>>& faceInMarkedElemAndRefinedFaces, - const std::vector>& cells_per_dim_vec) + const std::vector& cellRefinementsInfo) { // Step 1. Add LGR faces (new refined ones) for (int elem = 0; elem < current_data.size(0); ++elem) { @@ -1008,15 +1186,11 @@ void identifyLeafGridFaces(const Dune::cpgrid::CpGridData& current_data, const int level = assignRefinedLevel[elem]; assert(level > 0); - const int shiftedLevel = level - preAdaptMaxLevel - 1; for (int face = 0; face < markedElem_to_itsLgr[elem]->numFaces(); ++face) { - bool isInterior = !isRefinedFaceOnLgrBoundary(cells_per_dim_vec[shiftedLevel], - face, - markedElem_to_itsLgr[elem]); + bool isInterior = !isRefinedFaceOnLgrBoundary(face, markedElem_to_itsLgr[elem]); - if (isInterior) { - // Interior refined face->store immediately + if (isInterior) { // Interior refined face->store immediately insertBidirectional(elemLgrAndElemLgrFace_to_adaptedFace, // map a_to_b adaptedFace_to_elemLgrAndElemLgrFace, // unordered_map b_to_a {elem, face}, // keyA @@ -1028,15 +1202,15 @@ void identifyLeafGridFaces(const Dune::cpgrid::CpGridData& current_data, // of the marked element that got refined, then, we have two cases: // - the marked face appears only in one marked element -> then, we store this face now. // - the marked face appears twice (maximum times) in two marked elements -> we store it later. - int markedFace = getParentFaceWhereNewRefinedFaceLiesOn(current_data, cells_per_dim_vec[shiftedLevel], - face, markedElem_to_itsLgr[elem], elem); + const auto markedFace = getParentFaceWhereNewRefinedFaceLiesOn(face, + markedElem_to_itsLgr[elem], + cellRefinementsInfo[elem].boundaryRefinedFaceIdx_to_parentFaceIdx); assert(!faceInMarkedElemAndRefinedFaces[markedFace].empty()); int lastLgr = faceInMarkedElemAndRefinedFaces[markedFace].back().first; - - if (lastLgr == elem) { - // Store only at last appearance + + if (lastLgr == elem) { // Store only at last appearance insertBidirectional(elemLgrAndElemLgrFace_to_adaptedFace, // map a_to_b adaptedFace_to_elemLgrAndElemLgrFace, // unordered_map b_to_a {elem, face}, // keyA @@ -1057,154 +1231,20 @@ void identifyLeafGridFaces(const Dune::cpgrid::CpGridData& current_data, } } -std::array getRefinedFaceIJK(const std::array& cells_per_dim, - int faceIdxInLgr, - const std::shared_ptr& elemLgr_ptr) -{ - // Order defined in Geometry::refine - // K_FACES (k*cells_per_dim[0]*cells_per_dim[1]) + (j*cells_per_dim[0]) + i - // I_FACES (cells_per_dim[0]*cells_per_dim[1]*(cells_per_dim[2]+1)) - // + (i*cells_per_dim[1]*cells_per_dim[2]) + (k*cells_per_dim[1]) + j - // J_FACES (cells_per_dim[0]*cells_per_dim[1]*(cells_per_dim[2] +1)) - // + ((cells_per_dim[0]+1)*cells_per_dim[1]*cells_per_dim[2]) - // + (j*cells_per_dim[0]*cells_per_dim[2]) + (i*cells_per_dim[2]) + k - const auto& i_faces = (cells_per_dim[0] +1)*cells_per_dim[1]*cells_per_dim[2]; - const auto& j_faces = cells_per_dim[0]*(cells_per_dim[1]+1)*cells_per_dim[2]; - const auto& k_faces = cells_per_dim[0]*cells_per_dim[1]*(cells_per_dim[2]+1); - - if (faceIdxInLgr >= i_faces + j_faces + k_faces) { - OPM_THROW(std::logic_error, "Invalid face index from single-cell-refinement.\n"); - } - - const auto& faceTag = elemLgr_ptr ->faceTag(faceIdxInLgr); - std::array ijk; - switch (faceTag) { - case I_FACE: - faceIdxInLgr -= (cells_per_dim[0]*cells_per_dim[1]*(cells_per_dim[2]+1)); - // faceIdxInLgr = (i*cells_per_dim[1]*cells_per_dim[2]) + (k*cells_per_dim[1]) + j - ijk[1] = faceIdxInLgr % cells_per_dim[1]; - faceIdxInLgr -= ijk[1]; // (i*cells_per_dim[1]*cells_per_dim[2]) + (k*cells_per_dim[1]) - faceIdxInLgr /= cells_per_dim[1]; // (i*cells_per_dim[2]) + k - ijk[2] = faceIdxInLgr % cells_per_dim[2]; - faceIdxInLgr -=ijk[2]; // i*cells_per_dim[2] - ijk[0] = faceIdxInLgr / cells_per_dim[2]; - break; - case J_FACE: - faceIdxInLgr -= (cells_per_dim[0]*cells_per_dim[1]*(cells_per_dim[2] +1)) - + ((cells_per_dim[0]+1)*cells_per_dim[1]*cells_per_dim[2]); - // faceIdxInLgr = (j*cells_per_dim[0]*cells_per_dim[2]) + (i*cells_per_dim[2]) + k - ijk[2] = faceIdxInLgr % cells_per_dim[2]; - faceIdxInLgr -= ijk[2]; // (j*cells_per_dim[0]*cells_per_dim[2]) + (i*cells_per_dim[2]) - faceIdxInLgr /= cells_per_dim[2]; // (j*cells_per_dim[0]) + i - ijk[0] = faceIdxInLgr % cells_per_dim[0]; - faceIdxInLgr -=ijk[0]; // j*cells_per_dim[0] - ijk[1] = faceIdxInLgr / cells_per_dim[0]; - break; - case K_FACE: - // (k*cells_per_dim[0]*cells_per_dim[1]) + (j*cells_per_dim[0]) + i - ijk[0] = faceIdxInLgr % cells_per_dim[0]; - faceIdxInLgr -= ijk[0]; // (k*cells_per_dim[0]*cells_per_dim[1]) + (j*cells_per_dim[0]) - faceIdxInLgr /= cells_per_dim[0]; // (k*cells_per_dim[1]) + j - ijk[1] = faceIdxInLgr % cells_per_dim[1]; - faceIdxInLgr -=ijk[1]; // k*cells_per_dim[1] - ijk[2] = faceIdxInLgr / cells_per_dim[1]; - break; - default: - OPM_THROW(std::logic_error, "FaceTag is not I, J, or K!"); - } - return ijk; -} - -bool isRefinedFaceInInteriorLgr(const std::array& cells_per_dim, int faceIdxInLgr, const std::shared_ptr& elemLgr_ptr) -{ - - int refined_k_faces = cells_per_dim[0]*cells_per_dim[1]*(cells_per_dim[2]+1); - int refined_i_faces = (cells_per_dim[0]+1)*cells_per_dim[1]*cells_per_dim[2]; - - bool isKface = (faceIdxInLgr < refined_k_faces); - bool isIface = (faceIdxInLgr >= refined_k_faces) && (faceIdxInLgr < refined_k_faces + refined_i_faces); - bool isJface = (faceIdxInLgr >= refined_k_faces + refined_i_faces); - - const auto& ijk = getRefinedFaceIJK(cells_per_dim, faceIdxInLgr, elemLgr_ptr); - return ((ijk[0]%cells_per_dim[0] > 0 && isIface) || (ijk[1]%cells_per_dim[1]>0 && isJface) || (ijk[2]%cells_per_dim[2]>0 && isKface)); -} - - -bool isRefinedFaceOnLgrBoundary(const std::array& cells_per_dim, int faceIdxInLgr, +bool isRefinedFaceOnLgrBoundary(int faceIdxInLgr, const std::shared_ptr& elemLgr_ptr) { - const auto& ijk = getRefinedFaceIJK(cells_per_dim, faceIdxInLgr, elemLgr_ptr); - - int refined_k_faces = cells_per_dim[0]*cells_per_dim[1]*(cells_per_dim[2]+1); - int refined_i_faces = (cells_per_dim[0]+1)*cells_per_dim[1]*cells_per_dim[2]; - - bool isKface = (faceIdxInLgr < refined_k_faces); - bool isIface = (faceIdxInLgr >= refined_k_faces) && (faceIdxInLgr < refined_k_faces + refined_i_faces); - bool isJface = (faceIdxInLgr >= refined_k_faces + refined_i_faces); - - bool isOnParentCell_I_FACE = isIface && (ijk[0] % cells_per_dim[0] == 0) && (ijk[1]faceToCell(faceIdxInLgr).size() == 1; } -int getParentFaceWhereNewRefinedFaceLiesOn(const Dune::cpgrid::CpGridData& current_data, - const std::array& cells_per_dim, - int faceIdxInLgr, +int getParentFaceWhereNewRefinedFaceLiesOn(int faceIdxInLgr, const std::shared_ptr& elemLgr_ptr, - int elemLgr) + const std::vector& refinedFace_to_parentFace) { - assert(isRefinedFaceOnLgrBoundary(cells_per_dim, faceIdxInLgr, elemLgr_ptr)); - const auto& ijk = getRefinedFaceIJK(cells_per_dim, faceIdxInLgr, elemLgr_ptr); - const auto& parentCell_to_face = current_data.cellToFace(elemLgr); - // cell_to_face_ [ element ] = { I false, I true, J false, J true, K false, K true } if current leaf data is level zero - - if(parentCell_to_face.size()>6){ - OPM_THROW(std::logic_error, "The associated parent cell has more than six faces. Refinement/Adaptivity not supported yet."); - } - - // Order defined in Geometry::refine (to be used for distinguishing if faceIdxInLgr is K, I, or J face) - // - // K_FACES (k*cells_per_dim[0]*cells_per_dim[1]) + (j*cells_per_dim[0]) + i - // I_FACES (cells_per_dim[0]*cells_per_dim[1]*(cells_per_dim[2]+1)) - // + (i*cells_per_dim[1]*cells_per_dim[2]) + (k*cells_per_dim[1]) + j - // J_FACES (cells_per_dim[0]*cells_per_dim[1]*(cells_per_dim[2] +1)) - // + ((cells_per_dim[0]+1)*cells_per_dim[1]*cells_per_dim[2]) - // + (j*cells_per_dim[0]*cells_per_dim[2]) + (i*cells_per_dim[2]) + k - int refined_k_faces = cells_per_dim[0]*cells_per_dim[1]*(cells_per_dim[2]+1); - int refined_i_faces = (cells_per_dim[0]+1)*cells_per_dim[1]*cells_per_dim[2]; -#ifndef NDEBUG - int refined_j_faces = cells_per_dim[0]*(cells_per_dim[1]+1)*cells_per_dim[2]; - - assert( faceIdxInLgr < refined_k_faces + refined_i_faces + refined_j_faces); -#endif - for (const auto& face : parentCell_to_face) { - const auto& faceTag = current_data.faceTag(face.index()); - if (faceIdxInLgr < refined_k_faces ) { // It's a K_FACE - if ((ijk[2] == 0) && (faceTag == 2) && !face.orientation()) { // {K_FACE, false} - return face.index(); - } - if ((ijk[2] == cells_per_dim[2]) && (faceTag == 2) && face.orientation()) { // {K_FACE, true} - return face.index(); - } - } - if ((faceIdxInLgr >= refined_k_faces) && (faceIdxInLgr < refined_k_faces + refined_i_faces)) { // It's I_FACE - if ((ijk[0] == 0) && (faceTag == 0) && !face.orientation()) { // {I_FACE, false} - return face.index(); - } - if ((ijk[0] == cells_per_dim[0]) && (faceTag == 0) && face.orientation()) { // {I_FACE, true} - return face.index(); - } - } - if (faceIdxInLgr >= refined_k_faces + refined_i_faces) {// It's J_FACE - if ((ijk[1] == 0) && (faceTag == 1) && !face.orientation()) { // {J_FACE, false} - return face.index(); - } - if ((ijk[1] == cells_per_dim[1]) && (faceTag == 1) && face.orientation()) { // {J_FACE, true} - return face.index(); - } - } + assert(isRefinedFaceOnLgrBoundary(faceIdxInLgr, elemLgr_ptr)); + + if (refinedFace_to_parentFace[faceIdxInLgr] != -1 /* invalid index */) { + return refinedFace_to_parentFace[faceIdxInLgr]; } OPM_THROW(std::logic_error, "Cannot find index of parent face where the new refined face lies on."); } @@ -1239,7 +1279,6 @@ void populateRefinedFaces(std::vector,int>& markedElemAndEquivRefinedCorn_to_corner) { for (std::size_t shiftedLevel = 0; shiftedLevel < refined_face_count_vec.size(); ++shiftedLevel) { - // Store the refined faces refined_faces_vec[shiftedLevel].resize(refined_face_count_vec[shiftedLevel]); mutable_refined_face_tags_vec[shiftedLevel].resize(refined_face_count_vec[shiftedLevel]); @@ -1325,11 +1364,10 @@ void populateRefinedCells(const Dune::cpgrid::CpGridData& current_data, const std::map,std::array>& elemLgrAndElemLgrCorner_to_refinedLevelAndRefinedCorner, const std::map, std::array>& vanishedRefinedCorner_to_itsLastAppearance, const std::vector>& markedElem_to_itsLgr, - const std::vector& assignRefinedLevel, const int& preAdaptMaxLevel, const std::map,int>& markedElemAndEquivRefinedCorn_to_corner, const std::vector>>& cornerInMarkedElemWithEquivRefinedCorner, - const std::vector>& cells_per_dim_vec) + const std::vector& cellRefinementsInfo) { // --- Refined cells --- for (std::size_t shiftedLevel = 0; shiftedLevel < refined_cell_count_vec.size(); ++shiftedLevel) { @@ -1400,16 +1438,23 @@ void populateRefinedCells(const Dune::cpgrid::CpGridData& current_data, auto face_candidate = elemLgrAndElemLgrFace_to_refinedLevelAndRefinedFace.find({elemLgr, preAdaptFace}); if (face_candidate == elemLgrAndElemLgrFace_to_refinedLevelAndRefinedFace.end()) { // Get the index of the marked face where the refined face was born. - const auto& markedFace = getParentFaceWhereNewRefinedFaceLiesOn(current_data, - cells_per_dim_vec[shiftedLevel], - preAdaptFace, - markedElem_to_itsLgr[elemLgr], elemLgr); + const auto markedFace = getParentFaceWhereNewRefinedFaceLiesOn(preAdaptFace, + markedElem_to_itsLgr[elemLgr], + cellRefinementsInfo[elemLgr].boundaryRefinedFaceIdx_to_parentFaceIdx); // Get the last LGR (marked element) where the marked face appeared. - const int& lastLgrWhereMarkedFaceAppeared = faceInMarkedElemAndRefinedFaces[markedFace].back().first; - const auto& lastAppearanceLgrEquivFace = replaceLgr1FaceIdxByLgr2FaceIdx(cells_per_dim_vec[shiftedLevel], - preAdaptFace, - markedElem_to_itsLgr[elemLgr], - cells_per_dim_vec[assignRefinedLevel[lastLgrWhereMarkedFaceAppeared] - preAdaptMaxLevel -1]); + const auto& [ lastLgrWhereMarkedFaceAppeared, lastFaces] = faceInMarkedElemAndRefinedFaces[markedFace].back(); + assert( faceInMarkedElemAndRefinedFaces[markedFace].size() == 2); + + int lastAppearanceLgrEquivFace = -1; + assert(elemLgr != lastLgrWhereMarkedFaceAppeared); + const auto candidateNeigh = findMatchingFaceIdx(*markedElem_to_itsLgr[lastLgrWhereMarkedFaceAppeared], + lastFaces, + *markedElem_to_itsLgr[elemLgr], + preAdaptFace); + assert(candidateNeigh.has_value()); + lastAppearanceLgrEquivFace = candidateNeigh.value(); + assert(lastAppearanceLgrEquivFace>=0); + refinedFace = elemLgrAndElemLgrFace_to_refinedLevelAndRefinedFace.at({lastLgrWhereMarkedFaceAppeared, lastAppearanceLgrEquivFace})[1]; aux_refined_cell_to_face.push_back({refinedFace, face.orientation()}); } @@ -1418,7 +1463,7 @@ void populateRefinedCells(const Dune::cpgrid::CpGridData& current_data, refinedFace = face_candidate->second[1]; aux_refined_cell_to_face.push_back({refinedFace, face.orientation()}); } - } // end-cell_to_face + } // end-cell_to_face // Refined cell to face. refined_cell_to_face_vec[shiftedLevel].appendRow(aux_refined_cell_to_face.begin(), aux_refined_cell_to_face.end()); // Get the cell geometry. @@ -1433,61 +1478,6 @@ void populateRefinedCells(const Dune::cpgrid::CpGridData& current_data, } // end-shiftedLevel-for-loop } -int replaceLgr1FaceIdxByLgr2FaceIdx(const std::array& cells_per_dim_lgr1, - int faceIdxInLgr1, - const std::shared_ptr& elemLgr1_ptr, - const std::array& cells_per_dim_lgr2) -{ - const auto& ijkLgr1 = getRefinedFaceIJK(cells_per_dim_lgr1, faceIdxInLgr1, elemLgr1_ptr); - // lgr1 represents an element index < lgr2 (neighboring cells sharing a face with lgr1-element) - // Order defined in Geometry::refine - // K_FACES (k*cells_per_dim[0]*cells_per_dim[1]) + (j*cells_per_dim[0]) + i - // I_FACES (cells_per_dim[0]*cells_per_dim[1]*(cells_per_dim[2]+1)) - // + (i*cells_per_dim[1]*cells_per_dim[2]) + (k*cells_per_dim[1]) + j - // J_FACES (cells_per_dim[0]*cells_per_dim[1]*(cells_per_dim[2] +1)) - // + ((cells_per_dim[0]+1)*cells_per_dim[1]*cells_per_dim[2]) - // + (j*cells_per_dim[0]*cells_per_dim[2]) + (i*cells_per_dim[2]) + k - const int& kFacesLgr2 = cells_per_dim_lgr2[0]*cells_per_dim_lgr2[1]*(cells_per_dim_lgr2[2]+1); - const int& iFacesLgr2 = ((cells_per_dim_lgr2[0]+1)*cells_per_dim_lgr2[1]*cells_per_dim_lgr2[2]); - - const auto& face_tag = elemLgr1_ptr-> faceTag(faceIdxInLgr1); - - if (face_tag == I_FACE) { - assert( cells_per_dim_lgr1[1] == cells_per_dim_lgr2[1]); - assert( cells_per_dim_lgr1[2] == cells_per_dim_lgr2[2]); - if (ijkLgr1[0] == cells_per_dim_lgr1[0]) { // same j,k, but i = 0 - return kFacesLgr2 + (ijkLgr1[2]*cells_per_dim_lgr2[1]) + ijkLgr1[1]; - } - else { // same j,k, but i = cells_per_dim[0] - return kFacesLgr2 + (cells_per_dim_lgr2[0]*cells_per_dim_lgr2[1]*cells_per_dim_lgr2[2]) - + (ijkLgr1[2]*cells_per_dim_lgr2[1]) + ijkLgr1[1]; - } - } - if (face_tag == J_FACE) { - assert( cells_per_dim_lgr1[0] == cells_per_dim_lgr2[0]); - assert( cells_per_dim_lgr1[2] == cells_per_dim_lgr2[2]); - if (ijkLgr1[1] == cells_per_dim_lgr1[1]) { // same i,k, but j = 0 - return kFacesLgr2 + iFacesLgr2 + (ijkLgr1[0]*cells_per_dim_lgr2[2]) + ijkLgr1[2]; - } - else { // same i,k, but j = cells_per_dim[1] - return kFacesLgr2 + iFacesLgr2 + (cells_per_dim_lgr2[1]*cells_per_dim_lgr2[0]*cells_per_dim_lgr2[2]) - + (ijkLgr1[0]*cells_per_dim_lgr2[2]) + ijkLgr1[2]; - } - } - if (face_tag == K_FACE) { - assert( cells_per_dim_lgr1[0] == cells_per_dim_lgr2[0]); - assert( cells_per_dim_lgr1[1] == cells_per_dim_lgr2[1]); - if (ijkLgr1[2] == cells_per_dim_lgr1[2]) { // same i,j, but k = 0 - return (ijkLgr1[1]*cells_per_dim_lgr2[0]) + ijkLgr1[0]; - } - else{ // same i, j, but k = cells_per_dim[2] - return (cells_per_dim_lgr2[2]*cells_per_dim_lgr2[0]*cells_per_dim_lgr2[1]) - + (ijkLgr1[1]*cells_per_dim_lgr2[0]) + ijkLgr1[0]; - } - } - OPM_THROW(std::logic_error, "Cannot convert face index from one LGR to its neighboring LGR."); -} - void populateLeafGridCorners(const Dune::cpgrid::CpGridData& current_data, Dune::cpgrid::EntityVariableBase>& adapted_corners, const int& corner_count, @@ -1570,7 +1560,8 @@ void populateLeafGridFaces(const Dune::cpgrid::CpGridData& current_data, else { #ifndef NDEBUG const auto& shiftedLevel = assignRefinedLevel[elemLgr] - preAdaptMaxLevel -1; // Assigned level > preAdapt maxLevel - bool isNewRefinedCornInInteriorLgr = isRefinedCornerInInteriorLgr(cells_per_dim_vec[shiftedLevel], elemLgrCorn); + bool isNewRefinedCornInInteriorLgr = isRefinedCornerInInteriorLgr(cells_per_dim_vec[shiftedLevel], + elemLgrCorn); assert(!isNewRefinedCornInInteriorLgr); #endif // To locate vanished corners, we need a while-loop, since {elemLgr, elemLgrcorner} leads to @@ -1611,11 +1602,9 @@ void populateLeafGridCells(const Dune::cpgrid::CpGridData& current_data, const std::map,int>& elemLgrAndElemLgrCorner_to_adaptedCorner, const std::map, std::array>& vanishedRefinedCorner_to_itsLastAppearance, const std::vector>& markedElem_to_itsLgr, - const std::vector& assignRefinedLevel, const std::map,int>& markedElemAndEquivRefinedCorn_to_corner, const std::vector>>& cornerInMarkedElemWithEquivRefinedCorner, - const std::vector>& cells_per_dim_vec, - const int& preAdaptMaxLevel) + const std::vector& cellRefinementsInfo) { // Store the adapted cells. Main difficulty: to lookup correctly the indices of the corners and faces of each cell. adapted_cells.resize(cell_count); @@ -1680,7 +1669,6 @@ void populateLeafGridCells(const Dune::cpgrid::CpGridData& current_data, } adapted_cell_to_point[cell][corn] = adaptedCorn; } // end-cell_to_point - // Cell to face. for (const auto& face : preAdapt_cell_to_face) { const auto& preAdaptFace = face.index(); @@ -1689,7 +1677,7 @@ void populateLeafGridCells(const Dune::cpgrid::CpGridData& current_data, const int adaptedFace = candidate->second; aux_cell_to_face.push_back({adaptedFace, face.orientation()}); } - else{ + else{ // Face might have vanished - Search its refined lgr-children faces in that case - // last lgr where the face appears if (elemLgr ==-1) { // Coarse face got replaced by its children - from the last appearance of the marked face. @@ -1701,17 +1689,22 @@ void populateLeafGridCells(const Dune::cpgrid::CpGridData& current_data, } } if (elemLgr>-1) { // Refined face vanished and its equivalent refined face from a neighboring lgr got stored. - // Get shifted level - const auto& shiftedLevel = assignRefinedLevel[elemLgr] - preAdaptMaxLevel -1; // Assigned level > preAdapt maxLevel // Get the index of the marked face where the refined face was born. - const auto& markedFace = getParentFaceWhereNewRefinedFaceLiesOn(current_data, - cells_per_dim_vec[shiftedLevel], - preAdaptFace, - markedElem_to_itsLgr[elemLgr], elemLgr); + const auto markedFace = getParentFaceWhereNewRefinedFaceLiesOn(preAdaptFace, + markedElem_to_itsLgr[elemLgr], + cellRefinementsInfo[elemLgr].boundaryRefinedFaceIdx_to_parentFaceIdx); + // Get the last LGR (marked element) where the marked face appeared. - const auto& lastLgrWhereMarkedFaceAppeared = faceInMarkedElemAndRefinedFaces[markedFace].back().first; - const auto& lastAppearanceLgrEquivFace = replaceLgr1FaceIdxByLgr2FaceIdx(cells_per_dim_vec[shiftedLevel], preAdaptFace, markedElem_to_itsLgr[elemLgr], - cells_per_dim_vec[assignRefinedLevel[lastLgrWhereMarkedFaceAppeared] - preAdaptMaxLevel -1]); + const auto& [lastLgrWhereMarkedFaceAppeared, lastFaces] = faceInMarkedElemAndRefinedFaces[markedFace].back(); + int lastAppearanceLgrEquivFace = -1; + const auto candidateNeigh = findMatchingFaceIdx( *markedElem_to_itsLgr[lastLgrWhereMarkedFaceAppeared], + lastFaces, + *markedElem_to_itsLgr[elemLgr], + preAdaptFace); + assert(candidateNeigh.has_value()); + lastAppearanceLgrEquivFace = candidateNeigh.value(); + assert(lastAppearanceLgrEquivFace>=0); + const int adaptedFace = elemLgrAndElemLgrFace_to_adaptedFace.at({lastLgrWhereMarkedFaceAppeared, lastAppearanceLgrEquivFace}); aux_cell_to_face.push_back({adaptedFace, face.orientation()}); } @@ -2304,5 +2297,7 @@ void filterMarkedAquiferCellsAndConnections(Dune::CpGrid& grid, } } + + } // namespace Lgr } // namespace Opm diff --git a/opm/grid/cpgrid/LgrHelpers.hpp b/opm/grid/cpgrid/LgrHelpers.hpp index de86a87b1..1fd74722e 100644 --- a/opm/grid/cpgrid/LgrHelpers.hpp +++ b/opm/grid/cpgrid/LgrHelpers.hpp @@ -20,14 +20,24 @@ #ifndef OPM_GRID_CPGRID_LGRHELPERS_HEADER_INCLUDED #define OPM_GRID_CPGRID_LGRHELPERS_HEADER_INCLUDED -#include + +#include +#include +#include #include +#include + #include +#include +#include + #include +#include #include #include +#include #include #include #include @@ -39,6 +49,7 @@ namespace Dune namespace cpgrid { class CpGridData; +class DefaultGeometryPolicy; } } @@ -49,6 +60,12 @@ template class LevelCartesianIndexMapper; namespace Lgr { + +struct CellRefinementBoundaryInfo; +struct GridModificationMapping; + + + /// --------------- Auxiliary methods to support refinement --------------- /// @brief Refines all marked elements and establishes mappings between @@ -103,7 +120,9 @@ void refineAndProvideMarkedRefinedRelations(const Dune::CpGrid& grid,/* Marked e int& cell_count, std::vector>& preAdapt_level_to_leaf_cells_vec, /* Additional parameters */ - const std::vector>& cells_per_dim_vec); + const std::vector>& cells_per_dim_vec, + std::vector& cellRefinementsInfo, + bool& withoutFaults); /// @brief Establish child–parent relations for refined cells: /// - Maps each refined cell (in new refined grids) to its parent cell in the pre-adapt grid(s). @@ -193,14 +212,17 @@ void identifyRefinedCornersPerLevel(const Dune::cpgrid::CpGridData& current_data const std::vector& assignRefinedLevel, const std::vector>>& cornerInMarkedElemWithEquivRefinedCorner, const std::vector>>>& faceInMarkedElemAndRefinedFaces, - const std::vector>& cells_per_dim_vec); + const std::vector>& cells_per_dim_vec, + const std::vector& cellRefinementsInfo, + bool withoutFaults); /// @brief Check if a refined corner lies in the interior of a single-cell refinement. /// /// @param [in] cells_per_dim Number of child cells in {x, y, z} directions. /// @param [in] cornerIdxInLgr Corner index within the single-cell refinement. /// @return true if the corner is interior, false otherwise. -bool isRefinedCornerInInteriorLgr(const std::array& cells_per_dim, int cornerIdxInLgr); +bool isRefinedCornerInInteriorLgr(const std::array& cells_per_dim, + int cornerIdxInLgr); /// @brief Compute the {i,j,k} index of a refined corner from its linear index /// in a single-cell refinement. @@ -216,34 +238,6 @@ bool isRefinedCornerInInteriorLgr(const std::array& cells_per_dim, int co /// @return {i,j,k} index of the corner. std::array getRefinedCornerIJK(const std::array& cells_per_dim, int cornerIdxInLgr); -/// @brief Check if a refined corner lies on a parent-cell edge. -/// Specifically, on the boundary of the single-cell refinement, -/// but not coinciding with a pre-adapt corner. -/// -/// @param [in] cells_per_dim Number of child cells in {x,y,z} directions. -/// @param [in] cornerIdxInLgr Corner index in the single-cell refinement. -/// @return true if the corner is on an edge, false otherwise. -bool newRefinedCornerLiesOnEdge(const std::array& cells_per_dim, int cornerIdxInLgr); - -/// @brief Get the parent faces that contain the edge on which a new refined corner lies. -/// -/// @param [in] cells_per_dim Number of child cells in {x,y,z} directions. -/// @param [in] cornerIdxInLgr Corner index in the single-cell refinement. -/// @param [in] elemLgr Parent cell index (from the original grid) refined into a single-cell refinement. -/// @return Indices of the two parent faces sharing the edge. -std::array getParentFacesAssocWithNewRefinedCornLyingOnEdge(const Dune::cpgrid::CpGridData& current_data, - const std::array& cells_per_dim, - int cornerIdxInLgr, - int elemLgr); - -/// @brief Check if a refined corner lies on the boundary of the single-cell refinement -/// and is not a pre-adapt (original) corner. -/// -/// @param [in] cells_per_dim Number of child cells in {x,y,z} directions. -/// @param [in] cornerIdxInLgr Corner index in the single-cell refinement. -/// @return true if the corner is on the boundary and new, false otherwise. -bool isRefinedNewBornCornerOnLgrBoundary(const std::array& cells_per_dim, int cornerIdxInLgr); - // @brief Get the parent face containing the new refined corner. /// /// @param [in] cells_per_dim Number of child cells in {x, y, z} directions. @@ -253,36 +247,8 @@ bool isRefinedNewBornCornerOnLgrBoundary(const std::array& cells_per_dim, int getParentFaceWhereNewRefinedCornerLiesOn(const Dune::cpgrid::CpGridData& current_data, const std::array& cells_per_dim, int cornerIdxInLgr, - int elemLgr); - -/// @brief Map a refined corner from one single-cell refinement to a neighboring refinement. -/// -/// Given a corner index in the first single-cell refinement, compute the corresponding corner index -/// in the second single-cell refinement. -/// -/// @param [in] cells_per_dim_lgr1 Number of child cells in {x,y,z} directions for the first refinement. -/// @param [in] cornerIdxLgr1 Corner index in the first single-cell refinement. -/// @param [in] cells_per_dim_lgr2 Number of child cells in {x,y,z} directions for the second refinement. -/// @return Corresponding corner index in the second single-cell refinement. -int replaceLgr1CornerIdxByLgr2CornerIdx(const std::array& cells_per_dim_lgr1, - int cornerIdxLgr1, - const std::array& cells_per_dim_lgr2); - -/// @brief Map a new refined corner on an edge from one single-cell refinement to a neighboring refinement. -/// -/// Given a corner index in one refinement, compute its index in a neighboring refinement. The corner -/// lies on an edge and may appear in multiple refinements. -/// -/// @param [in] cells_per_dim_lgr1 Number of child cells in {x,y,z} directions for the first refinement. -/// @param [in] cornerIdxLgr1 Corner index in the first single-cell refinement. -/// @param [in] elemLgr1 Parent cell index of the first refinement. -/// @param [in] parentFaceLastAppearanceIdx Parent face index where the corner appears last. -/// @param [in] cells_per_dim_lgr2 Number of child cells in {x,y,z} directions for the second refinement. -/// @return Corresponding corner index in the second single-cell refinement. -int replaceLgr1CornerIdxByLgr2CornerIdx(const Dune::cpgrid::CpGridData& current_data, - const std::array& cells_per_dim_lgr1, - int cornerIdxLgr1, int elemLgr1, int parentFaceLastAppearanceIdx, - const std::array& cells_per_dim_lgr2); + int elemLgr, + const std::unordered_map& extraRefCornIdx_to_parentFaceIdx); /// @brief Identify corners on the leaf (adapted) grid and establish corner mappings. /// @@ -310,42 +276,86 @@ void identifyLeafGridCorners(const Dune::cpgrid::CpGridData& current_data, const std::vector>>& cornerInMarkedElemWithEquivRefinedCorner, std::map, std::array>& vanishedRefinedCorner_to_itsLastAppearance, const std::vector>>>& faceInMarkedElemAndRefinedFaces, - const std::vector>& cells_per_dim_vec); + const std::vector>& cells_per_dim_vec, + const std::vector& cellRefinementsInfo, + bool withoutFaults); void markVanishedCorner(const std::array& vanished, - const std::array& lastAppearance, + const std::array& lastAppearance, std::map, std::array>& vanishedRefinedCorner_to_itsLastAppearance); -void processInteriorCorners(int elemIdx, int shiftedLevel, - const std::shared_ptr& lgr, - int& corner_count, - std::map,int>& elemLgrAndElemLgrCorner_to_adaptedCorner, - std::unordered_map>& adaptedCorner_to_elemLgrAndElemLgrCorner, - const std::vector>& cells_per_dim_vec); - -void processEdgeCorners(int elemIdx, int shiftedLevel, - const std::shared_ptr& lgr, - int& corner_count, - std::map,int>& elemLgrAndElemLgrCorner_to_adaptedCorner, - std::unordered_map>& adaptedCorner_to_elemLgrAndElemLgrCorner, - std::map, std::array>& vanishedRefinedCorner_to_itsLastAppearance, - const Dune::cpgrid::CpGridData& current_data, - int preAdaptMaxLevel, - const std::vector& assignRefinedLevel, - const std::vector>>>& faceInMarkedElemAndRefinedFaces, - const std::vector>& cells_per_dim_vec); - -void processBoundaryCorners(int elemIdx, int shiftedLevel, +void processLevelInteriorCorners(int parentCellIdx, + int level, + const std::shared_ptr& singleCellRefinement, + int& level_corner_count, + std::map,std::array>& elemLgrAndElemLgrCorner_to_refinedLevelAndRefinedCorner, + std::map,std::array>& refinedLevelAndRefinedCorner_to_elemLgrAndElemLgrCorner, + const std::array& level_cells_per_dim, + std::vector>& visited); + +void processLeafInteriorCorners(int elemIdx, + int shiftedLevel, + const std::shared_ptr& lgr, + int& corner_count, + std::map,int>& elemLgrAndElemLgrCorner_to_adaptedCorner, + std::unordered_map>& adaptedCorner_to_elemLgrAndElemLgrCorner, + const std::vector>& cells_per_dim_vec, + std::vector>& visited); + +void processLevelEdgeCorners(int elemIdx, + int level, + const std::shared_ptr& lgr, + int& level_corner_count, + std::map,std::array>& elemLgrAndElemLgrCorner_to_refinedLevelAndRefinedCorner, + std::map,std::array>& refinedLevelAndRefinedCorner_to_elemLgrAndElemLgrCorner, + std::map, std::array>& vanishedRefinedCorner_to_itsLastAppearance, + const Dune::cpgrid::CpGridData& current_data, + const std::vector& assignRefinedLevel, + const std::vector>>>& faceInMarkedElemAndRefinedFaces, + const std::vector& coincideWithCoarseCorner, + const std::vector>& markedElem_to_itsLgr); + +void processLeafEdgeCorners(int elemIdx, const std::shared_ptr& lgr, int& corner_count, std::map,int>& elemLgrAndElemLgrCorner_to_adaptedCorner, std::unordered_map>& adaptedCorner_to_elemLgrAndElemLgrCorner, std::map, std::array>& vanishedRefinedCorner_to_itsLastAppearance, const Dune::cpgrid::CpGridData& current_data, - int preAdaptMaxLevel, const std::vector& assignRefinedLevel, const std::vector>>>& faceInMarkedElemAndRefinedFaces, - const std::vector>& cells_per_dim_vec); + const std::vector& coincideWithCoarseCorner, + const std::vector>& markedElem_to_itsLgr); + + +void processLevelBoundaryCorners(int elemIdx, + int level, + int shiftedLevel, + const std::shared_ptr& lgr, + int& level_corner_count, + std::map,std::array>& elemLgrAndElemLgrCorner_to_refinedLevelAndRefinedCorner, + std::map,std::array>& refinedLevelAndRefinedCorner_to_elemLgrAndElemLgrCorner, + std::map, std::array>& vanishedRefinedCorner_to_itsLastAppearance, + const Dune::cpgrid::CpGridData& current_data, + const std::vector& assignRefinedLevel, + const std::vector>>>& faceInMarkedElemAndRefinedFaces, + const std::vector>& cells_per_dim_vec, + const std::unordered_map& boundaryRefinedVertex_to_parentFace, + const std::vector& boundaryRefinedVertexCoincidesWithParentVertex, + const std::vector>& markedElem_to_itsLgr); + +void processLeafBoundaryCorners(int elemIdx, int shiftedLevel, + const std::shared_ptr& lgr, + int& corner_count, + std::map,int>& elemLgrAndElemLgrCorner_to_adaptedCorner, + std::unordered_map>& adaptedCorner_to_elemLgrAndElemLgrCorner, + std::map, std::array>& vanishedRefinedCorner_to_itsLastAppearance, + const Dune::cpgrid::CpGridData& current_data, + const std::vector>>>& faceInMarkedElemAndRefinedFaces, + const std::vector>& cells_per_dim_vec, + const std::unordered_map& boundaryRefinedVertex_to_parentFace, + const std::vector& boundaryRefinedVertexCoincidesWithParentVertex, + const std::vector>& markedElem_to_itsLgr); // To insert bidirectional mapping and increment counter // keyB is equal to counter, before it gets increased by one. @@ -379,10 +389,10 @@ void insertBidirectional(std::map,std::array>& a_to_b, /// @param [out] refinedLevelAndRefinedFace_to_elemLgrAndElemLgrFace /// Inverse mapping: (refined level grid, refined face idx)->(marked element idx, marked-element-refined face idx). /// @param [out] refined_face_count_vec Number of refined faces per refined level grid. -/// @param [in] markedElem_to_itsLgr -/// @param [in] assignRefinedLevel -/// @param [in] faceInMarkedElemAndRefinedFaces -/// @param [in] cells_per_dim_vec +/// @param [in] markedElem_to_itsLgr +/// @param [in] assignRefinedLevel +/// @param [in] faceInMarkedElemAndRefinedFaces +/// @param [in] singleCellRef_refinedFace_to_parentFace void identifyRefinedFacesPerLevel(const Dune::cpgrid::CpGridData& current_data, int preAdaptMaxLevel, std::map,std::array>& elemLgrAndElemLgrFace_to_refinedLevelAndRefinedFace, @@ -391,7 +401,7 @@ void identifyRefinedFacesPerLevel(const Dune::cpgrid::CpGridData& current_data, const std::vector>& markedElem_to_itsLgr, const std::vector& assignRefinedLevel, const std::vector>>>& faceInMarkedElemAndRefinedFaces, - const std::vector>& cells_per_dim_vec); + const std::vector& cellRefinements); /// @brief Identify faces on the leaf (adapted) grid and establish face mappings. /// @@ -403,67 +413,35 @@ void identifyRefinedFacesPerLevel(const Dune::cpgrid::CpGridData& current_data, /// @param [out] adaptedFace_to_elemLgrAndElemLgrFace /// Inverse mapping: leaf grid face -> (marked element idx, marked-element-refined face idx) or {-1, original face idx}. /// @param [out] face_count Total number of faces in the leaf (adapted) grid. -/// @param [in] markedElem_to_itsLgr -/// @param [in] assignRefinedLevel -/// @param [in] faceInMarkedElemAndRefinedFaces -/// @param [in] cells_per_dim_vec +/// @param [in] markedElem_to_itsLgr +/// @param [in] assignRefinedLevel +/// @param [in] faceInMarkedElemAndRefinedFaces +/// @param [in] singleCellRef_refinedFace_to_parentFace void identifyLeafGridFaces(const Dune::cpgrid::CpGridData& current_data, - int preAdaptMaxLevel, std::map,int>& elemLgrAndElemLgrFace_to_adaptedFace, std::unordered_map>& adaptedFace_to_elemLgrAndElemLgrFace, int& face_count, const std::vector>& markedElem_to_itsLgr, const std::vector& assignRefinedLevel, const std::vector>>>& faceInMarkedElemAndRefinedFaces, - const std::vector>& cells_per_dim_vec); - -/// @brief Compute the {i,j,k} index of a refined face from its linear index in a single-cell refinement. -/// -/// A single cell refined into {nx, ny, nz} children has -/// ((nx+1)*ny*nz) + (nx*(ny+1)*nz) + (nx*ny*(nz+1)) faces, stored in the order defined by Geometry::refine: -/// - K_FACES: (k*nx*ny) + (j*nx) + i -/// - I_FACES: (nx*ny*(nz+1)) + (i*ny*nz) + (k*ny) + j -/// - J_FACES: (nx*ny*(nz+1)) + ((nx+1)*ny*nz) + (j*nx*nz) + (i*nz) + k -/// where i=0..nx-1, j=0..ny-1, k=0..nz-1. -/// This function converts faceIdxInLgr to its {i,j,k} index. -/// -/// @param [in] cells_per_dim Number of child cells in {x,y,z} directions. -/// @param [in] faceIdxInLgr Face index in the single-cell refinement. -/// @param [in] elemLgr_ptr Pointer to the single-cell refinement grid. -/// @return {i,j,k} index of the face -std::array getRefinedFaceIJK(const std::array& cells_per_dim, int faceIdxInLgr, - const std::shared_ptr& elemLgr_ptr); - -/// @brief Check if a refined face lies in the interior of a single-cell refinement. -/// -/// @param [in] cells_per_dim Number of child cells in {x,y,z} directions. -/// @param [in] faceIdxInLgr Face index in the single-cell refinement. -/// @param [in] elemLgr_ptr Pointer to the single-cell refinement grid. -/// @return true if the face is interior, false otherwise. -bool isRefinedFaceInInteriorLgr(const std::array& cells_per_dim, int faceIdxInLgr, - const std::shared_ptr& elemLgr_ptr); + const std::vector& cellRefinementsInfo); /// @brief Check if a refined face lies on the boundary of a single-cell refinement. /// -/// @param [in] cells_per_dim Number of child cells in {x,y,z} directions. /// @param [in] faceIdxInLgr Face index in the single-cell refinement. /// @param [in] elemLgr_ptr Pointer to the single-cell refinement grid. /// @return true if the face is on the boundary, false otherwise. -bool isRefinedFaceOnLgrBoundary(const std::array& cells_per_dim, int faceIdxInLgr, +bool isRefinedFaceOnLgrBoundary(int faceIdxInLgr, const std::shared_ptr& elemLgr_ptr); /// @brief Get the parent face containing a new refined face. /// -/// @param [in] cells_per_dim Number of child cells in {x,y,z} directions. /// @param [in] faceIdxInLgr Face index in the single-cell refinement. /// @param [in] elemLgr_ptr Pointer to the single-cell refinement grid. -/// @param [in] elemLgr Parent cell index from the original grid. /// @return Index of the parent face containing the refined face. -int getParentFaceWhereNewRefinedFaceLiesOn(const Dune::cpgrid::CpGridData& current_data, - const std::array& cells_per_dim, - int faceIdxInLgr, +int getParentFaceWhereNewRefinedFaceLiesOn(int faceIdxInLgr, const std::shared_ptr& elemLgr_ptr, - int elemLgr); + const std::vector& refinedFace_to_parentFace); /// @brief Define the corners (geometry) for each refined level grid. void populateRefinedCorners(std::vector>>& refined_corners_vec, @@ -502,25 +480,10 @@ void populateRefinedCells(const Dune::cpgrid::CpGridData& current_data, const std::map,std::array>& elemLgrAndElemLgrCorner_to_refinedLevelAndRefinedCorner, const std::map, std::array>& vanishedRefinedCorner_to_itsLastAppearance, const std::vector>& markedElem_to_itsLgr, - const std::vector& assignRefinedLevel, const int& preAdaptMaxLevel, const std::map,int>& markedElemAndEquivRefinedCorn_to_corner, const std::vector>>& cornerInMarkedElemWithEquivRefinedCorner, - const std::vector>& cells_per_dim_vec); - -/// @brief Map a refined boundary face from one single-cell refinement to a neighboring refinement. -/// -/// A refined face on the boundary may appear in up to two single-cell refinements. Given its index -/// in the first refinement, this function computes the corresponding face index in the neighboring refinement. -/// -/// @param [in] cells_per_dim_lgr1 Number of child cells in {x,y,z} directions for the first refinement. -/// @param [in] faceIdxInLgr1 Face index in the first single-cell refinement. -/// @param [in] elemLgr1_ptr Pointer to the first single-cell refinement grid. -/// @param [in] cells_per_dim_lgr2 Number of child cells in {x,y,z} directions for the second refinement. -/// @return Corresponding face index in the second single-cell refinement. -int replaceLgr1FaceIdxByLgr2FaceIdx(const std::array& cells_per_dim_lgr1, int faceIdxInLgr1, - const std::shared_ptr& elemLgr1_ptr, - const std::array& cells_per_dim_lgr2); + const std::vector& cellRefinementsInfo); /// @brief Define the corners (gemotry) for the leaf grid view (or adapted grid). void populateLeafGridCorners(const Dune::cpgrid::CpGridData& current_data, @@ -560,11 +523,9 @@ void populateLeafGridCells(const Dune::cpgrid::CpGridData& current_data, const std::map,int>& elemLgrAndElemLgrCorner_to_adaptedCorner, const std::map, std::array>& vanishedRefinedCorner_to_itsLastAppearance, const std::vector>& markedElem_to_itsLgr, - const std::vector& assignRefinedLevel, const std::map,int>& markedElemAndEquivRefinedCorn_to_corner, const std::vector>>& cornerInMarkedElemWithEquivRefinedCorner, - const std::vector>& cells_per_dim_vec, - const int& preAdaptMaxLevel); + const std::vector& cellRefinementsInfo); /// @brief Auxilliary function to compute one or more properties on selected block of parent cells. /// diff --git a/tests/cpgrid/lgr/compute_new_vertices_of_overlapping_intersections_test.cpp b/tests/cpgrid/lgr/compute_new_vertices_of_overlapping_intersections_test.cpp new file mode 100644 index 000000000..1c360c34f --- /dev/null +++ b/tests/cpgrid/lgr/compute_new_vertices_of_overlapping_intersections_test.cpp @@ -0,0 +1,1679 @@ +/* + Copyright 2026 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 . +*/ +#include "config.h" + +#define BOOST_TEST_MODULE ParentCellWithMoreThanOneFacePerTypeTests +#include + +#include + +#include +#include +#include +#include + +#include + + +#include + +struct Fixture +{ + Fixture() + { + int m_argc = boost::unit_test::framework::master_test_suite().argc; + char** m_argv = boost::unit_test::framework::master_test_suite().argv; + Dune::MPIHelper::instance(m_argc, m_argv); + Opm::OpmLog::setupSimpleDefaultLogging(); + } +}; + +BOOST_GLOBAL_FIXTURE(Fixture); + +using Coordinate = Dune::FieldVector; + + +void checkFaceCountPerType(int repeatedFaceType, + int expectedRepeatedFaceTypeCount, + const std::array,6>& classifiedFaces) +{ + for (int faceType = 0; faceType < 6; ++faceType) { + int expectedFaceTypeCount = (faceType == repeatedFaceType) ? expectedRepeatedFaceTypeCount : 1; + BOOST_CHECK_EQUAL( classifiedFaces[faceType].size(), expectedFaceTypeCount); + } +} + +// The test cases consist in a grid with only 2 cells in level zero. +// Only one of them gets refined, the other appears on the leaf with +// same volume and center, but more faces. +void checkFaceCountInLeafCoarseElem(const Dune::CpGrid& grid, + int expectedTotalFaceCount, + int repeatedFaceType, + int expectedRepeatedFaceTypeCount) +{ + for (const auto& element : Dune::elements(grid.leafGridView())) { + if (element.level() == 0) { + + const auto& cellToFace = grid.currentLeafData().cellToFace(element.index()); + BOOST_CHECK_EQUAL( cellToFace.size(), expectedTotalFaceCount); + + const auto classifiedFaces = Opm::Lgr::groupFaceIndicesByType(grid.currentLeafData(), + element); + + checkFaceCountPerType(repeatedFaceType, + expectedRepeatedFaceTypeCount, + classifiedFaces); + } + } +} + +void checkFaceToCoord(const Dune::cpgrid::CpGridData& refinedGridData, + const std::vector& selectedFaces, + const std::set& expectedFaceToCoord1, + const std::set& expectedFaceToCoord2) +{ + + for (const auto& faceIdx : selectedFaces) { + + const auto& faceToPoint = refinedGridData.faceToPoint(faceIdx); + std::set faceToCoord{}; + for (const auto& point : faceToPoint) { + const auto pointEntity = Dune::cpgrid::Entity<3>(refinedGridData, point, true); + faceToCoord.insert(pointEntity.geometry().center()); + } + BOOST_CHECK( (faceToCoord == expectedFaceToCoord1) || (faceToCoord == expectedFaceToCoord2) ); + } +} + +void checkNewRefinedFaces(const Dune::CpGrid& grid, + const Dune::cpgrid::CpGridData& refinedGridData, + const std::vector>>& selectedFaceToCoord, + int repeatedFaceType) +{ + + for (const auto& refinedElem : Dune::elements(grid.levelGridView(1))) { + + const auto& cellToFace = refinedGridData.cellToFace(refinedElem.index()); + const auto classifiedFaces = Opm::Lgr::groupFaceIndicesByType(refinedGridData, refinedElem); + + if (selectedFaceToCoord[refinedElem.index()].size() == 2) { + + BOOST_CHECK_EQUAL( cellToFace.size(), 7); + + checkFaceCountPerType(repeatedFaceType, + /* expectedRepeatedFaceTypeCount = */ 2, + classifiedFaces); + + checkFaceToCoord(refinedGridData, + classifiedFaces[repeatedFaceType], + selectedFaceToCoord[refinedElem.index()][0], + selectedFaceToCoord[refinedElem.index()][1]); + + } + else if (selectedFaceToCoord[refinedElem.index()].size() == 1){ + + BOOST_CHECK_EQUAL( cellToFace.size(), 6); + + checkFaceCountPerType(/* repeatedFaceType = */ -1, // invalid face type + /* expectedRepeatedFaceTypeCount = */ 0, + classifiedFaces); + + checkFaceToCoord(refinedGridData, + classifiedFaces[repeatedFaceType], + selectedFaceToCoord[refinedElem.index()][0], + selectedFaceToCoord[refinedElem.index()][0]); // same, here there is no repeaetd face + } + else { + BOOST_CHECK(selectedFaceToCoord[refinedElem.index()].empty()); + BOOST_CHECK_EQUAL( cellToFace.size(), 6); + + checkFaceCountPerType(/* repeatedFaceType = */ -1, // invalid face type + /* expectedRepeatedFaceTypeCount = */ 0, + classifiedFaces); + } + } +} + +void expectedCellCountRespectToCellToFaceSize(const Dune::CpGrid& grid, + const std::vector& expectedCount7Faces) +{ + for (int level = 0; level <= grid.maxLevel(); ++level) { + int count_7faces_level = 0; + int count_6faces_level = 0; + for (const auto& element : Dune::elements(grid.levelGridView(level))) { + int count = grid.currentData()[level]->cellToFace(element.index()).size(); + if (count == 7) { + ++count_7faces_level; + } + else { + BOOST_CHECK_EQUAL(count, 6); + ++count_6faces_level; + } + } + BOOST_CHECK_EQUAL(count_7faces_level, expectedCount7Faces[level]); + BOOST_CHECK_EQUAL(count_6faces_level, grid.levelGridView(level).size(0) - count_7faces_level); + } +} + +void checkLevelVertices(const Dune::CpGrid& grid, + const std::vector>& expectedLgrVertices) +{ + for (int level = 1; level <= grid.maxLevel(); ++level) { + std::set levelVertices{}; + for (const auto& vertex : Dune::vertices(grid.levelGridView(level))) { + levelVertices.insert(vertex.geometry().center()); + } + + // Note: FieldVectorLess determines where each element lives in the ordered tree (from the set). + // The insertion order is discarded once the element is placed. + // Both sets use the same FieldVectorLess comparator. + // Check they have the same size + BOOST_REQUIRE_EQUAL( expectedLgrVertices[level-1].size(), levelVertices.size()); + + auto expected = expectedLgrVertices[level-1].begin(); + auto actual = levelVertices.begin(); + // Check every element is the same + for (; expected != expectedLgrVertices[level-1].end(); ++expected, ++actual) { + BOOST_CHECK_EQUAL_COLLECTIONS(expected->begin(), expected->end(), + actual->begin(), actual->end()); + } + } +} + + +void checkLeafVertices(const Dune::CpGrid& grid, + const std::set& expectedVertices) +{ + std::set leafVertices{}; + for (const auto& vertex : Dune::vertices(grid.leafGridView())) { + leafVertices.insert(vertex.geometry().center()); + } + BOOST_REQUIRE_EQUAL( expectedVertices.size(), leafVertices.size()); + + auto expected = expectedVertices.begin(); + auto actual = leafVertices.begin(); + + for (; expected != expectedVertices.end(); ++expected, ++actual) { + BOOST_CHECK_EQUAL_COLLECTIONS(expected->begin(), expected->end(), + actual->begin(), actual->end()); + } +} + +bool equalFaces(const std::vector>>& actual, + const std::vector>>& expected) +{ + if (actual.size() != expected.size()) + return false; + + for (std::size_t i = 0; i < actual.size(); ++i) { + if (actual[i].size() != expected[i].size()) + return false; + + auto aIt = actual[i].begin(); + auto eIt = expected[i].begin(); + + while (aIt != actual[i].end()) { + for (int d = 0; d < 3; ++d) // coordinate by coordinate + if ((*aIt)[d] != (*eIt)[d]) + return false; + + ++aIt; + ++eIt; + } + } + + return true; +} + +void checkFaces(const Dune::cpgrid::CpGridData& gridData, + const std::vector>& expectedFaces) +{ + std::vector>> actualFaces{}; + actualFaces.resize(gridData.numFaces()); + + for (int i = 0; i < gridData.numFaces(); ++i) { + for (const auto& vertexIdx : gridData.faceToPoint(i)){ + actualFaces[i].push_back(Dune::cpgrid::Entity<3>(gridData, vertexIdx, true).geometry().center()); + } + } + + BOOST_CHECK(equalFaces(actualFaces, expectedFaces)); +} + + +BOOST_AUTO_TEST_CASE(parentCellWithMoreThanOne_I_FACE_trueOriented_nonTrivialOverlap) +{ + // Level zero grid dims = 2x1x1 + // + // cell 0 + // bottom face corners (0,0,0), (6,0,0), (0,6,0), (6,6,0) + // top face corners (0,0,8), (6,0,8), (0,6,8), (6,6,8) + // + // cell 1 + // bottom face corners (6,0,1), (12,0,1), (6,6,1), (12,6,1) + // top face corners (6,0,9), (12,0,9), (12,6,9), (12,6,9) + const std::string deckString = + R"(RUNSPEC +DIMENS + 2 1 1 / + +GRID + +COORD + 0 0 0 0 0 9 + 6 0 0 6 0 9 +12 0 0 12 0 9 + + 0 6 0 0 6 9 + 6 6 0 6 6 9 +12 6 0 12 6 9 +/ + +ZCORN +0 0 1 1 0 0 1 1 +8 8 9 9 8 8 9 9 +/ + +ACTNUM +2*1 +/ + +PORO +2*0.15 +/ +)"; + + Dune::CpGrid grid; + Opm::createGridAndAddLgrs(grid, + deckString, + /* cells_per_dim_vec */ {{2,3,2}}, + /* startIJK_vec */ {{0,0,0}}, + /* endIJK_vec */ {{1,1,1}}, + /* lgr_name_vec */ {"LGR1"}); + + // LGR1 dimensions = {2,3,2} + // LGR1 indices + // + // k = 1 |10 11| + // | 8 9| + // | 6 7| + // ---------- + // k = 0 | 4 5| + // | 2 3| + // | 0 1| + // ---------- + + // Element 0 in level zero grid has two faces of type {I_FACE, true} + // + // Vertices of those faces lie on the plane x = 6 | After refinement, number of subdivisions in LGR1 cell indices + // | y- and z- directions: + // (6,0,8) ---------------- (6,6,8) | (6,0,8) --(6,2,8)-(6,4,8)--(6,6,8) x-----x-----x-----x + // | | | | * * | | * * | + // | | | | * * | | 7 * 9 * 11 | + // | | | | * * | | * * | + // | face idx 2 | | | * * | | * * | + // | | | (6,0,4) **(6,2,4)*(6,4,4)**(6,6,4) x*****x*****x*****x + // | | | | * * | | * * | + // | | | | * * | | * * | + // (6,0,1) -----------------(6,6,1) | (6,0,1) --(?,?,?)-(?,?,?)--(6,6,1) x- 1 -x- 3 -x- 5 -x + // | face idx 1 | | | * * | | * * | + // (6,0,0) -----------------(6,6,0) | (6,0,0) --(6,2,0)-(6,4,0)--(6,6,0) x-----x-----x-----x + // | + // | The missing vertices are (6,2,1) and (6,4,1), appering in elements 1,3, or 5 in LGR1. + // | In LGR1 element 1: (6,2,1) + // | In LGR1 element 3: (6,2,1) and (6,4,1) + // | In LGR1 element 5: (6,4,1) + + const auto& refinedGridData = *grid.currentData()[1]; + const auto& parentGridData = *grid.currentData()[0]; + const auto parentElem = Dune::cpgrid::Entity<0>(parentGridData, 0, true); + + BOOST_CHECK_EQUAL(parentGridData.cellToFace(parentElem.index()).size(), 7); + + BOOST_CHECK_EQUAL( refinedGridData.size(3), 40); + // LGR1 dims 2x3x2 -> 3x4x3 vertices + 4 extra missing vertices (6,0,1), (6,2,1), (6,4,1), and (6,6,1). + BOOST_CHECK_EQUAL( refinedGridData.numFaces(), 55); + // LGR1 dims 2x3x2 -> 52 faces (before correction due to missing points) + // 3 of those 52 faces vanished and give origin to 6 new faces: 52 - 3 + 6 = 55 faces + + const auto& leafGridData = grid.currentLeafData(); + BOOST_CHECK_EQUAL( leafGridData.size(3), 46); // 46 = 40 + 6 (40 in level 1 + 6 vertices from cell_to_point_ from coarse element) + BOOST_CHECK_EQUAL( leafGridData.numFaces(), 61); // 61 = 55 + 6 (55 in level 1 + 6 other faces from coarse element) + + // Originally, the element not involved in refinement + // had 7 faces. It's neihgbor in level zero + // got refined and the I_FACE that they shared has been + // replaced by 6 refined faces. Then, the leaf element has + // one of each I+,J-,J+, K-, K+, and 1 coarse + 6 refined I-. + checkFaceCountInLeafCoarseElem(grid, + /* expectedTotalFaceCount = */ 12, + /* repeatedFaceType = */ 0, // 0->I- + /* expectedRepeatedFaceTypeCount = */ 7); + + expectedCellCountRespectToCellToFaceSize(grid, + /* expectedCount7Faces = */ std::vector{2, 3, 3}); // level 0, level 1, leaf grid + + // Collect the expected data to later on check + std::vector>> selectedFaceToCoord{}; + selectedFaceToCoord.resize(grid.levelGridView(1).size(0)); + + for (const auto& refinedElem : Dune::elements(grid.levelGridView(1))) { + + std::set expectedNewFaceInFace2{}; // {vertex '0', vertex '1', vertex '2', vertex '3'} + std::set expectedNewFaceInFace1{}; + // Vertex order in I_FACE: 0->jk, 1-> (j+1)k, 2->(j+1)(k+1), 3->j(k+1) + // + // j(k+1) <-'3' --------- '2'-> (j+1)(k+1) + // | | + // | | + // jk <-'0' --------- '1'-> (j+1)k + + if (refinedElem.index() == 1){ + // this element has to have 7 faces: 1 I-,J-,J+,K-,K+, and 2 I+: + // (6,0,4) **(6,2,4) + // | * I_FACE, true with vertices (6,0,1),(6,2,1),(6,2,4),(6,0,4) + // | * + // (6,0,1) --(6,2,1) + // | * I_FACE, true with vertices (6,0,0),(6,2,0),(6,2,1),(6,0,1) + // (6,0,0) --(6,2,0) + expectedNewFaceInFace2 = {{6,0,1}, {6,2,1}, {6,2,4}, {6,0,4}}; + expectedNewFaceInFace1 = {{6,0,0}, {6,2,0}, {6,2,1}, {6,0,1}}; + + selectedFaceToCoord[1].push_back(expectedNewFaceInFace2); + selectedFaceToCoord[1].push_back(expectedNewFaceInFace1); + } + else if (refinedElem.index() == 3){ + // this element has to have 7 faces: 1 I-,J-,J+,K-,K+, and 2 I+: + // (6,2,4) **(6,4,4) + // | * I_FACE, true with vertices (6,2,1),(6,4,1),(6,4,4),(6,2,4) + // | * + // (6,2,1) --(6,4,1) + // | * I_FACE, true with vertices (6,2,0),(6,4,0),(6,4,1),(6,2,4) + // (6,2,0) --(6,4,0) + expectedNewFaceInFace2 = {{6,2,1},{6,4,1},{6,4,4},{6,2,4}}; + expectedNewFaceInFace1 = {{6,2,0},{6,4,0},{6,4,1},{6,2,1}}; + + selectedFaceToCoord[3].push_back(expectedNewFaceInFace2); + selectedFaceToCoord[3].push_back(expectedNewFaceInFace1); + } + else if (refinedElem.index() == 5){ + // this element has to have 7 faces: 1 I-,J-,J+,K-,K+, and 2 I+: + // (6,4,4) **(6,6,4) + // | * I_FACE, true with vertices (6,4,1),(6,6,1),(6,6,4),(6,4,4) + // | * + // (6,4,1) --(6,6,1) + // | * I_FACE, true with vertices (6,4,0),(6,6,0),(6,6,1),(6,4,1) + // (6,4,0) --(6,6,0) + expectedNewFaceInFace2 = {{6,4,1},{6,6,1},{6,6,4},{6,4,4}}; + expectedNewFaceInFace1 = {{6,4,0},{6,6,0},{6,6,1},{6,4,1}}; + + selectedFaceToCoord[5].push_back(expectedNewFaceInFace2); + selectedFaceToCoord[5].push_back(expectedNewFaceInFace1); + } + else if (refinedElem.index() == 7) { + expectedNewFaceInFace2 = {{6,0,4}, {6,2,4}, {6,2,8}, {6,0,8}}; + selectedFaceToCoord[7].push_back(expectedNewFaceInFace2); + } + else if (refinedElem.index() == 9) { + expectedNewFaceInFace2 = {{6,2,4}, {6,4,4}, {6,4,8}, {6,2,8}}; + selectedFaceToCoord[9].push_back(expectedNewFaceInFace2); + } + else if (refinedElem.index() == 11) { + expectedNewFaceInFace2 = {{6,4,4}, {6,6,4}, {6,6,8}, {6,4,8}}; + selectedFaceToCoord[11].push_back(expectedNewFaceInFace2); + } + } + checkNewRefinedFaces(grid, refinedGridData, + selectedFaceToCoord, /* repeatedFaceType = */ 1); // 1-> I+ + + Opm::checkGridWithLgrs(grid, + /* cells_per_dim_vec = */ {{2,3,2}}, + /* lgr_name_vec = */ {"LGR1"}); +} + +BOOST_AUTO_TEST_CASE(parentCellWithMoreThanOne_I_FACE_trueOriented_trivialOverlap) +{ + // Level zero grid dims = 2x1x1 + // + // cell 0 + // bottom face corners (0,0,0), (6,0,0), (0,6,0), (6,6,0) + // top face corners (0,0,8), (6,0,8), (0,6,8), (6,6,8) + // + // cell 1 + // bottom face corners (6,0,1), (12,0,1), (6,6,1), (12,6,1) + // top face corners (6,0,9), (12,0,9), (12,6,9), (12,6,9) + const std::string deckString = + R"(RUNSPEC +DIMENS + 2 1 1 / + +GRID + +COORD + 0 0 0 0 0 9 + 6 0 0 6 0 9 +12 0 0 12 0 9 + + 0 6 0 0 6 9 + 6 6 0 6 6 9 +12 6 0 12 6 9 +/ + +ZCORN +0 0 1 1 0 0 1 1 +8 8 9 9 8 8 9 9 +/ + +ACTNUM +2*1 +/ + +PORO +2*0.15 +/ +)"; + + Dune::CpGrid grid; + Opm::createGridAndAddLgrs(grid, + deckString, + /* cells_per_dim_vec */ {{2,3,8}}, + /* startIJK_vec */ {{0,0,0}}, + /* endIJK_vec */ {{1,1,1}}, + /* lgr_name_vec */ {"LGR1"}); + + + + // Element 0 in level zero grid has two faces of type {I_FACE, true} + // + // Vertices of those faces lie on the plane x = 6 | After refinement, number of subdivisions in + // | y- and z- directions: + // (6,0,8) ---------------- (6,6,8) | (6,0,8) --(6,2,8)-(6,4,8)--(6,6,8) + // | | | | * * | + // | | | (6,0,7) **(6,2,7)*(6,4,7)**(6,6,7) + // | | | | * * | + // | | | (6,0,6) **(6,2,6)*(6,4,6)**(6,6,6) + // | | | | * * | + // | face idx 2 | | (6,0,5) **(6,2,5)*(6,4,5)**(6,6,5) + // | | | | * * | + // | | | (6,0,4) **(6,2,4)*(6,4,4)**(6,6,4) + // | | | | * * | + // | | | (6,0,3) **(6,2,3)*(6,4,3)**(6,6,3) + // | | | | * * | + // | | | (6,0,2) **(6,2,2)*(6,4,2)**(6,6,2) + // | | | | * * | + // (6,0,1) -----------------(6,6,1) | (6,0,1) --(6,2,1)-(6,4,1)--(6,6,1) + // | face idx 1 | | | * * | + // (6,0,0) -----------------(6,6,0) | (6,0,0) --(6,2,0)-(6,4,0)--(6,6,0) + // | + + const auto& refinedGridData = *grid.currentData()[1]; + const auto& parentGridData = *grid.currentData()[0]; + const auto parentElem = Dune::cpgrid::Entity<0>(parentGridData, 0, true); + + BOOST_CHECK_EQUAL(parentGridData.cellToFace(parentElem.index()).size(), 7); + + BOOST_CHECK_EQUAL( refinedGridData.size(3), 108); + // LGR1 dims 2x3x8 -> 3x4x9 (= 108) vertices (4 "missing" vertices (6,0,1), (6,2,1), (6,4,1), and (6,6,1) exist). + BOOST_CHECK_EQUAL( refinedGridData.numFaces(), 190); + // LGR1 dims 2x3x8 -> (72+64+54=) 190 faces (before and after correction). + + + // Originally, the element not involved in refinement + // had 7 faces. It's neihgbor in level zero + // got refined and the I_FACE that they shared has been + // replaced by 6 refined faces. Then, the leaf element has + // one of each I+,J-,J+, K-, K+, and 1 coarse + 21 refined I-. + checkFaceCountInLeafCoarseElem(grid, + /* expectedTotalFaceCount = */ 27, + /* repeatedFaceType = */ 0, // 0->I- + /* expoectedRepeatedFaceTypeCount = */ 22); + + expectedCellCountRespectToCellToFaceSize(grid, + /* expectedCount7Faces = */ std::vector{2, 0}); // level 0, level 1 + + const auto& leafGridData = grid.currentLeafData(); + + BOOST_CHECK_EQUAL( leafGridData.size(3), 114); // 114 = 108 + 6 (108 in level 1 + 6 vertices from cell_to_point_ from coarse element) + BOOST_CHECK_EQUAL( leafGridData.numFaces(), 196); // 196 = 190 + 6 (190 in level 1 + 6 other faces from coarse element) + + Opm::checkGridWithLgrs(grid, + /* cells_per_dim_vec = */ {{2,3,8}}, + /* lgr_name_vec = */ {"LGR1"}); +} + + +BOOST_AUTO_TEST_CASE(parentCellWithMoreThanOne_I_FACE_false) +{ + // Level zero grid dims = 2x1x1 + // + // cell 0 + // bottom face corners (0,0,0), (6,0,0), (0,6,0), (6,6,0) + // top face corners (0,0,8), (6,0,8), (0,6,8), (6,6,8) + // + // cell 1 + // bottom face corners (6,0,1), (12,0,1), (6,6,1), (12,6,1) + // top face corners (6,0,9), (12,0,9), (12,6,9), (12,6,9) + const std::string deckString = + R"(RUNSPEC +DIMENS + 2 1 1 / + +GRID + +COORD + 0 0 0 0 0 9 + 6 0 0 6 0 9 +12 0 0 12 0 9 + + 0 6 0 0 6 9 + 6 6 0 6 6 9 +12 6 0 12 6 9 +/ + +ZCORN +0 0 1 1 0 0 1 1 +8 8 9 9 8 8 9 9 +/ + +ACTNUM +2*1 +/ + +PORO +2*0.15 +/ +)"; + + Dune::CpGrid grid; + Opm::createGridAndAddLgrs(grid, + deckString, + /* cells_per_dim_vec */ {{2,3,2}}, + /* startIJK_vec */ {{1,0,0}}, + /* endIJK_vec */ {{2,1,1}}, + /* lgr_name_vec */ {"LGR1"}); + + // LGR1 dimensions = {2,3,2} + // LGR1 indices + // + // k = 1 |10 11| + // | 8 9| + // | 6 7| + // ---------- + // k = 0 | 4 5| + // | 2 3| + // | 0 1| + // ---------- + + // Element 1 in level zero grid has two faces of type {I_FACE, false} + // + // Vertices of those faces lie on the plane x = 6 | After refinement, number of subdivisions in LGR1 cell indices + // | y- and z- directions: + // (6,0,9) -----------------(6,6,9) | (6,0,9) --(6,2,9)-(6,4,9)--(6,6,9) x*****x*****x*****x + // | face idx 3 | | | * * | | * * | + // (6,0,8) -----------------(6,6,8) | (6,0,8) --(?,?,?)-(?,?,?)--(6,6,8) x- 6 -x- 8 -x-10--x + // | | | | * * | | * * | + // | | | | * * | | * * | + // | | | | * * | | * * | + // | face idx 2 | | (6,0,5) **(6,2,5)*(6,4,5)**(6,6,5) x*****x*****x*****x + // | | | | * * | | * * | + // | | | | * * | | 0 * 2 * 4 | + // | | | | * * | | * * | + // (6,0,1) ---------------- (6,6,1) | (6,0,1) --(6,2,1)-(6,4,1)--(6,6,1) x-----x-----x-----x + // | + // | The missing vertices are (6,2,8) and (6,4,8), appering in elements 6,8, or 10 in LGR1. + // | In LGR1 element 6: (6,2,8) + // | In LGR1 element 8: (6,2,8) and (6,4,8) + // | In LGR1 element 10: (6,4,8) + + const auto& refinedGridData = *grid.currentData()[1]; + const auto& parentGridData = *grid.currentData()[0]; + const auto parentElem = Dune::cpgrid::Entity<0>(parentGridData, 1, true); + + BOOST_CHECK_EQUAL(parentGridData.cellToFace(parentElem.index()).size(), 7); + + BOOST_CHECK_EQUAL( refinedGridData.size(3), 40); + // LGR1 dims 2x3x2 -> 3x4x3 vertices + 4 extra missing vertices (6,0,8), (6,2,8), (6,4,8), and (6,6,8). + BOOST_CHECK_EQUAL( refinedGridData.numFaces(), 55); + // LGR1 dims 2x3x2 -> 52 faces (before correction due to missing points) + // 3 of those 52 faces vanished and give origin to 6 new faces: 52 - 3 + 6 = 55 faces + + // Originally, the element not involved in refinement + // had 7 faces. It's neihgbor in level zero + // got refined and the I_FACE that they shared has been + // replaced by 6 refined faces. Then, the leaf element has + // 1 of each I-,J-,J+, K-, K+, and 1 coarse + 6 refined I+. + checkFaceCountInLeafCoarseElem(grid, + /* expectedTotalFaceCount = */ 12, + /* repeatedFaceType = */ 1, // 1->I+ + /* expoectedRepeatedFaceTypeCount = */ 7); + + expectedCellCountRespectToCellToFaceSize(grid, + /* expectedCount7Faces = */ std::vector{2, 3}); // level 0, level 1 + + // Collect the expected data to later on check + std::vector>> selectedFaceToCoord{}; + selectedFaceToCoord.resize(grid.levelGridView(1).size(0)); + + for (const auto& refinedElem : Dune::elements(grid.levelGridView(1))) { + + std::set expectedNewFaceInFace3{}; + std::set expectedNewFaceInFace2{}; + // Vertex order in I_FACE: 0->jk, 1-> (j+1)k, 2->(j+1)(k+1), 3->j(k+1) + // + // j(k+1) <-'3' --------- '2'-> (j+1)(k+1) + // | | + // | | + // jk <-'0' --------- '1'-> (j+1)k + + if (refinedElem.index() == 6){ + // this element has to have 7 faces: 1 I+,J-,J+,K-,K+, and 2 I-: + // (6,0,9) --(6,2,9) + // | * I_FACE, false with vertices (6,0,8),(6,2,8),(6,2,9),(6,0,9) + // (6,0,8) **(6,2,8) + // | * I_FACE, false with vertices (6,0,5),(6,2,5),(6,2,8),(6,0,8) + // | * + // (6,0,5) --(6,2,5) + expectedNewFaceInFace3 = {{6,0,8},{6,2,8},{6,2,9},{6,0,9}}; + expectedNewFaceInFace2 = {{6,0,5},{6,2,5},{6,2,8},{6,0,8}}; + + selectedFaceToCoord[6].push_back(expectedNewFaceInFace3); + selectedFaceToCoord[6].push_back(expectedNewFaceInFace2); + } + else if (refinedElem.index() == 8){ + // this element has to have 7 faces: 1 I+,J-,J+,K-,K+, and 2 I-: + // (6,2,9) --(6,4,9) + // | * I_FACE, false with vertices (6,2,8),(6,4,8),(6,4,9),(6,2,9) + // (6,2,8) **(6,4,8) + // | * I_FACE, false with vertices (6,2,5),(6,4,5),(6,4,8),(6,2,8) + // | * + // (6,2,5) --(6,4,5) + expectedNewFaceInFace3 = {{6,2,8},{6,4,8},{6,4,9},{6,2,9}}; + expectedNewFaceInFace2 = {{6,2,5},{6,4,5},{6,4,8},{6,2,8}}; + + selectedFaceToCoord[8].push_back(expectedNewFaceInFace3); + selectedFaceToCoord[8].push_back(expectedNewFaceInFace2); + } + else if (refinedElem.index() == 10){ + // this element has to have 7 faces: 1 I+,J-,J+,K-,K+, and 2 I-: + // (6,4,9) --(6,6,9) + // | * I_FACE, false with vertices (6,4,8),(6,6,8),(6,6,9),(6,4,9) + // (6,4,8) **(6,6,8) + // | * I_FACE, false with vertices (6,4,5),(6,6,5),(6,6,8),(6,4,8) + // | * + // (6,4,5) --(6,6,5) + expectedNewFaceInFace3 = {{6,4,8},{6,6,8},{6,6,9},{6,4,9}}; + expectedNewFaceInFace2 = {{6,4,5},{6,6,5},{6,6,8},{6,4,8}}; + + selectedFaceToCoord[10].push_back(expectedNewFaceInFace3); + selectedFaceToCoord[10].push_back(expectedNewFaceInFace2); + } + else if (refinedElem.index() == 0) { + expectedNewFaceInFace2 = {{6,0,1}, {6,2,1}, {6,2,5}, {6,0,5}}; + selectedFaceToCoord[0].push_back(expectedNewFaceInFace2); + } + else if (refinedElem.index() == 2) { + expectedNewFaceInFace2 = {{6,2,1}, {6,4,1}, {6,4,5}, {6,2,5}}; + selectedFaceToCoord[2].push_back(expectedNewFaceInFace2); + } + else if (refinedElem.index() == 4) { + expectedNewFaceInFace2 = {{6,4,1}, {6,6,1}, {6,6,5}, {6,4,5}}; + selectedFaceToCoord[4].push_back(expectedNewFaceInFace2); + } + } + checkNewRefinedFaces(grid, refinedGridData, + selectedFaceToCoord, /* repeatedFaceType = */ 0); // 0-> I- + + Opm::checkGridWithLgrs(grid, + /* cells_per_dim_vec = */ {{2,3,2}}, + /* lgr_name_vec = */ {"LGR1"}); +} + +BOOST_AUTO_TEST_CASE(parentCellWithMoreThanSixIntersections_J_FACE_true) +{ + // Level zero grid dims = 1x2x1 + // + // cell 0 + // bottom face corners (0,0,0), (6,0,0), (0,6,0), (6,6,0) + // top face corners (0,0,8), (6,0,8), (0,6,8), (6,6,8) + // + // cell 1 + // bottom face corners (0,6,1), (6,6,1), (0,12,1), (6,12,1) + // top face corners (0,6,9), (6,6,9), (0,12,9), (6,12,9) + + const std::string deckString = + R"(RUNSPEC +DIMENS + 1 2 1 / + +GRID + +COORD + 0 0 0 0 0 9 + 6 0 0 6 0 9 + + 0 6 0 0 6 9 + 6 6 0 6 6 9 + + 0 12 0 0 12 9 + 6 12 0 6 12 9 +/ + +ZCORN +0 0 0 0 1 1 1 1 +8 8 8 8 9 9 9 9 +/ + +ACTNUM +2*1 +/ + +PORO +2*0.15 +/ +)"; + + Dune::CpGrid grid; + Opm::createGridAndAddLgrs(grid, + deckString, + /* cells_per_dim_vec */ {{3,2,2}}, + /* startIJK_vec */ {{0,0,0}}, + /* endIJK_vec */ {{1,1,1}}, + /* lgr_name_vec */ {"LGR1"}); + + // LGR1 dimensions = {3,2,2} + // LGR1 indices + // + // k = 1 | 9 10 11| + // | 6 7 8| + // ---------- + // k = 0 | 3 4 5| + // | 0 1 2| + // ------------ + + + // Element 0 in level zero grid has two faces of type {J_FACE, true} + // + // Vertices of those faces lie on the plane y = 6 | After refinement, number of subdivisions in LGR1 cell indices + // | y- and z- directions: + // (0,6,8) ---------------- (6,6,8) | (0,6,8) --(2,6,8)-(4,6,8)--(6,6,8) x-----x-----x-----x + // | | | | * * | | * * | + // | | | | * * | | 9 * 10 * 11 | + // | | | | * * | | * * | + // | face idx 6 | | | * * | | * * | + // | | | (0,6,4) **(2,6,4)*(4,6,4)**(6,6,4) x*****x*****x*****x + // | | | | * * | | * * | + // | | | | * * | | * * | + // (0,6,1) -----------------(6,6,1) | (0,6,1) --(?,?,?)-(?,?,?)--(6,6,1) x- 3 -x- 4 -x- 5 -x + // | face idx 5 | | | * * | | * * | + // (0,6,0) -----------------(6,6,0) | (0,6,0) --(2,6,0)-(4,6,0)--(6,6,0) x-----x-----x-----x + // | + // | The missing vertices are (2,6,1) and (4,6,1), appering in elements 3,4 or 5 in LGR1. + // | In LGR1 element 3: (2,6,1) + // | In LGR1 element 4: (2,6,1) and (4,6,1) + // | In LGR1 element 5: (4,6,1) + + const auto& refinedGridData = *grid.currentData()[1]; + const auto& parentGridData = *grid.currentData()[0]; + const auto parentElem = Dune::cpgrid::Entity<0>(parentGridData, 0, true); + + BOOST_CHECK_EQUAL(parentGridData.cellToFace(parentElem.index()).size(), 7); + + BOOST_CHECK_EQUAL( refinedGridData.size(3), 40); + // LGR1 dims 3x2x2 -> 4x3x3 vertices + 4 extra missing vertices (0,6,1), (2,6,1), (4,6,1), and (6,6,1). + BOOST_CHECK_EQUAL( refinedGridData.numFaces(), 55); + // LGR1 dims 3x2x2 -> 52 faces (before correction due to missing points) + // 3 of those 52 faces vanished and give origin to 6 new faces: 52 - 3 + 6 = 55 faces + + // Originally, the element not involved in refinement + // had 7 faces. It's neihgbor in level zero + // got refined and the I_FACE that they shared has been + // replaced by 6 refined faces. Then, the leaf element has + // one of each I-,I+,J+, K-, K+, and 1 coarse + 6 refined J-. + checkFaceCountInLeafCoarseElem(grid, + /* expectedTotalFaceCount = */ 12, + /* repeatedFaceType = */ 2, // 2->J- + /* expoectedRepeatedFaceTypeCount = */ 7); + + expectedCellCountRespectToCellToFaceSize(grid, + /* expectedCount7Faces = */ std::vector{2, 3}); // level 0, level 1 + + // Collect the expected data to later on check + std::vector>> selectedFaceToCoord{}; + selectedFaceToCoord.resize(grid.levelGridView(1).size(0)); + + for (const auto& refinedElem : Dune::elements(grid.levelGridView(1))) { + + std::set expectedNewFaceInFace6{}; + std::set expectedNewFaceInFace5{}; + // Vertex order in J_FACE: 0->(i+1)k, 1-> ik, 2->i(k+1), 3->(i+1)(k+1) + // + // i(k+1) <-'2' --------- '3'-> (i+1)(k+1) + // | | + // | | + // ik <-'1' --------- '0'-> (i+1)k + + if (refinedElem.index() == 3){ + // this element has to have 7 faces: 1 I-,I+,J-,K-,K+, and 2 J+: + // (0,6,4) **(2,6,4) + // | * J_FACE, true with vertices (0,6,1),(2,6,1),(2,6,4),(,6,4) + // | * + // (0,6,1) --(2,6,1) + // | * J_FACE, true with vertices (0,6,0),(2,6,0),(2,6,1),(0,6,1) + // (0,6,0) --(2,6,0) + expectedNewFaceInFace6 = {{2,6,1}, {0,6,1}, {0,6,4}, {2,6,4}}; + expectedNewFaceInFace5 = {{2,6,0}, {0,6,0}, {0,6,1}, {2,6,1}}; + + selectedFaceToCoord[3].push_back(expectedNewFaceInFace6); + selectedFaceToCoord[3].push_back(expectedNewFaceInFace5); + } + else if (refinedElem.index() == 4){ + // this element has to have 7 faces: 1 I-,I+,J-,K-,K+, and 2 J+: + // (2,6,4) **(4,6,4) + // | * J_FACE, true with vertices (2,6,1),(4,6,1),(4,6,4),(2,6,4) + // | * + // (2,6,1) --(4,6,1) + // | * J_FACE, true with vertices (2,6,0),(4,6,0),(4,6,1),(2,6,1) + // (2,6,0) --(4,6,0) + expectedNewFaceInFace6 = {{4,6,1}, {2,6,1}, {2,6,4}, {4,6,4}}; + expectedNewFaceInFace5 = {{4,6,0}, {2,6,0}, {2,6,1}, {4,6,1}}; + + selectedFaceToCoord[4].push_back(expectedNewFaceInFace6); + selectedFaceToCoord[4].push_back(expectedNewFaceInFace5); + } + else if (refinedElem.index() == 5){ + // this element has to have 7 faces: 1 I-,I+,J-,K-,K+, and 2 J+: + // (4,6,4) **(6,6,4) + // | * J_FACE, true with vertices (4,6,1),(6,6,1),(6,6,4),(4,6,4) + // | * + // (4,6,1) --(6,6,1) + // | * J_FACE, true with vertices (4,6,0),(6,6,0),(6,6,1),(4,6,1) + // (4,6,0) --(6,6,0) + expectedNewFaceInFace6 = {{6,6,1}, {4,6,1}, {4,6,4}, {6,6,4}}; + expectedNewFaceInFace5 = {{6,6,0}, {4,6,0}, {4,6,1}, {6,6,1}}; + + selectedFaceToCoord[5].push_back(expectedNewFaceInFace6); + selectedFaceToCoord[5].push_back(expectedNewFaceInFace5); + } + else if (refinedElem.index() == 9) { + expectedNewFaceInFace6 = {{2,6,4}, {0,6,4}, {0,6,8}, {2,6,8}}; + selectedFaceToCoord[9].push_back(expectedNewFaceInFace6); + } + else if (refinedElem.index() == 10) { + expectedNewFaceInFace6 = {{4,6,4}, {2,6,4}, {2,6,8}, {4,6,8}}; + selectedFaceToCoord[10].push_back(expectedNewFaceInFace6); + } + else if (refinedElem.index() == 11) { + expectedNewFaceInFace6 = {{6,6,4}, {4,6,4}, {4,6,8}, {6,6,8}}; + selectedFaceToCoord[11].push_back(expectedNewFaceInFace6); + } + } + checkNewRefinedFaces(grid, refinedGridData, + selectedFaceToCoord, /* repeatedFaceType = */ 3); // 3-> J+ + + Opm::checkGridWithLgrs(grid, + /* cells_per_dim_vec = */ {{3,2,2}}, + /* lgr_name_vec = */ {"LGR1"}); +} + + +BOOST_AUTO_TEST_CASE(parentCellWithMoreThanSixIntersections_J_FACE_false) +{ + // Level zero grid dims = 1x2x1 + // + // cell 0 + // bottom face corners (0,0,0), (6,0,0), (0,6,0), (6,6,0) + // top face corners (0,0,8), (6,0,8), (0,6,8), (6,6,8) + // + // cell 1 + // bottom face corners (0,6,1), (6,6,1), (0,12,1), (6,12,1) + // top face corners (0,6,9), (6,6,9), (0,12,9), (6,12,9) + + const std::string deckString = + R"(RUNSPEC +DIMENS + 1 2 1 / + +GRID + +COORD + 0 0 0 0 0 9 + 6 0 0 6 0 9 + + 0 6 0 0 6 9 + 6 6 0 6 6 9 + + 0 12 0 0 12 9 + 6 12 0 6 12 9 +/ + +ZCORN +0 0 0 0 1 1 1 1 +8 8 8 8 9 9 9 9 +/ + +ACTNUM +2*1 +/ + +PORO +2*0.15 +/ +)"; + + Dune::CpGrid grid; + Opm::createGridAndAddLgrs(grid, + deckString, + /* cells_per_dim_vec */ {{3,2,2}}, + /* startIJK_vec */ {{0,1,0}}, + /* endIJK_vec */ {{1,2,1}}, + /* lgr_name_vec */ {"LGR1"}); + + // LGR1 dimensions = {3,2,2} + // LGR1 indices + // + // k = 1 | 9 10 11| + // | 6 7 8| + // ---------- + // k = 0 | 3 4 5| + // | 0 1 2| + // ------------ + + // Element 1 in level zero grid has two faces of type {J_FACE, false} + // + // Vertices of those faces lie on the plane x = 6 | After refinement, number of subdivisions in LGR1 cell indices + // | y- and z- directions: + // (0,6,9) -----------------(6,6,9) | (0,6,9) --(2,6,9)-(4,6,9)--(6,6,9) x*****x*****x*****x + // | face idx 7 | | | * * | | * * | + // (0,6,8) -----------------(6,6,8) | (0,6,8) --(?,?,?)-(?,?,?)--(6,6,8) x- 6 -x- 7 -x- 8--x + // | | | | * * | | * * | + // | | | | * * | | * * | + // | | | | * * | | * * | + // | face idx 6 | | (0,6,5) **(2,6,5)*(4,6,5)**(6,6,5) x*****x*****x*****x + // | | | | * * | | * * | + // | | | | * * | | 0 * 1 * 2 | + // | | | | * * | | * * | + // (0,6,1) ---------------- (6,6,1) | (0,6,1) --(2,6,1)-(4,6,1)--(6,6,1) x-----x-----x-----x + // | + // | The missing vertices are (2,6,8) and (4,6,8), appering in elements 6,7, or 8 in LGR1. + // | In LGR1 element 6: (2,6,8) + // | In LGR1 element 7: (2,6,8) and (4,6,8) + // | In LGR1 element 8: (4,6,8) + + const auto& refinedGridData = *grid.currentData()[1]; + const auto& parentGridData = *grid.currentData()[0]; + const auto parentElem = Dune::cpgrid::Entity<0>(parentGridData, 1, true); + + BOOST_CHECK_EQUAL(parentGridData.cellToFace(parentElem.index()).size(), 7); + + BOOST_CHECK_EQUAL( refinedGridData.size(3), 40); + // LGR1 dims 3x2x2 -> 4x3x3 vertices + 4 extra missing vertices (0,6,8), (2,6,8), (4,6,8), and (6,6,8). + BOOST_CHECK_EQUAL( refinedGridData.numFaces(), 55); + // LGR1 dims 3x2x2 -> 52 faces (before correction due to missing points) + // 3 of those 52 faces vanished and give origin to 6 new faces: 52 - 3 + 6 = 55 faces + + // Originally, the element not involved in refinement + // had 7 faces. It's neihgbor in level zero + // got refined and the I_FACE that they shared has been + // replaced by 6 refined faces. Then, the leaf element has + // one of each I-,I+,J-, K-, K+, and 1 coarse + 6 refined J+. + checkFaceCountInLeafCoarseElem(grid, + /* expectedTotalFaceCount = */ 12, + /* repeatedFaceType = */ 3, // 3->J+ + /* expoectedRepeatedFaceTypeCount = */ 7); + + expectedCellCountRespectToCellToFaceSize(grid, + /* expectedCount7Faces = */ std::vector{2, 3}); // level 0, level 1 + + // Collect the expected data to later on check + std::vector>> selectedFaceToCoord{}; + selectedFaceToCoord.resize(grid.levelGridView(1).size(0)); + + for (const auto& refinedElem : Dune::elements(grid.levelGridView(1))) { + + std::set expectedNewFaceInFace7{}; + std::set expectedNewFaceInFace6{}; + // Vertex order in J_FACE: 0->(i+1)k, 1-> ik, 2->i(k+1), 3->(i+1)(k+1) + // + // i(k+1) <-'2' --------- '3'-> (i+1)(k+1) + // | | + // | | + // ik <-'1' --------- '0'-> (i+1)k + + if (refinedElem.index() == 6) { + // this element has to have 7 faces: 1 I-,I+,J+,K-,K+, and 2 J-: + // (0,6,9) --(2,6,9) + // | * J_FACE, false with vertices (0,6,8),(2,6,8),(2,6,9),(0,6,9) + // (0,6,8) **(2,6,8) + // | * J_FACE, false with vertices (0,6,5),(2,6,5),(2,6,8),(0,6,8) + // | * + // (0,6,5) --(2,6,5) + expectedNewFaceInFace7 = {{2,6,8}, {0,6,8}, {0,6,9}, {2,6,9}}; + expectedNewFaceInFace6 = {{2,6,5}, {0,6,5}, {0,6,8}, {2,6,8}}; + + selectedFaceToCoord[6].push_back(expectedNewFaceInFace7); + selectedFaceToCoord[6].push_back(expectedNewFaceInFace6); + } + else if (refinedElem.index() == 7) { + // this element has to have 7 faces: 1 I-,I+,J+,K-,K+, and 2 J-: + // (2,6,9) --(4,6,9) + // | * J_FACE, false with vertices (2,6,8),(4,6,8),(4,6,9),(2,6,9) + // (2,6,8) **(4,6,8) + // | * J_FACE, false with vertices (2,6,5),(4,6,5),(4,6,8),(2,6,8) + // | * + // (2,6,5) --(4,6,5) + expectedNewFaceInFace7 = {{4,6,8}, {2,6,8}, {2,6,9}, {4,6,9}}; + expectedNewFaceInFace6 = {{4,6,5}, {2,6,5}, {2,6,8}, {4,6,8}}; + + selectedFaceToCoord[7].push_back(expectedNewFaceInFace7); + selectedFaceToCoord[7].push_back(expectedNewFaceInFace6); + } + else if (refinedElem.index() == 8) { + // this element has to have 7 faces: 1 I-,I+,J+,K-,K+, and 2 J-: + // (4,6,9) --(6,6,9) + // | * J_FACE, false with vertices (4,6,8),(6,6,8),(6,6,9),(4,6,9) + // (4,6,8) **(6,6,8) + // | * J_FACE, false with vertices (4,6,5),(6,6,5),(6,6,8),(4,6,8) + // | * + // (4,6,5) --(6,6,5) + expectedNewFaceInFace7 = {{6,6,8}, {4,6,8}, {4,6,9}, {6,6,9}}; + expectedNewFaceInFace6 = {{6,6,5}, {4,6,5}, {4,6,8}, {6,6,8}}; + + selectedFaceToCoord[8].push_back(expectedNewFaceInFace7); + selectedFaceToCoord[8].push_back(expectedNewFaceInFace6); + } + else if (refinedElem.index() == 0) { + expectedNewFaceInFace6 = {{2,6,1}, {0,6,1}, {0,6,5}, {2,6,5}}; + selectedFaceToCoord[0].push_back(expectedNewFaceInFace6); + } + else if (refinedElem.index() == 1) { + expectedNewFaceInFace6 = {{4,6,1}, {2,6,1}, {2,6,5}, {4,6,5}}; + selectedFaceToCoord[1].push_back(expectedNewFaceInFace6); + } + else if (refinedElem.index() == 2) { + expectedNewFaceInFace6 = {{6,6,1},{4,6,1}, {4,6,5}, {6,6,5}}; + selectedFaceToCoord[2].push_back(expectedNewFaceInFace6); + } + } + checkNewRefinedFaces(grid, refinedGridData, + selectedFaceToCoord, /* repeatedFaceType = */ 2); // 2-> J- + + Opm::checkGridWithLgrs(grid, + /* cells_per_dim_vec = */ {{3,2,2}}, + /* lgr_name_vec = */ {"LGR1"}); +} + + +BOOST_AUTO_TEST_CASE(neighboringSingleCellRefinementsDifferentLgrs) +{ + // Level zero grid dims = 2x1x1 + // + // cell 0 + // bottom face corners (0,0,0), (6,0,0), (0,6,0), (6,6,0) + // top face corners (0,0,8), (6,0,8), (0,6,8), (6,6,8) + // + // cell 1 + // bottom face corners (6,0,1), (12,0,1), (6,6,1), (12,6,1) + // top face corners (6,0,9), (12,0,9), (12,6,9), (12,6,9) + const std::string deckString = + R"(RUNSPEC +DIMENS + 2 1 1 / + +GRID + +COORD + 0 0 0 0 0 9 + 6 0 0 6 0 9 +12 0 0 12 0 9 + + 0 6 0 0 6 9 + 6 6 0 6 6 9 +12 6 0 12 6 9 +/ + +ZCORN +0 0 1 1 0 0 1 1 +8 8 9 9 8 8 9 9 +/ + +ACTNUM +2*1 +/ + +PORO +2*0.15 +/ +)"; + + Dune::CpGrid grid; + Opm::createGridAndAddLgrs(grid, + deckString, + {{2,3,2}, {2,3,2}}, // cells_per_dim_vec + {{0,0,0}, {1,0,0}}, // startIJK_vec + {{1,1,1}, {2,1,1}}, // endIJK_vec + {"LGR1", "LGR2"}); // lgr_name_vec*/ + + // Element 0 and element 1 in level zero grid share an I_FACE (with face index 2) + // + // Vertices of those faces lie on the plane x = 6 | After refinement, number of subdivisions in + // | y- and z- directions: + // + // (6,0,9) -----------------(6,6,9) | (6,0,9) --(6,2,9)-(6,4,9)--(6,6,9) + // | face idx 3 | | | * * | + // (6,0,8) ---------------- (6,6,8) | (6,0,8) --(6,2,8)-(6,4,8)--(6,6,8) + // | | | | * * | + // | | | | * * | + // | | | | * * | + // | face idx 2 | | (6,0,5) **(6,2,5)*(6,4,5)**(6,6,5) + // | | | | * * | + // | | | (6,0,4) **(6,2,4)*(6,4,4)**(6,6,4) + // | | | | * * | + // | | | | * * | + // (6,0,1) -----------------(6,6,1) | (6,0,1) --(6,2,1)-(6,4,1)--(6,6,1) + // | face idx 1 | | | * * | + // (6,0,0) -----------------(6,6,0) | (6,0,0) --(6,2,0)-(6,4,0)--(6,6,0) + // | + + const auto& parentGridData = *grid.currentData()[0]; + const auto parent0 = Dune::cpgrid::Entity<0>(parentGridData, 0, true); + const auto parent1 = Dune::cpgrid::Entity<0>(parentGridData, 1, true); + + BOOST_CHECK_EQUAL(parentGridData.cellToFace(parent0.index()).size(), 7); + BOOST_CHECK_EQUAL(parentGridData.cellToFace(parent1.index()).size(), 7); + + const auto& refinedGrid1 = *grid.currentData()[1]; + BOOST_CHECK_EQUAL( refinedGrid1.size(3), 44); + // LGR1 dims 3x2x2 -> 4x3x3 vertices + 4 extra missing vertices (0,6,8), (2,6,8), (4,6,8), and (6,6,8)...... + BOOST_CHECK_EQUAL( refinedGrid1.numFaces(), 58); + + const auto& refinedGrid2 = *grid.currentData()[2]; + BOOST_CHECK_EQUAL( refinedGrid2.size(3), 44); + // LGR1 dims 3x2x2 -> 4x3x3 vertices + 4 extra missing vertices (0,6,8), (2,6,8), (4,6,8), and (6,6,8)........ + BOOST_CHECK_EQUAL( refinedGrid2.numFaces(), 58); + + const auto& leafGrid = grid.currentLeafData(); + + BOOST_CHECK_EQUAL( leafGrid.size(3), 72); // 44 + 44 -16 -> 72 + BOOST_CHECK_EQUAL( leafGrid.numFaces(), 107); // 58 + 58 - 9 ->107 + + expectedCellCountRespectToCellToFaceSize(grid, + /* expectedCount7Faces = */ std::vector{2, 6, 6}); // level 0, level 1, level2 + + // Leaf grid should have 12 elements with 7 faces (due to I_FACE shared between + // parent cells) and 24-12 = 12 with 6 faces + int count_7faces = 0; + int count_6faces = 0; + for (const auto& element : Dune::elements(grid.leafGridView())) { + int count = leafGrid.cellToFace(element.index()).size(); + if (count == 7) { + ++count_7faces; + } + else { + BOOST_CHECK_EQUAL(count, 6); + ++count_6faces; + } + } + BOOST_CHECK_EQUAL(count_7faces, 12); + BOOST_CHECK_EQUAL(count_6faces, grid.leafGridView().size(0) - count_7faces); + + + Opm::checkGridWithLgrs(grid, + {{2,3,2}, {2,3,2}}, // cells_per_dim_vec + {"LGR1", "LGR2"}); // lgr_name_vec + +} + +BOOST_AUTO_TEST_CASE(neighboringSingleCellRefinementsSameLgr) +{ + // Level zero grid dims = 2x1x1 + // + // cell 0 + // bottom face corners (0,0,0), (6,0,0), (0,6,0), (6,6,0) + // top face corners (0,0,8), (6,0,8), (0,6,8), (6,6,8) + // + // cell 1 + // bottom face corners (6,0,1), (12,0,1), (6,6,1), (12,6,1) + // top face corners (6,0,9), (12,0,9), (12,6,9), (12,6,9) + const std::string deckString = + R"(RUNSPEC +DIMENS + 2 1 1 / + +GRID + +COORD + 0 0 0 0 0 9 + 6 0 0 6 0 9 +12 0 0 12 0 9 + + 0 6 0 0 6 9 + 6 6 0 6 6 9 +12 6 0 12 6 9 +/ + +ZCORN +0 0 1 1 0 0 1 1 +8 8 9 9 8 8 9 9 +/ + +ACTNUM +2*1 +/ + +PORO +2*0.15 +/ +)"; + + Dune::CpGrid grid; + Opm::createGridAndAddLgrs(grid, + deckString, + /* cells_per_dim_vec */ {{2,3,2}}, + /* startIJK_vec */ {{0,0,0}}, + /* endIJK_vec */ {{2,1,1}}, + /* lgr_name_vec */ {"LGR1"}); + + // Element 0 and element 1 in level zero grid share an I_FACE (with face index 2) + // + // Vertices of those faces lie on the plane x = 6 | After refinement, number of subdivisions in + // | y- and z- directions: + // + // (6,0,9) -----------------(6,6,9) | (6,0,9) --(6,2,9)-(6,4,9)--(6,6,9) + // | face idx 3 | | | * * | + // (6,0,8) ---------------- (6,6,8) | (6,0,8) --(6,2,8)-(6,4,8)--(6,6,8) + // | | | | * * | + // | | | | * * | + // | | | | * * | + // | face idx 2 | | (6,0,5) **(6,2,5)*(6,4,5)**(6,6,5) + // | | | | * * | + // | | | (6,0,4) **(6,2,4)*(6,4,4)**(6,6,4) + // | | | | * * | + // | | | | * * | + // (6,0,1) -----------------(6,6,1) | (6,0,1) --(6,2,1)-(6,4,1)--(6,6,1) + // | face idx 1 | | | * * | + // (6,0,0) -----------------(6,6,0) | (6,0,0) --(6,2,0)-(6,4,0)--(6,6,0) + // | + const auto& parentGridData = *grid.currentData()[0]; + const auto parent0 = Dune::cpgrid::Entity<0>(parentGridData, 0, true); + const auto parent1 = Dune::cpgrid::Entity<0>(parentGridData, 1, true); + + BOOST_CHECK_EQUAL(parentGridData.cellToFace(parent0.index()).size(), 7); + BOOST_CHECK_EQUAL(parentGridData.cellToFace(parent1.index()).size(), 7); + + const auto& refinedGrid1 = *grid.currentData()[1]; + BOOST_CHECK_EQUAL( refinedGrid1.size(3), 72); + BOOST_CHECK_EQUAL( refinedGrid1.numFaces(), 107); + + const auto& leafGrid = grid.currentLeafData(); + BOOST_CHECK_EQUAL( leafGrid.size(3), 72); // 44 + 44 -16 -> 72 + BOOST_CHECK_EQUAL( leafGrid.numFaces(), 107); // 58 + 58 - 9 ->107 + + expectedCellCountRespectToCellToFaceSize(grid, + /* expectedCount7Faces = */ std::vector{2, 12}); // level 0, level 1 + + // Leaf grid should have 12 elements with 7 faces (due to I_FACE shared between + // parent cells) and 24-12 = 12 with 6 faces + int count_7faces = 0; + int count_6faces = 0; + for (const auto& element : Dune::elements(grid.leafGridView())) { + int count = leafGrid.cellToFace(element.index()).size(); + if (count == 7) { + ++count_7faces; + } + else { + BOOST_CHECK_EQUAL(count, 6); + ++count_6faces; + } + } + BOOST_CHECK_EQUAL(count_7faces, 12); + BOOST_CHECK_EQUAL(count_6faces, grid.leafGridView().size(0) - count_7faces); + + Opm::checkGridWithLgrs(grid, + {{2,3,2}}, // cells_per_dim_vec + {"LGR1"}); // lgr_name_vec +} + + + +BOOST_AUTO_TEST_CASE(simpleDiffLgr) +{ + // Level zero grid dims = 2x1x1 + // + // cell 0 + // bottom face corners (0,0,0), (6,0,0), (0,6,0), (6,6,0) + // top face corners (0,0,8), (6,0,8), (0,6,8), (6,6,8) + // + // cell 1 + // bottom face corners (6,0,1), (12,0,1), (6,6,1), (12,6,1) + // top face corners (6,0,9), (12,0,9), (12,6,9), (12,6,9) + const std::string deckString = + R"(RUNSPEC +DIMENS + 2 1 1 / + +GRID + +COORD + 0 0 0 0 0 9 + 6 0 0 6 0 9 +12 0 0 12 0 9 + + 0 6 0 0 6 9 + 6 6 0 6 6 9 +12 6 0 12 6 9 +/ + +ZCORN +0 0 1 1 0 0 1 1 +8 8 9 9 8 8 9 9 +/ + +ACTNUM +2*1 +/ + +PORO +2*0.15 +/ +)"; + + Dune::CpGrid grid; + Opm::createGridAndAddLgrs(grid, + deckString, + /* cells_per_dim_vec */ {{1,2,1}, {1,2,1}}, + /* startIJK_vec */ {{0,0,0}, {1,0,0}}, + /* endIJK_vec */ {{1,1,1}, {2,1,1}}, + /* lgr_name_vec */ {"LGR1", "LGR2"}); + + // Element 0 and element 1 in level zero grid share an I_FACE (with face index 2) + // + // Vertices of those faces lie on the plane x = 6 | After refinement, number of subdivisions in + // | y- and z- directions: + // + // (6,0,9) -----------------(6,6,9) | (6,0,9) --(6,3,9)---(6,6,9) + // | face idx 3 | | | * | + // (6,0,8) ---------------- (6,6,8) | (6,0,8) --(6,3,9)---(6,6,8) + // | | | | * | + // | | | | * | + // | | | | * | + // | face idx 2 | | | * | + // | | | | * | + // | | | | * | + // | | | | * | + // | | | | * | + // (6,0,1) -----------------(6,6,1) | (6,0,1) --(6,3,1)---(6,6,1) + // | face idx 1 | | | * | + // (6,0,0) -----------------(6,6,0) | (6,0,0) --(6,3,0)---(6,6,0) + // | + const auto& parentGridData = *grid.currentData()[0]; + const auto parent0 = Dune::cpgrid::Entity<0>(parentGridData, 0, true); + const auto parent1 = Dune::cpgrid::Entity<0>(parentGridData, 1, true); + + BOOST_CHECK_EQUAL(parentGridData.cellToFace(parent0.index()).size(), 7); + BOOST_CHECK_EQUAL(parentGridData.cellToFace(parent1.index()).size(), 7); + + const auto& refinedGrid1 = *grid.currentData()[1]; + BOOST_CHECK_EQUAL( refinedGrid1.size(3), 15); + BOOST_CHECK_EQUAL( refinedGrid1.numFaces(), 13); + + const auto& refinedGrid2 = *grid.currentData()[2]; + BOOST_CHECK_EQUAL( refinedGrid2.size(3), 15); + BOOST_CHECK_EQUAL( refinedGrid2.numFaces(), 13); + + const auto& leafGrid = grid.currentLeafData(); + BOOST_CHECK_EQUAL( leafGrid.size(3), 24); + BOOST_CHECK_EQUAL( leafGrid.numFaces(), 24); + + + const std::set expectedLGR1Vertices = { + {0.,0.,0.}, {0.,0.,8.}, // pillar x = 0, y = 0 + {6.,0.,0.}, {6.,0.,1.}, {6.,0.,8.}, // pillar x = 6, y = 0 + {0.,3.,0.}, {0.,3.,8.}, // pillar x = 0, y = 3 + {6.,3.,0.}, {6.,3.,1.}, {6.,3.,8.}, // pillar x = 6, y = 3 + {0.,6.,0.}, {0.,6.,8.}, // pillar x = 0, y = 6 + {6.,6.,0.}, {6.,6.,1.}, {6.,6.,8.} // pillar x = 6, y = 6 + }; + + const std::set expectedLGR2Vertices = { + {6.,0.,1.}, {6.,0.,8.}, {6.,0.,9.}, // pillar x = 6, y = 0 + {12.,0.,1.}, {12.,0.,9.}, // pillar x = 12, y = 0 + {6.,3.,1.}, {6.,3.,8.}, {6.,3.,9.}, // pillar x = 6, y = 3 + {12.,3.,1.}, {12.,3.,9.}, // pillar x = 12, y = 3 + {6.,6.,1.}, {6.,6.,8.}, {6.,6.,9.}, // pillar x = 6, y = 6 + {12.,6.,1.}, {12.,6.,9.} // pillar x = 12, y = 6 + }; + + const std::set expectedLeafVertices = { + {0.,0.,0.}, {0.,0.,8.}, // pillar x = 0, y = 0 + {6.,0.,0.}, {6.,0.,1.}, {6.,0.,8.}, {6.,0.,9.}, // pillar x = 6, y = 0 + {12.,0.,1.}, {12.,0.,9.}, // pillar x = 12, y = 0 + {0.,3.,0.}, {0.,3.,8.}, // pillar x = 0, y = 3 + {6.,3.,0.}, {6.,3.,1.}, {6.,3.,8.}, {6.,3.,9.}, // pillar x = 6, y = 3 + {12.,3.,1.}, {12.,3.,9.}, // pillar x = 12, y = 3 + {0.,6.,0.}, {0.,6.,8.}, // pillar x = 0, y = 6 + {6.,6.,0.}, {6.,6.,1.}, {6.,6.,8.}, {6.,6.,9.}, // pillar x = 6, y = 6 + {12.,6.,1.}, {12.,6.,9.} // pillar x = 12, y = 6 + }; + + checkLevelVertices(grid, std::vector{expectedLGR1Vertices, expectedLGR2Vertices}); + checkLeafVertices(grid, expectedLeafVertices); + + const std::vector> expectedLGR1Faces = { + {{0.,0.,0.}, {6.,0.,0.}, {6.,3.,0.}, {0.,3.,0.}}, // K_FACE z = 0, face 0 + {{0.,3.,0.}, {6.,3.,0.}, {6.,6.,0.}, {0.,6.,0.}}, // K_FACE z = 0, face 1 + {{0.,0.,8.}, {6.,0.,8.}, {6.,3.,8.}, {0.,3.,8.}}, // K_FACE z = 8, face 2 + {{0.,3.,8.}, {6.,3.,8.}, {6.,6.,8.}, {0.,6.,8.}}, // K_FACE z = 8, face 3 + {{0.,0.,0.}, {0.,3.,0.}, {0.,3.,8.}, {0.,0.,8.}}, // I_FACE x = 0, face 4 + {{0.,3.,0.}, {0.,6.,0.}, {0.,6.,8.}, {0.,3.,8.}}, // I_FACE x = 0, face 5 + {{6.,0.,0.}, {6.,3.,0.}, {6.,3.,1.}, {6.,0.,1.}}, // I_FACE x = 6, face 6 + {{6.,0.,1.}, {6.,3.,1.}, {6.,3.,8.}, {6.,0.,8.}}, // I_FACE x = 6, face 7 + {{6.,3.,0.}, {6.,6.,0.}, {6.,6.,1.}, {6.,3.,1.}}, // I_FACE x = 6, face 8 + {{6.,3.,1.}, {6.,6.,1.}, {6.,6.,8.}, {6.,3.,8.}}, // I_FACE x = 6, face 9 + {{0.,0.,0.}, {6.,0.,0.}, {6.,0.,8.}, {0.,0.,8.}}, // J_FACE y = 0, face 10 + {{0.,3.,0.}, {6.,3.,0.}, {6.,3.,8.}, {0.,3.,8.}}, // J_FACE y = 3, face 11 + {{0.,6.,0.}, {6.,6.,0.}, {6.,6.,8.}, {0.,6.,8.}}, // J_FACE y = 6, face 12 + }; + + const std::vector> expectedLGR2Faces = { + {{6.,0.,1.}, {12.,0.,1.}, {12.,3.,1.}, {6.,3.,1.}}, // K_FACE z = 1, face 0 + {{6.,3.,1.}, {12.,3.,1.}, {12.,6.,1.}, {6.,6.,1.}}, // K_FACE z = 1, face 1 + {{6.,0.,9.}, {12.,0.,9.}, {12.,3.,9.}, {6.,3.,9.}}, // K_FACE z = 9, face 2 + {{6.,3.,9.}, {12.,3.,9.}, {12.,6.,9.}, {6.,6.,9.}}, // K_FACE z = 9, face 3 + {{6.,0.,1.}, {6.,3.,1.}, {6.,3.,8.}, {6.,0.,8.}}, // I_FACE x = 6, face 4 + {{6.,0.,8.}, {6.,3.,8.}, {6.,3.,9.}, {6.,0.,9.}}, // I_FACE x = 6, face 5 + {{6.,3.,1.}, {6.,6.,1.}, {6.,6.,8.}, {6.,3.,8.}}, // I_FACE x = 6, face 6 + {{6.,3.,8.}, {6.,6.,8.}, {6.,6.,9.}, {6.,3.,9.}}, // I_FACE x = 6, face 7 + {{12.,0.,1.}, {12.,3.,1.}, {12.,3.,9.}, {12.,0.,9.}}, // I_FACE x = 12, face 8 + {{12.,3.,1.}, {12.,6.,1.}, {12.,6.,9.}, {12.,3.,9.}}, // I_FACE x = 12, face 9 + {{6.,0.,1.}, {12.,0.,1.}, {12.,0.,9.}, {6.,0.,9.}}, // J_FACE y = 0, face 10 + {{6.,3.,1.}, {12.,3.,1.}, {12.,3.,9.}, {6.,3.,9.}}, // J_FACE y = 3, face 11 + {{6.,6.,1.}, {12.,6.,1.}, {12.,6.,9.}, {6.,6.,9.}}, // J_FACE y = 6, face 12 + }; + + const std::vector> expectedLeafFaces = { + {{0.,0.,0.}, {6.,0.,0.}, {6.,3.,0.}, {0.,3.,0.}}, // K_FACE z = 0, face 0 + {{0.,3.,0.}, {6.,3.,0.}, {6.,6.,0.}, {0.,6.,0.}}, // K_FACE z = 0, face 1 + {{0.,0.,8.}, {6.,0.,8.}, {6.,3.,8.}, {0.,3.,8.}}, // K_FACE z = 8, face 2 + {{0.,3.,8.}, {6.,3.,8.}, {6.,6.,8.}, {0.,6.,8.}}, // K_FACE z = 8, face 3 + {{0.,0.,0.}, {0.,3.,0.}, {0.,3.,8.}, {0.,0.,8.}}, // I_FACE x = 0, face 6 + {{0.,3.,0.}, {0.,6.,0.}, {0.,6.,8.}, {0.,3.,8.}}, // I_FACE x = 0, face 5 + {{6.,0.,0.}, {6.,3.,0.}, {6.,3.,1.}, {6.,0.,1.}}, // I_FACE x = 6, face 6 + {{6.,3.,0.}, {6.,6.,0.}, {6.,6.,1.}, {6.,3.,1.}}, // I_FACE x = 6, face 7 + {{0.,0.,0.}, {6.,0.,0.}, {6.,0.,8.}, {0.,0.,8.}}, // J_FACE y = 0, face 8 + {{0.,3.,0.}, {6.,3.,0.}, {6.,3.,8.}, {0.,3.,8.}}, // J_FACE y = 3, face 9 + {{0.,6.,0.}, {6.,6.,0.}, {6.,6.,8.}, {0.,6.,8.}}, // J_FACE y = 6, face 10 + {{6.,0.,1.}, {12.,0.,1.}, {12.,3.,1.}, {6.,3.,1.}}, // K_FACE z = 1, face 11 + {{6.,3.,1.}, {12.,3.,1.}, {12.,6.,1.}, {6.,6.,1.}}, // K_FACE z = 1, face 12 + {{6.,0.,9.}, {12.,0.,9.}, {12.,3.,9.}, {6.,3.,9.}}, // K_FACE z = 9, face 13 + {{6.,3.,9.}, {12.,3.,9.}, {12.,6.,9.}, {6.,6.,9.}}, // K_FACE z = 9, face 14 + {{6.,0.,1.}, {6.,3.,1.}, {6.,3.,8.}, {6.,0.,8.}}, // I_FACE x = 6, face 15 + {{6.,0.,8.}, {6.,3.,8.}, {6.,3.,9.}, {6.,0.,9.}}, // I_FACE x = 6, face 16 + {{6.,3.,1.}, {6.,6.,1.}, {6.,6.,8.}, {6.,3.,8.}}, // I_FACE x = 6, face 17 + {{6.,3.,8.}, {6.,6.,8.}, {6.,6.,9.}, {6.,3.,9.}}, // I_FACE x = 6, face 18 + {{12.,0.,1.}, {12.,3.,1.}, {12.,3.,9.}, {12.,0.,9.}}, // I_FACE x = 12, face 19 + {{12.,3.,1.}, {12.,6.,1.}, {12.,6.,9.}, {12.,3.,9.}}, // I_FACE x = 12, face 20 + {{6.,0.,1.}, {12.,0.,1.}, {12.,0.,9.}, {6.,0.,9.}}, // J_FACE y = 0, face 21 + {{6.,3.,1.}, {12.,3.,1.}, {12.,3.,9.}, {6.,3.,9.}}, // J_FACE y = 3, face 22 + {{6.,6.,1.}, {12.,6.,1.}, {12.,6.,9.}, {6.,6.,9.}}, // J_FACE y = 6, face 23 + }; + + checkFaces(refinedGrid1, expectedLGR1Faces); + checkFaces(refinedGrid2, expectedLGR2Faces); + checkFaces(leafGrid, expectedLeafFaces); + + Opm::checkGridWithLgrs(grid, + {{1,2,1}, {1,2,1}}, // cells_per_dim_vec + {"LGR1", "LGR2"}); // lgr_name_vec +} + + +BOOST_AUTO_TEST_CASE(simpleSameLgr) +{ + // Level zero grid dims = 2x1x1 + // + // cell 0 + // bottom face corners (0,0,0), (6,0,0), (0,6,0), (6,6,0) + // top face corners (0,0,8), (6,0,8), (0,6,8), (6,6,8) + // + // cell 1 + // bottom face corners (6,0,1), (12,0,1), (6,6,1), (12,6,1) + // top face corners (6,0,9), (12,0,9), (12,6,9), (12,6,9) + const std::string deckString = + R"(RUNSPEC +DIMENS + 2 1 1 / + +GRID + +COORD + 0 0 0 0 0 9 + 6 0 0 6 0 9 +12 0 0 12 0 9 + + 0 6 0 0 6 9 + 6 6 0 6 6 9 +12 6 0 12 6 9 +/ + +ZCORN +0 0 1 1 0 0 1 1 +8 8 9 9 8 8 9 9 +/ + +ACTNUM +2*1 +/ + +PORO +2*0.15 +/ +)"; + + Dune::CpGrid grid; + Opm::createGridAndAddLgrs(grid, + deckString, + /* cells_per_dim_vec */ {{1,2,1}}, + /* startIJK_vec */ {{0,0,0}}, + /* endIJK_vec */ {{2,1,1}}, + /* lgr_name_vec */ {"LGR1"}); + + // Element 0 and element 1 in level zero grid share an I_FACE (with face index 2) + // + // Vertices of those faces lie on the plane x = 6 | After refinement, number of subdivisions in + // | y- and z- directions: + // + // (6,0,9) -----------------(6,6,9) | (6,0,9) --(6,3,9)---(6,6,9) + // | face idx 3 | | | * | + // (6,0,8) ---------------- (6,6,8) | (6,0,8) --(6,3,9)---(6,6,8) + // | | | | * | + // | | | | * | + // | | | | * | + // | face idx 2 | | | * | + // | | | | * | + // | | | | * | + // | | | | * | + // | | | | * | + // (6,0,1) -----------------(6,6,1) | (6,0,1) --(6,3,1)---(6,6,1) + // | face idx 1 | | | * | + // (6,0,0) -----------------(6,6,0) | (6,0,0) --(6,3,0)---(6,6,0) + // | + const auto& parentGridData = *grid.currentData()[0]; + const auto parent0 = Dune::cpgrid::Entity<0>(parentGridData, 0, true); + const auto parent1 = Dune::cpgrid::Entity<0>(parentGridData, 1, true); + + BOOST_CHECK_EQUAL(parentGridData.cellToFace(parent0.index()).size(), 7); + BOOST_CHECK_EQUAL(parentGridData.cellToFace(parent1.index()).size(), 7); + + const auto& refinedGrid1 = *grid.currentData()[1]; + BOOST_CHECK_EQUAL( refinedGrid1.size(3), 24); + BOOST_CHECK_EQUAL( refinedGrid1.numFaces(), 24); + + const auto& leafGrid = grid.currentLeafData(); + BOOST_CHECK_EQUAL( leafGrid.size(3), 24); + BOOST_CHECK_EQUAL( leafGrid.numFaces(), 24); + + const std::set expectedVertices = { + {0.,0.,0.}, {0.,0.,8.}, // pillar x = 0, y = 0 + {6.,0.,0.}, {6.,0.,1.}, {6.,0.,8.}, {6.,0.,9.}, // pillar x = 6, y = 0 + {12.,0.,1.}, {12.,0.,9.}, // pillar x = 12, y = 0 + {0.,3.,0.}, {0.,3.,8.}, // pillar x = 0, y = 3 + {6.,3.,0.}, {6.,3.,1.}, {6.,3.,8.}, {6.,3.,9.}, // pillar x = 6, y = 3 + {12.,3.,1.}, {12.,3.,9.}, // pillar x = 12, y = 3 + {0.,6.,0.}, {0.,6.,8.}, // pillar x = 0, y = 6 + {6.,6.,0.}, {6.,6.,1.}, {6.,6.,8.}, {6.,6.,9.}, // pillar x = 6, y = 6 + {12.,6.,1.}, {12.,6.,9.} // pillar x = 12, y = 6 + }; + + checkLevelVertices(grid, std::vector{expectedVertices}); + checkLeafVertices(grid, expectedVertices); + + const std::vector> expectedFaces = { + {{0.,0.,0.}, {6.,0.,0.}, {6.,3.,0.}, {0.,3.,0.}}, // K_FACE z = 0, face 0 + {{0.,3.,0.}, {6.,3.,0.}, {6.,6.,0.}, {0.,6.,0.}}, // K_FACE z = 0, face 1 + {{0.,0.,8.}, {6.,0.,8.}, {6.,3.,8.}, {0.,3.,8.}}, // K_FACE z = 8, face 2 + {{0.,3.,8.}, {6.,3.,8.}, {6.,6.,8.}, {0.,6.,8.}}, // K_FACE z = 8, face 3 + {{0.,0.,0.}, {0.,3.,0.}, {0.,3.,8.}, {0.,0.,8.}}, // I_FACE x = 0, face 4 + {{0.,3.,0.}, {0.,6.,0.}, {0.,6.,8.}, {0.,3.,8.}}, // I_FACE x = 0, face 5 + {{6.,0.,0.}, {6.,3.,0.}, {6.,3.,1.}, {6.,0.,1.}}, // I_FACE x = 6, face 6 + {{6.,3.,0.}, {6.,6.,0.}, {6.,6.,1.}, {6.,3.,1.}}, // I_FACE x = 6, face 7 + {{0.,0.,0.}, {6.,0.,0.}, {6.,0.,8.}, {0.,0.,8.}}, // J_FACE y = 0, face 8 + {{0.,3.,0.}, {6.,3.,0.}, {6.,3.,8.}, {0.,3.,8.}}, // J_FACE y = 3, face 9 + {{0.,6.,0.}, {6.,6.,0.}, {6.,6.,8.}, {0.,6.,8.}}, // J_FACE y = 6, face 10 + {{6.,0.,1.}, {12.,0.,1.}, {12.,3.,1.}, {6.,3.,1.}}, // K_FACE z = 1, face 11 + {{6.,3.,1.}, {12.,3.,1.}, {12.,6.,1.}, {6.,6.,1.}}, // K_FACE z = 1, face 12 + {{6.,0.,9.}, {12.,0.,9.}, {12.,3.,9.}, {6.,3.,9.}}, // K_FACE z = 9, face 13 + {{6.,3.,9.}, {12.,3.,9.}, {12.,6.,9.}, {6.,6.,9.}}, // K_FACE z = 9, face 14 + {{6.,0.,1.}, {6.,3.,1.}, {6.,3.,8.}, {6.,0.,8.}}, // I_FACE x = 6, face 15 + {{6.,0.,8.}, {6.,3.,8.}, {6.,3.,9.}, {6.,0.,9.}}, // I_FACE x = 6, face 16 + {{6.,3.,1.}, {6.,6.,1.}, {6.,6.,8.}, {6.,3.,8.}}, // I_FACE x = 6, face 17 + {{6.,3.,8.}, {6.,6.,8.}, {6.,6.,9.}, {6.,3.,9.}}, // I_FACE x = 6, face 18 + {{12.,0.,1.}, {12.,3.,1.}, {12.,3.,9.}, {12.,0.,9.}}, // I_FACE x = 12, face 19 + {{12.,3.,1.}, {12.,6.,1.}, {12.,6.,9.}, {12.,3.,9.}}, // I_FACE x = 12, face 20 + {{6.,0.,1.}, {12.,0.,1.}, {12.,0.,9.}, {6.,0.,9.}}, // J_FACE y = 0, face 21 + {{6.,3.,1.}, {12.,3.,1.}, {12.,3.,9.}, {6.,3.,9.}}, // J_FACE y = 3, face 22 + {{6.,6.,1.}, {12.,6.,1.}, {12.,6.,9.}, {6.,6.,9.}}, // J_FACE y = 6, face 23 + }; + + checkFaces(refinedGrid1, expectedFaces); + checkFaces(leafGrid, expectedFaces); + + Opm::checkGridWithLgrs(grid, + {{1,2,1}}, // cells_per_dim_vec + {"LGR1"}); // lgr_name_vec +} diff --git a/tests/cpgrid/lgr/replace_lgr1_corner_idx_by_lgr2_corner_idx_test.cpp b/tests/cpgrid/lgr/replace_lgr1_corner_idx_by_lgr2_corner_idx_test.cpp deleted file mode 100644 index 8a5804290..000000000 --- a/tests/cpgrid/lgr/replace_lgr1_corner_idx_by_lgr2_corner_idx_test.cpp +++ /dev/null @@ -1,304 +0,0 @@ -/* - Copyright 2025 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 . -*/ -#include "config.h" - -#define BOOST_TEST_MODULE ReplaceCornerIdxNeighCellsTests -#include - -#include -#include -#include - -#include -#include -#include -#include - -struct Fixture -{ - Fixture() - { - int m_argc = boost::unit_test::framework::master_test_suite().argc; - char** m_argv = boost::unit_test::framework::master_test_suite().argv; - Dune::MPIHelper::instance(m_argc, m_argv); - Opm::OpmLog::setupSimpleDefaultLogging(); - } -}; - -BOOST_GLOBAL_FIXTURE(Fixture); - -/* To add LGRs in a CpGrid, each marked element for refinement gets refined into a - single-cell-refinement. To store new born refined entities [points or faces] - only once, we detect equivalent entities via their indices in each single-cell-refinement. - - To test replaceLgr1CornerIdxByLgr2CornerIdx(...), we create two grids, each of them - containing only one cell. Add different LGRs in each grid, in different cases to - create all possible escenarios (the two coarse cells sharing I_FACE, J_FACE or K_FACE). - - Why single-cell-refinements instead of adding LGRs in one grid?: - replaceLgr1CornerIdxByLgr2CornerIdx is used between two independent/un-related single-cell-refinements - (stored in CpGridData objects). Therefore, creating a grid, adding LGRs to it, and checking corner - indices afterwards in refined cells on bouandary of the LGRs is not the escenario where this method - should be tested. -*/ - -const std::shared_ptr createSingleCellGridAndRefine(const std::array& lgr_dim) -{ - // Create two grids, one single cell in each grid. - Dune::CpGrid lgr; - const std::array& cell_sizes = {1.0, 1.0, 1.0}; - const std::array& coarse_grid_dim = {1,1,1}; - lgr.createCartesian(coarse_grid_dim, cell_sizes); - - std::vector>>> faceInMarkedElemAndRefinedFaces{}; - faceInMarkedElemAndRefinedFaces.resize(6); - - // Single-cell-refinement for the only cell contained in lgr grid. - const auto& [lgr_ptr, - lgr_parentCorners_to_equivalentRefinedCorners] - = lgr.currentLeafData().refineSingleCell(lgr_dim, 0, faceInMarkedElemAndRefinedFaces); - return lgr_ptr; -} - -void checkOrderDoesNotMatterWhenReplaceCornerIdxOfSharedRefinedFaceBetweenSingleCellRefinements(const Dune::cpgrid::Entity<0>& elemLgrA, - const Dune::cpgrid::Entity<0>& elemLgrB, - const std::unordered_map& lgrA_to_lgrB, - const std::array& lgrA_dim, - const std::array& lgrB_dim) -{ - for (const auto& [idx_in_cell_lgrA, idx_in_cell_lgrB] : lgrA_to_lgrB) - { - const auto& corn_lgrA = elemLgrA.subEntity<3>( idx_in_cell_lgrA ).index(); - const auto& corn_lgrB = elemLgrB.subEntity<3>( idx_in_cell_lgrB ).index(); - - BOOST_CHECK_EQUAL( Opm::Lgr::replaceLgr1CornerIdxByLgr2CornerIdx(lgrA_dim, corn_lgrA, lgrB_dim), corn_lgrB); - BOOST_CHECK_EQUAL( Opm::Lgr::replaceLgr1CornerIdxByLgr2CornerIdx(lgrB_dim, corn_lgrB, lgrA_dim), corn_lgrA); - } -} - - -BOOST_AUTO_TEST_CASE(neighboring_singleCellRefinements_x) -{ - // lgr1 and lgr2 grids mimick single-cell-refinements sharing I_FACE: | 0 | 1 | - - // Refine grids lgr1 and lgr2. - const std::array& lgr1_dim = {3,3,3}; - const std::array& lgr2_dim = {4,3,3}; - // Number of subbivisions in y- and z- direction must coincide, when cells - // from different LGRs share I_FACEs. In x-direction, they can differ. - - const auto& lgr1_ptr = createSingleCellGridAndRefine(lgr1_dim); - const auto& lgr2_ptr = createSingleCellGridAndRefine(lgr2_dim); - - // Recall how the 8 corners of a cell are stored in cell_to_point_ - // 6 -- 7 TOP FACE - // / / - // 4 -- 5 - // 2 -- 3 BOTTOM FACE - // / / - // 0 -- 1 - const std::unordered_map& lgrLeft_to_lgrRight = {{1,0}, {3,2}, {5,4}, {7,6}}; - - // Illustration of cells on the boundary between LGR1 and LGR2, for k=1, - // if LGR1 refines cell 0 and LGR2 refined cell 1. - // LGR1 LGR2 - // 15 16 17 | 20 21 22 23 - // 12 13 14 | 16 17 18 19 - // 9 10 11 | 12 13 14 15 - - // elem 14 from lgr1 corners 1,2,5,7 - // should coincide with - // elem 16 from lgr2 corners 0,3,4,6 respectively. - const auto& elem14_lgr1 = Dune::cpgrid::Entity<0>(*(lgr1_ptr), 14, true); - const auto& elem16_lgr2 = Dune::cpgrid::Entity<0>(*(lgr2_ptr), 16, true); - - checkOrderDoesNotMatterWhenReplaceCornerIdxOfSharedRefinedFaceBetweenSingleCellRefinements(elem14_lgr1, - elem16_lgr2, - lgrLeft_to_lgrRight, - lgr1_dim, - lgr2_dim); - - // Illustration of cells on the boundary between LGR1 and LGR2, for k=1, - // if LGR2 refines cell 0 and LGR1 refines cell 1. - // LGR2 LGR1 - // 20 21 22 23 | 15 16 17 - // 16 17 18 19 | 12 13 14 - // 12 13 14 15 | 9 10 11 - - // elem 12 from lgr1 corners 1,2,5,7 - // should coincide with - // elem 19 from lgr2 corners 0,3,4,6 respectively. - const auto& elem19_lgr2 = Dune::cpgrid::Entity<0>(*(lgr2_ptr), 19, true); - const auto& elem12_lgr1 = Dune::cpgrid::Entity<0>(*(lgr1_ptr), 12, true); - - checkOrderDoesNotMatterWhenReplaceCornerIdxOfSharedRefinedFaceBetweenSingleCellRefinements(elem19_lgr2, - elem12_lgr1, - lgrLeft_to_lgrRight, - lgr2_dim, - lgr1_dim); - // lgr1 has (3+1)x(3+1)x(3+1) = 64 corners (with indices 0, ..., 63). - // lgr2 has (4+1)x(3+1)x(3+1) = 80 corners (with indices 0, ..., 79). - const auto& non_existing_corner = 80; // non exisitng corner index for both lgrs. - BOOST_CHECK_THROW( Opm::Lgr::replaceLgr1CornerIdxByLgr2CornerIdx(lgr1_dim, non_existing_corner, lgr2_dim), std::logic_error); - BOOST_CHECK_THROW( Opm::Lgr::replaceLgr1CornerIdxByLgr2CornerIdx(lgr2_dim, non_existing_corner, lgr1_dim), std::logic_error); -} - -BOOST_AUTO_TEST_CASE(neighboring_singleCellRefinements_y) -{ - // lgr1 and lgr2 mimick a coarse grid having 2 cells sharing J_FACE: - // / 1 / - // --- shared J_FACE - // / 0 / - // --- - - // Refine grids lgr1 and lgr2. - const std::array& lgr1_dim = {3,3,3}; - const std::array& lgr2_dim = {3,4,3}; - // Number of subbivisions in x- and z- direction must coincide, when cells - // from different LGRs share J_FACEs. In y-direction, they can differ. - const auto& lgr1_ptr = createSingleCellGridAndRefine(lgr1_dim); - const auto& lgr2_ptr = createSingleCellGridAndRefine(lgr2_dim); - - // Recall how the 8 corners of a cell are stored in cell_to_point_ - // 6 -- 7 TOP FACE - // / / - // 4 -- 5 - // 2 -- 3 BOTTOM FACE - // / / - // 0 -- 1 - const std::unordered_map& lgrBack_to_lgrFront = {{2,0}, {3,1}, {6,4}, {7,5}}; - - // Illustration of cells on the boundary between LGR1 and LGR2, for k=1, - // if LGR1 refines cell 0 and LGR2 refined cell 1. - // 21 22 23 LGR2 - // 18 19 20 - // 15 16 17 - // 12 13 14 - // --------- - // 15 16 17 LGR1 - // 12 13 14 - // 9 10 11 - - - // elem 16 from lgr1 corners 0,1,4,5 - // should coincide with - // elem 13 from lgr2 corners 2,3,6,7 respectively. - const auto& elem16_lgr1 = Dune::cpgrid::Entity<0>(*(lgr1_ptr), 16, true); - const auto& elem13_lgr2 = Dune::cpgrid::Entity<0>(*(lgr2_ptr), 13, true); - - checkOrderDoesNotMatterWhenReplaceCornerIdxOfSharedRefinedFaceBetweenSingleCellRefinements(elem16_lgr1, - elem13_lgr2, - lgrBack_to_lgrFront, - lgr1_dim, - lgr2_dim); - - // Illustration of cells on the boundary between LGR1 and LGR2, for k=1, - // if LGR1 refines cell 1 and LGR2 refined cell 0. - // 15 16 17 LGR1 - // 12 13 14 - // 9 10 11 - // ------- - // 21 22 23 LGR2 - // 18 19 20 - // 15 16 17 - // 12 13 14 - - // elem 10 from lgr1 corners 0,1,4,5 - // should coincide with - // elem 22 from lgr2 corners 2,3,6,7 respectively. - const auto& elem22_lgr2 = Dune::cpgrid::Entity<0>(*(lgr2_ptr), 22, true); - const auto& elem10_lgr1 = Dune::cpgrid::Entity<0>(*(lgr1_ptr), 10, true); - - checkOrderDoesNotMatterWhenReplaceCornerIdxOfSharedRefinedFaceBetweenSingleCellRefinements(elem22_lgr2, - elem10_lgr1, - lgrBack_to_lgrFront, - lgr2_dim, - lgr1_dim); -} - -BOOST_AUTO_TEST_CASE(neighboring_singleCellRefinements_z) -{ - // lgr1 and lgr2 mimick a coarse grid has 2 cells sharing K_FACE: - // / 1 / - // --- shared K_FACE - // / 0 / - // --- - - // Refine grids lgr1 and lgr2. - const std::array& lgr1_dim = {3,3,3}; - const std::array& lgr2_dim = {3,3,4}; - // Number of subbivisions in x- and y- direction must coincide, when cells - // from different LGRs share K_FACEs. In z-direction, they can differ. - const auto& lgr1_ptr = createSingleCellGridAndRefine(lgr1_dim); - const auto& lgr2_ptr = createSingleCellGridAndRefine(lgr2_dim); - - // Recall how the 8 corners of a cell are stored in cell_to_point_ - // 6 -- 7 TOP FACE - // / / - // 4 -- 5 - // 2 -- 3 BOTTOM FACE - // / / - // 0 -- 1 - const std::unordered_map& lgrTop_to_lgrBottom = {{4,0}, {5,1}, {6,2}, {7,3}}; - - // Illustration of cells on the boundary between LGR1 and LGR2, - // if LGR1 refines cell 1 and LGR2 refined cell 0. - // 6 7 8 LGR2 BOTTOM - // 3 4 5 - // 0 1 2 - // ------ - // 24 25 26 LGR1 TOP - // 21 22 23 - // 18 19 20 - - // elem 22 from lgr1 corners 4,5,6,7 - // should coincide with - // elem 4 from lgr2 corners 0,1,2,3 respectively. - const auto& elem22_lgr1 = Dune::cpgrid::Entity<0>(*(lgr1_ptr), 22, true); - const auto& elem4_lgr2 = Dune::cpgrid::Entity<0>(*(lgr2_ptr), 4, true); - - checkOrderDoesNotMatterWhenReplaceCornerIdxOfSharedRefinedFaceBetweenSingleCellRefinements(elem22_lgr1, - elem4_lgr2, - lgrTop_to_lgrBottom, - lgr1_dim, - lgr2_dim); - - // Illustration of cells on the boundary between LGR1 and LGR2, - // if LGR1 refines cell 1 and LGR2 refined cell 0. - // 6 7 8 LGR1 BOTTOM - // 3 4 5 - // 0 1 2 - // ------- - // 33 34 35 LGR2 TOP - // 30 31 32 - // 27 28 29 - - - // elem 4 from lgr1 corners 4,5,6,7 - // should coincide with - // elem 31 from lgr2 corners 0,1,2,3 respectively. - const auto& elem31_lgr2 = Dune::cpgrid::Entity<0>(*(lgr2_ptr), 31, true); - const auto& elem4_lgr1 = Dune::cpgrid::Entity<0>(*(lgr1_ptr), 4, true); - - checkOrderDoesNotMatterWhenReplaceCornerIdxOfSharedRefinedFaceBetweenSingleCellRefinements(elem31_lgr2, - elem4_lgr1, - lgrTop_to_lgrBottom, - lgr2_dim, - lgr1_dim); -} diff --git a/tests/cpgrid/lgr/replace_lgr1_face_idx_by_lgr2_face_idx_test.cpp b/tests/cpgrid/lgr/replace_lgr1_face_idx_by_lgr2_face_idx_test.cpp deleted file mode 100644 index bc1a029ea..000000000 --- a/tests/cpgrid/lgr/replace_lgr1_face_idx_by_lgr2_face_idx_test.cpp +++ /dev/null @@ -1,259 +0,0 @@ -/* - Copyright 2025 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 . -*/ -#include "config.h" - -#define BOOST_TEST_MODULE ReplaceLgr1FaceIdxByLgr2FaceIdxTests -#include - -#include -#include -#include - -#include -#include -#include - -struct Fixture -{ - Fixture() - { - int m_argc = boost::unit_test::framework::master_test_suite().argc; - char** m_argv = boost::unit_test::framework::master_test_suite().argv; - Dune::MPIHelper::instance(m_argc, m_argv); - Opm::OpmLog::setupSimpleDefaultLogging(); - } -}; - -BOOST_GLOBAL_FIXTURE(Fixture); - -/* To add LGRs in a CpGrid, each marked element for refinement gets refined into a - single-cell-refinement. To store new born refined entities [points or faces] - only once, we detect equivalent entities via their indices in each single-cell-refinement. - - To test replaceLgr1FaceIdxByLgr2FaceIdx(...), we create two grids, each of them - containing only one cell. Add different LGRs in each grid, in different cases to - create all possible escenarios (the two coarse cells sharing I_FACE, J_FACE or K_FACE). - - Why single-cell-refinements instead of adding LGRs in one grid?: - replaceLgr1FaceIdxByLgr2FaceIdx is used between two independent/un-related single-cell-refinements - (stored in CpGridData objects). Therefore, creating a grid, adding LGRs to it, and checking face - indices afterwards in refined cells on bouandary of the LGRs is not the escenario where this - method should be tested. -*/ - -const std::shared_ptr createSingleCellGridAndRefine(const std::array& lgr_dim) -{ - Dune::CpGrid lgr; - // Create a single-cell-grid - const std::array& cell_sizes = {1.0, 1.0, 1.0}; - const std::array& coarse_grid_dim = {1,1,1}; - lgr.createCartesian(coarse_grid_dim, cell_sizes); - - std::vector>>> faceInMarkedElemAndRefinedFaces{}; - faceInMarkedElemAndRefinedFaces.resize(6); - - // Single-cell-refinement for the only cell contained in lgr grid. - const auto& [lgr_ptr, - lgr_parentCorners_to_equivalentRefinedCorners] - = lgr.currentLeafData().refineSingleCell(lgr_dim, 0, faceInMarkedElemAndRefinedFaces); - return lgr_ptr; -} - -BOOST_AUTO_TEST_CASE(neighboring_singleCellRefinements_x) -{ - // lgr1 and lgr2 grids mimick single-cell-refinements sharing I_FACE: | 0 | 1 | - - // Refine grids lgr1 and lgr2. - const std::array& lgr1_dim = {3,3,3}; - const std::array& lgr2_dim = {4,3,3}; - // Number of subbivisions in y- and z- direction must coincide, when cells - // from different LGRs share I_FACEs. In x-direction, they can differ. - - const auto& lgr1_ptr = createSingleCellGridAndRefine(lgr1_dim); - const auto& lgr2_ptr = createSingleCellGridAndRefine(lgr2_dim); - - // Illustration of cells on the boundary between LGR1 and LGR2, for k=1, - // if LGR1 refines cell 0 and LGR2 refined cell 1. - // LGR1 LGR2 - // 15 16 17 | 20 21 22 23 - // 12 13 14 | 16 17 18 19 - // 9 10 11 | 12 13 14 15 - - // elem 14 from lgr1 face {I true} - // should coincide with - // elem 16 from lgr2 face {I false} - - // Recall how the 6 faces of a cell are stored in cell_to_face_ - // in Geometry::refine - // cell_to_face_ [ element ] = {{K false}, {J false}, {I false}, {I true}, {J true}, {K true}}. - const auto& faceTrue_lgr1 = lgr1_ptr-> cellFace( /*elemIdx*/ 14, /*local face index*/ 3); // I true for elem14_lgr1 - const auto& faceFalse_lgr2 = lgr2_ptr -> cellFace( /*elemIdx*/ 16, /*local face index*/ 2); // I false for elem16_lgr2 - - BOOST_CHECK_EQUAL( Opm::Lgr::replaceLgr1FaceIdxByLgr2FaceIdx(lgr1_dim, faceTrue_lgr1, lgr1_ptr, lgr2_dim), faceFalse_lgr2); - BOOST_CHECK_EQUAL( Opm::Lgr::replaceLgr1FaceIdxByLgr2FaceIdx(lgr2_dim, faceFalse_lgr2, lgr2_ptr, lgr1_dim), faceTrue_lgr1); - - // Illustration of cells on the boundary between LGR1 and LGR2, for k=1, - // if LGR2 refines cell 0 and LGR1 refines cell 1. - // LGR2 LGR1 - // 20 21 22 23 | 15 16 17 - // 16 17 18 19 | 12 13 14 - // 12 13 14 15 | 9 10 11 - - // elem 12 from lgr1 face {I true} - // should coincide with - // elem 19 from lgr2 face {I false} - - const auto& faceTrue_lgr2 = lgr2_ptr-> cellFace( /*elemIdx*/ 19, /*local face index*/ 3);; // I true for elem19_lgr2 - const auto& faceFalse_lgr1 = lgr1_ptr -> cellFace( /*elemIdx*/ 12, /*local face index*/ 2); // I false for elem12_lgr1 - - BOOST_CHECK_EQUAL( Opm::Lgr::replaceLgr1FaceIdxByLgr2FaceIdx(lgr2_dim, faceTrue_lgr2, lgr2_ptr, lgr1_dim), faceFalse_lgr1); - BOOST_CHECK_EQUAL( Opm::Lgr::replaceLgr1FaceIdxByLgr2FaceIdx(lgr1_dim, faceFalse_lgr1, lgr1_ptr, lgr2_dim), faceTrue_lgr2); - - // lgr1 has 108 faces (with indices 0, ..., 107). - // lgr2 has 141 faces (with indices 0, ..., 140). - const auto& non_existing_face = 141; // non exisitng face index for both lgrs. - BOOST_CHECK_THROW( Opm::Lgr::replaceLgr1FaceIdxByLgr2FaceIdx(lgr1_dim, non_existing_face, lgr1_ptr, lgr2_dim), std::logic_error); - BOOST_CHECK_THROW( Opm::Lgr::replaceLgr1FaceIdxByLgr2FaceIdx(lgr2_dim, non_existing_face, lgr2_ptr, lgr1_dim), std::logic_error); -} - -BOOST_AUTO_TEST_CASE(neighboring_singleCellRefinements_y) -{ - // lgr1 and lgr2 mimick a coarse grid having 2 cells sharing J_FACE: - // / 1 / - // --- shared J_FACE - // / 0 / - // --- - - // Refine grids lgr1 and lgr2. - const std::array& lgr1_dim = {3,3,3}; - const std::array& lgr2_dim = {3,4,3}; - // Number of subbivisions in x- and z- direction must coincide, when cells - // from different LGRs share J_FACEs. In y-direction, they can differ. - const auto& lgr1_ptr = createSingleCellGridAndRefine(lgr1_dim); - const auto& lgr2_ptr = createSingleCellGridAndRefine(lgr2_dim); - - // Illustration of cells on the boundary between LGR1 and LGR2, for k=1, - // if LGR1 refines cell 0 and LGR2 refined cell 1. - // 21 22 23 LGR2 - // 18 19 20 - // 15 16 17 - // 12 13 14 - // --------- - // 15 16 17 LGR1 - // 12 13 14 - // 9 10 11 - - // elem 16 from lgr1 face {J true} - // should coincide with - // elem 13 from lgr2 face {J false} - - // Recall how the 6 faces of a cell are stored in cell_to_face_ - // in Geometry::refine - // cell_to_face_ [ element ] = {{K false}, {J false}, {I false}, {I true}, {J true}, {K true}}. - const auto& faceTrue_lgr1 = lgr1_ptr-> cellFace( /*elemIdx*/ 16, /*local face index*/ 4); // J true for elem16_lgr1 - const auto& faceFalse_lgr2 = lgr2_ptr -> cellFace( /*elemIdx*/ 13, /*local face index*/ 1); // J false for elem13_lgr2 - - BOOST_CHECK_EQUAL( Opm::Lgr::replaceLgr1FaceIdxByLgr2FaceIdx(lgr1_dim, faceTrue_lgr1, lgr1_ptr, lgr2_dim), faceFalse_lgr2); - BOOST_CHECK_EQUAL( Opm::Lgr::replaceLgr1FaceIdxByLgr2FaceIdx(lgr2_dim, faceFalse_lgr2, lgr2_ptr, lgr1_dim), faceTrue_lgr1); - - - // Illustration of cells on the boundary between LGR1 and LGR2, for k=1, - // if LGR1 refines cell 1 and LGR2 refined cell 0. - // 15 16 17 LGR1 - // 12 13 14 - // 9 10 11 - // ------- - // 21 22 23 LGR2 - // 18 19 20 - // 15 16 17 - // 12 13 14 - - // elem 10 from lgr1 face {J false} - // should coincide with - // elem 22 from lgr2 face {J true} - - const auto& faceTrue_lgr2 = lgr2_ptr-> cellFace( /*elemIdx*/ 22, /*local face index*/ 4); // J true for elem22_lgr2 - const auto& faceFalse_lgr1 = lgr1_ptr -> cellFace( /*elemIdx*/ 10, /*local face index*/ 1); // J false for elem10_lgr1 - - BOOST_CHECK_EQUAL( Opm::Lgr::replaceLgr1FaceIdxByLgr2FaceIdx(lgr2_dim, faceTrue_lgr2, lgr2_ptr, lgr1_dim), faceFalse_lgr1); - BOOST_CHECK_EQUAL( Opm::Lgr::replaceLgr1FaceIdxByLgr2FaceIdx(lgr1_dim, faceFalse_lgr1, lgr1_ptr, lgr2_dim), faceTrue_lgr2); - -} - -BOOST_AUTO_TEST_CASE(neighboring_singleCellRefinements_z) -{ - // lgr1 and lgr2 mimick a coarse grid has 2 cells sharing K_FACE: - // / 1 / - // --- shared K_FACE - // / 0 / - // --- - - // Refine grids lgr1 and lgr2. - const std::array& lgr1_dim = {3,3,3}; - const std::array& lgr2_dim = {3,3,4}; - // Number of subbivisions in x- and y- direction must coincide, when cells - // from different LGRs share K_FACEs. In z-direction, they can differ. - const auto& lgr1_ptr = createSingleCellGridAndRefine(lgr1_dim); - const auto& lgr2_ptr = createSingleCellGridAndRefine(lgr2_dim); - - // Illustration of cells on the boundary between LGR1 and LGR2, - // if LGR1 refines cell 1 and LGR2 refined cell 0. - // 6 7 8 LGR2 BOTTOM - // 3 4 5 - // 0 1 2 - // ------ - // 24 25 26 LGR1 TOP - // 21 22 23 - // 18 19 20 - - // elem 22 from lgr1 {K true} - // should coincide with - // elem 4 from lgr2 {K false} - - // Recall how the 6 faces of a cell are stored in cell_to_face_ - // in Geometry::refine - // cell_to_face_ [ element ] = {{K false}, {J false}, {I false}, {I true}, {J true}, {K true}}. - const auto& faceTrue_lgr1 = lgr1_ptr-> cellFace( /*elemIdx*/ 22, /*local face index*/ 5); // J true for elem22_lgr1 - const auto& faceFalse_lgr2 = lgr2_ptr -> cellFace( /*elemIdx*/ 4, /*local face index*/ 0); // K false for elem4_lgr2 - - BOOST_CHECK_EQUAL( Opm::Lgr::replaceLgr1FaceIdxByLgr2FaceIdx(lgr1_dim, faceTrue_lgr1, lgr1_ptr, lgr2_dim), faceFalse_lgr2); - BOOST_CHECK_EQUAL( Opm::Lgr::replaceLgr1FaceIdxByLgr2FaceIdx(lgr2_dim, faceFalse_lgr2, lgr2_ptr, lgr1_dim), faceTrue_lgr1); - - - // Illustration of cells on the boundary between LGR1 and LGR2, - // if LGR1 refines cell 1 and LGR2 refined cell 0. - // 6 7 8 LGR1 BOTTOM - // 3 4 5 - // 0 1 2 - // ------- - // 33 34 35 LGR2 TOP - // 30 31 32 - // 27 28 29 - - - // elem 4 from lgr1 face {K false} - // should coincide with - // elem 31 from lgr2 {K true} - - const auto& faceTrue_lgr2 = lgr2_ptr-> cellFace( /*elemIdx*/ 31, /*local face index*/ 5);; // K true for elem31_lgr2 - const auto& faceFalse_lgr1 = lgr1_ptr -> cellFace( /*elemIdx*/ 4, /*local face index*/ 0); // K false for elem4_lgr1 - - BOOST_CHECK_EQUAL( Opm::Lgr::replaceLgr1FaceIdxByLgr2FaceIdx(lgr2_dim, faceTrue_lgr2, lgr2_ptr, lgr1_dim), faceFalse_lgr1); - BOOST_CHECK_EQUAL( Opm::Lgr::replaceLgr1FaceIdxByLgr2FaceIdx(lgr1_dim, faceFalse_lgr1, lgr1_ptr, lgr2_dim), faceTrue_lgr2); -} From 3f172ed3c922dc20b29dbc6266e5481b53cf9933 Mon Sep 17 00:00:00 2001 From: Antonella Ritorto Date: Mon, 10 Aug 2026 17:00:02 +0200 Subject: [PATCH 2/3] Fix search corner/refined faces --- CMakeLists_files.cmake | 2 +- opm/grid/cpgrid/LgrHelpers.cpp | 149 +- opm/grid/cpgrid/LgrHelpers.hpp | 1 - ...ions_test.cpp => lgrs_and_faults_test.cpp} | 1553 ++++++++--------- 4 files changed, 804 insertions(+), 901 deletions(-) rename tests/cpgrid/lgr/{compute_new_vertices_of_overlapping_intersections_test.cpp => lgrs_and_faults_test.cpp} (93%) diff --git a/CMakeLists_files.cmake b/CMakeLists_files.cmake index b7a51130c..651848c97 100644 --- a/CMakeLists_files.cmake +++ b/CMakeLists_files.cmake @@ -113,7 +113,7 @@ list(APPEND TEST_SOURCE_FILES tests/cpgrid/lgr/addLgrs_in_allActiveCartesianGrid_test.cpp tests/cpgrid/lgr/addLgrsOnDistributedGrid_test.cpp tests/cpgrid/lgr/autoRefine_test.cpp - tests/cpgrid/lgr/compute_new_vertices_of_overlapping_intersections_test.cpp + tests/cpgrid/lgr/lgrs_and_faults_test.cpp tests/cpgrid/lgr/global_refine_test.cpp tests/cpgrid/lgr/id_entity_entityrep_test.cpp tests/cpgrid/lgr/level_and_grid_cartesianIndexMappers_test.cpp diff --git a/opm/grid/cpgrid/LgrHelpers.cpp b/opm/grid/cpgrid/LgrHelpers.cpp index f408d4751..d0657afa1 100644 --- a/opm/grid/cpgrid/LgrHelpers.cpp +++ b/opm/grid/cpgrid/LgrHelpers.cpp @@ -1278,6 +1278,20 @@ void populateRefinedFaces(std::vector>>& cornerInMarkedElemWithEquivRefinedCorner, const std::map,int>& markedElemAndEquivRefinedCorn_to_corner) { + + auto findCornerIdx = [&](const Dune::FieldVector& w) { + for (const auto& [_, lastCellAndCorner] : vanishedRefinedCorner_to_itsLastAppearance) { + const auto v = Dune::cpgrid::Entity<3>(*markedElem_to_itsLgr[lastCellAndCorner[0]], lastCellAndCorner[1], true).geometry().center(); + if (!Opm::Lgr::areClose(w,v)) { + continue; + } + else { + return lastCellAndCorner; + } + } + return std::array{-1,-1}; + }; + for (std::size_t shiftedLevel = 0; shiftedLevel < refined_face_count_vec.size(); ++shiftedLevel) { // Store the refined faces refined_faces_vec[shiftedLevel].resize(refined_face_count_vec[shiftedLevel]); @@ -1309,6 +1323,8 @@ void populateRefinedFaces(std::vectorsecond].back(); } - else { - // To locate vanished corners, we need a while-loop, since {elemLgr, elemLgrcorner} leads to - // {neighboringElemLgr, neighboringElemLgrCornerIdx}, which might have also vanished. - // Then, use the lastest appearance of the current corner, meaning, the first (and unique one - by construction) that - // gives elemLgrAndElemLgrCorner_to_refinedCorner.count(lastAppearanceLgr_lgrCorner) == 1). - // This corner lies on the area occupied by a coarse face that got refined and belonged to two marked elements. - // Get the index of this corner with respect to the greatest marked element index, using find instead of count. - lastAppearanceLgr_lgrEquivCorner = vanishedRefinedCorner_to_itsLastAppearance.at({elemLgr, elemLgrCorn}); + else if(auto corner_candidate_2 = vanishedRefinedCorner_to_itsLastAppearance.find({elemLgr, elemLgrCorn}); + corner_candidate_2 != vanishedRefinedCorner_to_itsLastAppearance.end()) { + + lastAppearanceLgr_lgrEquivCorner = corner_candidate_2->second; // vanishedRefinedCorner_to_itsLastAppearance.at({elemLgr, elemLgrCorn}); while (elemLgrAndElemLgrCorner_to_refinedLevelAndRefinedCorner.find(lastAppearanceLgr_lgrEquivCorner) == elemLgrAndElemLgrCorner_to_refinedLevelAndRefinedCorner.end()) { const auto& tempLgr_lgrCorner = lastAppearanceLgr_lgrEquivCorner; lastAppearanceLgr_lgrEquivCorner = vanishedRefinedCorner_to_itsLastAppearance.at(tempLgr_lgrCorner); } } + else { + const Dune::FieldVector vertex = Dune::cpgrid::Entity<3>(*markedElem_to_itsLgr[elemLgr], elemLgrCorn, true).geometry().center(); + lastAppearanceLgr_lgrEquivCorner = findCornerIdx(vertex); + assert(lastAppearanceLgr_lgrEquivCorner[0]>=0); + assert(lastAppearanceLgr_lgrEquivCorner[1]>=0); + } refinedCorn = elemLgrAndElemLgrCorner_to_refinedLevelAndRefinedCorner.at(lastAppearanceLgr_lgrEquivCorner)[1]; } aux_refined_face_to_point[face].push_back(refinedCorn); @@ -1369,6 +1387,19 @@ void populateRefinedCells(const Dune::cpgrid::CpGridData& current_data, const std::vector>>& cornerInMarkedElemWithEquivRefinedCorner, const std::vector& cellRefinementsInfo) { + auto findCornerIdx = [&](const Dune::FieldVector& w) { + for (const auto& [_, lastCellAndCorner] : vanishedRefinedCorner_to_itsLastAppearance) { + const auto v = Dune::cpgrid::Entity<3>(*markedElem_to_itsLgr[lastCellAndCorner[0]], lastCellAndCorner[1], true).geometry().center(); + if (!Opm::Lgr::areClose(w,v)) { + continue; + } + else { std::cout<< v[0]<< " " << v[1] << " " << v[2] <{-1,-1}; + }; + // --- Refined cells --- for (std::size_t shiftedLevel = 0; shiftedLevel < refined_cell_count_vec.size(); ++shiftedLevel) { @@ -1408,16 +1439,21 @@ void populateRefinedCells(const Dune::cpgrid::CpGridData& current_data, lastAppearanceLgr_lgrCorner = cornerInMarkedElemWithEquivRefinedCorner[candidate->second].back(); } else { - // To locate vanished corners, we need a while-loop, since {elemLgr, elemLgrcorner} leads to - // {neighboringElemLgr, neighboringElemLgrCornerIdx}, which might have also vanished. - // Then, use the lastest appearance of the current corner, meaning, the first (and unique one - by construction) that - // gives elemLgrAndElemLgrCorner_to_adaptedCorner.count( lastAppearanceLgr_lgrCorner ) == 1). - // This corner lies on the area occupied by a coarse face that got refined and belonged to two marked elements. - // Get the index of this corner with respect to the greatest marked element index. - lastAppearanceLgr_lgrCorner = vanishedRefinedCorner_to_itsLastAppearance.at({elemLgr, preAdaptCorn}); - while (elemLgrAndElemLgrCorner_to_refinedLevelAndRefinedCorner.find(lastAppearanceLgr_lgrCorner) == elemLgrAndElemLgrCorner_to_refinedLevelAndRefinedCorner.end()) { - const auto& tempLgr_lgrCorner = lastAppearanceLgr_lgrCorner; - lastAppearanceLgr_lgrCorner = vanishedRefinedCorner_to_itsLastAppearance.at(tempLgr_lgrCorner); + if(auto corner_candidate_2 = vanishedRefinedCorner_to_itsLastAppearance.find({elemLgr, preAdaptCorn}); + corner_candidate_2 != vanishedRefinedCorner_to_itsLastAppearance.end()) { + + lastAppearanceLgr_lgrCorner = corner_candidate_2->second; // vanishedRefinedCorner_to_itsLastAppearance.at({elemLgr, elemLgrCorn}); + while (elemLgrAndElemLgrCorner_to_refinedLevelAndRefinedCorner.find(lastAppearanceLgr_lgrCorner) == + elemLgrAndElemLgrCorner_to_refinedLevelAndRefinedCorner.end()) { + const auto& tempLgr_lgrCorner = lastAppearanceLgr_lgrCorner; + lastAppearanceLgr_lgrCorner = vanishedRefinedCorner_to_itsLastAppearance.at(tempLgr_lgrCorner); + } + } + else { + const auto vertex = Dune::cpgrid::Entity<3>(*markedElem_to_itsLgr[elemLgr], preAdaptCorn, true).geometry().center(); + lastAppearanceLgr_lgrCorner = findCornerIdx(vertex); + assert(lastAppearanceLgr_lgrCorner[0]>=0); + assert(lastAppearanceLgr_lgrCorner[1]>=0); } } refinedCorn = elemLgrAndElemLgrCorner_to_refinedLevelAndRefinedCorner.at(lastAppearanceLgr_lgrCorner)[1]; @@ -1511,6 +1547,19 @@ void populateLeafGridFaces(const Dune::cpgrid::CpGridData& current_data, [[maybe_unused]] const std::vector>& cells_per_dim_vec, [[maybe_unused]] const int& preAdaptMaxLevel) { + auto findCornerIdx = [&](const Dune::FieldVector& w) { + for (const auto& [_, lastCellAndCorner] : vanishedRefinedCorner_to_itsLastAppearance) { + const auto v = Dune::cpgrid::Entity<3>(*markedElem_to_itsLgr[lastCellAndCorner[0]], lastCellAndCorner[1], true).geometry().center(); + if (!Opm::Lgr::areClose(w,v)) { + continue; + } + else { std::cout<< v[0]<< " " << v[1] << " " << v[2] <{-1,-1}; + }; + adapted_faces.resize(face_count); mutable_face_tags.resize(face_count); mutable_face_normals.resize(face_count); @@ -1564,16 +1613,22 @@ void populateLeafGridFaces(const Dune::cpgrid::CpGridData& current_data, elemLgrCorn); assert(!isNewRefinedCornInInteriorLgr); #endif - // To locate vanished corners, we need a while-loop, since {elemLgr, elemLgrcorner} leads to - // {neighboringElemLgr, neighboringElemLgrCornerIdx}, which might have also vanished. - // Then, use the lastest appearance of the current corner, meaning, the first (and unique one - by construction) that - // gives elemLgrAndElemLgrCorner_to_adaptedCorner.count(lastAppearanceLgr_lgrEquivCorner) == 1). - // This corner lies on the area occupied by a coarse face that got refined and belonged to two marked elements. - // Get the index of this corner with respect to the greatest marked element index, using find instead of count. - lastAppearanceLgr_lgrEquivCorner = vanishedRefinedCorner_to_itsLastAppearance.at({elemLgr, elemLgrCorn}); - while (elemLgrAndElemLgrCorner_to_adaptedCorner.find( lastAppearanceLgr_lgrEquivCorner ) == elemLgrAndElemLgrCorner_to_adaptedCorner.end()) { - const auto& tempLgr_lgrCorner = lastAppearanceLgr_lgrEquivCorner; - lastAppearanceLgr_lgrEquivCorner = vanishedRefinedCorner_to_itsLastAppearance.at(tempLgr_lgrCorner); + + if(auto corner_candidate_2 = vanishedRefinedCorner_to_itsLastAppearance.find({elemLgr, elemLgrCorn}); + corner_candidate_2 != vanishedRefinedCorner_to_itsLastAppearance.end()) { + + lastAppearanceLgr_lgrEquivCorner = corner_candidate_2->second; // vanishedRefinedCorner_to_itsLastAppearance.at({elemLgr, elemLgrCorn}); + while (elemLgrAndElemLgrCorner_to_adaptedCorner.find(lastAppearanceLgr_lgrEquivCorner) == + elemLgrAndElemLgrCorner_to_adaptedCorner.end()) { + const auto& tempLgr_lgrCorner = lastAppearanceLgr_lgrEquivCorner; + lastAppearanceLgr_lgrEquivCorner = vanishedRefinedCorner_to_itsLastAppearance.at(tempLgr_lgrCorner); + } + } + else { + const auto vertex = Dune::cpgrid::Entity<3>(*markedElem_to_itsLgr[elemLgr], elemLgrCorn, true).geometry().center(); + lastAppearanceLgr_lgrEquivCorner = findCornerIdx(vertex); + assert(lastAppearanceLgr_lgrEquivCorner[0]>=0); + assert(lastAppearanceLgr_lgrEquivCorner[1]>=0); } } } // end-if(elemLgr>-1) @@ -1606,6 +1661,19 @@ void populateLeafGridCells(const Dune::cpgrid::CpGridData& current_data, const std::vector>>& cornerInMarkedElemWithEquivRefinedCorner, const std::vector& cellRefinementsInfo) { + auto findCornerIdx = [&](const Dune::FieldVector& w) { + for (const auto& [_, lastCellAndCorner] : vanishedRefinedCorner_to_itsLastAppearance) { + const auto v = Dune::cpgrid::Entity<3>(*markedElem_to_itsLgr[lastCellAndCorner[0]], lastCellAndCorner[1], true).geometry().center(); + if (!Opm::Lgr::areClose(w,v)) { + continue; + } + else { std::cout<< v[0]<< " " << v[1] << " " << v[2] <{-1,-1}; + }; + // Store the adapted cells. Main difficulty: to lookup correctly the indices of the corners and faces of each cell. adapted_cells.resize(cell_count); adapted_cell_to_point.resize(cell_count); @@ -1647,16 +1715,21 @@ void populateLeafGridCells(const Dune::cpgrid::CpGridData& current_data, lastAppearanceLgr_lgrEquivCorner = cornerInMarkedElemWithEquivRefinedCorner[candidate->second].back(); } else { - // To locate vanished corners, we need a while-loop, since {elemLgr, elemLgrcorner} leads to - // {neighboringElemLgr, neighboringElemLgrCornerIdx}, which might have also vanished. - // Then, use the lastest appearance of the current corner, meaning, the first (and unique one - by construction) that - // gives elemLgrAndElemLgrCorner_to_adaptedCorner.count( lastAppearanceLgr_lgrEquivCorner ) == 1). - // This corner lies on the area occupied by a coarse face that got refined and belonged to two marked elements. - // Get the index of this corner with respect to the greatest marked element index. - lastAppearanceLgr_lgrEquivCorner = vanishedRefinedCorner_to_itsLastAppearance.at({elemLgr, preAdaptCorn}); - while (elemLgrAndElemLgrCorner_to_adaptedCorner.find(lastAppearanceLgr_lgrEquivCorner) == elemLgrAndElemLgrCorner_to_adaptedCorner.end()) { - const auto& tempLgr_lgrCorner = lastAppearanceLgr_lgrEquivCorner; - lastAppearanceLgr_lgrEquivCorner = vanishedRefinedCorner_to_itsLastAppearance.at(tempLgr_lgrCorner); + if(auto corner_candidate_2 = vanishedRefinedCorner_to_itsLastAppearance.find({elemLgr, preAdaptCorn}); + corner_candidate_2 != vanishedRefinedCorner_to_itsLastAppearance.end()) { + + lastAppearanceLgr_lgrEquivCorner = corner_candidate_2->second; // vanishedRefinedCorner_to_itsLastAppearance.at({elemLgr, elemLgrCorn}); + while (elemLgrAndElemLgrCorner_to_adaptedCorner.find(lastAppearanceLgr_lgrEquivCorner) == + elemLgrAndElemLgrCorner_to_adaptedCorner.end()) { + const auto& tempLgr_lgrCorner = lastAppearanceLgr_lgrEquivCorner; + lastAppearanceLgr_lgrEquivCorner = vanishedRefinedCorner_to_itsLastAppearance.at(tempLgr_lgrCorner); + } + } + else { + const auto vertex = Dune::cpgrid::Entity<3>(*markedElem_to_itsLgr[elemLgr], preAdaptCorn, true).geometry().center(); + lastAppearanceLgr_lgrEquivCorner = findCornerIdx(vertex); + assert(lastAppearanceLgr_lgrEquivCorner[0]>=0); + assert(lastAppearanceLgr_lgrEquivCorner[1]>=0); } } } diff --git a/opm/grid/cpgrid/LgrHelpers.hpp b/opm/grid/cpgrid/LgrHelpers.hpp index 1fd74722e..9b8a3c27e 100644 --- a/opm/grid/cpgrid/LgrHelpers.hpp +++ b/opm/grid/cpgrid/LgrHelpers.hpp @@ -464,7 +464,6 @@ void populateRefinedFaces(std::vector>>& cornerInMarkedElemWithEquivRefinedCorner, const std::map,int>& markedElemAndEquivRefinedCorn_to_corner); - /// @brief Define the cells, cell_to_point_, global_cell_, cell_to_face_, face_to_cell_, for each refined level grid. void populateRefinedCells(const Dune::cpgrid::CpGridData& current_data, std::vector>>& refined_cells_vec, diff --git a/tests/cpgrid/lgr/compute_new_vertices_of_overlapping_intersections_test.cpp b/tests/cpgrid/lgr/lgrs_and_faults_test.cpp similarity index 93% rename from tests/cpgrid/lgr/compute_new_vertices_of_overlapping_intersections_test.cpp rename to tests/cpgrid/lgr/lgrs_and_faults_test.cpp index 1c360c34f..dae08bea2 100644 --- a/tests/cpgrid/lgr/compute_new_vertices_of_overlapping_intersections_test.cpp +++ b/tests/cpgrid/lgr/lgrs_and_faults_test.cpp @@ -18,7 +18,7 @@ */ #include "config.h" -#define BOOST_TEST_MODULE ParentCellWithMoreThanOneFacePerTypeTests +#define BOOST_TEST_MODULE LgrWithFaultsTests #include #include @@ -30,9 +30,10 @@ #include - #include + + struct Fixture { Fixture() @@ -46,6 +47,19 @@ struct Fixture BOOST_GLOBAL_FIXTURE(Fixture); +// Test that corner and face relationships are correctly updated when +// LGRs are refined in the presence of faults. +// +// The tests use three basic deck configurations: 2x1x1, 1x2x1, and 2x1x2. +// The grid cells are shifted such that every cell in the level-zero grid +// has seven faces. Normally, a cell has one face of each type +// (I-, I+, J-, J+, K-, K+), but faults can cause a cell to have multiple +// faces of the same type. +// +// These grids are refined in different ways to cover several cases, +// including refining both cells, refining only one cell, an LGR containing +// a fault, and multiple LGRs whose boundaries coincide with faults. + using Coordinate = Dune::FieldVector; @@ -256,20 +270,17 @@ void checkFaces(const Dune::cpgrid::CpGridData& gridData, BOOST_CHECK(equalFaces(actualFaces, expectedFaces)); } - -BOOST_AUTO_TEST_CASE(parentCellWithMoreThanOne_I_FACE_trueOriented_nonTrivialOverlap) -{ - // Level zero grid dims = 2x1x1 - // - // cell 0 - // bottom face corners (0,0,0), (6,0,0), (0,6,0), (6,6,0) - // top face corners (0,0,8), (6,0,8), (0,6,8), (6,6,8) - // - // cell 1 - // bottom face corners (6,0,1), (12,0,1), (6,6,1), (12,6,1) - // top face corners (6,0,9), (12,0,9), (12,6,9), (12,6,9) - const std::string deckString = - R"(RUNSPEC +// Level zero grid dims = 2x1x1 +// +// cell 0 +// bottom face corners (0,0,0), (6,0,0), (0,6,0), (6,6,0) +// top face corners (0,0,8), (6,0,8), (0,6,8), (6,6,8) +// +// cell 1 +// bottom face corners (6,0,1), (12,0,1), (6,6,1), (12,6,1) +// top face corners (6,0,9), (12,0,9), (12,6,9), (12,6,9) +const std::string deckTwoCellsInXDirGrid = + R"(RUNSPEC DIMENS 2 1 1 / @@ -280,9 +291,9 @@ COORD 6 0 0 6 0 9 12 0 0 12 0 9 - 0 6 0 0 6 9 - 6 6 0 6 6 9 -12 6 0 12 6 9 + 0 6 0 0 6 9 + 6 6 0 6 6 9 +12 6 0 12 6 9 / ZCORN @@ -299,9 +310,12 @@ PORO / )"; + +BOOST_AUTO_TEST_CASE(parentCellWithMoreThanOne_I_FACE_trueOriented_nonTrivialOverlap) +{ Dune::CpGrid grid; Opm::createGridAndAddLgrs(grid, - deckString, + deckTwoCellsInXDirGrid, /* cells_per_dim_vec */ {{2,3,2}}, /* startIJK_vec */ {{0,0,0}}, /* endIJK_vec */ {{1,1,1}}, @@ -449,49 +463,9 @@ PORO BOOST_AUTO_TEST_CASE(parentCellWithMoreThanOne_I_FACE_trueOriented_trivialOverlap) { - // Level zero grid dims = 2x1x1 - // - // cell 0 - // bottom face corners (0,0,0), (6,0,0), (0,6,0), (6,6,0) - // top face corners (0,0,8), (6,0,8), (0,6,8), (6,6,8) - // - // cell 1 - // bottom face corners (6,0,1), (12,0,1), (6,6,1), (12,6,1) - // top face corners (6,0,9), (12,0,9), (12,6,9), (12,6,9) - const std::string deckString = - R"(RUNSPEC -DIMENS - 2 1 1 / - -GRID - -COORD - 0 0 0 0 0 9 - 6 0 0 6 0 9 -12 0 0 12 0 9 - - 0 6 0 0 6 9 - 6 6 0 6 6 9 -12 6 0 12 6 9 -/ - -ZCORN -0 0 1 1 0 0 1 1 -8 8 9 9 8 8 9 9 -/ - -ACTNUM -2*1 -/ - -PORO -2*0.15 -/ -)"; - Dune::CpGrid grid; Opm::createGridAndAddLgrs(grid, - deckString, + deckTwoCellsInXDirGrid, /* cells_per_dim_vec */ {{2,3,8}}, /* startIJK_vec */ {{0,0,0}}, /* endIJK_vec */ {{1,1,1}}, @@ -560,49 +534,9 @@ PORO BOOST_AUTO_TEST_CASE(parentCellWithMoreThanOne_I_FACE_false) { - // Level zero grid dims = 2x1x1 - // - // cell 0 - // bottom face corners (0,0,0), (6,0,0), (0,6,0), (6,6,0) - // top face corners (0,0,8), (6,0,8), (0,6,8), (6,6,8) - // - // cell 1 - // bottom face corners (6,0,1), (12,0,1), (6,6,1), (12,6,1) - // top face corners (6,0,9), (12,0,9), (12,6,9), (12,6,9) - const std::string deckString = - R"(RUNSPEC -DIMENS - 2 1 1 / - -GRID - -COORD - 0 0 0 0 0 9 - 6 0 0 6 0 9 -12 0 0 12 0 9 - - 0 6 0 0 6 9 - 6 6 0 6 6 9 -12 6 0 12 6 9 -/ - -ZCORN -0 0 1 1 0 0 1 1 -8 8 9 9 8 8 9 9 -/ - -ACTNUM -2*1 -/ - -PORO -2*0.15 -/ -)"; - Dune::CpGrid grid; Opm::createGridAndAddLgrs(grid, - deckString, + deckTwoCellsInXDirGrid, /* cells_per_dim_vec */ {{2,3,2}}, /* startIJK_vec */ {{1,0,0}}, /* endIJK_vec */ {{2,1,1}}, @@ -744,452 +678,188 @@ PORO /* lgr_name_vec = */ {"LGR1"}); } -BOOST_AUTO_TEST_CASE(parentCellWithMoreThanSixIntersections_J_FACE_true) + + +BOOST_AUTO_TEST_CASE(neighboringSingleCellRefinementsDifferentLgrs) { - // Level zero grid dims = 1x2x1 + Dune::CpGrid grid; + Opm::createGridAndAddLgrs(grid, + deckTwoCellsInXDirGrid, + {{2,3,2}, {2,3,2}}, // cells_per_dim_vec + {{0,0,0}, {1,0,0}}, // startIJK_vec + {{1,1,1}, {2,1,1}}, // endIJK_vec + {"LGR1", "LGR2"}); // lgr_name_vec*/ + + // Element 0 and element 1 in level zero grid share an I_FACE (with face index 2) // - // cell 0 - // bottom face corners (0,0,0), (6,0,0), (0,6,0), (6,6,0) - // top face corners (0,0,8), (6,0,8), (0,6,8), (6,6,8) + // Vertices of those faces lie on the plane x = 6 | After refinement, number of subdivisions in + // | y- and z- directions: // - // cell 1 - // bottom face corners (0,6,1), (6,6,1), (0,12,1), (6,12,1) - // top face corners (0,6,9), (6,6,9), (0,12,9), (6,12,9) + // (6,0,9) -----------------(6,6,9) | (6,0,9) --(6,2,9)-(6,4,9)--(6,6,9) + // | face idx 3 | | | * * | + // (6,0,8) ---------------- (6,6,8) | (6,0,8) --(6,2,8)-(6,4,8)--(6,6,8) + // | | | | * * | + // | | | | * * | + // | | | | * * | + // | face idx 2 | | (6,0,5) **(6,2,5)*(6,4,5)**(6,6,5) + // | | | | * * | + // | | | (6,0,4) **(6,2,4)*(6,4,4)**(6,6,4) + // | | | | * * | + // | | | | * * | + // (6,0,1) -----------------(6,6,1) | (6,0,1) --(6,2,1)-(6,4,1)--(6,6,1) + // | face idx 1 | | | * * | + // (6,0,0) -----------------(6,6,0) | (6,0,0) --(6,2,0)-(6,4,0)--(6,6,0) + // | - const std::string deckString = - R"(RUNSPEC -DIMENS - 1 2 1 / + const auto& parentGridData = *grid.currentData()[0]; + const auto parent0 = Dune::cpgrid::Entity<0>(parentGridData, 0, true); + const auto parent1 = Dune::cpgrid::Entity<0>(parentGridData, 1, true); -GRID + BOOST_CHECK_EQUAL(parentGridData.cellToFace(parent0.index()).size(), 7); + BOOST_CHECK_EQUAL(parentGridData.cellToFace(parent1.index()).size(), 7); -COORD - 0 0 0 0 0 9 - 6 0 0 6 0 9 + const auto& refinedGrid1 = *grid.currentData()[1]; + BOOST_CHECK_EQUAL( refinedGrid1.size(3), 44); + // LGR1 dims 3x2x2 -> 4x3x3 vertices + 4 extra missing vertices (0,6,8), (2,6,8), (4,6,8), and (6,6,8)...... + BOOST_CHECK_EQUAL( refinedGrid1.numFaces(), 58); - 0 6 0 0 6 9 - 6 6 0 6 6 9 + const auto& refinedGrid2 = *grid.currentData()[2]; + BOOST_CHECK_EQUAL( refinedGrid2.size(3), 44); + // LGR1 dims 3x2x2 -> 4x3x3 vertices + 4 extra missing vertices (0,6,8), (2,6,8), (4,6,8), and (6,6,8)........ + BOOST_CHECK_EQUAL( refinedGrid2.numFaces(), 58); - 0 12 0 0 12 9 - 6 12 0 6 12 9 -/ + const auto& leafGrid = grid.currentLeafData(); -ZCORN -0 0 0 0 1 1 1 1 -8 8 8 8 9 9 9 9 -/ + BOOST_CHECK_EQUAL( leafGrid.size(3), 72); // 44 + 44 -16 -> 72 + BOOST_CHECK_EQUAL( leafGrid.numFaces(), 107); // 58 + 58 - 9 ->107 -ACTNUM -2*1 -/ + expectedCellCountRespectToCellToFaceSize(grid, + /* expectedCount7Faces = */ std::vector{2, 6, 6}); // level 0, level 1, level2 + + // Leaf grid should have 12 elements with 7 faces (due to I_FACE shared between + // parent cells) and 24-12 = 12 with 6 faces + int count_7faces = 0; + int count_6faces = 0; + for (const auto& element : Dune::elements(grid.leafGridView())) { + int count = leafGrid.cellToFace(element.index()).size(); + if (count == 7) { + ++count_7faces; + } + else { + BOOST_CHECK_EQUAL(count, 6); + ++count_6faces; + } + } + BOOST_CHECK_EQUAL(count_7faces, 12); + BOOST_CHECK_EQUAL(count_6faces, grid.leafGridView().size(0) - count_7faces); -PORO -2*0.15 -/ -)"; + Opm::checkGridWithLgrs(grid, + {{2,3,2}, {2,3,2}}, // cells_per_dim_vec + {"LGR1", "LGR2"}); // lgr_name_vec + +} + +BOOST_AUTO_TEST_CASE(neighboringSingleCellRefinementsSameLgr) +{ Dune::CpGrid grid; Opm::createGridAndAddLgrs(grid, - deckString, - /* cells_per_dim_vec */ {{3,2,2}}, + deckTwoCellsInXDirGrid, + /* cells_per_dim_vec */ {{2,3,2}}, /* startIJK_vec */ {{0,0,0}}, - /* endIJK_vec */ {{1,1,1}}, + /* endIJK_vec */ {{2,1,1}}, /* lgr_name_vec */ {"LGR1"}); - // LGR1 dimensions = {3,2,2} - // LGR1 indices - // - // k = 1 | 9 10 11| - // | 6 7 8| - // ---------- - // k = 0 | 3 4 5| - // | 0 1 2| - // ------------ - - - // Element 0 in level zero grid has two faces of type {J_FACE, true} + // Element 0 and element 1 in level zero grid share an I_FACE (with face index 2) // - // Vertices of those faces lie on the plane y = 6 | After refinement, number of subdivisions in LGR1 cell indices + // Vertices of those faces lie on the plane x = 6 | After refinement, number of subdivisions in // | y- and z- directions: - // (0,6,8) ---------------- (6,6,8) | (0,6,8) --(2,6,8)-(4,6,8)--(6,6,8) x-----x-----x-----x - // | | | | * * | | * * | - // | | | | * * | | 9 * 10 * 11 | - // | | | | * * | | * * | - // | face idx 6 | | | * * | | * * | - // | | | (0,6,4) **(2,6,4)*(4,6,4)**(6,6,4) x*****x*****x*****x - // | | | | * * | | * * | - // | | | | * * | | * * | - // (0,6,1) -----------------(6,6,1) | (0,6,1) --(?,?,?)-(?,?,?)--(6,6,1) x- 3 -x- 4 -x- 5 -x - // | face idx 5 | | | * * | | * * | - // (0,6,0) -----------------(6,6,0) | (0,6,0) --(2,6,0)-(4,6,0)--(6,6,0) x-----x-----x-----x + // + // (6,0,9) -----------------(6,6,9) | (6,0,9) --(6,2,9)-(6,4,9)--(6,6,9) + // | face idx 3 | | | * * | + // (6,0,8) ---------------- (6,6,8) | (6,0,8) --(6,2,8)-(6,4,8)--(6,6,8) + // | | | | * * | + // | | | | * * | + // | | | | * * | + // | face idx 2 | | (6,0,5) **(6,2,5)*(6,4,5)**(6,6,5) + // | | | | * * | + // | | | (6,0,4) **(6,2,4)*(6,4,4)**(6,6,4) + // | | | | * * | + // | | | | * * | + // (6,0,1) -----------------(6,6,1) | (6,0,1) --(6,2,1)-(6,4,1)--(6,6,1) + // | face idx 1 | | | * * | + // (6,0,0) -----------------(6,6,0) | (6,0,0) --(6,2,0)-(6,4,0)--(6,6,0) // | - // | The missing vertices are (2,6,1) and (4,6,1), appering in elements 3,4 or 5 in LGR1. - // | In LGR1 element 3: (2,6,1) - // | In LGR1 element 4: (2,6,1) and (4,6,1) - // | In LGR1 element 5: (4,6,1) - - const auto& refinedGridData = *grid.currentData()[1]; const auto& parentGridData = *grid.currentData()[0]; - const auto parentElem = Dune::cpgrid::Entity<0>(parentGridData, 0, true); + const auto parent0 = Dune::cpgrid::Entity<0>(parentGridData, 0, true); + const auto parent1 = Dune::cpgrid::Entity<0>(parentGridData, 1, true); - BOOST_CHECK_EQUAL(parentGridData.cellToFace(parentElem.index()).size(), 7); + BOOST_CHECK_EQUAL(parentGridData.cellToFace(parent0.index()).size(), 7); + BOOST_CHECK_EQUAL(parentGridData.cellToFace(parent1.index()).size(), 7); - BOOST_CHECK_EQUAL( refinedGridData.size(3), 40); - // LGR1 dims 3x2x2 -> 4x3x3 vertices + 4 extra missing vertices (0,6,1), (2,6,1), (4,6,1), and (6,6,1). - BOOST_CHECK_EQUAL( refinedGridData.numFaces(), 55); - // LGR1 dims 3x2x2 -> 52 faces (before correction due to missing points) - // 3 of those 52 faces vanished and give origin to 6 new faces: 52 - 3 + 6 = 55 faces + const auto& refinedGrid1 = *grid.currentData()[1]; + BOOST_CHECK_EQUAL( refinedGrid1.size(3), 72); + BOOST_CHECK_EQUAL( refinedGrid1.numFaces(), 107); - // Originally, the element not involved in refinement - // had 7 faces. It's neihgbor in level zero - // got refined and the I_FACE that they shared has been - // replaced by 6 refined faces. Then, the leaf element has - // one of each I-,I+,J+, K-, K+, and 1 coarse + 6 refined J-. - checkFaceCountInLeafCoarseElem(grid, - /* expectedTotalFaceCount = */ 12, - /* repeatedFaceType = */ 2, // 2->J- - /* expoectedRepeatedFaceTypeCount = */ 7); + const auto& leafGrid = grid.currentLeafData(); + BOOST_CHECK_EQUAL( leafGrid.size(3), 72); // 44 + 44 -16 -> 72 + BOOST_CHECK_EQUAL( leafGrid.numFaces(), 107); // 58 + 58 - 9 ->107 expectedCellCountRespectToCellToFaceSize(grid, - /* expectedCount7Faces = */ std::vector{2, 3}); // level 0, level 1 - - // Collect the expected data to later on check - std::vector>> selectedFaceToCoord{}; - selectedFaceToCoord.resize(grid.levelGridView(1).size(0)); - - for (const auto& refinedElem : Dune::elements(grid.levelGridView(1))) { + /* expectedCount7Faces = */ std::vector{2, 12}); // level 0, level 1 - std::set expectedNewFaceInFace6{}; - std::set expectedNewFaceInFace5{}; - // Vertex order in J_FACE: 0->(i+1)k, 1-> ik, 2->i(k+1), 3->(i+1)(k+1) - // - // i(k+1) <-'2' --------- '3'-> (i+1)(k+1) - // | | - // | | - // ik <-'1' --------- '0'-> (i+1)k - - if (refinedElem.index() == 3){ - // this element has to have 7 faces: 1 I-,I+,J-,K-,K+, and 2 J+: - // (0,6,4) **(2,6,4) - // | * J_FACE, true with vertices (0,6,1),(2,6,1),(2,6,4),(,6,4) - // | * - // (0,6,1) --(2,6,1) - // | * J_FACE, true with vertices (0,6,0),(2,6,0),(2,6,1),(0,6,1) - // (0,6,0) --(2,6,0) - expectedNewFaceInFace6 = {{2,6,1}, {0,6,1}, {0,6,4}, {2,6,4}}; - expectedNewFaceInFace5 = {{2,6,0}, {0,6,0}, {0,6,1}, {2,6,1}}; - - selectedFaceToCoord[3].push_back(expectedNewFaceInFace6); - selectedFaceToCoord[3].push_back(expectedNewFaceInFace5); - } - else if (refinedElem.index() == 4){ - // this element has to have 7 faces: 1 I-,I+,J-,K-,K+, and 2 J+: - // (2,6,4) **(4,6,4) - // | * J_FACE, true with vertices (2,6,1),(4,6,1),(4,6,4),(2,6,4) - // | * - // (2,6,1) --(4,6,1) - // | * J_FACE, true with vertices (2,6,0),(4,6,0),(4,6,1),(2,6,1) - // (2,6,0) --(4,6,0) - expectedNewFaceInFace6 = {{4,6,1}, {2,6,1}, {2,6,4}, {4,6,4}}; - expectedNewFaceInFace5 = {{4,6,0}, {2,6,0}, {2,6,1}, {4,6,1}}; - - selectedFaceToCoord[4].push_back(expectedNewFaceInFace6); - selectedFaceToCoord[4].push_back(expectedNewFaceInFace5); - } - else if (refinedElem.index() == 5){ - // this element has to have 7 faces: 1 I-,I+,J-,K-,K+, and 2 J+: - // (4,6,4) **(6,6,4) - // | * J_FACE, true with vertices (4,6,1),(6,6,1),(6,6,4),(4,6,4) - // | * - // (4,6,1) --(6,6,1) - // | * J_FACE, true with vertices (4,6,0),(6,6,0),(6,6,1),(4,6,1) - // (4,6,0) --(6,6,0) - expectedNewFaceInFace6 = {{6,6,1}, {4,6,1}, {4,6,4}, {6,6,4}}; - expectedNewFaceInFace5 = {{6,6,0}, {4,6,0}, {4,6,1}, {6,6,1}}; - - selectedFaceToCoord[5].push_back(expectedNewFaceInFace6); - selectedFaceToCoord[5].push_back(expectedNewFaceInFace5); - } - else if (refinedElem.index() == 9) { - expectedNewFaceInFace6 = {{2,6,4}, {0,6,4}, {0,6,8}, {2,6,8}}; - selectedFaceToCoord[9].push_back(expectedNewFaceInFace6); - } - else if (refinedElem.index() == 10) { - expectedNewFaceInFace6 = {{4,6,4}, {2,6,4}, {2,6,8}, {4,6,8}}; - selectedFaceToCoord[10].push_back(expectedNewFaceInFace6); - } - else if (refinedElem.index() == 11) { - expectedNewFaceInFace6 = {{6,6,4}, {4,6,4}, {4,6,8}, {6,6,8}}; - selectedFaceToCoord[11].push_back(expectedNewFaceInFace6); - } - } - checkNewRefinedFaces(grid, refinedGridData, - selectedFaceToCoord, /* repeatedFaceType = */ 3); // 3-> J+ - - Opm::checkGridWithLgrs(grid, - /* cells_per_dim_vec = */ {{3,2,2}}, - /* lgr_name_vec = */ {"LGR1"}); -} - - -BOOST_AUTO_TEST_CASE(parentCellWithMoreThanSixIntersections_J_FACE_false) -{ - // Level zero grid dims = 1x2x1 - // - // cell 0 - // bottom face corners (0,0,0), (6,0,0), (0,6,0), (6,6,0) - // top face corners (0,0,8), (6,0,8), (0,6,8), (6,6,8) - // - // cell 1 - // bottom face corners (0,6,1), (6,6,1), (0,12,1), (6,12,1) - // top face corners (0,6,9), (6,6,9), (0,12,9), (6,12,9) - - const std::string deckString = - R"(RUNSPEC -DIMENS - 1 2 1 / - -GRID - -COORD - 0 0 0 0 0 9 - 6 0 0 6 0 9 - - 0 6 0 0 6 9 - 6 6 0 6 6 9 - - 0 12 0 0 12 9 - 6 12 0 6 12 9 -/ - -ZCORN -0 0 0 0 1 1 1 1 -8 8 8 8 9 9 9 9 -/ - -ACTNUM -2*1 -/ - -PORO -2*0.15 -/ -)"; - - Dune::CpGrid grid; - Opm::createGridAndAddLgrs(grid, - deckString, - /* cells_per_dim_vec */ {{3,2,2}}, - /* startIJK_vec */ {{0,1,0}}, - /* endIJK_vec */ {{1,2,1}}, - /* lgr_name_vec */ {"LGR1"}); - - // LGR1 dimensions = {3,2,2} - // LGR1 indices - // - // k = 1 | 9 10 11| - // | 6 7 8| - // ---------- - // k = 0 | 3 4 5| - // | 0 1 2| - // ------------ - - // Element 1 in level zero grid has two faces of type {J_FACE, false} - // - // Vertices of those faces lie on the plane x = 6 | After refinement, number of subdivisions in LGR1 cell indices - // | y- and z- directions: - // (0,6,9) -----------------(6,6,9) | (0,6,9) --(2,6,9)-(4,6,9)--(6,6,9) x*****x*****x*****x - // | face idx 7 | | | * * | | * * | - // (0,6,8) -----------------(6,6,8) | (0,6,8) --(?,?,?)-(?,?,?)--(6,6,8) x- 6 -x- 7 -x- 8--x - // | | | | * * | | * * | - // | | | | * * | | * * | - // | | | | * * | | * * | - // | face idx 6 | | (0,6,5) **(2,6,5)*(4,6,5)**(6,6,5) x*****x*****x*****x - // | | | | * * | | * * | - // | | | | * * | | 0 * 1 * 2 | - // | | | | * * | | * * | - // (0,6,1) ---------------- (6,6,1) | (0,6,1) --(2,6,1)-(4,6,1)--(6,6,1) x-----x-----x-----x - // | - // | The missing vertices are (2,6,8) and (4,6,8), appering in elements 6,7, or 8 in LGR1. - // | In LGR1 element 6: (2,6,8) - // | In LGR1 element 7: (2,6,8) and (4,6,8) - // | In LGR1 element 8: (4,6,8) - - const auto& refinedGridData = *grid.currentData()[1]; - const auto& parentGridData = *grid.currentData()[0]; - const auto parentElem = Dune::cpgrid::Entity<0>(parentGridData, 1, true); - - BOOST_CHECK_EQUAL(parentGridData.cellToFace(parentElem.index()).size(), 7); - - BOOST_CHECK_EQUAL( refinedGridData.size(3), 40); - // LGR1 dims 3x2x2 -> 4x3x3 vertices + 4 extra missing vertices (0,6,8), (2,6,8), (4,6,8), and (6,6,8). - BOOST_CHECK_EQUAL( refinedGridData.numFaces(), 55); - // LGR1 dims 3x2x2 -> 52 faces (before correction due to missing points) - // 3 of those 52 faces vanished and give origin to 6 new faces: 52 - 3 + 6 = 55 faces - - // Originally, the element not involved in refinement - // had 7 faces. It's neihgbor in level zero - // got refined and the I_FACE that they shared has been - // replaced by 6 refined faces. Then, the leaf element has - // one of each I-,I+,J-, K-, K+, and 1 coarse + 6 refined J+. - checkFaceCountInLeafCoarseElem(grid, - /* expectedTotalFaceCount = */ 12, - /* repeatedFaceType = */ 3, // 3->J+ - /* expoectedRepeatedFaceTypeCount = */ 7); - - expectedCellCountRespectToCellToFaceSize(grid, - /* expectedCount7Faces = */ std::vector{2, 3}); // level 0, level 1 - - // Collect the expected data to later on check - std::vector>> selectedFaceToCoord{}; - selectedFaceToCoord.resize(grid.levelGridView(1).size(0)); - - for (const auto& refinedElem : Dune::elements(grid.levelGridView(1))) { - - std::set expectedNewFaceInFace7{}; - std::set expectedNewFaceInFace6{}; - // Vertex order in J_FACE: 0->(i+1)k, 1-> ik, 2->i(k+1), 3->(i+1)(k+1) - // - // i(k+1) <-'2' --------- '3'-> (i+1)(k+1) - // | | - // | | - // ik <-'1' --------- '0'-> (i+1)k - - if (refinedElem.index() == 6) { - // this element has to have 7 faces: 1 I-,I+,J+,K-,K+, and 2 J-: - // (0,6,9) --(2,6,9) - // | * J_FACE, false with vertices (0,6,8),(2,6,8),(2,6,9),(0,6,9) - // (0,6,8) **(2,6,8) - // | * J_FACE, false with vertices (0,6,5),(2,6,5),(2,6,8),(0,6,8) - // | * - // (0,6,5) --(2,6,5) - expectedNewFaceInFace7 = {{2,6,8}, {0,6,8}, {0,6,9}, {2,6,9}}; - expectedNewFaceInFace6 = {{2,6,5}, {0,6,5}, {0,6,8}, {2,6,8}}; - - selectedFaceToCoord[6].push_back(expectedNewFaceInFace7); - selectedFaceToCoord[6].push_back(expectedNewFaceInFace6); - } - else if (refinedElem.index() == 7) { - // this element has to have 7 faces: 1 I-,I+,J+,K-,K+, and 2 J-: - // (2,6,9) --(4,6,9) - // | * J_FACE, false with vertices (2,6,8),(4,6,8),(4,6,9),(2,6,9) - // (2,6,8) **(4,6,8) - // | * J_FACE, false with vertices (2,6,5),(4,6,5),(4,6,8),(2,6,8) - // | * - // (2,6,5) --(4,6,5) - expectedNewFaceInFace7 = {{4,6,8}, {2,6,8}, {2,6,9}, {4,6,9}}; - expectedNewFaceInFace6 = {{4,6,5}, {2,6,5}, {2,6,8}, {4,6,8}}; - - selectedFaceToCoord[7].push_back(expectedNewFaceInFace7); - selectedFaceToCoord[7].push_back(expectedNewFaceInFace6); - } - else if (refinedElem.index() == 8) { - // this element has to have 7 faces: 1 I-,I+,J+,K-,K+, and 2 J-: - // (4,6,9) --(6,6,9) - // | * J_FACE, false with vertices (4,6,8),(6,6,8),(6,6,9),(4,6,9) - // (4,6,8) **(6,6,8) - // | * J_FACE, false with vertices (4,6,5),(6,6,5),(6,6,8),(4,6,8) - // | * - // (4,6,5) --(6,6,5) - expectedNewFaceInFace7 = {{6,6,8}, {4,6,8}, {4,6,9}, {6,6,9}}; - expectedNewFaceInFace6 = {{6,6,5}, {4,6,5}, {4,6,8}, {6,6,8}}; - - selectedFaceToCoord[8].push_back(expectedNewFaceInFace7); - selectedFaceToCoord[8].push_back(expectedNewFaceInFace6); - } - else if (refinedElem.index() == 0) { - expectedNewFaceInFace6 = {{2,6,1}, {0,6,1}, {0,6,5}, {2,6,5}}; - selectedFaceToCoord[0].push_back(expectedNewFaceInFace6); - } - else if (refinedElem.index() == 1) { - expectedNewFaceInFace6 = {{4,6,1}, {2,6,1}, {2,6,5}, {4,6,5}}; - selectedFaceToCoord[1].push_back(expectedNewFaceInFace6); + // Leaf grid should have 12 elements with 7 faces (due to I_FACE shared between + // parent cells) and 24-12 = 12 with 6 faces + int count_7faces = 0; + int count_6faces = 0; + for (const auto& element : Dune::elements(grid.leafGridView())) { + int count = leafGrid.cellToFace(element.index()).size(); + if (count == 7) { + ++count_7faces; } - else if (refinedElem.index() == 2) { - expectedNewFaceInFace6 = {{6,6,1},{4,6,1}, {4,6,5}, {6,6,5}}; - selectedFaceToCoord[2].push_back(expectedNewFaceInFace6); + else { + BOOST_CHECK_EQUAL(count, 6); + ++count_6faces; } } - checkNewRefinedFaces(grid, refinedGridData, - selectedFaceToCoord, /* repeatedFaceType = */ 2); // 2-> J- + BOOST_CHECK_EQUAL(count_7faces, 12); + BOOST_CHECK_EQUAL(count_6faces, grid.leafGridView().size(0) - count_7faces); Opm::checkGridWithLgrs(grid, - /* cells_per_dim_vec = */ {{3,2,2}}, - /* lgr_name_vec = */ {"LGR1"}); + {{2,3,2}}, // cells_per_dim_vec + {"LGR1"}); // lgr_name_vec } - -BOOST_AUTO_TEST_CASE(neighboringSingleCellRefinementsDifferentLgrs) +BOOST_AUTO_TEST_CASE(simpleDiffLgr) { - // Level zero grid dims = 2x1x1 - // - // cell 0 - // bottom face corners (0,0,0), (6,0,0), (0,6,0), (6,6,0) - // top face corners (0,0,8), (6,0,8), (0,6,8), (6,6,8) - // - // cell 1 - // bottom face corners (6,0,1), (12,0,1), (6,6,1), (12,6,1) - // top face corners (6,0,9), (12,0,9), (12,6,9), (12,6,9) - const std::string deckString = - R"(RUNSPEC -DIMENS - 2 1 1 / - -GRID - -COORD - 0 0 0 0 0 9 - 6 0 0 6 0 9 -12 0 0 12 0 9 - - 0 6 0 0 6 9 - 6 6 0 6 6 9 -12 6 0 12 6 9 -/ - -ZCORN -0 0 1 1 0 0 1 1 -8 8 9 9 8 8 9 9 -/ - -ACTNUM -2*1 -/ - -PORO -2*0.15 -/ -)"; - Dune::CpGrid grid; Opm::createGridAndAddLgrs(grid, - deckString, - {{2,3,2}, {2,3,2}}, // cells_per_dim_vec - {{0,0,0}, {1,0,0}}, // startIJK_vec - {{1,1,1}, {2,1,1}}, // endIJK_vec - {"LGR1", "LGR2"}); // lgr_name_vec*/ + deckTwoCellsInXDirGrid, + /* cells_per_dim_vec */ {{1,2,1}, {1,2,1}}, + /* startIJK_vec */ {{0,0,0}, {1,0,0}}, + /* endIJK_vec */ {{1,1,1}, {2,1,1}}, + /* lgr_name_vec */ {"LGR1", "LGR2"}); // Element 0 and element 1 in level zero grid share an I_FACE (with face index 2) // // Vertices of those faces lie on the plane x = 6 | After refinement, number of subdivisions in // | y- and z- directions: // - // (6,0,9) -----------------(6,6,9) | (6,0,9) --(6,2,9)-(6,4,9)--(6,6,9) - // | face idx 3 | | | * * | - // (6,0,8) ---------------- (6,6,8) | (6,0,8) --(6,2,8)-(6,4,8)--(6,6,8) - // | | | | * * | - // | | | | * * | - // | | | | * * | - // | face idx 2 | | (6,0,5) **(6,2,5)*(6,4,5)**(6,6,5) - // | | | | * * | - // | | | (6,0,4) **(6,2,4)*(6,4,4)**(6,6,4) - // | | | | * * | - // | | | | * * | - // (6,0,1) -----------------(6,6,1) | (6,0,1) --(6,2,1)-(6,4,1)--(6,6,1) - // | face idx 1 | | | * * | - // (6,0,0) -----------------(6,6,0) | (6,0,0) --(6,2,0)-(6,4,0)--(6,6,0) + // (6,0,9) -----------------(6,6,9) | (6,0,9) --(6,3,9)---(6,6,9) + // | face idx 3 | | | * | + // (6,0,8) ---------------- (6,6,8) | (6,0,8) --(6,3,9)---(6,6,8) + // | | | | * | + // | | | | * | + // | | | | * | + // | face idx 2 | | | * | + // | | | | * | + // | | | | * | + // | | | | * | + // | | | | * | + // (6,0,1) -----------------(6,6,1) | (6,0,1) --(6,3,1)---(6,6,1) + // | face idx 1 | | | * | + // (6,0,0) -----------------(6,6,0) | (6,0,0) --(6,3,0)---(6,6,0) // | - const auto& parentGridData = *grid.currentData()[0]; const auto parent0 = Dune::cpgrid::Entity<0>(parentGridData, 0, true); const auto parent1 = Dune::cpgrid::Entity<0>(parentGridData, 1, true); @@ -1198,93 +868,126 @@ PORO BOOST_CHECK_EQUAL(parentGridData.cellToFace(parent1.index()).size(), 7); const auto& refinedGrid1 = *grid.currentData()[1]; - BOOST_CHECK_EQUAL( refinedGrid1.size(3), 44); - // LGR1 dims 3x2x2 -> 4x3x3 vertices + 4 extra missing vertices (0,6,8), (2,6,8), (4,6,8), and (6,6,8)...... - BOOST_CHECK_EQUAL( refinedGrid1.numFaces(), 58); + BOOST_CHECK_EQUAL( refinedGrid1.size(3), 15); + BOOST_CHECK_EQUAL( refinedGrid1.numFaces(), 13); const auto& refinedGrid2 = *grid.currentData()[2]; - BOOST_CHECK_EQUAL( refinedGrid2.size(3), 44); - // LGR1 dims 3x2x2 -> 4x3x3 vertices + 4 extra missing vertices (0,6,8), (2,6,8), (4,6,8), and (6,6,8)........ - BOOST_CHECK_EQUAL( refinedGrid2.numFaces(), 58); + BOOST_CHECK_EQUAL( refinedGrid2.size(3), 15); + BOOST_CHECK_EQUAL( refinedGrid2.numFaces(), 13); const auto& leafGrid = grid.currentLeafData(); + BOOST_CHECK_EQUAL( leafGrid.size(3), 24); + BOOST_CHECK_EQUAL( leafGrid.numFaces(), 24); - BOOST_CHECK_EQUAL( leafGrid.size(3), 72); // 44 + 44 -16 -> 72 - BOOST_CHECK_EQUAL( leafGrid.numFaces(), 107); // 58 + 58 - 9 ->107 - - expectedCellCountRespectToCellToFaceSize(grid, - /* expectedCount7Faces = */ std::vector{2, 6, 6}); // level 0, level 1, level2 - - // Leaf grid should have 12 elements with 7 faces (due to I_FACE shared between - // parent cells) and 24-12 = 12 with 6 faces - int count_7faces = 0; - int count_6faces = 0; - for (const auto& element : Dune::elements(grid.leafGridView())) { - int count = leafGrid.cellToFace(element.index()).size(); - if (count == 7) { - ++count_7faces; - } - else { - BOOST_CHECK_EQUAL(count, 6); - ++count_6faces; - } - } - BOOST_CHECK_EQUAL(count_7faces, 12); - BOOST_CHECK_EQUAL(count_6faces, grid.leafGridView().size(0) - count_7faces); + const std::set expectedLGR1Vertices = { + {0.,0.,0.}, {0.,0.,8.}, // pillar x = 0, y = 0 + {6.,0.,0.}, {6.,0.,1.}, {6.,0.,8.}, // pillar x = 6, y = 0 + {0.,3.,0.}, {0.,3.,8.}, // pillar x = 0, y = 3 + {6.,3.,0.}, {6.,3.,1.}, {6.,3.,8.}, // pillar x = 6, y = 3 + {0.,6.,0.}, {0.,6.,8.}, // pillar x = 0, y = 6 + {6.,6.,0.}, {6.,6.,1.}, {6.,6.,8.} // pillar x = 6, y = 6 + }; - Opm::checkGridWithLgrs(grid, - {{2,3,2}, {2,3,2}}, // cells_per_dim_vec - {"LGR1", "LGR2"}); // lgr_name_vec + const std::set expectedLGR2Vertices = { + {6.,0.,1.}, {6.,0.,8.}, {6.,0.,9.}, // pillar x = 6, y = 0 + {12.,0.,1.}, {12.,0.,9.}, // pillar x = 12, y = 0 + {6.,3.,1.}, {6.,3.,8.}, {6.,3.,9.}, // pillar x = 6, y = 3 + {12.,3.,1.}, {12.,3.,9.}, // pillar x = 12, y = 3 + {6.,6.,1.}, {6.,6.,8.}, {6.,6.,9.}, // pillar x = 6, y = 6 + {12.,6.,1.}, {12.,6.,9.} // pillar x = 12, y = 6 + }; -} + const std::set expectedLeafVertices = { + {0.,0.,0.}, {0.,0.,8.}, // pillar x = 0, y = 0 + {6.,0.,0.}, {6.,0.,1.}, {6.,0.,8.}, {6.,0.,9.}, // pillar x = 6, y = 0 + {12.,0.,1.}, {12.,0.,9.}, // pillar x = 12, y = 0 + {0.,3.,0.}, {0.,3.,8.}, // pillar x = 0, y = 3 + {6.,3.,0.}, {6.,3.,1.}, {6.,3.,8.}, {6.,3.,9.}, // pillar x = 6, y = 3 + {12.,3.,1.}, {12.,3.,9.}, // pillar x = 12, y = 3 + {0.,6.,0.}, {0.,6.,8.}, // pillar x = 0, y = 6 + {6.,6.,0.}, {6.,6.,1.}, {6.,6.,8.}, {6.,6.,9.}, // pillar x = 6, y = 6 + {12.,6.,1.}, {12.,6.,9.} // pillar x = 12, y = 6 + }; -BOOST_AUTO_TEST_CASE(neighboringSingleCellRefinementsSameLgr) -{ - // Level zero grid dims = 2x1x1 - // - // cell 0 - // bottom face corners (0,0,0), (6,0,0), (0,6,0), (6,6,0) - // top face corners (0,0,8), (6,0,8), (0,6,8), (6,6,8) - // - // cell 1 - // bottom face corners (6,0,1), (12,0,1), (6,6,1), (12,6,1) - // top face corners (6,0,9), (12,0,9), (12,6,9), (12,6,9) - const std::string deckString = - R"(RUNSPEC -DIMENS - 2 1 1 / + checkLevelVertices(grid, std::vector{expectedLGR1Vertices, expectedLGR2Vertices}); + checkLeafVertices(grid, expectedLeafVertices); -GRID + const std::vector> expectedLGR1Faces = { + {{0.,0.,0.}, {6.,0.,0.}, {6.,3.,0.}, {0.,3.,0.}}, // K_FACE z = 0, face 0 + {{0.,3.,0.}, {6.,3.,0.}, {6.,6.,0.}, {0.,6.,0.}}, // K_FACE z = 0, face 1 + {{0.,0.,8.}, {6.,0.,8.}, {6.,3.,8.}, {0.,3.,8.}}, // K_FACE z = 8, face 2 + {{0.,3.,8.}, {6.,3.,8.}, {6.,6.,8.}, {0.,6.,8.}}, // K_FACE z = 8, face 3 + {{0.,0.,0.}, {0.,3.,0.}, {0.,3.,8.}, {0.,0.,8.}}, // I_FACE x = 0, face 4 + {{0.,3.,0.}, {0.,6.,0.}, {0.,6.,8.}, {0.,3.,8.}}, // I_FACE x = 0, face 5 + {{6.,0.,0.}, {6.,3.,0.}, {6.,3.,1.}, {6.,0.,1.}}, // I_FACE x = 6, face 6 + {{6.,0.,1.}, {6.,3.,1.}, {6.,3.,8.}, {6.,0.,8.}}, // I_FACE x = 6, face 7 + {{6.,3.,0.}, {6.,6.,0.}, {6.,6.,1.}, {6.,3.,1.}}, // I_FACE x = 6, face 8 + {{6.,3.,1.}, {6.,6.,1.}, {6.,6.,8.}, {6.,3.,8.}}, // I_FACE x = 6, face 9 + {{0.,0.,0.}, {6.,0.,0.}, {6.,0.,8.}, {0.,0.,8.}}, // J_FACE y = 0, face 10 + {{0.,3.,0.}, {6.,3.,0.}, {6.,3.,8.}, {0.,3.,8.}}, // J_FACE y = 3, face 11 + {{0.,6.,0.}, {6.,6.,0.}, {6.,6.,8.}, {0.,6.,8.}}, // J_FACE y = 6, face 12 + }; -COORD - 0 0 0 0 0 9 - 6 0 0 6 0 9 -12 0 0 12 0 9 + const std::vector> expectedLGR2Faces = { + {{6.,0.,1.}, {12.,0.,1.}, {12.,3.,1.}, {6.,3.,1.}}, // K_FACE z = 1, face 0 + {{6.,3.,1.}, {12.,3.,1.}, {12.,6.,1.}, {6.,6.,1.}}, // K_FACE z = 1, face 1 + {{6.,0.,9.}, {12.,0.,9.}, {12.,3.,9.}, {6.,3.,9.}}, // K_FACE z = 9, face 2 + {{6.,3.,9.}, {12.,3.,9.}, {12.,6.,9.}, {6.,6.,9.}}, // K_FACE z = 9, face 3 + {{6.,0.,1.}, {6.,3.,1.}, {6.,3.,8.}, {6.,0.,8.}}, // I_FACE x = 6, face 4 + {{6.,0.,8.}, {6.,3.,8.}, {6.,3.,9.}, {6.,0.,9.}}, // I_FACE x = 6, face 5 + {{6.,3.,1.}, {6.,6.,1.}, {6.,6.,8.}, {6.,3.,8.}}, // I_FACE x = 6, face 6 + {{6.,3.,8.}, {6.,6.,8.}, {6.,6.,9.}, {6.,3.,9.}}, // I_FACE x = 6, face 7 + {{12.,0.,1.}, {12.,3.,1.}, {12.,3.,9.}, {12.,0.,9.}}, // I_FACE x = 12, face 8 + {{12.,3.,1.}, {12.,6.,1.}, {12.,6.,9.}, {12.,3.,9.}}, // I_FACE x = 12, face 9 + {{6.,0.,1.}, {12.,0.,1.}, {12.,0.,9.}, {6.,0.,9.}}, // J_FACE y = 0, face 10 + {{6.,3.,1.}, {12.,3.,1.}, {12.,3.,9.}, {6.,3.,9.}}, // J_FACE y = 3, face 11 + {{6.,6.,1.}, {12.,6.,1.}, {12.,6.,9.}, {6.,6.,9.}}, // J_FACE y = 6, face 12 + }; - 0 6 0 0 6 9 - 6 6 0 6 6 9 -12 6 0 12 6 9 -/ + const std::vector> expectedLeafFaces = { + {{0.,0.,0.}, {6.,0.,0.}, {6.,3.,0.}, {0.,3.,0.}}, // K_FACE z = 0, face 0 + {{0.,3.,0.}, {6.,3.,0.}, {6.,6.,0.}, {0.,6.,0.}}, // K_FACE z = 0, face 1 + {{0.,0.,8.}, {6.,0.,8.}, {6.,3.,8.}, {0.,3.,8.}}, // K_FACE z = 8, face 2 + {{0.,3.,8.}, {6.,3.,8.}, {6.,6.,8.}, {0.,6.,8.}}, // K_FACE z = 8, face 3 + {{0.,0.,0.}, {0.,3.,0.}, {0.,3.,8.}, {0.,0.,8.}}, // I_FACE x = 0, face 6 + {{0.,3.,0.}, {0.,6.,0.}, {0.,6.,8.}, {0.,3.,8.}}, // I_FACE x = 0, face 5 + {{6.,0.,0.}, {6.,3.,0.}, {6.,3.,1.}, {6.,0.,1.}}, // I_FACE x = 6, face 6 + {{6.,3.,0.}, {6.,6.,0.}, {6.,6.,1.}, {6.,3.,1.}}, // I_FACE x = 6, face 7 + {{0.,0.,0.}, {6.,0.,0.}, {6.,0.,8.}, {0.,0.,8.}}, // J_FACE y = 0, face 8 + {{0.,3.,0.}, {6.,3.,0.}, {6.,3.,8.}, {0.,3.,8.}}, // J_FACE y = 3, face 9 + {{0.,6.,0.}, {6.,6.,0.}, {6.,6.,8.}, {0.,6.,8.}}, // J_FACE y = 6, face 10 + {{6.,0.,1.}, {12.,0.,1.}, {12.,3.,1.}, {6.,3.,1.}}, // K_FACE z = 1, face 11 + {{6.,3.,1.}, {12.,3.,1.}, {12.,6.,1.}, {6.,6.,1.}}, // K_FACE z = 1, face 12 + {{6.,0.,9.}, {12.,0.,9.}, {12.,3.,9.}, {6.,3.,9.}}, // K_FACE z = 9, face 13 + {{6.,3.,9.}, {12.,3.,9.}, {12.,6.,9.}, {6.,6.,9.}}, // K_FACE z = 9, face 14 + {{6.,0.,1.}, {6.,3.,1.}, {6.,3.,8.}, {6.,0.,8.}}, // I_FACE x = 6, face 15 + {{6.,0.,8.}, {6.,3.,8.}, {6.,3.,9.}, {6.,0.,9.}}, // I_FACE x = 6, face 16 + {{6.,3.,1.}, {6.,6.,1.}, {6.,6.,8.}, {6.,3.,8.}}, // I_FACE x = 6, face 17 + {{6.,3.,8.}, {6.,6.,8.}, {6.,6.,9.}, {6.,3.,9.}}, // I_FACE x = 6, face 18 + {{12.,0.,1.}, {12.,3.,1.}, {12.,3.,9.}, {12.,0.,9.}}, // I_FACE x = 12, face 19 + {{12.,3.,1.}, {12.,6.,1.}, {12.,6.,9.}, {12.,3.,9.}}, // I_FACE x = 12, face 20 + {{6.,0.,1.}, {12.,0.,1.}, {12.,0.,9.}, {6.,0.,9.}}, // J_FACE y = 0, face 21 + {{6.,3.,1.}, {12.,3.,1.}, {12.,3.,9.}, {6.,3.,9.}}, // J_FACE y = 3, face 22 + {{6.,6.,1.}, {12.,6.,1.}, {12.,6.,9.}, {6.,6.,9.}}, // J_FACE y = 6, face 23 + }; -ZCORN -0 0 1 1 0 0 1 1 -8 8 9 9 8 8 9 9 -/ + checkFaces(refinedGrid1, expectedLGR1Faces); + checkFaces(refinedGrid2, expectedLGR2Faces); + checkFaces(leafGrid, expectedLeafFaces); -ACTNUM -2*1 -/ + Opm::checkGridWithLgrs(grid, + {{1,2,1}, {1,2,1}}, // cells_per_dim_vec + {"LGR1", "LGR2"}); // lgr_name_vec +} -PORO -2*0.15 -/ -)"; +BOOST_AUTO_TEST_CASE(simpleSameLgr) +{ Dune::CpGrid grid; Opm::createGridAndAddLgrs(grid, - deckString, - /* cells_per_dim_vec */ {{2,3,2}}, + deckTwoCellsInXDirGrid, + /* cells_per_dim_vec */ {{1,2,1}}, /* startIJK_vec */ {{0,0,0}}, /* endIJK_vec */ {{2,1,1}}, /* lgr_name_vec */ {"LGR1"}); @@ -1294,20 +997,20 @@ PORO // Vertices of those faces lie on the plane x = 6 | After refinement, number of subdivisions in // | y- and z- directions: // - // (6,0,9) -----------------(6,6,9) | (6,0,9) --(6,2,9)-(6,4,9)--(6,6,9) - // | face idx 3 | | | * * | - // (6,0,8) ---------------- (6,6,8) | (6,0,8) --(6,2,8)-(6,4,8)--(6,6,8) - // | | | | * * | - // | | | | * * | - // | | | | * * | - // | face idx 2 | | (6,0,5) **(6,2,5)*(6,4,5)**(6,6,5) - // | | | | * * | - // | | | (6,0,4) **(6,2,4)*(6,4,4)**(6,6,4) - // | | | | * * | - // | | | | * * | - // (6,0,1) -----------------(6,6,1) | (6,0,1) --(6,2,1)-(6,4,1)--(6,6,1) - // | face idx 1 | | | * * | - // (6,0,0) -----------------(6,6,0) | (6,0,0) --(6,2,0)-(6,4,0)--(6,6,0) + // (6,0,9) -----------------(6,6,9) | (6,0,9) --(6,3,9)---(6,6,9) + // | face idx 3 | | | * | + // (6,0,8) ---------------- (6,6,8) | (6,0,8) --(6,3,9)---(6,6,8) + // | | | | * | + // | | | | * | + // | | | | * | + // | face idx 2 | | | * | + // | | | | * | + // | | | | * | + // | | | | * | + // | | | | * | + // (6,0,1) -----------------(6,6,1) | (6,0,1) --(6,3,1)---(6,6,1) + // | face idx 1 | | | * | + // (6,0,0) -----------------(6,6,0) | (6,0,0) --(6,3,0)---(6,6,0) // | const auto& parentGridData = *grid.currentData()[0]; const auto parent0 = Dune::cpgrid::Entity<0>(parentGridData, 0, true); @@ -1317,71 +1020,94 @@ PORO BOOST_CHECK_EQUAL(parentGridData.cellToFace(parent1.index()).size(), 7); const auto& refinedGrid1 = *grid.currentData()[1]; - BOOST_CHECK_EQUAL( refinedGrid1.size(3), 72); - BOOST_CHECK_EQUAL( refinedGrid1.numFaces(), 107); + BOOST_CHECK_EQUAL( refinedGrid1.size(3), 24); + BOOST_CHECK_EQUAL( refinedGrid1.numFaces(), 24); const auto& leafGrid = grid.currentLeafData(); - BOOST_CHECK_EQUAL( leafGrid.size(3), 72); // 44 + 44 -16 -> 72 - BOOST_CHECK_EQUAL( leafGrid.numFaces(), 107); // 58 + 58 - 9 ->107 - - expectedCellCountRespectToCellToFaceSize(grid, - /* expectedCount7Faces = */ std::vector{2, 12}); // level 0, level 1 + BOOST_CHECK_EQUAL( leafGrid.size(3), 24); + BOOST_CHECK_EQUAL( leafGrid.numFaces(), 24); - // Leaf grid should have 12 elements with 7 faces (due to I_FACE shared between - // parent cells) and 24-12 = 12 with 6 faces - int count_7faces = 0; - int count_6faces = 0; - for (const auto& element : Dune::elements(grid.leafGridView())) { - int count = leafGrid.cellToFace(element.index()).size(); - if (count == 7) { - ++count_7faces; - } - else { - BOOST_CHECK_EQUAL(count, 6); - ++count_6faces; - } - } - BOOST_CHECK_EQUAL(count_7faces, 12); - BOOST_CHECK_EQUAL(count_6faces, grid.leafGridView().size(0) - count_7faces); + const std::set expectedVertices = { + {0.,0.,0.}, {0.,0.,8.}, // pillar x = 0, y = 0 + {6.,0.,0.}, {6.,0.,1.}, {6.,0.,8.}, {6.,0.,9.}, // pillar x = 6, y = 0 + {12.,0.,1.}, {12.,0.,9.}, // pillar x = 12, y = 0 + {0.,3.,0.}, {0.,3.,8.}, // pillar x = 0, y = 3 + {6.,3.,0.}, {6.,3.,1.}, {6.,3.,8.}, {6.,3.,9.}, // pillar x = 6, y = 3 + {12.,3.,1.}, {12.,3.,9.}, // pillar x = 12, y = 3 + {0.,6.,0.}, {0.,6.,8.}, // pillar x = 0, y = 6 + {6.,6.,0.}, {6.,6.,1.}, {6.,6.,8.}, {6.,6.,9.}, // pillar x = 6, y = 6 + {12.,6.,1.}, {12.,6.,9.} // pillar x = 12, y = 6 + }; - Opm::checkGridWithLgrs(grid, - {{2,3,2}}, // cells_per_dim_vec - {"LGR1"}); // lgr_name_vec -} + checkLevelVertices(grid, std::vector{expectedVertices}); + checkLeafVertices(grid, expectedVertices); + const std::vector> expectedFaces = { + {{0.,0.,0.}, {6.,0.,0.}, {6.,3.,0.}, {0.,3.,0.}}, // K_FACE z = 0, face 0 + {{0.,3.,0.}, {6.,3.,0.}, {6.,6.,0.}, {0.,6.,0.}}, // K_FACE z = 0, face 1 + {{0.,0.,8.}, {6.,0.,8.}, {6.,3.,8.}, {0.,3.,8.}}, // K_FACE z = 8, face 2 + {{0.,3.,8.}, {6.,3.,8.}, {6.,6.,8.}, {0.,6.,8.}}, // K_FACE z = 8, face 3 + {{0.,0.,0.}, {0.,3.,0.}, {0.,3.,8.}, {0.,0.,8.}}, // I_FACE x = 0, face 4 + {{0.,3.,0.}, {0.,6.,0.}, {0.,6.,8.}, {0.,3.,8.}}, // I_FACE x = 0, face 5 + {{6.,0.,0.}, {6.,3.,0.}, {6.,3.,1.}, {6.,0.,1.}}, // I_FACE x = 6, face 6 + {{6.,3.,0.}, {6.,6.,0.}, {6.,6.,1.}, {6.,3.,1.}}, // I_FACE x = 6, face 7 + {{0.,0.,0.}, {6.,0.,0.}, {6.,0.,8.}, {0.,0.,8.}}, // J_FACE y = 0, face 8 + {{0.,3.,0.}, {6.,3.,0.}, {6.,3.,8.}, {0.,3.,8.}}, // J_FACE y = 3, face 9 + {{0.,6.,0.}, {6.,6.,0.}, {6.,6.,8.}, {0.,6.,8.}}, // J_FACE y = 6, face 10 + {{6.,0.,1.}, {12.,0.,1.}, {12.,3.,1.}, {6.,3.,1.}}, // K_FACE z = 1, face 11 + {{6.,3.,1.}, {12.,3.,1.}, {12.,6.,1.}, {6.,6.,1.}}, // K_FACE z = 1, face 12 + {{6.,0.,9.}, {12.,0.,9.}, {12.,3.,9.}, {6.,3.,9.}}, // K_FACE z = 9, face 13 + {{6.,3.,9.}, {12.,3.,9.}, {12.,6.,9.}, {6.,6.,9.}}, // K_FACE z = 9, face 14 + {{6.,0.,1.}, {6.,3.,1.}, {6.,3.,8.}, {6.,0.,8.}}, // I_FACE x = 6, face 15 + {{6.,0.,8.}, {6.,3.,8.}, {6.,3.,9.}, {6.,0.,9.}}, // I_FACE x = 6, face 16 + {{6.,3.,1.}, {6.,6.,1.}, {6.,6.,8.}, {6.,3.,8.}}, // I_FACE x = 6, face 17 + {{6.,3.,8.}, {6.,6.,8.}, {6.,6.,9.}, {6.,3.,9.}}, // I_FACE x = 6, face 18 + {{12.,0.,1.}, {12.,3.,1.}, {12.,3.,9.}, {12.,0.,9.}}, // I_FACE x = 12, face 19 + {{12.,3.,1.}, {12.,6.,1.}, {12.,6.,9.}, {12.,3.,9.}}, // I_FACE x = 12, face 20 + {{6.,0.,1.}, {12.,0.,1.}, {12.,0.,9.}, {6.,0.,9.}}, // J_FACE y = 0, face 21 + {{6.,3.,1.}, {12.,3.,1.}, {12.,3.,9.}, {6.,3.,9.}}, // J_FACE y = 3, face 22 + {{6.,6.,1.}, {12.,6.,1.}, {12.,6.,9.}, {6.,6.,9.}}, // J_FACE y = 6, face 23 + }; + checkFaces(refinedGrid1, expectedFaces); + checkFaces(leafGrid, expectedFaces); -BOOST_AUTO_TEST_CASE(simpleDiffLgr) -{ - // Level zero grid dims = 2x1x1 - // - // cell 0 - // bottom face corners (0,0,0), (6,0,0), (0,6,0), (6,6,0) - // top face corners (0,0,8), (6,0,8), (0,6,8), (6,6,8) - // - // cell 1 - // bottom face corners (6,0,1), (12,0,1), (6,6,1), (12,6,1) - // top face corners (6,0,9), (12,0,9), (12,6,9), (12,6,9) - const std::string deckString = - R"(RUNSPEC + Opm::checkGridWithLgrs(grid, + {{1,2,1}}, // cells_per_dim_vec + {"LGR1"}); // lgr_name_vec +} + +// Level zero grid dims = 1x2x1 +// +// cell 0 +// bottom face corners (0,0,0), (6,0,0), (0,6,0), (6,6,0) +// top face corners (0,0,8), (6,0,8), (0,6,8), (6,6,8) +// +// cell 1 +// bottom face corners (0,6,1), (6,6,1), (0,12,1), (6,12,1) +// top face corners (0,6,9), (6,6,9), (0,12,9), (6,12,9) + +const std::string deckTwoCellsInYDirGrid = + R"(RUNSPEC DIMENS - 2 1 1 / + 1 2 1 / GRID COORD - 0 0 0 0 0 9 - 6 0 0 6 0 9 -12 0 0 12 0 9 + 0 0 0 0 0 9 + 6 0 0 6 0 9 0 6 0 0 6 9 6 6 0 6 6 9 -12 6 0 12 6 9 + + 0 12 0 0 12 9 + 6 12 0 6 12 9 / ZCORN -0 0 1 1 0 0 1 1 -8 8 9 9 8 8 9 9 +0 0 0 0 1 1 1 1 +8 8 8 8 9 9 9 9 / ACTNUM @@ -1393,287 +1119,392 @@ PORO / )"; +BOOST_AUTO_TEST_CASE(parentCellWithMoreThanSixIntersections_J_FACE_true) +{ Dune::CpGrid grid; Opm::createGridAndAddLgrs(grid, - deckString, - /* cells_per_dim_vec */ {{1,2,1}, {1,2,1}}, - /* startIJK_vec */ {{0,0,0}, {1,0,0}}, - /* endIJK_vec */ {{1,1,1}, {2,1,1}}, - /* lgr_name_vec */ {"LGR1", "LGR2"}); + deckTwoCellsInYDirGrid, + /* cells_per_dim_vec */ {{3,2,2}}, + /* startIJK_vec */ {{0,0,0}}, + /* endIJK_vec */ {{1,1,1}}, + /* lgr_name_vec */ {"LGR1"}); - // Element 0 and element 1 in level zero grid share an I_FACE (with face index 2) + // LGR1 dimensions = {3,2,2} + // LGR1 indices // - // Vertices of those faces lie on the plane x = 6 | After refinement, number of subdivisions in - // | y- and z- directions: + // k = 1 | 9 10 11| + // | 6 7 8| + // ---------- + // k = 0 | 3 4 5| + // | 0 1 2| + // ------------ + + + // Element 0 in level zero grid has two faces of type {J_FACE, true} // - // (6,0,9) -----------------(6,6,9) | (6,0,9) --(6,3,9)---(6,6,9) - // | face idx 3 | | | * | - // (6,0,8) ---------------- (6,6,8) | (6,0,8) --(6,3,9)---(6,6,8) - // | | | | * | - // | | | | * | - // | | | | * | - // | face idx 2 | | | * | - // | | | | * | - // | | | | * | - // | | | | * | - // | | | | * | - // (6,0,1) -----------------(6,6,1) | (6,0,1) --(6,3,1)---(6,6,1) - // | face idx 1 | | | * | - // (6,0,0) -----------------(6,6,0) | (6,0,0) --(6,3,0)---(6,6,0) + // Vertices of those faces lie on the plane y = 6 | After refinement, number of subdivisions in LGR1 cell indices + // | y- and z- directions: + // (0,6,8) ---------------- (6,6,8) | (0,6,8) --(2,6,8)-(4,6,8)--(6,6,8) x-----x-----x-----x + // | | | | * * | | * * | + // | | | | * * | | 9 * 10 * 11 | + // | | | | * * | | * * | + // | face idx 6 | | | * * | | * * | + // | | | (0,6,4) **(2,6,4)*(4,6,4)**(6,6,4) x*****x*****x*****x + // | | | | * * | | * * | + // | | | | * * | | * * | + // (0,6,1) -----------------(6,6,1) | (0,6,1) --(?,?,?)-(?,?,?)--(6,6,1) x- 3 -x- 4 -x- 5 -x + // | face idx 5 | | | * * | | * * | + // (0,6,0) -----------------(6,6,0) | (0,6,0) --(2,6,0)-(4,6,0)--(6,6,0) x-----x-----x-----x // | + // | The missing vertices are (2,6,1) and (4,6,1), appering in elements 3,4 or 5 in LGR1. + // | In LGR1 element 3: (2,6,1) + // | In LGR1 element 4: (2,6,1) and (4,6,1) + // | In LGR1 element 5: (4,6,1) + + const auto& refinedGridData = *grid.currentData()[1]; const auto& parentGridData = *grid.currentData()[0]; - const auto parent0 = Dune::cpgrid::Entity<0>(parentGridData, 0, true); - const auto parent1 = Dune::cpgrid::Entity<0>(parentGridData, 1, true); + const auto parentElem = Dune::cpgrid::Entity<0>(parentGridData, 0, true); - BOOST_CHECK_EQUAL(parentGridData.cellToFace(parent0.index()).size(), 7); - BOOST_CHECK_EQUAL(parentGridData.cellToFace(parent1.index()).size(), 7); + BOOST_CHECK_EQUAL(parentGridData.cellToFace(parentElem.index()).size(), 7); - const auto& refinedGrid1 = *grid.currentData()[1]; - BOOST_CHECK_EQUAL( refinedGrid1.size(3), 15); - BOOST_CHECK_EQUAL( refinedGrid1.numFaces(), 13); + BOOST_CHECK_EQUAL( refinedGridData.size(3), 40); + // LGR1 dims 3x2x2 -> 4x3x3 vertices + 4 extra missing vertices (0,6,1), (2,6,1), (4,6,1), and (6,6,1). + BOOST_CHECK_EQUAL( refinedGridData.numFaces(), 55); + // LGR1 dims 3x2x2 -> 52 faces (before correction due to missing points) + // 3 of those 52 faces vanished and give origin to 6 new faces: 52 - 3 + 6 = 55 faces - const auto& refinedGrid2 = *grid.currentData()[2]; - BOOST_CHECK_EQUAL( refinedGrid2.size(3), 15); - BOOST_CHECK_EQUAL( refinedGrid2.numFaces(), 13); + // Originally, the element not involved in refinement + // had 7 faces. It's neihgbor in level zero + // got refined and the I_FACE that they shared has been + // replaced by 6 refined faces. Then, the leaf element has + // one of each I-,I+,J+, K-, K+, and 1 coarse + 6 refined J-. + checkFaceCountInLeafCoarseElem(grid, + /* expectedTotalFaceCount = */ 12, + /* repeatedFaceType = */ 2, // 2->J- + /* expoectedRepeatedFaceTypeCount = */ 7); - const auto& leafGrid = grid.currentLeafData(); - BOOST_CHECK_EQUAL( leafGrid.size(3), 24); - BOOST_CHECK_EQUAL( leafGrid.numFaces(), 24); + expectedCellCountRespectToCellToFaceSize(grid, + /* expectedCount7Faces = */ std::vector{2, 3}); // level 0, level 1 + // Collect the expected data to later on check + std::vector>> selectedFaceToCoord{}; + selectedFaceToCoord.resize(grid.levelGridView(1).size(0)); - const std::set expectedLGR1Vertices = { - {0.,0.,0.}, {0.,0.,8.}, // pillar x = 0, y = 0 - {6.,0.,0.}, {6.,0.,1.}, {6.,0.,8.}, // pillar x = 6, y = 0 - {0.,3.,0.}, {0.,3.,8.}, // pillar x = 0, y = 3 - {6.,3.,0.}, {6.,3.,1.}, {6.,3.,8.}, // pillar x = 6, y = 3 - {0.,6.,0.}, {0.,6.,8.}, // pillar x = 0, y = 6 - {6.,6.,0.}, {6.,6.,1.}, {6.,6.,8.} // pillar x = 6, y = 6 - }; + for (const auto& refinedElem : Dune::elements(grid.levelGridView(1))) { - const std::set expectedLGR2Vertices = { - {6.,0.,1.}, {6.,0.,8.}, {6.,0.,9.}, // pillar x = 6, y = 0 - {12.,0.,1.}, {12.,0.,9.}, // pillar x = 12, y = 0 - {6.,3.,1.}, {6.,3.,8.}, {6.,3.,9.}, // pillar x = 6, y = 3 - {12.,3.,1.}, {12.,3.,9.}, // pillar x = 12, y = 3 - {6.,6.,1.}, {6.,6.,8.}, {6.,6.,9.}, // pillar x = 6, y = 6 - {12.,6.,1.}, {12.,6.,9.} // pillar x = 12, y = 6 - }; + std::set expectedNewFaceInFace6{}; + std::set expectedNewFaceInFace5{}; + // Vertex order in J_FACE: 0->(i+1)k, 1-> ik, 2->i(k+1), 3->(i+1)(k+1) + // + // i(k+1) <-'2' --------- '3'-> (i+1)(k+1) + // | | + // | | + // ik <-'1' --------- '0'-> (i+1)k + + if (refinedElem.index() == 3){ + // this element has to have 7 faces: 1 I-,I+,J-,K-,K+, and 2 J+: + // (0,6,4) **(2,6,4) + // | * J_FACE, true with vertices (0,6,1),(2,6,1),(2,6,4),(,6,4) + // | * + // (0,6,1) --(2,6,1) + // | * J_FACE, true with vertices (0,6,0),(2,6,0),(2,6,1),(0,6,1) + // (0,6,0) --(2,6,0) + expectedNewFaceInFace6 = {{2,6,1}, {0,6,1}, {0,6,4}, {2,6,4}}; + expectedNewFaceInFace5 = {{2,6,0}, {0,6,0}, {0,6,1}, {2,6,1}}; + + selectedFaceToCoord[3].push_back(expectedNewFaceInFace6); + selectedFaceToCoord[3].push_back(expectedNewFaceInFace5); + } + else if (refinedElem.index() == 4){ + // this element has to have 7 faces: 1 I-,I+,J-,K-,K+, and 2 J+: + // (2,6,4) **(4,6,4) + // | * J_FACE, true with vertices (2,6,1),(4,6,1),(4,6,4),(2,6,4) + // | * + // (2,6,1) --(4,6,1) + // | * J_FACE, true with vertices (2,6,0),(4,6,0),(4,6,1),(2,6,1) + // (2,6,0) --(4,6,0) + expectedNewFaceInFace6 = {{4,6,1}, {2,6,1}, {2,6,4}, {4,6,4}}; + expectedNewFaceInFace5 = {{4,6,0}, {2,6,0}, {2,6,1}, {4,6,1}}; + + selectedFaceToCoord[4].push_back(expectedNewFaceInFace6); + selectedFaceToCoord[4].push_back(expectedNewFaceInFace5); + } + else if (refinedElem.index() == 5){ + // this element has to have 7 faces: 1 I-,I+,J-,K-,K+, and 2 J+: + // (4,6,4) **(6,6,4) + // | * J_FACE, true with vertices (4,6,1),(6,6,1),(6,6,4),(4,6,4) + // | * + // (4,6,1) --(6,6,1) + // | * J_FACE, true with vertices (4,6,0),(6,6,0),(6,6,1),(4,6,1) + // (4,6,0) --(6,6,0) + expectedNewFaceInFace6 = {{6,6,1}, {4,6,1}, {4,6,4}, {6,6,4}}; + expectedNewFaceInFace5 = {{6,6,0}, {4,6,0}, {4,6,1}, {6,6,1}}; + + selectedFaceToCoord[5].push_back(expectedNewFaceInFace6); + selectedFaceToCoord[5].push_back(expectedNewFaceInFace5); + } + else if (refinedElem.index() == 9) { + expectedNewFaceInFace6 = {{2,6,4}, {0,6,4}, {0,6,8}, {2,6,8}}; + selectedFaceToCoord[9].push_back(expectedNewFaceInFace6); + } + else if (refinedElem.index() == 10) { + expectedNewFaceInFace6 = {{4,6,4}, {2,6,4}, {2,6,8}, {4,6,8}}; + selectedFaceToCoord[10].push_back(expectedNewFaceInFace6); + } + else if (refinedElem.index() == 11) { + expectedNewFaceInFace6 = {{6,6,4}, {4,6,4}, {4,6,8}, {6,6,8}}; + selectedFaceToCoord[11].push_back(expectedNewFaceInFace6); + } + } + checkNewRefinedFaces(grid, refinedGridData, + selectedFaceToCoord, /* repeatedFaceType = */ 3); // 3-> J+ + + Opm::checkGridWithLgrs(grid, + /* cells_per_dim_vec = */ {{3,2,2}}, + /* lgr_name_vec = */ {"LGR1"}); +} + + +BOOST_AUTO_TEST_CASE(parentCellWithMoreThanSixIntersections_J_FACE_false) +{ + Dune::CpGrid grid; + Opm::createGridAndAddLgrs(grid, + deckTwoCellsInYDirGrid, + /* cells_per_dim_vec */ {{3,2,2}}, + /* startIJK_vec */ {{0,1,0}}, + /* endIJK_vec */ {{1,2,1}}, + /* lgr_name_vec */ {"LGR1"}); + + // LGR1 dimensions = {3,2,2} + // LGR1 indices + // + // k = 1 | 9 10 11| + // | 6 7 8| + // ---------- + // k = 0 | 3 4 5| + // | 0 1 2| + // ------------ + + // Element 1 in level zero grid has two faces of type {J_FACE, false} + // + // Vertices of those faces lie on the plane x = 6 | After refinement, number of subdivisions in LGR1 cell indices + // | y- and z- directions: + // (0,6,9) -----------------(6,6,9) | (0,6,9) --(2,6,9)-(4,6,9)--(6,6,9) x*****x*****x*****x + // | face idx 7 | | | * * | | * * | + // (0,6,8) -----------------(6,6,8) | (0,6,8) --(?,?,?)-(?,?,?)--(6,6,8) x- 6 -x- 7 -x- 8--x + // | | | | * * | | * * | + // | | | | * * | | * * | + // | | | | * * | | * * | + // | face idx 6 | | (0,6,5) **(2,6,5)*(4,6,5)**(6,6,5) x*****x*****x*****x + // | | | | * * | | * * | + // | | | | * * | | 0 * 1 * 2 | + // | | | | * * | | * * | + // (0,6,1) ---------------- (6,6,1) | (0,6,1) --(2,6,1)-(4,6,1)--(6,6,1) x-----x-----x-----x + // | + // | The missing vertices are (2,6,8) and (4,6,8), appering in elements 6,7, or 8 in LGR1. + // | In LGR1 element 6: (2,6,8) + // | In LGR1 element 7: (2,6,8) and (4,6,8) + // | In LGR1 element 8: (4,6,8) + + const auto& refinedGridData = *grid.currentData()[1]; + const auto& parentGridData = *grid.currentData()[0]; + const auto parentElem = Dune::cpgrid::Entity<0>(parentGridData, 1, true); + + BOOST_CHECK_EQUAL(parentGridData.cellToFace(parentElem.index()).size(), 7); + + BOOST_CHECK_EQUAL( refinedGridData.size(3), 40); + // LGR1 dims 3x2x2 -> 4x3x3 vertices + 4 extra missing vertices (0,6,8), (2,6,8), (4,6,8), and (6,6,8). + BOOST_CHECK_EQUAL( refinedGridData.numFaces(), 55); + // LGR1 dims 3x2x2 -> 52 faces (before correction due to missing points) + // 3 of those 52 faces vanished and give origin to 6 new faces: 52 - 3 + 6 = 55 faces + + // Originally, the element not involved in refinement + // had 7 faces. It's neihgbor in level zero + // got refined and the I_FACE that they shared has been + // replaced by 6 refined faces. Then, the leaf element has + // one of each I-,I+,J-, K-, K+, and 1 coarse + 6 refined J+. + checkFaceCountInLeafCoarseElem(grid, + /* expectedTotalFaceCount = */ 12, + /* repeatedFaceType = */ 3, // 3->J+ + /* expoectedRepeatedFaceTypeCount = */ 7); - const std::set expectedLeafVertices = { - {0.,0.,0.}, {0.,0.,8.}, // pillar x = 0, y = 0 - {6.,0.,0.}, {6.,0.,1.}, {6.,0.,8.}, {6.,0.,9.}, // pillar x = 6, y = 0 - {12.,0.,1.}, {12.,0.,9.}, // pillar x = 12, y = 0 - {0.,3.,0.}, {0.,3.,8.}, // pillar x = 0, y = 3 - {6.,3.,0.}, {6.,3.,1.}, {6.,3.,8.}, {6.,3.,9.}, // pillar x = 6, y = 3 - {12.,3.,1.}, {12.,3.,9.}, // pillar x = 12, y = 3 - {0.,6.,0.}, {0.,6.,8.}, // pillar x = 0, y = 6 - {6.,6.,0.}, {6.,6.,1.}, {6.,6.,8.}, {6.,6.,9.}, // pillar x = 6, y = 6 - {12.,6.,1.}, {12.,6.,9.} // pillar x = 12, y = 6 - }; + expectedCellCountRespectToCellToFaceSize(grid, + /* expectedCount7Faces = */ std::vector{2, 3}); // level 0, level 1 - checkLevelVertices(grid, std::vector{expectedLGR1Vertices, expectedLGR2Vertices}); - checkLeafVertices(grid, expectedLeafVertices); + // Collect the expected data to later on check + std::vector>> selectedFaceToCoord{}; + selectedFaceToCoord.resize(grid.levelGridView(1).size(0)); - const std::vector> expectedLGR1Faces = { - {{0.,0.,0.}, {6.,0.,0.}, {6.,3.,0.}, {0.,3.,0.}}, // K_FACE z = 0, face 0 - {{0.,3.,0.}, {6.,3.,0.}, {6.,6.,0.}, {0.,6.,0.}}, // K_FACE z = 0, face 1 - {{0.,0.,8.}, {6.,0.,8.}, {6.,3.,8.}, {0.,3.,8.}}, // K_FACE z = 8, face 2 - {{0.,3.,8.}, {6.,3.,8.}, {6.,6.,8.}, {0.,6.,8.}}, // K_FACE z = 8, face 3 - {{0.,0.,0.}, {0.,3.,0.}, {0.,3.,8.}, {0.,0.,8.}}, // I_FACE x = 0, face 4 - {{0.,3.,0.}, {0.,6.,0.}, {0.,6.,8.}, {0.,3.,8.}}, // I_FACE x = 0, face 5 - {{6.,0.,0.}, {6.,3.,0.}, {6.,3.,1.}, {6.,0.,1.}}, // I_FACE x = 6, face 6 - {{6.,0.,1.}, {6.,3.,1.}, {6.,3.,8.}, {6.,0.,8.}}, // I_FACE x = 6, face 7 - {{6.,3.,0.}, {6.,6.,0.}, {6.,6.,1.}, {6.,3.,1.}}, // I_FACE x = 6, face 8 - {{6.,3.,1.}, {6.,6.,1.}, {6.,6.,8.}, {6.,3.,8.}}, // I_FACE x = 6, face 9 - {{0.,0.,0.}, {6.,0.,0.}, {6.,0.,8.}, {0.,0.,8.}}, // J_FACE y = 0, face 10 - {{0.,3.,0.}, {6.,3.,0.}, {6.,3.,8.}, {0.,3.,8.}}, // J_FACE y = 3, face 11 - {{0.,6.,0.}, {6.,6.,0.}, {6.,6.,8.}, {0.,6.,8.}}, // J_FACE y = 6, face 12 - }; + for (const auto& refinedElem : Dune::elements(grid.levelGridView(1))) { - const std::vector> expectedLGR2Faces = { - {{6.,0.,1.}, {12.,0.,1.}, {12.,3.,1.}, {6.,3.,1.}}, // K_FACE z = 1, face 0 - {{6.,3.,1.}, {12.,3.,1.}, {12.,6.,1.}, {6.,6.,1.}}, // K_FACE z = 1, face 1 - {{6.,0.,9.}, {12.,0.,9.}, {12.,3.,9.}, {6.,3.,9.}}, // K_FACE z = 9, face 2 - {{6.,3.,9.}, {12.,3.,9.}, {12.,6.,9.}, {6.,6.,9.}}, // K_FACE z = 9, face 3 - {{6.,0.,1.}, {6.,3.,1.}, {6.,3.,8.}, {6.,0.,8.}}, // I_FACE x = 6, face 4 - {{6.,0.,8.}, {6.,3.,8.}, {6.,3.,9.}, {6.,0.,9.}}, // I_FACE x = 6, face 5 - {{6.,3.,1.}, {6.,6.,1.}, {6.,6.,8.}, {6.,3.,8.}}, // I_FACE x = 6, face 6 - {{6.,3.,8.}, {6.,6.,8.}, {6.,6.,9.}, {6.,3.,9.}}, // I_FACE x = 6, face 7 - {{12.,0.,1.}, {12.,3.,1.}, {12.,3.,9.}, {12.,0.,9.}}, // I_FACE x = 12, face 8 - {{12.,3.,1.}, {12.,6.,1.}, {12.,6.,9.}, {12.,3.,9.}}, // I_FACE x = 12, face 9 - {{6.,0.,1.}, {12.,0.,1.}, {12.,0.,9.}, {6.,0.,9.}}, // J_FACE y = 0, face 10 - {{6.,3.,1.}, {12.,3.,1.}, {12.,3.,9.}, {6.,3.,9.}}, // J_FACE y = 3, face 11 - {{6.,6.,1.}, {12.,6.,1.}, {12.,6.,9.}, {6.,6.,9.}}, // J_FACE y = 6, face 12 - }; + std::set expectedNewFaceInFace7{}; + std::set expectedNewFaceInFace6{}; + // Vertex order in J_FACE: 0->(i+1)k, 1-> ik, 2->i(k+1), 3->(i+1)(k+1) + // + // i(k+1) <-'2' --------- '3'-> (i+1)(k+1) + // | | + // | | + // ik <-'1' --------- '0'-> (i+1)k - const std::vector> expectedLeafFaces = { - {{0.,0.,0.}, {6.,0.,0.}, {6.,3.,0.}, {0.,3.,0.}}, // K_FACE z = 0, face 0 - {{0.,3.,0.}, {6.,3.,0.}, {6.,6.,0.}, {0.,6.,0.}}, // K_FACE z = 0, face 1 - {{0.,0.,8.}, {6.,0.,8.}, {6.,3.,8.}, {0.,3.,8.}}, // K_FACE z = 8, face 2 - {{0.,3.,8.}, {6.,3.,8.}, {6.,6.,8.}, {0.,6.,8.}}, // K_FACE z = 8, face 3 - {{0.,0.,0.}, {0.,3.,0.}, {0.,3.,8.}, {0.,0.,8.}}, // I_FACE x = 0, face 6 - {{0.,3.,0.}, {0.,6.,0.}, {0.,6.,8.}, {0.,3.,8.}}, // I_FACE x = 0, face 5 - {{6.,0.,0.}, {6.,3.,0.}, {6.,3.,1.}, {6.,0.,1.}}, // I_FACE x = 6, face 6 - {{6.,3.,0.}, {6.,6.,0.}, {6.,6.,1.}, {6.,3.,1.}}, // I_FACE x = 6, face 7 - {{0.,0.,0.}, {6.,0.,0.}, {6.,0.,8.}, {0.,0.,8.}}, // J_FACE y = 0, face 8 - {{0.,3.,0.}, {6.,3.,0.}, {6.,3.,8.}, {0.,3.,8.}}, // J_FACE y = 3, face 9 - {{0.,6.,0.}, {6.,6.,0.}, {6.,6.,8.}, {0.,6.,8.}}, // J_FACE y = 6, face 10 - {{6.,0.,1.}, {12.,0.,1.}, {12.,3.,1.}, {6.,3.,1.}}, // K_FACE z = 1, face 11 - {{6.,3.,1.}, {12.,3.,1.}, {12.,6.,1.}, {6.,6.,1.}}, // K_FACE z = 1, face 12 - {{6.,0.,9.}, {12.,0.,9.}, {12.,3.,9.}, {6.,3.,9.}}, // K_FACE z = 9, face 13 - {{6.,3.,9.}, {12.,3.,9.}, {12.,6.,9.}, {6.,6.,9.}}, // K_FACE z = 9, face 14 - {{6.,0.,1.}, {6.,3.,1.}, {6.,3.,8.}, {6.,0.,8.}}, // I_FACE x = 6, face 15 - {{6.,0.,8.}, {6.,3.,8.}, {6.,3.,9.}, {6.,0.,9.}}, // I_FACE x = 6, face 16 - {{6.,3.,1.}, {6.,6.,1.}, {6.,6.,8.}, {6.,3.,8.}}, // I_FACE x = 6, face 17 - {{6.,3.,8.}, {6.,6.,8.}, {6.,6.,9.}, {6.,3.,9.}}, // I_FACE x = 6, face 18 - {{12.,0.,1.}, {12.,3.,1.}, {12.,3.,9.}, {12.,0.,9.}}, // I_FACE x = 12, face 19 - {{12.,3.,1.}, {12.,6.,1.}, {12.,6.,9.}, {12.,3.,9.}}, // I_FACE x = 12, face 20 - {{6.,0.,1.}, {12.,0.,1.}, {12.,0.,9.}, {6.,0.,9.}}, // J_FACE y = 0, face 21 - {{6.,3.,1.}, {12.,3.,1.}, {12.,3.,9.}, {6.,3.,9.}}, // J_FACE y = 3, face 22 - {{6.,6.,1.}, {12.,6.,1.}, {12.,6.,9.}, {6.,6.,9.}}, // J_FACE y = 6, face 23 - }; + if (refinedElem.index() == 6) { + // this element has to have 7 faces: 1 I-,I+,J+,K-,K+, and 2 J-: + // (0,6,9) --(2,6,9) + // | * J_FACE, false with vertices (0,6,8),(2,6,8),(2,6,9),(0,6,9) + // (0,6,8) **(2,6,8) + // | * J_FACE, false with vertices (0,6,5),(2,6,5),(2,6,8),(0,6,8) + // | * + // (0,6,5) --(2,6,5) + expectedNewFaceInFace7 = {{2,6,8}, {0,6,8}, {0,6,9}, {2,6,9}}; + expectedNewFaceInFace6 = {{2,6,5}, {0,6,5}, {0,6,8}, {2,6,8}}; - checkFaces(refinedGrid1, expectedLGR1Faces); - checkFaces(refinedGrid2, expectedLGR2Faces); - checkFaces(leafGrid, expectedLeafFaces); + selectedFaceToCoord[6].push_back(expectedNewFaceInFace7); + selectedFaceToCoord[6].push_back(expectedNewFaceInFace6); + } + else if (refinedElem.index() == 7) { + // this element has to have 7 faces: 1 I-,I+,J+,K-,K+, and 2 J-: + // (2,6,9) --(4,6,9) + // | * J_FACE, false with vertices (2,6,8),(4,6,8),(4,6,9),(2,6,9) + // (2,6,8) **(4,6,8) + // | * J_FACE, false with vertices (2,6,5),(4,6,5),(4,6,8),(2,6,8) + // | * + // (2,6,5) --(4,6,5) + expectedNewFaceInFace7 = {{4,6,8}, {2,6,8}, {2,6,9}, {4,6,9}}; + expectedNewFaceInFace6 = {{4,6,5}, {2,6,5}, {2,6,8}, {4,6,8}}; + + selectedFaceToCoord[7].push_back(expectedNewFaceInFace7); + selectedFaceToCoord[7].push_back(expectedNewFaceInFace6); + } + else if (refinedElem.index() == 8) { + // this element has to have 7 faces: 1 I-,I+,J+,K-,K+, and 2 J-: + // (4,6,9) --(6,6,9) + // | * J_FACE, false with vertices (4,6,8),(6,6,8),(6,6,9),(4,6,9) + // (4,6,8) **(6,6,8) + // | * J_FACE, false with vertices (4,6,5),(6,6,5),(6,6,8),(4,6,8) + // | * + // (4,6,5) --(6,6,5) + expectedNewFaceInFace7 = {{6,6,8}, {4,6,8}, {4,6,9}, {6,6,9}}; + expectedNewFaceInFace6 = {{6,6,5}, {4,6,5}, {4,6,8}, {6,6,8}}; + + selectedFaceToCoord[8].push_back(expectedNewFaceInFace7); + selectedFaceToCoord[8].push_back(expectedNewFaceInFace6); + } + else if (refinedElem.index() == 0) { + expectedNewFaceInFace6 = {{2,6,1}, {0,6,1}, {0,6,5}, {2,6,5}}; + selectedFaceToCoord[0].push_back(expectedNewFaceInFace6); + } + else if (refinedElem.index() == 1) { + expectedNewFaceInFace6 = {{4,6,1}, {2,6,1}, {2,6,5}, {4,6,5}}; + selectedFaceToCoord[1].push_back(expectedNewFaceInFace6); + } + else if (refinedElem.index() == 2) { + expectedNewFaceInFace6 = {{6,6,1},{4,6,1}, {4,6,5}, {6,6,5}}; + selectedFaceToCoord[2].push_back(expectedNewFaceInFace6); + } + } + checkNewRefinedFaces(grid, refinedGridData, + selectedFaceToCoord, /* repeatedFaceType = */ 2); // 2-> J- Opm::checkGridWithLgrs(grid, - {{1,2,1}, {1,2,1}}, // cells_per_dim_vec - {"LGR1", "LGR2"}); // lgr_name_vec + /* cells_per_dim_vec = */ {{3,2,2}}, + /* lgr_name_vec = */ {"LGR1"}); } - -BOOST_AUTO_TEST_CASE(simpleSameLgr) -{ - // Level zero grid dims = 2x1x1 - // - // cell 0 - // bottom face corners (0,0,0), (6,0,0), (0,6,0), (6,6,0) - // top face corners (0,0,8), (6,0,8), (0,6,8), (6,6,8) - // - // cell 1 - // bottom face corners (6,0,1), (12,0,1), (6,6,1), (12,6,1) - // top face corners (6,0,9), (12,0,9), (12,6,9), (12,6,9) - const std::string deckString = - R"(RUNSPEC +// Level zero grid dims = 2x2x1 +// +// Cell 0 (x=0..6, y=0..6) +// bottom face corners (0,0,0), (6,0,0), (0,6,1), (6,6,1) +// top face corners (0,0,8), (6,0,8), (0,6,9), (6,6,9) +// +// Cell 1 (x=6..12, y=0..6) +// bottom face corners (6,0,1), (12,0,1), (6,6,2), (12,6,2) +// top face corners (6,0,9), (12,0,9), (6,6,10), (12,6,10) +// +// Cell 2 (x=0..6, y=6..12) +// bottom face corners (0,6,0), (6,6,0), (0,12,1), (6,12,1) +// top face corners (0,6,8), (6,6,8), (0,12,9), (6,12,9) +// +// Cell 3 (x=6..12, y=6..12) +// bottom face corners (6,6,1), (12,6,1), (6,12,2), (12,12,2) +// top face corners (6,6,9), (12,6,9), (6,12,10), (12,12,10) + +const std::string deckTwoColumnsGrid = + R"(RUNSPEC DIMENS - 2 1 1 / + 2 1 2 / GRID COORD - 0 0 0 0 0 9 - 6 0 0 6 0 9 -12 0 0 12 0 9 + 0 0 0 0 0 17 + 6 0 0 6 0 17 +12 0 0 12 0 17 - 0 6 0 0 6 9 - 6 6 0 6 6 9 -12 6 0 12 6 9 + 0 6 0 0 6 17 + 6 6 0 6 6 17 +12 6 0 12 6 17 / ZCORN 0 0 1 1 0 0 1 1 8 8 9 9 8 8 9 9 + + 8 8 9 9 8 8 9 9 +16 16 17 17 16 16 17 17 / ACTNUM -2*1 +4*1 / PORO -2*0.15 +4*0.15 / )"; +BOOST_AUTO_TEST_CASE(faultBetweenTwoColumnsSameLgr) +{ Dune::CpGrid grid; Opm::createGridAndAddLgrs(grid, - deckString, - /* cells_per_dim_vec */ {{1,2,1}}, + deckTwoColumnsGrid, + /* cells_per_dim_vec */{{1,2,1}}, /* startIJK_vec */ {{0,0,0}}, - /* endIJK_vec */ {{2,1,1}}, + /* endIJK_vec */ {{2,1,2}}, /* lgr_name_vec */ {"LGR1"}); - // Element 0 and element 1 in level zero grid share an I_FACE (with face index 2) - // - // Vertices of those faces lie on the plane x = 6 | After refinement, number of subdivisions in - // | y- and z- directions: - // - // (6,0,9) -----------------(6,6,9) | (6,0,9) --(6,3,9)---(6,6,9) - // | face idx 3 | | | * | - // (6,0,8) ---------------- (6,6,8) | (6,0,8) --(6,3,9)---(6,6,8) - // | | | | * | - // | | | | * | - // | | | | * | - // | face idx 2 | | | * | - // | | | | * | - // | | | | * | - // | | | | * | - // | | | | * | - // (6,0,1) -----------------(6,6,1) | (6,0,1) --(6,3,1)---(6,6,1) - // | face idx 1 | | | * | - // (6,0,0) -----------------(6,6,0) | (6,0,0) --(6,3,0)---(6,6,0) - // | - const auto& parentGridData = *grid.currentData()[0]; - const auto parent0 = Dune::cpgrid::Entity<0>(parentGridData, 0, true); - const auto parent1 = Dune::cpgrid::Entity<0>(parentGridData, 1, true); - - BOOST_CHECK_EQUAL(parentGridData.cellToFace(parent0.index()).size(), 7); - BOOST_CHECK_EQUAL(parentGridData.cellToFace(parent1.index()).size(), 7); - - const auto& refinedGrid1 = *grid.currentData()[1]; - BOOST_CHECK_EQUAL( refinedGrid1.size(3), 24); - BOOST_CHECK_EQUAL( refinedGrid1.numFaces(), 24); + Opm::checkGridWithLgrs(grid, + /* cells_per_dim_vec = */ {{1,2,1}}, + /* lgr_name_vec = */ {"LGR1"}); - const auto& leafGrid = grid.currentLeafData(); - BOOST_CHECK_EQUAL( leafGrid.size(3), 24); - BOOST_CHECK_EQUAL( leafGrid.numFaces(), 24); +} - const std::set expectedVertices = { - {0.,0.,0.}, {0.,0.,8.}, // pillar x = 0, y = 0 - {6.,0.,0.}, {6.,0.,1.}, {6.,0.,8.}, {6.,0.,9.}, // pillar x = 6, y = 0 - {12.,0.,1.}, {12.,0.,9.}, // pillar x = 12, y = 0 - {0.,3.,0.}, {0.,3.,8.}, // pillar x = 0, y = 3 - {6.,3.,0.}, {6.,3.,1.}, {6.,3.,8.}, {6.,3.,9.}, // pillar x = 6, y = 3 - {12.,3.,1.}, {12.,3.,9.}, // pillar x = 12, y = 3 - {0.,6.,0.}, {0.,6.,8.}, // pillar x = 0, y = 6 - {6.,6.,0.}, {6.,6.,1.}, {6.,6.,8.}, {6.,6.,9.}, // pillar x = 6, y = 6 - {12.,6.,1.}, {12.,6.,9.} // pillar x = 12, y = 6 - }; +BOOST_AUTO_TEST_CASE(faultBetweenTwoColumnsDifferentVerticalLgrs) +{ + Dune::CpGrid grid; + Opm::createGridAndAddLgrs(grid, + deckTwoColumnsGrid, + /* cells_per_dim_vec */{{1,2,1}, {1,2,1}}, + /* startIJK_vec */ {{0,0,0}, {1,0,0}}, + /* endIJK_vec */ {{1,1,2}, {2,1,2}}, + /* lgr_name_vec */ {"LGR1", "LGR2"}); - checkLevelVertices(grid, std::vector{expectedVertices}); - checkLeafVertices(grid, expectedVertices); + Opm::checkGridWithLgrs(grid, + /* cells_per_dim_vec = */ {{1,2,1}, {1,2,1}}, + /* lgr_name_vec = */ {"LGR1", "LGR2"}); - const std::vector> expectedFaces = { - {{0.,0.,0.}, {6.,0.,0.}, {6.,3.,0.}, {0.,3.,0.}}, // K_FACE z = 0, face 0 - {{0.,3.,0.}, {6.,3.,0.}, {6.,6.,0.}, {0.,6.,0.}}, // K_FACE z = 0, face 1 - {{0.,0.,8.}, {6.,0.,8.}, {6.,3.,8.}, {0.,3.,8.}}, // K_FACE z = 8, face 2 - {{0.,3.,8.}, {6.,3.,8.}, {6.,6.,8.}, {0.,6.,8.}}, // K_FACE z = 8, face 3 - {{0.,0.,0.}, {0.,3.,0.}, {0.,3.,8.}, {0.,0.,8.}}, // I_FACE x = 0, face 4 - {{0.,3.,0.}, {0.,6.,0.}, {0.,6.,8.}, {0.,3.,8.}}, // I_FACE x = 0, face 5 - {{6.,0.,0.}, {6.,3.,0.}, {6.,3.,1.}, {6.,0.,1.}}, // I_FACE x = 6, face 6 - {{6.,3.,0.}, {6.,6.,0.}, {6.,6.,1.}, {6.,3.,1.}}, // I_FACE x = 6, face 7 - {{0.,0.,0.}, {6.,0.,0.}, {6.,0.,8.}, {0.,0.,8.}}, // J_FACE y = 0, face 8 - {{0.,3.,0.}, {6.,3.,0.}, {6.,3.,8.}, {0.,3.,8.}}, // J_FACE y = 3, face 9 - {{0.,6.,0.}, {6.,6.,0.}, {6.,6.,8.}, {0.,6.,8.}}, // J_FACE y = 6, face 10 - {{6.,0.,1.}, {12.,0.,1.}, {12.,3.,1.}, {6.,3.,1.}}, // K_FACE z = 1, face 11 - {{6.,3.,1.}, {12.,3.,1.}, {12.,6.,1.}, {6.,6.,1.}}, // K_FACE z = 1, face 12 - {{6.,0.,9.}, {12.,0.,9.}, {12.,3.,9.}, {6.,3.,9.}}, // K_FACE z = 9, face 13 - {{6.,3.,9.}, {12.,3.,9.}, {12.,6.,9.}, {6.,6.,9.}}, // K_FACE z = 9, face 14 - {{6.,0.,1.}, {6.,3.,1.}, {6.,3.,8.}, {6.,0.,8.}}, // I_FACE x = 6, face 15 - {{6.,0.,8.}, {6.,3.,8.}, {6.,3.,9.}, {6.,0.,9.}}, // I_FACE x = 6, face 16 - {{6.,3.,1.}, {6.,6.,1.}, {6.,6.,8.}, {6.,3.,8.}}, // I_FACE x = 6, face 17 - {{6.,3.,8.}, {6.,6.,8.}, {6.,6.,9.}, {6.,3.,9.}}, // I_FACE x = 6, face 18 - {{12.,0.,1.}, {12.,3.,1.}, {12.,3.,9.}, {12.,0.,9.}}, // I_FACE x = 12, face 19 - {{12.,3.,1.}, {12.,6.,1.}, {12.,6.,9.}, {12.,3.,9.}}, // I_FACE x = 12, face 20 - {{6.,0.,1.}, {12.,0.,1.}, {12.,0.,9.}, {6.,0.,9.}}, // J_FACE y = 0, face 21 - {{6.,3.,1.}, {12.,3.,1.}, {12.,3.,9.}, {6.,3.,9.}}, // J_FACE y = 3, face 22 - {{6.,6.,1.}, {12.,6.,1.}, {12.,6.,9.}, {6.,6.,9.}}, // J_FACE y = 6, face 23 - }; +} - checkFaces(refinedGrid1, expectedFaces); - checkFaces(leafGrid, expectedFaces); +BOOST_AUTO_TEST_CASE(faultBetweenTwoColumnsDifferentHorizontalLgrs) +{ + Dune::CpGrid grid; + Opm::createGridAndAddLgrs(grid, + deckTwoColumnsGrid, + /* cells_per_dim_vec */{{1,2,1}, {1,2,1}}, + /* startIJK_vec */ {{0,0,0}, {0,0,1}}, + /* endIJK_vec */ {{2,1,1}, {2,1,2}}, + /* lgr_name_vec */ {"LGR1", "LGR2"}); Opm::checkGridWithLgrs(grid, - {{1,2,1}}, // cells_per_dim_vec - {"LGR1"}); // lgr_name_vec + /* cells_per_dim_vec = */ {{1,2,1}, {1,2,1}}, + /* lgr_name_vec = */ {"LGR1", "LGR2"}); + } From 4e425f790d33b6e4ad310ad67f98cb5da4590fb9 Mon Sep 17 00:00:00 2001 From: Antonella Ritorto Date: Mon, 17 Aug 2026 10:43:01 +0200 Subject: [PATCH 3/3] Add explict check cell-to-face and face-to-cell in simple grid, with 1x2x1 children per parent --- opm/grid/cpgrid/LgrFaultHelpers.hpp | 5 +- opm/grid/cpgrid/LgrHelpers.cpp | 6 +- tests/cpgrid/lgr/lgrs_and_faults_test.cpp | 748 ++++++++++++++-------- 3 files changed, 492 insertions(+), 267 deletions(-) diff --git a/opm/grid/cpgrid/LgrFaultHelpers.hpp b/opm/grid/cpgrid/LgrFaultHelpers.hpp index ddbdf7d21..39853014e 100644 --- a/opm/grid/cpgrid/LgrFaultHelpers.hpp +++ b/opm/grid/cpgrid/LgrFaultHelpers.hpp @@ -104,9 +104,10 @@ struct FieldVectorLess { bool operator()(const Dune::FieldVector& v, const Dune::FieldVector& w) const { + double tolerance = 1e-8; for (int i = 0; i < 3; ++i) { - if (v[i] < w[i]) return true; - if (v[i] > w[i]) return false; + if (v[i] < w[i] - tolerance) return true; + if (v[i] > w[i] + tolerance) return false; } return false; } diff --git a/opm/grid/cpgrid/LgrHelpers.cpp b/opm/grid/cpgrid/LgrHelpers.cpp index d0657afa1..84e9eb568 100644 --- a/opm/grid/cpgrid/LgrHelpers.cpp +++ b/opm/grid/cpgrid/LgrHelpers.cpp @@ -1393,7 +1393,7 @@ void populateRefinedCells(const Dune::cpgrid::CpGridData& current_data, if (!Opm::Lgr::areClose(w,v)) { continue; } - else { std::cout<< v[0]<< " " << v[1] << " " << v[2] <; +// In all the test cases, which are quite simple grids of dimensions +// 2x1x1, 1x2x1, or 2x1x2, the grid cells are shifted such that +// every cell in the level-zero grid has seven faces. +void checkFaultInLevelZeroGrid(const Dune::CpGrid& grid) +{ + const auto& parentGridData = *grid.currentData()[0]; + for (const auto& element : Dune::elements(grid.levelGridView(0))) { + BOOST_CHECK_EQUAL(parentGridData.cellToFace(element.index()).size(), 7); + } +} + +// In a without-faults-grid of dimensions {nx, ny, nz}, +// - the total amount of vertices is given by (nx+1)*(ny+1)*(nz+1) +// - the total amount of faces is given by ((nx+1)*ny*nz) + (nx*(ny+1)*nz) + (nx*ny*(nz+1)) +// Since now the refinement is aware of +// (a) parent cell having more than one face per type +// (e.g. level zero grid having cell 0 with two I+ faces and cell 1 with two I- faces) +// (b) neighboring refinements with faults (creating new vertices and faces) +// the total amount of vertices and faces in presence of faults may be larger than +// (nx+1)*(ny+1)*(nz+1) and ((nx+1)*ny*nz) + (nx*(ny+1)*nz) + (nx*ny*(nz+1)) respectively. +void checkVertexAndFaceCount(const Dune::cpgrid::CpGridData& gridData, + const std::array& nxnynz, + int newVertexCount, + int vanishedFaceCount, + int newFaceCount) +{ + const auto& [nx,ny,nz] = nxnynz; + BOOST_CHECK_EQUAL( gridData.size(3), (nx+1)*(ny+1)*(nz+1) + newVertexCount); + BOOST_CHECK_EQUAL( gridData.numFaces(), ((nx+1)*ny*nz) + (nx*(ny+1)*nz) + (nx*ny*(nz+1)) - vanishedFaceCount + newFaceCount); +} + +void checkVertexAndFaceLeafCount(const Dune::CpGrid& grid, + int sharedBetweenLevelsVertexCount, + int sharedBetweenLevelsFaceCount) +{ int vertexCount = 0; + int faceCount = 0; + for (int level = 0; level <= grid.maxLevel(); ++level) { + vertexCount += grid.currentData()[level]->size(3); + faceCount += grid.currentData()[level]->numFaces(); + } + + BOOST_CHECK_EQUAL( grid.size(3), vertexCount - sharedBetweenLevelsVertexCount); + BOOST_CHECK_EQUAL( grid.numFaces(), faceCount - sharedBetweenLevelsFaceCount); +} void checkFaceCountPerType(int repeatedFaceType, int expectedRepeatedFaceTypeCount, @@ -256,12 +300,29 @@ bool equalFaces(const std::vector>>& act } void checkFaces(const Dune::cpgrid::CpGridData& gridData, - const std::vector>& expectedFaces) + const std::vector>& expectedFaces, + const std::vector>& expectedFaceToCell) { std::vector>> actualFaces{}; actualFaces.resize(gridData.numFaces()); for (int i = 0; i < gridData.numFaces(); ++i) { + + const auto& faceToCell = gridData.faceToCell(i); + BOOST_CHECK(faceToCell.size() <= 2); + + const auto& [cell1, cell2] = expectedFaceToCell[i]; + int expectedFaceToCellSize = (cell2 == -1)? 1 : 2; + + if (expectedFaceToCellSize>1) { + BOOST_CHECK_EQUAL( faceToCell[0].index(), cell1); + BOOST_CHECK_EQUAL( faceToCell[1].index(), cell2); + } + else { + BOOST_CHECK_EQUAL( faceToCell[0].index(), cell1); + } + + for (const auto& vertexIdx : gridData.faceToPoint(i)){ actualFaces[i].push_back(Dune::cpgrid::Entity<3>(gridData, vertexIdx, true).geometry().center()); } @@ -270,6 +331,37 @@ void checkFaces(const Dune::cpgrid::CpGridData& gridData, BOOST_CHECK(equalFaces(actualFaces, expectedFaces)); } +void checkCellToFace(const Dune::CpGrid& grid, int level, + const std::vector>>& expectedCellToFace) +{ + bool isLeafGrid = (level<0); + int cell_count = isLeafGrid? grid.leafGridView().size(0) : grid.levelGridView(level).size(0); + + BOOST_CHECK_EQUAL(cell_count, expectedCellToFace.size()); + + const auto& elements = isLeafGrid? Dune::elements(grid.leafGridView()) : Dune::elements(grid.levelGridView(level)); + const auto& gridData = isLeafGrid? grid.currentLeafData() : *grid.currentData()[level]; + + for (const auto& element : elements) { + const auto& cellToFace = gridData.cellToFace(element.index()); + + std::vector>> actualCellToFace{}; + actualCellToFace.resize(cellToFace.size()); + + BOOST_CHECK_EQUAL( cellToFace.size(), expectedCellToFace[element.index()].size()); + + int count = 0; + for (const auto& face : cellToFace) { + for (const auto& vertexIdx : gridData.faceToPoint(face.index())){ + actualCellToFace[count].push_back(Dune::cpgrid::Entity<3>(gridData, vertexIdx, true).geometry().center()); + } + ++count; + } + + BOOST_CHECK(equalFaces(actualCellToFace, expectedCellToFace[element.index()])); + } +} + // Level zero grid dims = 2x1x1 // // cell 0 @@ -310,6 +402,387 @@ PORO / )"; +// In the test cases "simpleRefinementDiffLgrs" and "simpleRefinementSameLgr" +// each parent cell gets refined into 1x2x1 children. In this way, it's pretty +// easy and not so long to provide the expected cell-to-face and face-to-cell +// relationships, as well as the vertices coordinates and the face vertices +// coordinates for level and leaf grids. +// The leaf grid view in both test cases coincide, therefore we introduce below +// a few "expected-leaf-grid" data that will be used for both test cases. + +// Element 0 and element 1 in level zero grid share an I_FACE (with face index 2) +// +// Vertices of those faces lie on the plane x = 6 | After refinement, number of subdivisions in +// | y- and z- directions: +// +// (6,0,9) -----------------(6,6,9) | (6,0,9) --(6,3,9)---(6,6,9) +// | face idx 3 | | | * | +// (6,0,8) ---------------- (6,6,8) | (6,0,8) --(6,3,8)---(6,6,8) +// | | | | * | +// | | | | * | +// | | | | * | +// | face idx 2 | | | * | +// | | | | * | +// | | | | * | +// | | | | * | +// | | | | * | +// (6,0,1) -----------------(6,6,1) | (6,0,1) --(6,3,1)---(6,6,1) +// | face idx 1 | | | * | +// (6,0,0) -----------------(6,6,0) | (6,0,0) --(6,3,0)---(6,6,0) +// | + +// "simpleRefinementDiffLgrs" +// +// Recall that for a level zero input grid of dimensions 2x1x1 that gets refined +// LGR1 and LGR2, with 1x2x1 children per cell, +// +// k = 0 | cell 0 | cell 1 | level zero grid +// +// Parent cell from level zero refined into 1x2x2 children: +// k = 0, j = 1 | cell 1 (LGR*) | level 1 and 2 grid cell indices are equal. +// |---------------| +// j = 0 | cell 0 (LGR*) | +// +// k = 0, j = 1 | cell 1 (from LGR1) | cell 3 (from LGR2)| leaf grid cell indices +// |--------------------|-------------------| +// j = 0 | cell 0 (from LGR1) | cell 2 (from LGR2)| +// +// +// LGR1 | LGR2 +// New vertices: (6,0,1),(6,3,1),(6,6,1) | (6,0,8),(6,3,8),(6,6,8) +// | +// New faces: | +// (6,0,8) --(6,3,8)---(6,6,8) | (6,0,9) --(6,3,9)---(6,6,9) +// | * | | | * | +// | * | | (6,0,8) --(6,3,8)---(6,6,8) +// | * | | | * | +// (6,0,1) --(6,3,1)---(6,6,1) | | * | +// | * | | | * | +// (6,0,0) --(6,3,0)---(6,6,0) | (6,0,1) --(6,3,1)---(6,6,1) + +// "simpleRefinementSameLgr" +// +// Recall that for a level zero input grid of dimensions 2x1x1 that gets refined +// into one LGR1 with 1x2x1 children per cell, +// +// k = 0 | cell 0 | cell 1 | level zero grid +// +// Entire level zero grid gets refined, each parent cell has 1x2x1 children: +// +// k = 0, j = 1 | cell 1 | cell 3 | level 1 and leaf grid cell indices +// |---------|--------| +// j = 0 | cell 0 | cell 2 | + + +// To avoid creating containers with the same content, here we provide a few +// cell-to-face and face-to-cell relationships that appear in both test cases. + +const std::vector> expectedLeafCellToFace0 = { + {{0.,0.,0.}, {6.,0.,0.}, {6.,3.,0.}, {0.,3.,0.}}, // K_FACE z = 0, face 0 + {{0.,0.,8.}, {6.,0.,8.}, {6.,3.,8.}, {0.,3.,8.}}, // K_FACE z = 8, face 1 + {{0.,0.,0.}, {0.,3.,0.}, {0.,3.,8.}, {0.,0.,8.}}, // I_FACE x = 0, face 2 + {{6.,0.,0.}, {6.,3.,0.}, {6.,3.,1.}, {6.,0.,1.}}, // I_FACE x = 6, face 3 + {{6.,0.,1.}, {6.,3.,1.}, {6.,3.,8.}, {6.,0.,8.}}, // I_FACE x = 6, face 4 + {{0.,0.,0.}, {6.,0.,0.}, {6.,0.,8.}, {0.,0.,8.}}, // J_FACE y = 0, face 5 + {{0.,3.,0.}, {6.,3.,0.}, {6.,3.,8.}, {0.,3.,8.}} // J_FACE y = 3, face 6 +}; + +const std::vector> expectedLeafCellToFace1 = { + {{0.,3.,0.}, {6.,3.,0.}, {6.,6.,0.}, {0.,6.,0.}}, // K_FACE z = 0, face 0 + {{0.,3.,8.}, {6.,3.,8.}, {6.,6.,8.}, {0.,6.,8.}}, // K_FACE z = 8, face 1 + {{0.,3.,0.}, {0.,6.,0.}, {0.,6.,8.}, {0.,3.,8.}}, // I_FACE x = 0, face 2 + {{6.,3.,0.}, {6.,6.,0.}, {6.,6.,1.}, {6.,3.,1.}}, // I_FACE x = 6, face 3 + {{6.,3.,1.}, {6.,6.,1.}, {6.,6.,8.}, {6.,3.,8.}}, // I_FACE x = 6, face 4 + {{0.,3.,0.}, {6.,3.,0.}, {6.,3.,8.}, {0.,3.,8.}}, // J_FACE y = 3, face 5 + {{0.,6.,0.}, {6.,6.,0.}, {6.,6.,8.}, {0.,6.,8.}} // J_FACE y = 6, face 6 +}; + +const std::vector> expectedLeafCellToFace2 = { + {{6.,0.,1.}, {12.,0.,1.}, {12.,3.,1.}, {6.,3.,1.}}, // K_FACE z = 1, face 0 + {{6.,0.,9.}, {12.,0.,9.}, {12.,3.,9.}, {6.,3.,9.}}, // K_FACE z = 9, face 1 + {{6.,0.,1.}, {6.,3.,1.}, {6.,3.,8.}, {6.,0.,8.}}, // I_FACE x = 6, face 2 + {{6.,0.,8.}, {6.,3.,8.}, {6.,3.,9.}, {6.,0.,9.}}, // I_FACE x = 6, face 3 + {{12.,0.,1.}, {12.,3.,1.}, {12.,3.,9.}, {12.,0.,9.}}, // I_FACE x = 12, face 4 + {{6.,0.,1.}, {12.,0.,1.}, {12.,0.,9.}, {6.,0.,9.}}, // J_FACE y = 0, face 5 + {{6.,3.,1.}, {12.,3.,1.}, {12.,3.,9.}, {6.,3.,9.}}, // J_FACE y = 3, face 6 +}; + +const std::vector> expectedLeafCellToFace3 = { + {{6.,3.,1.}, {12.,3.,1.}, {12.,6.,1.}, {6.,6.,1.}}, // K_FACE z = 1, face 0 + {{6.,3.,9.}, {12.,3.,9.}, {12.,6.,9.}, {6.,6.,9.}}, // K_FACE z = 9, face 1 + {{6.,3.,1.}, {6.,6.,1.}, {6.,6.,8.}, {6.,3.,8.}}, // I_FACE x = 6, face 2 + {{6.,3.,8.}, {6.,6.,8.}, {6.,6.,9.}, {6.,3.,9.}}, // I_FACE x = 6, face 3 + {{12.,3.,1.}, {12.,6.,1.}, {12.,6.,9.}, {12.,3.,9.}}, // I_FACE x = 12, face 4 + {{6.,3.,1.}, {12.,3.,1.}, {12.,3.,9.}, {6.,3.,9.}}, // J_FACE y = 3, face 5 + {{6.,6.,1.}, {12.,6.,1.}, {12.,6.,9.}, {6.,6.,9.}}, // J_FACE y = 6, face 6 +}; + +// Leaf faces whose faceToCell has 2 elements +// +// (6,0,8) --(6,3,9)---(6,6,8) +// | * | +// | * | +// | * | leaf face index 15 to cells = {0, 2} +// | face * face | leaf face index 17 to cells = {1, 3} +// | idx * idx | +// | 15 * 17 | +// | * | +// | * | +// (6,0,1) --(6,3,1)---(6,6,1) + +const std::vector> expectedLeafFaces = { + {{0.,0.,0.}, {6.,0.,0.}, {6.,3.,0.}, {0.,3.,0.}}, // K_FACE z = 0, face 0 + {{0.,3.,0.}, {6.,3.,0.}, {6.,6.,0.}, {0.,6.,0.}}, // K_FACE z = 0, face 1 + {{0.,0.,8.}, {6.,0.,8.}, {6.,3.,8.}, {0.,3.,8.}}, // K_FACE z = 8, face 2 + {{0.,3.,8.}, {6.,3.,8.}, {6.,6.,8.}, {0.,6.,8.}}, // K_FACE z = 8, face 3 + {{0.,0.,0.}, {0.,3.,0.}, {0.,3.,8.}, {0.,0.,8.}}, // I_FACE x = 0, face 4 + {{0.,3.,0.}, {0.,6.,0.}, {0.,6.,8.}, {0.,3.,8.}}, // I_FACE x = 0, face 5 + {{6.,0.,0.}, {6.,3.,0.}, {6.,3.,1.}, {6.,0.,1.}}, // I_FACE x = 6, face 6 + {{6.,3.,0.}, {6.,6.,0.}, {6.,6.,1.}, {6.,3.,1.}}, // I_FACE x = 6, face 7 + {{0.,0.,0.}, {6.,0.,0.}, {6.,0.,8.}, {0.,0.,8.}}, // J_FACE y = 0, face 8 + {{0.,3.,0.}, {6.,3.,0.}, {6.,3.,8.}, {0.,3.,8.}}, // J_FACE y = 3, face 9 + {{0.,6.,0.}, {6.,6.,0.}, {6.,6.,8.}, {0.,6.,8.}}, // J_FACE y = 6, face 10 + {{6.,0.,1.}, {12.,0.,1.}, {12.,3.,1.}, {6.,3.,1.}}, // K_FACE z = 1, face 11 + {{6.,3.,1.}, {12.,3.,1.}, {12.,6.,1.}, {6.,6.,1.}}, // K_FACE z = 1, face 12 + {{6.,0.,9.}, {12.,0.,9.}, {12.,3.,9.}, {6.,3.,9.}}, // K_FACE z = 9, face 13 + {{6.,3.,9.}, {12.,3.,9.}, {12.,6.,9.}, {6.,6.,9.}}, // K_FACE z = 9, face 14 + {{6.,0.,1.}, {6.,3.,1.}, {6.,3.,8.}, {6.,0.,8.}}, // I_FACE x = 6, face 15 + {{6.,0.,8.}, {6.,3.,8.}, {6.,3.,9.}, {6.,0.,9.}}, // I_FACE x = 6, face 16 + {{6.,3.,1.}, {6.,6.,1.}, {6.,6.,8.}, {6.,3.,8.}}, // I_FACE x = 6, face 17 + {{6.,3.,8.}, {6.,6.,8.}, {6.,6.,9.}, {6.,3.,9.}}, // I_FACE x = 6, face 18 + {{12.,0.,1.}, {12.,3.,1.}, {12.,3.,9.}, {12.,0.,9.}}, // I_FACE x = 12, face 19 + {{12.,3.,1.}, {12.,6.,1.}, {12.,6.,9.}, {12.,3.,9.}}, // I_FACE x = 12, face 20 + {{6.,0.,1.}, {12.,0.,1.}, {12.,0.,9.}, {6.,0.,9.}}, // J_FACE y = 0, face 21 + {{6.,3.,1.}, {12.,3.,1.}, {12.,3.,9.}, {6.,3.,9.}}, // J_FACE y = 3, face 22 + {{6.,6.,1.}, {12.,6.,1.}, {12.,6.,9.}, {6.,6.,9.}}, // J_FACE y = 6, face 23 +}; + +const std::vector> expectedLeafFaceToCell = { + {0, -1}, // K_FACE z = 0, face 0 {{0.,0.,0.}, {6.,0.,0.}, {6.,3.,0.}, {0.,3.,0.}} + {1, -1}, // K_FACE z = 0, face 1 {{0.,3.,0.}, {6.,3.,0.}, {6.,6.,0.}, {0.,6.,0.}} + {0, -1}, // K_FACE z = 8, face 2 {{0.,0.,8.}, {6.,0.,8.}, {6.,3.,8.}, {0.,3.,8.}} + {1, -1}, // K_FACE z = 8, face 3 {{0.,3.,8.}, {6.,3.,8.}, {6.,6.,8.}, {0.,6.,8.}} + {0, -1}, // I_FACE x = 0, face 4 {{0.,0.,0.}, {0.,3.,0.}, {0.,3.,8.}, {0.,0.,8.}} + {1, -1}, // I_FACE x = 0, face 5 {{0.,3.,0.}, {0.,6.,0.}, {0.,6.,8.}, {0.,3.,8.}} + {0, -1}, // I_FACE x = 6, face 6 {{6.,0.,0.}, {6.,3.,0.}, {6.,3.,1.}, {6.,0.,1.}} + {1, -1}, // I_FACE x = 6, face 7 {{6.,3.,0.}, {6.,6.,0.}, {6.,6.,1.}, {6.,3.,1.}} + {0, -1}, // J_FACE y = 0, face 8 {{0.,0.,0.}, {6.,0.,0.}, {6.,0.,8.}, {0.,0.,8.}} + {0, 1}, // J_FACE y = 3, face 9 {{0.,3.,0.}, {6.,3.,0.}, {6.,3.,8.}, {0.,3.,8.}} + {1, -1}, // J_FACE y = 6, face 10 {{0.,6.,0.}, {6.,6.,0.}, {6.,6.,8.}, {0.,6.,8.}} + {2, -1}, // K_FACE z = 1, face 11 {{6.,0.,1.}, {12.,0.,1.}, {12.,3.,1.}, {6.,3.,1.}} + {3, -1}, // K_FACE z = 1, face 12 {{6.,3.,1.}, {12.,3.,1.}, {12.,6.,1.}, {6.,6.,1.}} + {2, -1}, // K_FACE z = 9, face 13 {{6.,0.,9.}, {12.,0.,9.}, {12.,3.,9.}, {6.,3.,9.}} + {3, -1}, // K_FACE z = 9, face 14 {{6.,3.,9.}, {12.,3.,9.}, {12.,6.,9.}, {6.,6.,9.}} + {0, 2}, // I_FACE x = 6, face 15 {{6.,0.,1.}, {6.,3.,1.}, {6.,3.,8.}, {6.,0.,8.}} + {2, -1}, // I_FACE x = 6, face 16 {{6.,0.,8.}, {6.,3.,8.}, {6.,3.,9.}, {6.,0.,9.}} + {1, 3}, // I_FACE x = 6, face 17 {{6.,3.,1.}, {6.,6.,1.}, {6.,6.,8.}, {6.,3.,8.}} + {3, -1}, // I_FACE x = 6, face 18 {{6.,3.,8.}, {6.,6.,8.}, {6.,6.,9.}, {6.,3.,9.}} + {2, -1}, // I_FACE x = 12, face 19 {{12.,0.,1.}, {12.,3.,1.}, {12.,3.,9.}, {12.,0.,9.}} + {3, -1}, // I_FACE x = 12, face 20 {{12.,3.,1.}, {12.,6.,1.}, {12.,6.,9.}, {12.,3.,9.}} + {2, -1}, // J_FACE y = 0, face 21 {{6.,0.,1.}, {12.,0.,1.}, {12.,0.,9.}, {6.,0.,9.}} + {2, 3}, // J_FACE y = 3, face 22 {{6.,3.,1.}, {12.,3.,1.}, {12.,3.,9.}, {6.,3.,9.}} + {3, -1}, // J_FACE y = 6, face 23 {{6.,6.,1.}, {12.,6.,1.}, {12.,6.,9.}, {6.,6.,9.}} +}; + +BOOST_AUTO_TEST_CASE(simpleRefinementDiffLgrs) +{ + Dune::CpGrid grid; + Opm::createGridAndAddLgrs(grid, + deckTwoCellsInXDirGrid, + /* cells_per_dim_vec */ {{1,2,1}, {1,2,1}}, + /* startIJK_vec */ {{0,0,0}, {1,0,0}}, + /* endIJK_vec */ {{1,1,1}, {2,1,1}}, + /* lgr_name_vec */ {"LGR1", "LGR2"}); + + checkFaultInLevelZeroGrid(grid); + + // In a grid of dimensions {nx, ny, nz}, + // - the total amount of vertices is given by (nx+1)*(ny+1)*(nz+1) + // - the total amount of faces is given by ((nx+1)*ny*nz) + (nx*(ny+1)*nz) + (nx*ny*(nz+1)) + // Since now the refinement is aware of + // (a) parent cell having more than one face per type + // (like in this level zero grid having cell 0 with two I+ faces and cell 1 with two I- faces) + // (b) neighboring refinements with faults (creating new vertices and faces) + // the total amount of vertices and faces in presence of faults may be larger than + // (nx+1)*(ny+1)*(nz+1) and ((nx+1)*ny*nz) + (nx*(ny+1)*nz) + (nx*ny*(nz+1)) respectively. + + const auto& refinedGrid1 = *grid.currentData()[1]; + const auto& refinedGrid2 = *grid.currentData()[2]; + // for LGR1 and LGR2, {nx,ny,nz} = {1,2,1} + // (nx+1)*(ny+1)*(nz+1) + "new vertices" = (2x3x2) + 3 = 15 + // ((nx+1)*ny*nz) + (nx*(ny+1)*nz) + (nx*ny*(nz+1)) - vanished faces + new faces = (2x2x1) + (1x3x1) + (1x2x2) - 2 + 4 = 13 + checkVertexAndFaceCount(refinedGrid1, /* nxnynz = */ {1,2,1}, /* newVertexCount = */ 3, + /* vanishedFaceCount = */ 2, /* newFaceCount = */ 4); + checkVertexAndFaceCount(refinedGrid2, /* nxnynz = */ {1,2,1}, /* newVertexCount = */ 3, + /* vanishedFaceCount = */ 2, /* newFaceCount = */ 4); + + const auto& leafGrid = grid.currentLeafData(); + // level 0 + level 1 + level 2 vertices - shared vertices = + // 16 + 15 + 15 - 10 (shared level 0 and 1) - 10 (shared level 0 and 2) - 2 (shared level 1 and 2, not level 0) = 24 + // level 0 + level 1 + level 2 faces - shared/vanished faces = 13 + 13 + 13 - 13 (vanished level 0) - 2 (shared level 1 and level 2) = 24 + checkVertexAndFaceLeafCount(grid, /* sharedBetweenLevelsVertexCount = */ 22, /* sharedBetweenLevelsFaceCount = */ 15); + + const std::set expectedLGR1Vertices = { + {0.,0.,0.}, {0.,0.,8.}, // pillar x = 0, y = 0 + {6.,0.,0.}, {6.,0.,1.}, {6.,0.,8.}, // pillar x = 6, y = 0 + {0.,3.,0.}, {0.,3.,8.}, // pillar x = 0, y = 3 + {6.,3.,0.}, {6.,3.,1.}, {6.,3.,8.}, // pillar x = 6, y = 3 + {0.,6.,0.}, {0.,6.,8.}, // pillar x = 0, y = 6 + {6.,6.,0.}, {6.,6.,1.}, {6.,6.,8.} // pillar x = 6, y = 6 + }; + + const std::set expectedLGR2Vertices = { + {6.,0.,1.}, {6.,0.,8.}, {6.,0.,9.}, // pillar x = 6, y = 0 + {12.,0.,1.}, {12.,0.,9.}, // pillar x = 12, y = 0 + {6.,3.,1.}, {6.,3.,8.}, {6.,3.,9.}, // pillar x = 6, y = 3 + {12.,3.,1.}, {12.,3.,9.}, // pillar x = 12, y = 3 + {6.,6.,1.}, {6.,6.,8.}, {6.,6.,9.}, // pillar x = 6, y = 6 + {12.,6.,1.}, {12.,6.,9.} // pillar x = 12, y = 6 + }; + + const std::set expectedLeafVertices = { + {0.,0.,0.}, {0.,0.,8.}, // pillar x = 0, y = 0 + {6.,0.,0.}, {6.,0.,1.}, {6.,0.,8.}, {6.,0.,9.}, // pillar x = 6, y = 0 + {12.,0.,1.}, {12.,0.,9.}, // pillar x = 12, y = 0 + {0.,3.,0.}, {0.,3.,8.}, // pillar x = 0, y = 3 + {6.,3.,0.}, {6.,3.,1.}, {6.,3.,8.}, {6.,3.,9.}, // pillar x = 6, y = 3 + {12.,3.,1.}, {12.,3.,9.}, // pillar x = 12, y = 3 + {0.,6.,0.}, {0.,6.,8.}, // pillar x = 0, y = 6 + {6.,6.,0.}, {6.,6.,1.}, {6.,6.,8.}, {6.,6.,9.}, // pillar x = 6, y = 6 + {12.,6.,1.}, {12.,6.,9.} // pillar x = 12, y = 6 + }; + + checkLevelVertices(grid, std::vector{expectedLGR1Vertices, expectedLGR2Vertices}); + checkLeafVertices(grid, expectedLeafVertices); + + checkCellToFace(grid, /* level = */ 1, std::vector{expectedLeafCellToFace0, expectedLeafCellToFace1}); + checkCellToFace(grid, /* level = */ 2, std::vector{expectedLeafCellToFace2, expectedLeafCellToFace3}); + checkCellToFace(grid, /* level = */ -1 /* leafGrid!*/, + std::vector{expectedLeafCellToFace0, expectedLeafCellToFace1, + expectedLeafCellToFace2, expectedLeafCellToFace3}); + + const std::vector> expectedLGR1Faces = { + {{0.,0.,0.}, {6.,0.,0.}, {6.,3.,0.}, {0.,3.,0.}}, // K_FACE z = 0, face 0 + {{0.,3.,0.}, {6.,3.,0.}, {6.,6.,0.}, {0.,6.,0.}}, // K_FACE z = 0, face 1 + {{0.,0.,8.}, {6.,0.,8.}, {6.,3.,8.}, {0.,3.,8.}}, // K_FACE z = 8, face 2 + {{0.,3.,8.}, {6.,3.,8.}, {6.,6.,8.}, {0.,6.,8.}}, // K_FACE z = 8, face 3 + {{0.,0.,0.}, {0.,3.,0.}, {0.,3.,8.}, {0.,0.,8.}}, // I_FACE x = 0, face 4 + {{0.,3.,0.}, {0.,6.,0.}, {0.,6.,8.}, {0.,3.,8.}}, // I_FACE x = 0, face 5 + {{6.,0.,0.}, {6.,3.,0.}, {6.,3.,1.}, {6.,0.,1.}}, // I_FACE x = 6, face 6 + {{6.,0.,1.}, {6.,3.,1.}, {6.,3.,8.}, {6.,0.,8.}}, // I_FACE x = 6, face 7 + {{6.,3.,0.}, {6.,6.,0.}, {6.,6.,1.}, {6.,3.,1.}}, // I_FACE x = 6, face 8 + {{6.,3.,1.}, {6.,6.,1.}, {6.,6.,8.}, {6.,3.,8.}}, // I_FACE x = 6, face 9 + {{0.,0.,0.}, {6.,0.,0.}, {6.,0.,8.}, {0.,0.,8.}}, // J_FACE y = 0, face 10 + {{0.,3.,0.}, {6.,3.,0.}, {6.,3.,8.}, {0.,3.,8.}}, // J_FACE y = 3, face 11 + {{0.,6.,0.}, {6.,6.,0.}, {6.,6.,8.}, {0.,6.,8.}}, // J_FACE y = 6, face 12 + }; + const std::vector> expectedLGR1FaceToCell = { + {0, -1}, // K_FACE z = 0, face 0 {{0.,0.,0.}, {6.,0.,0.}, {6.,3.,0.}, {0.,3.,0.}}, + {1, -1}, // K_FACE z = 0, face 1 {{0.,3.,0.}, {6.,3.,0.}, {6.,6.,0.}, {0.,6.,0.}}, + {0, -1}, // K_FACE z = 8, face 2 {{0.,0.,8.}, {6.,0.,8.}, {6.,3.,8.}, {0.,3.,8.}}, + {1, -1}, // K_FACE z = 8, face 3 {{0.,3.,8.}, {6.,3.,8.}, {6.,6.,8.}, {0.,6.,8.}}, + {0, -1}, // I_FACE x = 0, face 4 {{0.,0.,0.}, {0.,3.,0.}, {0.,3.,8.}, {0.,0.,8.}}, + {1, -1}, // I_FACE x = 0, face 5 {{0.,3.,0.}, {0.,6.,0.}, {0.,6.,8.}, {0.,3.,8.}}, + {0, -1}, // I_FACE x = 6, face 6 {{6.,0.,0.}, {6.,3.,0.}, {6.,3.,1.}, {6.,0.,1.}}, + {0, -1}, // I_FACE x = 6, face 7 {{6.,0.,1.}, {6.,3.,1.}, {6.,3.,8.}, {6.,0.,8.}}, + {1, -1}, // I_FACE x = 6, face 8 {{6.,3.,0.}, {6.,6.,0.}, {6.,6.,1.}, {6.,3.,1.}}, + {1, -1}, // I_FACE x = 6, face 9 {{6.,3.,1.}, {6.,6.,1.}, {6.,6.,8.}, {6.,3.,8.}}, + {0, -1}, // J_FACE y = 0, face 10 {{0.,0.,0.}, {6.,0.,0.}, {6.,0.,8.}, {0.,0.,8.}}, + {0, 1}, // J_FACE y = 3, face 11 {{0.,3.,0.}, {6.,3.,0.}, {6.,3.,8.}, {0.,3.,8.}}, + {1, -1} // J_FACE y = 6, face 12 {{0.,6.,0.}, {6.,6.,0.}, {6.,6.,8.}, {0.,6.,8.}}, + }; + checkFaces(refinedGrid1, expectedLGR1Faces, expectedLGR1FaceToCell); + + + const std::vector> expectedLGR2Faces = { + {{6.,0.,1.}, {12.,0.,1.}, {12.,3.,1.}, {6.,3.,1.}}, // K_FACE z = 1, face 0 + {{6.,3.,1.}, {12.,3.,1.}, {12.,6.,1.}, {6.,6.,1.}}, // K_FACE z = 1, face 1 + {{6.,0.,9.}, {12.,0.,9.}, {12.,3.,9.}, {6.,3.,9.}}, // K_FACE z = 9, face 2 + {{6.,3.,9.}, {12.,3.,9.}, {12.,6.,9.}, {6.,6.,9.}}, // K_FACE z = 9, face 3 + {{6.,0.,1.}, {6.,3.,1.}, {6.,3.,8.}, {6.,0.,8.}}, // I_FACE x = 6, face 4 + {{6.,0.,8.}, {6.,3.,8.}, {6.,3.,9.}, {6.,0.,9.}}, // I_FACE x = 6, face 5 + {{6.,3.,1.}, {6.,6.,1.}, {6.,6.,8.}, {6.,3.,8.}}, // I_FACE x = 6, face 6 + {{6.,3.,8.}, {6.,6.,8.}, {6.,6.,9.}, {6.,3.,9.}}, // I_FACE x = 6, face 7 + {{12.,0.,1.}, {12.,3.,1.}, {12.,3.,9.}, {12.,0.,9.}}, // I_FACE x = 12, face 8 + {{12.,3.,1.}, {12.,6.,1.}, {12.,6.,9.}, {12.,3.,9.}}, // I_FACE x = 12, face 9 + {{6.,0.,1.}, {12.,0.,1.}, {12.,0.,9.}, {6.,0.,9.}}, // J_FACE y = 0, face 10 + {{6.,3.,1.}, {12.,3.,1.}, {12.,3.,9.}, {6.,3.,9.}}, // J_FACE y = 3, face 11 + {{6.,6.,1.}, {12.,6.,1.}, {12.,6.,9.}, {6.,6.,9.}}, // J_FACE y = 6, face 12 + }; + const std::vector> expectedLGR2FaceToCell = { + {0, -1}, // K_FACE z = 1, face 0 {{6.,0.,1.}, {12.,0.,1.}, {12.,3.,1.}, {6.,3.,1.}}, + {1, -1}, // K_FACE z = 1, face 1 {{6.,3.,1.}, {12.,3.,1.}, {12.,6.,1.}, {6.,6.,1.}}, + {0, -1}, // K_FACE z = 9, face 2 {{6.,0.,9.}, {12.,0.,9.}, {12.,3.,9.}, {6.,3.,9.}}, + {1, -1}, // K_FACE z = 9, face 3 {{6.,3.,9.}, {12.,3.,9.}, {12.,6.,9.}, {6.,6.,9.}}, + {0, -1}, // I_FACE x = 6, face 4 {{6.,0.,1.}, {6.,3.,1.}, {6.,3.,8.}, {6.,0.,8.}}, + {0, -1}, // I_FACE x = 6, face 5 {{6.,0.,8.}, {6.,3.,8.}, {6.,3.,9.}, {6.,0.,9.}}, + {1, -1}, // I_FACE x = 6, face 6 {{6.,3.,1.}, {6.,6.,1.}, {6.,6.,8.}, {6.,3.,8.}}, + {1, -1}, // I_FACE x = 6, face 7 {{6.,3.,8.}, {6.,6.,8.}, {6.,6.,9.}, {6.,3.,9.}}, + {0, -1}, // I_FACE x = 12, face 8 {{12.,0.,1.}, {12.,3.,1.}, {12.,3.,9.}, {12.,0.,9.}}, + {1, -1}, // I_FACE x = 12, face 9 {{12.,3.,1.}, {12.,6.,1.}, {12.,6.,9.}, {12.,3.,9.}}, + {0, -1}, // J_FACE y = 0, face 10 {{6.,0.,1.}, {12.,0.,1.}, {12.,0.,9.}, {6.,0.,9.}}, + {0, 1}, // J_FACE y = 3, face 11 {{6.,3.,1.}, {12.,3.,1.}, {12.,3.,9.}, {6.,3.,9.}}, + {1, -1} // J_FACE y = 6, face 12 {{6.,6.,1.}, {12.,6.,1.}, {12.,6.,9.}, {6.,6.,9.}}, + }; + checkFaces(refinedGrid2, expectedLGR2Faces, expectedLGR2FaceToCell); + + checkFaces(leafGrid, expectedLeafFaces, expectedLeafFaceToCell); + + Opm::checkGridWithLgrs(grid, + {{1,2,1}, {1,2,1}}, // cells_per_dim_vec + {"LGR1", "LGR2"}); // lgr_name_vec +} + +BOOST_AUTO_TEST_CASE(simpleRefinementSameLgr) +{ + Dune::CpGrid grid; + Opm::createGridAndAddLgrs(grid, + deckTwoCellsInXDirGrid, + /* cells_per_dim_vec */ {{1,2,1}}, + /* startIJK_vec */ {{0,0,0}}, + /* endIJK_vec */ {{2,1,1}}, + /* lgr_name_vec */ {"LGR1"}); + + const auto& refinedGrid1 = *grid.currentData()[1]; + // for LGR1, {nx,ny,nz} = {2,2,1} + // (nx+1)*(ny+1)*(nz+1) + "new vertices" = (3x3x2) + 6 = 24 + // ((nx+1)*ny*nz) + (nx*(ny+1)*nz) + (nx*ny*(nz+1)) - vanished faces + new faces = (3x2x1) + (2x3x1) + (2x2x1) - 2 + 6 = 24 + checkVertexAndFaceCount(refinedGrid1, /* nxnynz = */ {2,2,1}, /* newVertexCount = */ 6, + /* vanishedFaceCount = */ 2, /* newFaceCount = */ 6); + + const auto& leafGrid = grid.currentLeafData(); + // level 0 + level 1 vertices - shared vertices = 16 + 24 - 16 (shared level 0 and 1) = 24 + // level 0 + level 1 faces - shared/vanished faces = 13 + 24 - 13 (vanished level 0) = 24 + checkVertexAndFaceLeafCount(grid, /* sharedBetweenLevelsVertexCount = */ 16, /* sharedBetweenLevelsFaceCount = */ 13); + + const std::set expectedVertices = { + {0.,0.,0.}, {0.,0.,8.}, // pillar x = 0, y = 0 + {6.,0.,0.}, {6.,0.,1.}, {6.,0.,8.}, {6.,0.,9.}, // pillar x = 6, y = 0 + {12.,0.,1.}, {12.,0.,9.}, // pillar x = 12, y = 0 + {0.,3.,0.}, {0.,3.,8.}, // pillar x = 0, y = 3 + {6.,3.,0.}, {6.,3.,1.}, {6.,3.,8.}, {6.,3.,9.}, // pillar x = 6, y = 3 + {12.,3.,1.}, {12.,3.,9.}, // pillar x = 12, y = 3 + {0.,6.,0.}, {0.,6.,8.}, // pillar x = 0, y = 6 + {6.,6.,0.}, {6.,6.,1.}, {6.,6.,8.}, {6.,6.,9.}, // pillar x = 6, y = 6 + {12.,6.,1.}, {12.,6.,9.} // pillar x = 12, y = 6 + }; + + checkLevelVertices(grid, std::vector{expectedVertices}); + checkLeafVertices(grid, expectedVertices); + + checkCellToFace(grid, /* level = */ 1, std::vector{expectedLeafCellToFace0, expectedLeafCellToFace1, + expectedLeafCellToFace2, expectedLeafCellToFace3}); + checkCellToFace(grid, /* level = */ -1 /* leafGrid!*/, + std::vector{expectedLeafCellToFace0, expectedLeafCellToFace1, + expectedLeafCellToFace2, expectedLeafCellToFace3}); + + checkFaces(refinedGrid1, expectedLeafFaces, expectedLeafFaceToCell); + checkFaces(leafGrid, expectedLeafFaces, expectedLeafFaceToCell); + + Opm::checkGridWithLgrs(grid, + {{1,2,1}}, // cells_per_dim_vec + {"LGR1"}); // lgr_name_vec +} BOOST_AUTO_TEST_CASE(parentCellWithMoreThanOne_I_FACE_trueOriented_nonTrivialOverlap) { @@ -354,21 +827,20 @@ BOOST_AUTO_TEST_CASE(parentCellWithMoreThanOne_I_FACE_trueOriented_nonTrivialOve // | In LGR1 element 3: (6,2,1) and (6,4,1) // | In LGR1 element 5: (6,4,1) - const auto& refinedGridData = *grid.currentData()[1]; - const auto& parentGridData = *grid.currentData()[0]; - const auto parentElem = Dune::cpgrid::Entity<0>(parentGridData, 0, true); - - BOOST_CHECK_EQUAL(parentGridData.cellToFace(parentElem.index()).size(), 7); - - BOOST_CHECK_EQUAL( refinedGridData.size(3), 40); - // LGR1 dims 2x3x2 -> 3x4x3 vertices + 4 extra missing vertices (6,0,1), (6,2,1), (6,4,1), and (6,6,1). - BOOST_CHECK_EQUAL( refinedGridData.numFaces(), 55); + const auto& refinedGrid = *grid.currentData()[1]; + // for LGR1, {nx,ny,nz} = {2,3,2} + // (nx+1)*(ny+1)*(nz+1) + "new vertices" = (3x4x3) + 4 = 36 + 4 = 40 + // new vertices (6,0,1), (6,2,1), (6,4,1), and (6,6,1). + // ((nx+1)*ny*nz) + (nx*(ny+1)*nz) + (nx*ny*(nz+1)) - vanished faces + new faces = (3x3x2) + (2x4x2) + (2x3x3) - 3 + 6 = 52 - 3 + 6 = 55 // LGR1 dims 2x3x2 -> 52 faces (before correction due to missing points) // 3 of those 52 faces vanished and give origin to 6 new faces: 52 - 3 + 6 = 55 faces + checkVertexAndFaceCount(refinedGrid, /* nxnynz = */ {2,3,2}, /* newVertexCount = */ 4, + /* vanishedFaceCount = */ 3, /* newFaceCount = */ 6); + + // level 0 + level 1 vertices - shared vertices = 16 + 40 - 10 (shared level 0 and 1) = 46 + // level 0 + level 1 faces - shared/vanished faces = 13 + 55 - 7 (vanished level 0) = 61 + checkVertexAndFaceLeafCount(grid, /* sharedBetweenLevelsVertexCount = */ 10, /* sharedBetweenLevelsFaceCount = */ 7); - const auto& leafGridData = grid.currentLeafData(); - BOOST_CHECK_EQUAL( leafGridData.size(3), 46); // 46 = 40 + 6 (40 in level 1 + 6 vertices from cell_to_point_ from coarse element) - BOOST_CHECK_EQUAL( leafGridData.numFaces(), 61); // 61 = 55 + 6 (55 in level 1 + 6 other faces from coarse element) // Originally, the element not involved in refinement // had 7 faces. It's neihgbor in level zero @@ -453,7 +925,7 @@ BOOST_AUTO_TEST_CASE(parentCellWithMoreThanOne_I_FACE_trueOriented_nonTrivialOve selectedFaceToCoord[11].push_back(expectedNewFaceInFace2); } } - checkNewRefinedFaces(grid, refinedGridData, + checkNewRefinedFaces(grid, refinedGrid, selectedFaceToCoord, /* repeatedFaceType = */ 1); // 1-> I+ Opm::checkGridWithLgrs(grid, @@ -678,8 +1150,6 @@ BOOST_AUTO_TEST_CASE(parentCellWithMoreThanOne_I_FACE_false) /* lgr_name_vec = */ {"LGR1"}); } - - BOOST_AUTO_TEST_CASE(neighboringSingleCellRefinementsDifferentLgrs) { Dune::CpGrid grid; @@ -830,252 +1300,6 @@ BOOST_AUTO_TEST_CASE(neighboringSingleCellRefinementsSameLgr) {"LGR1"}); // lgr_name_vec } -BOOST_AUTO_TEST_CASE(simpleDiffLgr) -{ - Dune::CpGrid grid; - Opm::createGridAndAddLgrs(grid, - deckTwoCellsInXDirGrid, - /* cells_per_dim_vec */ {{1,2,1}, {1,2,1}}, - /* startIJK_vec */ {{0,0,0}, {1,0,0}}, - /* endIJK_vec */ {{1,1,1}, {2,1,1}}, - /* lgr_name_vec */ {"LGR1", "LGR2"}); - - // Element 0 and element 1 in level zero grid share an I_FACE (with face index 2) - // - // Vertices of those faces lie on the plane x = 6 | After refinement, number of subdivisions in - // | y- and z- directions: - // - // (6,0,9) -----------------(6,6,9) | (6,0,9) --(6,3,9)---(6,6,9) - // | face idx 3 | | | * | - // (6,0,8) ---------------- (6,6,8) | (6,0,8) --(6,3,9)---(6,6,8) - // | | | | * | - // | | | | * | - // | | | | * | - // | face idx 2 | | | * | - // | | | | * | - // | | | | * | - // | | | | * | - // | | | | * | - // (6,0,1) -----------------(6,6,1) | (6,0,1) --(6,3,1)---(6,6,1) - // | face idx 1 | | | * | - // (6,0,0) -----------------(6,6,0) | (6,0,0) --(6,3,0)---(6,6,0) - // | - const auto& parentGridData = *grid.currentData()[0]; - const auto parent0 = Dune::cpgrid::Entity<0>(parentGridData, 0, true); - const auto parent1 = Dune::cpgrid::Entity<0>(parentGridData, 1, true); - - BOOST_CHECK_EQUAL(parentGridData.cellToFace(parent0.index()).size(), 7); - BOOST_CHECK_EQUAL(parentGridData.cellToFace(parent1.index()).size(), 7); - - const auto& refinedGrid1 = *grid.currentData()[1]; - BOOST_CHECK_EQUAL( refinedGrid1.size(3), 15); - BOOST_CHECK_EQUAL( refinedGrid1.numFaces(), 13); - - const auto& refinedGrid2 = *grid.currentData()[2]; - BOOST_CHECK_EQUAL( refinedGrid2.size(3), 15); - BOOST_CHECK_EQUAL( refinedGrid2.numFaces(), 13); - - const auto& leafGrid = grid.currentLeafData(); - BOOST_CHECK_EQUAL( leafGrid.size(3), 24); - BOOST_CHECK_EQUAL( leafGrid.numFaces(), 24); - - - const std::set expectedLGR1Vertices = { - {0.,0.,0.}, {0.,0.,8.}, // pillar x = 0, y = 0 - {6.,0.,0.}, {6.,0.,1.}, {6.,0.,8.}, // pillar x = 6, y = 0 - {0.,3.,0.}, {0.,3.,8.}, // pillar x = 0, y = 3 - {6.,3.,0.}, {6.,3.,1.}, {6.,3.,8.}, // pillar x = 6, y = 3 - {0.,6.,0.}, {0.,6.,8.}, // pillar x = 0, y = 6 - {6.,6.,0.}, {6.,6.,1.}, {6.,6.,8.} // pillar x = 6, y = 6 - }; - - const std::set expectedLGR2Vertices = { - {6.,0.,1.}, {6.,0.,8.}, {6.,0.,9.}, // pillar x = 6, y = 0 - {12.,0.,1.}, {12.,0.,9.}, // pillar x = 12, y = 0 - {6.,3.,1.}, {6.,3.,8.}, {6.,3.,9.}, // pillar x = 6, y = 3 - {12.,3.,1.}, {12.,3.,9.}, // pillar x = 12, y = 3 - {6.,6.,1.}, {6.,6.,8.}, {6.,6.,9.}, // pillar x = 6, y = 6 - {12.,6.,1.}, {12.,6.,9.} // pillar x = 12, y = 6 - }; - - const std::set expectedLeafVertices = { - {0.,0.,0.}, {0.,0.,8.}, // pillar x = 0, y = 0 - {6.,0.,0.}, {6.,0.,1.}, {6.,0.,8.}, {6.,0.,9.}, // pillar x = 6, y = 0 - {12.,0.,1.}, {12.,0.,9.}, // pillar x = 12, y = 0 - {0.,3.,0.}, {0.,3.,8.}, // pillar x = 0, y = 3 - {6.,3.,0.}, {6.,3.,1.}, {6.,3.,8.}, {6.,3.,9.}, // pillar x = 6, y = 3 - {12.,3.,1.}, {12.,3.,9.}, // pillar x = 12, y = 3 - {0.,6.,0.}, {0.,6.,8.}, // pillar x = 0, y = 6 - {6.,6.,0.}, {6.,6.,1.}, {6.,6.,8.}, {6.,6.,9.}, // pillar x = 6, y = 6 - {12.,6.,1.}, {12.,6.,9.} // pillar x = 12, y = 6 - }; - - checkLevelVertices(grid, std::vector{expectedLGR1Vertices, expectedLGR2Vertices}); - checkLeafVertices(grid, expectedLeafVertices); - - const std::vector> expectedLGR1Faces = { - {{0.,0.,0.}, {6.,0.,0.}, {6.,3.,0.}, {0.,3.,0.}}, // K_FACE z = 0, face 0 - {{0.,3.,0.}, {6.,3.,0.}, {6.,6.,0.}, {0.,6.,0.}}, // K_FACE z = 0, face 1 - {{0.,0.,8.}, {6.,0.,8.}, {6.,3.,8.}, {0.,3.,8.}}, // K_FACE z = 8, face 2 - {{0.,3.,8.}, {6.,3.,8.}, {6.,6.,8.}, {0.,6.,8.}}, // K_FACE z = 8, face 3 - {{0.,0.,0.}, {0.,3.,0.}, {0.,3.,8.}, {0.,0.,8.}}, // I_FACE x = 0, face 4 - {{0.,3.,0.}, {0.,6.,0.}, {0.,6.,8.}, {0.,3.,8.}}, // I_FACE x = 0, face 5 - {{6.,0.,0.}, {6.,3.,0.}, {6.,3.,1.}, {6.,0.,1.}}, // I_FACE x = 6, face 6 - {{6.,0.,1.}, {6.,3.,1.}, {6.,3.,8.}, {6.,0.,8.}}, // I_FACE x = 6, face 7 - {{6.,3.,0.}, {6.,6.,0.}, {6.,6.,1.}, {6.,3.,1.}}, // I_FACE x = 6, face 8 - {{6.,3.,1.}, {6.,6.,1.}, {6.,6.,8.}, {6.,3.,8.}}, // I_FACE x = 6, face 9 - {{0.,0.,0.}, {6.,0.,0.}, {6.,0.,8.}, {0.,0.,8.}}, // J_FACE y = 0, face 10 - {{0.,3.,0.}, {6.,3.,0.}, {6.,3.,8.}, {0.,3.,8.}}, // J_FACE y = 3, face 11 - {{0.,6.,0.}, {6.,6.,0.}, {6.,6.,8.}, {0.,6.,8.}}, // J_FACE y = 6, face 12 - }; - - const std::vector> expectedLGR2Faces = { - {{6.,0.,1.}, {12.,0.,1.}, {12.,3.,1.}, {6.,3.,1.}}, // K_FACE z = 1, face 0 - {{6.,3.,1.}, {12.,3.,1.}, {12.,6.,1.}, {6.,6.,1.}}, // K_FACE z = 1, face 1 - {{6.,0.,9.}, {12.,0.,9.}, {12.,3.,9.}, {6.,3.,9.}}, // K_FACE z = 9, face 2 - {{6.,3.,9.}, {12.,3.,9.}, {12.,6.,9.}, {6.,6.,9.}}, // K_FACE z = 9, face 3 - {{6.,0.,1.}, {6.,3.,1.}, {6.,3.,8.}, {6.,0.,8.}}, // I_FACE x = 6, face 4 - {{6.,0.,8.}, {6.,3.,8.}, {6.,3.,9.}, {6.,0.,9.}}, // I_FACE x = 6, face 5 - {{6.,3.,1.}, {6.,6.,1.}, {6.,6.,8.}, {6.,3.,8.}}, // I_FACE x = 6, face 6 - {{6.,3.,8.}, {6.,6.,8.}, {6.,6.,9.}, {6.,3.,9.}}, // I_FACE x = 6, face 7 - {{12.,0.,1.}, {12.,3.,1.}, {12.,3.,9.}, {12.,0.,9.}}, // I_FACE x = 12, face 8 - {{12.,3.,1.}, {12.,6.,1.}, {12.,6.,9.}, {12.,3.,9.}}, // I_FACE x = 12, face 9 - {{6.,0.,1.}, {12.,0.,1.}, {12.,0.,9.}, {6.,0.,9.}}, // J_FACE y = 0, face 10 - {{6.,3.,1.}, {12.,3.,1.}, {12.,3.,9.}, {6.,3.,9.}}, // J_FACE y = 3, face 11 - {{6.,6.,1.}, {12.,6.,1.}, {12.,6.,9.}, {6.,6.,9.}}, // J_FACE y = 6, face 12 - }; - - const std::vector> expectedLeafFaces = { - {{0.,0.,0.}, {6.,0.,0.}, {6.,3.,0.}, {0.,3.,0.}}, // K_FACE z = 0, face 0 - {{0.,3.,0.}, {6.,3.,0.}, {6.,6.,0.}, {0.,6.,0.}}, // K_FACE z = 0, face 1 - {{0.,0.,8.}, {6.,0.,8.}, {6.,3.,8.}, {0.,3.,8.}}, // K_FACE z = 8, face 2 - {{0.,3.,8.}, {6.,3.,8.}, {6.,6.,8.}, {0.,6.,8.}}, // K_FACE z = 8, face 3 - {{0.,0.,0.}, {0.,3.,0.}, {0.,3.,8.}, {0.,0.,8.}}, // I_FACE x = 0, face 6 - {{0.,3.,0.}, {0.,6.,0.}, {0.,6.,8.}, {0.,3.,8.}}, // I_FACE x = 0, face 5 - {{6.,0.,0.}, {6.,3.,0.}, {6.,3.,1.}, {6.,0.,1.}}, // I_FACE x = 6, face 6 - {{6.,3.,0.}, {6.,6.,0.}, {6.,6.,1.}, {6.,3.,1.}}, // I_FACE x = 6, face 7 - {{0.,0.,0.}, {6.,0.,0.}, {6.,0.,8.}, {0.,0.,8.}}, // J_FACE y = 0, face 8 - {{0.,3.,0.}, {6.,3.,0.}, {6.,3.,8.}, {0.,3.,8.}}, // J_FACE y = 3, face 9 - {{0.,6.,0.}, {6.,6.,0.}, {6.,6.,8.}, {0.,6.,8.}}, // J_FACE y = 6, face 10 - {{6.,0.,1.}, {12.,0.,1.}, {12.,3.,1.}, {6.,3.,1.}}, // K_FACE z = 1, face 11 - {{6.,3.,1.}, {12.,3.,1.}, {12.,6.,1.}, {6.,6.,1.}}, // K_FACE z = 1, face 12 - {{6.,0.,9.}, {12.,0.,9.}, {12.,3.,9.}, {6.,3.,9.}}, // K_FACE z = 9, face 13 - {{6.,3.,9.}, {12.,3.,9.}, {12.,6.,9.}, {6.,6.,9.}}, // K_FACE z = 9, face 14 - {{6.,0.,1.}, {6.,3.,1.}, {6.,3.,8.}, {6.,0.,8.}}, // I_FACE x = 6, face 15 - {{6.,0.,8.}, {6.,3.,8.}, {6.,3.,9.}, {6.,0.,9.}}, // I_FACE x = 6, face 16 - {{6.,3.,1.}, {6.,6.,1.}, {6.,6.,8.}, {6.,3.,8.}}, // I_FACE x = 6, face 17 - {{6.,3.,8.}, {6.,6.,8.}, {6.,6.,9.}, {6.,3.,9.}}, // I_FACE x = 6, face 18 - {{12.,0.,1.}, {12.,3.,1.}, {12.,3.,9.}, {12.,0.,9.}}, // I_FACE x = 12, face 19 - {{12.,3.,1.}, {12.,6.,1.}, {12.,6.,9.}, {12.,3.,9.}}, // I_FACE x = 12, face 20 - {{6.,0.,1.}, {12.,0.,1.}, {12.,0.,9.}, {6.,0.,9.}}, // J_FACE y = 0, face 21 - {{6.,3.,1.}, {12.,3.,1.}, {12.,3.,9.}, {6.,3.,9.}}, // J_FACE y = 3, face 22 - {{6.,6.,1.}, {12.,6.,1.}, {12.,6.,9.}, {6.,6.,9.}}, // J_FACE y = 6, face 23 - }; - - checkFaces(refinedGrid1, expectedLGR1Faces); - checkFaces(refinedGrid2, expectedLGR2Faces); - checkFaces(leafGrid, expectedLeafFaces); - - Opm::checkGridWithLgrs(grid, - {{1,2,1}, {1,2,1}}, // cells_per_dim_vec - {"LGR1", "LGR2"}); // lgr_name_vec -} - - -BOOST_AUTO_TEST_CASE(simpleSameLgr) -{ - Dune::CpGrid grid; - Opm::createGridAndAddLgrs(grid, - deckTwoCellsInXDirGrid, - /* cells_per_dim_vec */ {{1,2,1}}, - /* startIJK_vec */ {{0,0,0}}, - /* endIJK_vec */ {{2,1,1}}, - /* lgr_name_vec */ {"LGR1"}); - - // Element 0 and element 1 in level zero grid share an I_FACE (with face index 2) - // - // Vertices of those faces lie on the plane x = 6 | After refinement, number of subdivisions in - // | y- and z- directions: - // - // (6,0,9) -----------------(6,6,9) | (6,0,9) --(6,3,9)---(6,6,9) - // | face idx 3 | | | * | - // (6,0,8) ---------------- (6,6,8) | (6,0,8) --(6,3,9)---(6,6,8) - // | | | | * | - // | | | | * | - // | | | | * | - // | face idx 2 | | | * | - // | | | | * | - // | | | | * | - // | | | | * | - // | | | | * | - // (6,0,1) -----------------(6,6,1) | (6,0,1) --(6,3,1)---(6,6,1) - // | face idx 1 | | | * | - // (6,0,0) -----------------(6,6,0) | (6,0,0) --(6,3,0)---(6,6,0) - // | - const auto& parentGridData = *grid.currentData()[0]; - const auto parent0 = Dune::cpgrid::Entity<0>(parentGridData, 0, true); - const auto parent1 = Dune::cpgrid::Entity<0>(parentGridData, 1, true); - - BOOST_CHECK_EQUAL(parentGridData.cellToFace(parent0.index()).size(), 7); - BOOST_CHECK_EQUAL(parentGridData.cellToFace(parent1.index()).size(), 7); - - const auto& refinedGrid1 = *grid.currentData()[1]; - BOOST_CHECK_EQUAL( refinedGrid1.size(3), 24); - BOOST_CHECK_EQUAL( refinedGrid1.numFaces(), 24); - - const auto& leafGrid = grid.currentLeafData(); - BOOST_CHECK_EQUAL( leafGrid.size(3), 24); - BOOST_CHECK_EQUAL( leafGrid.numFaces(), 24); - - const std::set expectedVertices = { - {0.,0.,0.}, {0.,0.,8.}, // pillar x = 0, y = 0 - {6.,0.,0.}, {6.,0.,1.}, {6.,0.,8.}, {6.,0.,9.}, // pillar x = 6, y = 0 - {12.,0.,1.}, {12.,0.,9.}, // pillar x = 12, y = 0 - {0.,3.,0.}, {0.,3.,8.}, // pillar x = 0, y = 3 - {6.,3.,0.}, {6.,3.,1.}, {6.,3.,8.}, {6.,3.,9.}, // pillar x = 6, y = 3 - {12.,3.,1.}, {12.,3.,9.}, // pillar x = 12, y = 3 - {0.,6.,0.}, {0.,6.,8.}, // pillar x = 0, y = 6 - {6.,6.,0.}, {6.,6.,1.}, {6.,6.,8.}, {6.,6.,9.}, // pillar x = 6, y = 6 - {12.,6.,1.}, {12.,6.,9.} // pillar x = 12, y = 6 - }; - - checkLevelVertices(grid, std::vector{expectedVertices}); - checkLeafVertices(grid, expectedVertices); - - const std::vector> expectedFaces = { - {{0.,0.,0.}, {6.,0.,0.}, {6.,3.,0.}, {0.,3.,0.}}, // K_FACE z = 0, face 0 - {{0.,3.,0.}, {6.,3.,0.}, {6.,6.,0.}, {0.,6.,0.}}, // K_FACE z = 0, face 1 - {{0.,0.,8.}, {6.,0.,8.}, {6.,3.,8.}, {0.,3.,8.}}, // K_FACE z = 8, face 2 - {{0.,3.,8.}, {6.,3.,8.}, {6.,6.,8.}, {0.,6.,8.}}, // K_FACE z = 8, face 3 - {{0.,0.,0.}, {0.,3.,0.}, {0.,3.,8.}, {0.,0.,8.}}, // I_FACE x = 0, face 4 - {{0.,3.,0.}, {0.,6.,0.}, {0.,6.,8.}, {0.,3.,8.}}, // I_FACE x = 0, face 5 - {{6.,0.,0.}, {6.,3.,0.}, {6.,3.,1.}, {6.,0.,1.}}, // I_FACE x = 6, face 6 - {{6.,3.,0.}, {6.,6.,0.}, {6.,6.,1.}, {6.,3.,1.}}, // I_FACE x = 6, face 7 - {{0.,0.,0.}, {6.,0.,0.}, {6.,0.,8.}, {0.,0.,8.}}, // J_FACE y = 0, face 8 - {{0.,3.,0.}, {6.,3.,0.}, {6.,3.,8.}, {0.,3.,8.}}, // J_FACE y = 3, face 9 - {{0.,6.,0.}, {6.,6.,0.}, {6.,6.,8.}, {0.,6.,8.}}, // J_FACE y = 6, face 10 - {{6.,0.,1.}, {12.,0.,1.}, {12.,3.,1.}, {6.,3.,1.}}, // K_FACE z = 1, face 11 - {{6.,3.,1.}, {12.,3.,1.}, {12.,6.,1.}, {6.,6.,1.}}, // K_FACE z = 1, face 12 - {{6.,0.,9.}, {12.,0.,9.}, {12.,3.,9.}, {6.,3.,9.}}, // K_FACE z = 9, face 13 - {{6.,3.,9.}, {12.,3.,9.}, {12.,6.,9.}, {6.,6.,9.}}, // K_FACE z = 9, face 14 - {{6.,0.,1.}, {6.,3.,1.}, {6.,3.,8.}, {6.,0.,8.}}, // I_FACE x = 6, face 15 - {{6.,0.,8.}, {6.,3.,8.}, {6.,3.,9.}, {6.,0.,9.}}, // I_FACE x = 6, face 16 - {{6.,3.,1.}, {6.,6.,1.}, {6.,6.,8.}, {6.,3.,8.}}, // I_FACE x = 6, face 17 - {{6.,3.,8.}, {6.,6.,8.}, {6.,6.,9.}, {6.,3.,9.}}, // I_FACE x = 6, face 18 - {{12.,0.,1.}, {12.,3.,1.}, {12.,3.,9.}, {12.,0.,9.}}, // I_FACE x = 12, face 19 - {{12.,3.,1.}, {12.,6.,1.}, {12.,6.,9.}, {12.,3.,9.}}, // I_FACE x = 12, face 20 - {{6.,0.,1.}, {12.,0.,1.}, {12.,0.,9.}, {6.,0.,9.}}, // J_FACE y = 0, face 21 - {{6.,3.,1.}, {12.,3.,1.}, {12.,3.,9.}, {6.,3.,9.}}, // J_FACE y = 3, face 22 - {{6.,6.,1.}, {12.,6.,1.}, {12.,6.,9.}, {6.,6.,9.}}, // J_FACE y = 6, face 23 - }; - - checkFaces(refinedGrid1, expectedFaces); - checkFaces(leafGrid, expectedFaces); - - Opm::checkGridWithLgrs(grid, - {{1,2,1}}, // cells_per_dim_vec - {"LGR1"}); // lgr_name_vec -} // Level zero grid dims = 1x2x1 //