Structured Grid to Unstructured Grid Conversion

Nick Gibbons and Rowan Gollan, 2023-07-26

This workflow tip demonstrates how to take a structured grid built using the Eilmer-native grid tools and convert it into an unstructured grid. One might wonder why? What’s the advantage to converting my beautifully curated structured grid into an unstructured grid? The principal reason we use this capability is so that we can do effective partitioning of big grids using METIS. METIS operates on unstructured grids only.

What we are doing in this workflow tip is decoupling geometry and grid building from the concerns of partitioning and load balancing.

The starting point

For this example, we are going to work with a 2-block domain for reacting flow over a ramp. In our collection of Eilmer examples, this is conversion examaple is found at:

gdtk/examples/eilmer/2D/reacting-ramp/su2-grid/

The 2-block ramp in its structured grid form is shown here.

ramp 2 block structured cropped

Displayed below is the first 24 lines of the script file su2-grid-gen.lua. There is nothing too new or interesting for users familiar with Eilmer structured grids. This setups up some points and lines, then configures them to produce to structured grids.

-- SU2 grid generation script
-- e4shared --custom-script --script-file=su2-grid-gen.lua

theta = 15 * math.pi/180.0 -- ramp angle, radians
L = 1.0 -- ramp length, meters

-- Set up two quadrilaterals in the (x,y)-plane by first defining
-- the corner nodes, then the lines between those corners.
a = Vector3:new{x=-0.5, y=0.0}
b = Vector3:new{x=0.0, y=0.0}
c = Vector3:new{x=1.0, y=L*math.tan(theta)}
d = Vector3:new{x=1.0, y=1.0}
e = Vector3:new{x=0.0, y=1.0}
f = Vector3:new{x=-0.5, y=1.0}
ab = Line:new{p0=a, p1=b}; be = Line:new{p0=b, p1=e} -- lower boundary including cone surface
fe = Line:new{p0=f, p1=e}; ed = Line:new{p0=e, p1=d} -- upper boundary
af = Line:new{p0=a, p1=f}; be = Line:new{p0=b, p1=e} -- vertical lines
bc = Line:new{p0=b, p1=c}; cd = Line:new{p0=c, p1=d} -- vertical lines
quad0 = makePatch{north=fe, east=be, south=ab, west=af}
quad1 = makePatch{north=ed, east=cd, south=bc, west=be} --, gridType="ao"}
-- Mesh the patches, with particular discretisation.
nx0 = 20; nx1 = 40; ny = 40
grid0 = StructuredGrid:new{psurface=quad0, niv=nx0+1, njv=ny+1}
grid1 = StructuredGrid:new{psurface=quad1, niv=nx1+1, njv=ny+1}

Converting the structured grids to unstructured grids

It’s really easy to convert a structured grid object to an unstructured grid in Eilmer; we simply pass a Structured grid object in at creation time of an Unstructured grid. Let’s see that in action by revealing the next two lines:

ugrid0 = UnstructuredGrid:new{sgrid=grid0}
ugrid1 = UnstructuredGrid:new{sgrid=grid1}

Next, we’ll add the boundary tags. This is not strictly a grid step, but while we still have the connection to the original Structured grid, we’re in a good position of knowing which grid edge should map to which boundary tag. This is shown in the next few lines.

ugrid0:set_boundaryset_tag(Face.west, "inflow")
ugrid0:set_boundaryset_tag(Face.south, "wall")
ugrid0:set_boundaryset_tag(Face.north, "outflow")

ugrid1:set_boundaryset_tag(Face.east, "outflow")
ugrid1:set_boundaryset_tag(Face.south, "wall")
ugrid1:set_boundaryset_tag(Face.north, "outflow")

Join pieces to produce a single unstructured grid

The last step is also straightforward but it introduces a new method: joinGrid. Here are the lines of code, and description follows.

-- join all unstructured grids into a single grid
usgrid = ugrid0
usgrid:joinGrid(ugrid1)

In Line 38, we create a new grid piece called usgrid and populate it with the 0th unstructured grid piece. We’ll use usgrid as an accumulator for grid pieces.

In Line 39, we join ugrid1 onto usgrid. At this point, usgrid has ugrid0 and ugrid1 fused into a single piece. And, at this point for this example, we are done.

For grids with more original blocks, this step could be repeated in a loop. In the loop case, it would be convenient to store the initial grid pieces in an array.

Writing to disk and partitioning

The last line in the script writes our single-piece unstructured grid to disk as an SU2 file.

-- write out unstructured grid in .su2 format
usgrid:write_to_su2_file("ramp15.su2")

We can partition this grid via METIS with the Eilmer-wrapped tool. The outcome of splitting into 8 blocks in shown here.