Compare commits

...

24 Commits

Author SHA1 Message Date
d6cc79fe76 FIX: incorrect DynamicList resizing logic (memory pool)
- reserve() did not set the addressable size to the current capacity
  before resizing, which meant that the delete[] would not have the true
  allocated size.
  Only affected memory-pool usage, which was not yet integrated
  (#3381)

ENH: remove unused DynamicList '*_unsafe()' methods

- could result in a mismatch between allocated and addressed sizes,
  which becomes important for memory-pool usage.
2025-06-23 11:08:46 +02:00
9dee2cad3e ENH: integrate memory pool support for List allocations (#3381)
- provides an optional memory management using a memory pool.
  Currently can support Umpire (https://github.com/LLNL/Umpire)

  When available, its use can be controlled by the FOAM_MEMORY_POOL
  environment variable, or the memory_pool Optimisation switch
  (etc/controlDict).

Notes:

  Use of the memory-pool is controlled by the 'is_aligned_type()' test
  and the minimum field size, controlled by the 'use_memory_pool()' test.

  If the memory-pool is not enabled or not required according to the two
  above tests, the allocation falls back to either an aligned or unaligned
  allocation (depending on the field size).

  The thresholds for aligned, unaligned, memory-pool allocation
  are still a compile-time option. Made by direct edit of the
  corrsponding functions.
2025-06-23 11:08:38 +02:00
23adebdb86 FIX: missing specialisations for transformF[av]PatchField
- fix for 25139e492e
2025-06-18 11:07:28 +01:00
2b0e4dc97a ENH: potentialFoam: allow swirl bc. See #3211
Bypasses the constraint override. Contentious -
does field algebra or boundary constraints take
priority.
2025-06-16 17:13:31 +01:00
e803646228 Merge branch 'consistent-handling-of-filtered-names' into 'develop'
consistent handling of filtered patch/zone names. More inGroups handling for utilities etc.

See merge request Development/openfoam!748
2025-06-13 14:17:48 +01:00
be278abcc0 ENH: revise patch group selection to ensightMesh
- supports inGroup while also respecting allow/deny semantics

- support inGroup for cellZone/faceZone selection
2025-06-13 10:29:32 +02:00
93f980834b ENH: support patch group selection
- vtkWrite, foamToVTK, surfaceMeshExtract
2025-06-13 10:29:32 +02:00
e8dce32b0a ENH: consistent handling of filtered patch/zone names
- the indices(const wordRes& allow, const wordRes& deny) methods
  were not defined consistently with the wordRes::filter handling.

  wordRes::filter - allow/deny both empty:
      = no filtering (ie, accept everything)

  indices(allow,deny) - allow/deny both empty:
     = return identity list (NEW behaviour)
     = return empty list (OLD behaviour)

  Consider the old behaviour a minor bug since the limited number of
  callers had their own checks that avoided the poor behaviour.

  Example of the inconsistent behaviour:

     pbm.indices(wordRes(), wordRes({"non-existent"}))
        --> identity list (old, new behaviour)

     pbm.indices(wordRes(), wordRes())
         --> identity list (new behaviour)
         --> empty list    (old behaviour)
2025-06-13 09:15:58 +02:00
91925871d9 Merge branch 'fix-3374-questionable-const_cast' into 'develop'
avoid casting workarounds for syncTools::syncBoundaryFaceList

See merge request Development/openfoam!747
2025-06-12 12:49:26 +00:00
a5090c37a3 ENH: minor improvements to UPstream::communicator wrapper class
- robuster reset() method that handles self-assignment
- additional swap() and constCast() methods

STYLE: relocate UPstream::communicator declarations within header
2025-06-12 13:13:26 +02:00
0d7816b7fd ENH: avoid questionable const_cast of SubList (#3374) 2025-06-12 13:13:26 +02:00
9bdb75eeef ENH: add ListOps::equal() function
- tests for list equality with different but compatible data types.
  Eg, when comparing lists of int32 and int64 values.

STYLE: pass UList instead of List references into ListOps functors
2025-06-12 13:13:26 +02:00
a860d48637 ENH: make some vectorTensorTransform methods inplace
- avoids intermediate allocation and re-assignment to self (#3374)

BUG: checkMesh (application) with questionable memory handling (#3374)

- move the contents of the new points instead of attempting to transfer
  the entire list

COMP: replace mapDistribute specializations with if constexpr handling

- simplify future maintenance
2025-06-12 13:13:26 +02:00
97296043c0 ENH: snappyHexMesh: more warnings. See #3377
This one only tackles the per-region for refinementSurfaces.
Other ones tbd.
2025-06-12 10:10:16 +01:00
6bdceaf29f BUG: AMI: local communicators. Fixes #3376 2025-06-11 16:39:48 +01:00
34df4eaf40 ENH: ensightWrite: allow inGroup names in patches and excludePatches 2025-06-11 13:36:14 +01:00
75b2d0b656 BUG: masterStream forwards without communicator (fixes #3373)
- in messageStream::masterStream(int), it forwarded to stream()
  without the communicator, which meant it would incorrectly check
  UPstream::master(worldComm) and possibly not produce any output (or
  block).
2025-06-10 15:20:11 +02:00
9bc6f2f91f ENH: support 'rpm' input for propeller functionObject (as per rotorDisk)
- update code style for forces/propeller.
- simplify coordinate handling in propeller functionObject
2025-06-10 10:32:03 +02:00
96872f031f Merge branch 'feature-orientedSurface' into 'develop'
ENH: snappyHexMesh: work better on non-manifold. Fixes ##3361

See merge request Development/openfoam!740
2025-06-09 15:12:47 +00:00
55d89ac4d6 ENH: snappyHexMesh: work better on non-manifold. Fixes ##3361 2025-06-09 15:12:47 +00:00
fe0ba07a7a SUBMODULE: update OpenQBMM for v2506 2025-06-05 16:06:56 +02:00
164a3e8330 ENH: IOstream::unsetf() now returns old flags (eg, for toggling)
ENH: align MPI_Probe non-blocking handling with header description

- the header states that the commsType is non-blocking or not,
  but the implementation actually checked for 'buffered' or not.

STYLE: fix some spacing and some documentation
2025-06-05 16:06:56 +02:00
2f6581133c ENH: preserve matrix manipulation state in boundary consistency check
- add placeholder methods in faPatchField and move setter functions
  from protected to public access.
2025-06-05 15:09:25 +02:00
9e8e14e448 TUT: minor tutorial cleanup
- use functionObject writeInterval not timeInterval.
  No change in behaviour since the missing writeInterval is treated
  as '1' anyhow when using 'timeStep' for the writeControl

- consistent use of 'adjustable' vs 'adjustableRunTime'

- prefer '#eval{ vector(...) }' to calling '#eval' multiple times
2025-06-04 16:39:34 +02:00
165 changed files with 2936 additions and 1508 deletions

View File

@ -13,7 +13,14 @@ volVectorField U
); );
// Initialise the velocity internal field to zero // Initialise the velocity internal field to zero
U = dimensionedVector(U.dimensions(), Zero); // Note: explicitly bypass evaluation of contraint patch overrides
// (e.g. swirlFanVelocity might lookup phi,rho)
//U = dimensionedVector(U.dimensions(), Zero);
{
const dimensionedVector dt(U.dimensions(), Zero);
U.internalFieldRef() = dt;
U.boundaryFieldRef() = dt.value();
}
surfaceScalarField phi surfaceScalarField phi
( (

View File

@ -51,6 +51,7 @@ See also
#include "IndirectList.H" #include "IndirectList.H"
#include "SubList.H" #include "SubList.H"
#include "SliceList.H" #include "SliceList.H"
#include "SubField.H"
#include "ListPolicy.H" #include "ListPolicy.H"
#include <list> #include <list>
@ -203,16 +204,6 @@ int main(int argc, char *argv[])
Info<<" " << *iter; Info<<" " << *iter;
} }
Info<< nl; Info<< nl;
Info<< "data:" << Foam::name(ident.cdata())
<< " size:" << ident.size() << nl;
Info<< "resize_unsafe(10)" << nl;
ident.resize_unsafe(10);
Info<< "data:" << Foam::name(ident.cdata())
<< " size:" << ident.size() << nl;
} }
if (false) if (false)
@ -281,6 +272,33 @@ int main(int argc, char *argv[])
}; };
Info<< "list4: " << list4 << endl; Info<< "list4: " << list4 << endl;
{
List<scalar> list4Mag = ListOps::create<scalar>
(
list4,
[](const auto& a){ return a.mag(); }
);
const auto equalMag = [](const auto& a, const auto& b)
{
return (Foam::mag(a) == Foam::mag(b));
};
Info<< "list4 (mag): " << list4Mag << endl;
bool same = ListOps::equal(list4, list4Mag, equalMag);
Info<< "mag(list4) == list4(mag): " << same << nl;
SubField<scalar>(list4Mag) *= -1;
same = ListOps::equal(list4, list4Mag, equalMag);
Info<< "mag(list4) == list4(mag): " << same << nl;
SubField<scalar>(list4Mag) *= 1.1;
same = ListOps::equal(list4, list4Mag, equalMag);
Info<< "mag(list4) == list4(mag): " << same << nl;
}
List<vector> list5 List<vector> list5
{ {
{5, 3, 1}, {5, 3, 1},

View File

@ -1,3 +1,3 @@
Test-parallel-broadcast.C Test-parallel-broadcast.cxx
EXE = $(FOAM_USER_APPBIN)/Test-parallel-broadcast EXE = $(FOAM_USER_APPBIN)/Test-parallel-broadcast

View File

@ -1,3 +1,3 @@
Test-parallel-chunks.C Test-parallel-chunks.cxx
EXE = $(FOAM_USER_APPBIN)/Test-parallel-chunks EXE = $(FOAM_USER_APPBIN)/Test-parallel-chunks

View File

@ -1,3 +1,3 @@
Test-parallel-comm0.C Test-parallel-comm0.cxx
EXE = $(FOAM_USER_APPBIN)/Test-parallel-comm0 EXE = $(FOAM_USER_APPBIN)/Test-parallel-comm0

View File

@ -1,3 +1,3 @@
Test-parallel-comm1.C Test-parallel-comm1.cxx
EXE = $(FOAM_USER_APPBIN)/Test-parallel-comm1 EXE = $(FOAM_USER_APPBIN)/Test-parallel-comm1

View File

@ -1,3 +1,3 @@
Test-parallel-comm3a.C Test-parallel-comm3a.cxx
EXE = $(FOAM_USER_APPBIN)/Test-parallel-comm3a EXE = $(FOAM_USER_APPBIN)/Test-parallel-comm3a

View File

@ -1,3 +1,3 @@
Test-parallel-comm3b.C Test-parallel-comm3b.cxx
EXE = $(FOAM_USER_APPBIN)/Test-parallel-comm3b EXE = $(FOAM_USER_APPBIN)/Test-parallel-comm3b

View File

@ -1,3 +1,3 @@
Test-parallel-external-init.C Test-parallel-external-init.cxx
EXE = $(FOAM_USER_APPBIN)/Test-parallel-external-init EXE = $(FOAM_USER_APPBIN)/Test-parallel-external-init

View File

@ -1,3 +1,3 @@
Test-parallel-nbx2.C Test-parallel-nbx2.cxx
EXE = $(FOAM_USER_APPBIN)/Test-parallel-nbx2 EXE = $(FOAM_USER_APPBIN)/Test-parallel-nbx2

View File

@ -131,7 +131,6 @@ int main(int argc, char *argv[])
if (probed.second > 0) if (probed.second > 0)
{ {
// Message found and had size: receive it // Message found and had size: receive it
const label proci(probed.first); const label proci(probed.first);
const label count(probed.second); const label count(probed.second);
@ -164,8 +163,7 @@ int main(int argc, char *argv[])
scalarField fld(is); scalarField fld(is);
Info<< "from [" << probed.first Info<< "from [" << proci << "] : " << flatOutput(fld) << endl;
<< "] : " << flatOutput(fld) << endl;
} }
} }

View File

@ -1,3 +1,3 @@
Test-parallel-nonBlocking.C Test-parallel-nonBlocking.cxx
EXE = $(FOAM_USER_APPBIN)/Test-parallel-nonBlocking EXE = $(FOAM_USER_APPBIN)/Test-parallel-nonBlocking

View File

@ -1,3 +1,3 @@
Test-parallel-waitSome.C Test-parallel-waitSome.cxx
EXE = $(FOAM_USER_APPBIN)/Test-parallel-waitSome EXE = $(FOAM_USER_APPBIN)/Test-parallel-waitSome

View File

@ -1,7 +1,7 @@
/*--------------------------------*- C++ -*----------------------------------*\ /*--------------------------------*- C++ -*----------------------------------*\
| ========= | | | ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2412 | | \\ / O peration | Version: v2506 |
| \\ / A nd | Website: www.openfoam.com | | \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | | | \\/ M anipulation | |
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
@ -26,7 +26,7 @@ stopAt writeNow;
endTime 4; endTime 4;
writeControl adjustableRunTime; writeControl adjustable;
writeInterval 0.1; writeInterval 0.1;

View File

@ -1,7 +1,7 @@
/*--------------------------------*- C++ -*----------------------------------*\ /*--------------------------------*- C++ -*----------------------------------*\
| ========= | | | ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox | | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2412 | | \\ / O peration | Version: v2506 |
| \\ / A nd | Website: www.openfoam.com | | \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | | | \\/ M anipulation | |
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
@ -27,7 +27,7 @@ endTime 0.1;
deltaT 0.0001; deltaT 0.0001;
writeControl adjustableRunTime; writeControl adjustable;
writeInterval 0.01; writeInterval 0.01;

View File

@ -525,6 +525,7 @@ public:
} }
} }
}; };
class edgePointTransformOp class edgePointTransformOp
{ {
public: public:
@ -543,25 +544,24 @@ public:
points1[i] = fld[i].second(); points1[i] = fld[i].second();
} }
pointField points0New;
pointField points1New;
if (forward) if (forward)
{ {
points0New = vt.transformPosition(points0); vt.transformPositionList(points0);
points1New = vt.transformPosition(points1); vt.transformPositionList(points1);
} }
else else
{ {
points0New = vt.invTransformPosition(points0); vt.invTransformPositionList(points0);
points1New = vt.invTransformPosition(points1); vt.invTransformPositionList(points1);
} }
forAll(fld, i) forAll(fld, i)
{ {
fld[i] = PointPair(points0New[i], points1New[i]); fld[i] = PointPair(points0[i], points1[i]);
} }
} }
}; };
class edgePointFlipOp class edgePointFlipOp
{ {
public: public:
@ -572,6 +572,7 @@ public:
return newVal; return newVal;
} }
}; };
void testEdgeFlip2(const polyMesh& mesh, Random& rndGen) void testEdgeFlip2(const polyMesh& mesh, Random& rndGen)
{ {
Info<< nl << "Testing edge-wise (oriented) data synchronisation." << endl; Info<< nl << "Testing edge-wise (oriented) data synchronisation." << endl;
@ -759,13 +760,11 @@ class pointListOps
{ {
public: public:
void operator()(pointList& lhs, const pointList& rhs) const void operator()(UList<point>& lhs, const UList<point>& rhs) const
{ {
forAll(lhs, i) forAll(lhs, i)
{ {
point& l = lhs[i]; maxMagSqrEqOp<vector>()(lhs[i], rhs[i]);
const point& r = rhs[i];
maxMagSqrEqOp<vector>()(l, r);
} }
} }
@ -773,38 +772,31 @@ public:
( (
const vectorTensorTransform& vt, const vectorTensorTransform& vt,
const bool forward, const bool forward,
List<pointList>& fld UList<pointList>& fld
) const ) const
{ {
if (forward) if (forward)
{ {
for (auto& elems : fld) for (auto& pts : fld)
{ {
for (auto& elem : elems) vt.transformPositionList(pts);
{
elem = vt.transformPosition(elem);
}
} }
} }
else else
{ {
for (auto& elems : fld) for (auto& pts : fld)
{ {
for (auto& elem : elems) vt.invTransformPositionList(pts);
{
elem = vt.invTransformPosition(elem);
}
} }
} }
} }
//- Transform patch-based field //- Transform patch-based field
void operator()(const coupledPolyPatch& cpp, List<pointList>& fld) const void operator()(const coupledPolyPatch& cpp, UList<pointList>& fld) const
{ {
forAll(fld, facei) forAll(fld, facei)
{ {
pointList& pts = fld[facei]; for (auto& pt : fld[facei])
for (auto& pt : pts)
{ {
cpp.transformPosition(pt, facei); cpp.transformPosition(pt, facei);
} }

View File

@ -39,8 +39,7 @@ Foam::label Foam::findOppositeWedge
&& isA<wedgePolyPatch>(patches[patchi]) && isA<wedgePolyPatch>(patches[patchi])
) )
{ {
const wedgePolyPatch& pp = const auto& pp = refCast<const wedgePolyPatch>(patches[patchi]);
refCast<const wedgePolyPatch>(patches[patchi]);
// Calculate (cos of) angle to wpp (not pp!) centre normal // Calculate (cos of) angle to wpp (not pp!) centre normal
scalar ppCosAngle = wpp.centreNormal() & pp.n(); scalar ppCosAngle = wpp.centreNormal() & pp.n();
@ -80,8 +79,7 @@ bool Foam::checkWedges
{ {
if (patches[patchi].size() && isA<wedgePolyPatch>(patches[patchi])) if (patches[patchi].size() && isA<wedgePolyPatch>(patches[patchi]))
{ {
const wedgePolyPatch& pp = const auto& pp = refCast<const wedgePolyPatch>(patches[patchi]);
refCast<const wedgePolyPatch>(patches[patchi]);
scalar wedgeAngle = acos(pp.cosAngle()); scalar wedgeAngle = acos(pp.cosAngle());
@ -105,7 +103,7 @@ bool Foam::checkWedges
return true; return true;
} }
const wedgePolyPatch& opp = const auto& opp =
refCast<const wedgePolyPatch>(patches[oppositePatchi]); refCast<const wedgePolyPatch>(patches[oppositePatchi]);
@ -275,25 +273,27 @@ namespace Foam
void operator() void operator()
( (
const coupledPolyPatch& cpp, const coupledPolyPatch& cpp,
List<pointField>& pts UList<pointField>& pts
) const ) const
{ {
// Each element of pts is all the points in the face. Convert into // Each element of pts is all the points in the face.
// lists of size cpp to transform. // Convert into lists of size cpp to transform.
List<pointField> newPts(pts.size()); List<pointField> newPts(pts.size());
forAll(pts, facei) forAll(pts, facei)
{ {
newPts[facei].setSize(pts[facei].size()); newPts[facei].resize(pts[facei].size());
} }
pointField ptsAtIndex(pts.size());
label index = 0; label index = 0;
while (true) while (true)
{ {
label n = 0; label n = 0;
// Extract for every face the i'th position // Extract for every face the i'th position
pointField ptsAtIndex(pts.size(), Zero); ptsAtIndex = Zero;
forAll(cpp, facei) forAll(cpp, facei)
{ {
const pointField& facePts = pts[facei]; const pointField& facePts = pts[facei];
@ -326,7 +326,8 @@ namespace Foam
index++; index++;
} }
pts.transfer(newPts); // Transfer newPts -> pts
std::move(newPts.begin(), newPts.end(), pts.begin());
} }
}; };
} }
@ -352,10 +353,7 @@ bool Foam::checkCoupledPoints
{ {
if (patches[patchi].coupled()) if (patches[patchi].coupled())
{ {
const coupledPolyPatch& cpp = refCast<const coupledPolyPatch> const auto& cpp = refCast<const coupledPolyPatch>(patches[patchi]);
(
patches[patchi]
);
forAll(cpp, i) forAll(cpp, i)
{ {
@ -387,8 +385,7 @@ bool Foam::checkCoupledPoints
{ {
if (patches[patchi].coupled()) if (patches[patchi].coupled())
{ {
const coupledPolyPatch& cpp = const auto& cpp = refCast<const coupledPolyPatch>(patches[patchi]);
refCast<const coupledPolyPatch>(patches[patchi]);
if (cpp.owner()) if (cpp.owner())
{ {
@ -1023,7 +1020,7 @@ Foam::label Foam::checkGeometry
{ {
if (isA<cyclicAMIPolyPatch>(pbm[patchi])) if (isA<cyclicAMIPolyPatch>(pbm[patchi]))
{ {
const cyclicAMIPolyPatch& cpp = const auto& cpp =
refCast<const cyclicAMIPolyPatch>(pbm[patchi]); refCast<const cyclicAMIPolyPatch>(pbm[patchi]);
if (cpp.owner()) if (cpp.owner())
@ -1058,7 +1055,7 @@ Foam::label Foam::checkGeometry
if (isA<cyclicACMIPolyPatch>(pbm[patchi])) if (isA<cyclicACMIPolyPatch>(pbm[patchi]))
{ {
const cyclicACMIPolyPatch& pp = const auto& pp =
refCast<const cyclicACMIPolyPatch>(pbm[patchi]); refCast<const cyclicACMIPolyPatch>(pbm[patchi]);
scalarField mergedMask; scalarField mergedMask;
@ -1108,8 +1105,9 @@ Foam::label Foam::checkGeometry
if (isA<cyclicACMIPolyPatch>(pbm[patchi])) if (isA<cyclicACMIPolyPatch>(pbm[patchi]))
{ {
const cyclicACMIPolyPatch& pp = const auto& pp =
refCast<const cyclicACMIPolyPatch>(pbm[patchi]); refCast<const cyclicACMIPolyPatch>(pbm[patchi]);
scalarField mergedMask; scalarField mergedMask;
globalFaces().gather globalFaces().gather
( (

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2021-2023 OpenCFD Ltd. Copyright (C) 2021-2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM, distributed under GPL-3.0-or-later. This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
@ -44,10 +44,10 @@ forAll(meshes, regioni)
IOobjectOption::NO_REGISTER IOobjectOption::NO_REGISTER
); );
if (fieldSelector && !fieldSelector().empty()) if (fieldSelector)
{ {
objects.filterObjects(fieldSelector()); objects.filterObjects(fieldSelector);
faObjects.filterObjects(fieldSelector()); faObjects.filterObjects(fieldSelector);
} }
// Remove "*_0" restart fields // Remove "*_0" restart fields

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2016-2022 OpenCFD Ltd. Copyright (C) 2016-2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -406,34 +406,27 @@ int main(int argc, char *argv[])
// Field selection/deselection // Field selection/deselection
wordRes includedFields, excludedFields; wordRes includedFields, excludedFields;
autoPtr<wordRes::filter> fieldSelector(nullptr);
const bool doConvertFields = !args.found("no-fields"); const bool doConvertFields = !args.found("no-fields");
if (doConvertFields) if (doConvertFields)
{ {
bool resetFilter = false;
if (args.readListIfPresent<wordRe>("fields", includedFields)) if (args.readListIfPresent<wordRe>("fields", includedFields))
{ {
resetFilter = true;
Info<< "Including fields " Info<< "Including fields "
<< flatOutput(includedFields) << nl << endl; << flatOutput(includedFields) << nl << endl;
} }
if (args.readListIfPresent<wordRe>("exclude-fields", excludedFields)) if (args.readListIfPresent<wordRe>("exclude-fields", excludedFields))
{ {
resetFilter = true;
Info<< "Excluding fields " Info<< "Excluding fields "
<< flatOutput(excludedFields) << nl << endl; << flatOutput(excludedFields) << nl << endl;
} }
if (resetFilter)
{
fieldSelector =
autoPtr<wordRes::filter>::New(includedFields, excludedFields);
}
} }
else if (doConvertFields) else
{ {
Info<< "Field conversion disabled with the '-no-fields' option" << nl; Info<< "Field conversion disabled with the '-no-fields' option" << nl;
} }
const wordRes::filter fieldSelector(includedFields, excludedFields);
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
#include "createTime.H" #include "createTime.H"

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2018-2023 OpenCFD Ltd. Copyright (C) 2018-2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM, distributed under GPL-3.0-or-later. This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
@ -136,7 +136,7 @@ Description
labelList patchIds; labelList patchIds;
if (doBoundary) if (doBoundary)
{ {
patchIds = getSelectedPatches(patches, patchSelector); patchIds = patchSelector.indices(patches);
} }
if (oneBoundary && patchIds.size()) if (oneBoundary && patchIds.size())

View File

@ -166,56 +166,54 @@ Note
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
labelList getSelectedPatches namespace Foam
(
const polyBoundaryMesh& patches,
const autoPtr<wordRes::filter>& patchSelector
)
{ {
labelList indices;
if (patchSelector && !patchSelector().empty()) // Simple wrapper for polyBoundaryMesh::indices() with some additional logic
struct polyBoundaryPatchSelector
{
wordRes allow_;
wordRes deny_;
void clear()
{ {
// Name-based selection allow_.clear();
indices = deny_.clear();
(
stringListOps::findMatching
(
patches,
patchSelector(),
nameOp<polyPatch>()
)
);
}
else
{
indices = identity(patches.size());
} }
// Remove undesirable patches //- Forward to polyBoundaryMesh::indices() with additional handling.
// Prune emptyPolyPatch (always) and processorPolyPatch (in parallel)
label count = 0; labelList indices(const polyBoundaryMesh& pbm) const
for (const label patchi : indices)
{ {
const polyPatch& pp = patches[patchi]; labelList ids = pbm.indices(allow_, deny_);
if (isType<emptyPolyPatch>(pp)) const bool excludeProcPatches = UPstream::parRun();
// Prune undesirable patches
label count = 0;
for (const label patchi : ids)
{ {
continue; const auto& pp = pbm[patchi];
}
else if (UPstream::parRun() && bool(isA<processorPolyPatch>(pp))) if (isType<emptyPolyPatch>(pp))
{ {
break; // No processor patches for parallel output continue;
}
else if (excludeProcPatches && bool(isA<processorPolyPatch>(pp)))
{
break; // No processor patches for parallel output
}
ids[count] = patchi;
++count;
} }
indices[count] = patchi; ids.resize(count);
++count; return ids;
} }
};
indices.resize(count); } // End namespace Foam
return indices;
}
// //
@ -552,45 +550,38 @@ int main(int argc, char *argv[])
} }
// Patch selection/deselection // Patch selection/deselection
wordRes includedPatches, excludedPatches; polyBoundaryPatchSelector patchSelector;
autoPtr<wordRes::filter> patchSelector(nullptr);
if (doBoundary) if (doBoundary)
{ {
bool resetFilter = false; if
if (args.readListIfPresent<wordRe>("patches", includedPatches)) (
auto& slot = patchSelector.allow_;
args.readListIfPresent<wordRe>("patches", slot)
)
{ {
resetFilter = true; Info<< "Including patches " << flatOutput(slot) << nl << endl;
Info<< "Including patches "
<< flatOutput(includedPatches) << nl << endl;
} }
if (args.readListIfPresent<wordRe>("exclude-patches", excludedPatches)) if
(
auto& slot = patchSelector.deny_;
args.readListIfPresent<wordRe>("exclude-patches", slot)
)
{ {
resetFilter = true; Info<< "Excluding patches " << flatOutput(slot) << nl << endl;
Info<< "Excluding patches "
<< flatOutput(excludedPatches) << nl << endl;
}
if (resetFilter)
{
patchSelector =
autoPtr<wordRes::filter>::New(includedPatches, excludedPatches);
} }
} }
// Field selection/deselection // Field selection/deselection
wordRes includedFields, excludedFields; wordRes includedFields, excludedFields;
autoPtr<wordRes::filter> fieldSelector(nullptr);
bool doConvertFields = !args.found("no-fields"); bool doConvertFields = !args.found("no-fields");
if (doConvertFields) if (doConvertFields)
{ {
bool resetFilter = false;
if (args.readListIfPresent<wordRe>("fields", includedFields)) if (args.readListIfPresent<wordRe>("fields", includedFields))
{ {
Info<< "Including fields " Info<< "Including fields "
<< flatOutput(includedFields) << nl << endl; << flatOutput(includedFields) << nl << endl;
resetFilter = !includedFields.empty();
if (includedFields.empty()) if (includedFields.empty())
{ {
// Compat: Can be specified as empty (ie, no fields) // Compat: Can be specified as empty (ie, no fields)
@ -603,22 +594,22 @@ int main(int argc, char *argv[])
} }
if (args.readListIfPresent<wordRe>("exclude-fields", excludedFields)) if (args.readListIfPresent<wordRe>("exclude-fields", excludedFields))
{ {
resetFilter = true;
Info<< "Excluding fields " Info<< "Excluding fields "
<< flatOutput(excludedFields) << nl << endl; << flatOutput(excludedFields) << nl << endl;
} }
if (resetFilter && doConvertFields) if (!doConvertFields)
{ {
fieldSelector = includedFields.clear();
autoPtr<wordRes::filter>::New(includedFields, excludedFields); excludedFields.clear();
} }
} }
else if (doConvertFields) else
{ {
Info<< "Field conversion disabled with the '-no-fields' option" << nl; Info<< "Field conversion disabled with the '-no-fields' option" << nl;
} }
const wordRes::filter fieldSelector(includedFields, excludedFields);
// Non-mandatory // Non-mandatory
const wordRes selectedFaceZones(args.getList<wordRe>("faceZones", false)); const wordRes selectedFaceZones(args.getList<wordRe>("faceZones", false));
@ -799,10 +790,10 @@ int main(int argc, char *argv[])
IOobjectOption::NO_REGISTER IOobjectOption::NO_REGISTER
); );
if (fieldSelector && !fieldSelector().empty()) if (fieldSelector)
{ {
objects.filterObjects(fieldSelector()); objects.filterObjects(fieldSelector);
faObjects.filterObjects(fieldSelector()); faObjects.filterObjects(fieldSelector);
} }
// Remove "*_0" restart fields // Remove "*_0" restart fields

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017-2024 OpenCFD Ltd. Copyright (C) 2017-2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -155,50 +155,39 @@ void writeOBJ
} }
} }
// Simple wrapper for polyBoundaryMesh::indices() with some additional logic
// - prune emptyPolyPatch (always) and (maybe) processorPolyPatch
labelList getSelectedPatches labelList getSelectedPatches
( (
const polyBoundaryMesh& patches, const polyBoundaryMesh& pbm,
const wordRes& allow, const wordRes& allow,
const wordRes& deny const wordRes& deny,
const bool excludeProcPatches
) )
{ {
// Name-based selection labelList ids = pbm.indices(allow, deny);
labelList indices
(
stringListOps::findMatching
(
patches,
allow,
deny,
nameOp<polyPatch>()
)
);
// Remove undesirable patches // Remove undesirable patches
label count = 0; label count = 0;
for (const label patchi : indices) for (const label patchi : ids)
{ {
const polyPatch& pp = patches[patchi]; const polyPatch& pp = pbm[patchi];
if (isType<emptyPolyPatch>(pp)) if (isType<emptyPolyPatch>(pp))
{ {
continue; continue;
} }
else if (Pstream::parRun() && bool(isA<processorPolyPatch>(pp))) else if (excludeProcPatches && bool(isA<processorPolyPatch>(pp)))
{ {
break; // No processor patches for parallel output break; // No processor patches for parallel output
} }
indices[count] = patchi; ids[count] = patchi;
++count; ++count;
} }
indices.resize(count); ids.resize(count);
return ids;
return indices;
} }
@ -668,11 +657,14 @@ int main(int argc, char *argv[])
const labelList patchIds = const labelList patchIds =
( (
(includePatches.size() || excludePatches.size()) getSelectedPatches
? getSelectedPatches(bMesh, includePatches, excludePatches) (
: includeProcPatches bMesh,
? identity(bMesh.size()) includePatches,
: identity(bMesh.nNonProcessor()) excludePatches,
// No processor patches? (parallel output or excluded)
(UPstream::parRun() || !includeProcPatches)
)
); );
labelList faceZoneIds; labelList faceZoneIds;

View File

@ -132,6 +132,11 @@ projectDir="$HOME/OpenFOAM/OpenFOAM-$WM_PROJECT_VERSION"
# projectDir="@PROJECT_DIR@" # projectDir="@PROJECT_DIR@"
: # Safety statement (if the user removed all fallback values) : # Safety statement (if the user removed all fallback values)
# [FOAM_MEMORY_POOL] - Optional memory management
# - overrides the 'memory_pool' etc/controlDict entry
# = "true | false | host [size=nn] [incr=nn]"
#export FOAM_MEMORY_POOL="host"
# [FOAM_SIGFPE] - Trap floating-point exceptions. # [FOAM_SIGFPE] - Trap floating-point exceptions.
# - overrides the 'trapFpe' controlDict entry # - overrides the 'trapFpe' controlDict entry
# = true | false # = true | false

View File

@ -221,6 +221,9 @@ OptimisationSwitches
// Other // Other
// ===== // =====
// Optional memory management (sizing in MB)
// memory_pool "host; size=1024; incr=5"
// Trap floating point exception. // Trap floating point exception.
// Can override with FOAM_SIGFPE env variable (true|false) // Can override with FOAM_SIGFPE env variable (true|false)
trapFpe 1; trapFpe 1;

View File

@ -134,6 +134,11 @@ set projectDir=`lsof +p $$ |& sed -ne 's#^[^/]*##;\@/'"$projectName"'[^/]*/etc/c
# Or optionally hard-coded (eg, with autoconfig) # Or optionally hard-coded (eg, with autoconfig)
# set projectDir="@PROJECT_DIR@" # set projectDir="@PROJECT_DIR@"
# [FOAM_MEMORY_POOL] - Optional memory management
# - overrides the 'memory_pool' etc/controlDict entry
# = "true | false | host [size=nn] [incr=nn]"
#setenv FOAM_MEMORY_POOL "host"
# [FOAM_SIGFPE] - Trap floating-point exceptions. # [FOAM_SIGFPE] - Trap floating-point exceptions.
# - overrides the 'trapFpe' controlDict entry # - overrides the 'trapFpe' controlDict entry
# = true | false # = true | false

View File

@ -3,6 +3,8 @@ MSwindows.C
cpuInfo/cpuInfo.C cpuInfo/cpuInfo.C
memInfo/memInfo.C memInfo/memInfo.C
memory/MemoryPool.cxx
signals/sigFpe.cxx signals/sigFpe.cxx
signals/sigInt.cxx signals/sigInt.cxx
signals/sigQuit.cxx signals/sigQuit.cxx

View File

@ -0,0 +1,83 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "MemoryPool.H"
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
// bool Foam::MemoryPool::create(const std::string& ctrl, bool verbose)
// {
// return false;
// }
bool Foam::MemoryPool::create(bool verbose)
{
// No banner information since it is currently never an option
return false;
}
void Foam::MemoryPool::destroy(bool verbose)
{}
bool Foam::MemoryPool::active() noexcept
{
return false;
}
bool Foam::MemoryPool::suspend() noexcept
{
return false;
}
void Foam::MemoryPool::resume() noexcept
{}
bool Foam::MemoryPool::is_pool(void* ptr)
{
return false;
}
void* Foam::MemoryPool::try_allocate(std::size_t nbytes)
{
return nullptr;
}
bool Foam::MemoryPool::try_deallocate(void* ptr)
{
return (!ptr);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -2,6 +2,7 @@
cd "${0%/*}" || exit # Run from this directory cd "${0%/*}" || exit # Run from this directory
targetType=libo # Preferred library type targetType=libo # Preferred library type
. ${WM_PROJECT_DIR:?}/wmake/scripts/AllwmakeParseArguments $* . ${WM_PROJECT_DIR:?}/wmake/scripts/AllwmakeParseArguments $*
. ${WM_PROJECT_DIR:?}/wmake/scripts/have_umpire
#------------------------------------------------------------------------------ #------------------------------------------------------------------------------
# Hack for MacOS (with Gcc). # Hack for MacOS (with Gcc).
@ -59,6 +60,47 @@ then
export COMP_FLAGS="-DFOAM_USE_INOTIFY" export COMP_FLAGS="-DFOAM_USE_INOTIFY"
fi fi
#------------------------------------------------------------------------------
# Have -lumpire, but also -lcamp etc.
# Also need to follow the link order
get_umpire_libs()
{
if [ -d "${UMPIRE_LIB_DIR}" ]
then
set -- $(
# Expected link order
for name in umpire fmt camp
do
[ -f "$UMPIRE_LIB_DIR/lib${name}.a" ] && echo "-l$name"
done
)
echo "$@"
else
echo
fi
}
if have_umpire
then
libNames="$(get_umpire_libs)"
if [ -n "$libNames" ]
then
echo " found umpire -- enabling memory pool interface" 1>&2
echo " umpire libs: $libNames" 1>&2
COMP_FLAGS="$COMP_FLAGS -DFOAM_USE_UMPIRE -I${UMPIRE_INC_DIR}"
LINK_FLAGS="$LINK_FLAGS -L${UMPIRE_LIB_DIR} $libNames"
export COMP_FLAGS LINK_FLAGS
else
echo " expecting umpire, but did not resolve the libraries" 1>&2
fi
fi
#------------------------------------------------------------------------------
# Make object (non-shared by default) # Make object (non-shared by default)
# Never want/need openmp, especially for static objects # Never want/need openmp, especially for static objects
wmake -no-openmp $targetType wmake -no-openmp $targetType

View File

@ -4,6 +4,8 @@ cpuInfo/cpuInfo.C
cpuTime/cpuTimePosix.C cpuTime/cpuTimePosix.C
memInfo/memInfo.C memInfo/memInfo.C
memory/MemoryPool.cxx
signals/sigFpe.cxx signals/sigFpe.cxx
signals/sigSegv.cxx signals/sigSegv.cxx
signals/sigInt.cxx signals/sigInt.cxx

View File

@ -1 +1,4 @@
EXE_INC = $(COMP_FLAGS) /* umpire uses old-style cast etc */
EXE_INC = $(COMP_FLAGS) $(c++LESSWARN)
LIBO_LIBS = $(LINK_FLAGS)

View File

@ -0,0 +1,510 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
\*---------------------------------------------------------------------------*/
#include "MemoryPool.H"
#include "debug.H"
#include "dictionary.H"
#include "sigFpe.H"
#include "OSspecific.H" // For getEnv
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
#ifdef FOAM_USE_UMPIRE
// #include <cerrno>
#include <cinttypes>
#include <tuple>
#include "umpire/Allocator.hpp"
#include "umpire/ResourceManager.hpp"
#include "umpire/strategy/AlignedAllocator.hpp"
#include "umpire/strategy/DynamicPoolList.hpp"
static bool disabled_(false);
static umpire::Allocator aligned_allocator;
static umpire::Allocator pooled_allocator;
static umpire::ResourceManager* manager_(nullptr);
static umpire::ResourceManager* suspended_(nullptr);
#endif
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
#ifdef FOAM_USE_UMPIRE
namespace
{
// Different supported allocation types
enum class Types { undefined, none, host, device, managed };
typedef std::tuple<Types, std::size_t, std::size_t> ctrlTuple;
// Extract key=INT, the key includes the '='
int getIntParameter(const std::string& key, const std::string& ctrl)
{
int val(0);
const auto pos = ctrl.find(key);
if (pos == std::string::npos)
{
return val;
}
const char* buf = (ctrl.data() + pos + key.size());
char *endptr = nullptr;
errno = 0;
auto parsed = std::strtoimax(buf, &endptr, 10);
if (errno || endptr == buf)
{
// Some type of error OR no conversion
}
else
{
val = int(parsed);
}
return val;
}
ctrlTuple getControlValues(const std::string& ctrl)
{
ctrlTuple result(Types::undefined, 0, 0);
bool checkParam = false;
// Also find things that look like Switch constants.
// Unfortunately need to do this manually since Switch::find()
// itself would not manage to parse something like "true; size=10"
if (ctrl.empty())
{
// Nothing => undefined
}
else if
(
std::string::npos != ctrl.find("false") // ctrl.contains("false")
|| std::string::npos != ctrl.find("off") // ctrl.contains("off")
|| std::string::npos != ctrl.find("no") // ctrl.contains("no")
|| std::string::npos != ctrl.find("none") // ctrl.contains("none")
)
{
std::get<0>(result) = Types::none;
}
else if
(
std::string::npos != ctrl.find("true") // ctrl.contains("true")
|| std::string::npos != ctrl.find("on") // ctrl.contains("on")
|| std::string::npos != ctrl.find("yes") // ctrl.contains("yes")
|| std::string::npos != ctrl.find("host") // ctrl.contains("host")
|| std::string::npos != ctrl.find("system") // ctrl.contains("system")
)
{
std::get<0>(result) = Types::host;
checkParam = true;
}
// These need more testing
else if
(
std::string::npos != ctrl.find("device") // ctrl.contains("device")
)
{
std::get<0>(result) = Types::device;
checkParam = true;
}
else if
(
std::string::npos != ctrl.find("managed") // ctrl.contains("managed")
)
{
std::get<0>(result) = Types::managed;
checkParam = true;
}
if (checkParam)
{
std::get<1>(result) = getIntParameter("size=", ctrl);
std::get<2>(result) = getIntParameter("incr=", ctrl);
}
return result;
}
bool create_from(const ctrlTuple& controls, bool verbose)
{
using namespace Foam;
if (manager_ || suspended_)
{
// Already created
return true;
}
// Type, initial size, increment
auto [which, size, incr] = controls;
// std::cerr
// << "which=" << int(which)
// << ", size=" << int(size)
// << ", incr=" << int(incr) << '\n';
constexpr size_t MegaByte(1024*1024);
switch (which)
{
case Types::undefined :
{
if (verbose)
{
Info<< "memory pool : unused" << nl;
}
break;
}
case Types::none :
{
if (verbose)
{
Info<< "memory pool : disabled" << nl;
}
break;
}
case Types::host :
{
// Default sizing parameters
if (!size) size = 1024;
if (!incr) incr = 5;
auto& rm = umpire::ResourceManager::getInstance();
manager_ = &rm;
aligned_allocator =
rm.makeAllocator<umpire::strategy::AlignedAllocator>
(
"aligned_allocator",
rm.getAllocator("HOST"),
// alignment
256
);
pooled_allocator =
rm.makeAllocator<umpire::strategy::DynamicPoolList>
(
"openfoam_HOST_pool",
aligned_allocator,
// initial block allocation size
(size*MegaByte),
// incremental block allocation size
(incr*MegaByte)
);
if (verbose)
{
Info<< "memory pool : host (size="
<< int(size) << "MB, incr="
<< int(incr) << "MB)\n";
}
break;
}
case Types::device :
{
auto& rm = umpire::ResourceManager::getInstance();
manager_ = &rm;
aligned_allocator = rm.getAllocator("DEVICE");
pooled_allocator =
rm.makeAllocator<umpire::strategy::DynamicPoolList>
(
"openfoam_DEVICE_pool",
aligned_allocator
);
if (verbose)
{
Info<< "memory pool : device" << nl;
}
break;
}
case Types::managed :
{
// Default sizing parameters
if (!size) size = 10*1024;
if (!incr) incr = 10;
auto& rm = umpire::ResourceManager::getInstance();
manager_ = &rm;
aligned_allocator = rm.getAllocator("UM");
pooled_allocator =
rm.makeAllocator<umpire::strategy::DynamicPoolList>
(
"openfoam_UM_pool",
aligned_allocator,
// initial block allocation size
(size*MegaByte),
// incremental block allocation size
(incr*MegaByte)
);
if (verbose)
{
Info<< "memory pool : managed (size="
<< int(size) << "MB, incr="
<< int(incr) << "MB)\n";
}
break;
}
}
return (which != Types::undefined && which != Types::none);
}
} // End anonymous namespace
#endif // FOAM_USE_UMPIRE
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
// bool Foam::MemoryPool::create(const std::string& ctrl, bool verbose)
// {
// #ifdef FOAM_USE_UMPIRE
// if (manager_ || suspended_)
// {
// // Already created
// return true;
// }
//
// auto controls = getControlValues(ctrl);
//
// return create_from(controls, verbose);
// #else
// return false;
// #endif
// }
bool Foam::MemoryPool::create(bool verbose)
{
#ifdef FOAM_USE_UMPIRE
if (disabled_)
{
// Disallowed
return false;
}
else if (manager_ || suspended_)
{
// Already created
return true;
}
// First check environment
auto controls = getControlValues(Foam::getEnv("FOAM_MEMORY_POOL"));
if (std::get<0>(controls) == Types::none)
{
// Disabled from environment - has highest priority
disabled_ = true;
}
// Currently no easy way to handle <system>/controlDict...
// Fallback from etc/controlDict
if (std::get<0>(controls) == Types::undefined)
{
// From central etc/controlDict
const auto& dict = Foam::debug::optimisationSwitches();
if (auto* eptr = dict.findStream("memory_pool", keyType::LITERAL))
{
const token& firstToken = eptr->front();
if (firstToken.isStringType())
{
controls = getControlValues(firstToken.stringToken());
}
}
}
return create_from(controls, verbose);
#else
if (verbose)
{
Info<< "memory pool : not available" << nl;
}
return false;
#endif
}
void Foam::MemoryPool::destroy(bool verbose)
{
// Nothing currently needed but could add in something like this:
// if (manager_ || suspended_)
// {
// pooled_allocator.release();
// }
// However, need to find the proper sequence within
// Foam::exit() or UPstream::exit() ...
}
bool Foam::MemoryPool::active() noexcept
{
#ifdef FOAM_USE_UMPIRE
return bool(manager_);
#else
return false;
#endif
}
bool Foam::MemoryPool::suspend() noexcept
{
#ifdef FOAM_USE_UMPIRE
bool status(suspended_);
if (manager_) // <- and (!suspended_)
{
std::swap(manager_, suspended_);
}
return status;
#else
return false;
#endif
}
void Foam::MemoryPool::resume() noexcept
{
#ifdef FOAM_USE_UMPIRE
if (suspended_) // <- and (!manager_)
{
std::swap(manager_, suspended_);
}
#endif
}
bool Foam::MemoryPool::is_pool(void* ptr)
{
#ifdef FOAM_USE_UMPIRE
if (ptr)
{
if (manager_)
{
return manager_->hasAllocator(ptr);
}
else if (suspended_)
{
return suspended_->hasAllocator(ptr);
}
}
#endif
return false;
}
void* Foam::MemoryPool::try_allocate(std::size_t nbytes)
{
void* ptr = nullptr;
#ifdef FOAM_USE_UMPIRE
if (manager_)
{
ptr = pooled_allocator.allocate(nbytes);
// std::cerr<< "allocate(" << int(nbytes) << ")\n";
// Optionally fill with NaN (depends on current flags)
Foam::sigFpe::fillNan_if(ptr, nbytes);
if (!ptr)
{
// Pout<< "umpire failed to allocate memory\n";
}
}
#endif
return ptr;
}
bool Foam::MemoryPool::try_deallocate(void* ptr)
{
#ifdef FOAM_USE_UMPIRE
if (ptr)
{
if (manager_)
{
if (manager_->hasAllocator(ptr)) // <- ie, is_pool()
{
// std::cerr<< "deallocate()\n";
manager_->deallocate(ptr);
return true;
}
}
else if (suspended_)
{
// Deallocate even if nominally suspended
if (suspended_->hasAllocator(ptr)) // <- ie, is_pool()
{
// std::cerr<< "deallocate()\n";
suspended_->deallocate(ptr);
return true;
}
}
}
#endif
return (!ptr);
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -203,7 +203,7 @@ public:
//- Change the value for the list capacity directly (ADVANCED, UNSAFE) //- Change the value for the list capacity directly (ADVANCED, UNSAFE)
//- Does not perform any memory management or resizing. //- Does not perform any memory management or resizing.
void setCapacity_unsafe(const label len) noexcept { capacity_ = len; } void setCapacity_unsafe(label len) noexcept { capacity_ = len; }
//- Reserve allocation space for at least this size, allocating new //- Reserve allocation space for at least this size, allocating new
//- space if required and \em retaining old content. //- space if required and \em retaining old content.
@ -251,11 +251,6 @@ public:
//- Shrink the allocated space to the number of elements used. //- Shrink the allocated space to the number of elements used.
inline void shrink_to_fit(); inline void shrink_to_fit();
//- Shrink the internal bookkeeping of the allocated space to the
//- number of addressed elements without affecting allocation.
// \note when empty() it will delete any allocated memory.
inline void shrink_unsafe();
// Edit // Edit

View File

@ -68,7 +68,9 @@ inline void Foam::DynamicList<T, SizeMin>::doCapacity
// Addressable length, possibly truncated by new capacity // Addressable length, possibly truncated by new capacity
const label currLen = Foam::min(List<T>::size(), newCapacity); const label currLen = Foam::min(List<T>::size(), newCapacity);
// Consistent allocated sizing
List<T>::setAddressableSize(capacity_); List<T>::setAddressableSize(capacity_);
if (nocopy) if (nocopy)
{ {
List<T>::resize_nocopy(newCapacity); List<T>::resize_nocopy(newCapacity);
@ -95,6 +97,9 @@ inline void Foam::DynamicList<T, SizeMin>::doReserve
// Preserve addressed size // Preserve addressed size
const label currLen = List<T>::size(); const label currLen = List<T>::size();
// Consistent allocated sizing
List<T>::setAddressableSize(capacity_);
// Increase capacity (eg, doubling) // Increase capacity (eg, doubling)
capacity_ = capacity_ =
Foam::ListPolicy::reserve_size<SizeMin, 2>(len, capacity_); Foam::ListPolicy::reserve_size<SizeMin, 2>(len, capacity_);
@ -105,8 +110,10 @@ inline void Foam::DynamicList<T, SizeMin>::doReserve
} }
else else
{ {
List<T>::resize(capacity_); List<T>::resize_copy(currLen, capacity_);
} }
capacity_ = List<T>::size();
List<T>::setAddressableSize(currLen); List<T>::setAddressableSize(currLen);
} }
} }
@ -271,7 +278,7 @@ inline Foam::DynamicList<T, SizeMin>::DynamicList
List<T>(std::move(static_cast<List<T>&>(list))), List<T>(std::move(static_cast<List<T>&>(list))),
capacity_(list.capacity()) capacity_(list.capacity())
{ {
list.setCapacity_unsafe(0); // Same as shrink_unsafe() but noexcept list.setCapacity_unsafe(0); // All contents moved
} }
@ -285,7 +292,7 @@ inline Foam::DynamicList<T, SizeMin>::DynamicList
List<T>(std::move(static_cast<List<T>&>(list))), List<T>(std::move(static_cast<List<T>&>(list))),
capacity_(list.capacity()) capacity_(list.capacity())
{ {
list.setCapacity_unsafe(0); // Same as shrink_unsafe() but noexcept list.setCapacity_unsafe(0); // All contents moved
} }
@ -361,8 +368,15 @@ inline void Foam::DynamicList<T, SizeMin>::reserve_exact
// Preserve addressed size // Preserve addressed size
const label currLen = List<T>::size(); const label currLen = List<T>::size();
capacity_ = len; // Consistent allocated sizing
List<T>::resize(capacity_); List<T>::setAddressableSize(capacity_);
// if (!nocopy)
{
List<T>::resize_copy(currLen, len);
}
capacity_ = List<T>::size();
List<T>::setAddressableSize(currLen); List<T>::setAddressableSize(currLen);
} }
} }
@ -449,18 +463,6 @@ inline void Foam::DynamicList<T, SizeMin>::shrink_to_fit()
} }
template<class T, int SizeMin>
inline void Foam::DynamicList<T, SizeMin>::shrink_unsafe()
{
if (List<T>::empty())
{
// Delete storage if empty
List<T>::clear();
}
capacity_ = List<T>::size();
}
template<class T, int SizeMin> template<class T, int SizeMin>
inline void inline void
Foam::DynamicList<T, SizeMin>::swap(List<T>& list) Foam::DynamicList<T, SizeMin>::swap(List<T>& list)

