- local data to be written is now transferable into the
OFstreamCollator. This avoids making a full copy when threading is
active.
- use plain lists for managing proc data
* storage: List<List<char>> instead of PtrList<List<char>>
* views: List<stdFoam::span<char>> instead of PtrList<SubList<char>>
- use gather/write (unthreaded) as backstop if the output is too big
to fit in the buffer size. Emit warning instead of FatalError
- OCharStream for serializing
- skip intermediate blocks without reading
- support character spans
- read and distribute with direct non-blocking send/recv
instead of PstreamBuffers or with IPstream/OPstream streaming
operators.
- non-blocking gather/write when using intermediate buffer space
- use OCharStream instead of OStringStream to avoid copying char data.
- direct non-blocking send/recv with probing instead of PstreamBuffers
to avoid serialization/de-serialization of char data and reduce the
memory footprint somewhat.
- polling dispatch to write file content as it becomes available,
which should improve communication and IO overlap
- range(proci) instead of localStart(proci), localSize(proci) combination.
* does the same thing, can be used directly with various other
routines for slicing etc.
Eg,
Foam::identity(globalNumbering.range(myProci))
- globalIndex::calcOffset() instead of constructing a globalIndex and
taking the localStart(). Avoids intermediate resizing and storing of
an offsets table (which is then discarded) as well as the subsequent
lookup into that table
- creates an IOobject at the current time instance (timeName) with
NO_READ/NO_WRITE/NO_REGISTER characteristics.
This generalises and replaces the Cloud fieldIOobject() to simplify
some common use.
// Shorter version (new):
volScalarField fld
(
mesh.newIOobject(name),
...
);
// Longer version:
volScalarField fld
(
IOobject
(
name,
mesh.time().timeName(),
mesh,
IOobject::NO_READ,
IOobject::NO_WRITE
IOobject::NO_REGISTER
),
...
);
- can be useful when using memory-based streams for buffering,
in which case the name() can be used to specify the filesystem
location instead of the default stream names ("input", "output").
- shape optimisation: SQP failed due to wrong divScheme for the adjoint
equations
- shape optimisation: tutorials designed to show the impact of different flow
conditions were actually using the same U
- topology optimisation: tutorials designed to show the impact of the
flow rate distribution were actually using the same target
fractions
- topology optimisation: updated old fvSolution syntax
- had max(std::streamsize, label) but this does not resolve properly
on OSX, so write out in long form instead.
The similar logic in DynamicList is okay since there it compares
max(label, label) instead
In steadyOptimisation mode, each time-step corresponds to an
optimisation cycle and is sub-cycled, to allow for iterating the flow
and adjoint equations. This sub-cycling does not allow the execution of
function objects. This was circumvented in 8947735b1d, by explicitly
calling the execution of the function objects in the simple solver
of adjointOptimisationFoam.
However, each sub-cycled iteration is a writeTime, if the current
optimisation cycle corresponds to a writeTime. This means that function
objects with a
writeControl write;
will be executed in each iteration of the flow equations, within this
specific optimisation cycle, leading to a lot of disc space and file
clutter, if the function object outputs fields (e.g. yPlus).
8947735b1d is partially rolled back, by protecting the call to the
execution of the function objects with a bool that defaults to false.
- adjointOptimisation : missing link to fileFormats
- snappyHexMesh : add fvMotionSolvers link (#3058)
STYLE: remove remnant -DFULLDEBUG hints
- now more easily covered with wmake -debug ...
- the fileHandler changes included setting cacheLevel(0) to avoid
blocking with redistributePar. However, this meant if clouds
were not uniformly present on all ranks the fileHandler would follow
different code paths and lead to blocking.
Now switch to distributed mode for the lagrangian operations within
redistributePar based on the cacheLevel information.
FIX: avoid triggering a false processor check in argList
- when redistributing to few ranks
The solution of the QP subproblem can become quite expensive, especially
for cases with many design variables (e.g. topology optimisation).
A (potentially dense) matrix with the size of the design variables is
solved using a matrix-free CG solver. The convergence speed greatly
depends on the used preconditioner. This commit adds
preconditioner-vector products based on the L-BFGS inverse Hessian and,
more importantly, a preconditioner computed using the Sherman-Morrison
formula. The latter is applicable here since the LHS of the QP problem
is computed as the sum of rank-2 L-BFGS updates, a sum of rank-1 updates
(as many as the flow-related constraints) and a diagonal matrix
depending on the bound constraints.
Additionally, the QP subproblem could have no feasible points. To relax
this, constraints can be applied gradually through the
targetConstraintReduction enty (typical value of 0.1 for topology
optimisation).
Most cases now rely on the nullSpace update method, instead of MMA,
since it has proven more reliable.
Also, added some constrained optimisation cases, including constraints
on the flow rate partition and total pressure losses as well as cases
targeting uniformity as the objective function.
Added a 3D topology optimisation case which also includes constraints.
of the STL written by topology optimisation.
BUG: when determining which mesh faces are cut by iso-surface faces,
only append the latter if it contains more than two points
by a small amount, if all of them lay on the lower or upper bounds at
the beginning of the optimisation, to avoid singular matrices when
computing the update of the design variables.
and the Jacobian of the objective function wrt the turbulence variables
is called (rare/unorthodox case).
Additionally, objectivePowerDissipation dissipation can now be used in
topology optimisation, adding the necessary blockage dependency to it.
- Building the iso-surface spliting fluid and solid parts in topology
optimisation has been re-worked to obtain an iso-surface with unique
point numbering
- The mechanism behind marchingCells for dynamicTopODesignVariables has
been slightly reworked
The derivatives of the objective and constraint functions can optionally
be normalised in each optimisation cycle, so that MMA does not put an
excesive stress on the constraints, which can negatively affect the
course of the optimisation
A 1-Inlet-2-Outlet geometry is showcased for laminar and turbulent
flows, set-up with different variants of porosity-based and
level-set-based topology optimisation
Both porosity-based and level-set-based topO frameworks are included
through the topO and levelSet designVariables, respectively.
Both frameworks work by manipulating an underlying field of design
variables, defined in all cells of the computational domain. That field
is then regularised through a Helmholtz-like filter, before being
processed in a different way from the two topO frameworks (the
porosity-based topO sharpens/projects it while the level-set-based topO
computes signed distances around its zero iso-surface). The result of
this processing is then fed into functions that define source terms to
be added to the mean flow and turbulence model equations, to block
off/solidify parts of the mesh that are counterproductive with respect
to the objective function. These source terms are added through
fvOptions.
Since the designed walls are only simulated through source terms, the
outcome of topO should be re-analyzed on a body-fitted grid, to quantify
the actual gain in the objective function. Both topO frameworks output
the designed wall in STL format which can be used, for instance with
snappyHexMesh, to construct such a body fitted grid.
This provides a list of faces (can be internal ones) to act as
additional seeds for the wave algorithm. The default argument provides
an empty list, so the behaviour of patchWave should not change.
Useful in topology optimisation, for propagating the active design
variables from the seed faces to the interior, with a given number of
cells at a time.
- advectionDiffusion is frequently used within optimisation loops since
it is differentiable. In shape optimisation, the re-computation of
mesh distances is performed at the very beginning of a new
optimisation cycle, due to inheriting from MeshObject. If the mesh
quality is poor enough, the advectionDiffusion PDE might diverge and
crash the run, before the problematic mesh is written to files for
inspection. The default behaviour now is to check the mesh before
solving the advectionDiffusion PDE and write the mesh points if some
mesh check fails.
- fvOptions can now be included in advectionDiffusion (necessary for
topology optimisation of turbulent flows for models that include the
distance field)
- Minor changes in the numerical treatment of the diffusion term, to
enhance stability
Parts of the adjoint optimisation library were re-designed to generalise
the way sensitivity derivatives (SDs) are computed and to allow easier
extension to primal problems other than the ones governed by
incompressible flows. In specific:
- the adjoint solver now holds virtual functions returning the part of
SDs that depends only on the primal and the adjoint fields.
- a new class named designVariables was introduced which, apart from
defining the design variables of the optimisation problem and
providing hooks for updating them in an optimisation loop, provides
the part of the SDs that affects directly the flow residuals (e.g.
geometric variations in shape optimisation, derivatives of source
terms in topology optimisation, etc). The final assembly of the SDs
happens here, with the updated sensitivity class acting as an
intermediate.
With the new structure, when the primal problem changes (for instance,
passive scalars are included), the same design variables and sensitivity
classes can be re-used for all physics, with additional contributions to
the SDs being limited (and contained) to the new adjoint solver to be
implemented. The old code structure would require new SD classes for
each additional primal problem.
As a side-effect, setting up a case has arguably become a bit easier and
more intuitive.
Additional changes include:
---------------------------
- Changes in the formulation and computation of shape sensitivity derivatives
using the E-SI approach. The latter is now derived directly from the
FI approach, with proper discretization for the terms and boundary
conditions that emerge from applying the Gauss divergence theorem used
to transition from FI to E-SI. When E-SI and FI are based on the same
Laplace grid displacement model, they are now numerically equivalent
(the previous formulation proved the theoretical equivalence of the
two approaches but numerical results could differ, depending on the
case).
- Sensitivity maps at faces are now computed based (and are deriving
from) sensitivity maps at points, with a constistent point-to-face
interpolation (requires the differentiation of volPointInterpolation).
- The objective class now allocates only the member pointers that
correspond to the non-zero derivatives of the objective w.r.t. the
flow and geometric quantities, leading to a reduced memory footprint.
Additionally, contributions from volume-based objectives to the
adjoint equations have been re-worked, removing the need for
objectiveManager to be virtual.
- In constrained optimisation, an adjoint solver needs to be present for
each constraint function. For geometric constraints though, no adjoint
equations need to solved. This is now accounted for through the null
adjoint solver and the geometric objectives which do not allocate
adjoint fields for this kind of constraints, reducing memory
requirements and file clutter.
- Refactoring of the updateMethod to collaborate with the new
designVariables. Additionally, all updateMethods can now read and
write restart data in binary, facilitating exact continuation.
Furthermore, code shared by various quasi-Newton methods (BFGS, DBFGS,
LBFGS, SR1) has been organised in the namesake class. Over and above,
an SQP variant capable of tackling inequality constraints has been
added (ISQP, with I indicating that the QP problem in the presence of
inequality constraints is solved through an interior point method).
Inequality constraints can be one-sided (constraint < upper-value)
or double-sided (lower-value < constraint < upper-value).
- Bounds can now be defined for the design variables.
For volumetricBSplines in specific, these can be computed as the
mid-points of the control points and their neighbouring ones. This
usually leads to better-defined optimisation problems and reduces the
chances of an invalid mesh during optimisation.
- Convergence criteria can now be defined for the optimisation loop
which will stop if the relative objective function reduction over
the last objective value is lower than a given threshold and
constraints are satisfied within a give tolerance. If no criteria are
defined, the optimisation will run for the max. given number of cycles
provided in controlDict.
- Added a new grid displacement method based on the p-Laplacian
equation, which seems to outperform other PDE-based approaches.
TUT: updated the shape optimisation tutorials and added a new one
showcasing the use of double-sided constraints, ISQP, applying
no-overlapping constraints to volumetric B-Splines control points
and defining convergence criteria for the optimisation loop.
- enhance POSIX compliance
- apply distinct colours and dash type for each line
- standardize the frame size to 1200x627
- dynamically replace the title with <function-object-name>/<file-name>
- address underscore character issues
- introduce legend components for tensors
- resolve a bug caused by parentheses in tensor files
BUG: particleTrackProperties: correct the typo (fixes#3050)
- on large memory systems (eg, 6TB) the process information
exceeds an 'int' range, so adjust parsing of the /proc/..
to use int64
ENH: update/modernize OSspecific system information
ENH: minor update of profiling code
- std::string, noexcept, lazier evaluations
STYLE: use direct call of memInfo
- use Foam::zero as a dispatch tag
FIX: return moleculeCloud::constProps() List by reference not copy
STYLE: range-for when iterating cloud parcels
STYLE: more consistent typedefs / declarations for Clouds
- better code style and seems to avoid triggering a gcc warning about
possibly uninitialized values
COMP: JSONformatter writeEntry missing a return value
STYLE: accept 'json' for checkMesh write format
- consistent with caseInfo functionObject
- for clang-based compilers the default linker may be lld or simply ld.
Support '+link-ld' to explicitly select use of the ld linker.
- consolidate linker rules into single files
STYLE: adjust SPDX Identifier
redistributePar -decompose switches communicator when
reading on master. However other processors still get
constructed with the worldComm. >v2306 AMI stores the communicator
from construction time there was a mismatch
- regression introduced by commit 0ff86ee2
(only affects recent develop).
- now split off first/final iterations into a separate
"controls" dictionary (instead of lumping them into "solver") to
make them persistent between iterations.
- updating the header information (by copying) was closing the stream,
removing all watches and doing a checkOut/checkIn, which could lead to
dangling references.
Now just close the stream and simply copy the IOobject header
information directly.
STYLE: mark regIOobject assignment operator as possibly deprecated
- will revisit to revise or remove in the future
- the faMesh/fvMesh copy constructors were using the readOption from
the base-mesh schemes/solution instead of copying their contents.
This would not really affect fvMesh (since it has its own IOobject
for the constructor), but did affect faMesh. However, the problem
only shows up with collated + redistribute, since that is where
the ranks can be doing uncoordinated IO.
Only consider as a bug for recent develop since previous versions
had other problems with collated+redistribute with finite-area
anyhow.
- simplifies handling.
* enables unprotecting to avoid accidentally cloning.
* removes the need for dedicated constructor or factory forms.
* simplfies DimensionedField and GeometricField New factory methods
- update objectRegistry management method (internal use)
old: bool cacheTemporaryObject(...)
new: bool is_cacheTemporaryObject(...)
to clarify that it is a query, not a request for caching etc.
- give precedence to ~openmp (-no-openmp) over +openmp (-openmp)
in the general rules and in the Makefile. This makes it robuster
when specifying +openmp in general, but ~openmp for specific build
components.
- disable openmp for OSspecific and Pstream components.
Neither should contain any openmp code anyhow.
Additionally, since OSspecific is generally built as a static
object, it can become problematic (eg, with AMD ROCm) if the
compiler generates information that openmp is required but then uses
static linkage.
- the fields for finite-area are currently stored directly on the
polyMesh registry, but for future relocation to a sub-registry
provide a uniform accessor.
ENH: use thisDb() for faMatrix access and extrapolatedCalculated
- replace typeGlobal() global function with is_globalIOobject
traits for more consistent and easier overriding.
- relocate typeFilePath() global function as a member of IOobject
for consistency with typeHeaderOk.
BUG: faSchemes, fvSchemes not marked as global file types
- caused issues with collated
- static version of polyMesh::meshDir(), which takes a region name
polyMesh::meshDir(regionName)
vs
polyMesh::regionName(regionName)/polyMesh::meshSubDir
STYLE: use polyMesh::regionName(..) instead of comparing to defaultRegion
STYLE: use getOrDefault when retrieving various -region options
FIX: polyMesh::dbDir() now checks registry name, not full path (#3033)
Generates sample positions from points specified in a file as Abaqus mesh
points.
Example usage:
sets
{
cone25 // user-specified set name
{
type abaqusMesh;
file "abaqusMesh.inp";
// Optional entries
// Scale, e.g. mm to m
scale 0.001;
// Search distance when the sample point is not located in a cell
maxDist 0.25;
...
}
}
Write coordSet(s) as Abaqus point fields
Example usage
T
{
type sets;
setFormat abaqus;
fields (T);
sets
{
...
}
}
\endverbatim
Optional format options
\verbatim
formatOptions
{
abaqus
{
format ascii;
// Optional entries
// Custom header: $ entries are substituions
header
(
"** OpenFOAM abaqus output"
"** Project $FOAM_CASE"
"** File $FILE_NAME"
"** $FIELD_NAME Time t=$TIME"
);
// Write geometry in addition to field data
writeGeometry yes;
// Null value when sample value is not found
// Default is scalar::min
nullValue 0;
// Insert additional time sub-directory in the output path
// - yes : postProcessing/<fo-name>/<time>/<file>
// - no : postProcessing/<fo-name>/<file>
useTimeDir no;
// Available when 'useTimeDir' is 'no' to disambiguate file names
// Time base for output file names:
// - 'time' : <base>.inp_<field>.<time>
// - 'iteration' : <base>.inp_<field>.<iteration>
timeBase iteration;
// Optional start counters when using timeBase iteration
writeIndex
(
T 1
);
...
}
}
Example:
formatOptions
{
<writer>
{
// Apply offsets to field values
fieldLevel
{
T 273.15; // Convert from K to C by subtracting 273.15
}
// Note: scale applied after application of field level
fieldScale
{
p 0.001; // Convert pressure from Pa to kPa by scaling by 0.001
}
}
}
Added -writeChecks <format> option
- writes computed mesh metrics to file in using <format>
- currently supported formats are OpenFOAM dictionary and JSON
Collects and writes case information to file in OpenFOAM dictionary or JSON
format. Data includes:
- meta: case name, path, regions, parallel etc.
- dictionaries: entries retrieved from dictionaries - registered or from file
- per region: mesh metrics, boundary and boundary field types
- function object results
Example of function object specification:
caseInfo
{
type caseInfo;
libs (utilityFunctionObjects);
// Warn when entries are not found
lookupMode warn; // none | warn | error;
// Write format
writeFormat json; // dictionary | json;
dictionaries
{
USolver // User-specified names
{
// Look up using registered name
name "fvSolution";
// Optionally limit to specific entries
include
(
"solvers/U/solver"
);
}
fvSchemes
{
name "fvSchemes";
// include all entries by default
}
timeScheme
{
name "fvSchemes";
include
(
"/ddtSchemes/default"
);
}
turbulence
{
name "turbulenceProperties";
// include all entries by default
}
controlDict
{
// Look up using file path
path "<case>/system/controlDict";
include
(
"application"
"deltaT"
"startTime"
"endTime"
);
}
}
functionObjects (minMax1);
}
Quality metrics, e.g. non-orthogonality, skewness etc are calculated/reported
in polyMeshCheck functions. These results are now added to the meshState/mesh
dictionary to enable external access.
ENH: added 'mesh' dictionary to meshState to hold mesh properties
- solver information now stored in a 'solver' dictionary (was solverPerformance)
- {first|final}Iteration entry now stored in solver dict instead of top level
- mesh data (new) stored in 'mesh' dictionary
- code is compiled dynamically on the master node.
In the normal (non-distributed) case, simply poll the NFS
to see when it appears on the sub-procs.
For a case with distributed roots, first broadcast it (via MPI)
to the IO master nodes and then poll afterwards.
- on startup, detect and create missing processorXXX/ subdirectories
on distributed filesystems
- when reading, detect all clouds on all processors and uses this when
reading fields. Similarly, when writing it uses writeOnProc to skip
clouds that are empty on any particular processor.
Co-authored-by: Mark Olesen <>
- was previously limited to 'char' whereas gatherv/scatterv
already supported various integer and float types
STYLE: rebundle allToAll declarations with macros
ENH: provide a version of allToAllConsensus returning the Map
- simplifies use and avoids ambiguities in the send/recv parameters
- the Map version will now also transmit zero value data if they exist
in the Map. Unlike the List version, zero values are not necessary to
signal connectivity with a Map.
COMP: forwarding template parameters for NBX routines
ENH: consolidate PstreamBuffers size exchange options
- had a variety of nearly identical backends for all-to-all,
gather/scatter. Now combined internally with a dispatch enumeration
which provides better control over which size exchange algorithm
is used.
DEFEATURE: remove experimental full-NBX PstreamBuffers variant
- no advantages seen compared to the hybrid NBX/PEX approach.
Removal reduces some code cruft.
DEFEATURE: remove experimental "double non-blocking" NBX version
- the idea was to avoid blocking receives for very large data transfers,
but that is usually better accomplished with a hybrid NBX/PEX approach
like PstreamBuffers allows
- provide a globalIndex::calcOffsets() taking an indirect list, which
enables convenient offsets calculation from a variety of inputs.
- new CompactListList unpack variant: copy_unpack()
The copy_unpack() works somewhat like std::copy() in that it writes
the generated sublists to iterator positions, which makes this
type of code possible:
CompactListList<label> compact = ...;
DynamicList<face> extracted;
compact.copy_unpack<face>
(
std::back_inserter(extracted),
labelRange(4, 10)
);
-and-
const label nOldFaces = allFaces.size();
allFaces.resize(allFaces + nNewFaces);
auto iter = allFaces.begin(nOldFaces);
iter = compact.copy_unpack<face>(iter, /* selection 1 */);
...
iter = compact.copy_unpack<face>(iter, /* selection 2 */);
ENH: globalIndex resize()
- can be used to shrink or grow the offsets table.
Any extension of the offsets table corresponds to 'slots'
with 0 local size.
- report location with previous good offset and the new count that
would cause overflow. Simpler to report and the (very long) list
of input sizes is not particularly useful for diagnostics either.
ENH: add globalIndex comparison operators
- for outputting lists of globalIndex
- allows construction of string tokens holding character content.
For example, data that has been serialized and buffered and that
now needs to be written or sent to another process.
- the default returns -1 (ie, not found/available). This is overridden
by processorCyclicPolyPatch to actually perform a search
COMP: explicitly define polyMesh::writeObject in the header
- currently no special treatment, but allows future adjustments
without affecting the header.
- extends the enumeration (NO_REGISTER, REGISTER, LEGACY_REGISTER).
Can be used to tweak registration preference where required and
potentially (TDB) to define a different default value in the future
- CompactListList::size() corresponds to the number of sub-lists
whereas globalIndex::size() corresponds to the totalSize().
This difference can lead to potential coding errors when switching
between pure addressing (eg globalIndex) and addressing with content
(eg, CompactListList).
Within the source tree, there are no longer any occurances of
globalIndex::size() but it is nonetheless unsafe to change its
meaning now. Instead provide a commonly named length() method that
corresponds to the natural length: ie, the number of offsets minus 1
(with guards).
- add CompactListList::writeMatrix for writing the compact contents
in an unpacked form (eg, for debugging) without actually needing to
unpack into storage.
- provide globalIndex::whichProcID() two-parameter version
with myProcNo as the first argument.
Symmetric with isLocal etc, useful when using a communicator
that is not worldComm.
- avoids clutter of argList::envGlobalPath() ...
ENH: allow temporary overwriting of output writeFormat
- allows switching for particular output routines
COMP: explicitly use TimePaths methods with Time
- this simplifies any overloading done at a later stage
- remnant was left in the NBX implementation for Map<Type>.
Still not entirely certain which vendors/versions handle message
probe/recv properly, but using the "regular" probe and recv is OK
since everything is without threaded race conditions.
STYLE: adjust file extension of UPstreamWrapping templates
- avoids it being exposed via lnInclude
- this makes it easier to split creation into a two-stage process
as required
- extend handling for polyBoundaryMeshEntries, faBoundaryMeshEntries
with more functionality. Ensure that these are never registered.
ENH: addition writeEntry methods for polyBoundaryMesh
- simplifies streaming and collating into other files
ENH: polyMesh rereading - update owner/neighbour header information
- this avoids accidentally reading the "cells" file if the mesh has
been created with NO_READ and then updated
STYLE: less vertical space when outputting empty PtrList
- combined most of the unweighted and weighted decomposition routines
such that an empty weight field is treated as uniform weighting.
This allows default parameters and cuts down on the number of
decompose methods.
- for topology-driven decomposition, it is now possible to pass in the
owner/neighbour connectivity as a CompactListList directly instead
of first creating a labelListList (which was internally repacked into
a CompactListList in many cases).
However, multiLevelDecomp still uses unpacking (to avoid a larger
reworking of code).
- support direct creation of some methods (eg, random, scotch etc)
without a dictionary
- fix incorrect neighbour face weighting (fixes#3019)
ENH: relocate calcCellCells from decompositionMethod to globalMeshData
- makes it more universally available
- usually only need big/little defines (which are now in the Fwd)
and rarely need byte-swapping.
Provide endian.H compatibility include, but foamEndianFwd.H or
foamEndian.H to avoid potential name clashes.
- The pTraits_cmptType returns the data type of 'cmptType' (for
arithmetic and VectorSpace types) or is simply a pass-through.
This can be combined with the pTraits_nComponents for casting.
For example,
function
(
reinterpret_cast<pTraits_cmptType<Type>::type*>(buf.data()),
(buf.size()/pTraits_nComponents<Type>::value)
);
ENH: extend Foam::identityOp so support array indexing (pass-through)
- single() method : simply tests if the globalIndex has nProcs == 1,
which is typically from a gatherNone invocation.
For example,
globalIndex gi;
if (...) gi.reset(localSize);
else gi.reset(globalIndex::gatherNone{}, localSize);
// later...
const label begin = (gi.single() ? 0 : gi.localStart());
const label count = (gi.single() ? gi.totalSize() : gi.localSize());
- add front() and back() methods to return the begin/end ranges,
and begin_value(), end_value() - as per labelRange.
- make more methods noexcept
- calcOffset(), calcRange() helper functions to determine
the processor-local of a numbering range without the overhead of
creating a list of offsets.
For example,
label myOffset = globalIndex::calcOffset(mesh.nCells());
labelRange mySlice = globalIndex::calcRange(mesh.nCells());
- add globalIndex localEnd() as per CompactListList method
STYLE: align looping constructs in CompactListList with List
- make more methods noexcept
- becoming more frequently used and there is no ambiguity in calling
parameters either - identity(label) vs identity(labelUList&).
Provide both int32 and int64 versions.
- it seems that both sides of the ternary are evaluated despite
the divide-by-zero protection. Use volatile to force the compiler
to use in-order evaluation.
- attempt to minimize rounding in the cached time values
since these are also used to re-populate the case files
STYLE: remove ancient handling of "meshes" entry
- was superseded by "geometry" entry in OpenFOAM-1912 and later.
Now remove the transitional shim, which was in place for
restart migration from 1906.
CONFIG: downgrade non-uniform time from error to warning
- can be a spurious error when the deltaT is very small
CONFIG: support keywords 'minFreq', 'maxFreq'
- these are the updated naming for 'fl' and 'fu' (still supported)
- new format option keywords: timeFormat, timePrecision
CONFIG: default ensight output is now consistently BINARY
- this removes some uncertainty with the ensightWrite functionObject
which was previously dependent on the simulation writeFormat
and makes its behaviour consistent with foamToEnsight
Note: binary Ensight output is consistent with the
defaults for VTP output (inline binary)
ENH: minor adjustment of ensight writing methods
- retain group information when copying zones
- support construct empty (add details later)
- improve consistency for zone and boundaryMesh construction
- support front/back/both selection for faceZoneToCell
STYLE: prefer faceZone patch() method instead of operator()
STYLE: use std::unique_ptr instead of manual pointer management
- for zones and core patch types.
Easier data management, allows default destructors (for example)
- use add_tokens() instead of the old multi-parameter
append(.., bool) method which was misleading since it added tokens
at the current tokenIndex, not at the end.
- stringify ITstream contents with CharStream instead of StringStream.
Allows string_view for copying out the content.
ENH: set namedDictionary dictionary name from Istream
- provides context for error messages etc (#2990)
- now mark methods with strict deprecation, to make it easier to find
their use but without adding extra compilation noise for others
ENH: minor update for Enum methods and iterator
- add warnOnly (failsafe) option for readEntry and getOrDefault
- add good() method to Enum iterator (simliar to HashTable)
- replace unused/fragile Enum find() methods with iterator return
that can be used more generally
- explicit use of UPstream::worldComm in globalIndex methods
for more clarity
- adjust method declaration ordering:
de-emphasize the processor-local convenience methods
- consistent use of leading tag dispatch,
remove unused enum-based dispatch tag
- add begin()/cbegin() with offset (as per List containers)
BUG: missing use of communicator in globalIndex gatherNonLocal
- does not affect any existing code (which all use worldComm anyhow)
- support std::string_view (c++17) or span view (older c++) of stream
buffer contents. This simplifies formatting + reparsing.
Example,
OCharStream os;
os << ...;
ISpanStream is(os.view());
is >> ...;
- additional release() method for ICharStream, OCharStream
that returns the contents as a DynamicList<char> and resets the stream.
- provide a str() method for API compatibility with older
std::ostringstream etc.
- change write(const string&) to write(const std::string&).
This allows output of std::string without an intermediate copy.
- additional writeQuoted method to handle range of char data:
writeQuoted(const char* str, std::streamsize len, bool)
This helps with supporting string_view and span<char>
- add operator<< for stdFoam::span<char> and std::string_view (c++17)
- avoid duplicate code in OBJstream
STYLE: add override keyword for IO stream methods
- default construct is now identical to HashTable(Foam::zero).
It performs no allocation and is also noexcept.
The previously used default capacity (128) was a holdover from
much older versions where set/insert did not properly handle
insertion into a table with zero capacity (number of buckets).
- earlier deletion of unpopulated HashTable on resizing:
If the table is already clear (ie, has no entries),
can immediately remove the old internal table before reallocating
the newly sized table, which may avoid a needless memory spike.
- reserve() method:
Naming and general behaviour as per std::unordered_map.
It behaves similarly to the resize() method but is supplied the
number of elements instead of the capacity, which can be a more
natural way of specifying the storage requirements.
Additionally, reserve() will only increase the table capacity for
behaviour similar to DynamicList and std::vector, std::string etc.
Old:
labelHashSet set;
set.resize(2*nElems);
Now:
labelHashSet set;
set.reserve(nElems);
- remove unused HashTable(Istream&, label) constructor
STYLE: static_cast of (nullptr) and std::fill_n for filling table
- changes the addressed list size without affecting list allocation.
Can be useful for the following type of coding pattern:
- pre-allocate a List with some max content length
- populate with some content (likely not the entire pre-allocated size)
- truncate the list to the length of valid content
- process the List
- discard the List
Since the List is being discarded, using resize_unsafe() instead of
resize() avoids an additional allocation with the new size and
copying/moving of the elements.
This programming pattern can also be used when the List is being
returned from a subroutine, and carrying about a bit of unused memory
is less important than avoiding reallocation + copy/move.
If used improperly, it can obviously result in addressing into
unmanaged memory regions (ie, 'unsafe').
- shrink_to_fit()
corresponds to std::vector naming.
For DynamicList it is a *binding* request.
- shrink_unsafe()
simply adjusts the capacity() to match the
current size() without forcing a re-allocation.
Useful when collapsing to a non-dynamic list to avoid reallocation
and copying contents. The memory cleanup will still occur properly
at a later stage.
- DynamicList::swap(List&)
simple recovery of content into a non-dynamic List that also
ensures that the capacity is correctly updated.
STYLE: promote List::capacity() to public visibility (like std::vector)
STYLE: remove unused expandStorage() method
- simply a wrapper for resize(capacity())
- when running with "errors warn;" it will reset the warnings counter
(if any) when it returns to a good state.
This re-enables un-suppressed warnings for the next cycle.
Also reset the warnings counter on end().
ENH: add short-circuit in HashTable::erase(key)
- skip and return false if the table is empty or the key is not found.
This makes for faster no-op behaviour.
- for workflows with appearing/disappearing patches (for example)
can specify that empty surfaces should be ignored or warned about
instead of raising a FatalError.
Note that this handling is additional to the regular top-level
"errors" specification. So specifying 'strict' will only actually
result in a FatalError if the "errors" does not trap errors.
- "ignore" : any empty surfaces are simply ignored and no
file output (besides the header).
- "warn" : empty surfaces are warned about a few times (10)
and the file output contains a NaN entry
- "strict" : corresponds to the default behaviour.
Throws a FatalError if the surface is empty.
This error may still be caught by the top-level "errors" handling.
- support UList shallowCopy with pointer/size
(eg, for slicing into or from span)
ENH: add SubList::reset() functionality
- allows modification of a SubList after construction.
Previously a SubList had an immutable location after construction
and there was no way to shift or change its location.
BUG: missed special handling for DynamicList<char>::readList (fixes#2974)
- equivalent to List<char>::readList, in which the stream is
temporarily toggled from ASCII to BINARY when reading in a List of
char data.
This specialization was missed when DynamicList<T>::readList() was
fully implemented.
- defines values for EMPTY, UNIFORM, NONUNIFORM and MIXED
that allow bitwise OR reduction and provide an algorithm
for calculating uniformity
ENH: consolidate more efficient uniformity checks in PackedList
ENH: improve linebreak handling when outputting small matrices
- use ignore instead of seekg/tellg to swallow input (robuster)
- check for bad gcount() values
- wrap Foam::fileSize() compressed/uncompressed handling into IFstream.
- improve handling of compressed files in masterUncollatedFileOperation.
Previously read into a string via stream iterators.
Now read chunk-wise into a List of char for fewer reallocations.
- soft renames (ie, old names still available via typedefs) for more
reasonable names and more coverage with std stream variants.
The old names could be a bit cryptic.
For example, uiliststream (== an unallocated/external list storage),
which is written as std::ispanstream for C++23.
Could similarly argue that IListStream is better named as
ICharStream, since it is an input stream of characters and the
internal storage mechanism (List or something else) is mostly
irrelevant.
Extending the coverage to include all std stream variants, and
simply rewrap them for OpenFOAM IOstream types. This simplifies the
inheritance patterns and allows reuse of icharstream/ocharstream as
a drop-in replace for istringstream/ostringstream in other wrappers.
Classes:
* icharstream / ICharStream [old: none / IListStream]
* ocharstream / OCharStream [old: none / OListStream]
* ispanstream / ISpanStream [old: uiliststream / UIListStream]
* ospanstream / OSpanStream [old: none / UOListStream]
Possible new uses : read file contents into a buffer, broadcast
buffer contents to other ranks and then transfer into an icharstream
to be read from. This avoid the multiple intermediate copies that
would be associated when using an istringstream.
- Use size doubling instead of block-wise incremental for ocharstream
(OCharStream). This corresponds to the sizing behaviour as per
std::stringstream (according to gcc-11 includes)
STYLE: drop Foam_IOstream_extras constructors for memory streams
- transitional/legacy constructors but not used in any code
- nonBlocking: receive before send
- nonBlocking: wait for receive requests, process and then wait for
other requests. Can be extended to use polling...
- the 'fake' send (to self) now send copies into recv buffers instead
of send buffers.
This provides a clear separation of send and receive fields
- avoid unnecessary reallocations with PtrList of send/recv buffers
- remove outer looping for accessAndFlip and pass target field
as parameter for inner looping instead
ENH: refine mapDistribute send/recv requests handling
- separate send/recv requests for finer control
- receive does not need access to PtrList of sendBuffers, since the
send-to-self now uses the recvBuffers
- totalSize() returns retrieve the linear (total) size
(naming as per globalIndex)
- operator[] retrieves the referenced value (linear indexing)
- labels() returns a flattened labelList (as per labelRange itself)
- broadcasts list contiguous content as a two-step process:
1. broadcast the size, and resize for receiver list
2. broadcast contiguous contents (if non-empty)
This avoids serialization/de-serialization memory overhead but at
the expense of an additional broadcast call.
The trade-off of the extra broadcast of the size will be less
important than avoiding a memory peak for large contiguous mesh data.
REVERT: unstable MPI_Mprobe/MPI_Mrecv on intelmpi + PMI-2 (#2796)
- partial revert of commit c6f528588b, for NBX implementation.
Not yet flagged as causing errors here, but eliminated for
consistency.
- simplifies use with other allocators (eg, memory pools).
Can also be used with other containers.
vectorField fld = ...;
sigFpe::fillNan(fld.data_bytes(), fld.size_bytes());
COMP: inline sigFpe::ignore helper class
- now unused (may be removed in the future), but can avoid compiling
code for it
COMP: missing sigStopAtWriteNow() definition for MSwindows
- simplifies internal handling (like a fileName) and allows the
dictionary name to be used with unambiguous addressing.
The previous dot (.) separator is ambiguous (ie, as dictionary
separator or as part of a keyword).
ENH: foamDictionary report -add/-set to stderr
- selected with '+strict' in WM_COMPILE_CONTROL or 'wmake -strict', it
enables the FOAM_DEPRECATED_STRICT() macro, which can be used to
mark methods that are implicitly deprecated, but are not yet marked
as full deprecated (eg, API modification is too recent, generates
too many warnings). Can be considered a developer option.
- since the Apple SIP (System Integrity Protection) clears environment
variables such as DYLD_LIBRARY_PATH, a number of workarounds have
been used to provide shadow values. However, for a more robust
installation using -rpath at compilation time appears to be the
better solution.
In addition to the usual -rpath specification with absolute file
paths, MacOS supports (@loader_path, @executable_path) as well.
Now default to link with rpath information for MacOS, which can be
disabled by adding `~rpath` in WM_COMPILE_CONTROL
Explicit library paths handled:
- FOAM_FOAM_EXT_LIBBIN, FOAM_EXT_LIBBIN/FOAM_MPI
The executable rpaths are handled assuming a structure of
install-path/bin
install-path/lib/$(FOAM_MPI)
install-path/lib
Absolute compile-time paths for FOAM_USER_LIBBIN, FOAM_SITE_LIBBIN
and FOAM_LIBBIN are not handled since these are either too fragile
(FOAM_USER_LIBBIN and FOAM_SITE_LIBBIN values) or covered via
@loader_path anyhow (FOAM_LIBBIN).
Since the value of FOAM_MPI is a compile-time value, this rpath
treatment makes the installation less suitable for runtime changes
to the MPI vendor/version.
Note: no rpath added for c-only compilations since there are
currently no c-only libraries or executables with dynamic loading
- eliminate ClassName in favour of simple debug
- include Apple-specific FPE handling after local definition
to allow for more redefinitions
COMP: remove stray <csignal> includes
- naming like std::map::try_emplace(), it behaves like emplace_set()
if there is no element at the given location otherwise a no-op
ENH: reuse existing HashPtrTable 'slot' when setting pointers
- avoids extra HashTable operations
- the construction of compound tokens is now split into two stages:
- default construct
- read contents
This permits a larger variety of handling.
- the new token::readCompoundToken(..) method allows for simpler
more failsafe invocations.
- forward resize(), read() methods for compound tokens to support
separate read and population.
Top-level refCompoundToken() method for modify access.
ENH: split off a private readCompoundToken() method within ISstream
- this allows overloading and alternative tokenisation handling for
derived classes
- simplifies iteration of ITstream using nRemainingTokens() and skip()
methods or directly as a list of tokens.
The currentToken() method returns const or non-const access to
the token at the current tokenIndex.
The peekToken(label) method provides failsafe read access to tokens
at given locations.
ENH: add primitiveEntry construct with moving a single token
Increase usage of std algoritms within the OpenFOAM List classes. Remove reliance on linked-list during reading
See merge request Development/openfoam!620
- drop unnecessary Foam::Swap specializations when MoveConstructible
and MoveAssignable already apply. The explicit redirect to swap
member functions was needed before proper move semantics where
added.
Removed specializations: autoPtr, refPtr, tmp, UList.
Retained specialization: DynamicList, FixedList.
Special handling for DynamicList is only to accommodate dissimilar
sizing template parameters (which probably doesn't occur in
practice).
Special handling for FixedList to apply element-wise swapping.
- use std::swap for primitives. No need to mask with Foam::Swap wrapper
- fully implement DynamicList::readList() instead of simply
redirecting to List::readList(). This also benefits DynamicField.
Leverage DynamicList reading to simplify and improve CircularBuffer
reading.
- bracket lists are now read chunk-wise instead of using a
singly-linked list. For integral and vector-space types
(eg, scalar, vector, etc) this avoids intermediate allocations
for each element.
ENH: add CircularBuffer emplace_front/emplace_back
STYLE: isolate to-be-deprecated construct/assign forms
- still have construct/assign FixedList from a C-array.
This is not really needed, can use std::initializer_list
- still have construct/assign List from SLList.
Prefer to avoid these in the future.
DEFEATURE: remove construct/assign FixedList from SLList
- never used
DEFEATURE: remove move construct/assign List from SLList
- now unused. Retain copy construct/assign from SLList for transition
purposes.
- test for existing globalData() or perhaps use DIY globalIndex instead
STYLE: check for non-ASCII instead of BINARY with compression
- allows for other non-ASCII formats
- is_vectorspace :
test existence and non-zero value of the Type 'rank' static variable
- pTraits_rank :
value of 'rank' static variable (if it exists), 0 otherwise
- pTraits_nComponents :
value of 'nComponents' static variable (if it exists), 1 otherwise
- pTraits_has_zero :
test for pTraits<T>::zero member, which probably means that it also
has one, min, max members as well
Note that these traits are usable with any classes. For example,
- is_vectorspace<std::string>::value ==> false
- pTraits_nComponents<std::string>::value ==> 1
- pTraits<std::string>::nComponents ==> fails to compile
Thus also allows testing pTraits_rank<...>::value with items
for which pTraits<...>::rank fails to compile.
Eg, cyclicAMIPolyPatch::interpolate called by FaceCellWave with a
wallPoint.
pTraits<wallPoint>::rank ==> fails to compile
is_vectorspace<wallPoint>::value ==> false
GIT: relocate ListLoopM.H to src/OpenFOAM/fields/Fields (future isolation)
- in most cases a parallel-consistent order is required.
Even when the order is not important, it will generally require
fewer allocations to create a UPtrList of entries instead of a
HashTable or even a wordList.
- 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
- removed gatherv control.
The globalIndex information is cached on the merged surface
and thus not triggered often.
- strip out debug mergeField method which was a precursor to
what is now within surfaceWriter itself.
- add 'merge' true/false handling to allow testing without
parallel merging (implies no writing)
- continue to support spherical by default (for compatibility)
but add the 'spherical' switch to disable that and use a cubic
distribution instead.
STYLE: reduce number of inline files
Co-authored-by: Mark Olesen <>
- 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>()
);
- can reduce communication by only sending non-zero data (especially
when using NBX for size exchanges), but proper synchronisation with
multiply-connected processor/processor patches (eg, processorCyclic)
may still require speculative sends.
Can now setup for PstreamBuffers 'registered' sends to avoid
ad hoc bookkeeping within the caller.
- 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.
- when constructing from a sendMap, can now also specify a linear
receive layout instead of a localFirst layout
This will make it easier to reduce some code (#2932)
- add missing interface for simple distribute of List/DynamicList
with a specified commsType. Was previously restricted to
defaultCommsType only.
ENH: mapDistribute distribute/reverseDistribute with specified commsType
STYLE: prefer UPstream vs Pstream within mapDistribute
- replaces previous (similar) union but leverages the type tag for
handling logic
STYLE: remove unneeded refCount from exprResult
COMP: operator!= as member operator (exprResultDelayed, exprResultStored)
- the operator!= as a free function failed to resolve after removing
the refCount inheritance
- 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
- handle existence/non-existence of a FoamFile header automatically
- support an upper limit when getting the number of blocks and
use that for a hasBlock(...) method, which will stop reading sooner.
- Time is normally constructed with READ_MODIFIED for its controlDict
and objectRegistry, but for certain applications (eg, redistributePar)
it can be useful to construct without file monitoring and specifying
MUST_READ instead.
Example,
Info<< "Create time\n" << Foam::endl;
Time runTime
(
Time::controlDictName,
args,
false, // Disallow functionObjects
true, // Allow controlDict "libs"
IOobjectOption::MUST_READ // Instead of READ_MODIFIED
);
- update TimeState access methods
- use writeTime() instead of old method name outputTime()
- use deltaTValue() instead of deltaT().value()
to avoids pointless construct of intermediate
- no change in behaviour except to emit a warning when called with the
a non-reading readOption
STYLE: remove redundant size check
- size checking is already done by Field::assign() within the
DimensionedField::readField
- commit fb69a54bc3 accidentally changed the constructMap compact
order from linear ordering to local elements first order. Seems to
interact poorly with other bookkeeping so doing a partial revert,
but still replacing the old allGatherList with exchangeSizes.
Note:
the processorLOD method does actually use a constructMap with local
elements first ordering, so some inconsistency may still exist
there
Corrects turbulence viscosity field (e.g. nut) within a specified
region by applying a maximum limit, set according to a coefficient
multiplied by the laminar viscosity:
\nu_{t,max} = c \nu
Corrections applied to:
nut | Turbulence vicosity [m2/s2]
Usage
Minimal example by using \c constant/fvOptions:
\verbatim
limitTurbulenceViscosity1
{
// Mandatory entries (unmodifiable)
type limitTurbulenceViscosity;
// Optional entries (runtime modifiable)
nut nut;
c 1e5;
// Mandatory/Optional (inherited) entries
...
}
The optional areaNormalisationMode entry determines how the area normalisation
is performed. Options are:
- `project`: tri face area dotted with patch face normal; same as v2212 (default)
- `mag`: tri face area magnitude (v2206 and earlier)
Example usage:
AMI1
{
type cyclicAMI;
...
areaNormalisationMode mag;
//areaNormalisationMode project;
}
- the special MacOS dlopen handling (commit f584ec97d0)
did not fully solve the problem with SIP clearing.
Eg, sourcing the RunFunctions (for runParallel) triggers SIP and
clears DYLD_LIBRARY_PATH. With the cleared path it finds the dummy
libraries: the dummy Pstream::init() fails.
- for simulations where the yPlus is needed for other purposes or
just for obtaining information on the patches it can be useful
to disable field writing and save disk space.
The 'writeFields' flag (as per some other function objects)
has been added control writing the yPlus volume field.
If unspecified, the default value is 'true' so that the yPlus
function object continues to work as before.
However, this default may change to 'false' in the future to align
with other function objects.
ENH: wallShearStress: support disable of field writing
- similar to yPlus, the write() method combines writing information
and writing the fields. The 'writeFields' flag allows some
separation of that logic.
- replace Map with a List or DynamicList to reduce the number of
operations and allocations within the loops.
Use polyBoundaryMesh::nProcessorPatches() for initial capacity
to avoid reallocations.
- returns the number of processorPolyPatch patches (finiteVolume)
or else the number of processorFaPatch patches (finiteArea).
These can be useful when sizing lists etc.
- the changes introduced in f215ad15d1 aim to reduce unnecessary
point-to-point communication. However, if there are also
processorCyclic boundaries involved, there are multiple connections
between any two processors, so simply skipping empty sends will cause
synchronization problems.
Eg,
On the send side:
patch0to1_a is zero (doesn't send) and patch0to1_b does send
(to the same processor).
On the receive side:
patch1to0_a receives the data intended for patch1to0_b !
Remedy
======
Simply stream all of send data into PstreamBuffers
(regardless if empty or non-empty) but track the sends
as a bit operation: empty (0) or non-empty (1)
Reset the buffer slots that were only sent empty data.
This adds an additional local overhead but avoids communication
as much as possible.
- 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
- freeCommmunicatorComponents needs an additional bounds check.
When MPI is initialized outside of OpenFOAM, there are no
UPstream communicator equivalents
- for boundary conditions such as uniformFixed, uniformMixed etc the
optional 'value' entry (optional) is used for the initial values and
restarts. Otherwise the various Function1 or PatchFunction1 entries
are evaluated and used determine the boundary condition values.
In most cases this is OK, but in some case such coded or expression
entries with references to other fields it can be problematic since
they may reference fields (eg, phi) that have not yet been created.
For these cases the 'value' entry will be needed: documentation
updated accordingly.
STYLE: eliminate some unneeded/unused declaration headers
- 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
- can be broadly categorised as 'unthreaded'
or 'collated' (threading requirement depends on buffering)
without other opaque inheritances.
CONFIG: add hostUncollated to bash completion prompt
- The Apple SIP (System Integrity Protection) clears environment
variables, which affects the behaviour of dynamic library loading
(the DYLD_LIBRARY_PATH env variable).
OpenFOAM shadows this variable as FOAM_LD_LIBRARY_PATH, which has
been used to restore DYLD_LIBRARY_PATH (eg, in RunFunctions script).
However, this solution is not quite complete, as it
(a) requires sourcing of RunFunctions file,
(b) additional errors appear depending on a user workflow.
This changeset alleviates the problem by also iterating through
paths stored in the shadow variable when loading dynamic libraries
(if the DYLD_LIBRARY_PATH is empty).
- with C++11, static constexpr variables apparently also require
definition in a translation unit and not just as inlined quantities.
Mostly not an issue, however gcc with -O0 does not do the inlining
and thus actually requires them to be defined in a translation unit
as well.
These variables were provided for symmetry with worldComm, but only
used in low-level internal code. Changing to inlined functions
solves the linkage issue and also aligns with the commWorld()
function naming.
Mnemonics:
MPI_COMM_SELF => UPstream::commSelf()
overall MPI_COMM_WORLD => UPstream::commGlobal(), sometimes commWorld()
local COMM_WORLD => UPstream::commWorld()
- useful when speculative receives have been initiated but are no
longer required.
Combines MPI_Cancel() + MPI_Request_free() for consistent resource
management. Currently no feedback provided if the request was
satisfied by a completed send/recv or by cancellation (can be added
later if required).
- 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.
- enable 'faceZones' support.
- enable 'writeFile' support to better control file output.
- rename 'PatchPostProcessing' as 'ParticlePostProcessing' for better clarity.
- fix#1808
- enable 'faceZone' support.
- introduce 'cloudFunctionObjectTools' to simplify collection of particle info
on patches or face zones.
- enable 'writeFile' support to better control file output.
- rename 'PatchParticleHistogram' as 'ParticleHistogram' for better clarity.
- extend the loadOrCreateMesh functionality to work in conjunction
with file handlers. This allows selective loading of the mesh parts
without the ugly workaround of writing zero-sized meshes to disk and
then reading them back.
Co-authored-by: Mark Olesen <>
- 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>
- use local function for the decision making, whether worldComm or a
dedicated communicator is needed (and which sibling ranks are
involved)
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
- previously checked on destruction, but it is robuster to check for a
locally defined communicator during construction
- add InfoProxy output for fileOperation
ENH: add fileOperation::storeComm()
- transfers management of the communicator from external to internal.
Use with caution
- for special cases it can simplify sharing of processor communication
patterns, but no visible change for most code.
- make fileHandler communicator modifiable (mutable), for special
cases. The changes from 9711b7f1b9 now make this safer to do.
Continue to support legacy global function using an autoPtr:
autoPtr<fileOperation> Foam::fileHandler(autoPtr<fileOperation>&&);
However, new code using refPtr uses the following static method since
swapping out file handlers is an infrequent operation that should
also stand out a bit more.
fileOperation::fileHandler(...);
- consolidate file synchronization checks in dynamicCode
STYLE: report missing library on master only (not every rank)
- avoid flooding the output with messages
Co-authored-by: mattijs <mattijs>
- avoid explicit isFile() check in favour of a lazy-read.
With redistributePar + fileHandler, for example, it is possible that
the master processor finds file but not the subprocs
ENH: lazy reading of tetBasePtIs
- delay reading until needed
Co-authored-by: Mark Olesen <>
- 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
UPstream::allocateCommunicator
- with contiguous sub-procs. Simpler, more compact handling, ranks
are guaranteed to be monotonic
UPstream::commWorld(label)
- ignore placeholder values, prevents accidental negative values
- make communicator non-optional for UPstream::broadcast(), which
means it has three mandatory parameters and thus always fully
disambiguated from Pstream::broadcast().
ENH: relax size checking on gatherList/scatterList
- only fatal if the List size is less than nProcs.
Can silent ignore any trailing elements: they will be untouched.
- calling the mixed BC dictionary construct with NO_READ leaves the
fields properly sized, but not initialised.
ENH: add mixed BC constructor zero initialise
- sometimes the last commit is not enough information about
the tested state (especially with extensive rebasing).
Also provide the short context of some previous commits.
- this refinement of commit 81807646ca makes these methods
consistent with other objects/containers.
The 'unsigned char' access is still available via cdata()
- extend toc/sortedToc wrappers to bitSet and labelHashSet to allow
use of BitOps::toc(...) in templated code
- size_data() method to return the number of addressed integer blocks
similar to size_bytes() does, but for int instead of char.
- 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.
- ensures that read failures can be properly detected
COMP: include refPtr.H instead of autoPtr.H in IOobject.H
- ensures inclusion of autoPtr/refPtr/tmp/stdFoam
ENH: add IOobject::resetHeader() method
- when re-using an IOobject for repeated read operations it enforces
resetting of headerClassName, scalar/label sizes etc prior to
reading. Permits convenient resetting of the name too (optional).
Example,
IOobject rio("none", ..., IOobject::LAZY_READ);
rio.resetHeader("U")
if (returnReduceOr(rio.typeHeaderOk<volVectorField>(false)))
...
io.resetHeader("p")
if (returnReduceOr(rio.typeHeaderOk<volScalarField>(false)))
...
- 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().
- initialise with Switch::INVALID and then test if good() to
trigger the initial update.
This avoids some overhead, but primarily avoids ambiguity with
implicit casting to a 'bool' that autoPtr<bool> has.
- Allows clearing or freeing pointers without touching the underlying
list size. Was previously only for PtrDynList, but now available on
UPtrList, PtrList as well.
- add transfer() method to PtrDynList to avoid potential slicing.
- provide uniformMixed conditions for finite-area and finite-volume.
These are intended to replace the exprMixed condition but allow
the full range of different PatchFunction1 and Function1 types.
- add uniformFixedGradient to finite-area for completeness.
Note:
- still some possible difficulties with the order of evaluation.
- eg, using an expression within the 'U' field that depends
of the surface 'phi' field before that is constructed.
In this case, the 'value' entry is really needed.
- multiply-connected edges can arise at the centre of a "star"
connection or because the patch faces are actually baffles.
- In the serial case these internal edges are also rather dubious in
terms of modelling. However, when they are split across multiple
processors there can only be a single processor-to-processor
connectivity.
We don't necessary have enough information to know how things should
be connected, so connect pair-wise as the first remedial solution
- Any extra dangle edges are relegated to an 'ignore' faPatch
to tag as needing different handling.
- this is a placeholder boundary BC for using with bad or illegal
edges. It is currently functionally identical to zero-gradient.
Naming and definition still subject to change.
- 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)
{
...
}
- functionality introduced by openfoam.org to support selective
caching of temporary fields. The purpose is two-fold: to enable
diagnostics and to allow more places to use unregistered fields by
default.
For example to cache the grad(k) field in
cacheTemporaryObjects
(
grad(k)
);
If the name of a field which in never constructed is added to the
cacheTemporaryObjects list a waning message is generated which
includes a useful list of ALL the temporary fields constructed
during the time step
Multiple regions are also supported by specifying individual region
names in a cacheTemporaryObjects dictionary.
cacheTemporaryObjects
{
porous
(
porosityBlockage:UNbr
);
}
functions
{
writePorousObjects
{
type writeObjects;
libs (utilityFunctionObjects);
region porous;
writeControl writeTime;
writeOption anyWrite;
objects (porosityBlockage:UNbr);
}
}
- for interface polling previously required that both send and recv
requests were completed before evaluating (values or matrix update).
However, only the recv needs to be complete, which helps disentangle
the inter-rank waiting.
NB: this change is possible following (1f5cf3958b) that replaced
UPstream::resetRequests() call in favour of UPstream::waitRequests()
- UPstream exit with a non-zero return code is raised by things like
exit(FatalError) which means there is no reason to believe that
any/all of the buffered sends, requests etc have completed.
Thus avoid detaching buffers, freeing communicators etc in this
situation. This makes exit(1) behave much more like abort(), but
without any stack trace. Should presumably help with avoiding
deadlocks on exit.
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.
- can use traits to distinguish label vs scalar types and
setComponents to properly index into single or multi-component
types without needing template specialisations for the task.
This avoids the need for a concrete translation unit and the
reported problem of multiply-defined specialisations when the header
is included in different places.
- the default (uninitialised) value for edge connections of -1
could be confused with a tagged finiteArea patch, which used
(-patchid-1) encoding. This would lead to messages about erroneous
processor-processor addressing, but is in fact an mismatched edge
connection.
Now tag the finiteArea patch as (-patchid-2) to avoid this ambiguity
and correctly generate an "Undefined connection:" message instead.
Properly flush the VTP writers before raising a FatalError
to ensure that they are not prematurely truncated.
Open Point:
The base problem of "Undefined connection:" is largely related to
multiply-connected face edges (ie, from the underlying volume mesh).
Not easily remedied in the finiteArea generation.
TUT: basic finiteArea setup on motorBike
- have read(nullptr, count) and readRaw(nullptr, count) act like a
forward seek instead of failing.
This lets it be used to advance through a file without needing to
allocate (and discard) storage space etc.
- 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
- directory discovery originally designed for a sub-dir location
(eg, etc/openfoam) but failed if called from within the sub-dir
itself.
Now simply assume it is located in the project directory or the etc/
sub-dir, so that it can also be relocated into the project directory
in the future (pending changes to RPM and debian packaging)
- for querying all outstanding requests:
if (UPstream::finishedRequests(startRequest)) ...
if (UPstream::finishedRequests(startRequest, -1)) ...
- for querying slice of outstanding requests:
if (UPstream::finishedRequests(startRequest, 10)) ...
- 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))
- for robustness with small edges (which can occur with snappy meshes),
the Le() and magLe() are limited to SMALL (commit a0f1e98d24).
Now use factor sqrt(1/3) in the components to maintain magnitude of 1.
ENH: add fvMesh::unitSf() and faMesh::unitLe() methods
- simple wrappers around Sf()/magSf() and Le()/magLe() but with
the potential for additional/alternative corrections.
STYLE: thisDb() in faMesh code to simplify future changes in storage
ENH: do not register finite-area geometric fields
- consistent with finite-volume treatment
- 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.
- with (nPollProcInterfaces < 0) it does the following:
- loop, waiting for some requests to finish
- for each out-of-date interface, check if its associated
requests have now finished (ie, the ready() check).
- if ready() -> call updateInterfaceMatrix()
In contrast to (nPollProcInterfaces > 0) which loops a specified
number of times with several calls to MPI_Test each time, the
(nPollProcInterfaces < 0) variant relies on internal MPI looping
within MPI_Waitsome to progress communication.
The actual dispatch still remains non-deterministic (ie, waiting for
some requests to finish does not mean that any particular interface
is eligible for update, or in any particular order). However, using
Waitsome places the tight looping into the MPI layer, which results
in few calls and eliminates behaviour dependent on the value of
nPollProcInterfaces.
TUT: add polling to windAroundBuildings case (for testing purposes)
- fewer calls, potentially more consistent
ENH: update sendRequest state after recvRequest wait
- previously had this type of code:
// Treat send as finished when recv is done
UPstream::waitRequest(recvRequest_);
recvRequest_ = -1;
sendRequest_ = -1;
Now refined as follows:
// Require receive data. Update the send request state.
UPstream::waitRequest(recvRequest_);
recvRequest_ = -1;
if (UPstream::finishedRequest(sendRequest_)) sendRequest_ = -1;
Can potentially investigate with requiring both,
but this may be over-contrained.
Example,
// Require receive data, but also wait for sends too
UPstream::waitRequestPair(recvRequest_, sendRequest_);
- checks requests from completion, returning true when some requests
have completed and false when there are no active requests.
This allows it to be used in a polling loop to progress MPI
and then respond when as requests become satisfied.
When using as part of a dispatch loop, waitSomeRequests() is
probably more efficient than calling waitAnyRequest() and can help
avoid biasing which client requests are serviced.
Takes an optional return parameter, to retrieve the indices,
but more importantly to avoid inner-loop reallocations.
Example,
DynamicList<int> indices;
while (UPstream::waitSomeRequests(startRequest, &indices))
{
// Dispatch something ....
}
// Reset list of outstanding requests with 'Waitall' for safety
UPstream::waitRequests(startRequest);
---
If only dealing with single items and an index is required for
dispatching, it can be better to use a list of UPstream::Request
instead.
Example,
List<UPstream::Request> requests = ...;
label index = -1;
while ((index = UPstream::waitAnyRequest(requests)) >= 0)
{
// Do something at index
}
ENH: pair-wise wrappers for MPI_Test or MPI_Wait
- for send/recv pairs of requests, can bundle both together and use a
single MPI_Testsome and MPI_Waitall instead of two individual
calls.
- previously had an additional stack for freedRequests_,
which were used to 'remember' locations into the list of
outstandingRequests_ that were handled by 'waitRequest()'.
This was principally done for sanity checks on shutdown,
but we now just test for any outstanding requests that
are *not* MPI_REQUEST_NULL instead (much simpler).
The framework with freedRequests_ also had a provision to 'recycle'
them by popping from that stack, but this is rather fragile since it
would only triggered by some collectives
(MPI_Iallreduce, MPI_Ialltoall, MPI_Igather, MPI_Iscatter)
with no guarantee that these will all be properly removed again.
There was also no pruning of extraneous indices.
ENH: consolidate internal reset/push of requests
- replace duplicate code with inline functions
reset_request(), push_request()
ENH: null out trailing requests
- extra safety (paranoia) for the UPstream::Request versions
of finishedRequests(), waitAnyRequest()
CONFIG: document nPollProcInterfaces in etc/controlDict
- still experimental, but at least make the keyword known
- mechanism has been unused for at least a decade or more
(or was never used). Message tags are assigned on an ad hoc basis
locally when collision avoidance is necessary.
- 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
- allow reporting even when profiling is suspended
- consolidate reporting into profilingPstream itself
(avoids code scatter).
Example of possible advanced use for timing only one section of
code:
====
// Profile local operations
profilingPstream::enable();
... do something
// Don't profile elsewhere
profilingPstream::suspend();
====
- separate broadcast times from reduce/gather/scatter time
- separate wait times from all-to-all time
- support invocation counts, split off requests time/count
from others to avoid flooding the counts
- support 'detail' switch to increase the output information.
Format may change in the future
- 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
- with the current handling of small edges (finite-area), the LSQ
vectors can result in singular/2D tensors. However, the regular
2D handling in field inv() only detects based on the first element.
Provide a 'failsafe' inv() method for symmTensor and tensor that
follows a similar logic for avoiding zero determinates, but it is
applied on a per element basis, instead of deciding based on the
first field element.
The symmTensor::inv(bool) and tensor::inv(bool) methods have a
fairly modest additional overhead.
- unroll the field inv() function to avoid creating an intermediate
field. Reduce the number of operations when adjusting/re-adjusting
the diagonal.
- 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.
- when only a partial stacktrace is desirable.
ENH: add stack trace decorators
- the 0-th frame is always printStack(), so skip that and emit
some headers/footers instead. Eg,
[stack trace]
=============
#1 Foam::SymmTensor<double> Foam::inv<double>(...)
#2 Foam::inv(Foam::UList<Foam::SymmTensor<double>> const&) ...
...
=============
- data_bytes(), size_bytes() methods to support broadcasting or
gather/scatter content. Additional construct from raw bytes
to support transmitting content.
- missed consistency in a few places.
- return nullptr (with automatic conversion to tmp) on failures
instead of tmp<....>(nullptr), for cleaner coding.
INT: add support for an 'immovable' tmp pointer
- this idea is from openfoam.org, to allow creation of a tmp that is
protected from having its memory reclaimed in field operations
ENH: tmp NewImmovable factory method, forwards as immovable/movable
- no-op implementations, but makes the call to
GeometricBoundaryField::evaluate() less dependent on PatchField type
- add updated()/manipulatedMatrix() methods to faePatchField,
fvsPatchField etc. These are mostly no-ops, but provide name
compatible with fvPatchField etc.
- 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)
- constructing with valueRequired as a bool is still supported,
but now also support more refined requirements
(eg, NO_READ, MUST_READ, LAZY_READ)
- continue with LAZY_READ for finite-area fields
- interpret as '-decomposeParDict xyz' for simpler scripting:
A empty value ("") as well as "none" or "false" values are ignored.
Eg,
unset decompDict
if some_condition; then decompDict=decomposeParDict-12; fi
runParallel -decompose-dict=$decompDict ...
ENH: more generous when scanning decomposeParDict for numberOfSubdomains
- assume file is in system/ directory if not otherwise found
- 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.
- other systems (eg, ARM64 linux with clang) do not have a separate
mpfr library configured so also check for mpfr (gmp is assumed to be
the same) and return corresponding cgal flavour (eg, header-no-mpfr)
Note:
in some borderline cases (eg, PDRFoam) the multiplication order
and rounding imposed by the lerp function may affect the
results slightly.
eg, (valueFraction_ * this->patch().deltaCoeffs()*refValue_)
vs. (valueFraction_ * (this->patch().deltaCoeffs()*refValue_))
- 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
- clearer, more consistent parameter naming, which helps when
maintaining different field function types (eg, DimensionedFields,
GeometricFields)
- provide reuseTmpGeometricField::New taking a reference (not a tmp),
with forwarding. This helps centralise naming and acquisition etc
- split binary function macros into transform/interface
for easier support of different transform loops.
- initial field macros for looping over ternaries
- 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.
- run-time warning about deprecated features. For example,
DeprecatedInFunction(2212)
<< "Prefer using xyz boundary condition. "
<< "This boundary condition will be removed in the future." << endl;
CONFIG: mark exprFixedValue as deprecated
- same functionality is possible with uniformFixedValue and an
expression PatchFunction1, which can also be easily changed to any
other PatchFunction1
- was using UPstream::procIDs(), which returns the sub-ranks with
respect to the parent communicator. This is normally just an
identity list (single-world) but with multi-world the indexing
is incorrect. Use UPstream::allProcs() instead.
- was only used in Pstream::combineReduce(...) with a full list,
which should have been avoided in most cases anyhow.
Much more efficient to simply gather the sizes directly
- adjust nullptr checks to discourage flip-flop when confronted with
multiple null values.
Old: (a && b) ? (*a < *b) : bool(a);
New: (a && b) ? (*a < *b) : !b;
comparing (non-null < null) and (null < non-null) behaves
identically, but comparing (null < null) now tests as true
(ie, already sorted) whereas before it would have been false
(ie, needs a swap)
- add UPtrList trimTrailingNull(), which reduces the effective
(addressable) list size to ignore any trailing null pointers, but
without reallocation. This is particularly useful when creating a
UPtrList list view. For example,
UPtrList<some_iterator> validValues(container.size());
...Loop to add valid entries, by some criteria...
// Shorten list to hide null entries
validValues.trimTrailingNull();
This list view now only needs a single allocation, whereas using
a resize (as was previously necessary) could invoke a second
allocation, as well as recopying.
- 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.
- to service both List and Map exchanges with limited message sizes
(termed 'data chunking' here) add a PstreamDetail for walking and
dispatching. Like other Detail components, the API is subject
to (possibly breaking) changes in the future at any time.
The regular exchangeBuf detail has this type of signature:
PstreamDetail::exchangeBuf
(
const UList<std::pair<int, stdFoam::span<const Type>>>& sends,
const UList<std::pair<int, stdFoam::span<Type>>>& recvs,
...
)
Where [rank, span] is the tuple pack.
The basic idea is to pre-process the send/receive buffers and
marshall them into a flat list of [rank, span] tuples.
The originating buffers could be any type of container (List or Map)
which is then marshalled into this given sequence that can be
processed in source-agnostic fashion.
If data chunking is required (when UPstream::maxCommsSize > 0)
it is possible to make a cheap copy of the rank/address information
and then walk different slices or views.
ENH: replace private static methods with PstreamDetail functions
- simpler to update locally.
- since List is being used to manage the storage content for
DynamicList, it needs to free old memory for zero-sized lists first.
Consider this case (slightly exaggerated):
line 0: DynamicList<label> list;
line 1: list.reserve(100000);
line 2: list.reserve(200000);
After line 0:
- list has size=0, capacity=0 and data=nullptr
After line 1:
- list has size=0, capacity=1e+5 and data != nullptr
After line 2:
- list has size=0, capacity=2e+5 and data != nullptr
---
The internal resizing associated with line 1 corresponds to what the
List resize would naturally do. Namely allocate new storage, copy/move
any overlapping elements (in this case none) before freeing the old
storage and replacing with new storage.
Applying the same resizing logic for line 2 means, however, that the
old memory (1e5) and new memory (2e5) are temporarily both
accessible - leading to an unnecessary memory peak.
Now: if there is no overlap, just remove old memory first.
- 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.
- use persistent PstreamBuffers between iterations, restrict size
information exchange to the processor neighbours (which is what the
algorithm is handling there anyhow).
- attempted reduction in bookkeeping (commit: 068ab8ccc7) meant that
the worldComm didn't have a group from which sub-communicators could
be spun off.
- do not force reset of PstreamBuffers positions
STYLE: UPstream::globalComm instead of '0'
- functionality provided as 'found(key)' in OpenFOAM naming, since
there was no stl equivalent at the time. Now support contains(),
which is the equivalent for C++20 maps/sets.
STYLE: general contains() method for containers
STYLE: treat Enum and Switch similarly as hash-like objects
- 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.
- make nProcs() independent of internal storage mechanism.
- reset receive positions with finished sends
- use size of received buffers to manage validity instead of
an separate additional gather operation.
- clearing the receive 'slots' is preferrable to clearing out the map
itself since this can potentially preserve allocated space (eg
DynamicList entries) between calls.
BUG: remove stray MPI barrier in exchange code
- 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
- allows the possibility of using demand-driven internal buffers
and/or different storage mechanisms.
Changes:
* old: sendBuf_[proci] -> accessSendBuffer(proci)
* old: recvBuf_[proci] -> accessRecvBuffer(proci)
* old: recvBufPos_[proci] -> accessRecvPosition(proci)
only affects internals of UIPstreamBase and UOPstreamBase
BUG: reduceOr in PstreamBuffers uses world communicator
- should respect the value of the communicator defined within
PstreamBuffers
- 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();
transformation support in-place modifies the data (e.g. to
add a transform). This might cause the neighbour side patch
to pick up owner side information.
- wish to deprecate and remove exprFixedValue in the future since the
same functionality is possible using patch expressions with a
uniformFixedValue condition.
- 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.
- This simplifies definition of 'lazier' (READ_IF_PRESENT)
construction or assignment.
For construction:
- For MUST_READ and key not found: FatalIOError.
- For LAZY_READ and key not found: initialise field with Zero.
- For NO_READ and key not found: simply size the field.
For assignment:
- If len == 0 : a no-op and return True.
- For NO_READ : a no-op and return False.
- For MUST_READ and key not found : FatalIOError
- encompasses isReadOptional or isReadRequired check
STYLE: allow LAZY_READ as a shorter synonym for READ_IF_PRESENT
- add helper for downgrading MUST_READ... to LAZY_READ
- with geometryOrder=1, edge normal calculation is done directly from
the faces, whereas geometryOrder=2 they are calculated based on the
point normals of each end.
In both cases, the geometry calculation uses processor communication
(with corresponding waitRequests etc).
Since the final correction and the halo face normals also need
collective communication, these routines must be triggered on all
processors or they will block. Thus also include edgeAreaNormals()
triggering in addition to pointAreaNormals() triggering.
- handle lower geometryOrder values directly within edgeAreaNormals()
and reuse the results within Le().
- direct nonBlocking recv/send of edge normals instead using the
intermediate processorLduInterface buffers
- 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)
- avoids implicit promotion of label to scalar for no-op,
or alternatively promotion of symmTensor to tensor for no-op
(ie, ambiguous).
- fix incorrect transform(.., symmTensor, ...) declarations.
STYLE: rename some internal buffers with the data types
low-level : byteSendBuf_, byteRecvBuf_
field level: sendBuf_, recvBuf_
solve level: scalarSendBuf_, scalarRecvBuf_
- with alternative faceCell addressing, use the three-parameter
version only. This avoids potential future ambiguity with the
two-parameter version (eg, with a label type)
ENH: add faPatchField patchInternalField() for symmetry with fvPatchField
ENH: direct reference to mesh thisDb instead of inferring
ENH: pointMesh::boundaryMesh() method (eg, similar to fvMesh)
- 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.
- reduces clutter. In some cases the Fwd typedefs were also incorrect
STYLE: combine Scalar specialisations into corresponding PatchFields.C
- reduces clutter, simplifies future adjustments
- simplifies code, consistent with other matrix transfer functions.
Use a setter method.
STYLE: AMIInterpolation::upToDate(bool) setter method
ENH: add guards to avoid float-compressed transfer of integral types
STYLE: drop unused debug member from abstract interface classes
- now simply a no-op for out-of-range values (instead of an error),
which simplifies the calling code.
Previously
==========
if (request_ >= 0 && request_ < UPstream::nRequests())
{
UPstream::waitRequest(request_);
}
Updated
=======
UPstream::waitRequest(request_);
- when 'recycling' freed request indices, ensure they are actually
within the currently addressable range
- MPI finalization now checks outstanding requests against
MPI_REQUEST_NULL to verify that they have been waited or tested on.
Previously simply checked against freed request indices
ENH: consistent initialisation of send/receive bookkeeping
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.