- prefer csorted() method for const access since it ensures that the
return values are also const pointers (for example) even if
the object itself can be accessed as a non-const.
- the csorted() method already existed for HashTable and
objectRegistry, but now added to IOobjectList for method name
consistency (even although the IOobjectList only has a const-access
version)
ENH: objectRegistry with templated strict lookup
- for lookupClass and csorted/sorted. Allows isType restriction as a
compile-time specification.
* resize_null() methods for PtrList variants
- for cases where an existing PtrList needs a specific size and
but not retain any existing entries.
Eg,
ptrs.resize_null(100);
vs. ptrs.free(); ptr.resize(100);
or ptr.resize(100); ptrs.free();
* remove stored pointer before emplacing PtrList elements
- may reduce memory peaks
* STYLE: static_cast of (nullptr) instead of reinterpret_cast of (0)
* COMP: implement emplace_set() for PtrDynList
- previously missing, which meant it would have leaked through to the
underlying PtrList definition
* emplace methods for autoPtr, refPtr, tmp
- applies reset() with forwarding arguments.
For example,
tmp<GeoField> tfld = ...;
later...
tfld.emplace(io, mesh);
vs.
tfld.reset(new GeoField(io, mesh));
or
tfld.reset(tmp<GeoField>::New(io, mesh));
The emplace() obviously has reduced typing, but also allows the
existing stored pointer to be deleted *before* creating its
replacement (reduces memory peaks).
- this simplifies polling receives and allows separation from
the sends
ENH: add UPstream::removeRequests(pos, len)
- cancel/free of outstanding requests and remove segment from the
internal list of outstanding requests
- can be used, for example, to track global states:
// Encode as 0:empty, 1:uniform, 2:nonuniform, 3:mixed
PackedList<2> uniformity(fields.size());
forAll(fields, i)
{
uniformity.set(i, fields[i].whichUniformity());
}
reduce
(
uniformity.data(),
uniformity.size_data(),
bitOrOp<unsigned>()
);
- simplifies code by avoiding code duplication:
* parLagrangianDistributor
* meshToMesh (processorLOD and AABBTree methods)
BUG: inconsistent mapping when using processorLOD boxes (fixes#2932)
- internally the processorLODs createMap() method used a 'localFirst'
layout whereas a 'linear' order is what is actually expected for the
meshToMesh mapping. This will cause of incorrect behaviour
if using processorLOD instead of AABBTree.
A dormant bug since processorLOD is not currently selectable.
- primarily for handling expression results,
but can also be used as a universal value holder.
Has some characteristics suitable for type-less IO:
eg, is_integral(), nComponents()
ENH: add is_pointer() check for expression scanToken
- update TimeState access methods
- use writeTime() instead of old method name outputTime()
- use deltaTValue() instead of deltaT().value()
to avoids pointless construct of intermediate
- files might have been set during token reading so only on
known on master processor.
Broadcast names to all processors (even alhough they are only
checked on master) so that the watched states remain synchronised
- provides a more succinct way of writing
{fa,fv}PatchField<Type>::patchInternalField(*this)
as well as a consistent naming that can be used for patches derived
from valuePointPatchField
ENH: readGradientEntry helper method for fixedGradient conditions
- simplifies coding and logic.
- support different read construct modes for fixedGradient
- individual processor Time databases are purely for internal logistics
and should not be introducing any new library symbols: these will
already have been loaded in the outer loop.
- MPI_THREAD_MULTIPLE is usually undesirable for performance reasons,
but in some cases may be necessary if a linked library expects it.
Provide a '-mpi-threads' option to explicitly request it.
ENH: consolidate some looping logic within argList
- primarily relevant for finite-area meshes, in which case they can be
considered to be an additional, detailed diagnositic that is
normally not needed (clutters the file system).
Writing can be enabled with the `-write-edges` option.
- fatten the interface to continue allowing write control with a bool
or with a dedicated file handler. This may slim down in the future.
Co-authored-by: mattijs <mattijs>
- accept plain lists (space or comma separated) as well as the
traditional OpenFOAM lists. This simplifies argument handling
with job scripts.
For example,
simpleFoam -ioRanks 0,4,8 ...
vs
simpleFoam -ioRanks '(0 4 8)' ...
It is also possible to select the IO ranks on a per-host basis:
simpleFoam -ioRanks host ...
- expose rank/subrank handling as static fileOperation methods
- added UPstream::allGatherValues() with a direct call to MPI_Allgather.
This enables possible benefit from a variety of internal algorithms
and simplifies the caller
Old:
labelList nPerProc
(
UPstream::listGatherValues<label>(patch_.size(), myComm)
);
Pstream::broadcast(nPerProc, myComm);
New:
const labelList nPerProc
(
UPstream::allGatherValues<label>(patch_.size(), myComm)
);
- Pstream::allGatherList uses MPI_Allgather for contiguous values
instead of the hand-rolled tree walking involved with
gatherList/scatterList.
-
- simplified the calling parameters for mpiGather/mpiScatter.
Since send/recv data types are identical, the send/recv count
is also always identical. Eliminates the possibility of any
discrepancies.
Since this is a low-level call, it does not affect much code.
Currently just Foam::profilingPstream and a UPstream internal.
BUG: call to MPI_Allgather had hard-coded MPI_BYTE (not the data type)
- a latent bug since it is currently only passed char data anyhow
- this refinement of commit 81807646ca makes these methods
consistent with other objects/containers.
The 'unsigned char' access is still available via cdata()
- use typeHeaderOk<regIOobject>(false) for some generic file existence
checks. Often had something like labelIOField as a placeholder, but
that may be construed to have a particular something.
- coupled patches are treated distinctly and independently of
internalFacesOnly, it makes little sense to report them with a
warning about turning off boundary faces (which would not work
anyhow).
STYLE: update code style for createBaffles
- permitting a cast to a non-const pointer adds uncertainty of
ownership.
- adjust PtrDynList transfer. Remove the unused 'PtrDynList::remove()'
method, which is better handled with pop().
- this complements the whichPatch(meshFacei) method [binary search]
and the list of patchID() by adding internal range checks.
eg,
Before
~~~~~~
if (facei >= mesh.nInternalFaces() && facei < mesh.nFaces())
{
patchi = pbm.patchID()[facei - mesh.nInternalFaces()];
...
}
After
~~~~~
patchi = pbm.patchID(facei);
if (patchi >= 0)
{
...
}
ENH: support transfer from a wrapped MPI request to global list
- allows coding with a list UPstream::Request and subsequently either
retain that list or transfer into the global list.
- construct from components, or use word::null to ensure
consistent avoid naming between IOobject vs dimensioned type.
- support construct with parameter ordering as per DimensionedField
ENH: instantiate a uniformDimensionedLabelField
- eg, for registering standalone integer counters
- simplifies communication structuring with intra-host communication.
Can be used for IO only, or for specialised communication.
Demand-driven construction. Gathers the SHA1 of host names when
determining the connectivity. Internally uses an MPI_Gather of the
digests and a MPI_Bcast of the unique host indices.
NOTE:
does not use MPI_Comm_splt or MPI_Comm_splt_type since these
return MPI_COMM_NULL on non-participating process which does not
easily fit into the OpenFOAM framework.
Additionally, if using the caching version of
UPstream::commInterHost() and UPstream::commIntraHost()
the topology is determined simultaneously
(ie, equivalent or potentially lower communication).
- make sizing of commsStruct List demand-driven as well
for more robustness, fewer unneeded allocations.
- fix potential latent bug with allBelow/allNotBelow for proc 0
(linear communication).
ENH: remove unused/unusable UPstream::communicator optional parameter
- had constructor option to avoid constructing the MPI backend,
but this is not useful and inconsistent with what the reset or
destructor expect.
STYLE: local use of UPstream::communicator
- automatically frees communicator when it leaves scope
- these are primarily when encountering sparse (eg, inter-host)
communicators. Additional UPstream convenience methods:
is_rank(comm)
=> True if process corresponds to a rank in the communicators.
Can be a master rank or a sub-rank.
is_parallel(comm)
=> True if parallel algorithm or exchange is used on the process.
same as
(parRun() && (nProcs(comm) > 1) && is_rank(comm))
- replace the "one-size-fits-all" approach of tensor field inv()
with individual 'failsafe' inverts.
The inv() field function historically just checked the first entry
to detect 2D cases and adjusted/readjusted *all* tensors accordingly
(to avoid singularity tensors and/or noisy inversions).
This seems to have worked reasonably well with 3D volume meshes, but
breaks down for 2D area meshes, which can be axis-aligned
differently on different sections of the mesh.
- not currently used, but it is possible that communicator allocation
modifies the list of sub-ranks. Ensure that the correct size is used
when (re)initialising the linear/tree structures.
STYLE: adjust MPI test applications
- remove some clutter and unneeded grouping.
Some ideas for host-only communicators
- attributes such as assignable(), coupled() etc
- common patchField types: calculatedType(), zeroGradientType() etc.
This simplifies reference to these types without actually needing a
typed patchField version.
ENH: add some basic patchField types to fieldTypes namespace
- allows more general use of the names
ENH: set extrapolated/calculated from patchInternalField directly
- avoids intermediate tmp
- for cases where a 3D tensor is being used to represent 2D content,
the determinant is zero. Can use inv2D(excludeDirection) to compensate
and invert as if it were only 2D.
ENH: consistent definitions for magSqr of symmTensors, diagSqr() norm
COMP: return scalar not component type for magSqr
- had inconsistent definitions with SymmTensor returning the component
type and Tensor returning scalar. Only evident with complex.
- similar to UPstream::parRun(), the setter returns the previous value.
The accessors are prefixed with 'comm':
Eg, commGlobal(), commWarn(), commWorld(), commSelf().
This distinguishes them from any existing variables (eg, worldComm)
and arguably more similar to MPI_COMM_WORLD etc...
If demand-driven communicators are added in the future, the function
call syntax can help encapsulate that.
Previously:
const label oldWarnComm = UPstream::warnComm;
const label oldWorldComm = UPstream::worldComm;
UPstream::warnComm = myComm;
UPstream::worldComm = myComm;
...
UPstream::warnComm = oldWarnComm;
UPstream::worldComm = oldWorldComm;
Now:
const label oldWarnComm = UPstream::commWarn(myComm);
const label oldWorldComm = UPstream::commWorld(myComm);
...
UPstream::commWarn(oldWarnComm);
UPstream::commWorld(oldWorldComm);
STYLE: check (warnComm >= 0) instead of (warnComm != -1)
- useful when regular contents are to be read via an IOobject and
returned.
Eg, dictionary propsDict(IOdictionary::readContents(dictIO));
vs. dictionary propsDict(static_cast<dictionary&&>(IOdictionary(dictIO)));
Commonly these would have simply been constructed directly as the
IO container:
eg, IOdictionary propsDict(dictIO);
However, that style may not ensure proper move semantics for return
types.
Now,
=====
labelList decomp(labelIOList::readContents(io));
... something
return decomp;
=====
Previously,
=====
labelIOList decomp(io);
// Hope for the best...
return decomp;
// Or be explicit and ensure elision occurs...
return labelList(std::move(static_cast<labelList&>(decomp)));
=====
Note:
labelList list(labelIOList(io));
looks like a good idea, but generally fails to compile
- the iterator/const_iterator now skip any nullptr entries,
which enables the following code to work even if the PtrList
contains nullptr:
for (const auto& intf : interfaces)
{
// Do something
...
}
- this is a change in behaviour compared to OpenFOAM-v2212 and earlier,
but is non-breaking:
* Lists without null entries will traverse exactly as before.
* Lists with null entries will now traverse correctly without
provoking a FatalError.
- allows unambiguous of count() for other classes.
Naming as per std::shared_ptr.
STYLE: qualify use_count() and unique() methods with the refCount base
- clearer/consistent meaning
- the null output adapter was previously used for the HashTables API
when HashSet actually stored key/value. Now that the node only
contains the key, having suppressed output is redundant, as is the
zero::null class (reduces clutter)
STYLE: replace one::minus dispatch in extendedEdgeMesh
GIT: remove Foam::nil typedef (deprecated since May-2017)
ENH: add pTraits and IO for std::int8_t
STYLE: cull some implicitly available includes
- pTraits.H is included by label/scalar etc
- zero.H is included by UList
STYLE: cull redundant forward declarations for Istream/Ostream
- in earlier versions: used 'fixed' notation
to force floating point numbers to be printed with at least
some decimal digits. However, in the meantime we are more
flexible with handling float/int input so remove this constraint.
- use ITstream::toString, which makes the string expansion of ${var}
and the expression expansion of $[var] consistent.
- defined for lerp between two fields,
either with a constant or a field of interpolation factors.
* plain Field, DimensionedField, FieldField, GeometricFields
- using a field to lerp between two constants is not currently
supported
- newer naming allows for less confusing code.
Eg,
max(lower) -> clamp_min(lower)
min(upper) -> clamp_max(upper)
- prefer combined method, for few operations.
Eg,
max(lower) + min(upper) -> clamp_range(lower, upper)
The updated naming also helps avoid some obvious coding errors.
Eg,
Re.min(1200.0);
Re.max(18800.0);
instead of
Re.clamp_range(1200.0, 18800.0);
- can also use implicit conversion of zero_one to MinMax<Type> for
this type of code:
lambda_.clamp_range(zero_one{});
- this is slightly longer to write (but consistent with clamp_min
etc). The main reason is that this allows easier use of the clamp()
free function.
STYLE: skip checks for bad/invalid clamping ranges
- ranges are either already validated before calling, the caller logic
has already made the branching decision.
- in most cases can simply construct mapDistribute with the sendMap
and have it take care of communication and addressing for the
corresponding constructMap.
This removes code duplication, which in some cases was also using
much less efficient mechanisms (eg, combineReduce on list of
lists, or an allGatherList on the send sizes etc) and also
reduces the number of places where Pstream::exchange/exchangeSizes
is being called.
ENH: reduce communication in turbulentDFSEMInlet
- was doing an allGatherList to populate a mapDistribute.
Now simply use PstreamBuffers mechanisms directly.
- dynamic sparse data exchange using Map to hold data and sizes.
Still uses the personalised exchange paradigm, but with non-blocking
consensus exchange to obtain the sizes and regular point-to-point
for the data exchange itself. This avoids an all-to-all but still
keeps the point-to-point for overlapping communication, data
chunking etc.
- basic functionality similar to std::span (C++20).
Holds pointer and size: for lightweight handling of address ranges.
- implements cdata_bytes() and data_bytes() methods for similarity
with UList. For span, however, both container accesses are const
but the data_bytes() method is only available when the
underlying pointer is non-const.
No specializations of std::as_bytes() or std::as_writeable_bytes()
as free functions, since std::byte etc are not available anyhow.
- name and functionality similar to std::unordered_map (C++17).
Formalizes what had been previously been implemented in IOobjectList
but now manages without pointer deletion/creation.
- waits for completion of any of the listed requests and returns the
corresponding index into the list.
This allows, for example, dispatching of data when the receive is
completed.
- permits distinction between communicators/groups that were
user-created (eg, MPI_Comm_create) versus those queried from MPI.
Previously simply relied on non-null values, but that is too fragile
ENH: support List<Request> version of UPstream::finishedRequests
- allows more independent algorithms
ENH: added UPstream::probeMessage(...). Blocking or non-blocking
- previously built the entire adjacency table (full communication!)
but this is only strictly needed when using 'scheduled' as the
default communication mode. For blocking/nonBlocking modes this
information is not necessary at that point.
The processorTopology::New now generally creates a smaller amount of
data at startup: the processor->patch mapping and the patchSchedule.
If the default communication mode is 'scheduled', the behaviour is
almost identical to previously.
- Use Map<label> for the processor->patch mapping for a smaller memory
footprint on large (ie, sparsely connected) cases. It also
simplifies coding and allows recovery of the list of procNeighbours
on demand.
- Setup the processor initEvaluate/evaluate states with fewer loops
over the patches.
========
BREAKING: procNeighbours() method changed definition
- this was previously the entire adjacency table, but is now only the
processor-local neighbours. Now use procAdjacency() to create or
recover the entire adjacency table.
The only known use is within Cloud<ParticleType>::move and there it
was only used to obtain processor-local information.
Old:
const labelList& neighbourProcs =
mesh.globalData().topology().procNeighbours()[Pstream::myProcNo()];
New:
const labelList& neighbourProcs =
mesh.globalData().topology().procNeighbours();
// If needed, the old definition (with communication!)
const labelListList& connectivity =
mesh.globalData().topology().procAdjacency();
- skip loading of fields with -no-internal, -no-boundary
- suppress reporting fields with -no-internal, -no-boundary
- cache loaded volume field for reuse with point interpolation.
Trade off some memory overhead against reading twice.
NOTE: this issue will not be evident with foamToEnsight since there
it only handles cell data *or* point data (not both), so a field is
only ever loaded/processed once.
- symmetrical evaluation for processor patches, eliminates
scalar/vector multiply followed by projection.
STYLE: use evaluateCoupled instead of local versions
- vector, tensor versions are defined component-wise
to avoid intermediates.
The base version uses the form "(1-t)*a + t*b" without any bounds
checking (ie, will also extrapolate).
- proper component-wise clamping for MinMax clamp().
- construct clampOp from components
- propagate clamp() method from GeometricField to FieldField and Field
- clamp_min() and clamp_max() for one-sided clamping,
as explicit alternative to min/max free functions which can
be less intuitive and often involve additional field copies.
- top-level checks to skip applying invalid min/max ranges
and bypass the internal checks of MinMax::clamp() etc.
GIT: primitives/compat with compatibility includes
GIT: primitives/traits with pTraits, contiguous, zero, one etc.
COMP: relocate base equal(a,b) definition from scalar.H -> label.H
- make more universally available
STYLE: replace occasional use of notEqual(a,b) with !equal(a,b)
COMP: update include for CGAL-5.5 (#2665)
old: Robust_circumcenter_filtered_traits_3
new: Robust_weighted_circumcenter_filtered_traits_3
COMP: adjust CGAL rule for OSX (#2664)
- since CGAL is now header-only, the previous OSX-specific rules have
become redundant
- UPstream::Request wrapping class provides an opaque wrapper for
vendor MPI_Request values, independent of global lists.
ENH: support for MPI barrier (blocking or non-blocking)
ENH: support for MPI sync-send variants
STYLE: deprecate waitRequests() without a position parameter
- in many cases this can indicate a problem in the program logic since
normally the startOfRequests should be tracked locally.
It has been observed that the finite-area framework is prone to numerical
issues when zero-valued edge lenghts, edge/face normals and face areas exist.
To improve exception handling at identified code sections to gracefully
overcome math errors, the problematic entities are lower-bounded by SMALL.
- UPstream::globalComm constant always refers to MPI_COMM_WORLD but
UPstream::worldComm could be MPI_COMM_WORLD (single world)
or a dedicated local communicator (for multi-world).
- provide a Pstream wrapped version of MPI_COMM_SELF,
references as UPstream::selfComm
- UPstream::isUserComm(label)
test for additional user-defined communicators
- was previously populated with "IOobject" (the typeName) but then
cannot easily detect if the object was actually read.
Also clear the headerClassName on a failed read
BUG: parallel inconsistency in regIOobject::readHeaderOk
- headerOk() checked with master, but possible parallel operations
within it
- comprises a few different elements:
FilterField (currently packaged in PatchFunction1Types namespace)
~~~~~~~~~~~
The FilterField helper class provides a multi-sweep median filter
for a Field of data associated with a geometric point cloud.
The points can be freestanding or the faceCentres (or points)
of a meshedSurface, for example.
Using an initial specified search radius, the nearest point
neighbours are gathered and addressing/weights are built for them.
This currently uses an area-weighted, linear RBF interpolator
with provision for quadratic RBF interpolator etc.
After the weights and addressing are established,
the evaluate() method can be called to apply a median filter
to data fields, with a specified number of sweeps.
boundaryDataSurfaceReader
~~~~~~~~~~~~~~~~~~~~~~~~~
- a surfaceReader (similar to ensightSurfaceReader) when a general
point data reader is needed.
MappedFile
~~~~~~~~~~
- has been extended to support alternative surface reading formats.
This allows, for example, sampled ensight data to be reused for
mapping. Cavaet: multi-patch entries may still needs some work.
- additional multi-sweep median filtering of the input data.
This can be used to remove higher spatial frequencies when
sampling onto a coarse mesh.
smoothSurfaceData
~~~~~~~~~~~~~~~~~
- standalone application for testing of filter radii/sweeps
Changes / Improvements
- more consistent subsetting, interface
* 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.
- easier construction of non-caching versions. The bounding boxes are
rarely cached, so simpler constructors without the caching bool
are provided.
- expose findNearest (bound sphere) method to allow general use
since this does not actually need a tree.
- static helpers
The boxes() static methods can be used by callers that need to build
their own treeBoundBoxList of common shapes (edge, face, cell)
that are also available as treeData types.
The bounds() static methods can be used by callers to determine the
overall bound-box size prior to constructing an indexedOctree
without writing ad hoc code inplace.
Not implemented for treeDataPrimitivePatch since similiar
functionality is available directly from the PrimitivePatch::box()
method with less typing.
========
BREAKING: cellLabels(), faceLabels(), edgeLabel() access methods
- 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[](index) to de-reference to the original object.
- use default initialize boundBox instead of invertedBox
- reset() instead of assigning from invertedBox
- extend (three parameter version) and grow method
- inflate(Random) instead of extend + re-assigning
- null() static method
* as const reference to the invertedBox with the appropriate casting.
- boundBox inflate(random)
* refactored from treeBoundBox::extend, but allows in-place modification
- boundBox::hexFaces() instead of boundBox::faces
* rarely used, but avoids confusion with treeBoundBox::faces
and reuses hexCell face definitions without code duplication
- boundBox::hexCorners() for corner points corresponding to a hexCell.
Can also be accessed from a treeBoundBox without ambiguity with
points(), which could be hex corners (boundBox) or octant corners
(treeBoundBox)
- boundBox::add with pairs of points
* convenient (for example) when adding edges or a 'box' that has
been extracted from a primitive mesh shape.
- declare boundBox nPoints(), nFaces(), nEdges() as per hexCell
ENH: return invertedBox instead of FatalError for empty trees
- similar to #2612
ENH: cellShape(HEX, ...) + boundBox hexCorners for block meshes
STYLE: cellModel::ref(...) instead of de-reference cellModel::ptr(...)
- the boundBox for a given cell, using the cheapest calculation:
- cellPoints if already available, since this will involve the
fewest number of min/max comparisions.
- otherwise walk the cell faces: via the cell box() method
to avoid creating demand-driven cellPoints etc.
ENH: use direct access to pointHit as point(), use dist(), distSqr()
- if the pointHit has already been checked for hit(), can/should
simply use point() noexcept access subsequently to avoid redundant
checks. Using vector distSqr() methods provides a minor optimization
(no itermediate temporary), but can also make for clearer code.
ENH: copy construct pointIndexHit with different index
- symmetric with constructing from a pointHit with an index
STYLE: prefer pointHit point() instead of rawPoint()
- provides 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, ...)
ENH: add triangle edge vectors
- traditionally used first(), last() methods,
but front(), back() are well-known from std::vector etc
which makes the access more familiar.
- support push_back() method for containers that already had append().
This increases name familiar and can help when porting between
different C++ code bases.
- support pop_back() method for List containers.
This is similar to std::vector
- ie, front(), back(), push_front(), push_back(), pop_front()
ENH: add CircularBuffer flattening operator() and list() method
- useful if assigning content to a List etc
BUG: CircularBuffer find() did not return logical index
- in makeFaMesh, the serial fields are now only read on the master
process and broadcast to the other ranks. The read+distribute is
almost identical to that used in redistributePar, except that in
this case entire fields are sent and not a zero-sized subset.
- improved internal faMesh checking for files so that the TryNew
method works with distributed roots.
- if the volume faceProcAddressing is missing, it is not readily
possible to determine equivalent area procAddressing.
Instead of throwing an error, be more fault-tolerant by having it
create with READ_IF_PRESENT and then detect and warn
if there are problems.
- accept IOobjectOption::registerOption with (MUST_READ, NO_WRITE)
being implicit. Direct handling of IOobjectOption itself, for
consistency with IOobject.
The disabling of object registration is currently the only case
where IOobjectList doesn't use default construction parameters,
but it was previously a bit awkward to specify.
- had an off-by-one in the accounting for some corner caes,
partly because the logic was a bit convoluted
ENH: improved string wrapping (#2625)
- reworked logic (like a state machine) to handle backtracking
with fallback of splitting near punctuation characters.
Still doesn't compete with nroff or TeX, but does avoid long lines
and many funny splits. With this change the help for mapFieldsPar
now like this:
=====
Specify the mapping method
(direct|mapNearest|cellVolumeWeight|
correctedCellVolumeWeight)
=====
Since the list of options is very long without any spaces, it takes
'|' as the best split point, which definitely reads better
- since ensight format is always float and also always written
component-wise, perform the double -> float narrowing when
extracting the components. This reduces the amount of data
transferred between processors.
ENH: avoid vtk/ensight parallel communication of empty messages
- since ensight writes by element type (eg, tet, hex, polyhedral) the
individual written field sections will tend to be relatively sparse.
Skip zero-size messages, which should help reduce some of the
synchronization bottlenecks.
ENH: use 'data chunking' when writing ensight files in parallel
- since ensight fields are written on a per-element basis, the
corresponding segment can become rather sparsely distributed. With
'data chunking', we attempt to get as many send/recv messages in
before flushing the buffer for writing. This should make the
sequential send/recv less affected by the IO time.
ENH: allow use of an external buffer when writing ensight components
STYLE: remove last vestiges of autoPtr<ensightFile> for output routines
- with ATOMIC, an intermediary file is created - eg, (fileAbc~tmp~)
where all of the output is written to. When the stream goes out of
scope, this intermediary file is moved/renamed to the actually
output name - eg, (fileAbc~tmp~) -> (fileAbc).
This adds some safety if the simulation crashes while writing the
file, since it will the partial (corrupt) file will be left
behind as (fileAbc~tmp~) and not as (fileAbc), which means it will
will be treated as a backup file and not loaded again on restart.
ENH: provided enumeration for APPEND/NON_APPEND
- clearer than using bool (with comments).
Since append mode is primarily only used by masterOFstream etc
this change is unlikely to affect user coding.
ENH: use file atomic for ensight file creation
- avoids corrupt (truncated) files being referenced by the ensight
case file if the simulation crashes while writing the ensight file.
- eg, for partially incomplete systems (without libz devel header)
ENH: clearer binding of dummy Pstream in OpenFOAM/Make/options
- link of dummy stub Pstream now contingent on linking libOpenFOAM as
well. This makes the purpose slightly clearer
ENH: cleaner option naming/handling in wmake script
- allow special purpose -no-openfoam option.
Eg, compiling test programs without OpenFOAM and Pstream libraries
but using the rest of the wmake system.
ENH: add +openmp support into WM_COMPILE_CONTROL (#2633)
- this adds compile/link flags for openmp.
For single-use, can also use 'wmake -openmp'.
If both +openmp and ~openmp are specified in WM_COMPILE_CONTROL
the ~openmp will have priority.
This is actually done indirectly since ~openmp will set empty
COMP_OPENMP, LINK_OPENMP internal variables, which the +openmp then
adds to the c++FLAGS and linkexe targets (ie, won't actually add
anything).
ENH: add +ccache or ccache=... support into WM_COMPILE_CONTROL (#2633)
- with the first version (+ccache), simply use ccache from the path
without any extra options.
- with the second version (ccache=...), can be more specific about
what is called.
Using "+ccache" is identical to "ccache=ccache", but the later could
be used in other ways. For example,
ccache=/strange/install/path/ccache
ccache=</path/my-tooling --option>
Have the choice of unquoted, single or double quoted or '< >' quoted
STYLE: relocate FOAM_EXTRA_LDFLAGS in general makefile
- removes clutter for different linkers (eg, gold, mold, ldd)
making it easier to extend for other linkers.
STYLE: protect makefile checks with 'strip' function
- consistent with sumOp
ENH: globalIndex with gatherNonLocal tag, and use leading dispatch tags
- useful for gather/write where the master data can be written
separately. Leading vs trailing dispatch tags for more similarity to
other C++ conventions.
The improvements include:
- Allowing overset patches to be displaced outside background domain.
- The approach does not support overlapping of multiple inset meshes
on top of background domain.
- Allowing fringe faces to walk away from hole cells in background domain.
- The approach was not extensibly tested with overlapping patches.
- Improving mass conservation.
- Various experimental entries are removed: massFluxInterpolation, ddtCorr.
- New entries:
- oversetAdjustPhi: adds a flux correction outside the pressure equation.
- massCorrection: adds an implicit correction.
- replaced ad hoc handling of formatOptions with coordSetWriter and
surfaceWriter helpers.
Accompanying this change, it is now possible to specify "default"
settings to be inherited, format-specific settings and have a
similar layering with surface-specific overrides.
- snappyHexMesh now conforms to setFormats
Eg,
formatOptions
{
default
{
verbose true;
format binary;
}
vtk
{
precision 10;
}
}
surfaces
{
surf1
{
...
formatOptions
{
ensight
{
scale 1000;
}
}
}
}
- support globalIndex for points/faces as an output parameter,
which allows reuse in subsequent field merge operations.
- make pointMergeMap an optional parameter. This information is not
always required. Eg, if only using gatherAndMerge to combine faces
but without any point fields.
ENH: make globalIndex() noexcept, add globalIndex::clear() method
- end_value() corresponds to the infrequently used after() method, but
with naming that corresponds better to iterator naming conventions.
Eg,
List<Type> list = ...;
labelRange range = ...;
std::transform
(
(list.data() + range.begin_value()),
(list.data() + range.end_value()),
outIter,
op
);
- promote min()/max() methods from labelRange to IntRange base class
STYLE: change timeSelector from "is-a" to "has-a" scalarRanges.
- resets min/max to be identical to the specified value,
which can be 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
- provide MinMax::operator&=() to replace (unused) intersect() method
ENH: single/double value reset method for boundBox
- boundBox::operator&=() to replace (rarely used) intersect() method.
Deprecate boundBox::intersect() to avoid confusion with various
intersects() method
COMP: provide triangleFwd.H
- background: for some application it can be useful to have fully
sorted points. i.e., sorted by x, followed by y, followed by z.
The default VectorSpace 'operator<' compares *all*
components. This is seen by the following comparisons
1. a = (-2.2 -3.3 -4.4)
b = (-1.1 -2.2 3.3)
(a < b) : True
Each 'a' component is less than each 'b' component
2. a = (-2.2 -3.3 -4.4)
b = (-2.2 3.3 4.4)
(a < b) : False
The a.x() is not less than b.x()
The static definitions 'less_xyz', 'less_yzx', 'less_zxy'
instead use comparison of the next components as tie breakers
(like a lexicographic sort).
- same type of definition that Pair and Tuple2 use.
a = (-2.2 -3.3 -4.4)
b = (-2.2 3.3 4.4)
vector::less_xyz(a, b) : True
The a.x() == b.x(), but a.y() < b.y()
They can be used directly as comparators:
pointField points = ...;
std::sort(points.begin(), points.end(), vector::less_zxy);
ENH: make VectorSpace named access methods noexcept.
Since the addressing range is restricted to enumerated offsets
(eg, X/Y/Z) into storage, always remains in-range.
Possible to make constexpr with future C++ versions.
STYLE: VectorSpace 'operator>' defined using 'operator<'
- standard rewriting rule
STYLE: combine templated/non-templated headers (reduced clutter)
STYLE: use hitPoint(const point&) combined setter
- same as setHit() + setPoint(const point&)
ENH: expose and use labelOctBits::pack method for addressing
- construct boundBox from Pair<point> of min/max limits,
make sortable
- additional bounding box intersections (linePointRef), add noexcept
- templated access for boundBox hex-corners
(used to avoid temporary point field).
Eg, unrolled plane/bound-box intersection with early exit
- bounding box grow() to expand box by absolute amounts
Eg,
bb.grow(ROOTVSMALL); // Or: bb.grow(point::uniform(ROOTVSMALL));
vs
bb.min() -= point::uniform(ROOTVSMALL);
bb.max() += point::uniform(ROOTVSMALL);
- treeBoundBox bounding box extend with two or three parameters.
The three parameter version includes grow(...) for reduced writing.
Eg,
bb = bb.extend(rndGen, 1e-4, ROOTVSMALL);
vs
bb = bb.extend(rndGen, 1e-4);
bb.min() -= point::uniform(ROOTVSMALL);
bb.max() += point::uniform(ROOTVSMALL);
This also permits use as const variables or parameter passing.
Eg,
const treeBoundBox bb
(
treeBoundBox(some_points).extend(rndGen, 1e-4, ROOTVSMALL)
);
- box method on meshShapes (cell,edge,face,triangle,...)
returns a Pair<point>.
Can be used directly without dependency on boundBox,
but the limits can also passed through to boundBox.
- Direct box calculation for cell, which walks the cell-faces and
mesh-faces. Direct calculation for face (#2609)
ENH: extend rmDir to handle removal of empty directories only
- recursively remove directories that only contain other directories
but no other contents. Treats dead links as non-content.
- stem(), replace_name(), replace_ext(), remove_ext() etc
- string::contains() method - similar to C++23 method
Eg,
if (keyword.contains('/')) ...
vs
if (keyword.find('/') != std::string::npos) ...
- construct based on db and mesh information from an existing field
- check movable() instead of isTmp() when reusing fields
STYLE: isolate check for reuse GeometricField into Detail namespace
- in continuation of #2565 (rotationCentre for surface output formats)
it is helpful to also support READ_IF_PRESENT behaviour for the
'origin' keyword.
This can be safely used wherever the coordinate system definition
is embedded within a sub-dictionary scope.
Eg,
dict1
{
coordinateSystem
{
origin (0 0 0); // now optional here
rotation ...;
}
}
but remains mandatory if constructed without a sub-dict:
dict2
{
origin (0 0 0); // still mandatory
e1 (1 0 0);
e3 (0 0 1);
}
With this change, the "transform" sub-dictionary can written
more naturally:
formatOptions
{
vtk
{
scale 1000; // m -> mm
transform
{
rotationCentre (1 0 0);
rotation axisAngle;
axis (0 0 1);
angle -45;
}
}
}
ENH: simplify handling of "coordinateSystem" dictionary lookups
- coordinateSystems::NewIfPresent method for optional entries:
coordSysPtr_ = coordinateSystem::NewIfPresent(mesh, dict);
Instead of
if (dict.found(coordinateSystem::typeName, keyType::LITERAL))
{
coordSysPtr_ =
coordinateSystem::New
(
mesh_,
dict,
coordinateSystem::typeName
);
}
else
{
coordSysPtr_.reset();
}
ENH: more consistent handling of priorities for binModels, forces (#2598)
- if the dictionaries are overspecified, give a 'coordinateSystem'
entry a higher prioriy than the 'CofR' shortcuts.
Was previously slightly inconsistent between the different models.
- with IOstreamOption there are no cases where we need to construct
top-level streams (eg, IFstream, OFstream) with additional information
about the internal IOstream 'version' (eg, version: 2.0).
Makes it more convenient to open files with a specified
format/compression combination - no clutter of specifying the
version
- avoids redundant dictionary searching
STYLE: remove dictionary lookupOrDefaultCompat wrapper
- deprecated and replaced by getOrDefaultCompat (2019-05).
The function is usually specific to internal keyword upgrading
(version compatibility) and unlikely to exist in any user code.
- read construct from dictionary.
Calling syntax similar to dimensionedType, dimensionedSet,...
Replaces the older getEntry(), getOptional() static methods
- support readIfPresent
- noexcept on some Time methods
ENH: pass through is_oriented() method for clearer coding
- use logical and/or/xor instead of bitwise versions (clearer intent)
Header information now includes, e.g.
f [Hz] vs P(f) [Pa]
Lower frequency: 2.500000e+01
Upper frequency: 5.000000e+03
Window model: Hanning
Window number: 2
Window samples: 512
Window overlap %: 5.000000e+01
dBRef : 2.000000e-05
Area average: false
Area sum : 6.475194e-04
Number of faces: 473
Note: output files now have .dat extension
- for example,
defaultFieldValues
(
areaScalarFieldValue h 0.00014
);
regions
(
clipPlaneToFace
{
point (0 0 0);
normal (1 0 0);
fieldValues
(
areaScalarFieldValue h 0.00015
);
}
);
ENH: additional clipPlaneTo{Cell,Face,Point} topo sets
- less cumbersome than defining a semi-infinite bounding box
- remedy by performing the attach() action sequentially (as per
stitchMesh changes). This ensures that the current point addressing
is always used and avoids references to the already-merged points
(which is what causes the failure).
ENH: improve handling of empty patch removal
- only remove empty *merged* patches, but leave any other empty
patches untouched since they may intentional placeholders for other
parts of a workflow.
- remove any empty point/face zones created for patch merging