View File

@ -236,13 +236,6 @@ public:
// Otherwise the contents will be uninitialized. // Otherwise the contents will be uninitialized.
inline void resize_nocopy(const label len); inline void resize_nocopy(const label len);
//- Change the addressed list size directly without affecting
//- any memory management (advanced usage).
//
// It is left to the caller to avoid \em unsafe lengthening beyond
// the allocated memory region.
inline void resize_unsafe(const label len) noexcept;
//- Alias for resize() //- Alias for resize()
void setSize(const label n) { this->resize(n); } void setSize(const label n) { this->resize(n); }

View File

@ -178,13 +178,6 @@ inline void Foam::List<T>::resize_nocopy(const label len)
} }
template<class T>
inline void Foam::List<T>::resize_unsafe(const label len) noexcept
{
UList<T>::setAddressableSize(len);
}
template<class T> template<class T>
inline T& Foam::List<T>::newElmt(const label i) inline T& Foam::List<T>::newElmt(const label i)
{ {

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2015 OpenFOAM Foundation Copyright (C) 2011-2015 OpenFOAM Foundation
Copyright (C) 2018-2024 OpenCFD Ltd. Copyright (C) 2018-2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -28,8 +28,6 @@ License
#include "ListOps.H" #include "ListOps.H"
#include "CompactListList.H" #include "CompactListList.H"
#include "HashSet.H"
#include <numeric>
// * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Global Functions * * * * * * * * * * * * * //
@ -115,7 +113,8 @@ Foam::Map<Foam::label> Foam::invertToMap(const labelUList& values)
{ {
const label len = values.size(); const label len = values.size();
Map<label> inverse(2*len); Map<label> inverse;
inverse.reserve(len);
for (label i = 0 ; i < len; ++i) for (label i = 0 ; i < len; ++i)
{ {
@ -280,13 +279,14 @@ void Foam::inplaceReorder
void Foam::ListOps::unionEqOp::operator() void Foam::ListOps::unionEqOp::operator()
( (
labelList& x, labelList& x,
const labelList& y const labelUList& y
) const ) const
{ {
if (y.size()) if (y.size())
{ {
if (x.size()) if (x.size())
{ {
// Using HashSet will likely change the order of list
labelHashSet set(x); labelHashSet set(x);
set.insert(y); set.insert(y);
x = set.toc(); x = set.toc();

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2017-2024 OpenCFD Ltd. Copyright (C) 2017-2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -485,7 +485,6 @@ labelPair findMinMax(const ListType& input, label start=0);
// <code> (list[i] < val) </code> for the test. // <code> (list[i] < val) </code> for the test.
// //
// \tparam ListType The input list type // \tparam ListType The input list type
// \tparam T The value type (should normally be ListType::value_type)
// //
// \param input The sorted list to search // \param input The sorted list to search
// \param val The value for searching/comparing // \param val The value for searching/comparing
@ -508,7 +507,7 @@ label findSortedIndex
// <code> lessOp<T>(list[i], val) </code> for the test. // <code> lessOp<T>(list[i], val) </code> for the test.
// //
// \tparam ListType The input list type // \tparam ListType The input list type
// \tparam T The value type (is often the same as ListType::value_type) // \tparam T The value type (usually the same as ListType::value_type)
// \tparam ComparePredicate The type of the comparison functor that // \tparam ComparePredicate The type of the comparison functor that
// returns true for sorting below. // returns true for sorting below.
// //
@ -585,23 +584,33 @@ namespace ListOps
template<class T> template<class T>
struct appendEqOp struct appendEqOp
{ {
void operator()(List<T>& x, const List<T>& y) const; void operator()(List<T>& x, const UList<T>& y) const;
}; };
//- List helper to append y unique elements onto the end of x //- List helper to append y unique elements onto the end of x
template<class T> template<class T>
struct uniqueEqOp struct uniqueEqOp
{ {
void operator()(List<T>& x, const List<T>& y) const; void operator()(List<T>& x, const UList<T>& y) const;
}; };
//- List helper to add y unique elements to x //- List helper to add y unique elements to x
struct unionEqOp struct unionEqOp
{ {
void operator()(labelList& x, const labelList& y) const; void operator()(labelList& x, const labelUList& y) const;
}; };
//- Test for list equality with different but compatible data types.
//- Eg, int32 and int64
template<class Type1, class Type2>
bool equal(const UList<Type1>& a, const UList<Type2>& b);
//- Test for list equality with different but compatible data types.
template<class Type1, class Type2, class BinaryPredicate>
bool equal(const UList<Type1>& a, const UList<Type2>& b, BinaryPredicate pred);
// Public classes // Public classes
//- A list compare binary predicate for normal sort //- A list compare binary predicate for normal sort

View File

@ -1081,7 +1081,7 @@ template<class T>
void Foam::ListOps::appendEqOp<T>::operator() void Foam::ListOps::appendEqOp<T>::operator()
( (
List<T>& x, List<T>& x,
const List<T>& y const UList<T>& y
) const ) const
{ {
if (y.size()) if (y.size())
@ -1102,7 +1102,7 @@ template<class T>
void Foam::ListOps::uniqueEqOp<T>::operator() void Foam::ListOps::uniqueEqOp<T>::operator()
( (
List<T>& x, List<T>& x,
const List<T>& y const UList<T>& y
) const ) const
{ {
if (y.size()) if (y.size())
@ -1111,6 +1111,7 @@ void Foam::ListOps::uniqueEqOp<T>::operator()
{ {
for (const T& val : y) for (const T& val : y)
{ {
// Not very efficient
x.push_uniq(val); x.push_uniq(val);
} }
} }
@ -1122,6 +1123,37 @@ void Foam::ListOps::uniqueEqOp<T>::operator()
} }
template<class Type1, class Type2>
bool Foam::ListOps::equal
(
const UList<Type1>& a,
const UList<Type2>& b
)
{
return
(
(a.size() == b.size())
&& std::equal(a.cbegin(), a.cend(), b.cbegin())
);
}
template<class Type1, class Type2, class BinaryPredicate>
bool Foam::ListOps::equal
(
const UList<Type1>& a,
const UList<Type2>& b,
BinaryPredicate pred
)
{
return
(
(a.size() == b.size())
&& std::equal(a.cbegin(), a.cend(), b.cbegin(), pred)
);
}
template<class ListType, class UnaryPredicate> template<class ListType, class UnaryPredicate>
Foam::label Foam::ListOps::count_if Foam::label Foam::ListOps::count_if
( (

View File

@ -34,6 +34,7 @@ Description
#ifndef Foam_ListPolicy_H #ifndef Foam_ListPolicy_H
#define Foam_ListPolicy_H #define Foam_ListPolicy_H
#include "MemoryPool.H" // Also includes <cstdint>
#include "contiguous.H" // Also includes <type_traits> #include "contiguous.H" // Also includes <type_traits>
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -103,6 +104,18 @@ template<> struct no_linebreak<wordRe> : std::true_type {};
// - use_offload(n) : // - use_offload(n) :
// Lower threshold for switching to device offloading // Lower threshold for switching to device offloading
// //
//
// Use of the memory-pool is controlled by the 'is_aligned_type()' test
// and the minimum field size, controlled by the 'use_memory_pool()' test.
//
// If the memory-pool is not enabled or not required according to the two
// above tests, the allocation falls back to either an aligned or unaligned
// allocation.
//
// The decision about when to choose aligned vs unaligned allocation
// is still a compile-time option. Made by direct edit of the
// appropriate functions.
//
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
//- Consider aligned allocation for the given type? //- Consider aligned allocation for the given type?
@ -146,27 +159,104 @@ inline constexpr bool use_offload(IntType n) noexcept
} }
//- Default alignment for larger fields
inline constexpr std::align_val_t default_alignment() noexcept
{
return std::align_val_t(256);
}
//- Allocate from memory pool (if active), or aligned, or normal
template<class T, class IntType> template<class T, class IntType>
inline T* allocate(IntType n) inline T* allocate(IntType n)
{ {
// Plain new if constexpr (ListPolicy::is_aligned_type<T>())
return new T[n]; {
// Note: threshold for use_memory_pool() >= use_alignment()
if (ListPolicy::use_alignment(n))
{
if
(
void *pool_ptr
(
// Consider memory pool for large amounts of data
ListPolicy::use_memory_pool(n)
? Foam::MemoryPool::try_allocate(sizeof(T)*n)
: nullptr
);
pool_ptr
)
{
// Placement new
return new (pool_ptr) T[n];
}
else
{
return new (ListPolicy::default_alignment()) T[n];
}
}
else
{
// Plain new
return new T[n];
}
}
else
{
// Plain new
return new T[n];
}
} }
//- Deallocate from memory pool, or normal
template<class T, class IntType> template<class T, class IntType>
inline void deallocate(T* ptr) inline void deallocate(T* ptr)
{ {
// Plain new if constexpr (ListPolicy::is_aligned_type<T>())
delete[] ptr; {
if (ptr && !Foam::MemoryPool::try_deallocate(ptr))
{
// Plain new
delete[] ptr;
}
}
else
{
// Plain new
delete[] ptr;
}
} }
//- Deallocate from memory pool, or aligned, or normal
template<class T, class IntType> template<class T, class IntType>
inline void deallocate(T* ptr, [[maybe_unused]] IntType n) inline void deallocate(T* ptr, [[maybe_unused]] IntType n)
{ {
// Plain new if constexpr (ListPolicy::is_aligned_type<T>())
delete[] ptr; {
// Note: threshold for use_memory_pool() >= use_alignment()
if (ListPolicy::use_alignment(n))
{
if (ptr && !Foam::MemoryPool::try_deallocate(ptr))
{
// Alignment depends on the number of elements
::operator delete[](ptr, ListPolicy::default_alignment());
}
}
else
{
// Plain new
delete[] ptr;
}
}
else
{
// Plain new
delete[] ptr;
}
} }

View File

@ -112,23 +112,26 @@ public:
//- Change the value for the list capacity directly (ADVANCED, UNSAFE) //- Change the value for the list capacity directly (ADVANCED, UNSAFE)
//- Does not perform any memory management or resizing. //- Does not perform any memory management or resizing.
void setCapacity_unsafe(const label len) noexcept { capacity_ = len; } void setCapacity_unsafe(label len) noexcept { capacity_ = len; }
//- Reserve allocation space for at least this size. //- Reserve allocation space for at least this size.
// New entries are initialized to nullptr.
inline void reserve(const label len); inline void reserve(const label len);
//- Reserve allocation space for at least this size. //- Reserve allocation space for at least this size.
//- If allocation is required, uses the specified size //- If allocation is required, uses the specified size
//- without any other resizing logic. //- without any other resizing logic.
// New entries are initialized to nullptr.
inline void reserve_exact(const label len); inline void reserve_exact(const label len);
//- Alter the addressed list size. //- Alter the addressed list size.
inline void resize(const label newLen); // New entries are initialized to nullptr.
inline void resize(const label len);
//- Set the addressed list to the given size, //- Set the addressed list to the given size,
//- deleting all existing entries. //- deleting all existing entries.
//- Afterwards the list contains all \c nullptr entries. //- Afterwards the list contains all \c nullptr entries.
inline void resize_null(const label newLen); inline void resize_null(const label len);
//- Clear the addressed list, i.e. set the size to zero. //- Clear the addressed list, i.e. set the size to zero.
// Allocated size does not change // Allocated size does not change
@ -140,11 +143,6 @@ public:
//- Shrink the allocated space to the number of elements used. //- Shrink the allocated space to the number of elements used.
inline void shrink_to_fit(); inline void shrink_to_fit();
//- Shrink the internal bookkeeping of the allocated space to the
//- number of addressed elements without affecting allocation.
// \note when empty() it will delete any allocated memory.
inline void shrink_unsafe();
//- Alias for shrink_to_fit() //- Alias for shrink_to_fit()
void shrink() { this->shrink_to_fit(); } void shrink() { this->shrink_to_fit(); }

View File

@ -82,10 +82,7 @@ inline Foam::PtrDynList<T, SizeMin>::PtrDynList
PtrList<T>(std::move(list)), PtrList<T>(std::move(list)),
capacity_(list.capacity()) capacity_(list.capacity())
{ {
// FUTURE: list.setCapacity_unsafe(0); // All contents moved
// list.setCapacity_unsafe(0); // Same as shrink_unsafe() but noexcept
list.clearStorage(); // capacity=0 etc.
} }
@ -99,10 +96,7 @@ inline Foam::PtrDynList<T, SizeMin>::PtrDynList
PtrList<T>(std::move(list)), PtrList<T>(std::move(list)),
capacity_(list.capacity()) capacity_(list.capacity())
{ {
// FUTURE: list.setCapacity_unsafe(0); // All contents moved
// list.setCapacity_unsafe(0); // Same as shrink_unsafe() but noexcept
list.clearStorage(); // capacity=0 etc.
} }
@ -135,11 +129,17 @@ inline void Foam::PtrDynList<T, SizeMin>::reserve(const label len)
// Preserve addressed size // Preserve addressed size
const label currLen = PtrList<T>::size(); const label currLen = PtrList<T>::size();
// Consistent allocated sizing
PtrList<T>::setAddressableSize(capacity_);
// Increase capacity (eg, doubling) // Increase capacity (eg, doubling)
capacity_ = capacity_ =
Foam::ListPolicy::reserve_size<SizeMin, 2>(len, capacity_); Foam::ListPolicy::reserve_size<SizeMin, 2>(len, capacity_);
// No PtrList<T>::resize_copy(...) -> copying nullptr is cheap
PtrList<T>::resize(capacity_); PtrList<T>::resize(capacity_);
capacity_ = PtrList<T>::size();
PtrList<T>::setAddressableSize(currLen); PtrList<T>::setAddressableSize(currLen);
} }
} }
@ -153,8 +153,13 @@ inline void Foam::PtrDynList<T, SizeMin>::reserve_exact(const label len)
// Preserve addressed size // Preserve addressed size
const label currLen = PtrList<T>::size(); const label currLen = PtrList<T>::size();
capacity_ = len; // Consistent allocated sizing
PtrList<T>::resize(capacity_); PtrList<T>::setAddressableSize(capacity_);
// No PtrList<T>::resize_copy(...) -> copying nullptr is cheap
PtrList<T>::resize(len);
capacity_ = PtrList<T>::size();
PtrList<T>::setAddressableSize(currLen); PtrList<T>::setAddressableSize(currLen);
} }
} }
@ -164,16 +169,12 @@ template<class T, int SizeMin>
inline void Foam::PtrDynList<T, SizeMin>::resize(const label newLen) inline void Foam::PtrDynList<T, SizeMin>::resize(const label newLen)
{ {
auto& ptrs = this->ptrs_; auto& ptrs = this->ptrs_;
const label oldLen = ptrs.size(); const label oldLen = ptrs.size();
if (capacity_ < newLen) if (capacity_ < newLen)
{ {
// Increase capacity (eg, doubling) // Extend list
capacity_ = this->reserve(newLen);
Foam::ListPolicy::reserve_size<SizeMin, 2>(newLen, capacity_);
PtrList<T>::resize(capacity_);
} }
else if (newLen != oldLen) else if (newLen != oldLen)
{ {
@ -191,13 +192,16 @@ inline void Foam::PtrDynList<T, SizeMin>::resize(const label newLen)
template<class T, int SizeMin> template<class T, int SizeMin>
inline void Foam::PtrDynList<T, SizeMin>::resize_null(const label newLen) inline void Foam::PtrDynList<T, SizeMin>::resize_null(const label len)
{ {
if (capacity_ < newLen) if (capacity_ < len)
{ {
// Consistent allocated sizing
PtrList<T>::setAddressableSize(capacity_);
// Increase capacity (eg, doubling) // Increase capacity (eg, doubling)
capacity_ = capacity_ =
Foam::ListPolicy::reserve_size<SizeMin, 2>(newLen, capacity_); Foam::ListPolicy::reserve_size<SizeMin, 2>(len, capacity_);
PtrList<T>::resize_null(capacity_); PtrList<T>::resize_null(capacity_);
} }
@ -207,7 +211,7 @@ inline void Foam::PtrDynList<T, SizeMin>::resize_null(const label newLen)
} }
// Adjust addressed size // Adjust addressed size
PtrList<T>::setAddressableSize(newLen); PtrList<T>::setAddressableSize(len);
} }
@ -240,18 +244,6 @@ inline void Foam::PtrDynList<T, SizeMin>::shrink_to_fit()
} }
template<class T, int SizeMin>
inline void Foam::PtrDynList<T, SizeMin>::shrink_unsafe()
{
if (PtrList<T>::empty())
{
// Delete empty list
PtrList<T>::clear();
}
capacity_ = PtrList<T>::size();
}
template<class T, int SizeMin> template<class T, int SizeMin>
inline Foam::label Foam::PtrDynList<T, SizeMin>::squeezeNull() inline Foam::label Foam::PtrDynList<T, SizeMin>::squeezeNull()
{ {

View File

@ -257,13 +257,13 @@ public:
return ioState_ & std::ios_base::badbit; return ioState_ & std::ios_base::badbit;
} }
//- Return true if the stream has not failed //- True if the stream has not failed
explicit operator bool() const noexcept explicit operator bool() const noexcept
{ {
return !fail(); return !fail();
} }
//- Return true if the stream has failed //- True if the stream has failed
bool operator!() const noexcept bool operator!() const noexcept
{ {
return fail(); return fail();
@ -406,10 +406,10 @@ public:
return flags((flags() & ~mask) | (f & mask)); return flags((flags() & ~mask) | (f & mask));
} }
//- Unset flags of stream //- Unset stream flags, return old stream flags
void unsetf(std::ios_base::fmtflags f) std::ios_base::fmtflags unsetf(std::ios_base::fmtflags f)
{ {
flags(flags() & ~f); return flags(flags() & ~f);
} }

View File

@ -179,6 +179,9 @@ public:
// Public Classes // Public Classes
//- Wrapper for OpenFOAM internal communicator index
class communicator; // Forward Declaration
//- Wrapper for MPI_Comm //- Wrapper for MPI_Comm
class Communicator; // Forward Declaration class Communicator; // Forward Declaration
@ -378,6 +381,25 @@ public:
//- Print un-directed graph in graphviz dot format //- Print un-directed graph in graphviz dot format
void printGraph(Ostream& os, int proci = 0) const; void printGraph(Ostream& os, int proci = 0) const;
//- Write the communication tree
Ostream& writeList(Ostream& os) const
{
return tree_.writeList(os);
}
// Member / Friend Operators
//- Write the communication tree
friend Ostream& operator<<
(
Ostream& os,
const commsStructList& rhs
)
{
return rhs.writeList(os);
}
}; };
@ -850,7 +872,7 @@ public:
const bool withComponents = true const bool withComponents = true
); );
//- Creaet new communicator with sub-ranks on the parent communicator //- Create new communicator with sub-ranks on the parent communicator
static label newCommunicator static label newCommunicator
( (
//! The parent communicator //! The parent communicator
@ -896,126 +918,6 @@ public:
const bool withComponents = true const bool withComponents = true
); );
//- Wrapper class for allocating/freeing communicators. Always invokes
//- allocateCommunicatorComponents() and freeCommunicatorComponents()
class communicator
{
label comm_;
public:
//- No copy construct
communicator(const communicator&) = delete;
//- No copy assignment
void operator=(const communicator&) = delete;
//- Default construct (a placeholder communicator)
communicator() noexcept : comm_(-1) {}
//- Move construct, takes ownership
communicator(communicator&& c) : comm_(c.comm_) { c.comm_ = -1; }
//- Allocate communicator for contiguous sub-ranks on given parent
communicator
(
//! The parent communicator
const label parentComm,
//! The contiguous sub-ranks of parent to use
const labelRange& subRanks
)
:
comm_(UPstream::newCommunicator(parentComm, subRanks))
{}
//- Allocate communicator for sub-ranks on given parent
communicator
(
//! The parent communicator
const label parentComm,
//! The sub-ranks of parent to use (negative values ignored)
const labelUList& subRanks
)
:
comm_(UPstream::newCommunicator(parentComm, subRanks))
{}
//- Factory Method :
//- Duplicate the given communicator
static communicator duplicate(const label parentComm)
{
communicator c;
c.comm_ = UPstream::dupCommunicator(parentComm);
return c;
}
//- Factory Method :
//- Split the communicator on the given \em colour.
static communicator split
(
//! The parent communicator
const label parentComm,
//! The colouring to select which ranks to include.
//! Negative values correspond to 'ignore'
const int colour,
//! Use MPI_Allgather+MPI_Comm_create_group vs MPI_Comm_split
const bool two_step = true
)
{
communicator c;
c.comm_ =
UPstream::splitCommunicator(parentComm, colour, two_step);
return c;
}
//- Free allocated communicator
~communicator() { UPstream::freeCommunicator(comm_); }
//- True if communicator is non-negative (ie, was allocated)
bool good() const noexcept { return (comm_ >= 0); }
//- The communicator label
label comm() const noexcept { return comm_; }
//- Release ownership of the communicator, return old value.
// Leave further management to the caller
label release() noexcept { label c(comm_); comm_ = -1; return c; }
//- Free allocated communicator
void reset() { UPstream::freeCommunicator(comm_); comm_ = -1; }
//- Allocate with contiguous sub-ranks of parent communicator
void reset(label parent, const labelRange& subRanks)
{
UPstream::freeCommunicator(comm_);
comm_ = UPstream::newCommunicator(parent, subRanks);
}
//- Allocate with sub-ranks of parent communicator
void reset(label parent, const labelUList& subRanks)
{
UPstream::freeCommunicator(comm_);
comm_ = UPstream::newCommunicator(parent, subRanks);
}
//- Take ownership, free allocated communicator
// \caution do not call as self-assignment
void reset(communicator&& c)
{
if (comm_ != c.comm_) UPstream::freeCommunicator(comm_);
comm_ = c.comm_;
c.comm_ = -1;
}
//- Move assignment, takes ownership
// \caution do not call as self-assignment
void operator=(communicator&& c) { reset(std::move(c)); }
//- Cast to label - the same as comm()
operator label() const noexcept { return comm_; }
};
//- Return physical processor number (i.e. processor number in //- Return physical processor number (i.e. processor number in
//- worldComm) given communicator and processor //- worldComm) given communicator and processor
static int baseProcNo(label comm, int procID); static int baseProcNo(label comm, int procID);
@ -1839,6 +1741,168 @@ public:
} }
}; };
/*---------------------------------------------------------------------------*\
Class UPstream::communicator Declaration
\*---------------------------------------------------------------------------*/
//- Wrapper for internally indexed communicator label.
//- Always invokes UPstream::allocateCommunicatorComponents()
//- and UPstream::freeCommunicatorComponents()
class UPstream::communicator
{
// Private Data
//- The communicator label
label comm_;
public:
// Generated Methods
//- No copy construct
communicator(const communicator&) = delete;
//- No copy assignment
void operator=(const communicator&) = delete;
// Constructors
//- Default construct (a placeholder communicator)
communicator() noexcept : comm_(-1) {}
//- Move construct, takes ownership
communicator(communicator&& c) : comm_(c.comm_) { c.comm_ = -1; }
//- Allocate communicator for contiguous sub-ranks on given parent
communicator
(
//! The parent communicator
const label parentComm,
//! The contiguous sub-ranks of parent to use
const labelRange& subRanks
)
:
comm_(UPstream::newCommunicator(parentComm, subRanks))
{}
//- Allocate communicator for sub-ranks on given parent
communicator
(
//! The parent communicator
const label parentComm,
//! The sub-ranks of parent to use (negative values ignored)
const labelUList& subRanks
)
:
comm_(UPstream::newCommunicator(parentComm, subRanks))
{}
// Destructor
//- Free allocated communicator
~communicator() { UPstream::freeCommunicator(comm_); }
// Factory Methods
//- Duplicate the given communicator
static communicator duplicate(const label parentComm)
{
communicator c;
c.comm_ = UPstream::dupCommunicator(parentComm);
return c;
}
//- Factory Method :
//- Split the communicator on the given \em colour.
static communicator split
(
//! The parent communicator
const label parentComm,
//! The colouring to select which ranks to include.
//! Negative values correspond to 'ignore'
const int colour,
//! Use MPI_Allgather+MPI_Comm_create_group vs MPI_Comm_split
const bool two_step = true
)
{
communicator c;
c.comm_ = UPstream::splitCommunicator(parentComm, colour, two_step);
return c;
}
// Member Functions
//- True if communicator is non-negative (ie, was allocated)
bool good() const noexcept { return (comm_ >= 0); }
//- The communicator label
label comm() const noexcept { return comm_; }
//- Return non-const reference to this
communicator& constCast() const noexcept
{
return const_cast<communicator&>(*this);
}
//- Release ownership of the communicator, return old value.
// Leave further management to the caller
label release() noexcept { label c(comm_); comm_ = -1; return c; }
//- Free allocated communicator
void reset() { UPstream::freeCommunicator(comm_); comm_ = -1; }
//- Allocate with contiguous sub-ranks of parent communicator
void reset(label parent, const labelRange& subRanks)
{
UPstream::freeCommunicator(comm_);
comm_ = UPstream::newCommunicator(parent, subRanks);
}
//- Allocate with sub-ranks of parent communicator
void reset(label parent, const labelUList& subRanks)
{
UPstream::freeCommunicator(comm_);
comm_ = UPstream::newCommunicator(parent, subRanks);
}
//- Take ownership, free managed communicator
void reset(communicator&& c)
{
if (this == &c) return; // No self-assignment
if (comm_ != c.comm_) UPstream::freeCommunicator(comm_);
comm_ = c.comm_;
c.comm_ = -1;
}
//- Swap communicator labels
void swap(communicator& c) { std::swap(comm_, c.comm_); }
// Member Operators
//- Implicit cast to label - the same as comm()
operator label() const noexcept { return comm_; }
//- Move assignment, takes ownership
void operator=(communicator&& c) { reset(std::move(c)); }
//- Test for equality
bool operator==(const communicator& c) const noexcept
{
return (comm_ == c.comm_);
}
//- Test for inequality
bool operator!=(const communicator& c) const noexcept
{
return (comm_ != c.comm_);
}
};
/*---------------------------------------------------------------------------*\ /*---------------------------------------------------------------------------*\
Class UPstream::Communicator Declaration Class UPstream::Communicator Declaration

View File

@ -470,18 +470,10 @@ public:
//- Copy append a list of tokens at the current tokenIndex, //- Copy append a list of tokens at the current tokenIndex,
//- incrementing the index. //- incrementing the index.
//
// \param newTokens the list of tokens to copy append
// \param lazy leaves any excess capacity for further appends.
// The caller will be responsible for resizing later.
void add_tokens(const UList<token>& toks); void add_tokens(const UList<token>& toks);
//- Move append a list of tokens at the current tokenIndex, //- Move append a list of tokens at the current tokenIndex,
//- incrementing the index. //- incrementing the index.
//
// \param newTokens the list of tokens to move append
// \param lazy leaves any excess capacity for further appends.
// The caller will be responsible for resizing later.
void add_tokens(List<token>&& toks); void add_tokens(List<token>&& toks);

View File

@ -32,7 +32,7 @@ Note
#include "error.H" #include "error.H"
#include "dictionary.H" #include "dictionary.H"
#include "foamVersion.H" #include "foamVersion.H"
#include "Pstream.H" #include "UPstream.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -106,22 +106,34 @@ Foam::messageStream::messageStream(const dictionary& dict)
Foam::OSstream& Foam::messageStream::stream Foam::OSstream& Foam::messageStream::stream
( (
OSstream* alternative OSstream* alternative,
int communicator
) )
{ {
if (communicator < 0)
{
communicator = UPstream::worldComm;
}
if (level) if (level)
{ {
// Serlal (master only) output? // Master-only output?
const bool serialOnly const bool masterOnly
( (
!UPstream::parRun() !UPstream::parRun()
|| ((severity_ & ~errorSeverity::USE_STDERR) == errorSeverity::INFO) || ((severity_ & ~errorSeverity::USE_STDERR) == errorSeverity::INFO)
|| ((severity_ & ~errorSeverity::USE_STDERR) == errorSeverity::WARNING) || ((severity_ & ~errorSeverity::USE_STDERR) == errorSeverity::WARNING)
); );
if (serialOnly && (UPstream::parRun() && !UPstream::master())) if
(
masterOnly
&& (UPstream::parRun() && !UPstream::master(communicator))
)
{ {
return Snull; // Non-serial, non-master: exit early // Requested master-only output but is non-master (in parallel)
// -> early exit
return Snull;
} }
@ -139,10 +151,9 @@ Foam::OSstream& Foam::messageStream::stream
OSstream* osptr; OSstream* osptr;
if (serialOnly) if (masterOnly)
{ {
// Use supplied alternative? Valid for serial only // Use supplied alternative? Valid for master-only output
osptr = osptr =
( (
alternative alternative
@ -152,7 +163,6 @@ Foam::OSstream& Foam::messageStream::stream
} }
else else
{ {
// Non-serial
osptr = (use_stderr ? &Perr : &Pout); osptr = (use_stderr ? &Perr : &Pout);
} }
@ -175,8 +185,13 @@ Foam::OSstream& Foam::messageStream::stream
} }
Foam::OSstream& Foam::messageStream::masterStream(const int communicator) Foam::OSstream& Foam::messageStream::masterStream(int communicator)
{ {
if (communicator < 0)
{
communicator = UPstream::worldComm;
}
if (UPstream::warnComm >= 0 && communicator != UPstream::warnComm) if (UPstream::warnComm >= 0 && communicator != UPstream::warnComm)
{ {
Perr<< "** messageStream with comm:" << communicator << endl; Perr<< "** messageStream with comm:" << communicator << endl;
@ -185,7 +200,7 @@ Foam::OSstream& Foam::messageStream::masterStream(const int communicator)
if (communicator == UPstream::worldComm || UPstream::master(communicator)) if (communicator == UPstream::worldComm || UPstream::master(communicator))
{ {
return this->stream(); return this->stream(nullptr, communicator);
} }
return Snull; return Snull;
@ -194,6 +209,7 @@ Foam::OSstream& Foam::messageStream::masterStream(const int communicator)
std::ostream& Foam::messageStream::stdStream() std::ostream& Foam::messageStream::stdStream()
{ {
// Currently do not need communicator != worldComm
return this->stream().stdStream(); return this->stream().stdStream();
} }
@ -400,13 +416,13 @@ Foam::OSstream& Foam::messageStream::operator()
Foam::messageStream Foam::Info Foam::messageStream Foam::Info
( (
"", // No title // No title
Foam::messageStream::INFO Foam::messageStream::INFO
); );
Foam::messageStream Foam::InfoErr Foam::messageStream Foam::InfoErr
( (
"", // No title // No title
Foam::messageStream::INFO, Foam::messageStream::INFO,
0, 0,
true // use_stderr = true true // use_stderr = true

View File

@ -179,7 +179,7 @@ public:
// \return the previous value for maxErrors // \return the previous value for maxErrors
int maxErrors(int nErrors) noexcept int maxErrors(int nErrors) noexcept
{ {
int old = maxErrors_; int old(maxErrors_);
maxErrors_ = nErrors; maxErrors_ = nErrors;
return old; return old;
} }
@ -191,12 +191,15 @@ public:
OSstream& stream OSstream& stream
( (
//! An alternative output stream (serial-only) //! An alternative output stream (serial-only)
OSstream* alternative = nullptr OSstream* alternative = nullptr,
//! Communicator. Negative is treated like UPstream::worldComm
int communicator = -1
); );
//- Return OSstream for output operations on the master process only, //- Return OSstream for output operations on the master process only,
//- Snull on other processes. //- Snull on other processes.
OSstream& masterStream(const int communicator); // A negative communicator is treated like UPstream::worldComm
OSstream& masterStream(int communicator);
//- Return std::ostream for output operations. //- Return std::ostream for output operations.
std::ostream& stdStream(); std::ostream& stdStream();

View File

@ -145,9 +145,9 @@ public:
// Static Member Functions // Static Member Functions
//- Return a null DimensionedField (reference to a nullObject). //- Return a null DimensionedField (reference to a nullObject).
static const DimensionedField<Type, GeoMesh>& null() noexcept static const this_type& null() noexcept
{ {
return NullObjectRef<DimensionedField<Type, GeoMesh>>(); return NullObjectRef<this_type>();
} }

View File

@ -217,7 +217,7 @@ public:
//- Change the value for the list capacity directly (ADVANCED, UNSAFE) //- Change the value for the list capacity directly (ADVANCED, UNSAFE)
//- Does not perform any memory management or resizing. //- Does not perform any memory management or resizing.
void setCapacity_unsafe(const label len) noexcept { capacity_ = len; } void setCapacity_unsafe(label len) noexcept { capacity_ = len; }
//- Reserve allocation space for at least this size, allocating new //- Reserve allocation space for at least this size, allocating new
//- space if required and \em retaining old content. //- space if required and \em retaining old content.
@ -265,11 +265,6 @@ public:
//- Shrink the allocated space to the number of elements used. //- Shrink the allocated space to the number of elements used.
inline void shrink_to_fit(); inline void shrink_to_fit();
//- Shrink the internal bookkeeping of the allocated space to the
//- number of addressed elements without affecting allocation.
// \note when empty() it will delete any allocated memory.
inline void shrink_unsafe();
// Edit // Edit

View File

@ -66,7 +66,9 @@ inline void Foam::DynamicField<T, SizeMin>::doCapacity
// Addressable length, possibly truncated by new capacity // Addressable length, possibly truncated by new capacity
const label currLen = Foam::min(List<T>::size(), newCapacity); const label currLen = Foam::min(List<T>::size(), newCapacity);
// Consistent allocated sizing
List<T>::setAddressableSize(capacity_); List<T>::setAddressableSize(capacity_);
if (nocopy) if (nocopy)
{ {
List<T>::resize_nocopy(newCapacity); List<T>::resize_nocopy(newCapacity);
@ -93,6 +95,9 @@ inline void Foam::DynamicField<T, SizeMin>::doReserve
// Preserve addressed size // Preserve addressed size
const label currLen = List<T>::size(); const label currLen = List<T>::size();
// Consistent allocated sizing
List<T>::setAddressableSize(capacity_);
// Increase capacity (eg, doubling) // Increase capacity (eg, doubling)
capacity_ = capacity_ =
Foam::ListPolicy::reserve_size<SizeMin, 2>(len, capacity_); Foam::ListPolicy::reserve_size<SizeMin, 2>(len, capacity_);
@ -103,8 +108,10 @@ inline void Foam::DynamicField<T, SizeMin>::doReserve
} }
else else
{ {
List<T>::resize(capacity_); List<T>::resize_copy(currLen, capacity_);
} }
capacity_ = List<T>::size();
List<T>::setAddressableSize(currLen); List<T>::setAddressableSize(currLen);
} }
} }
@ -246,7 +253,7 @@ inline Foam::DynamicField<T, SizeMin>::DynamicField
Field<T>(std::move(static_cast<List<T>&>(content))), Field<T>(std::move(static_cast<List<T>&>(content))),
capacity_(content.capacity()) capacity_(content.capacity())
{ {
content.setCapacity_unsafe(0); // Same as shrink_unsafe() but noexcept content.setCapacity_unsafe(0); // All contents moved
} }
@ -259,7 +266,7 @@ inline Foam::DynamicField<T, SizeMin>::DynamicField
Field<T>(std::move(static_cast<List<T>&>(content))), Field<T>(std::move(static_cast<List<T>&>(content))),
capacity_(content.capacity()) capacity_(content.capacity())
{ {
content.setCapacity_unsafe(0); // Same as shrink_unsafe() but noexcept content.setCapacity_unsafe(0); // All contents moved
} }
@ -273,7 +280,7 @@ inline Foam::DynamicField<T, SizeMin>::DynamicField
Field<T>(std::move(static_cast<List<T>&>(content))), Field<T>(std::move(static_cast<List<T>&>(content))),
capacity_(content.capacity()) capacity_(content.capacity())
{ {
content.setCapacity_unsafe(0); // Same as shrink_unsafe() but noexcept content.setCapacity_unsafe(0); // All contents moved
} }
@ -292,7 +299,7 @@ inline Foam::DynamicField<T, SizeMin>::DynamicField
{ {
Field<T>::transfer(static_cast<List<T>&>(content)); Field<T>::transfer(static_cast<List<T>&>(content));
capacity_ = content.capacity(); capacity_ = content.capacity();
content.setCapacity_unsafe(0); content.setCapacity_unsafe(0); // All contents moved
} }
else else
{ {
@ -317,7 +324,7 @@ inline Foam::DynamicField<T, SizeMin>::DynamicField
{ {
Field<T>::transfer(static_cast<List<T>&>(content)); Field<T>::transfer(static_cast<List<T>&>(content));
capacity_ = content.capacity(); capacity_ = content.capacity();
content.setCapacity_unsafe(0); content.setCapacity_unsafe(0); // All contents moved
} }
else else
{ {
@ -462,8 +469,15 @@ inline void Foam::DynamicField<T, SizeMin>::reserve_exact
// Preserve addressed size // Preserve addressed size
const label currLen = List<T>::size(); const label currLen = List<T>::size();
capacity_ = len; // Consistent allocated sizing
List<T>::resize(capacity_); List<T>::setAddressableSize(capacity_);
// if (!nocopy)
{
List<T>::resize_copy(currLen, len);
}
capacity_ = List<T>::size();
List<T>::setAddressableSize(currLen); List<T>::setAddressableSize(currLen);
} }
} }
@ -551,18 +565,6 @@ inline void Foam::DynamicField<T, SizeMin>::shrink_to_fit()
} }
template<class T, int SizeMin>
inline void Foam::DynamicField<T, SizeMin>::shrink_unsafe()
{
if (List<T>::empty())
{
// Delete storage if empty
List<T>::clear();
}
capacity_ = List<T>::size();
}
template<class T, int SizeMin> template<class T, int SizeMin>
inline void inline void
Foam::DynamicField<T, SizeMin>::swap(List<T>& list) Foam::DynamicField<T, SizeMin>::swap(List<T>& list)

View File

@ -38,31 +38,27 @@ template<class CheckPatchFieldType>
bool Foam::GeometricBoundaryField<Type, PatchField, GeoMesh>::checkConsistency bool Foam::GeometricBoundaryField<Type, PatchField, GeoMesh>::checkConsistency
( (
const scalar tol, const scalar tol,
const bool doExit const bool exitIfBad
) const ) const
{ {
if (!this->size()) auto& bfld = this->constCast();
if (!bfld.size())
{ {
return true; return true;
} }
if (debug&2) if (debug&2)
{ {
const auto& pfld0 = this->operator[](0);
PoutInFunction PoutInFunction
<< " Checking boundary consistency for field " << " Checking boundary consistency for field "
<< pfld0.internalField().name() << bfld[0].internalField().name() << endl;
<< endl;
} }
auto& bfld = this->constCast(); // Store old values and states
List<Field<Type>> oldFields(bfld.size());
boolList oldUpdated(bfld.size());
// Store old value boolList oldManipulated(bfld.size());
List<Field<Type>> oldBfld(this->size());
boolList oldUpdated(this->size());
//Note: areaFields (finiteArea) do not have manipulatedMatrix() flag. TBD.
//boolList oldManipulated(this->size());
label nEvaluated(0); label nEvaluated(0);
@ -71,9 +67,9 @@ bool Foam::GeometricBoundaryField<Type, PatchField, GeoMesh>::checkConsistency
if (isA<CheckPatchFieldType>(pfld)) if (isA<CheckPatchFieldType>(pfld))
{ {
const label patchi = pfld.patch().index(); const label patchi = pfld.patch().index();
oldFields[patchi] = pfld;
oldUpdated[patchi] = pfld.updated(); oldUpdated[patchi] = pfld.updated();
oldBfld[patchi] = pfld; oldManipulated[patchi] = pfld.manipulatedMatrix();
//oldManipulated[patchi] = pfld.manipulatedMatrix();
++nEvaluated; ++nEvaluated;
} }
} }
@ -117,16 +113,16 @@ bool Foam::GeometricBoundaryField<Type, PatchField, GeoMesh>::checkConsistency
if (isA<CheckPatchFieldType>(pfld)) if (isA<CheckPatchFieldType>(pfld))
{ {
const label patchi = pfld.patch().index(); const label patchi = pfld.patch().index();
const auto& oldPfld = oldBfld[patchi]; auto& oldPfld = oldFields[patchi];
bool localOk(true); bool localOk(true);
if (allOk) if (allOk)
{ {
// Only check once // Only check for first failed patch
forAll(pfld, facei) forAll(pfld, facei)
{ {
if (mag(pfld[facei]-oldPfld[facei]) > tol) if (tol < Foam::mag(pfld[facei]-oldPfld[facei]))
{ {
allOk = false; allOk = false;
localOk = false; localOk = false;
@ -137,50 +133,44 @@ bool Foam::GeometricBoundaryField<Type, PatchField, GeoMesh>::checkConsistency
if (!localOk) if (!localOk)
{ {
if (doExit) // Raise warning or error
OSstream& err =
(
exitIfBad
? FatalErrorInFunction
: WarningInFunction
);
err << "Field "
<< pfld.internalField().name()
<< " is not evaluated?"
<< " On patch " << pfld.patch().name()
<< " type " << pfld.type()
<< " : average of field = "
<< average(oldPfld)
<< ". Average of evaluated field = "
<< average(pfld)
<< ". Difference:" << average(pfld-oldPfld)
<< ". Tolerance:" << tol << endl;
if (exitIfBad)
{ {
FatalErrorInFunction << "Field " FatalError<< exit(FatalError);
<< pfld.internalField().name()
<< " is not evaluated?"
<< " On patch " << pfld.patch().name()
<< " type " << pfld.type()
<< " : average of field = "
<< average(oldPfld)
<< ". Average of evaluated field = "
<< average(pfld)
<< ". Difference:" << average(pfld-oldPfld)
<< ". Tolerance:" << tol << endl
<< exit(FatalError);
}
else
{
WarningInFunction << "Field "
<< pfld.internalField().name()
<< " is not evaluated?"
<< " On patch " << pfld.patch().name()
<< " type " << pfld.type()
<< " : average of field = "
<< average(oldPfld)
<< ". Average of evaluated field = "
<< average(pfld)
<< ". Difference:" << average(pfld-oldPfld)
<< ". Tolerance:" << tol << endl;
} }
} }
// Restore bfld, updated // Restore patch field values and states
static_cast<Field<Type>&>(pfld) = std::move(oldPfld);
pfld.setUpdated(oldUpdated[patchi]); pfld.setUpdated(oldUpdated[patchi]);
static_cast<Field<Type>&>(pfld) = std::move(oldBfld[patchi]); pfld.setManipulated(oldManipulated[patchi]);
//pfld.setManipulated(oldManipulated[patchi]);
} }
} }
if (debug&2) if (debug&2)
{ {
const auto& pfld0 = this->operator[](0);
PoutInFunction PoutInFunction
<< " Result of checking for field " << " Result of checking for field "
<< pfld0.internalField().name() << " : " << allOk << endl; << bfld[0].internalField().name() << " : " << allOk << endl;
} }
return allOk; return allOk;

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2017,2022 OpenFOAM Foundation Copyright (C) 2011-2017,2022 OpenFOAM Foundation
Copyright (C) 2015-2024 OpenCFD Ltd. Copyright (C) 2015-2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -88,7 +88,8 @@ private:
// Private Member Functions // Private Member Functions
//- Helper: check if patchfields have been evaluated. If not: //- Check if patch fields have been consistently evaluated.
// If not:
// exit = true : FatalError // exit = true : FatalError
// exit = false : return bool // exit = false : return bool
template<class CheckPatchField> template<class CheckPatchField>

View File

@ -156,9 +156,9 @@ public:
// Static Member Functions // Static Member Functions
//- Return a null GeometricField (reference to a nullObject). //- Return a null GeometricField (reference to a nullObject).
static const GeometricField<Type, PatchField, GeoMesh>& null() noexcept static const this_type& null() noexcept
{ {
return NullObjectRef<GeometricField<Type, PatchField, GeoMesh>>(); return NullObjectRef<this_type>();
} }

View File

@ -318,6 +318,7 @@ void Foam::pointPatchField<Type>::evaluate(const Pstream::commsTypes)
} }
pointPatchFieldBase::setUpdated(false); pointPatchFieldBase::setUpdated(false);
pointPatchFieldBase::setManipulated(false);
} }

View File

@ -98,16 +98,6 @@ protected:
// Useful when initially constructed without a dictionary // Useful when initially constructed without a dictionary
virtual void readDict(const dictionary& dict); virtual void readDict(const dictionary& dict);
//- Set updated state
void setUpdated(bool state) noexcept
{
updated_ = state;
}
//- Set matrix manipulated state. Currently a no-op for pointPatchField.
void setManipulated(bool state) noexcept
{}
public: public:
@ -228,13 +218,24 @@ public:
return updated_; return updated_;
} }
//- Set updated state
void setUpdated(bool state) noexcept
{
updated_ = state;
}
//- True if the matrix has already been manipulated. //- True if the matrix has already been manipulated.
//- Currently ignored (always false) for pointPatchField //- Currently always false for pointPatchField
bool manipulatedMatrix() const noexcept bool manipulatedMatrix() const noexcept
{ {
return false; return false;
} }
//- Set matrix manipulated state.
//- Currently a no-op for pointPatchField.
void setManipulated(bool state) noexcept
{}
// Check // Check
@ -262,6 +263,9 @@ public:
//- The value_type for the patch field //- The value_type for the patch field
typedef Type value_type; typedef Type value_type;
//- The component type for patch field
typedef typename pTraits<Type>::cmptType cmptType;
//- The internal field type associated with the patch field //- The internal field type associated with the patch field
typedef DimensionedField<Type, pointMesh> Internal; typedef DimensionedField<Type, pointMesh> Internal;

View File

@ -37,6 +37,7 @@ License
#include "IOobject.H" #include "IOobject.H"
#include "dynamicCode.H" #include "dynamicCode.H"
#include "simpleObjectRegistry.H" #include "simpleObjectRegistry.H"
#include "MemoryPool.H"
#include "sigFpe.H" #include "sigFpe.H"
#include "sigInt.H" #include "sigInt.H"
#include "sigQuit.H" #include "sigQuit.H"
@ -2182,6 +2183,9 @@ void Foam::argList::parse
sigQuit::set(bannerEnabled()); sigQuit::set(bannerEnabled());
sigSegv::set(bannerEnabled()); sigSegv::set(bannerEnabled());
// Create memory pool (if any) after MPI has been setup
MemoryPool::create(bannerEnabled());
if (UPstream::master() && bannerEnabled()) if (UPstream::master() && bannerEnabled())
{ {
Info<< "fileModificationChecking : " Info<< "fileModificationChecking : "

View File

@ -0,0 +1,116 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2025 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Class
Foam::MemoryPool
Description
Optional memory management using a memory pool such as Umpire
(https://github.com/LLNL/Umpire).
When compiled with Umpire, its use can be controlled by the
\c FOAM_MEMORY_POOL environment variable, or the
\c memory_pool Optimisation switch (etc/controlDict).
It currently looks for any of the following entries, in this order:
- true - same as \em "host"
- false/none - disabled.
- \em "host" - uses host memory pool
- \em "system" - same as \em "host"
- \em "device" - uses device memory pool
- \em "managed" - uses managed host/device memory pool
.
The parameters "size=nn" and "incr=nn" (in MegaBytes) can be used
to specify alternatives to the default sizing.
\*---------------------------------------------------------------------------*/
#ifndef Foam_MemoryPool_H
#define Foam_MemoryPool_H
#include <cstdint> // For size_t
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class MemoryPool Declaration
\*---------------------------------------------------------------------------*/
class MemoryPool
{
public:
// Constructors
//- Create a memory pool instance (if not already active).
// Uses environment or etc/controlDict entry
static bool create(bool verbose = false);
// Destructor
//- Remove the memory pool instance (currently does nothing)
static void destroy(bool verbose = false);
// Member Functions
//- True if pool is active (ie, created and not suspended)
static bool active() noexcept;
//- Suspend use of memory pool (for allocation).
// \return previous suspend status
static bool suspend() noexcept;
//- Resume use of memory pool (if previously active)
static void resume() noexcept;
//- Test if given pointer belongs to the pool
static bool is_pool(void *ptr);
//- Allocate from pool (if active).
// \returns nullptr if the pool is not active
static void* try_allocate(std::size_t nbytes);
//- Deallocate a pointer managed by the pool
// \returns True if a nullptr (no-op) or when the pointer was
// managed by the pool.
static bool try_deallocate(void *ptr);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2018-2024 OpenCFD Ltd. Copyright (C) 2018-2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -89,7 +89,11 @@ void Foam::pointBoundaryMesh::calcGroupIDs() const
// Remove groups that clash with patch names // Remove groups that clash with patch names
forAll(patches, patchi) forAll(patches, patchi)
{ {
if (groupLookup.erase(patches[patchi].name())) if (groupLookup.empty())
{
break; // Early termination
}
else if (groupLookup.erase(patches[patchi].name()))
{ {
WarningInFunction WarningInFunction
<< "Removed group '" << patches[patchi].name() << "Removed group '" << patches[patchi].name()
@ -370,7 +374,7 @@ Foam::labelList Foam::pointBoundaryMesh::indices
// Only check groups if requested and they exist // Only check groups if requested and they exist
const bool checkGroups = (useGroups && this->hasGroupIDs()); const bool checkGroups = (useGroups && this->hasGroupIDs());
labelHashSet ids(0); labelHashSet ids;
if (matcher.isPattern()) if (matcher.isPattern())
{ {
@ -381,7 +385,7 @@ Foam::labelList Foam::pointBoundaryMesh::indices
{ {
if (matcher(iter.key())) if (matcher(iter.key()))
{ {
// Add patch ids associated with the group // Add ids associated with the group
ids.insert(iter.val()); ids.insert(iter.val());
} }
} }
@ -413,7 +417,7 @@ Foam::labelList Foam::pointBoundaryMesh::indices
if (iter.good()) if (iter.good())
{ {
// Hash ids associated with the group // Add ids associated with the group
ids.insert(iter.val()); ids.insert(iter.val());
} }
} }
@ -438,7 +442,7 @@ Foam::labelList Foam::pointBoundaryMesh::indices
return this->indices(matcher.front(), useGroups); return this->indices(matcher.front(), useGroups);
} }
labelHashSet ids(0); labelHashSet ids;
// Only check groups if requested and they exist // Only check groups if requested and they exist
if (useGroups && this->hasGroupIDs()) if (useGroups && this->hasGroupIDs())
@ -450,7 +454,7 @@ Foam::labelList Foam::pointBoundaryMesh::indices
{ {
if (matcher(iter.key())) if (matcher(iter.key()))
{ {
// Add patch ids associated with the group // Add ids associated with the group
ids.insert(iter.val()); ids.insert(iter.val());
} }
} }
@ -471,20 +475,20 @@ Foam::labelList Foam::pointBoundaryMesh::indices
Foam::labelList Foam::pointBoundaryMesh::indices Foam::labelList Foam::pointBoundaryMesh::indices
( (
const wordRes& select, const wordRes& allow,
const wordRes& ignore, const wordRes& deny,
const bool useGroups const bool useGroups
) const ) const
{ {
//return mesh().boundaryMesh().indices(select, ignore, useGroups); if (allow.empty() && deny.empty())
if (ignore.empty())
{ {
return this->indices(select, useGroups); // Fast-path: select all
return identity(this->size());
} }
const wordRes::filter matcher(select, ignore); const wordRes::filter matcher(allow, deny);
labelHashSet ids(0); labelHashSet ids;
// Only check groups if requested and they exist // Only check groups if requested and they exist
if (useGroups && this->hasGroupIDs()) if (useGroups && this->hasGroupIDs())
@ -496,7 +500,7 @@ Foam::labelList Foam::pointBoundaryMesh::indices
{ {
if (matcher(iter.key())) if (matcher(iter.key()))
{ {
// Add patch ids associated with the group // Add ids associated with the group
ids.insert(iter.val()); ids.insert(iter.val());
} }
} }

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2013 OpenFOAM Foundation Copyright (C) 2011-2013 OpenFOAM Foundation
Copyright (C) 2018-2024 OpenCFD Ltd. Copyright (C) 2018-2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -28,7 +28,9 @@ Class
Foam::pointBoundaryMesh Foam::pointBoundaryMesh
Description Description
Foam::pointBoundaryMesh A pointBoundaryMesh is a pointPatch list with registered IO,
a reference to the associated pointMesh,
with additional search methods etc.
SourceFiles SourceFiles
pointBoundaryMesh.C pointBoundaryMesh.C
@ -102,10 +104,10 @@ public:
// Constructors // Constructors
//- Construct from polyBoundaryMesh //- Construct from pointMesh and polyBoundaryMesh
pointBoundaryMesh(const pointMesh&, const polyBoundaryMesh&); pointBoundaryMesh(const pointMesh&, const polyBoundaryMesh&);
//- Construct from IOobject and polyBoundaryMesh //- Construct from IOobject, pointMesh and polyBoundaryMesh
pointBoundaryMesh pointBoundaryMesh
( (
const IOobject& io, const IOobject& io,
@ -141,24 +143,29 @@ public:
//- Return a list of physical types //- Return a list of physical types
wordList physicalTypes() const; wordList physicalTypes() const;
//- Return (sorted) patch indices for all matches. //- The (sorted) patch indices for all matches,
// A no-op (returns empty list) for an empty matcher //- optionally matching patch groups.
// \returns an empty list for an empty matcher
labelList indices(const wordRe& matcher, const bool useGroups) const; labelList indices(const wordRe& matcher, const bool useGroups) const;
//- Return (sorted) patch indices for all matches. //- The (sorted) patch indices for all matches,
// A no-op (returns empty list) for an empty matcher //- optionally matching patch groups.
// \returns an empty list for an empty matcher
labelList indices(const wordRes& matcher, const bool useGroups) const; labelList indices(const wordRes& matcher, const bool useGroups) const;
//- Return (sorted) patch indices for all selected matches that //- The (sorted) patch indices: logic as per Foam::wordRes::filter,
//- are not ignored. //- optionally matching patch groups.
//- The selection logic as per Foam::wordRes::filter. //
// Optionally matches patch groups. // An empty \em allow accepts everything not in \em deny.
// A no-op (returns empty list) for an empty select matcher // A literal \em allow match has higher priority than any \em deny.
// A regex \em allow match has lower priority than any \em deny.
//
// \returns identity list when allow/deny are both empty.
labelList indices labelList indices
( (
const wordRes& select, const wordRes& allow,
const wordRes& ignore, const wordRes& deny,
const bool useGroups const bool useGroups //!< Match patch groups
) const; ) const;
//- Find patch index given a name //- Find patch index given a name

View File

@ -40,96 +40,6 @@ namespace Foam
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
template<>
void Foam::mapDistribute::transform::operator()
(
const vectorTensorTransform&,
const bool,
List<label>&
) const {}
template<>
void Foam::mapDistribute::transform::operator()
(
const coupledPolyPatch&,
UList<label>&
) const {}
template<>
void Foam::mapDistribute::transform::operator()
(
const coupledPolyPatch&,
Map<label>&
) const {}
template<>
void Foam::mapDistribute::transform::operator()
(
const coupledPolyPatch&,
EdgeMap<label>&
) const {}
template<>
void Foam::mapDistribute::transform::operator()
(
const vectorTensorTransform&,
const bool,
List<scalar>&
) const {}
template<>
void Foam::mapDistribute::transform::operator()
(
const coupledPolyPatch&,
UList<scalar>&
) const {}
template<>
void Foam::mapDistribute::transform::operator()
(
const coupledPolyPatch&,
Map<scalar>&
) const {}
template<>
void Foam::mapDistribute::transform::operator()
(
const coupledPolyPatch&,
EdgeMap<scalar>&
) const {}
template<>
void Foam::mapDistribute::transform::operator()
(
const vectorTensorTransform&,
const bool,
List<bool>&
) const {}
template<>
void Foam::mapDistribute::transform::operator()
(
const coupledPolyPatch&,
UList<bool>&
) const {}
template<>
void Foam::mapDistribute::transform::operator()
(
const coupledPolyPatch&,
Map<bool>&
) const {}
template<>
void Foam::mapDistribute::transform::operator()
(
const coupledPolyPatch&,
EdgeMap<bool>&
) const {}
void Foam::mapDistribute::printLayout(Ostream& os) const void Foam::mapDistribute::printLayout(Ostream& os) const
{ {
mapDistributeBase::printLayout(os); mapDistributeBase::printLayout(os);

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2015-2023 OpenCFD Ltd. Copyright (C) 2015-2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -176,25 +176,25 @@ class mapDistribute
//- Helper function: copy transformElements without transformation //- Helper function: copy transformElements without transformation
template<class T> template<class T>
void applyDummyTransforms(List<T>& field) const; void applyDummyTransforms(UList<T>& field) const;
template<class T, class TransformOp> template<class T, class TransformOp>
void applyTransforms void applyTransforms
( (
const globalIndexAndTransform& globalTransforms, const globalIndexAndTransform& globalTransforms,
List<T>& field, UList<T>& field,
const TransformOp& top const TransformOp& top
) const; ) const;
//- Helper function: copy transformElements without transformation //- Helper function: copy transformElements without transformation
template<class T> template<class T>
void applyDummyInverseTransforms(List<T>& field) const; void applyDummyInverseTransforms(UList<T>& field) const;
template<class T, class TransformOp> template<class T, class TransformOp>
void applyInverseTransforms void applyInverseTransforms
( (
const globalIndexAndTransform& globalTransforms, const globalIndexAndTransform& globalTransforms,
List<T>& field, UList<T>& field,
const TransformOp& top const TransformOp& top
) const; ) const;
@ -219,11 +219,14 @@ public:
( (
const vectorTensorTransform& vt, const vectorTensorTransform& vt,
const bool forward, const bool forward,
List<Type>& fld UList<Type>& fld
) const ) const
{ {
const tensor T(forward ? vt.R() : vt.R().T()); if constexpr (is_rotational_vectorspace_v<Type>)
transformList(T, fld); {
const tensor rot(forward ? vt.R() : vt.R().T());
transformList(rot, fld);
}
} }
template<class Type> template<class Type>
@ -234,9 +237,13 @@ public:
List<List<Type>>& flds List<List<Type>>& flds
) const ) const
{ {
for (List<Type>& fld : flds) if constexpr (is_rotational_vectorspace_v<Type>)
{ {
operator()(vt, forward, fld); const tensor rot(forward ? vt.R() : vt.R().T());
for (auto& fld : flds)
{
transformList(rot, fld);
}
} }
} }
@ -244,9 +251,12 @@ public:
template<class Type> template<class Type>
void operator()(const coupledPolyPatch& cpp, UList<Type>& fld) const void operator()(const coupledPolyPatch& cpp, UList<Type>& fld) const
{ {
if (!cpp.parallel()) if constexpr (is_rotational_vectorspace_v<Type>)
{ {
transformList(cpp.forwardT(), fld); if (!cpp.parallel())
{
transformList(cpp.forwardT(), fld);
}
} }
} }
@ -255,9 +265,12 @@ public:
void operator()(const coupledPolyPatch& cpp, Container<Type>& map) void operator()(const coupledPolyPatch& cpp, Container<Type>& map)
const const
{ {
if (!cpp.parallel()) if constexpr (is_rotational_vectorspace_v<Type>)
{ {
transformList(cpp.forwardT(), map); if (!cpp.parallel())
{
transformList(cpp.forwardT(), map);
}
} }
} }
}; };
@ -271,17 +284,16 @@ public:
( (
const vectorTensorTransform& vt, const vectorTensorTransform& vt,
const bool forward, const bool forward,
List<point>& fld UList<point>& fld
) const ) const
{ {
pointField pfld(std::move(fld));
if (forward) if (forward)
{ {
fld = vt.transformPosition(pfld); vt.transformPositionList(fld);
} }
else else
{ {
fld = vt.invTransformPosition(pfld); vt.invTransformPositionList(fld);
} }
} }
@ -292,9 +304,19 @@ public:
List<List<point>>& flds List<List<point>>& flds
) const ) const
{ {
for (List<point>& fld : flds) if (forward)
{ {
operator()(vt, forward, fld); for (auto& fld : flds)
{
vt.transformPositionList(fld);
}
}
else
{
for (auto& fld : flds)
{
vt.invTransformPositionList(fld);
}
} }
} }
@ -682,86 +704,6 @@ public:
}; };
// Template specialisation for primitives that do not need transform
template<>
void mapDistribute::transform::operator()
(
const vectorTensorTransform&,
const bool,
List<label>&
) const;
template<>
void mapDistribute::transform::operator()
(
const coupledPolyPatch&,
UList<label>&
) const;
template<>
void mapDistribute::transform::operator()
(
const coupledPolyPatch&,
Map<label>&
) const;
template<>
void mapDistribute::transform::operator()
(
const coupledPolyPatch&,
EdgeMap<label>&
) const;
template<>
void mapDistribute::transform::operator()
(
const coupledPolyPatch&,
UList<scalar>&
) const;
template<>
void mapDistribute::transform::operator()
(
const vectorTensorTransform&,
const bool,
List<scalar>&
) const;
template<>
void mapDistribute::transform::operator()
(
const coupledPolyPatch&,
Map<scalar>&
) const;
template<>
void mapDistribute::transform::operator()
(
const coupledPolyPatch&,
EdgeMap<scalar>&
) const;
template<>
void mapDistribute::transform::operator()
(
const coupledPolyPatch& cpp,
UList<bool>& fld
) const;
template<>
void mapDistribute::transform::operator()
(
const vectorTensorTransform&,
const bool,
List<bool>&
) const;
template<>
void mapDistribute::transform::operator()
(
const coupledPolyPatch&,
Map<bool>&
) const;
template<>
void mapDistribute::transform::operator()
(
const coupledPolyPatch&,
EdgeMap<bool>&
) const;
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam } // End namespace Foam

