- can be useful for various orientation-related geometry or mesh
manipulations during pre-/post-processing:
* combine with linearDirection to achieve better extrusion results.
* orientation of transformations, blockMesh, result projections, ...
STYLE: minor code modernizations
Co-authored-by: Mark Olesen <>
- exprValueFieldTag is an extended version of exprValue,
with additional Field/List uniformity handling
- the exprValueFieldTag reduce() method provides a more efficient
method than using a regular combine operator. Since fields are
usually non-uniform, will mostly only need the bitwise reduce and
not a more expensive gather/combine.
ENH: output of exprValue (scalar type) now includes '.'
- prevents scalar/label ambiguity for values like '100.0', which would
otherwise be written as '100' and thus interpreted as a label value
when re-reading.
Based on the reference
Tomiyama, A., Kataoka, I., Zun, I., Sakaguchi, T. (1998)
Drag coefficients of single bubbles under normal and micro gravity
conditions
JSME International Journal, 41(2), 472-479.
Example usage
subModels
{
particleForces
{
tomiyamaDrag
{
sigma 0.07;
contamination pure; // pure | slight | full
}
}
}
Determines radiation heat flux between patches when using the viewFactor
radiation model.
Example usage
viewFactorHeatFlux1
{
// Mandatory entries (unmodifiable)
type viewFactorHeatFlux;
libs (utilityFunctionObjects);
// Optional entries (runtime modifiable)
qr qr;
}
STYLE: polyPatch cached areaFraction as std::unique_ptr
- more consistent with other demand-driven data.
Getter now returns tmp field instead of const reference.
- the ensightReadFile init() now automatically sets up binary/ascii
(for geometry files) and checks for the transient "BEGIN TIME STEP"
marker. If found, will also populate the file offsets for each of
the timesteps. If no corresponding footer is found (which would be
very inefficient), it simply pretends that there is only a single
time step instead of performing a costly file scan.
- parsing of the ensight case file now also supports the use of
filename numbers:
as an alternative to
filename start number:
filename increment:
- improved parsing robustness of "time values:" entry.
Can now also have contents on the same line as the introducer.
ENH: base-level adjustments for writing transient single-file
- beginGeometry() is now separated out from file creation.
- in append mode, ensightFile and ensightGeoFile will attempt to
parse existing time-step information.
- previous support for file appending (largely unused) always
specified opening with the std::ios_base::app flag.
Now differentiate between append behaviours:
APPEND_APP
~~~~~~~~~~
Corresponds to std::ios_base::app behaviour:
- Existing files will be preserved and a seek-to-end is performed at
every write. With this mode seeks/repositioning within the file
will effectively be ignored on output.
APPEND_ATE
~~~~~~~~~~
Largely approximates std::ios_base::ate behaviour:
- Existing files will be preserved and a seek-to-end is performed
immediately after opening, but not subsequently. Can use seekp()
to overwrite parts of a file.
- evaluate()
the communication type is exposed as a parameter to allow for more
tuning, but default parameter remains defaultCommsType so there is
no change in behaviour for existing code
- evaluate_if()
supports a general selection predicate
- evaluateSelected()
now does initEvaluate() for all patches, waits and then calls
evaluate(). This avoids potential deadlocks when multiple patches
are inter-communicating.
ENH: align DimensionedField reading with GeometricField treatment
- use localIOdictionary to obtain the dictionary contents
ENH: update GeometricField code
- change GeometricField writeData() as primary output method
(not operator<<) for better clarity of purpose
- use unique_ptr for GeometricField demand-driven data
- boundary entries with writeEntry(const word&, ...) instead of
writeEntry(const keyType&, ...) to match with most other
writeEntry() signatures. Also, this content will not be used
to supply regex matched sub-dictionaries.
STYLE: more consistent patch initEvaluate()/evaluate() coding
- delay construction of message buffer
- OStringStream count() method to test if anything has been streamed
STYLE: explicit use of std::ios_base in IOstreams
- document the return information of set flag methods
- can be used with this type of code:
ITstream* streamPtr = dict.findStream(name);
if (streamPtr)
{
auto& is = *streamPtr;
...
}
versus:
const entry* eptr = dict.findEntry(name);
if (eptr && eptr->isStream())
{
auto& is = eptr->stream();
...
}
ENH: add findStream(), streamPtr(), isStream() to dictionary search
- symmetric with findDict(), dictPtr(), isDict() methods
STYLE: use findDict() instead of found() + subDict() pairing
COMP: define is_globalIOobject trait at top of IOobject header
- more visibility, permits reuse for specializations etc.
BUG: streamFunction used uninitialized values for symmetry patches
- related to 8a8b5db977 changes (#3144)
ENH: improve robustness of surface field flattening
- vtk::surfaceFieldWriter
- the maxCommsSize variable is used to 'chunk' large data transfers
(eg, with PstreamBuffers) into a multi-pass send/recv sequence.
The send/recv windows for chunk-wise transfers:
iter data window
---- -----------
0 [0, 1*chunk]
1 [1*chunk, 2*chunk]
2 [2*chunk, 3*chunk]
...
Since we mostly send/recv in bytes, the current internal limit
for MPI counts (INT_MAX) can be hit rather quickly.
The chunking limit should thus also be INT_MAX, but since it is
rather tedious to specify such large numbers, can instead use
maxCommsSize = -1
to specify (INT_MAX-1) as the limit.
The default value of maxCommsSize = 0 (ie, no chunking).
Note
~~~~
In previous versions, the number of chunks was determined by the
sender sizes. This required an additional MPI_Allreduce to establish
an overall consistent number of chunks to walk. This additional
overhead each time meant that maxCommsSize was rarely actually
enabled.
We can, however, instead rely on the send/recv buffers having been
consistently sized and simply walk through the local send/recvs until
no further chunks need to be exchanged. As an additional enhancement,
the message tags are connected to chunking iteration, which allows
the setup of all send/recvs without an intermediate Allwait.
ENH: extend UPstream::probeMessage to use int64 instead of int for sizes
- the timeSelector is often used to select single or multiple times
(eg, for post-processing). However, there are a few applications
where only a *single* time should be selected and set.
These are now covered by this type of use:
timeSelector::addOptions_singleTime(); // Single-time options
...
// Allow override of time from specified time options, or no-op
timeSelector::setTimeIfPresent(runTime, args);
In some cases, if can be desirable to force starting from the
initial Time=0 when no time options have been specified:
// Set time from specified time options, or force start from Time=0
timeSelector::setTimeIfPresent(runTime, args, true);
These changes make a number of includes redundant:
* addTimeOptions.H
* checkConstantOption.H
* checkTimeOption.H
* checkTimeOptions.H
* checkTimeOptionsNoConstant.H
ENH: add time handling to setFields, setAlphaField (#3143)
Co-authored-by: Johan Roenby <>
STYLE: replace instant("constant") with instant(0, "constant")
- avoids relying on atof parse behaviour returning zero
- for example,
string buffer = ...;
SubStrings<string> split;
{
auto colon = buffer.find(':');
if (colon != std::string::npos)
{
split = stringOps::splitSpace(buffer, colon+1);
}
}
Not really possible with a substr() since that would create a new
temporary which then disappears. Similarly awkward to split and
then scan for the ':' to decide how many to discard.
ENH: add pop_front() and pop_back() methods to SubStrings
- the content is trivial enough (a pair of iterators) and the total
number of elements is usually reasonable short so that removal of
elements is inexpensive
For example,
string buffer = ...;
auto split = stringOps::splitSpace(buffer);
if (!split.empty() && split[0].str() == "face")
{
split.pop_front();
}
- ensures more accurate values for message sizes than using
MPI Get_count(), which trucates at INT_MAX
- add more/better error messages when trying to receive messages
that exceed INT_MAX or the char buffer lengths
- "buffered" corresponds to MPI_Bsend (buffered send),
whereas the old name "blocking" is misleading since the
regular MPI_Send also blocks until completion
(ie, buffer can be reused).
ENH: IPstream::read() returns std::streamsize instead of label (#3152)
- previously returned a 'label' but std::streamsize is consistent with
the input parameter and will help with later adjustments.
- use <label> instead of <int> for internal accounting of the message
size, for consistency with the underyling List<char> buffers used.
- improve handling for corner case of IPstream receive with
non-blocking, although this combination is not used anywhere
- robuster and more reliable determination of inserted objects
(previous code could produce false positives).
Now also determine the number of inserted objects within the
constructor (instead of simply storing a bool). This allows reuse
in the address calculations to reduce overheads there.
BUG: dodgy short-circuit logic for insertedObjectLabels()
- as a quick short-circuit it previously created as demand-driven
pointer with a zero elements. However, this meant that if this code
was called first (before any other addressing), subsequent calls to
the addressing would fail.
BUG: bad logic and lookup for faAreaMapper (#3147)
- was using labelHashSet but returning a bool and set using the
addressing using the unfiltered objects!
This is a latent bug since interpolated/inserted faces not
currently supported anyhow.
ENH: use std::unique_ptr for demand-driven data
- manual revert for 44d0fbd594.
Unless required for post-processing the "value" entry should not
written if it is not mandatory for reading.
This is especially crucial with an 'empty' patch field where the
field (size 0) has a different size from the patch.
- the changes made align fvsPatchField behaviour with fvPatchField
- return autoPtr<token::compound> instead of the derived type,
otherwise cannot easily construct a token from it
ENH: additional typed version of refCompoundToken()
- symmetric with typed version of transferCompoundToken()
and isCompound()
- add ITstream::findCompound<Type>() method.
Useful for searching within token streams
- previously automatically skipped the first communicator (which was
assumed to be MPI_COMM_WORLD), but now simply rely on the
internal pendingMPIFree_ to track which communicators have actually
been allocated.
- UPstream::Communicator is similar to UPstream::Request to
wrap/unwrap MPI_Comm. Provides a 'lookup' method to transcribe
the internal OpenFOAM communicator tracking to the opaque wrapped
version.
- provide an 'openfoam_mpi.H' interfacing file, which includes
the <mpi.h> as well as casting routines.
Example (caution: ugly!)
MPI_Comm myComm =
PstreamUtils::Cast::to_mpi
(
UPstream::Communicator::lookup(UPstream::worldComm)
);
- replace point-to-point transmission of the argList args/options with
a broadcast. This is sufficient for most cases (without distributed
roots).
For "normal" cases (non-distributed roots) this will replace the
nProcs-1 messages with a single broadcast.
- for cases with distributed roots, distinguish between a single,
identical root and different roots. An identical root can also be
subsequently handled with a broadcast. Different roots will still
require individual point-to-point communication.
For cases with distributed roots, it will add the overhead of an
additional broadcast.
- adds consistency with regular point-to-point parallel streams.
ENH: add ITstream::tokens() methods
- useful, for example, to disambiguate constructing tokenList from
a ITstream.
ITstream& is = otherDict.lookup("original");
tokenList deepCopy(is); // Error: from Istream or tokenList??
tokenList deepCopy(is.tokens()); // OK: from tokenList
- The internal storage location of finite-area changes from being
piggybacked on the polyMesh registry to a having its own dedicated
registry:
* allows a clearer separation of field types without name clashes.
* prerequisite for supporting multiple finite-area regions (future)
Old Locations:
```
0/Us
constant/faMesh
system/faMeshDefinition
system/faSchemes
system/faSolution
```
New Locations:
```
0/finite-area/Us
constant/finite-area/faMesh
system/finite-area/faMeshDefinition (or system/faMeshDefinition)
system/finite-area/faSchemes
system/finite-area/faSolution
```
NOTES:
The new locations represent a hard change (breaking change) that
is normally to be avoided, but seamless compatibility handling
within the code was found to be unworkable.
The `foamUpgradeFiniteArea` script provides assistance with migration.
As a convenience, the system/faMeshDefinition location continues
to be supported (may be deprecated in the future).
- Delete() will perform a 'checkOut()' which does the following:
* remove the object from the registry
* delete the pointer (if owned by the registry)
- Release() does the following:
* transfer ownership of the pointer (if owned by the registry)
- Store() does the following:
* transfer ownership of the pointer to the registry
ENH: use UPtrList of sorted objects for MeshObject updates
- few allocations and lower overhead than using a HashTable,
ensures the same walk order over the objects (in parallel)
STYLE: adjust meshObject debug statements
STYLE: update code style for phi modification (engine motion)
ENH: pass isMeshUpdate param in fvMesh/polyMesh clearOut() methods
- top-level use of isMeshUpdate parameter to clearOut and
clearAddressing was being inadvertently filtered out
- after the modification of d578d48a4f, the parent was now actually
searched. However, should be returning "constant" and not trigger a
FatalError if the file/directory is not found.
- findStrings, findMatchingStrings now mostly covered by matching
intrinsics in wordRe and wordRes.
Add static wordRes match() and matching() variants
COMP: remove stringListOps include from objectRegistry.H
- was already noted for removal (NOV-2018)
- NewIFstream would read complete remote file to decide if
was collated.
- This limits files to 31bit size
- Instead now have master-only opening of file.
- Still has problem with refinement history/cellLevel etc.
- previously would always return "constant" as the instance for
an optional dir/file that wasn't found.
However, this meant retesting to screen out false positives.
Now support an additional parameter
'bool constant_fallback = ...'
to return "constant" or an empty word.
The method signature changes slightly with a new optional bool
parameter:
//! Return \c "constant" instead of \c "" if the search failed
const bool constant_fallback = true
ENH: code consolidation for findInstancePath
- relocate from Time to TimePaths and provide an additional static
version that is reused in fileOperations
BUG: distributedTriSurfaceMesh:::findLocalInstance broken (#3135)
- was not checking the parent at all.
COMP: remove unused findInstancePath(const fileName&, ..) method
- leave 'readContents' method name for exposed (public) methods.
Generally not a problem, but can confuse the compiler when various
public/private versions are available with the same number of
parameters.
STYLE: adjust meshObject debug statements
- the type/name for field caching were saved as word, but ensight has
things like "tensor symm" etc, which do not parse very well as
'word'. Now save as 'string' type.
Backwards compatibility is OK since a word token will also be
readable as string etc.
- makes string reading consistent with fileName reading.
Related to #3133 to also allow compatibility when reading existing
dictionaries written with unquoted string contents.
- used defunct "processors/" directory naming, and includes are now
addressed by the file-handler anyhow.
ENH: support 'tutorials/Alltest -init'
- for copying/creating test directory without running
- in renumberMesh replace calculation of a subMesh connectivity
with calculation of the full mesh connectivity followed by subsetting
of the full adjacency matrix. This should reduce the overall number of
operations. (MR !669)
- added solidBodyMotionFunctions to topoSet which allows things like
moving cellSet selection for fvOptions etc.
COMP: relocate solidBodyMotionFunctions to meshTools
Co-authored-by: Kutalmis Bercin <>
- provide no_topology() characteristic to avoid triggering potentially
expensive mesh connectivity calculations when they are not required.
- remove/deprecate unused pointField references from the renumber
methods. These appear to have crept in from outer similarities
with decompositionMethod, but have no meaning for renumbering.
- remove/deprecate various unused aggregation renumberings since these
have been previously replaced by pre-calling calcCellCells, or
using bandCompression directly.
- make regionFaceOrder for block-wise renumbering optional and
treat as experimental (ie, default is now disabled).
The original idea was to sort the intra-region and inter-region faces
separately. However, this will mostly lead to non-upper triangular
ordering between regions, which checkMesh and others don't really like.
ENH: add timing information for various renumberMesh stages
ENH: add reset of clockTime and cpuTime increment
- simplifies section-wise timings
ENH: add globalIndex::null() and fieldTypes::processorType conveniences
- provides more central management of these characteristics
- particularly useful in these combinations:
1.
OCharStream buf;
// populate
ISpanStream is(buf.view());
// parse
2.
// read from file
ifile.getLine(str);
ISpanStream is(str);
// parse
These avoid making a copy of the character content, compared to
versions with stringstream:
OStringStream buf;
IStringStream is(buf.str());
- a few places still used listCombineReduce instead of
newer constructs (eg allGatherList) with fewer MPI calls.
- align triangulation handling of turbulentDFSEMInlet and
patchInjectionBase with meshTools/triangulatedPatch
(will ease future code refactoring)
- renumberMesh now has -dry-run, -write-maps, -no-fields,
-renumber-method, -renumber-coeffs options.
* Use -dry-run with -write-maps to visualize the before/after
effects of renumbering (creates a VTK file).
* -no-fields to renumber the mesh only.
This is useful and faster when the input fields are uniform
and the -overwrite option is specified.
* -renumber-method allows a quick means of specifying a different
default renumber method (instead of Cuthill-McKee).
The -renumber-coeffs option allows passing of dictionary content
for the method.
Examples,
// Different ways to specify reverse Cuthill-McKee
* -renumber-method RCM
* -renumber-coeffs 'reverse true;'
* -renumber-method CuthillMcKee
* -renumber-coeffs 'reverse true;'
* -renumber-coeffs 'method CuthillMcKee; reverse true;'
// Other (without dictionary coefficients)
* renumberMesh -renumber-method random
// Other (with dictionary coefficients)
renumberMesh \
-renumber-method spring \
-renumber-coeffs 'maxCo 0.1; maxIter 1000; freezeFraction 0.99;'
// Other (with additional libraries)
renumberMesh -renumber-method zoltan -lib zoltanRenumber
COMP: build zoltan renumbering to MPI-specific location
- zoltan and Sloan renumbering are now longer automatically linked to
the renumberMesh utility but must be separately loaded by a
command-line option or through a dictionary "libs" entry.
ENH: add output cellID for decomposePar -dry-run -cellDist
ENH: eliminate unnecessary duplicate communicator
- in globalMeshData previously had a comm_dup hack to avoid clashes
with deltaCoeffs calculations. However, this was largely due to a
manual implementation of reduce() that used point-to-point
communication. This has since been updated to use an MPI_Allreduce
and now an MPI_Allgather, neither of which need this hack.
- this was previously a UList instead of SubList,
but SubList supports better assignment of values
ENH: add invertOneToManyCompact
- returns a CompactListList<label> instead of labelListList, which
allows for reuse as partitioning table etc and/or slightly reduced
memory overhead
- add convenience forms for common combinations
- avoid allocation for 1:1 identity agglomerations
- support subsetting forms (avoids an intermediate fvMeshSubset)
that also return the cellMap
- refactored to eliminate code duplication between weighted and
unweighted forms
- construct Map/HashTable from key/value lists.
- invertToMap() : like invert() but returns a Map<label>,
which is useful for sparse numbering
- inplaceRenumber() : taking a Map<label> for the mapper
ENH: construct/reset CStringList for list of C-strings
- surfaceWriter TryNew() factory methods for more failure tolerant
handling
- reduce communication for sampledSurfaces.
Track non-empty surfaces as bool, only updated on change
(expire/update).
- use Pstream::listScatterValues() instead of the old hand-rolled
method.
Reduces code and since it is mostly used with primitives it
will use MPI_Scatter directly (see #3087)
COMP: fix some inconsistent masterOp return types
- can use UList signature since the routines do not resize the list
or attempt to broadcast it: useful for SubList handling.
ENH: add IPstream/OPstream send/recv static methods
- related to issue #3095. Some type of geometry is required when
loading "measured" ensight data.
ENH: emit a fallback geometry-box for foamToEnsight
- eg, with "foamToEnsight -no-internal -no-boundary" and lagrangian
- process the contents of the cloud object registry, which enables
output support for calculated values such as Reynolds, Weber numbers
etc.
ENH: select any/all clouds by default instead of defaultCloud
- adds robustness
- the old Pstream::scatter routines (which were largely a misnomer)
have been superseded by various broadcast routines, but were left in
the code with #ifndef/#ifdef Foam_Pstream_scatter_nobroadcast
guards. Now noisily deprecate them, and remove the old manual tree
communication in favour of MPI broadcast and/or
serialize/de-serialize with wrapped Pstream::broadcast
- consolidate various gather methods to include the communication
structure directly. No functional change, but reduces the number of
methods.
ENH: add parallel guard to UPstream::whichCommunication() method
- returns List::null() as the schedule for non-parallel instead
of an inappropriate linear or tree schedule
ENH: Pstream::listGatherValues, Pstream::listScatterValues
- like the existing UPstream versions but supporting non-contiguous
- 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
- 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
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.