|
|
<!-- --- title: OpenFOAM C++ Coding Patterns (precision) -->
|
|
|
|
|
|
[Back to _coding patterns_](/coding/patterns/patterns)
|
|
|
|
|
|
***We are happy to incorporate content from volunteers!!***
|
|
|
|
|
|
|
|
|
## Coding Patterns - Precision
|
|
|
|
|
|
OpenFOAM supports compile-time selection of its usual integer elements
|
|
|
(`label`) and its usual floating-point elements (`scalar`).
|
|
|
|
|
|
This choice is defined by the environment variables:
|
|
|
- `WM_LABEL_SIZE` : Label size in bits (32 | 64)
|
|
|
- `WM_PRECISION_OPTION` : Floating-point precision (DP | SP | SPDP)
|
|
|
|
|
|
|
|
|
When writing code, some additional care must be taken to ensure that
|
|
|
the resulting code will compile properly for different values of
|
|
|
`label` and `scalar`. A simple, but counter-intuitive example:
|
|
|
```
|
|
|
scalar foo = ...;
|
|
|
|
|
|
if (equal(foo, 0.0))
|
|
|
{
|
|
|
}
|
|
|
```
|
|
|
The code looks good, the programmer even clearly documented that it is
|
|
|
a floating-point comparison by using `0.0`. Unfortunately, when
|
|
|
compiled with single precision, this is how the comparison actually
|
|
|
appears:
|
|
|
```
|
|
|
if (equal(<float>, <double>))
|
|
|
{
|
|
|
}
|
|
|
```
|
|
|
The default compiled type for `0.0` will be `double`.
|
|
|
For zero, the easiest way is to write it as an integer and let the
|
|
|
compiler promote to the correct type:
|
|
|
```
|
|
|
if (equal(foo, 0))
|
|
|
{
|
|
|
}
|
|
|
```
|
|
|
For non-zero values, use a functional cast instead:
|
|
|
```
|
|
|
if (equal(foo, scalar(1.5)))
|
|
|
{
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### Setup for testing
|
|
|
|
|
|
To ensure that developed code compiles properly across all ranges of
|
|
|
precision, the following combination is recommended:
|
|
|
```
|
|
|
export WM_LABEL_SIZE=64
|
|
|
export WM_PRECISION_OPTION=SPDP
|
|
|
```
|
|
|
If your code compiles flawlessly with this, you have done a good job!
|
|
|
|
|
|
|
|
|
### Dictionary input
|
|
|
|
|
|
When handling dictionary input, type deduction may need additional
|
|
|
assistance. This can written different ways:
|
|
|
```
|
|
|
xyz = dict.lookupOrDefault<scalar>("name", 1.5); // Preferred form
|
|
|
|
|
|
xyz = dict.lookupOrDefault("name", scalar(1.5)); // ... not quite so nice
|
|
|
```
|
|
|
The first form is preferrable since the templated type is more evident
|
|
|
and the value itself is easier to find.
|
|
|
|
|
|
|
|
|
**Anti-pattern**: Over-specifying `bool` input.
|
|
|
A reasonable amount of legacy code will still have code like the
|
|
|
following:
|
|
|
```
|
|
|
dict.lookupOrDefault<bool>("name", true);
|
|
|
|
|
|
dict.lookupOrDefault<Switch>("name", true);
|
|
|
```
|
|
|
|
|
|
Most code does not actually require use of `Switch` instead of `bool`.
|
|
|
The sole remaining purpose for `Switch` is to retain the named values
|
|
|
(`yes`, `no`, `on`, `off` ...) for _output_ purposes. For _input_
|
|
|
purposes, both `Switch` and `bool` accept exactly the same input.
|
|
|
|
|
|
Unless the code actually requires `Switch`, simply write
|
|
|
```
|
|
|
dict.lookupOrDefault("name", true);
|
|
|
```
|
|
|
there is no type ambiguity for the compiler.
|
|
|
|
|
|
----
|
|
|
|
|
|
Copyright (C) 2019 OpenCFD Ltd. |