... | ... | @@ -4,23 +4,526 @@ |
|
|
[][upgrade-guide]
|
|
|
[][code-patterns]
|
|
|
|
|
|
***Preview information, subject to change at any time !!!***
|
|
|
|
|
|
[[_TOC_]]
|
|
|
|
|
|
## Deprecation and Removal
|
|
|
## Potential breaking changes
|
|
|
|
|
|
### treeData items
|
|
|
|
|
|
As part of the updates to octree handling, various treeData items
|
|
|
now handle consistently full or partial subsets of data. As a
|
|
|
consequence of this, code using the direct access methods:
|
|
|
`cellLabels()`, `faceLabels()`, `edgeLabel()` is likely broken.
|
|
|
- It was _always_ unsafe to use the treeData xxxLabels() methods
|
|
|
without subsetting elements. However, since the various classes
|
|
|
(treeDataCell, treeDataEdge, etc) automatically provided an identity
|
|
|
lookup, this problem was not apparent.
|
|
|
- Use `objectIndex(label)` to safely de-reference to the original
|
|
|
index and `operator[](label)` to de-reference to the original
|
|
|
object. For treeDataEdge, the `line(label)` convenience helper is
|
|
|
often the preferred method to retrieve geometric data.
|
|
|
|
|
|
|
|
|
### Optional dictionary readEntry
|
|
|
|
|
|
In a few special cases, it can be useful to have the dictionary
|
|
|
`readEntry` be optional. For example,
|
|
|
```
|
|
|
dict.readEntry("key", keyType::LITERAL, false);
|
|
|
|
|
|
// Same as
|
|
|
dict.readIfPresent("key", keyType::LITERAL);
|
|
|
```
|
|
|
|
|
|
However, boolean arguments are often confusing to manage and require
|
|
|
reference to the documentation to remember what they mean. Sometimes
|
|
|
we would actually wish to handle a non-binary logic: (true|false|maybe).
|
|
|
To manage this, a lightweight `IOobjectOption` bundle of options has
|
|
|
been introduced, which can also be accessed from `IOobject`. This
|
|
|
transforms the previous `readEntry` as follows:
|
|
|
```
|
|
|
dict.readEntry("key", keyType::LITERAL, IOobject::READ_IF_PRESENT);
|
|
|
```
|
|
|
|
|
|
Given the rarity of `readEntry` with non-default options, this change
|
|
|
is not expected to break much existing user coding.
|
|
|
|
|
|
|
|
|
### Restrict stream renaming to ISstream
|
|
|
|
|
|
- non-const access was previously declared at the top-level (IOstream),
|
|
|
which meant that it was possible to alter the `OFstream::name()` etc
|
|
|
after opening a file, which would be inconsistent with the
|
|
|
underlying file that had been opened.
|
|
|
|
|
|
Now restrict name modification to ISstream (and ITstream
|
|
|
counterpart). Does not affect any existing valid code.
|
|
|
|
|
|
|
|
|
## Deprecated Methods
|
|
|
|
|
|
### PtrList::operator()(label)
|
|
|
|
|
|
The PtrList::operator()(label) method returns a const pointer to the
|
|
|
corresponding list item. This can be done equally well with any other
|
|
|
access method that express the coding intent more clearly:
|
|
|
|
|
|
- get(label) : same naming as unique_ptr
|
|
|
- set(label) : traditional name for checking, but can be visually
|
|
|
confused with two-parameter version
|
|
|
- test(label) : naming as per bitSet, boolList, labelHashSet
|
|
|
|
|
|
|
|
|
## Base classes/container improvements
|
|
|
|
|
|
### General
|
|
|
|
|
|
First efforts to align method names with more familiar STL method
|
|
|
names. This increases name familiar and can help when porting between
|
|
|
different C++ code bases.
|
|
|
|
|
|
- List containers, adjusted for similarity to
|
|
|
[std::vector](https://en.cppreference.com/w/cpp/container/vector)
|
|
|
- front(), back() methods
|
|
|
- push_back() method for containers that already had append().
|
|
|
- pop_back() method
|
|
|
|
|
|
- LinkedList containers, adjusted for similarity to
|
|
|
[std::list](https://en.cppreference.com/w/cpp/container/list)
|
|
|
- front(), back(), push_front(), push_back(), pop_front() methods
|
|
|
|
|
|
|
|
|
### Foam::string and Foam::fileName
|
|
|
|
|
|
Added a new `string::contains()` convenience method, which corresponds
|
|
|
to the same method which will be added to [C++23 std::string](https://en.cppreference.com/w/cpp/string/basic_string/contains).
|
|
|
For example,
|
|
|
```
|
|
|
if (keyword.contains('/')) ...
|
|
|
|
|
|
if (keyword.find('/') != std::string::npos) ...
|
|
|
```
|
|
|
|
|
|
Some `fileName` methods have been added or adjusted for similarity to
|
|
|
[std::filesystem::path](https://en.cppreference.com/w/cpp/filesystem/path):
|
|
|
|
|
|
- stem(), replace_name(), replace_ext(), remove_ext() etc
|
|
|
|
|
|
|
|
|
### PtrList
|
|
|
|
|
|
The PtrList::get(label) amd PtrList::set(label) methods now include
|
|
|
internal bounds checking and return `nullptr` for out-of-bounds
|
|
|
access. This additional check has trivial overhead but provides
|
|
|
failsafe behaviour for get() that is symmetric with
|
|
|
HashPtrTable, autoPtr etc and aligns the set(label) methods
|
|
|
for UPtrList, PtrList and PtrDynList.
|
|
|
|
|
|
|
|
|
### HashPtrTable
|
|
|
|
|
|
The HashPtrTable `set` method now supports refPtr/tmp for additional
|
|
|
flexibility.
|
|
|
|
|
|
### FixedList
|
|
|
|
|
|
Added templated `get<unsigned>()` methods which provide fast compile-time
|
|
|
indexing for FixedList (invalid indices trigger a compiler error).
|
|
|
This enables noexcept access, which can propagate into various
|
|
|
other uses (eg, triFace, triPoints, ...)
|
|
|
|
|
|
|
|
|
### MinMax
|
|
|
|
|
|
- The MinMax container now supports a `reset()` method taking single
|
|
|
or double parameter. These reset the min/max value to be identical
|
|
|
to the specified value(s), which is more convenient (and slightly
|
|
|
more efficient) than doing a full reset followed by add()
|
|
|
- Additional MinMax `intersects()` query, which works like
|
|
|
`overlaps()` but with exclusive checks at the ends.
|
|
|
- New `MinMax::operator&=()` to perform the union of two min-max
|
|
|
ranges. This operator replaces the _unused_ `intersect()` method,
|
|
|
which was confusingly similar in name to the `intersects()` query.
|
|
|
|
|
|
|
|
|
## IOstreams
|
|
|
|
|
|
### Support OFstream atomic file creation
|
|
|
|
|
|
The `IOstreamOption::ATOMIC` enumeration can used as a dispatch tag
|
|
|
when constructing an OFstream. With this form, an intermediary file is
|
|
|
created for writing. Only when the stream is closed does this
|
|
|
intermediary file get moved/renamed to the actually output name - eg,
|
|
|
`fileAbc~tmp~` becomes `fileAbc`. This provides safety if the
|
|
|
simulation crashes while writing the file, since it avoids partial
|
|
|
(corrupt) files. The choice of the name ending `~tmp~` means it will
|
|
|
will be treated as a backup file within OpenFOAM and not be loaded on
|
|
|
restart.
|
|
|
|
|
|
|
|
|
### Enumerated append/non-append open file
|
|
|
|
|
|
- Using IOstreamOption::APPEND and IOstreamOption::NON_APPEND
|
|
|
enumerations are clearer than a boolean parameter.
|
|
|
Unlikely to affect existing user coding.
|
|
|
|
|
|
|
|
|
### Simplified stream constructors
|
|
|
|
|
|
- With the introduction of IOstreamOption (added in OpenFOAM-v1806)
|
|
|
there are no cases where top-level streams (eg, IFstream, OFstream)
|
|
|
need additional information about the internal IOstream 'version'
|
|
|
(eg, version: 2.0) so these constructor forms have been
|
|
|
dropped.<br/> This makes it more convenient to open files with a
|
|
|
specified format/compression/append combination - no clutter of
|
|
|
specifying the version.
|
|
|
|
|
|
|
|
|
## IOobjectOption, IOobject
|
|
|
|
|
|
The creation of an IOobject typically contains something like this:
|
|
|
```
|
|
|
IOobject io
|
|
|
(
|
|
|
"foo",
|
|
|
runTime.timeName(),
|
|
|
mesh,
|
|
|
IOobject::MUST_READ,
|
|
|
IOobject::NO_WRITE,
|
|
|
false // do not register
|
|
|
);
|
|
|
```
|
|
|
The trailing _"do not register"_ comment shows that the calling
|
|
|
parameters are not really self-documenting. The typical options are
|
|
|
now collected in an `IOobjectOption` set of enumerations. The
|
|
|
register/no-register are now properly enumerated, which leads to this
|
|
|
type of call:
|
|
|
```
|
|
|
IOobject io
|
|
|
(
|
|
|
"foo",
|
|
|
runTime.timeName(),
|
|
|
mesh,
|
|
|
IOobject::MUST_READ,
|
|
|
IOobject::NO_WRITE,
|
|
|
IOobject::NO_REGISTER
|
|
|
);
|
|
|
```
|
|
|
The various options can also be bundled together, either explicitly or
|
|
|
implicitly:
|
|
|
```
|
|
|
IOobject io
|
|
|
(
|
|
|
"foo",
|
|
|
runTime.timeName(),
|
|
|
mesh,
|
|
|
{ IOobject::MUST_READ, IOobject::NO_REGISTER }
|
|
|
);
|
|
|
```
|
|
|
|
|
|
### IOobjectOption
|
|
|
|
|
|
The IOobjectOption class encapsulates read/write, storage flags for
|
|
|
lightweight handling, independent of objectRegistry etc. It can also
|
|
|
be used to supply read control information for dictionary reading,
|
|
|
without introducing any further sub-dependencies.
|
|
|
|
|
|
- additional IOobjectOption (or IOobject) queries for `isReadRequired()`
|
|
|
and `isReadOptional()`.
|
|
|
These encapsulate tests of `MUST_READ`, `MUST_READ_IF_MODIFIED`,
|
|
|
`READ_IF_PRESENT` for convenience and with less clutter.
|
|
|
For example,
|
|
|
```
|
|
|
if (isReadRequired() || (isReadOptional() && headerOk()))
|
|
|
{
|
|
|
...
|
|
|
}
|
|
|
```
|
|
|
Instead the longer and repetitive form:
|
|
|
```
|
|
|
if
|
|
|
(
|
|
|
(
|
|
|
readOpt() == IOobject::MUST_READ
|
|
|
|| readOpt() == IOobject::MUST_READ_IF_MODIFIED
|
|
|
)
|
|
|
|| (readOpt() == IOobject::READ_IF_PRESENT && headerOk())
|
|
|
)
|
|
|
{
|
|
|
...
|
|
|
}
|
|
|
```
|
|
|
|
|
|
### IOobjectOption for fine-tuned dictionary read
|
|
|
|
|
|
Previously had 'mandatory' (bool) for advanced control of reading
|
|
|
dictionary entries but its meaning was unclear in the calling code
|
|
|
without extra code comments.
|
|
|
|
|
|
Now use `IOobjectOption::readOption` instead, which allows further
|
|
|
options (ie, `NO_READ`) and is more transparent as to its purpose in
|
|
|
the code than a true/false bool flag was.
|
|
|
|
|
|
This is a minor breaking change (infrequent, advanced usage only)
|
|
|
|
|
|
|
|
|
## Improved/optimised geometric handling
|
|
|
|
|
|
This version adds a number of convenience methods when handling
|
|
|
geometric entities.
|
|
|
|
|
|
### General
|
|
|
|
|
|
- simplify tetrahedron and triangle handling with unified header definitions
|
|
|
and more pass-through methods.
|
|
|
- consistent member access for triFace / triangle etc.
|
|
|
Can access the vertices/points as a(), b(), c()
|
|
|
- triangle now has static centre() and areaNormal() and unitNormal()
|
|
|
methods for commonly used calculations.
|
|
|
|
|
|
|
|
|
### box()
|
|
|
|
|
|
Added low-level bound box() methods for meshShapes
|
|
|
(cell,edge,face,triangle,...) which returns a `Pair<point>`. These
|
|
|
extracted geometric limits can be used without dependency on
|
|
|
boundBox.
|
|
|
|
|
|
### mesh cellBb()
|
|
|
|
|
|
Added primitiveMesh `cellBb()` method. This returns the boundBox for
|
|
|
a given mesh cell, using the cheapest calculation:
|
|
|
- uses cellPoints if already available, since this will involve the
|
|
|
fewest number of min/max comparisions.
|
|
|
- or walks the cell faces: via the cell box() method
|
|
|
to avoid creating demand-driven cellPoints etc.
|
|
|
|
|
|
|
|
|
### patch sphere(facei)
|
|
|
|
|
|
For PrimitivePatch, added a `sphere(facei)` method that returns the
|
|
|
bounding sphere (origin + radius squared) that encloses the given
|
|
|
patch face.
|
|
|
|
|
|
|
|
|
### Additional vector methods
|
|
|
|
|
|
When working with geometries, comparison of points occurs quite
|
|
|
frequently. These are now bundled together as direct methods within
|
|
|
`Foam::vector`:
|
|
|
|
|
|
- mag() : the length (L2-norm) of the vector
|
|
|
- magSqr() : the length (L2-norm) squared of the vector.
|
|
|
- dist(const vector&) : the L2-norm distance from another vector
|
|
|
- distSqr(const vector&) : the L2-norm distance squared from another vector.
|
|
|
|
|
|
These methods are more succinct and avoid intermediary variables. For
|
|
|
example,
|
|
|
|
|
|
```
|
|
|
if (a.distSqr(b) < tol) ...
|
|
|
|
|
|
// vs.
|
|
|
if (magSqr(b - a) < tol) ...
|
|
|
```
|
|
|
|
|
|
The new `vector::less_xyz()` `vector::less_yzx()` and
|
|
|
`vector::less_zxy()` comparison methods are useful for lexicographic
|
|
|
sorting.
|
|
|
|
|
|
|
|
|
### boundBox() and treeBoundBox() handling.
|
|
|
|
|
|
The boundBox() and treeBoundBox() classes have been slightly
|
|
|
reorganised and extended with some of the following:
|
|
|
|
|
|
- additional construction and reset methods.
|
|
|
- null() static method :
|
|
|
as const reference to the invertedBox (with appropriate casting).
|
|
|
- grow() method : expand box by absolute amounts
|
|
|
- inflate(random) : an in-place version of treeBoundBox::extend
|
|
|
- boundBox::hexCorners(), boundBox::hexFaces()
|
|
|
for unambiguous addressing of points/faces corresponding to a hexCell.
|
|
|
- boundBox::add with pairs of points, when adding edges or a 'box' that has
|
|
|
been extracted from a primitive mesh shape.
|
|
|
|
|
|
|
|
|
## Octree improvements
|
|
|
|
|
|
Added octree `findBox()`, `findSphere()` with external storage of
|
|
|
results, which is more memory efficient within loops. For simple
|
|
|
tests, the octree `overlaps()` can be used. This works like findBox(),
|
|
|
findSphere() but early exit if any shapes overlap.
|
|
|
|
|
|
|
|
|
### treeData improvements
|
|
|
|
|
|
Changes to improve overall consistency in subsetting and the
|
|
|
interfaces.
|
|
|
|
|
|
- Extend the use of subset and non-subset collections with uniform
|
|
|
internal getters to ensure that the subset/non-subset versions
|
|
|
are robustly handled.
|
|
|
- operator[](label) and objectIndex(label) for standardized access
|
|
|
to the underlying item, or the original index, regardless of
|
|
|
subsetting or not.
|
|
|
- centres() and centre(label) for representative point cloud
|
|
|
information.
|
|
|
- nDim() returns the object dimensionality (0: point, 1: line, etc)
|
|
|
these can be used to determine how 'fat' each shape may be
|
|
|
and whether bounds(labelList) may contribute any useful information.
|
|
|
- bounds(labelList) to return the full bound box required for
|
|
|
specific items. Eg, the overall bounds for various 3D cells.
|
|
|
- static helpers : boxes() and bounds()
|
|
|
|
|
|
|
|
|
## Updated MPI (Pstream) methods
|
|
|
|
|
|
This release includes some code adjustments to ensure that native MPI
|
|
|
routines are used in more cases, but also includes a number of changes
|
|
|
to simplify some Pstream (MPI) methods:
|
|
|
|
|
|
- internal parRun guards to some UPstream methods to simplify calling
|
|
|
of routines,
|
|
|
|
|
|
- more consistent naming of MPI reductions:
|
|
|
|
|
|
| Unified Name | Older Name |
|
|
|
|--------------------|-----------------------|
|
|
|
| combineReduce | combineAllGather |
|
|
|
| listCombineReduce | listCombineAllGather |
|
|
|
| mapCombineReduce | mapCombineAllGather |
|
|
|
|
|
|
|
|
|
### Direct MPI and/or reductions
|
|
|
|
|
|
The `UPstream::reduceAnd` and `UPstream::reduceOr` have been added as
|
|
|
a direct wrapper of `MPI_LAND` and `MPI_LOR` intrinsics. These are
|
|
|
reused in special purpose returnReduce for logical operations.
|
|
|
|
|
|
> Using MPI bool operations allows vendor/hardware MPI optimisations.
|
|
|
|
|
|
Using `returnReduceAnd(bool)` and `returnReduceOr(bool)` as a inline wrappers
|
|
|
for returnReduce with `andOp<bool>()` and `orOp<bool>()` operators,
|
|
|
respectively provides a more easily handled expression. It also has
|
|
|
the benefit of unambiguously casting the parameter into a boolean.
|
|
|
|
|
|
|
|
|
Some examples of these new calls:
|
|
|
|
|
|
* Test for existence on any rank:
|
|
|
```
|
|
|
if (returnReduceOr(list.size()) { ... }
|
|
|
if (returnReduceOr(!list.empty()) { ... }
|
|
|
```
|
|
|
|
|
|
* Test for non-existence on all ranks:
|
|
|
```
|
|
|
if (returnReduceAnd(list.empty()) { ... }
|
|
|
if (!returnReduceOr(list.size()) { ... }
|
|
|
```
|
|
|
|
|
|
|
|
|
### Modifications for globalIndex
|
|
|
|
|
|
Use leading dispatch tags (more similarity with other C++ conventions)
|
|
|
and include a gatherNonLocal tag, which is useful for gather/write
|
|
|
where the master data can be written separately.
|
|
|
|
|
|
- added a clear() method, which resets to a null constructed state.
|
|
|
- PatchTools::gatherAndMerge supports recovery of the globalIndex as
|
|
|
an output parameter. This allows reuse in subsequent field merge
|
|
|
operations.
|
|
|
- PatchTools::gatherAndMerge now has pointMergeMap an optional
|
|
|
parameter. This information is not always required. Eg, if only
|
|
|
using gatherAndMerge to combine faces but without any point fields.
|
|
|
|
|
|
|
|
|
## Improved mesh/patch access methods.
|
|
|
|
|
|
There are a variety of minor, but convenient, changes for addressing
|
|
|
mesh and field components.
|
|
|
|
|
|
|
|
|
### Indexing into FieldField
|
|
|
|
|
|
Support tuple (pair) indexing into FieldField.
|
|
|
Can now use a (patchi, elemi) pair to access an element of a
|
|
|
FieldField.
|
|
|
|
|
|
|
|
|
### Simplify calls to faPatch/fvPatch patchField, lookupPatchField
|
|
|
|
|
|
The second (ununsed) template parameter is now entirely optional.
|
|
|
It was previously needed for old compilers (2008 and earlier).
|
|
|
|
|
|
|
|
|
### Extended polyBoundaryMesh patch/face query
|
|
|
|
|
|
The `whichPatchFace()` methods returns the (patchi, patchFacei) tuple,
|
|
|
and `whichPatch()` is now simpified wrapper for `whichPatchFace()`.
|
|
|
|
|
|
The new `groupNames()` method provides patch-based functionality
|
|
|
similar to zones.
|
|
|
|
|
|
|
|
|
### Extended finite-area mesh/face queries
|
|
|
|
|
|
To improve bookkeeping for finite-area to volume mesh correspondence:
|
|
|
|
|
|
- whichPolyPatches() = the polyPatches related to the areaMesh.
|
|
|
<br>
|
|
|
This helps when pre-calculating (and caching) any patch-specific
|
|
|
content.
|
|
|
- whichPatchFaces() = the poly-patch/patch-face for each of the faceLabels.
|
|
|
<br>
|
|
|
This allows more convenient lookups and, since the list is cached on
|
|
|
the area mesh, reduces the number of calls to whichPatch() etc.
|
|
|
|
|
|
- whichFace() = the area-face corresponding to the given mesh-face
|
|
|
|
|
|
|
|
|
In additional the volume to area mapper functions have been extended,
|
|
|
made more flexible and consistent.
|
|
|
|
|
|
|
|
|
### Deprecated Methods
|
|
|
### GeometricField field changes
|
|
|
|
|
|
### Removed Methods
|
|
|
Now have `GeometricField::internalFieldRef()` which is similar to
|
|
|
`boundaryFieldRef()` and `primitiveFieldRef()` for providing
|
|
|
write access. The naming is complimentary to `internalField()`.
|
|
|
|
|
|
### Removed Items
|
|
|
The meaning is identical to the `GeometricField::ref()` method, but
|
|
|
more explicitly named, and less likely to be confused with
|
|
|
a `tmp::ref()`, for example.
|
|
|
|
|
|
## Changes in definition
|
|
|
|
|
|
## Changes in behaviour
|
|
|
## Coordinate Systems
|
|
|
|
|
|
## Namespace changes
|
|
|
No fundamental changes in coordinate systems, but simplified handling
|
|
|
of `coordinateSystem` dictionary lookups.
|
|
|
The `coordinateSystems::NewIfPresent()` method greatly simplifies
|
|
|
handling of optional entries. For example,
|
|
|
```
|
|
|
coordSysPtr_ = coordinateSystem::NewIfPresent(mesh, dict);
|
|
|
```
|
|
|
Instead of the older, long form:
|
|
|
```
|
|
|
if (dict.found(coordinateSystem::typeName, keyType::LITERAL))
|
|
|
{
|
|
|
coordSysPtr_ =
|
|
|
coordinateSystem::New
|
|
|
(
|
|
|
mesh_,
|
|
|
dict,
|
|
|
coordinateSystem::typeName
|
|
|
);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
coordSysPtr_.reset();
|
|
|
}
|
|
|
```
|
|
|
|
|
|
----
|
|
|
|
... | ... | |