Hey there,
It’s Robin from CFD Engine & this week I’m preaching to the choir. I want to talk about templating & I reckon you’re probably already doing it.
But, if you run loads of derivative (almost the same) cases, or you have other users running cases for you, or you just want to make fewer mistakes, then this one is for you.
Templating
One of the best things about OpenFOAM is its “plain-text-files-in-a-directory” case structure. It also happens to be one of the worst things about OpenFOAM.
- Best: easy to change a value by editing one small text file.
- Worst: easy to change your whole case by editing one small text file.
To minimise the chances of me mucking up my next run, I want to touch as few files as possible.
To make life easier, I can strip all the values that I change regularly (flow parameters, geometry file names etc) from their respective dictionaries & replace them with references to variables that I’ll define elsewhere. My definitions could be in a text file, they could be an environment variables or they could even be the result of a calculation.
It usually needs a few iterations to get it all working, but once it is, I don’t need to touch any of the main dictionaries again.
I call it templating (it’s not a word, but I’ve come this far so I’ll stick with it) 👍
Top Tip:
diff -qr CASE01 CASE02
is your friend – it outputs a list of which files have changed between cases. Leave out the “q
” for more details on exactly what has changed. Add “s
” if you’d also like a list of all the files that are identical, just for your peace of mind.
Templating tools
My three most used templating “tools” in OpenFOAM are:
#include
OpenFOAM’s #include
functionality allows us to merge the contents of one file into another at run time – it’s the workhorse of templating.
Check out the motorBike tutorial for a good example of this in action. In particular, notice how the flow parameters are stored in 0.orig/include/initialConditions
then #include
-ed & referenced in each of the boundary condition dictionaries.
There are several other versions of #include
that do subtly different things:
#includeIfPresent
fails silently if the included file is missing (I don’t like things that fail silently – I like them to make a fuss so that I notice them).
#includeFunc
is built for use with functions (like forces etc), often seen in controlDict
.
There are a few more edge cases, but most of your needs will probably be met by #include
& #includeFunc
.
Environment Variables
If a variable is useful outside of an OpenFOAM dictionary then it might make sense to define it as an environment variable (in your shell or in your run script). You’re probably already using environment variables, like $FOAM_CASE
or $FOAM_ETC
to specify file paths, without really noticing.
But there’s nothing stopping you from defining your own & using them wherever it makes sense. Use them with care though. They can be very powerful, but they’re not as traceable as variables written in a text file.
Expressions
Expressions are mega – a whole host of functionality for performing calculations & manipulations inside your dictionaries. No more back-and-forth to a spreadsheet/python code/calculator or your fingers, to work stuff out. Reducing the chances of a cut-&-paste slip-up or a fat-finger typo along the way.
They’re only in the ESI releases at present, first appearing in v1912. You can do similar things with calc
in the Foundation version, but it feels like using a “sledgehammer to crack a nut” when compared to expressions.
Expressions probably deserve their own email – let me know if I should write one 🤔 In the meantime, you can find out more, here.
Tiny Tips
-
Don’t go crazy – if your “included” file is the size of a
snappyHexMeshDict
then things have gotten out of hand. You don’t need to template all the things. -
Comment your variables – when you pick this project up again next year, you’ll be glad you took a minute to document what’s what.
-
Avoid including things from outside your case/project unless you’re confident that they won’t change without your knowledge. Helps to avoid those “it works on my machine” & “it used to work & I haven’t changed anything” scenarios.
-
Avoid nested includes – if your included file also has an included file, which also has an included file, then your doing it wrong. A couple of files deep & it becomes tricky to hold it all in your head, especially when debugging. Many of the standard post-processing dictionaries are guilty of this, but fear not, it’s
foamDictionary
to the rescue.Top Tip: Use
foamDictionary
with the-expand
option to see what your dictionaries actually look like after OpenFOAM has parsed all of your includes and variables.
#include conclusion.txt
I’m sure you’re already doing something along these lines, but I hope there were a couple of useful nuggets in here (the foamDictionary -expand
one is a recent addition for me).
Do you make much use of includes, expressions and the like? Any novel use cases you’d like to share with the class? Or, are they more trouble than they’re worth – basically just swapping an edit in one file for an edit in another? Let me know, I’m always interested to learn how you do it.
Until next week, CFD safely,