- can restrict calculation of D32 and other spray properties to a
subset of parcels. Uses a predicate selection mechanism similar to
vtkCloud etc.
ENH: code cleanup in scalar predicates
- pass by value not reference in predicates
- additional assign() method to refactor common code
- the very old 'writer' class was fully stateless and always templated
on an particular output type.
This is now replaced with a 'coordSetWriter' with similar concepts
as previously introduced for surface writers (#1206).
- writers change from being a generic state-less set of routines to
more properly conforming to the normal notion of a writer.
- Parallel data is done *outside* of the writers, since they are used
in a wide variety of contexts and the caller is currently still in
a better position for deciding how to combine parallel data.
ENH: update sampleSets to sample on per-field basis (#2347)
- sample/write a field in a single step.
- support for 'sampleOnExecute' to obtain values at execution
intervals without writing.
- support 'sets' input as a dictionary entry (as well as a list),
which is similar to the changes for sampled-surface and permits use
of changeDictionary to modify content.
- globalIndex for gather to reduce parallel communication, less code
- qualify the sampleSet results (properties) with the name of the set.
The sample results were previously without a qualifier, which meant
that only the last property value was actually saved (previous ones
overwritten).
For example,
```
sample1
{
scalar
{
average(line,T) 349.96521;
min(line,T) 349.9544281;
max(line,T) 350;
average(cells,T) 349.9854619;
min(cells,T) 349.6589286;
max(cells,T) 350.4967271;
average(line,epsilon) 0.04947733869;
min(line,epsilon) 0.04449639927;
max(line,epsilon) 0.06452856475;
}
label
{
size(line,T) 79;
size(cells,T) 1720;
size(line,epsilon) 79;
}
}
```
ENH: update particleTracks application
- use globalIndex to manage original parcel addressing and
for gathering. Simplify code by introducing a helper class,
storing intermediate fields in hash tables instead of
separate lists.
ADDITIONAL NOTES:
- the regionSizeDistribution largely retains separate writers since
the utility of placing sum/dev/count for all fields into a single file
is questionable.
- the streamline writing remains a "soft" upgrade, which means that
scalar and vector fields are still collected a priori and not
on-the-fly. This is due to how the streamline infrastructure is
currently handled (should be upgraded in the future).
- for metis-like graphs there is no guarantee that a zero-sized graph
has an offsets list with size 1 or size 0, so always use
numCells = max(0, xadj.size()-1)
this was already done in most places, but missed in the
decomposeGeneral method
STYLE: use sumOp<label>() instead of plusOp<label>()
- the internal data are contiguous so can broadcast size and internals
directly without an intermediate stream.
ENH: split out broadcast time for profilingPstream information
STYLE: minor Pstream cleanup
- UPstream::commsType_ from protected to private, since it already has
inlined noexcept getters/setters that should be used.
- don't pass unused/unneed tag into low-level MPI reduction templates.
Document where tags are not needed
- had Pstream::broadcast instead of UPstream::broadcast in internals
- PstreamBuffers nProcs() and allProcs() methods to recover the rank
information consistent with the communicator used for construction
- allowClearRecv() methods for more control over buffer reuse
For example,
pBufs.allowClearRecv(false);
forAll(particles, particlei)
{
pBufs.clear();
fill...
read via IPstream(..., pBufs);
}
This preserves the receive buffers memory allocation between calls.
- finishedNeighbourSends() method as compact wrapper for
finishedSends() when send/recv ranks are identically
(eg, neighbours)
- hasSendData()/hasRecvData() methods for PstreamBuffers.
Can be useful for some situations to skip reading entirely.
For example,
pBufs.finishedNeighbourSends(neighProcs);
if (!returnReduce(pBufs.hasRecvData(), orOp<bool>()))
{
// Nothing to do
continue;
}
...
On an individual basis:
for (const int proci : pBufs.allProcs())
{
if (pBufs.hasRecvData(proci))
{
...
}
}
Also conceivable to do the following instead (nonBlocking only):
if (!returnReduce(pBufs.hasSendData(), orOp<bool>()))
{
// Nothing to do
pBufs.clear();
continue;
}
pBufs.finishedNeighbourSends(neighProcs);
...
The runTimeControl function object can activate further function objects using
triggers. Previously the trigger index could only advance; this change set
allows users to set smaller values to enable function object recycling, e.g.
Repeat for N cycles:
1. average the pressure at a point in space
2. when the average stabilises, run for a further 100 iterations
3. set a new patch inlet velocity
- back to (1)
- Removes old default behaviour that only permitted an increase in the
trigger level. This type of 'ratcheting' mechanism (if required) is
now the responsibility of the derived function object.
- as a side-effect of changes to probes, the file pointers are not
automatically creating when reading the dictionary but delayed
until prepare(WRITE_ACTION) is called.
This nuance was missed in thermoCoupleProbes.
- added in special handling for monitoring controlDict.
Since controlDict is an unwatchedIOdictionary (not IOdictionary) and
not registered either, the usual objectRegistry caching is not
available. Instead, access directly from Time.
Left the balance of the file handling largely intact (for handling
unregistered dictionaries) but could potentially revisit in the
future and attempt master-only file access if required. However,
most other IOdictionary types will be registered, otherwise the
READ_IF_MODIFIED mechanism would not really work properly.
- set() was silently deprecated in favour of reset() FEB-2018
since the original additional check for overwriting an existing
pointer was never used. The reset(...) name is more consistent
with unique_ptr, tmp etc.
Now emit deprecations for set().
- use direct test for autoPtr, tmp instead of valid() method.
More consistent with unique_ptr etc.
STYLE: eliminate redundant ptr() use on cloned quantities
Calculates propeller performance and wake field properties.
Controlled by executeControl:
- Propeller performance
- Thrust coefficient, Kt
- Torque coefficient, 10*Kq
- Advance coefficient, J
- Open water efficiency, etaO
- Written to postProcessing/<name>/<time>/propellerPerformance.dat
Controlled by writeControl:
- Wake field text file
- Wake: 1 - UzMean/URef
- Velocity in cylindrical coordinates at xyz locations
- Written to postProcessing/<name>/<time>/wake.dat
- Axial wake field text file
- 1 - Uz/URef at r/R and angle
- Written to postProcessing/<name>/<time>/axialWake.dat
- Velocity surface
- Written to postProcessing/<name>/surfaces/time>/disk.<fileType>
Usage
Example of function object specification:
\verbatim
propellerInfo1
{
type propellerInfo;
libs (forces);
writeControl writeTime;
patches ("propeller.*");
URef 5; // Function1 type; 'constant' form shown here
rho rhoInf; // incompressible
rhoInf 1.2;
// Optionally write propeller performance data
writePropellerPerformance yes;
// Propeller data:
// Radius
radius 0.1;
rotationMode specified; // specified | MRF
// rotationMode = specified:
origin (0 -0.1 0);
n 25.15;
axis (0 1 0);
// Optional reference direction for angle (alpha) = 0
alphaAxis (1 0 0);
//// rotationMode = mrf
//// MRF MRFZoneName;
//// (origin, n and axis retrieved from MRF model)
// Optionally write wake text files
// Note: controlled by writeControl
writeWakeFields yes;
// Sample plane (disk) properties
// Note: controlled by writeControl
sampleDisk
{
surfaceWriter vtk;
r1 0.05;
r2 0.2;
nTheta 36;
nRadial 10;
interpolationScheme cellPoint;
errorOnPointNotFound false;
}
}
\endverbatim
Where the entries comprise:
\table
Property | Description | Required | Deflt value
type | Type name: propellerInfo | yes |
log | Write to standard output | no | no
patches | Patches included in the forces calculation | yes |
p | Pressure field name | no | p
U | Velocity field name | no | U
rho | Density field name | no | rho
URef | Reference velocity | yes |
rotationMode | Rotation mode (see below) | yes |
origin | Sample disk centre | no* |
n | Revolutions per second | no* |
axis | Propeller axis | no* |
alphaAxis | Axis that defines alpha=0 dir | no |
MRF | Name of MRF zone | no* |
originOffset | Origin offset for MRF mode | no | (0 0 0)
writePropellerPerformance| Write propeller performance text file | yes |
writeWakeFields | Write wake field text files | yes |
surfaceWriter | Sample disk surface writer | no* |
r1 | Sample disk inner radius | no | 0
r2 | Sample disk outer radius | no* |
nTheta | Divisions in theta direction | no* |
nRadial | Divisions in radial direction | no* |
interpolationScheme | Sampling interpolation scheme | no* | cell
\endtable
Note
- URef is a scalar Function1 type, i.e. supports constant, table, lookup values
- rotationMode is used to set the origin, axis and revolutions per second
- if set to 'specified' all 3 entries are required
- note: origin is the sample disk origin
- if set to 'MRF' only the MRF entry is required
- to move the sample disk away from the MRF origin, use the originOffset
- if writePropellerPerformance is set to on|true:
- propellerPerformance text file will be written
- if writeWakeFields is set to on|true:
- wake and axialWake text files will be written
- if the surfaceWriter entry is set, the sample disk surface will be written
- extents set according to the r1 and r2 entries
- discretised according to the nTheta and nRadial entries
- provides a simple means of defining/modifying fields. For example,
```
<name1>
{
type exprField;
libs (fieldFunctionObjects);
field pTotal;
expression "p + 0.5*(rho*magSqr(U))";
dimensions [ Pa ];
}
```
It is is also possible to modify an existing field.
For example, to modify the previous one.
```
<name2>
{
type exprField;
libs (fieldFunctionObjects);
field pTotal;
action modify;
// Static pressure only in these regions
fieldMask
#{
(mag(pos()) < 0.05) && (pos().y() > 0)
|| cellZone(inlet)
#};
expression "p";
}
```
To use as a simple post-process calculator, simply avoid storing the
result and only generate on write:
```
<name2>
{
store false;
executionControl none;
writeControl writeTime;
...
}
```
COMP: implicit cast scope name to C++-string in IOobject::scopedName
- handles 'const char*' and allows a check for an empty scope name
COMP: avoid potential name conflict in local function (Istream)
- reportedly some resolution issues (unconfirmed) with Fujitsu clang
Example using mean turbulence fields (mean fields should be available e.g. from
a fieldAverage function object)
proudmanAcousticPower1
{
// Mandatory entries (unmodifiable)
type proudmanAcousticPower;
libs (fieldFunctionObjects);
...
// Turbulence field names (if not retrieved from the turb model)
k kMean;
epsilon epsilonMean;
omega none; // omegaMean
}
Previously, for basic incompressible and compressible simulations,
the "force" function object has not been using the user-specified "UName"
for the "devRhoReff" computation (affecting the tangential component),
but using the "U" of the latest available step. In contrast,
the user-specified "pName" has always been being used correctly.
This has been causing issues for users when they wish to use a specific
"UMean" field in various force and forceCoeff function object computations.