View File

@ -235,7 +235,7 @@ protected:
static void flipAndCombine static void flipAndCombine
( (
//! [in,out] The left of binary combine operation //! [in,out] The left of binary combine operation
List<T>& lhs, UList<T>& lhs,
//! The right of binary combine operation //! The right of binary combine operation
const UList<T>& rhs, const UList<T>& rhs,
//! The mapping indices //! The mapping indices
@ -254,8 +254,8 @@ protected:
static void accessAndFlip static void accessAndFlip
( (
//! [out] The result values //! [out] The result values
List<T>& output, UList<T>& output,
//! [out] The input values //! The input values
const UList<T>& values, const UList<T>& values,
//! The mapping indices //! The mapping indices
const labelUList& map, const labelUList& map,
@ -270,7 +270,7 @@ protected:
template<class T, class NegateOp> template<class T, class NegateOp>
static List<T> accessAndFlip static List<T> accessAndFlip
( (
//! [out] The input values //! The input values
const UList<T>& values, const UList<T>& values,
//! The mapping indices //! The mapping indices
const labelUList& map, const labelUList& map,
@ -895,7 +895,7 @@ public:
static void distribute static void distribute
( (
const UPstream::commsTypes commsType, const UPstream::commsTypes commsType,
const List<labelPair>& schedule, const UList<labelPair>& schedule,
const label constructSize, const label constructSize,
const labelListList& subMap, const labelListList& subMap,
const bool subHasFlip, const bool subHasFlip,
@ -918,7 +918,7 @@ public:
static void distribute static void distribute
( (
const UPstream::commsTypes commsType, const UPstream::commsTypes commsType,
const List<labelPair>& schedule, const UList<labelPair>& schedule,
const label constructSize, const label constructSize,
const labelListList& subMap, const labelListList& subMap,
const bool subHasFlip, const bool subHasFlip,
@ -1078,7 +1078,7 @@ public:
//- Do all sends using PstreamBuffers //- Do all sends using PstreamBuffers
template<class T> template<class T>
void send(PstreamBuffers& pBufs, const List<T>& field) const; void send(PstreamBuffers& pBufs, const UList<T>& field) const;
//- Do all receives using PstreamBuffers //- Do all receives using PstreamBuffers
template<class T> template<class T>

View File

@ -35,7 +35,7 @@ License
template<class T, class CombineOp, class NegateOp> template<class T, class CombineOp, class NegateOp>
void Foam::mapDistributeBase::flipAndCombine void Foam::mapDistributeBase::flipAndCombine
( (
List<T>& lhs, UList<T>& lhs,
const UList<T>& rhs, const UList<T>& rhs,
const labelUList& map, const labelUList& map,
@ -46,6 +46,9 @@ void Foam::mapDistributeBase::flipAndCombine
{ {
const label len = map.size(); const label len = map.size();
// FULLDEBUG: if (lhs.size() < max(map)) FatalError ...;
// FULLDEBUG: if (rhs.size() < len) FatalError ...;
if (hasFlip) if (hasFlip)
{ {
for (label i = 0; i < len; ++i) for (label i = 0; i < len; ++i)
@ -82,7 +85,7 @@ void Foam::mapDistributeBase::flipAndCombine
template<class T, class NegateOp> template<class T, class NegateOp>
void Foam::mapDistributeBase::accessAndFlip void Foam::mapDistributeBase::accessAndFlip
( (
List<T>& output, UList<T>& output,
const UList<T>& values, const UList<T>& values,
const labelUList& map, const labelUList& map,
const bool hasFlip, const bool hasFlip,
@ -91,6 +94,7 @@ void Foam::mapDistributeBase::accessAndFlip
{ {
const label len = map.size(); const label len = map.size();
// FULLDEBUG: if (values.size() < max(map)) FatalError ...;
// FULLDEBUG: if (output.size() < len) FatalError ...; // FULLDEBUG: if (output.size() < len) FatalError ...;
if (hasFlip) if (hasFlip)
@ -447,7 +451,7 @@ template<class T, class CombineOp, class NegateOp>
void Foam::mapDistributeBase::distribute void Foam::mapDistributeBase::distribute
( (
const UPstream::commsTypes commsType, const UPstream::commsTypes commsType,
const List<labelPair>& schedule, const UList<labelPair>& schedule,
const label constructSize, const label constructSize,
const labelListList& subMap, const labelListList& subMap,
const bool subHasFlip, const bool subHasFlip,
@ -894,7 +898,7 @@ template<class T, class NegateOp>
void Foam::mapDistributeBase::distribute void Foam::mapDistributeBase::distribute
( (
const UPstream::commsTypes commsType, const UPstream::commsTypes commsType,
const List<labelPair>& schedule, const UList<labelPair>& schedule,
const label constructSize, const label constructSize,
const labelListList& subMap, const labelListList& subMap,
const bool subHasFlip, const bool subHasFlip,
@ -1332,7 +1336,7 @@ template<class T>
void Foam::mapDistributeBase::send void Foam::mapDistributeBase::send
( (
PstreamBuffers& pBufs, PstreamBuffers& pBufs,
const List<T>& field const UList<T>& field
) const ) const
{ {
// Stream data into buffer // Stream data into buffer
@ -1482,13 +1486,11 @@ void Foam::mapDistributeBase::distribute
const int tag const int tag
) const ) const
{ {
values.shrink(); List<T> work(std::move(values));
List<T>& list = static_cast<List<T>&>(values); distribute(commsType, work, tag);
distribute(commsType, list, tag); values = std::move(work);
values.setCapacity(list.size());
} }

View File

@ -35,7 +35,7 @@ License
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
template<class T> template<class T>
void Foam::mapDistribute::applyDummyTransforms(List<T>& field) const void Foam::mapDistribute::applyDummyTransforms(UList<T>& field) const
{ {
forAll(transformElements_, trafoI) forAll(transformElements_, trafoI)
{ {
@ -51,7 +51,7 @@ void Foam::mapDistribute::applyDummyTransforms(List<T>& field) const
template<class T> template<class T>
void Foam::mapDistribute::applyDummyInverseTransforms(List<T>& field) const void Foam::mapDistribute::applyDummyInverseTransforms(UList<T>& field) const
{ {
forAll(transformElements_, trafoI) forAll(transformElements_, trafoI)
{ {
@ -70,7 +70,7 @@ template<class T, class TransformOp> //, class CombineOp>
void Foam::mapDistribute::applyTransforms void Foam::mapDistribute::applyTransforms
( (
const globalIndexAndTransform& globalTransforms, const globalIndexAndTransform& globalTransforms,
List<T>& field, UList<T>& field,
const TransformOp& top const TransformOp& top
) const ) const
{ {
@ -100,7 +100,7 @@ template<class T, class TransformOp> //, class CombineOp>
void Foam::mapDistribute::applyInverseTransforms void Foam::mapDistribute::applyInverseTransforms
( (
const globalIndexAndTransform& globalTransforms, const globalIndexAndTransform& globalTransforms,
List<T>& field, UList<T>& field,
const TransformOp& top const TransformOp& top
) const ) const
{ {
@ -193,13 +193,11 @@ void Foam::mapDistribute::distribute
const int tag const int tag
) const ) const
{ {
fld.shrink(); List<T> work(std::move(fld));
List<T>& list = static_cast<List<T>&>(fld); distribute(commsType, work, dummyTransform, tag);
distribute(commsType, list, dummyTransform, tag); fld = std::move(work);
fld.setCapacity(list.size());
} }

View File

@ -93,7 +93,11 @@ void Foam::polyBoundaryMesh::calcGroupIDs() const
// Remove groups that clash with patch names // Remove groups that clash with patch names
forAll(patches, patchi) forAll(patches, patchi)
{ {
if (groupLookup.erase(patches[patchi].name())) if (groupLookup.empty())
{
break; // Early termination
}
else if (groupLookup.erase(patches[patchi].name()))
{ {
WarningInFunction WarningInFunction
<< "Removed group '" << patches[patchi].name() << "Removed group '" << patches[patchi].name()
@ -782,7 +786,7 @@ Foam::labelList Foam::polyBoundaryMesh::indices
// Only check groups if requested and they exist // Only check groups if requested and they exist
const bool checkGroups = (useGroups && this->hasGroupIDs()); const bool checkGroups = (useGroups && this->hasGroupIDs());
labelHashSet ids(0); labelHashSet ids;
if (matcher.isPattern()) if (matcher.isPattern())
{ {
@ -850,7 +854,7 @@ Foam::labelList Foam::polyBoundaryMesh::indices
return this->indices(matcher.front(), useGroups); return this->indices(matcher.front(), useGroups);
} }
labelHashSet ids(0); labelHashSet ids;
// Only check groups if requested and they exist // Only check groups if requested and they exist
if (useGroups && this->hasGroupIDs()) if (useGroups && this->hasGroupIDs())
@ -883,19 +887,20 @@ Foam::labelList Foam::polyBoundaryMesh::indices
Foam::labelList Foam::polyBoundaryMesh::indices Foam::labelList Foam::polyBoundaryMesh::indices
( (
const wordRes& select, const wordRes& allow,
const wordRes& ignore, const wordRes& deny,
const bool useGroups const bool useGroups
) const ) const
{ {
if (ignore.empty()) if (allow.empty() && deny.empty())
{ {
return this->indices(select, useGroups); // Fast-path: select all
return identity(this->size());
} }
const wordRes::filter matcher(select, ignore); const wordRes::filter matcher(allow, deny);
labelHashSet ids(0); labelHashSet ids;
// Only check groups if requested and they exist // Only check groups if requested and they exist
if (useGroups && this->hasGroupIDs()) if (useGroups && this->hasGroupIDs())
@ -1069,7 +1074,7 @@ Foam::labelHashSet Foam::polyBoundaryMesh::patchSet
const bool useGroups const bool useGroups
) const ) const
{ {
labelHashSet ids(0); labelHashSet ids;
if (select.empty()) if (select.empty())
{ {
return ids; return ids;

View File

@ -28,8 +28,9 @@ Class
Foam::polyBoundaryMesh Foam::polyBoundaryMesh
Description Description
A polyBoundaryMesh is a polyPatch list with additional search methods A polyBoundaryMesh is a polyPatch list with registered IO,
and registered IO. a reference to the associated polyMesh,
with additional search methods etc.
SourceFiles SourceFiles
polyBoundaryMesh.C polyBoundaryMesh.C
@ -259,34 +260,37 @@ public:
labelRange range(const label patchi) const; labelRange range(const label patchi) const;
//- Return (sorted) patch indices for all matches. //- The (sorted) patch indices for all matches,
// Optionally matches patch groups. //- optionally matching patch groups.
// A no-op (returns empty list) for an empty matcher // \returns an empty list for an empty matcher
labelList indices labelList indices
( (
const wordRe& matcher, const wordRe& matcher,
const bool useGroups = true const bool useGroups = true
) const; ) const;
//- Return (sorted) patch indices for all matches. //- The (sorted) patch indices for all matches,
// Optionally matches patch groups. //- optionally matching patch groups.
// A no-op (returns empty list) for an empty matcher // \returns an empty list for an empty matcher
labelList indices labelList indices
( (
const wordRes& matcher, const wordRes& matcher,
const bool useGroups = true const bool useGroups = true //!< Match patch groups
) const; ) const;
//- Return (sorted) patch indices for all selected matches that //- The (sorted) patch indices: logic as per Foam::wordRes::filter,
//- are not ignored. //- optionally matching patch groups.
//- The selection logic as per Foam::wordRes::filter. //
// Optionally matches patch groups. // An empty \em allow accepts everything not in \em deny.
// A no-op (returns empty list) for an empty select matcher // A literal \em allow match has higher priority than any \em deny.
// A regex \em allow match has lower priority than any \em deny.
//
// \returns identity list when allow/deny are both empty.
labelList indices labelList indices
( (
const wordRes& select, const wordRes& allow,
const wordRes& ignore, const wordRes& deny,
const bool useGroups = true const bool useGroups = true //!< Match patch groups
) const; ) const;
//- Return (sorted) patch indices for patches that match the //- Return (sorted) patch indices for patches that match the

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2020 OpenCFD Ltd. Copyright (C) 2020-2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -47,17 +47,27 @@ namespace Foam
class dummyTransform class dummyTransform
{ {
public: public:
template<class T> template<class T>
void operator() void operator()
( (
const vectorTensorTransform& vt, const vectorTensorTransform& vt,
const bool forward, const bool forward,
List<T>& fld UList<T>& fld
) const
{}
template<class Type>
void operator()
(
const vectorTensorTransform& vt,
const bool forward,
List<List<Type>>& flds
) const ) const
{} {}
template<class T> template<class T>
void operator()(const coupledPolyPatch& cpp, Field<T>& fld) const void operator()(const coupledPolyPatch& cpp, UList<T>& fld) const
{} {}
template<class T, template<class> class Container> template<class T, template<class> class Container>

View File

@ -1135,11 +1135,7 @@ void Foam::syncTools::syncBoundaryFaceList
pp.start()-boundaryOffset pp.start()-boundaryOffset
); );
auto& fakeList = const_cast<List<T>&> top(procPatch, recvFld);
(
static_cast<const List<T>&>(recvFld)
);
top(procPatch, fakeList);
SubList<T> patchValues SubList<T> patchValues
( (

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2016-2024 OpenCFD Ltd. Copyright (C) 2016-2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -205,7 +205,11 @@ void Foam::ZoneMesh<ZoneType, MeshType>::calcGroupIDs() const
// Remove groups that clash with zone names // Remove groups that clash with zone names
forAll(zones, zonei) forAll(zones, zonei)
{ {
if (groupLookup.erase(zones[zonei].name())) if (groupLookup.empty())
{
break; // Early termination
}
else if (groupLookup.erase(zones[zonei].name()))
{ {
WarningInFunction WarningInFunction
<< "Removed group '" << zones[zonei].name() << "Removed group '" << zones[zonei].name()
@ -541,7 +545,7 @@ Foam::labelList Foam::ZoneMesh<ZoneType, MeshType>::indices
// Only check groups if requested and they exist // Only check groups if requested and they exist
const bool checkGroups = (useGroups && this->hasGroupIDs()); const bool checkGroups = (useGroups && this->hasGroupIDs());
labelHashSet ids(0); labelHashSet ids;
if (checkGroups) if (checkGroups)
{ {
@ -557,7 +561,7 @@ Foam::labelList Foam::ZoneMesh<ZoneType, MeshType>::indices
{ {
if (matcher(iter.key())) if (matcher(iter.key()))
{ {
// Hash ids associated with the group // Add ids associated with the group
ids.insert(iter.val()); ids.insert(iter.val());
} }
} }
@ -589,7 +593,7 @@ Foam::labelList Foam::ZoneMesh<ZoneType, MeshType>::indices
if (iter.good()) if (iter.good())
{ {
// Hash ids associated with the group // Add ids associated with the group
ids.insert(iter.val()); ids.insert(iter.val());
} }
} }
@ -615,7 +619,7 @@ Foam::labelList Foam::ZoneMesh<ZoneType, MeshType>::indices
return this->indices(matcher.front(), useGroups); return this->indices(matcher.front(), useGroups);
} }
labelHashSet ids(0); labelHashSet ids;
// Only check groups if requested and they exist // Only check groups if requested and they exist
if (useGroups && this->hasGroupIDs()) if (useGroups && this->hasGroupIDs())
@ -627,7 +631,7 @@ Foam::labelList Foam::ZoneMesh<ZoneType, MeshType>::indices
{ {
if (matcher(iter.key())) if (matcher(iter.key()))
{ {
// Hash the ids associated with the group // Add ids associated with the group
ids.insert(iter.val()); ids.insert(iter.val());
} }
} }
@ -649,19 +653,20 @@ Foam::labelList Foam::ZoneMesh<ZoneType, MeshType>::indices
template<class ZoneType, class MeshType> template<class ZoneType, class MeshType>
Foam::labelList Foam::ZoneMesh<ZoneType, MeshType>::indices Foam::labelList Foam::ZoneMesh<ZoneType, MeshType>::indices
( (
const wordRes& select, const wordRes& allow,
const wordRes& ignore, const wordRes& deny,
const bool useGroups const bool useGroups
) const ) const
{ {
if (ignore.empty()) if (allow.empty() && deny.empty())
{ {
return this->indices(select, useGroups); // Fast-path: select all
return identity(this->size());
} }
const wordRes::filter matcher(select, ignore); const wordRes::filter matcher(allow, deny);
labelHashSet ids(0); labelHashSet ids;
// Only check groups if requested and they exist // Only check groups if requested and they exist
if (useGroups && this->hasGroupIDs()) if (useGroups && this->hasGroupIDs())
@ -673,7 +678,7 @@ Foam::labelList Foam::ZoneMesh<ZoneType, MeshType>::indices
{ {
if (matcher(iter.key())) if (matcher(iter.key()))
{ {
// Add patch ids associated with the group // Add ids associated with the group
ids.insert(iter.val()); ids.insert(iter.val());
} }
} }

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2016-2024 OpenCFD Ltd. Copyright (C) 2016-2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -227,34 +227,37 @@ public:
wordList sortedNames(const wordRes& matcher) const; wordList sortedNames(const wordRes& matcher) const;
//- Return (sorted) zone indices for all matches //- The (sorted) patch indices for all matches,
// Optionally matches zone groups. //- optionally matching zone groups.
// A no-op (returns empty list) for an empty matcher // \returns an empty list for an empty matcher
labelList indices labelList indices
( (
const wordRe& matcher, const wordRe& matcher,
const bool useGroups = true const bool useGroups = true
) const; ) const;
//- Return (sorted) zone indices for all matches //- The (sorted) patch indices for all matches,
// Optionally matches zone groups. //- optionally matching zone groups.
// A no-op (returns empty list) for an empty matcher // \returns an empty list for an empty matcher
labelList indices labelList indices
( (
const wordRes& matcher, const wordRes& matcher,
const bool useGroups = true const bool useGroups = true
) const; ) const;
//- Return (sorted) zone indices for all selected matches that //- The (sorted) patch indices: logic as per Foam::wordRes::filter,
//- are not ignored. //- optionally matching zone groups.
//- The selection logic as per Foam::wordRes::filter. //
// Optionally matches patch groups. // An empty \em allow accepts everything not in \em deny.
// A no-op (returns empty list) for an empty select matcher // A literal \em allow match has higher priority than any \em deny.
// A regex \em allow match has lower priority than any \em deny.
//
// \returns identity list when allow/deny are both empty.
labelList indices labelList indices
( (
const wordRes& select, const wordRes& allow,
const wordRes& ignore, const wordRes& deny,
const bool useGroups = true const bool useGroups = true //!< Match zone groups
) const; ) const;
//- Zone index for the first match, return -1 if not found //- Zone index for the first match, return -1 if not found

View File

@ -6,6 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -60,6 +61,13 @@ Foam::vectorTensorTransform::vectorTensorTransform(Istream& is)
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::vectorTensorTransform::checkRotation(const scalar tol)
{
// Detect identity and zero rotations
hasR_ = !(R_.is_identity(tol) || Foam::mag(R_) < tol);
}
Foam::word Foam::name(const vectorTensorTransform& s) Foam::word Foam::name(const vectorTensorTransform& s)
{ {
OStringStream buf; OStringStream buf;
@ -70,32 +78,6 @@ Foam::word Foam::name(const vectorTensorTransform& s)
} }
template<>
Foam::tmp<Foam::Field<bool>> Foam::vectorTensorTransform::transform
(
const Field<bool>& fld
) const
{
return fld;
}
template<>
Foam::tmp<Foam::Field<Foam::label>> Foam::vectorTensorTransform::transform
(
const Field<label>& fld
) const
{
return fld;
}
template<>
Foam::tmp<Foam::Field<Foam::scalar>> Foam::vectorTensorTransform::transform
(
const Field<scalar>& fld
) const
{
return fld;
}
// * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * // // * * * * * * * * * * * * * * * IOstream Operators * * * * * * * * * * * * //
Foam::Istream& Foam::operator>>(Istream& is, vectorTensorTransform& tr) Foam::Istream& Foam::operator>>(Istream& is, vectorTensorTransform& tr)

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2020 OpenCFD Ltd. Copyright (C) 2020-2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -34,12 +34,12 @@ Description
SourceFiles SourceFiles
vectorTensorTransformI.H vectorTensorTransformI.H
vectorTensorTransform.C vectorTensorTransform.C
vectorTensorTransformTemplates.C vectorTensorTransform.txx
\*---------------------------------------------------------------------------*/ \*---------------------------------------------------------------------------*/
#ifndef vectorTensorTransform_H #ifndef Foam_vectorTensorTransform_H
#define vectorTensorTransform_H #define Foam_vectorTensorTransform_H
#include "tensor.H" #include "tensor.H"
#include "word.H" #include "word.H"
@ -126,39 +126,57 @@ public:
// Member Functions // Member Functions
// Access // Access
inline const vector& t() const; //- True if it has a non-identity rotation tensor
bool hasR() const noexcept { return hasR_; }
inline const tensor& R() const; //- The translation vector
const vector& t() const noexcept { return t_; }
inline bool hasR() const; //- The (forward) rotation tensor
const tensor& R() const noexcept { return R_; }
// Edit // Edit
inline vector& t(); //- Non-const access to the translation vector
vector& t() noexcept { return t_; }
inline tensor& R(); //- Non-const access to the rotation tensor. Sets hasR = true
inline tensor& R() noexcept;
//- Test for identity rotation and set hasR accordingly
void checkRotation(const scalar tol = ROOTVSMALL);
// Transform // Transform
//- Transform the given position //- Transform the given position
inline vector transformPosition(const vector& v) const; inline vector transformPosition(const vector& v) const;
//- Transform the given pointField //- Transform the given field of points
inline pointField transformPosition(const pointField& pts) const; inline pointField transformPosition(const pointField& pts) const;
//- Inverse transform the given position //- Inplace transform the given points
inline vector invTransformPosition(const vector& v) const; inline void transformPositionList(UList<point>& pts) const;
//- Inverse transform the given pointField //- Inverse transform the given position
inline pointField invTransformPosition(const pointField& pts) const; inline vector invTransformPosition(const vector& v) const;
//- Transform the given field //- Inverse transform the given field of points
template<class Type> inline pointField invTransformPosition(const pointField& pts) const;
tmp<Field<Type>> transform(const Field<Type>&) const;
//- Inplace inverse transform the given points
inline void invTransformPositionList(UList<point>& pts) const;
//- Transform the given field
template<class Type>
tmp<Field<Type>> transform(const Field<Type>& fld) const;
//- Inplace transform the given field
template<class Type>
void transformList(UList<Type>& fld) const;
// Member Operators // Member Operators
@ -196,18 +214,6 @@ inline vectorTensorTransform inv(const vectorTensorTransform& tr);
//- Return a string representation of a vectorTensorTransform //- Return a string representation of a vectorTensorTransform
word name(const vectorTensorTransform&); word name(const vectorTensorTransform&);
//- Template specialisations
template<>
tmp<Field<bool>> vectorTensorTransform::transform(const Field<bool>&) const;
template<>
tmp<Field<label>> vectorTensorTransform::transform(const Field<label>&) const;
template<>
tmp<Field<scalar>> vectorTensorTransform::transform(const Field<scalar>&)
const;
// * * * * * * * * * * * * * * * Global Operators * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Global Operators * * * * * * * * * * * * * //
inline bool operator== inline bool operator==
@ -262,7 +268,7 @@ inline vectorTensorTransform operator&
#include "vectorTensorTransformI.H" #include "vectorTensorTransformI.H"
#ifdef NoRepository #ifdef NoRepository
#include "vectorTensorTransformTemplates.C" #include "vectorTensorTransform.txx"
#endif #endif
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //

View File

@ -6,6 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -33,9 +34,16 @@ Foam::tmp<Foam::Field<Type>> Foam::vectorTensorTransform::transform
const Field<Type>& fld const Field<Type>& fld
) const ) const
{ {
if (hasR_) if constexpr (is_rotational_vectorspace_v<Type>)
{ {
return R() & fld; if (hasR_)
{
return (R() & fld);
}
else
{
return fld;
}
} }
else else
{ {
@ -44,4 +52,23 @@ Foam::tmp<Foam::Field<Type>> Foam::vectorTensorTransform::transform
} }
template<class Type>
void Foam::vectorTensorTransform::transformList
(
UList<Type>& fld
) const
{
if constexpr (is_rotational_vectorspace_v<Type>)
{
if (hasR_)
{
for (auto& val : fld)
{
val = (R() & val);
}
}
}
}
// ************************************************************************* // // ************************************************************************* //

View File

@ -6,6 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -66,35 +67,10 @@ inline Foam::vectorTensorTransform::vectorTensorTransform(const tensor& R)
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
inline const Foam::vector& Foam::vectorTensorTransform::t() const inline Foam::tensor& Foam::vectorTensorTransform::R() noexcept
{
return t_;
}
inline const Foam::tensor& Foam::vectorTensorTransform::R() const
{
return R_;
}
inline bool Foam::vectorTensorTransform::hasR() const
{
return hasR_;
}
inline Foam::vector& Foam::vectorTensorTransform::t()
{
return t_;
}
inline Foam::tensor& Foam::vectorTensorTransform::R()
{ {
// Assume that non-const access to R changes it from I, so set // Assume that non-const access to R changes it from I, so set
// hasR to true // hasR to true
hasR_ = true; hasR_ = true;
return R_; return R_;
@ -136,6 +112,28 @@ inline Foam::pointField Foam::vectorTensorTransform::transformPosition
} }
inline void Foam::vectorTensorTransform::transformPositionList
(
UList<point>& pts
) const
{
if (hasR_)
{
for (auto& p : pts)
{
p = t() + (R() & p);
}
}
else
{
for (auto& p : pts)
{
p += t();
}
}
}
inline Foam::vector Foam::vectorTensorTransform::invTransformPosition inline Foam::vector Foam::vectorTensorTransform::invTransformPosition
( (
const vector& v const vector& v
@ -171,6 +169,30 @@ inline Foam::pointField Foam::vectorTensorTransform::invTransformPosition
} }
inline void Foam::vectorTensorTransform::invTransformPositionList
(
UList<point>& pts
) const
{
if (hasR_)
{
const auto rot = R().T();
for (auto& p : pts)
{
p = (rot & (p - t()));
}
}
else
{
for (auto& p : pts)
{
p -= t();
}
}
}
// * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
inline void Foam::vectorTensorTransform::operator&= inline void Foam::vectorTensorTransform::operator&=

View File

@ -447,7 +447,7 @@ public:
inline constexpr IntType operator- inline constexpr IntType operator-
( (
const const_reverse_iterator& iter const const_reverse_iterator& iter
)const noexcept; ) const noexcept;
// Comparison // Comparison

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017-2022 OpenCFD Ltd. Copyright (C) 2017-2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -370,12 +370,12 @@ labelList findMatching
AccessOp aop = identityOp() AccessOp aop = identityOp()
); );
//- Return ids for items with matching names. //- Return ids for items with matching names,
// Uses a combination of allow and deny lists //- using a combination of allow and deny lists as per wordRes::filter
// //
// An empty 'allow' accepts everything not in 'deny'. // An empty \em allow accepts everything not in \em deny.
// A literal 'allow' match has higher priority than any 'deny'. // A literal \em allow match has higher priority than any \em deny.
// A regex 'allow' match has lower priority than any 'deny'. // A regex \em allow match has lower priority than any \em deny.
// //
// Example (when applied to a list of words), // Example (when applied to a list of words),
// \verbatim // \verbatim
@ -386,7 +386,7 @@ labelList findMatching
// result: (abc other val val1 wall1 wall2) // result: (abc other val val1 wall1 wall2)
// \endverbatim // \endverbatim
// //
// \return List indices for matches // \returns identity list when allow/deny are both empty.
template<class StringListType, class AccessOp = identityOp> template<class StringListType, class AccessOp = identityOp>
labelList findMatching labelList findMatching
( (

View File

@ -143,7 +143,7 @@ Foam::labelList Foam::stringListOps::findMatching
if (pred.empty()) if (pred.empty())
{ {
// Accept all // Fast-path: select all
return identity(len); return identity(len);
} }
@ -177,11 +177,10 @@ Foam::labelList Foam::stringListOps::findMatching
{ {
if (allow.empty() && deny.empty()) if (allow.empty() && deny.empty())
{ {
// Accept all // Fast-path: select all
return identity(input.size()); return identity(input.size());
} }
// Use combined accept/reject filter
const wordRes::filter pred(allow, deny); const wordRes::filter pred(allow, deny);
return stringListOps::findMatching(input, pred, aop); return stringListOps::findMatching(input, pred, aop);

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2016-2024 OpenCFD Ltd. Copyright (C) 2016-2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -99,7 +99,10 @@ public:
// No distinction made between literals and regular expressions. // No distinction made between literals and regular expressions.
static wordRes uniq(const UList<wordRe>& input); static wordRes uniq(const UList<wordRe>& input);
//- Test for a match //- Test for a match of any selectors against the text.
//
// \return \c false if no selectors are specified
// \return \c true if text matches \em any of the selectors
inline static bool match inline static bool match
( (
const UList<wordRe>& selectors, const UList<wordRe>& selectors,
@ -197,9 +200,10 @@ public:
//- No selectors defined //- No selectors defined
inline bool empty() const noexcept; inline bool empty() const noexcept;
//- True if text matches ANY of the selectors. //- Apply matcher predicate
//- Always false if entries are empty. //
// Allows use as a predicate. // \return \c false if no selectors are specified
// \return \c true if text matches \em any of the selectors
inline bool operator()(const std::string& text) const; inline bool operator()(const std::string& text) const;
private: private:
@ -209,9 +213,10 @@ public:
//- Functor wrapper of allow/deny lists of wordRe for filtering //- Functor wrapper of allow/deny lists of wordRe for filtering
// //
// An empty 'allow' accepts everything not in 'deny'. // An empty filter accepts everything.
// A literal 'allow' match has higher priority than any 'deny'. // An empty \em allow accepts everything not in \em deny.
// A regex 'allow' match has lower priority than any 'deny'. // A literal \em allow match has higher priority than any \em deny.
// A regex \em allow match has lower priority than any \em deny.
// //
// Example (when applied to a list of words), // Example (when applied to a list of words),
// \verbatim // \verbatim
@ -223,17 +228,23 @@ public:
// \endverbatim // \endverbatim
struct filter struct filter
{ {
//- Construct with 'allow' and 'deny' matchers //- Construct with \em allow and \em deny matchers
inline filter inline filter
( (
const UList<wordRe>& allow, const UList<wordRe>& allow,
const UList<wordRe>& deny const UList<wordRe>& deny
) noexcept; ) noexcept;
//- Nothing defined //- No filtering defined
inline bool empty() const noexcept; inline bool empty() const noexcept;
//- True if matched but not blocked //- True if filtering is defined
explicit operator bool() const noexcept { return !empty(); }
//- Apply filter against specified text
//
// \return \c true if no filtering has been defined
// \return \c true if matched but not blocked
inline bool operator()(const std::string& text) const; inline bool operator()(const std::string& text) const;
private: private:

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com \\ / A nd | www.openfoam.com
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2017-2022 OpenCFD Ltd. Copyright (C) 2017-2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -225,6 +225,7 @@ inline bool Foam::wordRes::matcher::empty() const noexcept
return select_.empty(); return select_.empty();
} }
inline bool Foam::wordRes::filter::empty() const noexcept inline bool Foam::wordRes::filter::empty() const noexcept
{ {
return (allow_.empty() && deny_.empty()); return (allow_.empty() && deny_.empty());
@ -241,12 +242,14 @@ inline bool Foam::wordRes::filter::operator()(const std::string& text) const
{ {
if (allow_.empty()) if (allow_.empty())
{ {
// No allow specified, so accept everything that is NOT blocked // Did not specify allow
// => accept everything that is NOT blocked
return (deny_.empty() || !wordRes::match(deny_, text)); return (deny_.empty() || !wordRes::match(deny_, text));
} }
else if (deny_.empty()) else if (deny_.empty())
{ {
// Nothing blocked, apply accept filter // Specified allow but did not specify blocked
// => select with accept filter
return wordRes::match(allow_, text); return wordRes::match(allow_, text);
} }
else else

View File

@ -1401,31 +1401,7 @@ Foam::UPstream::probeMessage
int flag = 0; int flag = 0;
MPI_Status status; MPI_Status status;
if (UPstream::commsTypes::buffered == commsType) if (UPstream::commsTypes::nonBlocking == commsType)
{
// Blocking
profilingPstream::beginTiming();
if
(
MPI_Probe
(
source,
tag,
PstreamGlobals::MPICommunicators_[communicator],
&status
)
)
{
FatalErrorInFunction
<< "MPI_Probe returned with error"
<< Foam::abort(FatalError);
}
profilingPstream::addProbeTime();
flag = 1;
}
else
{ {
// Non-blocking // Non-blocking
profilingPstream::beginTiming(); profilingPstream::beginTiming();
@ -1437,8 +1413,8 @@ Foam::UPstream::probeMessage
source, source,
tag, tag,
PstreamGlobals::MPICommunicators_[communicator], PstreamGlobals::MPICommunicators_[communicator],
&flag, &flag,
&status &status
) )
) )
{ {
@ -1449,6 +1425,30 @@ Foam::UPstream::probeMessage
profilingPstream::addRequestTime(); profilingPstream::addRequestTime();
} }
else
{
// Blocking
profilingPstream::beginTiming();
if
(
MPI_Probe
(
source,
tag,
PstreamGlobals::MPICommunicators_[communicator],
&status
)
)
{
FatalErrorInFunction
<< "MPI_Probe returned with error"
<< Foam::abort(FatalError);
}
profilingPstream::addProbeTime();
flag = 1;
}
if (flag) if (flag)
{ {

View File

@ -50,10 +50,9 @@ defineTypeNameAndDebug(removePoints, 0);
template<class T, template<class> class CombineOp> template<class T, template<class> class CombineOp>
class faceEqOp class faceEqOp
{ {
public: public:
void operator()(List<T>& x, const List<T>& y) const void operator()(List<T>& x, const UList<T>& y) const
{ {
if (y.size() > 0) if (y.size() > 0)
{ {

View File

@ -294,9 +294,9 @@ void Foam::tetDecomposer::splitBoundaryFaces
( (
mesh_, mesh_,
boundaryTris, boundaryTris,
[](faceList& result, const faceList& input) [](faceList& result, const UList<face>& input)
{ {
if (!result.size()) if (result.empty())
{ {
result = input; result = input;
} }
@ -307,9 +307,9 @@ void Foam::tetDecomposer::splitBoundaryFaces
( (
mesh_, mesh_,
boundaryQuads, boundaryQuads,
[](faceList& result, const faceList& input) [](faceList& result, const UList<face>& input)
{ {
if (!result.size()) if (result.empty())
{ {
result = input; result = input;
} }

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2016-2024 OpenCFD Ltd. Copyright (C) 2016-2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -31,36 +31,13 @@ License
#include "polyMesh.H" #include "polyMesh.H"
#include "emptyPolyPatch.H" #include "emptyPolyPatch.H"
#include "processorPolyPatch.H" #include "processorPolyPatch.H"
#include "stringListOps.H" // For stringListOps::findMatching() #include "ListOps.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
const Foam::label Foam::ensightMesh::internalZone = -1; const Foam::label Foam::ensightMesh::internalZone = -1;
// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
namespace Foam
{
// Patch names without processor patches
static wordList nonProcessorPatchNames(const polyBoundaryMesh& bmesh)
{
#ifdef FULLDEBUG
// Patches are output. Check that they are synced.
bmesh.checkParallelSync(true);
#endif
wordList patchNames(bmesh.names());
patchNames.resize(bmesh.nNonProcessor());
return patchNames;
}
} // End namespace Foam
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * // // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::ensightMesh::clear() void Foam::ensightMesh::clear()
@ -141,63 +118,69 @@ void Foam::ensightMesh::correct()
{ {
clear(); clear();
const wordRes& czMatcher = option().cellZoneSelection(); const auto& pbm = mesh_.boundaryMesh();
const wordRes& fzMatcher = option().faceZoneSelection();
// Possible cellZones // Selected patch indices
const wordList czNames = labelList patchIds;
(
if (option().useBoundaryMesh())
{
patchIds = pbm.indices
( (
option().useCellZones()
&& (!czMatcher.empty() || option().useInternalMesh())
)
? mesh_.cellZones().names()
: wordList()
);
const labelList czoneIds =
(
czMatcher.empty()
? identity(czNames.size()) // All
: czMatcher.matching(czNames) // Selected names
);
// Possible faceZones
const wordList fzNames =
(
option().useFaceZones()
? mesh_.faceZones().names()
: wordList()
);
const labelList fzoneIds =
(
fzMatcher.empty()
? identity(fzNames.size()) // All
: fzMatcher.matching(fzNames) // Selected names
);
// Possible patchNames
const wordList patchNames =
(
option().useBoundaryMesh()
? nonProcessorPatchNames(mesh_.boundaryMesh())
: wordList()
);
const labelList patchIds =
(
option().useBoundaryMesh()
? stringListOps::findMatching
(
patchNames,
option().patchSelection(), option().patchSelection(),
option().patchExclude() option().patchExclude()
) );
: labelList()
); // Prune undesirable patches - empty and processor patches
label count = 0;
for (const label patchi : patchIds)
{
const auto& pp = pbm[patchi];
if (isType<emptyPolyPatch>(pp))
{
continue;
}
else if (isA<processorPolyPatch>(pp))
{
break; // No processor patches
}
patchIds[count] = patchi;
++count;
}
patchIds.resize(count);
}
// Selection of cellZones
const auto& czMatcher = option().cellZoneSelection();
// Selected cell zone indices
labelList czoneIds;
if (option().useCellZones())
{
// Use allow/deny to have desired behaviour with empty selection
czoneIds = mesh_.cellZones().indices
(
option().cellZoneSelection(),
option().cellZoneExclude()
);
}
// Selected face zone indices
labelList fzoneIds;
if (option().useFaceZones())
{
// Use allow/deny to have desired behaviour with empty selection
fzoneIds = mesh_.faceZones().indices
(
option().faceZoneSelection(),
option().faceZoneExclude()
);
}
// Track which cells are in a zone or not // Track which cells are in a zone or not
@ -210,8 +193,8 @@ void Foam::ensightMesh::correct()
// cellZones first // cellZones first
for (const label zoneId : czoneIds) for (const label zoneId : czoneIds)
{ {
const word& zoneName = czNames[zoneId]; const auto& zn = mesh_.cellZones()[zoneId];
const cellZone& zn = mesh_.cellZones()[zoneId]; const auto& zoneName = zn.name();
if (returnReduceOr(!zn.empty())) if (returnReduceOr(!zn.empty()))
{ {
@ -323,7 +306,7 @@ void Foam::ensightMesh::correct()
// Ensure full mesh coverage // Ensure full mesh coverage
excludeFace.resize(mesh_.nFaces()); excludeFace.resize(mesh_.nFaces());
for (const polyPatch& p : mesh_.boundaryMesh()) for (const polyPatch& p : pbm)
{ {
const auto* cpp = isA<coupledPolyPatch>(p); const auto* cpp = isA<coupledPolyPatch>(p);
@ -344,8 +327,8 @@ void Foam::ensightMesh::correct()
// Patches // Patches
for (const label patchId : patchIds) for (const label patchId : patchIds)
{ {
const word& patchName = patchNames[patchId]; const auto& p = pbm[patchId];
const polyPatch& p = mesh_.boundaryMesh()[patchId]; const auto& patchName = p.name();
if (isA<emptyPolyPatch>(p)) if (isA<emptyPolyPatch>(p))
{ {
@ -386,11 +369,10 @@ void Foam::ensightMesh::correct()
// Face zones // Face zones
for (const label zoneId : fzoneIds) for (const label zoneId : fzoneIds)
{ {
const word& zoneName = fzNames[zoneId]; const auto& zn = mesh_.faceZones()[zoneId];
const faceZone& zn = mesh_.faceZones()[zoneId]; const auto& zoneName = zn.name();
ensightFaces& part = faceZoneParts_(zoneId); ensightFaces& part = faceZoneParts_(zoneId);

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2016-2024 OpenCFD Ltd. Copyright (C) 2016-2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -292,34 +292,46 @@ public:
//- Using boundary? //- Using boundary?
bool useBoundaryMesh() const noexcept; bool useBoundaryMesh() const noexcept;
//- Using faceZones?
bool useFaceZones() const noexcept;
//- Using cellZones? //- Using cellZones?
bool useCellZones() const noexcept; bool useCellZones() const noexcept;
//- Using faceZones?
bool useFaceZones() const noexcept;
//- Selection of patches. Empty if unspecified. //- Selection of patches. Empty if unspecified.
const wordRes& patchSelection() const noexcept const wordRes& patchSelection() const noexcept
{ {
return patchInclude_; return patchInclude_;
} }
//- Selection of black listed patches. Empty if unspecified. //- Excluded patches. Empty if unspecified.
const wordRes& patchExclude() const noexcept const wordRes& patchExclude() const noexcept
{ {
return patchExclude_; return patchExclude_;
} }
//- Selection of faceZones. Empty if unspecified. //- Selection of cell zones. Empty if unspecified.
const wordRes& cellZoneSelection() const noexcept
{
return cellZoneInclude_;
}
//- Excluded cell zones. Future use
const wordRes& cellZoneExclude() const noexcept
{
return wordRes::null();
}
//- Selection of face zones. Empty if unspecified.
const wordRes& faceZoneSelection() const noexcept const wordRes& faceZoneSelection() const noexcept
{ {
return faceZoneInclude_; return faceZoneInclude_;
} }
//- Selection of faceZones. Empty if unspecified. //- Excluded face zones. Future use
const wordRes& cellZoneSelection() const noexcept const wordRes& faceZoneExclude() const noexcept
{ {
return cellZoneInclude_; return wordRes::null();
} }
@ -356,18 +368,18 @@ public:
//- Define patch selection to exclude //- Define patch selection to exclude
void patchExclude(List<wordRe>&& patterns); void patchExclude(List<wordRe>&& patterns);
//- Define faceZone selection matcher
void faceZoneSelection(const UList<wordRe>& patterns);
//- Define faceZone selection matcher
void faceZoneSelection(List<wordRe>&& patterns);
//- Define cellZone selection matcher //- Define cellZone selection matcher
void cellZoneSelection(const UList<wordRe>& patterns); void cellZoneSelection(const UList<wordRe>& patterns);
//- Define cellZone selection matcher //- Define cellZone selection matcher
void cellZoneSelection(List<wordRe>&& patterns); void cellZoneSelection(List<wordRe>&& patterns);
//- Define faceZone selection matcher
void faceZoneSelection(const UList<wordRe>& patterns);
//- Define faceZone selection matcher
void faceZoneSelection(List<wordRe>&& patterns);
// Output // Output

View File

@ -88,7 +88,11 @@ void Foam::faBoundaryMesh::calcGroupIDs() const
// Remove groups that clash with patch names // Remove groups that clash with patch names
forAll(patches, patchi) forAll(patches, patchi)
{ {
if (groupLookup.erase(patches[patchi].name())) if (groupLookup.empty())
{
break; // Early termination
}
else if (groupLookup.erase(patches[patchi].name()))
{ {
WarningInFunction WarningInFunction
<< "Removed group '" << patches[patchi].name() << "Removed group '" << patches[patchi].name()
@ -584,7 +588,7 @@ Foam::labelList Foam::faBoundaryMesh::indices
// Only check groups if requested and they exist // Only check groups if requested and they exist
const bool checkGroups = (useGroups && this->hasGroupIDs()); const bool checkGroups = (useGroups && this->hasGroupIDs());
labelHashSet ids(0); labelHashSet ids;
if (matcher.isPattern()) if (matcher.isPattern())
{ {
@ -597,7 +601,7 @@ Foam::labelList Foam::faBoundaryMesh::indices
{ {
if (matcher(iter.key())) if (matcher(iter.key()))
{ {
// Add patch ids associated with the group // Add ids associated with the group
ids.insert(iter.val()); ids.insert(iter.val());
} }
} }
@ -629,7 +633,7 @@ Foam::labelList Foam::faBoundaryMesh::indices
if (iter.good()) if (iter.good())
{ {
// Add patch ids associated with the group // Add ids associated with the group
ids.insert(iter.val()); ids.insert(iter.val());
} }
} }
@ -654,7 +658,7 @@ Foam::labelList Foam::faBoundaryMesh::indices
return this->indices(matcher.front(), useGroups); return this->indices(matcher.front(), useGroups);
} }
labelHashSet ids(0); labelHashSet ids;
// Only check groups if requested and they exist // Only check groups if requested and they exist
if (useGroups && this->hasGroupIDs()) if (useGroups && this->hasGroupIDs())
@ -666,7 +670,7 @@ Foam::labelList Foam::faBoundaryMesh::indices
{ {
if (matcher(iter.key())) if (matcher(iter.key()))
{ {
// Add patch ids associated with the group // Add ids associated with the group
ids.insert(iter.val()); ids.insert(iter.val());
} }
} }
@ -687,19 +691,20 @@ Foam::labelList Foam::faBoundaryMesh::indices
Foam::labelList Foam::faBoundaryMesh::indices Foam::labelList Foam::faBoundaryMesh::indices
( (
const wordRes& select, const wordRes& allow,
const wordRes& ignore, const wordRes& deny,
const bool useGroups const bool useGroups
) const ) const
{ {
if (ignore.empty()) if (allow.empty() && deny.empty())
{ {
return this->indices(select, useGroups); // Fast-path: select all
return identity(this->size());
} }
const wordRes::filter matcher(select, ignore); const wordRes::filter matcher(allow, deny);
labelHashSet ids(0); labelHashSet ids;
// Only check groups if requested and they exist // Only check groups if requested and they exist
if (useGroups && this->hasGroupIDs()) if (useGroups && this->hasGroupIDs())
@ -711,7 +716,7 @@ Foam::labelList Foam::faBoundaryMesh::indices
{ {
if (matcher(iter.key())) if (matcher(iter.key()))
{ {
// Add patch ids associated with the group // Add ids associated with the group
ids.insert(iter.val()); ids.insert(iter.val());
} }
} }

View File

@ -28,7 +28,9 @@ Class
Foam::faBoundaryMesh Foam::faBoundaryMesh
Description Description
Finite area boundary mesh Finite area boundary mesh, which is a faPatch list with registered IO,
a reference to the associated faMesh,
with additional search methods etc.
SourceFiles SourceFiles
faBoundaryMesh.C faBoundaryMesh.C
@ -222,34 +224,37 @@ public:
labelRange range() const; labelRange range() const;
//- Return (sorted) patch indices for all matches. //- The (sorted) patch indices for all matches,
// Optionally matches patch groups. //- optionally matching patch groups.
// A no-op (returns empty list) for an empty matcher // \returns an empty list for an empty matcher
labelList indices labelList indices
( (
const wordRe& matcher, const wordRe& matcher,
const bool useGroups = true const bool useGroups = true
) const; ) const;
//- Return (sorted) patch indices for all matches. //- The (sorted) patch indices for all matches,
// Optionally matches patch groups. //- optionally matching patch groups.
// A no-op (returns empty list) for an empty matcher // \returns an empty list for an empty matcher
labelList indices labelList indices
( (
const wordRes& matcher, const wordRes& matcher,
const bool useGroups = true const bool useGroups = true
) const; ) const;
//- Return (sorted) patch indices for all selected matches that //- The (sorted) patch indices: logic as per Foam::wordRes::filter,
//- are not ignored. //- optionally matching patch groups.
//- The selection logic as per Foam::wordRes::filter. //
// Optionally matches patch groups. // An empty \em allow accepts everything not in \em deny.
// A no-op (returns empty list) for an empty select matcher // A literal \em allow match has higher priority than any \em deny.
// A regex \em allow match has lower priority than any \em deny.
//
// \returns identity list when allow/deny are both empty.
labelList indices labelList indices
( (
const wordRes& select, const wordRes& allow,
const wordRes& ignore, const wordRes& deny,
const bool useGroups = true const bool useGroups = true //!< Match patch groups
) const; ) const;
//- Return patch index for the first match, return -1 if not found //- Return patch index for the first match, return -1 if not found

View File

@ -86,7 +86,15 @@ Foam::transformFaPatchField<Type>::valueInternalCoeffs
const tmp<scalarField>& const tmp<scalarField>&
) const ) const
{ {
return pTraits<Type>::one - snGradTransformDiag(); // OR (!is_rotational_vectorspace_v<Type>)
if constexpr (std::is_arithmetic_v<Type>)
{
return tmp<Field<Type>>::New(this->size(), pTraits<Type>::one);
}
else
{
return pTraits<Type>::one - snGradTransformDiag();
}
} }
@ -111,7 +119,15 @@ template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::tmp<Foam::Field<Type>>
Foam::transformFaPatchField<Type>::gradientInternalCoeffs() const Foam::transformFaPatchField<Type>::gradientInternalCoeffs() const
{ {
return -this->patch().deltaCoeffs()*snGradTransformDiag(); // OR (!is_rotational_vectorspace_v<Type>)
if constexpr (std::is_arithmetic_v<Type>)
{
return tmp<Field<Type>>::New(this->size(), Foam::zero{});
}
else
{
return -this->patch().deltaCoeffs()*snGradTransformDiag();
}
} }

View File

@ -255,6 +255,7 @@ void Foam::faPatchField<Type>::evaluate(const Pstream::commsTypes)
} }
faPatchFieldBase::setUpdated(false); faPatchFieldBase::setUpdated(false);
faPatchFieldBase::setManipulated(false);
} }

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2016-2017 Wikki Ltd Copyright (C) 2016-2017 Wikki Ltd
Copyright (C) 2019-2024 OpenCFD Ltd. Copyright (C) 2019-2025 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -226,6 +226,17 @@ public:
updated_ = state; updated_ = state;
} }
//- True if the matrix has already been manipulated.
//- Currently always false for faPatchField
bool manipulatedMatrix() const noexcept
{
return false;
}
//- Set matrix manipulated state. Currently a no-op for faPatchField
void setManipulated(bool state) noexcept
{}
// Check // Check
@ -254,6 +265,9 @@ public:
//- The value_type for the patch field //- The value_type for the patch field
typedef Type value_type; typedef Type value_type;
//- The component type for patch field
typedef typename pTraits<Type>::cmptType cmptType;
//- The internal field type associated with the patch field //- The internal field type associated with the patch field
typedef DimensionedField<Type, areaMesh> Internal; typedef DimensionedField<Type, areaMesh> Internal;

View File

@ -98,14 +98,6 @@ protected:
// Useful when initially constructed without a dictionary // Useful when initially constructed without a dictionary
virtual void readDict(const dictionary& dict); virtual void readDict(const dictionary& dict);
//- Set updated state. This is a no-op for faePatchField
void setUpdated(bool state) noexcept
{}
//- Set matrix manipulated state. This is a no-op for faePatchField
void setManipulated(bool state) noexcept
{}
public: public:
@ -211,13 +203,22 @@ public:
return true; return true;
} }
//- Set updated state. This is a no-op for faePatchField
void setUpdated(bool state) noexcept
{}
//- True if the matrix has already been manipulated. //- True if the matrix has already been manipulated.
//- Currently ignored (always false) for faePatchField //- Always false for faePatchField
bool manipulatedMatrix() const noexcept bool manipulatedMatrix() const noexcept
{ {
return false; return false;
} }
//- Set matrix manipulated state.
//- This is a no-op for faePatchField
void setManipulated(bool state) noexcept
{}
// Check // Check
@ -246,6 +247,9 @@ public:
//- The value_type for the patch field //- The value_type for the patch field
typedef Type value_type; typedef Type value_type;
//- The component type for patch field
typedef typename pTraits<Type>::cmptType cmptType;
//- The internal field type associated with the patch field //- The internal field type associated with the patch field
typedef DimensionedField<Type, edgeMesh> Internal; typedef DimensionedField<Type, edgeMesh> Internal;

View File

@ -97,7 +97,15 @@ Foam::transformFvPatchField<Type>::valueInternalCoeffs
const tmp<scalarField>& const tmp<scalarField>&
) const ) const
{ {
return pTraits<Type>::one - snGradTransformDiag(); // OR (!is_rotational_vectorspace_v<Type>)
if constexpr (std::is_arithmetic_v<Type>)
{
return tmp<Field<Type>>::New(this->size(), pTraits<Type>::one);
}
else
{
return pTraits<Type>::one - snGradTransformDiag();
}
} }
@ -122,7 +130,15 @@ template<class Type>
Foam::tmp<Foam::Field<Type>> Foam::tmp<Foam::Field<Type>>
Foam::transformFvPatchField<Type>::gradientInternalCoeffs() const Foam::transformFvPatchField<Type>::gradientInternalCoeffs() const
{ {
return -this->patch().deltaCoeffs()*snGradTransformDiag(); // OR (!is_rotational_vectorspace_v<Type>)
if constexpr (std::is_arithmetic_v<Type>)
{
return tmp<Field<Type>>::New(this->size(), Foam::zero{});
}
else
{
return -this->patch().deltaCoeffs()*snGradTransformDiag();
}
} }

Some files were not shown because too many files have changed in this diff Show More