Issue 112 – September 3, 2022

Solution-Inspired Mesh Refinement

Hey there,

It’s Robin from CFD Engine & I’ve got an idea for how to make better meshes without going all-in with adaptive mesh refinement.

If you’re currently adding wake refinement via a handful of precisely positioned primitives, then hear me out.

I’m calling it “solution-inspired” mesh refinement – a sneaky hack that might save you a few cells and improve your wake capture.

Let’s go…

Where I’m coming from

I don’t use adaptive mesh refinement – I get it, I know how to do it, I just haven’t made the jump. Same goes for DES & Adjoint – I’m pretty sure I could benefit from what they offer, but they’re not in my everyday toolbox.

For context, most of my cases are steady-state, isothermal, incompressible, turbulent & use wall functions 🙈

A typical project involves building a baseline model & then testing relatively small geometry changes to try & find an improvement (usually within super-tight constraints).

A new widget here, a bit of re-profiling over there, trimming this bit, extending that bit – all whilst hoping the styling police don’t notice 🚨 pretty old school, but it works.

I want meshes that are as consistent & repeatable as possible. I want to know that the differences in the results are (at least for the most part) down to the geometry changes I just made. I’ll take consistency & repeatability over absolute accuracy any day.

For any new project, I’ll spend a decent amount of time crafting the baseline mesh recipe & then hold it constant for the remainder of the project (unless I have to make some really big geometry or boundary condition changes).

Crafting that baseline mesh recipe is an evolutionary process that goes a little something like this…

Crafting a baseline

Let’s assume the input geometry is ready to go & we’re jumping into snappyHexMesh

  1. Guesstimate the surface refinement levels required to capture the input geometry;
  2. Add some distance refinement to improve the mesh resolution close to those surfaces;
  3. Add refinement regions in the wake using boxes or other primitives;
  4. Add a few layers to the aerodynamically-sensitive bits;
  5. Solve ~500 iterations
  6. Visually check the results to see if the wake boxes are big enough / in the right place & whether the distance or surface refinements need altering;
  7. Make some tweaks, re-mesh & go back to Step 5;
  8. Rinse & repeat.

There’s also leak chasing, bad cell fixing & all that good stuff – but on a good day I might get away with a couple of rounds of the above.

It works, but it can be time-consuming & it’s not particularly cell-efficient to use boxes (& other primitives) for volume/wake refinement.

Here’s a solution-inspired alternative…

Solution-Inspired Mesh Refinement

Do steps 1-5 (as above) then…

  1. Export a wake isosurface (CpT = 0 perhaps?) in OBJ format using the sampledSurface function object;
  2. Add the wake OBJ to my snappyHexMeshDict as a refinement region & use distance refinement on the nearby volume mesh;
    • Note: Don’t add it as a refinement surface we don’t want SHM to snap to it.
  3. Remove some (or all) of the previous wake boxes;
  4. Re-mesh, check it worked & you’re good to go 👍

The intention is to carry this baseline isosurface across subsequent runs, only doing these steps once per project.

I reckon that, for my use case, “solution-inspired” mesh refinement would…

  • be as consistent, run-to-run, as my previous method;
  • be more cell-efficient than wake boxes;
  • capture shear layers better than wake boxes;
  • be quicker than doing solution-adaptive mesh refinement every run;

There’s obviously the chance that a geometry change could push the wake outside the new refinement zones – but this can happen when you’re using wake boxes 🤔

Also, if you need a couple of thousand iterations to get a decent isosurface then this idea might be too expensive – but then again, you’re not doing it every run 🤔

What do you reckon?

There you have it, “solution-inspired” mesh refinement, a.k.a. using an isosurface to define new mesh refinement zones in snappyHexMesh.

Do you think this (or something like it) might work in your process? There are plenty of cases where it wouldn’t work (multiphase, moving meshes etc) but maybe it could be useful to someone?

Or is it a stupid idea? Should I just embrace adaptive mesh refinement instead?

Drop me a note, I’m keen to hear your feedback, my inbox is always open.

Until next week, stay safe,

Signed Robin K