Describe the bug
Creating a nested grid using flopy.utils.cvfdutil.gridlist_to_disv_gridprops does not work correctly when larger cells are connected to 4 or more smaller cells. In that situation vertices are left out of the larger cells, causing the hydraulic connection between the "non-refined" cells and the "refined" cells to be incorrect.
This is caused by the fact that the vertex-to-cell mapping isn't updated as vertices are added to larger cells. This works fine as long as each larger cell shares corner vertices with the smaller cells it is connected to. For a quadtree refinement this works fine, and one refinement level extra (3 cells) is also fine, as the 3rd cell is implicitly added by handling the two smaller cells that share corner vertices with the larger cell.
As an example where this doesn't work, consider the following grid (a 1 to 5 cell refinement):

The algorithm does the following:
- The vertex list for cell 11 is updated with vertex 38 when it's processing vertex 14 (vertex 14 is shared by 4 cells, including cells 11 and 24).
- The vertex-to-cell mapping for vertex 38 only contains cells 24 and 29.
- So once it processes vertex 38, it never realizes that this vertex is also used by cell 11.
- Hence, vertices 47 and 53 are never added to the vertex list for cell 11.
Cell 11 ends up missing vertices on the shared face between the outer and inner grids:

To Fix
The simple fix that solved my particular case was to update the vertex-to-cell mapping as vertices are added to the larger cell. Not sure if this is sufficiently robust for all cases, but perhaps it's a good start for supporting arbitrary refinement.
Update function segment_face to accept vertex_cell_dict and icell1 so it updates the vertex-cell mapping when vertices are added to a cell. See the single line addition at the bottom:
def segment_face(ivert, ivlist1, ivlist2, vertices, vertex_cell_dict, icell1):
# go through ivlist1 and find faces that have ivert
faces_to_check = []
for ipos in range(len(ivlist1) - 1):
face = (ivlist1[ipos], ivlist1[ipos + 1])
if ivert in face:
faces_to_check.append(face)
# go through ivlist2 and find points to check
points_to_check = []
for ipos in range(len(ivlist2) - 1):
if ivlist2[ipos] == ivert:
points_to_check.append(ivlist2[ipos + 1])
elif ivlist2[ipos + 1] == ivert:
points_to_check.append(ivlist2[ipos])
for face in faces_to_check:
iva, ivb = face
x, y = vertices[iva]
a = Point(x, y)
x, y = vertices[ivb]
b = Point(x, y)
for ivc in points_to_check:
if ivc not in face:
x, y = vertices[ivc]
c = Point(x, y)
if isBetween(a, b, c):
ipos = ivlist1.index(ivb)
if ipos == 0:
ipos = len(ivlist1) - 1
ivlist1.insert(ipos, ivc)
vertex_cell_dict[ivc].append(icell1) # <-- update vertex-cell mapping
return True
return False
Then in to_cvfd() (L244-245) pass those arguments to segment_face
# don't share a face, so need to segment if necessary
segmented = segment_face(
ivert,
ivertlist1,
ivertlist2,
vertexdict_keys,
vertex_cell_dict, # pass vertex_cell_dict to update cells using added vertices
icell1, # pass cell number to update vertex_cell_dict
)
To Reproduce
Steps to reproduce the behavior, see notebook:
nested_mf6_grids.zip
Expected behavior
It would be nice if arbitrary levels of refinement were supported by this utility function.
Describe the bug
Creating a nested grid using
flopy.utils.cvfdutil.gridlist_to_disv_gridpropsdoes not work correctly when larger cells are connected to 4 or more smaller cells. In that situation vertices are left out of the larger cells, causing the hydraulic connection between the "non-refined" cells and the "refined" cells to be incorrect.This is caused by the fact that the vertex-to-cell mapping isn't updated as vertices are added to larger cells. This works fine as long as each larger cell shares corner vertices with the smaller cells it is connected to. For a quadtree refinement this works fine, and one refinement level extra (3 cells) is also fine, as the 3rd cell is implicitly added by handling the two smaller cells that share corner vertices with the larger cell.
As an example where this doesn't work, consider the following grid (a 1 to 5 cell refinement):

The algorithm does the following:
Cell 11 ends up missing vertices on the shared face between the outer and inner grids:

To Fix
The simple fix that solved my particular case was to update the vertex-to-cell mapping as vertices are added to the larger cell. Not sure if this is sufficiently robust for all cases, but perhaps it's a good start for supporting arbitrary refinement.
Update function
segment_faceto acceptvertex_cell_dictandicell1so it updates the vertex-cell mapping when vertices are added to a cell. See the single line addition at the bottom:Then in
to_cvfd()(L244-245) pass those arguments tosegment_faceTo Reproduce
Steps to reproduce the behavior, see notebook:
nested_mf6_grids.zip
Expected behavior
It would be nice if arbitrary levels of refinement were supported by this utility function.