Compare commits

..

5 Commits

Author SHA1 Message Date
11964a4731 ENH: reduce overhead and clearer data ownership for OFstreamCollator
- local data to be written is now transferable into the
  OFstreamCollator. This avoids making a full copy when threading is
  active.

- use plain lists for managing proc data
  * storage: List<List<char>> instead of PtrList<List<char>>
  * views:   List<stdFoam::span<char>> instead of PtrList<SubList<char>>

- use gather/write (unthreaded) as backstop if the output is too big
  to fit in the buffer size. Emit warning instead of FatalError
2024-01-23 17:16:02 +01:00
c82facdc8e ENH: reduce overhead of decomposedBlockData IO
- OCharStream for serializing
- skip intermediate blocks without reading
- support character spans
- read and distribute with direct non-blocking send/recv
  instead of PstreamBuffers or with IPstream/OPstream streaming
  operators.
- non-blocking gather/write when using intermediate buffer space
2024-01-23 17:16:02 +01:00
da560be4df ENH: reduce overhead of masterOFstream
- use OCharStream instead of OStringStream to avoid copying char data.

- direct non-blocking send/recv with probing instead of PstreamBuffers
  to avoid serialization/de-serialization of char data and reduce the
  memory footprint somewhat.

- polling dispatch to write file content as it becomes available,
  which should improve communication and IO overlap
2024-01-23 17:16:02 +01:00
cf6e3a1acf CONFIG: adjust compile-time value of maxThreadFileBufferSize to 0
- consistent with etc/controlDict default

STYLE: update banner message for collated
2024-01-23 17:16:02 +01:00
0a51a4848c TEST: add standalone test application: Test-checkIOspeed 2024-01-23 17:16:02 +01:00
282 changed files with 3597 additions and 9467 deletions

View File

@ -9,7 +9,6 @@ It is likely incomplete...
- Yu Ankun
- Tetsuo Aoyagi
- Akira Azami
- Pete Bachant
- William Bainbridge
- Gabriel Barajas
- Kutalmis Bercin

View File

@ -135,14 +135,14 @@ public:
virtual volScalarField& he()
{
NotImplemented;
return const_cast<volScalarField&>(volScalarField::null());
return thermo1_->he();
}
//- Enthalpy/Internal energy [J/kg]
virtual const volScalarField& he() const
{
NotImplemented;
return volScalarField::null();
return thermo1_->he();
}
//- Enthalpy/Internal energy
@ -213,7 +213,7 @@ public:
) const
{
NotImplemented;
return nullptr;
return tmp<scalarField>::New(p);
}
//- Heat capacity at constant volume [J/kg/K]
@ -236,7 +236,7 @@ public:
) const
{
NotImplemented;
return nullptr;
return tmp<scalarField>::New(p);
}
//- Gamma = Cp/Cv []

View File

@ -243,14 +243,14 @@ public:
virtual volScalarField& he()
{
NotImplemented;
return const_cast<volScalarField&>(volScalarField::null());
return phases_[0].thermo().he();
}
//- Enthalpy/Internal energy [J/kg]
virtual const volScalarField& he() const
{
NotImplemented;
return volScalarField::null();
return phases_[0].thermo().he();
}
//- Enthalpy/Internal energy
@ -327,7 +327,7 @@ public:
) const
{
NotImplemented;
return nullptr;
return tmp<scalarField>::New(p);
}
//- Heat capacity at constant volume [J/kg/K]
@ -350,7 +350,7 @@ public:
) const
{
NotImplemented;
return nullptr;
return tmp<scalarField>::New(p);
}
//- Gamma = Cp/Cv []

View File

@ -86,14 +86,14 @@ public:
virtual volScalarField& he()
{
NotImplemented;
return const_cast<volScalarField&>(volScalarField::null());
return p();
}
//- Return access to the internal energy field [J/Kg]
virtual const volScalarField& he() const
{
NotImplemented;
return volScalarField::null();
return p();
}
//- Enthalpy/Internal energy
@ -182,7 +182,7 @@ public:
) const
{
NotImplemented;
return nullptr;
return tmp<scalarField>::New(p);
}
//- Return Cv of the mixture
@ -205,7 +205,7 @@ public:
) const
{
NotImplemented;
return nullptr;
return tmp<scalarField>::New(p);
}
//- Gamma = Cp/Cv []

View File

@ -412,7 +412,7 @@ int main(int argc, char *argv[])
}
{
Info<< "range-for of list (" << list1.count_nonnull() << '/'
Info<< "range-for of list (" << list1.count() << '/'
<< list1.size() << ") non-null entries" << nl
<< "(" << nl;
for (const auto& item : list1)

View File

@ -64,7 +64,6 @@ int main(int argc, char *argv[])
// Add some more entries
{
label idx = 0;
dictionary subdict;
subdict.add("key", 100);
@ -73,30 +72,23 @@ int main(int argc, char *argv[])
subdict.add
(
new formattingEntry(++idx, "// comment - without newline.")
new formattingEntry(10, "// comment - without newline.")
);
subdict.add
(
// NB newline must be part of the content!
new formattingEntry(++idx, "// some comment - with newline?\n")
new formattingEntry(11, "// some comment - with newline?\n")
);
subdict.add
(
// NB newline must be part of the content!
new formattingEntry(++idx, "/* other comment */\n")
new formattingEntry(12, "/* other comment */\n")
);
// Other - invisible
subdict.add(new formattingEntry(++idx, token(123), false));
// Other - visible (probably not what anyone wants!)
subdict.add(new formattingEntry(++idx, token(456)));
subdict.add("val", 42);
Info<< "subdict keys:" << flatOutput(subdict.toc()) << nl;
dict.add("subdict", std::move(subdict));
}

View File

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

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2021-2024 OpenCFD Ltd.
Copyright (C) 2021-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -52,7 +52,7 @@ int main(int argc, char *argv[])
const labelList localValues
(
identity(2 *(UPstream::myProcNo()+1), -5*UPstream::myProcNo())
identity(2 *(Pstream::myProcNo()+1), -5*Pstream::myProcNo())
);
// Test resize
@ -76,8 +76,8 @@ int main(int argc, char *argv[])
// One-sided sizing! master only
const globalIndex allProcAddr
(
globalIndex::gatherOnly{},
sendData.size()
sendData.size(),
globalIndex::gatherOnly{}
);
Pout<< "listGather sizes: " << flatOutput(allProcAddr.sizes()) << nl;
@ -98,8 +98,8 @@ int main(int argc, char *argv[])
// One-sided sizing! master only
const globalIndex allProcAddr
(
globalIndex::gatherOnly{},
sendData.size()
sendData.size(),
globalIndex::gatherOnly{}
);
Pout<< "listGather sizes: " << flatOutput(allProcAddr.sizes()) << nl;
@ -116,7 +116,7 @@ int main(int argc, char *argv[])
{
const labelList::subList& sendData =
(
UPstream::master()
Pstream::master()
? SubList<label>(localValues, 0) // exclude
: SubList<label>(localValues)
);
@ -147,11 +147,11 @@ int main(int argc, char *argv[])
<< UPstream::listScatterValues(subProcAddr.offsets()) << nl;
Pout<< endl << "local list [" << UPstream::myProcNo() << "] "
Pout<< endl << "local list [" << Pstream::myProcNo() << "] "
<< flatOutput(localValues) << nl;
Pout<< endl << "local send [" << UPstream::myProcNo() << "] "
Pout<< endl << "local send [" << Pstream::myProcNo() << "] "
<< sendSize << nl;
@ -163,7 +163,7 @@ int main(int argc, char *argv[])
Pout<< "off-proc: " << allValues << endl;
if (UPstream::master())
if (Pstream::master())
{
Info<< "master: " << flatOutput(localValues) << nl;
@ -196,7 +196,7 @@ int main(int argc, char *argv[])
{
globalIndex glob
(
globalIndex::gatherNone{},
globalIndex:gatherNone{},
labelList(Foam::one{}, 0)
);
Info<< "single:" << nl;
@ -208,37 +208,35 @@ int main(int argc, char *argv[])
}
}
// Non-contiguous gather - use Pstream, not UPstream!
// This will likely fail - not declared as is_contiguous
// Cannot even catch since it triggers an abort()
#if 0
{
typedef std::pair<label,vector> valueType;
std::pair<label,vector> sendData(Pstream::myProcNo(), vector::one);
valueType sendData(UPstream::myProcNo(), vector::one);
const bool oldThrowingError = FatalError.throwing(true);
List<valueType> countValues
(
Pstream::listGatherValues(sendData)
);
Pout<< "listGather: " << flatOutput(countValues) << nl;
}
// Non-contiguous scatter - use Pstream, not UPstream!
{
List<fileName> allValues;
if (UPstream::master())
try
{
allValues.resize(UPstream::nProcs());
forAll(allValues, proci)
{
allValues[proci] = "processor" + Foam::name(proci);
}
List<std::pair<label,vector>> countValues
(
UPstream::listGatherValues<std::pair<label, vector>>
(
sendData
)
);
Pout<< "listGather: " << flatOutput(countValues) << nl;
}
catch (const Foam::error& err)
{
Info<< err.message().c_str() << nl;
}
fileName procName = Pstream::listScatterValues(allValues);
Pout<< "listScatter: " << procName << nl;
FatalError.throwing(oldThrowingError);
}
#endif
Info<< "\nEnd\n" << endl;

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2014 OpenFOAM Foundation
Copyright (C) 2019-2024 OpenCFD Ltd.
Copyright (C) 2019-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -48,7 +48,7 @@ class SimpleClass
public:
//- Default construct
SimpleClass() = default;
SimpleClass() {}
};
@ -73,8 +73,9 @@ void printInfo(const UList<T>& list)
int main()
{
// Test pointer and reference to a class
auto ptrToClass = autoPtr<SimpleClass>::New();
auto& refToClass = ptrToClass.ref();
SimpleClass* ptrToClass = new SimpleClass;
SimpleClass& refToClass(*ptrToClass);
std::cout
<< "nullObject addr=" << name(&(nullObjectPtr)) << nl
@ -88,13 +89,13 @@ int main()
<< " pointer:" << name(nullObjectPtr->pointer()) << nl
<< " value:" << nullObjectPtr->value() << nl << nl;
if (notNull(ptrToClass.get()))
if (notNull(ptrToClass))
{
Info<< "Pass: ptrToClass is not null" << nl;
}
else
{
Info<< "FAIL: ptrToClass is null" << nl;
Info<< "FAIL: refToClass is null" << nl;
}
if (notNull(refToClass))
@ -109,8 +110,8 @@ int main()
// Test pointer and reference to the nullObject
const SimpleClass* ptrToNull = NullObjectPtr<SimpleClass>();
const SimpleClass& refToNull = (*ptrToNull);
const SimpleClass* ptrToNull(NullObjectPtr<SimpleClass>());
const SimpleClass& refToNull(*ptrToNull);
if (isNull(ptrToNull))
{
@ -130,6 +131,9 @@ int main()
Info<< "FAIL: refToNull is not null" << nl;
}
// Clean-up
delete ptrToClass;
// Test List casting
{
@ -148,7 +152,7 @@ int main()
// Looks pretty ugly though!
NullObject::nullObject = "hello world";
NullObject::nullObject = Foam::identity(5);
NullObject::nullObject = labelList({1, 2, 3});
Info<< nl;

View File

@ -50,37 +50,37 @@ scalar sumReduce
)
{
scalar sum = 0;
if (UPstream::parRun())
if (Pstream::parRun())
{
if (UPstream::master(comm))
{
// Add master value and all sub-procs
// Add master value and all slaves
sum = localValue;
for (const int proci : UPstream::subProcs(comm))
for (const int slave : UPstream::subProcs(comm))
{
scalar procValue;
scalar slaveValue;
UIPstream::read
(
UPstream::commsTypes::blocking,
proci,
reinterpret_cast<char*>(&procValue),
Pstream::commsTypes::blocking,
slave,
reinterpret_cast<char*>(&slaveValue),
sizeof(scalar),
UPstream::msgType(), // tag
comm // communicator
);
sum += procValue;
sum += slaveValue;
}
// Send back
// Send back to slaves
for (const int proci : UPstream::subProcs(comm))
for (const int slave : UPstream::subProcs(comm))
{
UOPstream::write
(
UPstream::commsTypes::blocking,
proci,
slave,
reinterpret_cast<const char*>(&sum),
sizeof(scalar),
UPstream::msgType(), // tag

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2016-2024 OpenCFD Ltd.
Copyright (C) 2016-2020 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -52,27 +52,27 @@ void testMapDistribute()
// Generate random data.
List<Tuple2<label, List<scalar>>> complexData(100);
for (auto& data : complexData)
forAll(complexData, i)
{
data.first() = rndGen.position(0, UPstream::nProcs()-1);
data.second().resize(3);
data.second()[0] = 1;
data.second()[1] = 2;
data.second()[2] = 3;
complexData[i].first() = rndGen.position(0, Pstream::nProcs()-1);
complexData[i].second().setSize(3);
complexData[i].second()[0] = 1;
complexData[i].second()[1] = 2;
complexData[i].second()[2] = 3;
}
// Send all ones to processor indicated by .first()
// Count how many to send
labelList nSend(UPstream::nProcs(), Foam::zero{});
for (const auto& data : complexData)
labelList nSend(Pstream::nProcs(), Zero);
forAll(complexData, i)
{
const label proci = data.first();
const label proci = complexData[i].first();
nSend[proci]++;
}
// Collect items to be sent
labelListList sendMap(UPstream::nProcs());
labelListList sendMap(Pstream::nProcs());
forAll(sendMap, proci)
{
sendMap[proci].resize_nocopy(nSend[proci]);
@ -116,31 +116,40 @@ void testTransfer(const T& input)
{
T data = input;
if (UPstream::master())
if (Pstream::master())
{
Perr<<"test transfer (" << (typeid(T).name()) << "): ";
perrInfo(data) << nl << endl;
}
for (const int proci : UPstream::subProcs())
if (Pstream::master())
{
for (const int slave : Pstream::subProcs())
{
Perr<< "master receiving from proc:" << proci << endl;
IPstream::recv(data, proci);
Perr<< "master receiving from slave " << slave << endl;
IPstream fromSlave(Pstream::commsTypes::blocking, slave);
fromSlave >> data;
perrInfo(data) << endl;
}
for (const int proci : UPstream::subProcs())
for (const int slave : Pstream::subProcs())
{
Perr<< "master sending to proc:" << proci << endl;
OPstream::bsend(data, proci);
Perr<< "master sending to slave " << slave << endl;
OPstream toSlave(Pstream::commsTypes::blocking, slave);
toSlave << data;
}
}
else
{
Perr<< "proc sending to master" << endl;
OPstream::bsend(data, UPstream::masterNo());
{
Perr<< "slave sending to master " << Pstream::masterNo() << endl;
OPstream toMaster(Pstream::commsTypes::blocking, Pstream::masterNo());
toMaster << data;
}
Perr<< "proc receiving from master" << endl;
IPstream::recv(data, UPstream::masterNo());
Perr<< "slave receiving from master " << Pstream::masterNo() << endl;
IPstream fromMaster(Pstream::commsTypes::blocking, Pstream::masterNo());
fromMaster >> data;
perrInfo(data) << endl;
}
}
@ -151,31 +160,49 @@ void testTokenized(const T& data)
{
token tok;
if (UPstream::master())
if (Pstream::master())
{
Perr<< "test tokenized \"" << data << "\"" << nl << endl;
Perr<<"test tokenized \"" << data << "\"" << nl << endl;
}
for (const int proci : UPstream::subProcs())
if (Pstream::master())
{
for (const int slave : Pstream::subProcs())
{
Perr<< "master receiving from proc:" << proci << endl;
IPstream::recv(tok, proci);
Perr<< "master receiving from slave " << slave << endl;
IPstream fromSlave(Pstream::commsTypes::blocking, slave);
fromSlave >> tok;
Perr<< tok.info() << endl;
}
for (const int proci : UPstream::subProcs())
for (const int slave : Pstream::subProcs())
{
Perr<< "master sending to proc:" << proci << endl;
OPstream::bsend(tok, proci);
Perr<< "master sending to slave " << slave << endl;
OPstream toSlave(Pstream::commsTypes::blocking, slave);
toSlave << data;
}
}
else
{
Perr<< "proc sending to master" << endl;
OPstream::bsend(tok, UPstream::masterNo());
{
Perr<< "slave sending to master " << Pstream::masterNo() << endl;
OPstream toMaster
(
Pstream::commsTypes::blocking,
Pstream::masterNo()
);
Perr<< "proc receiving from master" << endl;
IPstream::recv(tok, UPstream::masterNo());
toMaster << data;
}
Perr<< "slave receiving from master " << Pstream::masterNo() << endl;
IPstream fromMaster
(
Pstream::commsTypes::blocking,
Pstream::masterNo()
);
fromMaster >> tok;
Perr<< tok.info() << endl;
}
}
@ -185,14 +212,12 @@ void testTokenized(const T& data)
int main(int argc, char *argv[])
{
argList::noCheckProcessorDirectories();
#include "setRootCase.H"
#include "createTime.H"
testMapDistribute();
if (!UPstream::parRun())
if (!Pstream::parRun())
{
Info<< "\nWarning: not parallel - skipping further tests\n" << endl;
return 0;

View File

@ -1,11 +0,0 @@
#!/bin/sh
cd "${0%/*}" || exit # Run from this directory
. ${WM_PROJECT_DIR:?}/bin/tools/CleanFunctions # Tutorial clean functions
#------------------------------------------------------------------------------
cleanCase
# Remove surface and features
rm -rf constant/triSurface
#------------------------------------------------------------------------------

View File

@ -1,27 +0,0 @@
#!/bin/sh
cd "${0%/*}" || exit # Run from this directory
. ${WM_PROJECT_DIR:?}/bin/tools/RunFunctions # Tutorial run functions
#------------------------------------------------------------------------------
#- Generate 2x2x1 cells
runApplication blockMesh
#- Remove cell0
runApplication topoSet
runApplication subsetMesh c0 -patch exposed0 -overwrite
#- Put exposed faces (2) into separate patches
runApplication -s face topoSet
runApplication createPatch -overwrite
#- Decompose - creates one processor without any faces in patches
runApplication decomposePar
#- Extract inter-patch points. Should include processor that does not
#- have faces on patch ...
mkdir -p constant/triSurface
runParallel surfaceMeshExtract \
-patches '(exposed0 exposed1)' -featureAngle 180 \
constant/triSurface/blockMesh.obj
#------------------------------------------------------------------------------

View File

@ -1,7 +0,0 @@
- 2x2x1 mesh
- remove one cell, exposing two faces
- move exposed faces into two patches
- decompose onto 3
- run surfaceMeshExtract -featureAngle 180
- should also mark points on the processor that has no
faces but is coupled

View File

@ -1,21 +0,0 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2312 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
location "constant";
object transportProperties;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
nu 0.01;
// ************************************************************************* //

View File

@ -1,88 +0,0 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2312 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
object blockMeshDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
scale 1;
vertices
(
//- Single block
(0 0 0)
(2 0 0)
(2 2 0)
(0 2 0)
(0 0 2)
(2 0 2)
(2 2 2)
(0 2 2)
);
blocks
(
hex (0 1 2 3 4 5 6 7) (2 2 1) simpleGrading (1 1 1)
);
edges
(
);
boundary
(
topWall
{
type wall;
faces
(
(3 7 6 2)
);
}
bottomWall
{
type wall;
faces
(
(1 5 4 0)
);
}
fixedWalls
{
type wall;
faces
(
(0 4 7 3)
(2 6 5 1)
);
}
frontAndBack
{
type patch;
faces
(
(0 3 2 1)
(4 5 6 7)
);
}
exposed0
{
type patch;
faces ();
}
);
mergePatchPairs
(
);
// ************************************************************************* //

View File

@ -1,48 +0,0 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2312 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
location "system";
object controlDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
application icoFoam;
startFrom startTime;
startTime 0;
stopAt endTime;
endTime 0.5;
deltaT 0.005;
writeControl timeStep;
writeInterval 20;
purgeWrite 0;
writeFormat ascii;
writePrecision 16;
writeCompression off;
timeFormat general;
timePrecision 6;
runTimeModifiable true;
// ************************************************************************* //

View File

@ -1,44 +0,0 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2312 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
object createPatchDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
pointSync false;
// Patches to create.
patches
(
// Example of creating mapped patches using geometric matching
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{
// Name of new patch
name exposed1;
// Dictionary to construct new patch from
patchInfo
{
type patch;
}
// How to select the faces:
// - set : specify faceSet in 'set'
// - patches : specify names in 'patches'
// - autoPatch : attempts automatic patching of the specified
// candidates in 'patches'.
constructFrom set;
set exposed0;
}
);
// ************************************************************************* //

View File

@ -1,24 +0,0 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2312 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
note "mesh decomposition control dictionary";
object decomposeParDict;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
//- The total number of domains (mandatory)
numberOfSubdomains 3;
//- The decomposition method (mandatory)
method scotch;
// ************************************************************************* //

View File

@ -1,51 +0,0 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2312 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
location "system";
object fvSchemes;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
ddtSchemes
{
default Euler;
}
gradSchemes
{
default Gauss linear;
grad(p) Gauss linear;
}
divSchemes
{
default none;
div(phi,U) Gauss linear;
}
laplacianSchemes
{
default Gauss linear orthogonal;
}
interpolationSchemes
{
default linear;
}
snGradSchemes
{
default orthogonal;
}
// ************************************************************************* //

View File

@ -1,52 +0,0 @@
/*--------------------------------*- C++ -*----------------------------------*\
| ========= | |
| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |
| \\ / O peration | Version: v2312 |
| \\ / A nd | Website: www.openfoam.com |
| \\/ M anipulation | |
\*---------------------------------------------------------------------------*/
FoamFile
{
version 2.0;
format ascii;
class dictionary;
location "system";
object fvSolution;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
solvers
{
p
{
solver PCG;
preconditioner DIC;
tolerance 1e-06;
relTol 0.05;
}
pFinal
{
$p;
relTol 0;
}
U
{
solver smoothSolver;
smoother symGaussSeidel;
tolerance 1e-05;
relTol 0;
}
}
PISO
{
nCorrectors 2;
nNonOrthogonalCorrectors 0;
pRefCell 0;
pRefValue 0;
}
// ************************************************************************* //

View File

@ -51,7 +51,7 @@ void printConnection(Ostream& os, const label proci, const labelUList& below)
// The number of receives - as per gatherList (v2112)
void printRecvCount_gatherList
(
const UList<UPstream::commsStruct>& comms,
const List<UPstream::commsStruct>& comms,
const label comm = UPstream::worldComm
)
{
@ -91,7 +91,7 @@ void printRecvCount_gatherList
// The number of sends - as per scatterList (v2112)
void printSendCount_scatterList
(
const UList<UPstream::commsStruct>& comms,
const List<UPstream::commsStruct>& comms,
const label comm = UPstream::worldComm
)
{
@ -131,7 +131,7 @@ void printSendCount_scatterList
// Transmission widths (contiguous data)
void printWidths
(
const UList<UPstream::commsStruct>& comms,
const List<UPstream::commsStruct>& comms,
const label comm = UPstream::worldComm
)
{

View File

@ -579,8 +579,8 @@ inline bool CGAL::indexedCell<Gt, Cb>::potentialCoplanarCell() const
if (nMasters == 2 && nSlaves == 2)
{
Foam::vector vp0(Foam::zero{});
Foam::vector vp1(Foam::zero{});
Foam::vector vp0(Foam::Zero);
Foam::vector vp1(Foam::Zero);
if
(

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2016-2024 OpenCFD Ltd.
Copyright (C) 2016-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -220,7 +220,7 @@ PtrList<FieldType> subsetFields
const pointMesh& pMesh
)
{
//const fvMesh& baseMesh = subsetter.baseMesh();
const fvMesh& baseMesh = subsetter.baseMesh();
const UPtrList<const IOobject> fieldObjects
(
@ -247,8 +247,8 @@ PtrList<FieldType> subsetFields
IOobject
(
io.name(),
pMesh.thisDb().time().timeName(),
pMesh.thisDb(),
baseMesh.time().timeName(),
baseMesh,
IOobjectOption::MUST_READ,
IOobjectOption::NO_WRITE,
IOobjectOption::NO_REGISTER
@ -382,8 +382,6 @@ int main(int argc, char *argv[])
#include "createTime.H"
#include "createNamedMesh.H"
// Make sure pointMesh gets constructed/read as well
(void)pointMesh::New(mesh, IOobject::READ_IF_PRESENT);
// arg[1] = word (cellSet) or wordRes (cellZone)
// const word selectionName = args[1];
@ -585,7 +583,7 @@ int main(int argc, char *argv[])
// Read point fields and subset
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
const pointMesh& pMesh = pointMesh::New(mesh, IOobject::READ_IF_PRESENT);
const pointMesh& pMesh = pointMesh::New(mesh);
#undef createSubsetFields
#define createSubsetFields(FieldType, Variable) \
@ -665,18 +663,6 @@ int main(int argc, char *argv[])
subsetter.subMesh().write();
processorMeshes::removeFiles(subsetter.subMesh());
auto* subPointMeshPtr =
subsetter.subMesh().thisDb().findObject<pointMesh>
(
pointMesh::typeName
);
if (subPointMeshPtr)
{
pointMesh& subPointMesh = const_cast<pointMesh&>(*subPointMeshPtr);
subPointMesh.setInstance(subsetter.subMesh().facesInstance());
subPointMesh.write();
}
// Volume fields
for (const auto& fld : vScalarFlds) { fld.write(); }

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2016-2022,2024 OpenCFD Ltd.
Copyright (C) 2016-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -661,9 +661,6 @@ int main(int argc, char *argv[])
),
decompDictFile
);
// Make sure pointMesh gets read as well
(void)pointMesh::New(mesh, IOobject::READ_IF_PRESENT);
// Decompose the mesh
if (!decomposeFieldsOnly)
@ -783,7 +780,6 @@ int main(int argc, char *argv[])
PtrList<labelIOList> cellProcAddressingList(mesh.nProcs());
PtrList<labelIOList> boundaryProcAddressingList(mesh.nProcs());
PtrList<labelIOList> pointProcAddressingList(mesh.nProcs());
PtrList<labelIOList> pointBoundaryProcAddressingList(mesh.nProcs());
PtrList<fvFieldDecomposer> fieldDecomposerList(mesh.nProcs());
PtrList<pointFieldDecomposer> pointFieldDecomposerList
@ -854,10 +850,7 @@ int main(int argc, char *argv[])
// Point fields
// ~~~~~~~~~~~~
// Read decomposed pointMesh
const pointMesh& pMesh =
pointMesh::New(mesh, IOobject::READ_IF_PRESENT);
const pointMesh& pMesh = pointMesh::New(mesh);
pointFieldDecomposer::fieldsCache pointFieldCache;
@ -1126,34 +1119,7 @@ int main(int argc, char *argv[])
pointProcAddressingList
);
const pointMesh& procPMesh =
pointMesh::New(procMesh, IOobject::READ_IF_PRESENT);
if (!pointBoundaryProcAddressingList.set(proci))
{
pointBoundaryProcAddressingList.set
(
proci,
autoPtr<labelIOList>::New
(
IOobject
(
"boundaryProcAddressing",
procMesh.facesInstance(),
polyMesh::meshSubDir
/pointMesh::meshSubDir,
procPMesh.thisDb(),
IOobject::READ_IF_PRESENT,
IOobject::NO_WRITE,
IOobject::NO_REGISTER
),
boundaryProcAddressing
)
);
}
const auto& pointBoundaryProcAddressing =
pointBoundaryProcAddressingList[proci];
const pointMesh& procPMesh = pointMesh::New(procMesh);
if (!pointFieldDecomposerList.set(proci))
{
@ -1165,7 +1131,7 @@ int main(int argc, char *argv[])
pMesh,
procPMesh,
pointProcAddressing,
pointBoundaryProcAddressing
boundaryProcAddressing
)
);
}
@ -1177,12 +1143,6 @@ int main(int argc, char *argv[])
if (times.size() == 1)
{
// Early deletion
pointBoundaryProcAddressingList.set
(
proci,
nullptr
);
pointProcAddressingList.set(proci, nullptr);
pointFieldDecomposerList.set(proci, nullptr);
}

View File

@ -44,12 +44,6 @@ License
#include "decompositionModel.H"
#include "hexRef8Data.H"
// For handling pointMeshes with additional patches
#include "pointMesh.H"
#include "meshPointPatch.H"
#include "processorPointPatch.H"
#include "DynamicField.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::domainDecomposition::mark
@ -746,101 +740,6 @@ bool Foam::domainDecomposition::writeDecomposition(const bool decomposeSets)
procMesh.write();
// Add pointMesh if it was available
const auto* pMeshPtr =
thisDb().cfindObject<pointMesh>(pointMesh::typeName);
if (pMeshPtr)
{
const auto& pMesh = *pMeshPtr;
const auto& pMeshBoundary = pMesh.boundary();
// 1. Generate pointBoundaryMesh from polyBoundaryMesh (so ignoring
// any additional patches
const auto& procPointMesh = pointMesh::New(procMesh);
pointBoundaryMesh& procBoundary =
const_cast<pointBoundaryMesh&>(procPointMesh.boundary());
// 2. Explicitly add subsetted meshPointPatches
forAll(pMeshBoundary, patchi)
{
const auto* mppPtr = isA<meshPointPatch>(pMeshBoundary[patchi]);
if (mppPtr && (procBoundary.findPatchID(mppPtr->name()) == -1))
{
const auto& mpp = *mppPtr;
DynamicList<label> procMeshPoints(mpp.size());
DynamicField<vector> procNormals(mpp.size());
forAll(mpp.meshPoints(), i)
{
const label pointi = mpp.meshPoints()[i];
const label procPointi = pointLookup[pointi];
if (procPointi != -1)
{
procMeshPoints.append(procPointi);
procNormals.append(mpp.pointNormals()[i]);
}
}
procBoundary.push_back
(
new meshPointPatch
(
mpp.name(),
procMeshPoints,
procNormals,
procBoundary.size(),
procBoundary,
meshPointPatch::typeName
)
);
}
}
// 3. Shuffle new patches before any processor patches
labelList oldToNew(procBoundary.size());
label newPatchi = 0;
forAll(procBoundary, patchi)
{
if (!isA<processorPointPatch>(procBoundary[patchi]))
{
oldToNew[patchi] = newPatchi;
newPatchi++;
}
}
// decomposed-to-undecomposed patch numbering
labelList boundaryProcAddressing(identity(newPatchi));
boundaryProcAddressing.setSize(procBoundary.size(), -1);
forAll(procBoundary, patchi)
{
if (isA<processorPointPatch>(procBoundary[patchi]))
{
oldToNew[patchi] = newPatchi++;
}
}
procBoundary.reorder(oldToNew, true);
// Write pointMesh/boundary
procBoundary.write();
// Write pointMesh/boundaryProcAddressing
IOobject ioAddr
(
"boundaryProcAddressing",
procMesh.facesInstance(),
polyMesh::meshSubDir/pointMesh::meshSubDir,
procPointMesh.thisDb(),
IOobject::NO_READ,
IOobject::NO_WRITE,
IOobject::NO_REGISTER
);
IOListRef<label>(ioAddr, boundaryProcAddressing).write();
}
// Write points if pointsInstance differing from facesInstance
if (facesInstancePointsPtr_)
{

View File

@ -411,18 +411,24 @@ int main(int argc, char *argv[])
{
Info<< "Reconstructing point fields" << nl << endl;
const pointMesh& pMesh = pointMesh::New
(
mesh,
IOobject::READ_IF_PRESENT
);
const pointMesh& pMesh = pointMesh::New(mesh);
PtrList<pointMesh> pMeshes(procMeshes.meshes().size());
forAll(pMeshes, proci)
{
pMeshes.set
(
proci,
new pointMesh(procMeshes.meshes()[proci])
);
}
pointFieldReconstructor reconstructor
(
pMesh,
procMeshes.pointMeshes(),
pMeshes,
procMeshes.pointProcAddressing(),
procMeshes.pointMeshBoundaryProcAddressing()
procMeshes.boundaryProcAddressing()
);
reconstructor.reconstructAllFields(objects, selectedFields);

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2017-2024 OpenCFD Ltd.
Copyright (C) 2017-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -34,13 +34,10 @@ Description
Extract patch or faceZone surfaces from a polyMesh.
Depending on output surface format triangulates faces.
Region numbers on faces not guaranteed to be the same as the patch indices.
Region numbers on faces no guaranteed to be the same as the patch indices.
Optionally only extracts named patches.
Optionally filters out points on feature-edges and generates pointPatches
for these - written to pointMesh/boundary.
If run in parallel, processor patches get filtered out by default and
the mesh is merged (based on topology).
@ -51,7 +48,6 @@ Description
#include "argList.H"
#include "Time.H"
#include "polyMesh.H"
#include "pointMesh.H"
#include "emptyPolyPatch.H"
#include "processorPolyPatch.H"
#include "ListListOps.H"
@ -59,11 +55,6 @@ Description
#include "globalMeshData.H"
#include "globalIndex.H"
#include "timeSelector.H"
#include "meshPointPatch.H"
#include "unitConversion.H"
#include "dummyTransform.H"
#include "syncTools.H"
#include "processorPointPatch.H"
using namespace Foam;
@ -115,551 +106,6 @@ labelList getSelectedPatches
}
label addMeshPointPatches
(
const polyMesh& mesh,
const pointMesh& pMesh,
const uindirectPrimitivePatch& allBoundary,
const labelUList& faceToZone,
const surfZoneIdentifierList& surfZones,
const scalar edgeFeatureAngle,
const scalar pointFeatureAngle,
const bool verbose = true
)
{
const pointBoundaryMesh& pointBm = pMesh.boundary();
const label nPointPatches = pointBm.size();
const globalMeshData& globalData = mesh.globalData();
const indirectPrimitivePatch& cpp = globalData.coupledPatch();
const mapDistribute& map = globalData.globalEdgeSlavesMap();
const auto& mp = allBoundary.meshPoints();
const vector nullVector(vector::uniform(0));
const auto assignNonNull = [&](vector& x, const vector& y)
{
if (x == nullVector && y != nullVector)
{
x = y;
}
};
// Calculate parallel-consistent point normals (as unweighted average
// of faceNormals). Note: only valid on patch points, not on mesh points
// that are coupled to these.
const pointField pointNormals
(
PatchTools::pointNormals
(
mesh,
allBoundary
)
);
// Expand to all coupled points
pointField meshPointNormals(mesh.nPoints(), nullVector);
UIndirectList<vector>(meshPointNormals, mp) = pointNormals;
syncTools::syncPointList
(
mesh,
meshPointNormals,
assignNonNull,
nullVector
);
// Find correspondence between allBoundary and coupled edges
labelList allEdges;
labelList coupledEdges;
bitSet sameEdgeOrientation;
PatchTools::matchEdges
(
allBoundary,
cpp,
allEdges,
coupledEdges,
sameEdgeOrientation
);
// To construct the patches we need to know per edge
// - patch on either side (if topological feature edge)
// - faceNormal on either side (if feature angle)
// We need to know per point
// - patches on all connected faces
// - faceNormals on all connected faces? And compare to average?
// or edge normals on all connected edges
typedef Tuple2<label, vector> PN;
const PN nullPN(-1, nullVector);
// Point-based analysis
// ~~~~~~~~~~~~~~~~~~~~
// Collect per (mesh)point the zones (1, 2 or >2). Note: per mesh to
// make it easier to sync. See edge-based code below where we explicitly
// have to transfer from patch-edge to mesh-point etc. Note sure which one
// fits better....
labelPairList pointToZones(mesh.nPoints(), labelPair(-1, -1));
{
// Combine zones.
const auto combineZones = [&](labelPair& x, const labelPair& y)
{
if (x == labelPair(-2, -2))
{
// Already marked
}
else if (y == labelPair(-2, -2))
{
x = y;
}
else
{
// Find first free slot
if (x[0] == -1)
{
if (y[0] != -1)
{
x[0] = y[0];
}
else
{
x[0] = y[1];
}
}
else if (x[1] == -1)
{
if (y[0] != -1 && y[0] != x[0])
{
x[1] = y[0];
}
else if (y[1] != -1 && y[1] != x[1])
{
x[1] = y[1];
}
}
else
{
// Both x slots filled. See if y adds a 3rd element
if (y[0] != -1 && y[0] != x[0] && y[0] != x[1])
{
x = labelPair(-2, -2);
}
else if (y[1] != -1 && y[1] != x[0] && y[1] != x[1])
{
x = labelPair(-2, -2);
}
}
}
};
forAll(allBoundary, facei)
{
const auto& f = allBoundary[facei];
const label zonei = faceToZone[facei];
for (const label pointi : f)
{
auto& pZones = pointToZones[pointi];
if (pZones != labelPair(-2, -2) && !pZones.contains(zonei))
{
if (pZones.first() == -1)
{
pZones.first() = zonei;
}
else if (pZones.second() == -1)
{
pZones.second() = zonei;
}
else
{
// Mark as >2 zones
pZones = labelPair(-2, -2);
}
}
}
}
syncTools::syncPointList
(
mesh,
pointToZones,
combineZones,
labelPair(-1, -1),
dummyTransform()
);
}
// Edge-based analysis
// ~~~~~~~~~~~~~~~~~~~~
// 1. Local analysis
List<Pair<PN>> allEdgeToFaces
(
allBoundary.nEdges(),
Pair<PN>(nullPN, nullPN)
);
{
const auto& edgeFaces = allBoundary.edgeFaces();
const auto& faceNormals = allBoundary.faceNormals();
forAll(edgeFaces, edgei)
{
const auto& eFaces = edgeFaces[edgei];
const vector& n0 = faceNormals[eFaces[0]];
const label zone0 = faceToZone[eFaces[0]];
if (eFaces.size() == 1)
{
allEdgeToFaces[edgei] = Pair<PN>(PN(zone0, n0), nullPN);
}
else
{
const vector& n1 = faceNormals[eFaces[1]];
const label zone1 = faceToZone[eFaces[1]];
allEdgeToFaces[edgei] = Pair<PN>
(
PN(zone0, n0),
PN(zone1, n1)
);
}
}
}
// 2. Sync across coupled patches
{
// Combine pair of normals
const auto vectorPairMax = [&](Pair<PN>& x, const Pair<PN>& y)
{
if (x[0] == nullPN)
{
if (y[0] != nullPN)
{
x[0] = y[0];
}
else
{
x[0] = y[1];
}
}
else if (x[1] == nullPN)
{
if (y[0] != nullPN && y[0] != x[0])
{
x[1] = y[0];
}
else
{
x[1] = y[1];
}
}
};
List<Pair<PN>> cppEdgeData
(
map.constructSize(),
Pair<PN>(nullPN, nullPN)
);
UIndirectList<Pair<PN>>(cppEdgeData, coupledEdges) =
UIndirectList<Pair<PN>>(allEdgeToFaces, allEdges);
globalData.syncData
(
cppEdgeData,
globalData.globalEdgeSlaves(),
globalData.globalEdgeTransformedSlaves(),
map,
globalData.globalTransforms(),
vectorPairMax,
dummyTransform()
);
UIndirectList<Pair<PN>>(allEdgeToFaces, allEdges) =
UIndirectList<Pair<PN>>(cppEdgeData, coupledEdges);
}
// Now we have all the per-patch edge information
// - do inter-patch edges
// - do feature-angle edges
// Store on mesh points
const auto assignNonNullPN = [&](PN& x, const PN& y)
{
if (x.second() == nullVector && y.second() != nullVector)
{
x = y;
}
};
// Storing the normal for points that are on inter-patch edges
vectorField patchEdgeNormal(mesh.nPoints(), nullVector);
// Storing the normal for points that are on patch-internal feat edges
List<PN> featEdgeNormal(mesh.nPoints(), nullPN);
forAll(allEdgeToFaces, edgei)
{
const edge& e = allBoundary.edges()[edgei];
const label mp0 = mp[e[0]];
const label mp1 = mp[e[1]];
const Pair<PN>& facesInfo = allEdgeToFaces[edgei];
if (facesInfo[1] == nullPN)
{
// Boundary edge
patchEdgeNormal[mp0] = pointNormals[e[0]];
patchEdgeNormal[mp1] = pointNormals[e[1]];
}
else
{
if (facesInfo[0].first() != facesInfo[1].first())
{
// Inter-patch
patchEdgeNormal[mp0] = pointNormals[e[0]];
patchEdgeNormal[mp1] = pointNormals[e[1]];
}
else
{
// Same patch - check for feature angle
const vector& n0 = facesInfo[0].second();
const vector& n1 = facesInfo[1].second();
if ((n0 & n1) < Foam::cos(degToRad(edgeFeatureAngle)))
{
if (patchEdgeNormal[mp0] == nullVector)
{
featEdgeNormal[mp0] = PN
(
facesInfo[0].first(), // zone
pointNormals[e[0]]
);
}
if (patchEdgeNormal[mp1] == nullVector)
{
featEdgeNormal[mp1] = PN
(
facesInfo[0].first(), // zone
pointNormals[e[1]]
);
}
}
}
}
}
syncTools::syncPointList
(
mesh,
patchEdgeNormal,
assignNonNull,
nullVector
);
syncTools::syncPointList
(
mesh,
featEdgeNormal,
assignNonNullPN,
nullPN,
dummyTransform()
);
// Make sure that inter-patch points are not also in feature-edge
// points. Note: not absolutely nessecary since all inter-patch points
// will also be in the 'normal' facePointPatches.
DynamicList<label> multiZoneMeshPoints(allBoundary.nPoints());
forAll(pointToZones, pointi)
{
if (pointToZones[pointi] == labelPair(-2, -2))
{
multiZoneMeshPoints.append(pointi);
// Unmark as feature angle point
patchEdgeNormal[pointi] = nullVector;
featEdgeNormal[pointi] = nullPN;
}
}
DynamicList<label> twoZoneMeshPoints(allBoundary.nPoints());
forAll(patchEdgeNormal, pointi)
{
if (patchEdgeNormal[pointi] != nullVector)
{
twoZoneMeshPoints.append(pointi);
// Unmark as feature angle point
featEdgeNormal[pointi] = nullPN;
}
}
// Sort featEdgeNormal according to zone
List<List<label>> zoneToMeshPoints(surfZones.size());
List<vectorField> zoneToNormal(surfZones.size());
{
labelList sizes(surfZones.size(), 0);
forAll(featEdgeNormal, pointi)
{
const auto& pInfo = featEdgeNormal[pointi];
if (pInfo != nullPN)
{
const label zonei = pInfo.first();
sizes[zonei]++;
}
}
forAll(zoneToMeshPoints, zonei)
{
zoneToMeshPoints[zonei].setSize(sizes[zonei]);
zoneToNormal[zonei].setSize(sizes[zonei]);
}
sizes = 0;
forAll(featEdgeNormal, pointi)
{
const auto& pInfo = featEdgeNormal[pointi];
if (pInfo != nullPN)
{
const label zonei = pInfo.first();
const label index = sizes[zonei]++;
zoneToMeshPoints[zonei][index] = pointi;
zoneToNormal[zonei][index] = pInfo.second();
}
}
}
// Add patches
forAll(zoneToMeshPoints, zonei)
{
const label nPoints =
returnReduce(zoneToMeshPoints[zonei].size(), sumOp<label>());
const word patchName(surfZones[zonei].name() + "Edges");
if (nPoints && (pointBm.findPatchID(patchName) == -1))
{
const_cast<pointBoundaryMesh&>(pointBm).push_back
(
new meshPointPatch
(
patchName,
zoneToMeshPoints[zonei],
zoneToNormal[zonei],
pointBm.size(),
pointBm,
meshPointPatch::typeName
)
);
if (verbose)
{
const auto& ppp = pointBm.last();
Info<< "Added feature-edges pointPatch " << ppp.name()
<< " with " << nPoints << " points" << endl;
}
}
}
// Add inter-patch points
const word allEdgePatchName("boundaryEdges");
const label nPatchEdgePoints =
returnReduce(twoZoneMeshPoints.size(), sumOp<label>());
if (nPatchEdgePoints && (pointBm.findPatchID(allEdgePatchName) == -1))
{
const_cast<pointBoundaryMesh&>(pointBm).push_back
(
new meshPointPatch
(
allEdgePatchName,
twoZoneMeshPoints,
vectorField
(
patchEdgeNormal, // is pointNormal expanded to all mesh
twoZoneMeshPoints
),
pointBm.size(),
pointBm,
meshPointPatch::typeName
)
);
if (verbose)
{
const auto& ppp = pointBm.last();
Info<< "Added inter-patch pointPatch " << ppp.name()
<< " with " << nPatchEdgePoints << " points" << endl;
}
}
const word allPointPatchName("boundaryPoints");
const label nMultiPoints =
returnReduce(multiZoneMeshPoints.size(), sumOp<label>());
if (nMultiPoints && (pointBm.findPatchID(allPointPatchName) == -1))
{
const_cast<pointBoundaryMesh&>(pointBm).push_back
(
new meshPointPatch
(
allPointPatchName,
multiZoneMeshPoints,
vectorField
(
meshPointNormals, // is pointNormal expanded to all mesh
multiZoneMeshPoints
),
pointBm.size(),
pointBm,
meshPointPatch::typeName
)
);
if (verbose)
{
const auto& ppp = pointBm.last();
Info<< "Added multi-patch pointPatch " << ppp.name()
<< " with " << nMultiPoints << " points" << endl;
}
}
// Shuffle into order
labelList oldToNew(pointBm.size());
label newPatchi = 0;
forAll(pointBm, patchi)
{
if (!isA<processorPointPatch>(pointBm[patchi]))
{
oldToNew[patchi] = newPatchi++;
}
}
forAll(pointBm, patchi)
{
if (isA<processorPointPatch>(pointBm[patchi]))
{
oldToNew[patchi] = newPatchi++;
}
}
const_cast<pointBoundaryMesh&>(pointBm).reorder(oldToNew, true);
return pointBm.size() - nPointPatches;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
int main(int argc, char *argv[])
@ -706,12 +152,6 @@ int main(int argc, char *argv[])
true // mark as an advanced option
);
argList::addOptionCompat("exclude-patches", {"excludePatches", 2306});
argList::addOption
(
"featureAngle",
"angle",
"Auto-extract feature edges/points and put into separate point-patches"
);
#include "setRootCase.H"
#include "createTime.H"
@ -759,28 +199,9 @@ int main(int argc, char *argv[])
<< nl << endl;
}
scalar featureAngle = 180.0;
const bool specifiedFeature = args.readIfPresent
(
"featureAngle",
featureAngle
);
Info<< "Reading mesh from time " << runTime.value() << endl;
#include "createNamedPolyMesh.H"
if (specifiedFeature)
{
Info<< "Detecting all sharp (>" << featureAngle
<< " degrees) patch edges." << nl << endl;
//#include "createNamedPointMesh.H"
// Do not read constant/pointMesh - construct from polyMesh only
Info<< "Create pointMesh for time = "
<< runTime.timeName() << Foam::nl << Foam::endl;
(void)pointMesh::New(mesh);
}
// User specified times
instantList timeDirs = timeSelector::select0(runTime, args);
@ -854,8 +275,6 @@ int main(int argc, char *argv[])
// Mesh face and compact zone indx
DynamicList<label> faceLabels;
DynamicList<label> compactZones;
// Per compact 'zone' index the name and location
surfZoneIdentifierList surfZones;
{
// Collect sizes. Hash on names to handle local-only patches (e.g.
@ -897,17 +316,6 @@ int main(int argc, char *argv[])
Pstream::broadcast(compactZoneID);
// Zones
surfZones.resize_nocopy(compactZoneID.size());
forAllConstIters(compactZoneID, iter)
{
surfZones[*iter] = surfZoneIdentifier(iter.key(), *iter);
Info<< "surfZone " << *iter
<< " : " << surfZones[*iter].name()
<< endl;
}
// Rework HashTable into labelList just for speed of conversion
labelList patchToCompactZone(bMesh.size(), -1);
labelList faceZoneToCompactZone(bMesh.size(), -1);
@ -953,7 +361,7 @@ int main(int argc, char *argv[])
// Addressing engine for all faces
const uindirectPrimitivePatch allBoundary
uindirectPrimitivePatch allBoundary
(
UIndirectList<face>(mesh.faces(), faceLabels),
mesh.points()
@ -991,7 +399,7 @@ int main(int argc, char *argv[])
// Gather all ZoneIDs
List<labelList> gatheredZones(Pstream::nProcs());
gatheredZones[Pstream::myProcNo()] = compactZones;
gatheredZones[Pstream::myProcNo()].transfer(compactZones);
Pstream::gatherList(gatheredZones);
// On master combine all points, faces, zones
@ -1019,6 +427,16 @@ int main(int argc, char *argv[])
gatheredZones.clear();
// Zones
surfZoneIdentifierList surfZones(compactZoneID.size());
forAllConstIters(compactZoneID, iter)
{
surfZones[*iter] = surfZoneIdentifier(iter.key(), *iter);
Info<< "surfZone " << *iter
<< " : " << surfZones[*iter].name()
<< endl;
}
UnsortedMeshedSurface<face> unsortedFace
(
std::move(allPoints),
@ -1045,31 +463,6 @@ int main(int argc, char *argv[])
sortedFace.write(globalCasePath);
}
if (specifiedFeature)
{
// Add edge patches
const auto& pMesh = pointMesh::New(mesh);
const label nAdded = addMeshPointPatches
(
mesh,
pMesh,
allBoundary, // all patches together
compactZones, // originating compactZone
surfZones, // per compactZone the index
featureAngle,
featureAngle
);
if (nAdded)
{
pMesh.boundary().write();
}
}
}
Info<< "End\n" << endl;

View File

@ -440,15 +440,6 @@ pointSet_doc
}
//- All points of pointpatch
{
source patchToPoint;
patches ("patch.*");
// or
patch somePatch;
}
//- Copy elements from pointSet
{
source pointToPoint;

View File

@ -38,8 +38,8 @@ SourceFiles
\*---------------------------------------------------------------------------*/
#ifndef Foam_ODESolver_H
#define Foam_ODESolver_H
#ifndef ODESolver_H
#define ODESolver_H
#include "ODESystem.H"
#include "typeInfo.H"
@ -56,9 +56,10 @@ namespace Foam
class ODESolver
{
protected:
// Protected Data
// Protected data
//- Reference to ODESystem
const ODESystem& odes_;
@ -105,7 +106,7 @@ public:
class stepState
{
public:
public:
const bool forward;
scalar dxTry;
@ -170,14 +171,14 @@ public:
// Member Functions
//- The number of equations to solve
label nEqns() const noexcept { return n_; }
//- Return the number of equations to solve
inline label nEqns() const;
//- Access to the absolute tolerance field
scalarField& absTol() noexcept { return absTol_; }
//- Return access to the absolute tolerance field
inline scalarField& absTol();
//- Access to the relative tolerance field
scalarField& relTol() noexcept { return relTol_; }
//- Return access to the relative tolerance field
inline scalarField& relTol();
//- Resize the ODE solver
virtual bool resize() = 0;

View File

@ -27,19 +27,36 @@ License
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
inline Foam::label Foam::ODESolver::nEqns() const
{
return n_;
}
inline Foam::scalarField& Foam::ODESolver::absTol()
{
return absTol_;
}
inline Foam::scalarField& Foam::ODESolver::relTol()
{
return relTol_;
}
template<class Type>
inline void Foam::ODESolver::resizeField(UList<Type>& f, const label n)
{
// shallowResize
f.shallowCopy(f.data(), n);
f.shallowCopy(UList<Type>(f.begin(), n));
}
template<class Type>
inline void Foam::ODESolver::resizeField(UList<Type>& f) const
{
// shallowResize
f.shallowCopy(f.data(), n_);
resizeField(f, n_);
}

View File

@ -716,10 +716,8 @@ $(pointMeshMapper)/pointPatchMapper.C
pointPatches = $(pointMesh)/pointPatches
$(pointPatches)/pointPatch/pointPatch.C
$(pointPatches)/pointPatch/pointPatchNew.C
$(pointPatches)/facePointPatch/facePointPatch.C
$(pointPatches)/facePointPatch/facePointPatchNew.C
$(pointPatches)/meshPointPatch/meshPointPatch.C
basicPointPatches = $(pointPatches)/basic
$(basicPointPatches)/coupled/coupledPointPatch.C

View File

@ -120,11 +120,8 @@ public:
// Static Member Functions
//- Return a null bitSet (reference to a nullObject).
static const bitSet& null() noexcept
{
return NullObjectRef<bitSet>();
}
//- Return a null bitSet reference
inline static const bitSet& null();
//- Declare type-name (with debug switch)

View File

@ -405,6 +405,12 @@ inline Foam::label Foam::bitSet::find_next(label pos) const
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
inline const Foam::bitSet& Foam::bitSet::null()
{
return NullObjectRef<bitSet>();
}
inline bool Foam::bitSet::all() const
{
if (empty()) return true; // SIC. boost convention

View File

@ -81,7 +81,7 @@ Foam::CompactListList<T> Foam::CompactListList<T>::pack_impl
if (len)
{
newOffsets.resize(len+1, Foam::zero{});
newOffsets.resize(len+1, Zero);
for (label i = 0; i < len; ++i)
{

View File

@ -138,11 +138,8 @@ public:
// Static Member Functions
//- Return a null CompactListList (reference to a nullObject).
static const CompactListList<T>& null() noexcept
{
return NullObjectRef<CompactListList<T>>();
}
//- Return a CompactListList reference to a nullObject
inline static const CompactListList<T>& null();
//- Construct by packing together the list of lists
template<class SubListType = List<T>>

View File

@ -29,6 +29,15 @@ License
#include "ListOps.H"
#include "SubList.H"
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
template<class T>
inline const Foam::CompactListList<T>& Foam::CompactListList<T>::null()
{
return NullObjectRef<CompactListList<T>>();
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
template<class T>
@ -89,7 +98,7 @@ inline Foam::CompactListList<T>::CompactListList
const label nVals
)
:
offsets_(mRows+1, Foam::zero{}),
offsets_(mRows+1, Zero),
values_(nVals)
{
// Optionally: enforceSizeSanity();
@ -104,8 +113,8 @@ inline Foam::CompactListList<T>::CompactListList
const Foam::zero
)
:
offsets_(mRows+1, Foam::zero{}),
values_(nVals, Foam::zero{})
offsets_(mRows+1, Zero),
values_(nVals, Zero)
{
// Optionally: enforceSizeSanity();
}
@ -119,7 +128,7 @@ inline Foam::CompactListList<T>::CompactListList
const T& val
)
:
offsets_(mRows+1, Foam::zero{}),
offsets_(mRows+1, Zero),
values_(nVals, val)
{
// Optionally: enforceSizeSanity();
@ -378,7 +387,7 @@ inline void Foam::CompactListList<T>::resize
}
else
{
offsets_.resize(mRows+1, Foam::zero{});
offsets_.resize(mRows+1, Zero);
values_.resize(nVals);
}
}
@ -399,7 +408,7 @@ inline void Foam::CompactListList<T>::resize_nocopy
}
else
{
offsets_.resize(mRows+1, Foam::zero{});
offsets_.resize(mRows+1, Zero);
values_.resize_nocopy(nVals);
}
}
@ -421,7 +430,7 @@ inline void Foam::CompactListList<T>::resize
}
else
{
offsets_.resize(mRows+1, Foam::zero{});
offsets_.resize(mRows+1, Zero);
values_.resize(nVals, val);
}
}

View File

@ -46,10 +46,9 @@ SourceFiles
#include "zero.H"
#include "contiguous.H"
#include "stdFoam.H"
#include "nullObject.H"
#include "autoPtr.H"
#include "Hash.H"
#include "ListPolicy.H"
#include "autoPtr.H"
// <algorithm> already included by stdFoam.H
#include <iterator>
@ -140,12 +139,8 @@ public:
// Static Functions
//- Return a null FixedList (reference to a nullObject).
//- Read/write access is questionable
static const FixedList<T, N>& null() noexcept
{
return NullObjectRef<FixedList<T, N>>();
}
//- Return a null FixedList
inline static const FixedList<T, N>& null();
// Constructors

View File

@ -28,6 +28,15 @@ License
#include "UList.H"
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
template<class T, unsigned N>
inline const Foam::FixedList<T, N>& Foam::FixedList<T, N>::null()
{
return NullObjectRef<FixedList<T, N>>();
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class T, unsigned N>

View File

@ -129,12 +129,8 @@ public:
// Static Member Functions
//- Return a null List (reference to a nullObject).
//- Behaves like an empty List.
static const List<T>& null() noexcept
{
return NullObjectRef<List<T>>();
}
//- Return a null List
inline static const List<T>& null();
// Constructors

View File

@ -133,6 +133,13 @@ inline Foam::autoPtr<Foam::List<T>> Foam::List<T>::clone() const
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class T>
inline const Foam::List<T>& Foam::List<T>::null()
{
return NullObjectRef<List<T>>();
}
template<class T>
inline void Foam::List<T>::clear()
{

View File

@ -73,12 +73,8 @@ public:
// Static Functions
//- Return a null SubList (reference to a nullObject).
//- Behaves like an empty SubList.
static const SubList<T>& null() noexcept
{
return NullObjectRef<SubList<T>>();
}
//- Return a null SubList
inline static const SubList<T>& null();
// Generated Methods

View File

@ -28,6 +28,15 @@ License
#include "FixedList.H"
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
template<class T>
inline const Foam::SubList<T>& Foam::SubList<T>::null()
{
return NullObjectRef<SubList<T>>();
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class T>
@ -115,7 +124,7 @@ inline Foam::SubList<T>::SubList
template<class T>
inline Foam::UList<T>& Foam::SubList<T>::reset(std::nullptr_t) noexcept
{
UList<T>::shallowCopy(nullptr);
UList<T>::shallowCopy(nullptr, 0);
return *this;
}

View File

@ -183,12 +183,8 @@ public:
// Static Functions
//- Return a null UList (reference to a nullObject).
//- Behaves like an empty UList.
static const UList<T>& null() noexcept
{
return NullObjectRef<UList<T>>();
}
//- Return a UList reference to a nullObject
inline static const UList<T>& null();
// Public Classes
@ -371,9 +367,6 @@ public:
//- Copy the pointer and size
inline void shallowCopy(T* __restrict__ ptr, const label len) noexcept;
//- Copy nullptr and zero size
inline void shallowCopy(std::nullptr_t) noexcept;
//- Copy the pointer and size held by the given UList
inline void shallowCopy(const UList<T>& list) noexcept;

View File

@ -93,6 +93,13 @@ inline void Foam::UList<T>::fill_uniform(const Foam::zero)
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class T>
inline const Foam::UList<T>& Foam::UList<T>::null()
{
return NullObjectRef<UList<T>>();
}
template<class T>
inline Foam::label Foam::UList<T>::fcIndex(const label i) const noexcept
{
@ -323,14 +330,6 @@ inline void Foam::UList<T>::shallowCopy
}
template<class T>
inline void Foam::UList<T>::shallowCopy(std::nullptr_t) noexcept
{
size_ = 0;
v_ = nullptr;
}
template<class T>
inline void Foam::UList<T>::shallowCopy(const UList<T>& list) noexcept
{

View File

@ -116,7 +116,7 @@ Foam::labelListList Foam::invertOneToMany
const labelUList& map
)
{
labelList sizes(len, Foam::zero{});
labelList sizes(len, Zero);
for (const label newIdx : map)
{

View File

@ -707,7 +707,7 @@ void Foam::invertManyToMany
)
{
// The output list sizes
labelList sizes(len, Foam::zero{});
labelList sizes(len, Zero);
for (const InputIntListType& sublist : input)
{

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2018-2024 OpenCFD Ltd.
Copyright (C) 2018-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -30,7 +30,7 @@ License
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class T>
Foam::label Foam::Detail::PtrListDetail<T>::count_nonnull() const noexcept
Foam::label Foam::Detail::PtrListDetail<T>::count() const noexcept
{
label n = 0;

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2018-2024 OpenCFD Ltd.
Copyright (C) 2018-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -95,8 +95,8 @@ public:
//- Return pointer to element or nullptr for out-of-range access.
inline T* get(const label i);
//- The number of non-nullptr entries in the list
label count_nonnull() const noexcept;
//- Return the number of non-null entries
label count() const noexcept;
//- FatalError if any null exists in the list
inline void checkNonNull() const;

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2018-2024 OpenCFD Ltd.
Copyright (C) 2018-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -40,8 +40,8 @@ Foam::Ostream& Foam::Detail::PtrListDetail<T>::write
{
const label len = this->size();
// The net length, optionally after trimming any nullptr
const label netLen = (trimNull ? this->count_nonnull() : len);
// The net length (after trimming any nullptr)
const label netLen = (trimNull ? this->count() : len);
if (!netLen)
{

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2018-2024 OpenCFD Ltd.
Copyright (C) 2018-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -257,8 +257,8 @@ public:
//- Size of the underlying storage.
inline label capacity() const noexcept;
//- The number of non-nullptr entries in the list
inline label count_nonnull() const noexcept;
//- The number of non-null entries in the list
inline label count() const noexcept;
//- Reference to the first element of the list
inline T& front();
@ -648,10 +648,6 @@ public:
//- Move append another list to the end of this list.
//FOAM_DEPRECATED_FOR(2022-10, "push_back()")
void append(UPtrList<T>&& other) { this->push_back(std::move(other)); }
//- The number of non-nullptr entries in the list
FOAM_DEPRECATED_FOR(2024-01, "count_nonnull()")
label count() const noexcept { return count_nonnull(); }
};

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2018-2024 OpenCFD Ltd.
Copyright (C) 2018-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -124,9 +124,9 @@ inline Foam::label Foam::UPtrList<T>::capacity() const noexcept
template<class T>
inline Foam::label Foam::UPtrList<T>::count_nonnull() const noexcept
inline Foam::label Foam::UPtrList<T>::count() const noexcept
{
return ptrs_.count_nonnull();
return ptrs_.count();
}

View File

@ -135,23 +135,15 @@ protected:
// Protected Member Functions
//- Helper: determine number of processors whose recvSizes fits
//- into maxBufferSize
static label calcNumProcs
(
const label comm,
const off_t maxBufferSize,
const labelUList& recvSizes,
const label startProci
);
//- Read data into *this. ISstream is only valid on master.
//- Read data (on master) and transmit.
static bool readBlocks
(
const label comm,
// [in] The input stream (only valid on master)
autoPtr<ISstream>& isPtr,
List<char>& contentChars,
const UPstream::commsTypes commsType
// [out] The processor local data
List<char>& localData,
const UPstream::commsTypes commsType /* unused */
);
//- Helper: skip a block of (binary) character data
@ -277,6 +269,19 @@ public:
}
//- Helper: write block of (binary) character content
// Housekeeping
static std::streamoff writeBlockEntry
(
OSstream& os,
const label blocki,
const stdFoam::span<char>& s
)
{
return writeBlockEntry(os, blocki, s.data(), s.size());
}
//- Helper: write block of (binary) character content
// Housekeeping
static std::streamoff writeBlockEntry
(
OSstream& os,
@ -307,41 +312,37 @@ public:
);
//- Read master header information (into headerIO) and return
//- data in stream. Note: isPtr is only valid on master.
//- data in stream.
static autoPtr<ISstream> readBlocks
(
const label comm,
const fileName& fName,
//! [in] The input stream (only valid on master)
autoPtr<ISstream>& isPtr,
//! [out] header information
IOobject& headerIO,
const UPstream::commsTypes commsType
const UPstream::commsTypes commsType /* unused */
);
//- Helper: gather single label. Note: using native Pstream.
// datas sized with num procs but undefined contents on
// slaves
static void gather
(
const label comm,
const label data,
labelList& datas
);
//- Helper: gather data from (subset of) slaves.
//- Helper: gather data from (subset of) sub-ranks.
// In non-blocking mode it sets up send/recv for non-empty content.
// In blocking/scheduled mode it uses MPI_Gatherv to collect data.
//
// Returns:
// - recvData : received data
// - recvData : the received data
// - recvOffsets : offset in data. recvOffsets is nProcs+1
static void gatherSlaveData
static void gatherProcData
(
const label comm,
const UList<char>& data,
const labelUList& recvSizes,
const UList<char>& localData, //!< [in] required on all procs
const labelUList& recvSizes, //!< [in] only required on master
const labelRange& fromProcs,
const labelRange& whichProcs, //!< [in] required on all procs
List<int>& recvOffsets,
DynamicList<char>& recvData
List<int>& recvOffsets, //!< [out] only relevant on master
DynamicList<char>& recvData, //!< [out] only relevant on master
const UPstream::commsTypes commsType
);
//- Write *this. Ostream only valid on master.
@ -349,19 +350,98 @@ public:
static bool writeBlocks
(
const label comm,
//! [in] output stream (relevant on master)
autoPtr<OSstream>& osPtr,
//! [out] start offsets to each block (relevant on master),
//! ignored if List::null() type
List<std::streamoff>& blockOffset,
const UList<char>& masterData,
const UList<char>& localData, //!< [in] required on all procs
const labelUList& recvSizes, //!< [in] only required on master
const labelUList& recvSizes,
// Optional slave data (on master)
const UPtrList<SubList<char>>& slaveData,
//! Optional proc data (only written on master)
//! but \b must also be symmetrically defined (empty/non-empty)
//! on all ranks
const UList<stdFoam::span<char>>& procData,
const UPstream::commsTypes commsType,
const bool syncReturnState = true
);
// Housekeeping
//- Write *this. Ostream only valid on master.
// Returns offsets of processor blocks in blockOffset
FOAM_DEPRECATED_FOR(2023-09, "write with char span instead")
static bool writeBlocks
(
const label comm,
autoPtr<OSstream>& osPtr,
List<std::streamoff>& blockOffset,
const UList<char>& localData, // [in] required on all procs
const labelUList& recvSizes, // [in] only required on master
// Optional proc data (only written on master)
// but \b must also be symmetrically defined (empty/non-empty)
// on all ranks
const UPtrList<SubList<char>>& procData,
const UPstream::commsTypes commsType,
const bool syncReturnState = true
)
{
// Transcribe to span<char>
List<stdFoam::span<char>> spans(procData.size());
forAll(procData, proci)
{
if (procData.test(proci))
{
spans[proci] = stdFoam::span<char>
(
const_cast<char*>(procData[proci].cdata()),
procData[proci].size()
);
}
}
return decomposedBlockData::writeBlocks
(
comm,
osPtr,
blockOffset,
localData,
recvSizes,
spans,
commsType,
syncReturnState
);
}
//- Deprecated(2023-09) - consider UPstream::listGatherValue
// The only difference is that this gather also resizes the output
// on the non-master procs
// \deprecated(2023-09) - consider UPstream::listGatherValue
FOAM_DEPRECATED_FOR(2023-09, "consider UPstream::listGatherValue()")
static void gather
(
const label comm,
const label localValue,
labelList& allValues
)
{
allValues.resize_nocopy(UPstream::nProcs(comm));
UPstream::mpiGather
(
reinterpret_cast<const char*>(&localValue),
allValues.data_bytes(),
sizeof(label), // The send/recv size per rank
comm
);
}
};

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2020-2024 OpenCFD Ltd.
Copyright (C) 2020-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -132,7 +132,7 @@ public:
// Member Functions
//- True if compiled with libz support
static bool supports_gz() noexcept;
static bool supports_gz();
// Access
@ -276,7 +276,7 @@ public:
// Member Functions
//- True if compiled with libz support
static bool supports_gz() noexcept;
static bool supports_gz();
// Access

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011 OpenFOAM Foundation
Copyright (C) 2018-2024 OpenCFD Ltd.
Copyright (C) 2018-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -40,7 +40,7 @@ License
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
bool Foam::ifstreamPointer::supports_gz() noexcept
bool Foam::ifstreamPointer::supports_gz()
{
#ifdef HAVE_LIBZ
return true;
@ -50,7 +50,7 @@ bool Foam::ifstreamPointer::supports_gz() noexcept
}
bool Foam::ofstreamPointer::supports_gz() noexcept
bool Foam::ofstreamPointer::supports_gz()
{
#ifdef HAVE_LIBZ
return true;
@ -71,7 +71,7 @@ Foam::ifstreamPointer::ifstreamPointer
IOstreamOption streamOpt // Currently unused
)
:
ptr_()
ptr_(nullptr)
{
open(pathname, streamOpt);
}
@ -82,7 +82,7 @@ Foam::ifstreamPointer::ifstreamPointer
const fileName& pathname
)
:
ptr_()
ptr_(nullptr)
{
open(pathname);
}
@ -110,7 +110,7 @@ Foam::ofstreamPointer::ofstreamPointer
const bool atomic
)
:
ptr_(),
ptr_(nullptr),
atomic_(atomic)
{
std::ios_base::openmode mode

View File

@ -29,7 +29,7 @@ License
#include "masterOFstream.H"
#include "OFstream.H"
#include "OSspecific.H"
#include "PstreamBuffers.H"
#include "Pstream.H"
#include "masterUncollatedFileOperation.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
@ -38,10 +38,10 @@ void Foam::masterOFstream::checkWrite
(
const fileName& fName,
const char* str,
std::streamsize len
const std::streamsize len
)
{
if (!len)
if (!str || !len)
{
// Can probably skip all of this if there is nothing to write
return;
@ -63,9 +63,7 @@ void Foam::masterOFstream::checkWrite
<< exit(FatalIOError);
}
// Use writeRaw() instead of writeQuoted(string,false) to output
// characters directly.
// Write characters directly to std::ostream
os.writeRaw(str, len);
if (!os.good())
@ -77,97 +75,159 @@ void Foam::masterOFstream::checkWrite
}
void Foam::masterOFstream::checkWrite
(
const fileName& fName,
const std::string& s
)
{
checkWrite(fName, s.data(), s.length());
}
void Foam::masterOFstream::commit()
{
// Take ownership of serialized content, without copying or reallocation
DynamicList<char> charData(OCharStream::release());
if (UPstream::parRun())
{
// Ignore content if not writing (reduces communication)
if (!writeOnProc_)
{
charData.clear();
}
List<fileName> filePaths(UPstream::nProcs(comm_));
filePaths[UPstream::myProcNo(comm_)] = pathName_;
Pstream::gatherList(filePaths, UPstream::msgType(), comm_);
// Test for identical output paths
bool uniform =
(
UPstream::master(comm_)
&& fileOperation::uniformFile(filePaths)
? fileOperation::uniformFile(filePaths)
: true
);
Pstream::broadcast(uniform, comm_);
if (uniform)
{
// Identical file paths - write on master
if (UPstream::master(comm_) && writeOnProc_)
{
checkWrite(pathName_, this->str());
checkWrite(pathName_, charData);
}
this->reset();
return;
}
// Different files
PstreamBuffers pBufs(comm_, UPstream::commsTypes::nonBlocking);
// ---------------
// Current strategy is to setup all non-blocking send/recv
// using the probed message size to establish the recv size
// (to avoid an additional communication of the sizes).
//
// For ranks with writeOnProc=false, the message size is 0.
if (!UPstream::master(comm_))
// An alternative approach would be to gather recv sizes
// to avoid zero-sized messages and/or use double buffering
// to recv into a buffer and write.
//
// const labelList recvSizes
// (
// UPstream::listGatherValues<label>
// (
// (UPstream::is_subrank(comm_) ? charData.size() : label(0)),
// comm_
// )
// );
const label startOfRequests = UPstream::nRequests();
// Some unique tag for this read/write/probe grouping
const int messageTag = UPstream::msgType() + 256;
if (UPstream::is_subrank(comm_))
{
if (writeOnProc_)
{
// Send buffer to master
string s(this->str());
UOPstream os(UPstream::masterNo(), pBufs);
os.write(s.data(), s.length());
}
this->reset(); // Done with contents
// Send to master. When (!writeOnProc_) it is zero-sized.
UOPstream::write
(
UPstream::commsTypes::nonBlocking,
UPstream::masterNo(),
charData.cdata_bytes(),
charData.size_bytes(),
messageTag,
comm_
);
}
pBufs.finishedGathers();
if (UPstream::master(comm_))
else if (UPstream::master(comm_))
{
// The receive slots
List<List<char>> procBuffers(UPstream::nProcs(comm_));
const auto recvProcs = UPstream::subProcs(comm_);
for (const int proci : recvProcs)
{
auto& procSlice = procBuffers[proci];
// Probe the message size
std::pair<int, int> probed =
UPstream::probeMessage
(
UPstream::commsTypes::blocking,
proci,
messageTag,
comm_
);
procSlice.resize_nocopy(probed.second);
// Receive content (can also be zero-sized)
UIPstream::read
(
UPstream::commsTypes::nonBlocking,
proci,
procSlice.data_bytes(),
procSlice.size_bytes(),
messageTag,
comm_
);
}
if (writeOnProc_)
{
// Write master data
checkWrite(filePaths[UPstream::masterNo()], this->str());
// Write non-empty master data
checkWrite(pathName_, charData);
}
this->reset(); // Done with contents
// Allocate large enough to read without resizing
List<char> buf(pBufs.maxRecvCount());
for (const int proci : UPstream::subProcs(comm_))
// Poll for completed receive requests and dispatch
DynamicList<int> indices(recvProcs.size());
while
(
UPstream::waitSomeRequests
(
startOfRequests,
recvProcs.size(),
&indices
)
)
{
const std::streamsize count(pBufs.recvDataCount(proci));
if (count)
for (const int idx : indices)
{
UIPstream is(proci, pBufs);
const int proci = recvProcs[idx];
auto& procSlice = procBuffers[proci];
is.read(buf.data(), count);
checkWrite(filePaths[proci], buf.cdata(), count);
if (!procSlice.empty())
{
// Write non-empty sub-proc data
checkWrite(filePaths[proci], procSlice);
}
// Eager cleanup?
// TBD: procSlice.clear();
}
}
}
UPstream::waitRequests(startOfRequests);
}
else
{
checkWrite(pathName_, this->str());
this->reset();
// Write (non-empty) data
checkWrite(pathName_, charData);
}
// This method is only called once (internally)
// so no need to clear/flush old buffered data
}
@ -183,7 +243,7 @@ Foam::masterOFstream::masterOFstream
const bool writeOnProc
)
:
OStringStream(streamOpt),
OCharStream(streamOpt),
pathName_(pathName),
atomic_(atomic),
compression_(streamOpt.compression()),

View File

@ -41,7 +41,7 @@ SourceFiles
#ifndef Foam_masterOFstream_H
#define Foam_masterOFstream_H
#include "StringStream.H"
#include "SpanStream.H"
#include "UPstream.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -55,7 +55,7 @@ namespace Foam
class masterOFstream
:
public OStringStream
public OCharStream
{
// Private Data
@ -85,13 +85,20 @@ class masterOFstream
(
const fileName& fName,
const char* str,
std::streamsize len
const std::streamsize len
);
//- Open file with checking and write append contents
void checkWrite(const fileName& fName, const std::string& s);
void checkWrite
(
const fileName& fName,
const UList<char>& charData
)
{
checkWrite(fName, charData.cdata(), charData.size_bytes());
}
//- Commit buffered information, including parallel gather as required
//- Commit buffered information, including communication as required
void commit();

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2015 OpenFOAM Foundation
Copyright (C) 2018-2024 OpenCFD Ltd.
Copyright (C) 2018-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -468,41 +468,6 @@ inline IOstream& scientific(IOstream& io)
namespace Detail
{
/*---------------------------------------------------------------------------*\
Class Detail::StreamAllocator Declaration
\*---------------------------------------------------------------------------*/
//- A wrapper to hold a std::stream type for OpenFOAM wrapped streams.
//- This is necessary since the OpenFOAM streams hold a reference to
//- the normal std::stream
template<class StreamType>
class StreamAllocator
{
protected:
// Protected Data
//- The std::stream
StreamType stream_;
// Constructors
//- Default construct (empty)
StreamAllocator() = default;
};
} // End namespace Detail
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Functions/Algorithms
namespace Detail
{
//- Termination for input looping (no-op)
template<class IS> inline void inputLoop(IS&) {}

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2013 OpenFOAM Foundation
Copyright (C) 2021-2024 OpenCFD Ltd.
Copyright (C) 2021-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -71,33 +71,6 @@ public:
const label comm = UPstream::worldComm,
IOstreamOption::streamFormat fmt = IOstreamOption::BINARY
);
// Static Functions
//- Receive and deserialize a value.
//- Uses \c operator>> for de-serialization
template<class Type>
static void recv
(
Type& value,
const int fromProcNo,
const int tag = UPstream::msgType(),
const label comm = UPstream::worldComm,
IOstreamOption::streamFormat fmt = IOstreamOption::BINARY
)
{
IPstream is
(
UPstream::commsTypes::scheduled,
fromProcNo,
0, // bufSize
tag,
comm,
fmt
);
is >> value;
}
};

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2013 OpenFOAM Foundation
Copyright (C) 2021-2024 OpenCFD Ltd.
Copyright (C) 2021-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -71,73 +71,6 @@ public:
const label comm = UPstream::worldComm,
IOstreamOption::streamFormat fmt = IOstreamOption::BINARY
);
// Static Functions
//- Serialize a value and send (buffered/blocking or standard mode).
//- Uses \c operator<< for serialization
template<class Type>
static void send
(
const Type& value,
//! blocking or scheduled only!
const UPstream::commsTypes commsType,
const int toProcNo,
const int tag = UPstream::msgType(),
const label comm = UPstream::worldComm,
IOstreamOption::streamFormat fmt = IOstreamOption::BINARY
)
{
OPstream os(commsType, toProcNo, 0, tag, comm, fmt);
os << value;
}
//- Serialize a value and send (buffered/blocking mode).
//- Uses \c operator<< for serialization
template<class Type>
static void bsend
(
const Type& value,
const int toProcNo,
const int tag = UPstream::msgType(),
const label comm = UPstream::worldComm,
IOstreamOption::streamFormat fmt = IOstreamOption::BINARY
)
{
OPstream::send
(
value,
UPstream::commsTypes::blocking,
toProcNo,
tag,
comm,
fmt
);
}
//- Serialize a value and send (standard mode).
//- Uses \c operator<< for serialization
template<class Type>
static void send
(
const Type& value,
const int toProcNo,
const int tag = UPstream::msgType(),
const label comm = UPstream::worldComm,
IOstreamOption::streamFormat fmt = IOstreamOption::BINARY
)
{
OPstream::send
(
value,
UPstream::commsTypes::scheduled,
toProcNo,
tag,
comm,
fmt
);
}
};

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2016-2024 OpenCFD Ltd.
Copyright (C) 2016-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -47,6 +47,9 @@ SourceFiles
#include "UPstream.H"
#include "DynamicList.H"
// Legacy
// #define Foam_Pstream_scatter_nobroadcast
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
@ -127,9 +130,22 @@ public:
// Gather
//- Gather (reduce) data, appyling \c bop to combine \c value
//- from different processors. The basis for Foam::reduce().
// Uses the specified communication schedule.
template<class T, class BinaryOp>
static void gather
(
const List<commsStruct>& comms,
T& value,
const BinaryOp& bop,
const int tag,
const label comm
);
//- Gather (reduce) data, applying \c bop to combine \c value
//- from different processors. The basis for Foam::reduce().
// Uses linear/tree communication (with parallel guard).
// Uses linear/tree communication.
template<class T, class BinaryOp>
static void gather
(
@ -139,46 +155,46 @@ public:
const label comm = UPstream::worldComm
);
//- Gather individual values into list locations.
// On master list length == nProcs, otherwise zero length.
// \n
// For \b non-parallel :
// the returned list length is 1 with localValue.
template<class T>
static List<T> listGatherValues
(
const T& localValue,
const label comm = UPstream::worldComm,
//! Only used for non-contiguous types
const int tag = UPstream::msgType()
);
//- Scatter individual values from list locations.
// On master input list length == nProcs, ignored on other procs.
// \n
// For \b non-parallel :
// returns the first list element (or default initialized).
template<class T>
static T listScatterValues
(
const UList<T>& allValues,
const label comm = UPstream::worldComm,
//! Only used for non-contiguous types
const int tag = UPstream::msgType()
);
// Gather/combine data
// Inplace combine values from processors.
// (Uses construct from Istream instead of \c << operator)
// (Uses construct from Istream instead of <<)
//- Gather data, applying \c cop to inplace combine \c value
//- from different processors.
// Uses linear/tree communication (with parallel guard).
// Uses the specified communication schedule.
template<class T, class CombineOp>
static void combineGather
(
//! [in,out]
const List<commsStruct>& comms,
T& value,
const CombineOp& cop,
const int tag,
const label comm
);
//- Gather data, applying \c cop to inplace combine \c value
//- from different processors.
// Uses linear/tree communication.
template<class T, class CombineOp>
static void combineGather
(
T& value,
const CombineOp& cop,
const int tag = UPstream::msgType(),
const label comm = UPstream::worldComm
);
//- Reduce inplace (cf. MPI Allreduce)
//- applying \c cop to inplace combine \c value
//- from different processors.
//- After completion all processors have the same data.
// Uses the specified communication schedule.
// Wraps combineGather/broadcast (may change in the future).
template<class T, class CombineOp>
static void combineReduce
(
const List<commsStruct>& comms,
T& value,
const CombineOp& cop,
const int tag = UPstream::msgType(),
@ -194,7 +210,6 @@ public:
template<class T, class CombineOp>
static void combineReduce
(
//! [in,out]
T& value,
const CombineOp& cop,
const int tag = UPstream::msgType(),
@ -217,25 +232,30 @@ public:
// Combine variants working on whole List at a time.
//- Combines List elements.
// Uses linear/tree communication (with parallel guard).
template<class T, class CombineOp>
static void listCombineGather
(
//! [in,out]
UList<T>& values,
const List<commsStruct>& comms,
List<T>& values,
const CombineOp& cop,
const int tag,
const label comm
);
//- Like above but switches between linear/tree communication
template<class T, class CombineOp>
static void listCombineGather
(
List<T>& values,
const CombineOp& cop,
const int tag = UPstream::msgType(),
const label comm = UPstream::worldComm
);
//- Combines List elements.
//- After completion all processors have the same data.
// Uses linear/tree communication (with parallel guard).
template<class T, class CombineOp>
static void listCombineReduce
(
//! [in,out] - List (not UList) due to broadcast()
List<T>& values,
const CombineOp& cop,
const int tag = UPstream::msgType(),
@ -246,7 +266,6 @@ public:
template<class T, class CombineOp>
static void listCombineAllGather
(
//! [in,out] - List (not UList) due to broadcast()
List<T>& values,
const CombineOp& cop,
const int tag = UPstream::msgType(),
@ -260,8 +279,17 @@ public:
// Combine variants working on whole map at a time.
// Container needs iterators, find() and insert methods defined.
//- Combine Map elements.
// Uses linear/tree communication (with parallel guard).
template<class Container, class CombineOp>
static void mapCombineGather
(
const List<commsStruct>& comms,
Container& values,
const CombineOp& cop,
const int tag,
const label comm
);
//- Like above but switches between linear/tree communication
template<class Container, class CombineOp>
static void mapCombineGather
(
@ -310,9 +338,8 @@ public:
template<class T>
static void gatherList
(
const UList<commsStruct>& comms,
//! [in,out]
UList<T>& values,
const List<commsStruct>& comms,
List<T>& values,
const int tag,
const label comm
);
@ -322,48 +349,133 @@ public:
template<class T>
static void gatherList
(
//! [in,out]
UList<T>& values,
List<T>& values,
const int tag = UPstream::msgType(),
const label comm = UPstream::worldComm
);
//- Gather data, but keep individual values separate.
//- Uses MPI_Allgather or manual linear/tree communication.
//- Uses linear/tree communication.
// After completion all processors have the same data.
// Wraps gatherList/scatterList (may change in the future).
template<class T>
static void allGatherList
(
//! [in,out]
UList<T>& values,
List<T>& values,
const int tag = UPstream::msgType(),
const label comm = UPstream::worldComm
);
// Scatter
// Scatter
//- Inverse of gatherList.
//- Uses the specified communication schedule.
template<class T>
static void scatterList
(
const UList<commsStruct>& comms,
UList<T>& values,
const int tag,
const label comm
);
//- Broadcast data: Distribute without modification.
// \note comms and tag parameters only used when
// Foam_Pstream_scatter_nobroadcast is defined
template<class T>
static void scatter
(
const List<commsStruct>& comms,
T& value,
const int tag,
const label comm
);
//- Inverse of gatherList.
//- Uses linear/tree communication.
template<class T>
static void scatterList
(
UList<T>& values,
const int tag = UPstream::msgType(),
const label comm = UPstream::worldComm
);
//- Broadcast data: Distribute without modification.
// \note tag parameter only used when
// Foam_Pstream_scatter_nobroadcast is defined
template<class T>
static void scatter
(
T& value,
const int tag = UPstream::msgType(),
const label comm = UPstream::worldComm
);
//- Broadcast data: Distribute without modification.
// \note tag parameter only used when
// Foam_Pstream_scatter_nobroadcast is defined
template<class T>
static void combineScatter
(
const List<commsStruct>& comms,
T& value,
const int tag,
const label comm
);
//- Broadcast data: Distribute without modification.
// \note tag parameter only used when
// Foam_Pstream_scatter_nobroadcast is defined
template<class T>
static void combineScatter
(
T& value,
const int tag = UPstream::msgType(),
const label comm = UPstream::worldComm
);
//- Broadcast data: Distribute without modification.
// \note comms and tag parameters only used when
// Foam_Pstream_scatter_nobroadcast is defined
template<class T>
static void listCombineScatter
(
const List<commsStruct>& comms,
List<T>& value,
const int tag,
const label comm
);
//- Broadcast data: Distribute without modification.
// \note comms and tag parameters only used when
// Foam_Pstream_scatter_nobroadcast is defined
template<class T>
static void listCombineScatter
(
List<T>& value,
const int tag = UPstream::msgType(),
const label comm = UPstream::worldComm
);
//- Broadcast data: Distribute without modification.
template<class Container>
static void mapCombineScatter
(
const List<commsStruct>& comms,
Container& values,
const int tag,
const label comm
);
//- Like above but switches between linear/tree communication
template<class Container>
static void mapCombineScatter
(
Container& values,
const int tag = UPstream::msgType(),
const label comm = UPstream::worldComm
);
//- Scatter data. Reverse of gatherList
template<class T>
static void scatterList
(
const List<commsStruct>& comms,
List<T>& values,
const int tag,
const label comm
);
//- Like above but switches between linear/tree communication
template<class T>
static void scatterList
(
List<T>& values,
const int tag = UPstream::msgType(),
const label comm = UPstream::worldComm
);
// Exchange
@ -542,61 +654,6 @@ public:
const label comm,
const bool wait = true //!< (ignored)
);
// Housekeeping
//- \deprecated(2024-01) Broadcast data
template<class T>
FOAM_DEPRECATED_FOR(2024-01, "Pstream::broadcast()")
static void scatter
(
T& value,
const int tag = UPstream::msgType(), //!< ignored
const label comm = UPstream::worldComm
)
{
Pstream::broadcast(value, comm);
}
//- \deprecated(2024-01) Broadcast data
template<class T>
FOAM_DEPRECATED_FOR(2024-01, "Pstream::broadcast()")
static void combineScatter
(
T& value,
const int tag = UPstream::msgType(), //!< ignored
const label comm = UPstream::worldComm
)
{
Pstream::broadcast(value, comm);
}
//- \deprecated(2024-01) Broadcast data
template<class T>
FOAM_DEPRECATED_FOR(2024-01, "Pstream::broadcast()")
static void listCombineScatter
(
List<T>& value,
const int tag = UPstream::msgType(), //!< ignored
const label comm = UPstream::worldComm
)
{
Pstream::broadcast(value, comm);
}
//- \deprecated(2024-01) Broadcast data
template<class Container>
FOAM_DEPRECATED_FOR(2024-01, "Pstream::broadcast()")
static void mapCombineScatter
(
Container& values,
const int tag = UPstream::msgType(), //!< ignored
const label comm = UPstream::worldComm
)
{
Pstream::broadcast(values, comm);
}
};

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2022-2024 OpenCFD Ltd.
Copyright (C) 2022-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -137,32 +137,4 @@ void Foam::Pstream::broadcastList(ListType& list, const label comm)
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Convenience wrappers - defined after all specialisations are known
namespace Foam
{
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
//- Return a broadcasted value (uses a copy internally)
template<class Type>
Type returnBroadcast
(
const Type& value,
const label comm = UPstream::worldComm
)
{
Type work(value);
Pstream::broadcast(work, comm);
return work;
}
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// ************************************************************************* //

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2019-2024 OpenCFD Ltd.
Copyright (C) 2019-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -25,7 +25,7 @@ License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Description
Variant of gather.
Variant of gather, scatter.
Normal gather uses:
- default construct and read (>>) from Istream
- binary operator and assignment operator to combine values
@ -46,6 +46,7 @@ Description
template<class T, class CombineOp>
void Foam::Pstream::combineGather
(
const List<UPstream::commsStruct>& comms,
T& value,
const CombineOp& cop,
const int tag,
@ -54,10 +55,8 @@ void Foam::Pstream::combineGather
{
if (UPstream::is_parallel(comm))
{
// Communication order
const auto& comms = UPstream::whichCommunication(comm);
// if (comms.empty()) return; // extra safety?
const auto& myComm = comms[UPstream::myProcNo(comm)];
// My communication order
const commsStruct& myComm = comms[UPstream::myProcNo(comm)];
// Receive from my downstairs neighbours
for (const label belowID : myComm.below())
@ -90,7 +89,7 @@ void Foam::Pstream::combineGather
(
UPstream::commsTypes::scheduled,
belowID,
0, // bufsize
0,
tag,
comm
);
@ -107,7 +106,7 @@ void Foam::Pstream::combineGather
}
// Send up value
if (myComm.above() >= 0)
if (myComm.above() != -1)
{
if (debug & 2)
{
@ -133,7 +132,7 @@ void Foam::Pstream::combineGather
(
UPstream::commsTypes::scheduled,
myComm.above(),
0, // bufsize
0,
tag,
comm
);
@ -144,6 +143,144 @@ void Foam::Pstream::combineGather
}
template<class T>
void Foam::Pstream::combineScatter
(
const List<UPstream::commsStruct>& comms,
T& value,
const int tag,
const label comm
)
{
#ifndef Foam_Pstream_scatter_nobroadcast
Pstream::broadcast(value, comm);
#else
if (UPstream::is_parallel(comm))
{
// My communication order
const UPstream::commsStruct& myComm = comms[UPstream::myProcNo(comm)];
// Receive from up
if (myComm.above() != -1)
{
if (is_contiguous<T>::value)
{
UIPstream::read
(
UPstream::commsTypes::scheduled,
myComm.above(),
reinterpret_cast<char*>(&value),
sizeof(T),
tag,
comm
);
}
else
{
IPstream fromAbove
(
UPstream::commsTypes::scheduled,
myComm.above(),
0,
tag,
comm
);
value = T(fromAbove);
}
}
// Send to my downstairs neighbours
forAllReverse(myComm.below(), belowI)
{
const label belowID = myComm.below()[belowI];
if (is_contiguous<T>::value)
{
UOPstream::write
(
UPstream::commsTypes::scheduled,
belowID,
reinterpret_cast<const char*>(&value),
sizeof(T),
tag,
comm
);
}
else
{
OPstream toBelow
(
UPstream::commsTypes::scheduled,
belowID,
0,
tag,
comm
);
toBelow << value;
}
}
}
#endif
}
template<class T, class CombineOp>
void Foam::Pstream::combineGather
(
T& value,
const CombineOp& cop,
const int tag,
const label comm
)
{
Pstream::combineGather
(
UPstream::whichCommunication(comm),
value,
cop,
tag,
comm
);
}
template<class T>
void Foam::Pstream::combineScatter
(
T& value,
const int tag,
const label comm
)
{
#ifndef Foam_Pstream_scatter_nobroadcast
Pstream::broadcast(value, comm);
#else
Pstream::combineScatter
(
UPstream::whichCommunication(comm),
value,
tag,
comm
);
#endif
}
template<class T, class CombineOp>
void Foam::Pstream::combineReduce
(
const List<UPstream::commsStruct>& comms,
T& value,
const CombineOp& cop,
const int tag,
const label comm
)
{
Pstream::combineGather(comms, value, cop, tag, comm);
Pstream::broadcast(value, comm);
}
template<class T, class CombineOp>
void Foam::Pstream::combineReduce
(
@ -155,7 +292,9 @@ void Foam::Pstream::combineReduce
{
if (UPstream::is_parallel(comm))
{
Pstream::combineGather(value, cop, tag, comm);
const auto& comms = UPstream::whichCommunication(comm);
Pstream::combineGather(comms, value, cop, tag, comm);
Pstream::broadcast(value, comm);
}
}
@ -166,7 +305,8 @@ void Foam::Pstream::combineReduce
template<class T, class CombineOp>
void Foam::Pstream::listCombineGather
(
UList<T>& values,
const List<UPstream::commsStruct>& comms,
List<T>& values,
const CombineOp& cop,
const int tag,
const label comm
@ -174,10 +314,8 @@ void Foam::Pstream::listCombineGather
{
if (UPstream::is_parallel(comm))
{
// Communication order
const auto& comms = UPstream::whichCommunication(comm);
// if (comms.empty()) return; // extra safety?
const auto& myComm = comms[UPstream::myProcNo(comm)];
// My communication order
const commsStruct& myComm = comms[UPstream::myProcNo(comm)];
// Receive from my downstairs neighbours
for (const label belowID : myComm.below())
@ -213,7 +351,7 @@ void Foam::Pstream::listCombineGather
(
UPstream::commsTypes::scheduled,
belowID,
0, // bufsize
0,
tag,
comm
);
@ -233,7 +371,7 @@ void Foam::Pstream::listCombineGather
}
// Send up values
if (myComm.above() >= 0)
if (myComm.above() != -1)
{
if (debug & 2)
{
@ -259,7 +397,7 @@ void Foam::Pstream::listCombineGather
(
UPstream::commsTypes::scheduled,
myComm.above(),
0, // bufsize
0,
tag,
comm
);
@ -270,6 +408,129 @@ void Foam::Pstream::listCombineGather
}
template<class T>
void Foam::Pstream::listCombineScatter
(
const List<UPstream::commsStruct>& comms,
List<T>& values,
const int tag,
const label comm
)
{
#ifndef Foam_Pstream_scatter_nobroadcast
Pstream::broadcast(values, comm);
#else
if (UPstream::is_parallel(comm))
{
// My communication order
const UPstream::commsStruct& myComm = comms[UPstream::myProcNo(comm)];
// Receive from up
if (myComm.above() != -1)
{
if (is_contiguous<T>::value)
{
UIPstream::read
(
UPstream::commsTypes::scheduled,
myComm.above(),
values.data_bytes(),
values.size_bytes(),
tag,
comm
);
}
else
{
IPstream fromAbove
(
UPstream::commsTypes::scheduled,
myComm.above(),
0,
tag,
comm
);
fromAbove >> values;
}
}
// Send to my downstairs neighbours
forAllReverse(myComm.below(), belowI)
{
const label belowID = myComm.below()[belowI];
if (is_contiguous<T>::value)
{
UOPstream::write
(
UPstream::commsTypes::scheduled,
belowID,
values.cdata_bytes(),
values.size_bytes(),
tag,
comm
);
}
else
{
OPstream toBelow
(
UPstream::commsTypes::scheduled,
belowID,
0,
tag,
comm
);
toBelow << values;
}
}
}
#endif
}
template<class T, class CombineOp>
void Foam::Pstream::listCombineGather
(
List<T>& values,
const CombineOp& cop,
const int tag,
const label comm
)
{
Pstream::listCombineGather
(
UPstream::whichCommunication(comm),
values,
cop,
tag,
comm
);
}
template<class T>
void Foam::Pstream::listCombineScatter
(
List<T>& values,
const int tag,
const label comm
)
{
#ifndef Foam_Pstream_scatter_nobroadcast
Pstream::broadcast(values, comm);
#else
Pstream::listCombineScatter
(
UPstream::whichCommunication(comm),
values,
tag,
comm
);
#endif
}
template<class T, class CombineOp>
void Foam::Pstream::listCombineReduce
(
@ -281,7 +542,9 @@ void Foam::Pstream::listCombineReduce
{
if (UPstream::is_parallel(comm))
{
Pstream::listCombineGather(values, cop, tag, comm);
const auto& comms = UPstream::whichCommunication(comm);
Pstream::listCombineGather(comms, values, cop, tag, comm);
Pstream::broadcast(values, comm);
}
}
@ -292,6 +555,7 @@ void Foam::Pstream::listCombineReduce
template<class Container, class CombineOp>
void Foam::Pstream::mapCombineGather
(
const List<UPstream::commsStruct>& comms,
Container& values,
const CombineOp& cop,
const int tag,
@ -300,10 +564,8 @@ void Foam::Pstream::mapCombineGather
{
if (UPstream::is_parallel(comm))
{
// Communication order
const auto& comms = UPstream::whichCommunication(comm);
// if (comms.empty()) return; // extra safety?
const auto& myComm = comms[UPstream::myProcNo(comm)];
// My communication order
const commsStruct& myComm = comms[UPstream::myProcNo(comm)];
// Receive from my downstairs neighbours
for (const label belowID : myComm.below())
@ -314,7 +576,7 @@ void Foam::Pstream::mapCombineGather
(
UPstream::commsTypes::scheduled,
belowID,
0, // bufsize
0,
tag,
comm
);
@ -349,7 +611,7 @@ void Foam::Pstream::mapCombineGather
}
// Send up values
if (myComm.above() >= 0)
if (myComm.above() != -1)
{
if (debug & 2)
{
@ -361,7 +623,7 @@ void Foam::Pstream::mapCombineGather
(
UPstream::commsTypes::scheduled,
myComm.above(),
0, // bufsize
0,
tag,
comm
);
@ -371,6 +633,110 @@ void Foam::Pstream::mapCombineGather
}
template<class Container>
void Foam::Pstream::mapCombineScatter
(
const List<UPstream::commsStruct>& comms,
Container& values,
const int tag,
const label comm
)
{
#ifndef Foam_Pstream_scatter_nobroadcast
Pstream::broadcast(values, comm);
#else
if (UPstream::is_parallel(comm))
{
// My communication order
const UPstream::commsStruct& myComm = comms[UPstream::myProcNo(comm)];
// Receive from up
if (myComm.above() != -1)
{
IPstream fromAbove
(
UPstream::commsTypes::scheduled,
myComm.above(),
0,
tag,
comm
);
fromAbove >> values;
if (debug & 2)
{
Pout<< " received from "
<< myComm.above() << " data:" << values << endl;
}
}
// Send to my downstairs neighbours
forAllReverse(myComm.below(), belowI)
{
const label belowID = myComm.below()[belowI];
if (debug & 2)
{
Pout<< " sending to " << belowID << " data:" << values << endl;
}
OPstream toBelow
(
UPstream::commsTypes::scheduled,
belowID,
0,
tag,
comm
);
toBelow << values;
}
}
#endif
}
template<class Container, class CombineOp>
void Foam::Pstream::mapCombineGather
(
Container& values,
const CombineOp& cop,
const int tag,
const label comm
)
{
Pstream::mapCombineGather
(
UPstream::whichCommunication(comm),
values,
cop,
tag,
comm
);
}
template<class Container>
void Foam::Pstream::mapCombineScatter
(
Container& values,
const int tag,
const label comm
)
{
#ifndef Foam_Pstream_scatter_nobroadcast
Pstream::broadcast(values, comm);
#else
Pstream::mapCombineScatter
(
UPstream::whichCommunication(comm),
values,
tag,
comm
);
#endif
}
template<class Container, class CombineOp>
void Foam::Pstream::mapCombineReduce
(
@ -382,7 +748,9 @@ void Foam::Pstream::mapCombineReduce
{
if (UPstream::is_parallel(comm))
{
Pstream::mapCombineGather(values, cop, tag, comm);
const auto& comms = UPstream::whichCommunication(comm);
Pstream::mapCombineGather(comms, values, cop, tag, comm);
Pstream::broadcast(values, comm);
}
}

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2019-2024 OpenCFD Ltd.
Copyright (C) 2019-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -26,7 +26,7 @@ License
Description
Gather data from all processors onto single processor according to some
communication schedule (usually tree-to-master).
communication schedule (usually linear-to-master or tree-to-master).
The gathered data will be a single value constructed from the values
on individual processors using a user-specified operator.
@ -41,6 +41,7 @@ Description
template<class T, class BinaryOp>
void Foam::Pstream::gather
(
const List<UPstream::commsStruct>& comms,
T& value,
const BinaryOp& bop,
const int tag,
@ -49,10 +50,8 @@ void Foam::Pstream::gather
{
if (UPstream::is_parallel(comm))
{
// Communication order
const auto& comms = UPstream::whichCommunication(comm);
// if (comms.empty()) return; // extra safety?
const auto& myComm = comms[UPstream::myProcNo(comm)];
// My communication order
const commsStruct& myComm = comms[UPstream::myProcNo(comm)];
// Receive from my downstairs neighbours
for (const label belowID : myComm.below())
@ -77,7 +76,7 @@ void Foam::Pstream::gather
(
UPstream::commsTypes::scheduled,
belowID,
0, // bufsize
0,
tag,
comm
);
@ -88,7 +87,7 @@ void Foam::Pstream::gather
}
// Send up value
if (myComm.above() >= 0)
if (myComm.above() != -1)
{
if (is_contiguous<T>::value)
{
@ -108,7 +107,7 @@ void Foam::Pstream::gather
(
UPstream::commsTypes::scheduled,
myComm.above(),
0, // bufsize
0,
tag,
comm
);
@ -120,181 +119,110 @@ void Foam::Pstream::gather
template<class T>
Foam::List<T> Foam::Pstream::listGatherValues
void Foam::Pstream::scatter
(
const T& localValue,
const label comm,
const int tag
const List<UPstream::commsStruct>& comms,
T& value,
const int tag,
const label comm
)
{
// OR
// if (is_contiguous<T>::value)
// {
// return UPstream::listGatherValues(localValue, comm);
// }
List<T> allValues;
#ifndef Foam_Pstream_scatter_nobroadcast
Pstream::broadcast(value, comm);
#else
if (UPstream::is_parallel(comm))
{
const label numProc = UPstream::nProcs(comm);
// My communication order
const commsStruct& myComm = comms[UPstream::myProcNo(comm)];
if (UPstream::master(comm))
// Receive from up
if (myComm.above() != -1)
{
allValues.resize(numProc);
}
if (is_contiguous<T>::value)
{
UPstream::mpiGather
(
reinterpret_cast<const char*>(&localValue),
allValues.data_bytes(),
sizeof(T), // The send/recv size per rank
comm
);
}
else
{
if (UPstream::master(comm))
if (is_contiguous<T>::value)
{
// Non-trivial to manage non-blocking gather without a
// PEX/NBX approach (eg, PstreamBuffers) but leave with
// with simple exchange for now
allValues[0] = localValue;
for (int proci = 1; proci < numProc; ++proci)
{
IPstream fromProc
(
UPstream::commsTypes::scheduled,
proci,
0, // bufsize
tag,
comm
);
fromProc >> allValues[proci];
}
}
else if (UPstream::is_rank(comm))
{
OPstream toProc
UIPstream::read
(
UPstream::commsTypes::scheduled,
UPstream::masterNo(),
0, // bufsize
myComm.above(),
reinterpret_cast<char*>(&value),
sizeof(T),
tag,
comm
);
toProc << localValue;
}
else
{
IPstream fromAbove
(
UPstream::commsTypes::scheduled,
myComm.above(),
0,
tag,
comm
);
fromAbove >> value;
}
}
// Send to my downstairs neighbours. Note reverse order (compared to
// receiving). This is to make sure to send to the critical path
// (only when using a tree schedule!) first.
forAllReverse(myComm.below(), belowI)
{
const label belowID = myComm.below()[belowI];
if (is_contiguous<T>::value)
{
UOPstream::write
(
UPstream::commsTypes::scheduled,
belowID,
reinterpret_cast<const char*>(&value),
sizeof(T),
tag,
comm
);
}
else
{
OPstream toBelow
(
UPstream::commsTypes::scheduled,
belowID,
0,
tag,
comm
);
toBelow << value;
}
}
}
else
{
// non-parallel: return own value
// TBD: only when UPstream::is_rank(comm) as well?
allValues.resize(1);
allValues[0] = localValue;
}
#endif
}
return allValues;
template<class T, class BinaryOp>
void Foam::Pstream::gather
(
T& value,
const BinaryOp& bop,
const int tag,
const label comm
)
{
Pstream::gather(UPstream::whichCommunication(comm), value, bop, tag, comm);
}
template<class T>
T Foam::Pstream::listScatterValues
(
const UList<T>& allValues,
const label comm,
const int tag
)
void Foam::Pstream::scatter(T& value, const int tag, const label comm)
{
// OR
// if (is_contiguous<T>::value)
// {
// return UPstream::listScatterValues(allValues, comm);
// }
T localValue{};
if (UPstream::is_parallel(comm))
{
const label numProc = UPstream::nProcs(comm);
if (UPstream::master(comm) && allValues.size() < numProc)
{
FatalErrorInFunction
<< "Attempting to send " << allValues.size()
<< " values to " << numProc << " processors" << endl
<< Foam::abort(FatalError);
}
if (is_contiguous<T>::value)
{
UPstream::mpiScatter
(
allValues.cdata_bytes(),
reinterpret_cast<char*>(&localValue),
sizeof(T), // The send/recv size per rank
comm
);
}
else
{
if (UPstream::master(comm))
{
const label startOfRequests = UPstream::nRequests();
List<DynamicList<char>> sendBuffers(numProc);
for (int proci = 1; proci < numProc; ++proci)
{
UOPstream toProc
(
UPstream::commsTypes::nonBlocking,
proci,
sendBuffers[proci],
tag,
comm
);
toProc << allValues[proci];
}
// Wait for outstanding requests
UPstream::waitRequests(startOfRequests);
return allValues[0];
}
else if (UPstream::is_rank(comm))
{
IPstream fromProc
(
UPstream::commsTypes::scheduled,
UPstream::masterNo(),
0, // bufsize
tag,
comm
);
fromProc >> localValue;
}
}
}
else
{
// non-parallel: return first value
// TBD: only when UPstream::is_rank(comm) as well?
if (!allValues.empty())
{
return allValues[0];
}
}
return localValue;
#ifndef Foam_Pstream_scatter_nobroadcast
Pstream::broadcast(value, comm);
#else
Pstream::scatter(UPstream::whichCommunication(comm), value, tag, comm);
#endif
}
// ************************************************************************* //

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2015-2024 OpenCFD Ltd.
Copyright (C) 2015-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -26,7 +26,7 @@ License
Description
Gather data from all processors onto single processor according to some
communication schedule (usually tree-to-master).
communication schedule (usually linear-to-master or tree-to-master).
The gathered data will be a list with element procID the data from processor
procID. Before calling every processor should insert its value into
values[UPstream::myProcNo(comm)].
@ -45,27 +45,24 @@ Description
template<class T>
void Foam::Pstream::gatherList
(
const UList<UPstream::commsStruct>& comms,
UList<T>& values,
const List<UPstream::commsStruct>& comms,
List<T>& values,
const int tag,
const label comm
)
{
if (!comms.empty() && UPstream::is_parallel(comm))
if (UPstream::is_parallel(comm))
{
const label myProci = UPstream::myProcNo(comm);
const label numProc = UPstream::nProcs(comm);
if (values.size() < numProc)
if (values.size() < UPstream::nProcs(comm))
{
FatalErrorInFunction
<< "List of values:" << values.size()
<< " < numProcs:" << numProc << nl
<< "List of values is too small:" << values.size()
<< " vs numProcs:" << UPstream::nProcs(comm) << nl
<< Foam::abort(FatalError);
}
// My communication order
const auto& myComm = comms[myProci];
const commsStruct& myComm = comms[UPstream::myProcNo(comm)];
// Receive from my downstairs neighbours
for (const label belowID : myComm.below())
@ -130,21 +127,21 @@ void Foam::Pstream::gatherList
// Send up from values:
// - my own value first
// - all belowLeaves next
if (myComm.above() >= 0)
if (myComm.above() != -1)
{
const labelList& belowLeaves = myComm.allBelow();
if (debug & 2)
{
Pout<< " sending to " << myComm.above()
<< " data from me:" << myProci
<< " data:" << values[myProci] << endl;
<< " data from me:" << UPstream::myProcNo(comm)
<< " data:" << values[UPstream::myProcNo(comm)] << endl;
}
if (is_contiguous<T>::value)
{
List<T> sending(belowLeaves.size() + 1);
sending[0] = values[myProci];
sending[0] = values[UPstream::myProcNo(comm)];
forAll(belowLeaves, leafI)
{
@ -171,7 +168,7 @@ void Foam::Pstream::gatherList
tag,
comm
);
toAbove << values[myProci];
toAbove << values[UPstream::myProcNo(comm)];
for (const label leafID : belowLeaves)
{
@ -192,8 +189,8 @@ void Foam::Pstream::gatherList
template<class T>
void Foam::Pstream::scatterList
(
const UList<UPstream::commsStruct>& comms,
UList<T>& values,
const List<UPstream::commsStruct>& comms,
List<T>& values,
const int tag,
const label comm
)
@ -202,24 +199,21 @@ void Foam::Pstream::scatterList
// between scatterList() and using broadcast(List<T>&) or a regular
// scatter(List<T>&) is that processor-local data is skipped.
if (!comms.empty() && UPstream::is_parallel(comm))
if (UPstream::is_parallel(comm))
{
const label myProci = UPstream::myProcNo(comm);
const label numProc = UPstream::nProcs(comm);
if (values.size() < numProc)
if (values.size() < UPstream::nProcs(comm))
{
FatalErrorInFunction
<< "List of values:" << values.size()
<< " < numProcs:" << numProc << nl
<< "List of values is too small:" << values.size()
<< " vs numProcs:" << UPstream::nProcs(comm) << nl
<< Foam::abort(FatalError);
}
// My communication order
const auto& myComm = comms[myProci];
const commsStruct& myComm = comms[UPstream::myProcNo(comm)];
// Receive from up
if (myComm.above() >= 0)
if (myComm.above() != -1)
{
const labelList& notBelowLeaves = myComm.allNotBelow();
@ -324,18 +318,12 @@ void Foam::Pstream::scatterList
template<class T>
void Foam::Pstream::gatherList
(
UList<T>& values,
List<T>& values,
const int tag,
const label comm
)
{
Pstream::gatherList
(
UPstream::whichCommunication(comm),
values,
tag,
comm
);
Pstream::gatherList(UPstream::whichCommunication(comm), values, tag, comm);
}
@ -343,25 +331,19 @@ void Foam::Pstream::gatherList
template<class T>
void Foam::Pstream::scatterList
(
UList<T>& values,
List<T>& values,
const int tag,
const label comm
)
{
Pstream::scatterList
(
UPstream::whichCommunication(comm),
values,
tag,
comm
);
Pstream::scatterList(UPstream::whichCommunication(comm), values, tag, comm);
}
template<class T>
void Foam::Pstream::allGatherList
(
UList<T>& values,
List<T>& values,
const int tag,
const label comm
)

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2016 OpenFOAM Foundation
Copyright (C) 2016-2024 OpenCFD Ltd.
Copyright (C) 2016-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -46,6 +46,28 @@ namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
//- Reduce inplace (cf. MPI Allreduce)
//- using specified communication schedule.
template<class T, class BinaryOp>
void reduce
(
const List<UPstream::commsStruct>& comms,
T& value,
const BinaryOp& bop,
const int tag,
const label comm
)
{
if (UPstream::warnComm >= 0 && comm != UPstream::warnComm)
{
Pout<< "** reducing:" << value << " with comm:" << comm << endl;
error::printStack(Pout);
}
Pstream::gather(comms, value, bop, tag, comm);
Pstream::broadcast(value, comm);
}
//- Reduce inplace (cf. MPI Allreduce)
//- using linear/tree communication schedule
template<class T, class BinaryOp>
@ -59,13 +81,7 @@ void reduce
{
if (UPstream::is_parallel(comm))
{
if (UPstream::warnComm >= 0 && comm != UPstream::warnComm)
{
Pout<< "** reducing:" << value << " with comm:" << comm << endl;
error::printStack(Pout);
}
Pstream::gather(value, bop, tag, comm);
Pstream::broadcast(value, comm);
Foam::reduce(UPstream::whichCommunication(comm), value, bop, tag, comm);
}
}
@ -420,7 +436,8 @@ Pstream_SumReduce(double);
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
// Convenience wrappers - defined after all specialisations are known
// Convenience wrappers for some reduction operations
// - defined after all specialisations are known
//- Perform reduction on a copy, using specified binary operation
// \return the resulting value

View File

@ -52,7 +52,6 @@ Foam::UPstream::commsTypeNames
({
{ commsTypes::blocking, "blocking" },
{ commsTypes::scheduled, "scheduled" },
// { commsTypes::nonBlocking, "non-blocking" },
{ commsTypes::nonBlocking, "nonBlocking" },
});

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2015-2024 OpenCFD Ltd.
Copyright (C) 2015-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -895,32 +895,21 @@ public:
);
//- Communication schedule for tree all-to-master (proc 0)
static const List<commsStruct>&
treeCommunication
static const List<commsStruct>& treeCommunication
(
const label communicator = worldComm
);
//- Communication schedule for all-to-master (proc 0) as
//- linear/tree/none with switching based on UPstream::nProcsSimpleSum
//- and the is_parallel() state
//- Communication schedule for linear/tree all-to-master (proc 0).
//- Chooses based on the value of UPstream::nProcsSimpleSum
static const List<commsStruct>& whichCommunication
(
const label communicator = worldComm
)
{
const label np
(
parRun_ && is_rank(communicator) // cf. is_parallel()
? nProcs(communicator)
: 0
);
return
(
np <= 1
? List<commsStruct>::null()
: np < nProcsSimpleSum
nProcs(communicator) < nProcsSimpleSum
? linearCommunication(communicator)
: treeCommunication(communicator)
);
@ -1149,7 +1138,7 @@ public:
// On master input list length == nProcs, ignored on other procs.
// \n
// For \b non-parallel :
// returns the first list element (or default initialized).
// returns the first list element (or zero).
template<class T>
static T listScatterValues
(
@ -1202,7 +1191,6 @@ public:
//- Process index of first sub-process
// \deprecated(2020-09) use subProcs() method instead
FOAM_DEPRECATED_FOR(2020-09, "subProcs() method")
static constexpr int firstSlave() noexcept
{
return 1;
@ -1210,7 +1198,6 @@ public:
//- Process index of last sub-process
// \deprecated(2020-09) use subProcs() method instead
FOAM_DEPRECATED_FOR(2020-09, "subProcs() or allProcs() method")
static int lastSlave(const label communicator = worldComm)
{
return nProcs(communicator) - 1;

View File

@ -34,6 +34,14 @@ Foam::List<T> Foam::UPstream::allGatherValues
const label comm
)
{
if (!is_contiguous<T>::value)
{
FatalErrorInFunction
<< "Cannot all-gather values for non-contiguous types" << endl
<< Foam::abort(FatalError);
}
List<T> allValues;
if (UPstream::is_parallel(comm))
@ -41,17 +49,7 @@ Foam::List<T> Foam::UPstream::allGatherValues
allValues.resize(UPstream::nProcs(comm));
allValues[UPstream::myProcNo(comm)] = localValue;
if (is_contiguous<T>::value)
{
UPstream::mpiAllGather(allValues.data_bytes(), sizeof(T), comm);
}
else
{
FatalErrorInFunction
<< "Cannot all-gather values for non-contiguous types"
" - consider Pstream variant instead" << endl
<< Foam::abort(FatalError);
}
UPstream::mpiAllGather(allValues.data_bytes(), sizeof(T), comm);
}
else
{
@ -72,6 +70,14 @@ Foam::List<T> Foam::UPstream::listGatherValues
const label comm
)
{
if (!is_contiguous<T>::value)
{
FatalErrorInFunction
<< "Cannot gather values for non-contiguous types" << endl
<< Foam::abort(FatalError);
}
List<T> allValues;
if (UPstream::is_parallel(comm))
@ -81,23 +87,13 @@ Foam::List<T> Foam::UPstream::listGatherValues
allValues.resize(UPstream::nProcs(comm));
}
if (is_contiguous<T>::value)
{
UPstream::mpiGather
(
reinterpret_cast<const char*>(&localValue),
allValues.data_bytes(),
sizeof(T), // The send/recv size per rank
comm
);
}
else
{
FatalErrorInFunction
<< "Cannot gather values for non-contiguous types"
" - consider Pstream variant instead" << endl
<< Foam::abort(FatalError);
}
UPstream::mpiGather
(
reinterpret_cast<const char*>(&localValue),
allValues.data_bytes(),
sizeof(T), // The send/recv size per rank
comm
);
}
else
{
@ -118,46 +114,47 @@ T Foam::UPstream::listScatterValues
const label comm
)
{
T localValue{};
if (!is_contiguous<T>::value)
{
FatalErrorInFunction
<< "Cannot scatter values for non-contiguous types" << endl
<< Foam::abort(FatalError);
}
T localValue;
if (UPstream::is_parallel(comm))
{
const label numProc = UPstream::nProcs(comm);
const label nproc = UPstream::nProcs(comm);
if (UPstream::master(comm) && allValues.size() < numProc)
if (UPstream::master(comm) && allValues.size() < nproc)
{
FatalErrorInFunction
<< "Attempting to send " << allValues.size()
<< " values to " << numProc << " processors" << endl
<< " values to " << nproc << " processors" << endl
<< Foam::abort(FatalError);
}
if (is_contiguous<T>::value)
{
UPstream::mpiScatter
(
allValues.cdata_bytes(),
reinterpret_cast<char*>(&localValue),
sizeof(T), // The send/recv size per rank
comm
);
}
else
{
FatalErrorInFunction
<< "Cannot scatter values for non-contiguous types"
" - consider Pstream variant instead" << endl
<< Foam::abort(FatalError);
}
UPstream::mpiScatter
(
allValues.cdata_bytes(),
reinterpret_cast<char*>(&localValue),
sizeof(T), // The send/recv size per rank
comm
);
}
else
{
// non-parallel: return first value
// TBD: only when UPstream::is_rank(comm) as well?
// non-parallel: return local value
if (!allValues.empty())
if (UPstream::is_rank(comm) && !allValues.empty())
{
return allValues[0];
localValue = allValues[0];
}
else
{
localValue = Zero;
}
}

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2017-2024 OpenCFD Ltd.
Copyright (C) 2017-2022 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -46,6 +46,60 @@ SourceFiles
namespace Foam
{
namespace Detail
{
/*---------------------------------------------------------------------------*\
Class Detail::StringStreamAllocator Declaration
\*---------------------------------------------------------------------------*/
//- Allocator for variants of a std stringstream
template<class StreamType>
class StringStreamAllocator
{
protected:
// Protected Member Data
//- The stream type
typedef StreamType stream_type;
//- The input/output stream.
stream_type stream_;
// Constructors
//- Default construct
StringStreamAllocator() = default;
//- Copy construct from string
StringStreamAllocator(const std::string& s)
:
stream_(s)
{}
public:
// Member Functions
//- Get the string - as Foam::string rather than std::string
Foam::string str() const
{
return Foam::string(stream_.str());
}
//- Set the string
void str(const std::string& s)
{
stream_.str(s);
}
};
} // End namespace Detail
/*---------------------------------------------------------------------------*\
Class IStringStream Declaration
\*---------------------------------------------------------------------------*/
@ -53,12 +107,10 @@ namespace Foam
//- Input from string buffer, using a ISstream. Always UNCOMPRESSED.
class IStringStream
:
public Foam::Detail::StreamAllocator<std::istringstream>,
public Foam::ISstream
public Detail::StringStreamAllocator<std::istringstream>,
public ISstream
{
typedef
Foam::Detail::StreamAllocator<std::istringstream>
allocator_type;
typedef Detail::StringStreamAllocator<std::istringstream> allocator_type;
public:
@ -81,11 +133,9 @@ public:
IOstreamOption streamOpt = IOstreamOption()
)
:
allocator_type(),
allocator_type(s),
ISstream(stream_, "input", streamOpt.format(), streamOpt.version())
{
stream_.str(s);
}
{}
//- Construct from char*
explicit IStringStream
@ -94,32 +144,20 @@ public:
IOstreamOption streamOpt = IOstreamOption()
)
:
allocator_type(),
allocator_type(s),
ISstream(stream_, "input", streamOpt.format(), streamOpt.version())
{
stream_.str(s);
}
{}
//- Copy construct, copies content and format
IStringStream(const IStringStream& str)
:
allocator_type(),
allocator_type(str.str()),
ISstream(stream_, str.name(), static_cast<IOstreamOption>(str))
{
stream_.str(str.str());
}
{}
// Member Functions
//- Get the string.
//- As Foam::string instead of std::string (may change in future)
Foam::string str() const { return Foam::string(stream_.str()); }
//- Set the string
void str(const std::string& s) { stream_.str(s); }
//- Reset the input buffer and rewind the stream
virtual void reset(const std::string& s)
{
@ -182,12 +220,10 @@ public:
//- Output to string buffer, using a OSstream. Always UNCOMPRESSED.
class OStringStream
:
public Foam::Detail::StreamAllocator<std::ostringstream>,
public Foam::OSstream
public Detail::StringStreamAllocator<std::ostringstream>,
public OSstream
{
typedef
Foam::Detail::StreamAllocator<std::ostringstream>
allocator_type;
typedef Detail::StringStreamAllocator<std::ostringstream> allocator_type;
public:
@ -206,23 +242,13 @@ public:
//- Copy construct, copies content and format
OStringStream(const OStringStream& str)
:
allocator_type(),
allocator_type(str.str()),
OSstream(stream_, str.name(), static_cast<IOstreamOption>(str))
{
stream_.str(str.str());
}
{}
// Member Functions
//- Get the string.
//- As Foam::string instead of std::string (may change in future)
Foam::string str() const { return Foam::string(stream_.str()); }
//- Set the string
void str(const std::string& s) { stream_.str(s); }
//- Reset the output buffer and rewind the stream
void reset()
{

View File

@ -91,14 +91,13 @@ Foam::ITstream& Foam::ITstream::empty_stream()
}
Foam::tokenList Foam::ITstream::parse_chars
Foam::tokenList Foam::ITstream::parse
(
const char* s,
size_t nbytes,
const UList<char>& input,
IOstreamOption streamOpt
)
{
ISpanStream is(s, nbytes, streamOpt);
ISpanStream is(input, streamOpt);
tokenList tokens;
parseStream(is, tokens);
@ -106,14 +105,31 @@ Foam::tokenList Foam::ITstream::parse_chars
}
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::ITstream::reset(const char* input, size_t nbytes)
Foam::tokenList Foam::ITstream::parse
(
const std::string& input,
IOstreamOption streamOpt
)
{
ISpanStream is(input, nbytes, static_cast<IOstreamOption>(*this));
ISpanStream is(input, streamOpt);
parseStream(is, static_cast<tokenList&>(*this));
ITstream::seek(0); // rewind(), but bypasss virtual
tokenList tokens;
parseStream(is, tokens);
return tokens;
}
Foam::tokenList Foam::ITstream::parse
(
const char* input,
IOstreamOption streamOpt
)
{
ISpanStream is(input, strlen(input), streamOpt);
tokenList tokens;
parseStream(is, tokens);
return tokens;
}
@ -238,7 +254,10 @@ Foam::ITstream::ITstream
:
ITstream(streamOpt, name)
{
reset(input.cdata(), input.size_bytes());
ISpanStream is(input, streamOpt);
parseStream(is, static_cast<tokenList&>(*this));
ITstream::seek(0); // rewind(), but bypasss virtual
}
@ -251,7 +270,10 @@ Foam::ITstream::ITstream
:
ITstream(streamOpt, name)
{
reset(input.data(), input.size());
ISpanStream is(input, streamOpt);
parseStream(is, static_cast<tokenList&>(*this));
ITstream::seek(0); // rewind(), but bypasss virtual
}
@ -264,7 +286,10 @@ Foam::ITstream::ITstream
:
ITstream(streamOpt, name)
{
reset(input, strlen(input));
ISpanStream is(input, strlen(input), streamOpt);
parseStream(is, static_cast<tokenList&>(*this));
ITstream::seek(0); // rewind(), but bypasss virtual
}

View File

@ -77,18 +77,6 @@ class ITstream
// but leave any excess capacity (ie, like reserve).
void reserveCapacity(const label newCapacity);
//- Convert input sequence into a list of tokens,
static tokenList parse_chars
(
const char* s,
size_t nbytes,
IOstreamOption streamOpt
);
//- Convert input sequence into a list of tokens,
//- using the existing stream format. Rewinds the stream
void reset(const char* input, size_t nbytes);
//- Failsafe read-access to token at specified location
//- or undefinedToken
inline const token& peekNoFail(const label i) const
@ -170,47 +158,6 @@ public:
const string& name = "input"
);
#if __cplusplus >= 201703L
//- Construct token list by parsing the input character sequence
// Uses static parse function internally.
explicit ITstream
(
std::string_view s,
IOstreamOption streamOpt = IOstreamOption()
)
:
ITstream(streamOpt)
{
reset(s.data(), s.size());
}
#endif
//- Construct token list by parsing the input character sequence
// Uses static parse function internally.
explicit ITstream
(
stdFoam::span<char> s,
IOstreamOption streamOpt = IOstreamOption()
)
:
ITstream(streamOpt)
{
reset(s.data(), s.size());
}
//- Construct token list by parsing the input character sequence
// Uses static parse function internally.
explicit ITstream
(
stdFoam::span<const char> s,
IOstreamOption streamOpt = IOstreamOption()
)
:
ITstream(streamOpt)
{
reset(s.data(), s.size());
}
// Additional constructors
@ -260,10 +207,7 @@ public:
(
const UList<char>& input,
IOstreamOption streamOpt = IOstreamOption()
)
{
return parse_chars(input.cdata(), input.size(), streamOpt);
}
);
//- Create token list by parsing the input string
//- until no good tokens remain.
@ -271,10 +215,7 @@ public:
(
const std::string& input,
IOstreamOption streamOpt = IOstreamOption()
)
{
return parse_chars(input.data(), input.size(), streamOpt);
}
);
//- Create token list by parsing the input character sequence
//- until no good tokens remain.
@ -282,45 +223,7 @@ public:
(
const char* input,
IOstreamOption streamOpt = IOstreamOption()
)
{
return parse_chars(input, strlen(input), streamOpt);
}
#if __cplusplus >= 201703L
//- Create token list by parsing the input character sequence
//- until no good tokens remain.
static tokenList parse
(
std::string_view s,
IOstreamOption streamOpt = IOstreamOption()
)
{
return parse_chars(s.data(), s.size(), streamOpt);
}
#endif
//- Create token list by parsing the input character sequence
//- until no good tokens remain.
static tokenList parse
(
stdFoam::span<char> s,
IOstreamOption streamOpt = IOstreamOption()
)
{
return parse_chars(s.data(), s.size(), streamOpt);
}
//- Create token list by parsing the input character sequence
//- until no good tokens remain.
static tokenList parse
(
stdFoam::span<const char> s,
IOstreamOption streamOpt = IOstreamOption()
)
{
return parse_chars(s.data(), s.size(), streamOpt);
}
);
// Member Functions

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011 OpenFOAM Foundation
Copyright (C) 2019-2024 OpenCFD Ltd.
Copyright (C) 2019-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -35,8 +35,8 @@ Description
#ifndef Foam_OSHA1stream_H
#define Foam_OSHA1stream_H
#include "SHA1.H"
#include "OSstream.H"
#include "SHA1.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -114,6 +114,33 @@ public:
};
namespace Detail
{
/*---------------------------------------------------------------------------*\
Class Detail::OSHA1streamAllocator Declaration
\*---------------------------------------------------------------------------*/
//- An allocator for holding Foam::osha1stream
class OSHA1streamAllocator
{
protected:
// Protected Data
//- The output stream
Foam::osha1stream stream_;
// Constructors
//- Default construct
OSHA1streamAllocator() = default;
};
} // End namespace Detail
/*---------------------------------------------------------------------------*\
Class OSHA1stream Declaration
\*---------------------------------------------------------------------------*/
@ -121,12 +148,10 @@ public:
//- The output stream for calculating SHA1 digests
class OSHA1stream
:
public Foam::Detail::StreamAllocator<Foam::osha1stream>,
public Foam::OSstream
public Detail::OSHA1streamAllocator,
public OSstream
{
typedef
Foam::Detail::StreamAllocator<Foam::osha1stream>
allocator_type;
typedef Detail::OSHA1streamAllocator allocator_type;
public:

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2017-2024 OpenCFD Ltd.
Copyright (C) 2017-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -42,6 +42,8 @@ See Also
#define Foam_ICharStream_H
#include "ISpanStream.H"
#include "List.H"
#include "DynamicList.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -203,6 +205,33 @@ public:
};
namespace Detail
{
/*---------------------------------------------------------------------------*\
Class Detail::ICharStreamAllocator Declaration
\*---------------------------------------------------------------------------*/
//- An allocator for holding Foam::icharstream
class ICharStreamAllocator
{
protected:
// Protected Data
//- The stream
Foam::icharstream stream_;
// Constructors
//- Default construct
ICharStreamAllocator() = default;
};
} // End namespace Detail
/*---------------------------------------------------------------------------*\
Class ICharStream Declaration
\*---------------------------------------------------------------------------*/
@ -210,12 +239,10 @@ public:
//- An ISstream with internal List storage. Always UNCOMPRESSED.
class ICharStream
:
public Foam::Detail::StreamAllocator<Foam::icharstream>,
public Detail::ICharStreamAllocator,
public Foam::ISstream
{
typedef
Foam::Detail::StreamAllocator<Foam::icharstream>
allocator_type;
typedef Detail::ICharStreamAllocator allocator_type;
public:

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2016-2024 OpenCFD Ltd.
Copyright (C) 2016-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -65,6 +65,7 @@ See Also
#define Foam_ISpanStream_H
#include "memoryStreamBuffer.H"
#include "UList.H"
#include "ISstream.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -212,23 +213,49 @@ public:
//- Some information about the input buffer position/capacity
void debug_info(Ostream& os) const
{
os << "get=" << input_pos() << '/' << capacity();
os << "get="
<< input_pos() << '/' << capacity();
}
};
namespace Detail
{
/*---------------------------------------------------------------------------*\
Class Detail::ISpanStreamAllocator Declaration
\*---------------------------------------------------------------------------*/
//- An allocator for holding Foam::ispanstream
class ISpanStreamAllocator
{
protected:
// Protected Data
//- The stream
Foam::ispanstream stream_;
// Constructors
//- Default construct (empty)
ISpanStreamAllocator() = default;
};
} // End namespace Detail
/*---------------------------------------------------------------------------*\
Class ISpanStream Declaration
\*---------------------------------------------------------------------------*/
class ISpanStream
:
public Foam::Detail::StreamAllocator<Foam::ispanstream>,
public Detail::ISpanStreamAllocator,
public Foam::ISstream
{
typedef
Foam::Detail::StreamAllocator<Foam::ispanstream>
allocator_type;
typedef Detail::ISpanStreamAllocator allocator_type;
public:

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2017-2024 OpenCFD Ltd.
Copyright (C) 2017-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -109,13 +109,7 @@ public:
//- The current output position within the buffer (tellp)
std::streampos output_pos() const
{
return buffer_type::span_tellp();
}
//- The number of bytes outputted
std::streamsize count() const
{
return buffer_type::size_bytes();
return (buffer_type::span_tellp());
}
//- The put buffer capacity
@ -195,6 +189,33 @@ public:
};
namespace Detail
{
/*---------------------------------------------------------------------------*\
Class Detail::OCharStreamAllocator Declaration
\*---------------------------------------------------------------------------*/
//- An allocator for holding Foam::ocharstream
class OCharStreamAllocator
{
protected:
// Protected Data
//- The stream
Foam::ocharstream stream_;
// Constructors
//- Default construct - empty
OCharStreamAllocator() = default;
};
} // End namespace Detail
/*---------------------------------------------------------------------------*\
Class OCharStream Declaration
\*---------------------------------------------------------------------------*/
@ -202,12 +223,10 @@ public:
//- An OSstream with internal List storage
class OCharStream
:
public Foam::Detail::StreamAllocator<Foam::ocharstream>,
public Detail::OCharStreamAllocator,
public Foam::OSstream
{
typedef
Foam::Detail::StreamAllocator<Foam::ocharstream>
allocator_type;
typedef Detail::OCharStreamAllocator allocator_type;
public:
@ -258,11 +277,8 @@ public:
//- The current output position within the buffer (tellp)
std::streampos output_pos() const { return stream_.output_pos(); }
//- The number of bytes outputted
std::streamsize count() const { return stream_.count(); }
//- The current output size. Same as count(), output_pos(), tellp().
label size() const { return label(stream_.count()); }
//- The current output size. Same as tellp(), output_pos()
label size() const { return label(stream_.output_pos()); }
//- The put buffer capacity
std::streamsize capacity() const { return stream_.capacity(); }

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2016-2024 OpenCFD Ltd.
Copyright (C) 2016-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -35,6 +35,7 @@ Description
#define Foam_OScountStream_H
#include "OSstream.H"
#include <iostream>
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -125,7 +126,7 @@ class ocountstream
// Member Functions
//- The number of bytes counted
//- The number of bytes counted.
std::streamsize count() const noexcept { return size_; }
//- Reset the count
@ -154,7 +155,7 @@ public:
//- This hides both signatures of std::basic_ios::rdbuf()
countbuf* rdbuf() { return &buf_; }
//- The number of bytes counted
//- \return The number of bytes counted
std::streamsize count() const noexcept { return buf_.count(); }
//- Reset the count
@ -172,6 +173,33 @@ public:
};
namespace Detail
{
/*---------------------------------------------------------------------------*\
Class Detail::OCountStreamAllocator Declaration
\*---------------------------------------------------------------------------*/
//- An allocator for holding Foam::ocountstream
class OCountStreamAllocator
{
protected:
// Protected Data
//- The output stream
Foam::ocountstream stream_;
// Constructors
//- Default construct
OCountStreamAllocator() = default;
};
} // End namespace Detail
/*---------------------------------------------------------------------------*\
Class OCountStream Declaration
\*---------------------------------------------------------------------------*/
@ -179,12 +207,10 @@ public:
//- An output stream for calculating byte counts
class OCountStream
:
public Foam::Detail::StreamAllocator<Foam::ocountstream>,
public Foam::OSstream
public Detail::OCountStreamAllocator,
public OSstream
{
typedef
Foam::Detail::StreamAllocator<Foam::ocountstream>
allocator_type;
typedef Detail::OCountStreamAllocator allocator_type;
public:
@ -212,10 +238,10 @@ public:
// Member Functions
//- The number of bytes counted
//- \return The number of bytes counted
std::streamsize count() const noexcept { return stream_.count(); }
//- The number of bytes counted
//- \return The number of bytes counted
std::streamsize size() const noexcept { return stream_.count(); }
//- Reset the count

View File

@ -5,7 +5,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2016-2024 OpenCFD Ltd.
Copyright (C) 2016-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -83,6 +83,7 @@ See Also
#define Foam_OSpanStream_H
#include "memoryStreamBuffer.H"
#include "DynamicList.H"
#include "OSstream.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -140,12 +141,6 @@ public:
return buffer_type::span_tellp();
}
//- The number of bytes outputted
std::streamsize count() const
{
return buffer_type::size_bytes();
}
//- The put buffer capacity
std::streamsize capacity() const
{
@ -204,23 +199,49 @@ public:
//- Some information about the output buffer position/capacity
void debug_info(Ostream& os) const
{
os << "put=" << output_pos() << '/' << capacity();
os << "put="
<< output_pos() << '/' << capacity();
}
};
namespace Detail
{
/*---------------------------------------------------------------------------*\
Class Detail::OSpanStreamAllocator Declaration
\*---------------------------------------------------------------------------*/
//- An allocator for holding Foam::ospanstream
class OSpanStreamAllocator
{
protected:
// Protected Data
//- The stream
Foam::ospanstream stream_;
// Constructors
//- Default construct (empty)
OSpanStreamAllocator() = default;
};
} // End namespace Detail
/*---------------------------------------------------------------------------*\
Class OSpanStream Declaration
\*---------------------------------------------------------------------------*/
class OSpanStream
:
public Foam::Detail::StreamAllocator<Foam::ospanstream>,
public Detail::OSpanStreamAllocator,
public Foam::OSstream
{
typedef
Foam::Detail::StreamAllocator<Foam::ospanstream>
allocator_type;
typedef Detail::OSpanStreamAllocator allocator_type;
public:
@ -293,11 +314,8 @@ public:
//- The current output position within the buffer (tellp)
std::streampos output_pos() const { return stream_.output_pos(); }
//- The number of bytes outputted
std::streamsize count() const { return stream_.count(); }
//- The current output size. Same as count(), output_pos(), tellp().
label size() const { return label(stream_.count()); }
//- The current output size. Same as tellp(), output_pos()
label size() const { return label(stream_.output_pos()); }
//- The put buffer capacity
std::streamsize capacity() const { return stream_.capacity(); }

View File

@ -541,7 +541,7 @@ public:
// No character stripping
inline explicit token(tokenType typ, const std::string&, label line=0);
//- Move construct word/string token with the specified variant.
//- Copy construct word/string token with the specified variant.
// A invalid word/string variant type is silently treated as STRING.
// No character stripping
inline explicit token(tokenType typ, std::string&&, label line=0);

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2023 Sergey Lesnik
Copyright (C) 2023-2024 OpenCFD Ltd.
Copyright (C) 2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -35,7 +35,7 @@ namespace Foam
{
// Write tokens without keyword, suppress/ignore bad tokens.
// Mostly like primitiveEntry::write(os, true);
// Mostly like primitiveEntry::write(os, false);
static void writeTokens(Ostream& os, const tokenList& toks)
{
@ -56,11 +56,11 @@ static void writeTokens(Ostream& os, const tokenList& toks)
started = true;
}
// Token output via direct handling in Ostream(s),
// or normal '<<' output operator
// Output token with direct handling in Ostream(s),
// or use normal '<<' output operator
if (!os.write(tok))
{
os << tok;
os << tok;
}
if (tok.isCharData())
@ -73,10 +73,18 @@ static void writeTokens(Ostream& os, const tokenList& toks)
if (s.starts_with("//") && !s.ends_with('\n'))
{
os << '\n';
started = false; // Does not need further space separator
started = false; // already have newline as separator
}
}
}
// Always finish up with a newline?
// eg,
//
// if (started)
// {
// os << nl;
// }
}
} // End namespace Foam
@ -133,10 +141,7 @@ Foam::formattingEntry::formattingEntry
void Foam::formattingEntry::write(Ostream& os) const
{
if (active_)
{
writeTokens(os, *this);
}
writeTokens(os, *this);
}

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2023 Sergey Lesnik
Copyright (C) 2023-2024 OpenCFD Ltd.
Copyright (C) 2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -51,17 +51,12 @@ class formattingEntry
:
public primitiveEntry
{
// Private Data
//- The output visibility
bool active_ = true;
public:
// Static Member Functions
//- Generate an entry keyword: "__format-entry__NNN".
//- The generated names are unlikely to collide with user dictionaries
//- Generate a default entry keyword: "__format-entry__NNN"
// The generated names are unlikely to collide with user dictionaries
static keyType defaultName(label n)
{
return keyType
@ -104,12 +99,6 @@ public:
formattingEntry(defaultName(n), std::move(content))
{}
//- Construct with token data, using a generated keyword
formattingEntry(const label n, token&& tok, bool visible=true)
:
primitiveEntry(defaultName(n), std::move(tok)),
active_(visible)
{}
//- Clone the entry
virtual autoPtr<entry> clone(const dictionary&) const
@ -123,21 +112,6 @@ public:
// Member Functions
//- Set output visibility on/off.
// \return the previous value
bool active(bool on) noexcept
{
bool old(active_);
active_ = on;
return old;
}
//- Get the output visibility
bool active() const noexcept
{
return active_;
}
//- Write content without the keyword.
// Special properties:
// - ignores any bad tokens on output.

View File

@ -115,7 +115,7 @@ Type Foam::Function1Types::Function1Expression<Type>::integrate
) const
{
NotImplemented;
return Type();
return Zero;
}

View File

@ -7,7 +7,7 @@
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2019-2024 OpenCFD Ltd.
Copyright (C) 2019-2021 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -163,7 +163,7 @@ operator_precedence()
svalue (lhs) ::= NUMBER (tok) . { lhs = (tok).scalarValue; } // scanToken
svalue (lhs) ::= ZERO . { lhs = Foam::zero{}; }
svalue (lhs) ::= ZERO . { lhs = Foam::Zero; }
svalue (lhs) ::= PI LPAREN RPAREN . { lhs = Foam::constant::mathematical::pi; }
svalue (lhs) ::= DEG_TO_RAD LPAREN RPAREN . { lhs = Foam::degToRad(); }
svalue (lhs) ::= RAD_TO_DEG LPAREN RPAREN . { lhs = Foam::radToDeg(); }

View File

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

View File

@ -28,6 +28,14 @@ License
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class Type, class GeoMesh>
inline const Foam::DimensionedField<Type, GeoMesh>&
Foam::DimensionedField<Type, GeoMesh>::null()
{
return NullObjectRef<DimensionedField<Type, GeoMesh>>();
}
template<class Type, class GeoMesh>
inline const typename GeoMesh::Mesh&
Foam::DimensionedField<Type, GeoMesh>::mesh() const noexcept

View File

@ -85,7 +85,7 @@ public:
~SlicedDimensionedField()
{
// Set internalField to nullptr to avoid deletion of underlying field
UList<Type>::shallowCopy(nullptr);
UList<Type>::shallowCopy(UList<Type>());
}
};

View File

@ -97,8 +97,8 @@ public:
// Static Member Functions
//- Return a null DynamicField (reference to a nullObject).
static const DynamicField<T, SizeMin>& null() noexcept
//- Return a null field
inline static const DynamicField<T, SizeMin>& null()
{
return NullObjectRef<DynamicField<T, SizeMin>>();
}

View File

@ -122,12 +122,8 @@ public:
// Static Member Functions
//- Return a null Field (reference to a nullObject).
//- Behaves like an empty Field.
static const Field<Type>& null() noexcept
{
return NullObjectRef<Field<Type>>();
}
//- Return nullObject reference Field
inline static const Field<Type>& null();
// Constructors

View File

@ -25,6 +25,15 @@ License
\*---------------------------------------------------------------------------*/
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
template<class Type>
inline const Foam::Field<Type>& Foam::Field<Type>::null()
{
return NullObjectRef<Field<Type>>();
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class Type>

View File

@ -69,12 +69,8 @@ public:
// Static Member Functions
//- Return a null SubField (reference to a nullObject).
//- Behaves like an empty SubField.
static const SubField<Type>& null() noexcept
{
return NullObjectRef<SubField<Type>>();
}
//- Return nullObject reference SubField
inline static const SubField<Type>& null();
// Constructors

View File

@ -26,6 +26,15 @@ License
\*---------------------------------------------------------------------------*/
// * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
template<class Type>
inline const Foam::SubField<Type>& Foam::SubField<Type>::null()
{
return NullObjectRef<SubField<Type>>();
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template<class Type>

View File

@ -154,11 +154,8 @@ public:
// Static Member Functions
//- Return a null GeometricField (reference to a nullObject).
static const GeometricField<Type, PatchField, GeoMesh>& null() noexcept
{
return NullObjectRef<GeometricField<Type, PatchField, GeoMesh>>();
}
//- Return a null geometric field
inline static const GeometricField<Type, PatchField, GeoMesh>& null();
// Constructors

View File

@ -28,6 +28,14 @@ License
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class Type, template<class> class PatchField, class GeoMesh>
inline const Foam::GeometricField<Type, PatchField, GeoMesh>&
Foam::GeometricField<Type, PatchField, GeoMesh>::null()
{
return NullObjectRef<GeometricField<Type, PatchField, GeoMesh>>();
}
template<class Type, template<class> class PatchField, class GeoMesh>
inline const typename
Foam::GeometricField<Type, PatchField, GeoMesh>::Internal&

View File

@ -176,11 +176,10 @@ makeBoundary
new SlicedPatchField<Type>
(
p,
DimensionedField<Type, GeoMesh>::null()
DimensionedField<Type, GeoMesh>::null(),
bField[patchi]
)
);
bf[patchi].UList<Type>::shallowCopy(bField[patchi]);
}
}
@ -369,7 +368,7 @@ Foam::SlicedGeometricField<Type, PatchField, SlicedPatchField, GeoMesh>::
~SlicedGeometricField()
{
// Set internalField to nullptr to avoid deletion of underlying field
UList<Type>::shallowCopy(nullptr);
UList<Type>::shallowCopy(UList<Type>());
}

View File

@ -47,9 +47,9 @@ bool Foam::OFstreamCollator::writeFile
const label comm,
const word& objectType,
const fileName& fName,
const string& masterData,
const UList<char>& localData,
const labelUList& recvSizes,
const UPtrList<SubList<char>>& slaveData, // optional slave data
const UList<stdFoam::span<char>>& procData, // optional proc data
IOstreamOption streamOpt,
IOstreamOption::atomicType atomic,
IOstreamOption::appendType append,
@ -58,18 +58,14 @@ bool Foam::OFstreamCollator::writeFile
{
if (debug)
{
Pout<< "OFstreamCollator : Writing master " << label(masterData.size())
Pout<< "OFstreamCollator : Writing local " << localData.size()
<< " bytes to " << fName << " using comm " << comm
<< " and " << slaveData.size() << " sub-ranks" << endl;
<< " and " << procData.size() << " sub-ranks" << endl;
forAll(slaveData, proci)
forAll(procData, proci)
{
if (slaveData.set(proci))
{
Pout<< " " << proci
<< " size:" << slaveData[proci].size()
<< endl;
}
Pout<< " " << proci << " size:"
<< label(procData[proci].size()) << nl;
}
}
@ -104,32 +100,27 @@ bool Foam::OFstreamCollator::writeFile
// for some mpi so default is non-blocking.
const UPstream::commsTypes myCommsType
(
mag
(
fileOperations::masterUncollatedFileOperation::
maxMasterFileBufferSize == 0
)
maxMasterFileBufferSize
) < 1
? UPstream::commsTypes::scheduled
: UPstream::commsTypes::nonBlocking
);
UList<char> slice
(
const_cast<char*>(masterData.data()),
label(masterData.size())
);
List<std::streamoff> blockOffset;
List<std::streamoff> blockOffsets; // Optional
decomposedBlockData::writeBlocks
(
comm,
osPtr,
blockOffset,
slice,
blockOffsets, // or List<std::streamoff>::null()
localData,
recvSizes,
slaveData,
procData,
myCommsType,
false // do not reduce return state
false // do not sync return state
);
if (osPtr && !osPtr->good())
@ -140,17 +131,18 @@ bool Foam::OFstreamCollator::writeFile
if (debug)
{
Pout<< "OFstreamCollator : Finished writing " << masterData.size()
<< " bytes";
Pout<< "OFstreamCollator : Finished writing "
<< localData.size() << " bytes";
if (UPstream::master(comm))
{
off_t sum = 0;
off_t total = 0;
for (const label recv : recvSizes)
{
sum += recv;
total += recv;
}
// Use std::to_string to display long int
Pout<< " (overall " << std::to_string(sum) << ')';
Pout<< " (overall " << std::to_string(total) << ')';
}
Pout<< " to " << fName
<< " using comm " << comm << endl;
@ -167,13 +159,16 @@ void* Foam::OFstreamCollator::writeAll(void *threadarg)
// Consume stack
while (true)
{
writeData* ptr = nullptr;
std::unique_ptr<writeData> ptr;
{
std::lock_guard<std::mutex> guard(handler.mutex_);
if (handler.objects_.size())
{
ptr = handler.objects_.pop();
// FIFO
ptr.reset(handler.objects_.front());
handler.objects_.pop_front();
}
}
@ -181,51 +176,39 @@ void* Foam::OFstreamCollator::writeAll(void *threadarg)
{
break;
}
else
writeData& obj = *ptr;
// Obtain spans from storage
List<stdFoam::span<char>> procData(obj.procData_.size());
forAll(procData, proci)
{
// Convert storage to pointers
PtrList<SubList<char>> slaveData;
if (ptr->slaveData_.size())
{
slaveData.resize(ptr->slaveData_.size());
forAll(slaveData, proci)
{
if (ptr->slaveData_.set(proci))
{
slaveData.set
(
proci,
new SubList<char>
(
ptr->slaveData_[proci],
ptr->sizes_[proci]
)
);
}
}
}
bool ok = writeFile
procData[proci] = stdFoam::span<char>
(
ptr->comm_,
ptr->objectType_,
ptr->pathName_,
ptr->data_,
ptr->sizes_,
slaveData,
ptr->streamOpt_,
ptr->atomic_,
ptr->append_,
ptr->headerEntries_
const_cast<char*>(obj.procData_[proci].cdata()),
obj.procData_[proci].size()
);
if (!ok)
{
FatalIOErrorInFunction(ptr->pathName_)
<< "Failed writing " << ptr->pathName_
<< exit(FatalIOError);
}
}
delete ptr;
bool ok = writeFile
(
obj.comm_,
obj.objectType_,
obj.pathName_,
obj.localData_,
obj.sizes_,
procData,
obj.streamOpt_,
obj.atomic_,
obj.append_,
obj.headerEntries_
);
if (!ok)
{
FatalIOErrorInFunction(obj.pathName_)
<< "Failed writing " << obj.pathName_
<< exit(FatalIOError);
}
//sleep(1);
}
@ -248,14 +231,14 @@ void Foam::OFstreamCollator::waitForBufferSpace(const off_t wantedSize) const
{
while (true)
{
// Count files to be written
// The pending output size(s)
off_t totalSize = 0;
{
std::lock_guard<std::mutex> guard(mutex_);
forAllConstIters(objects_, iter)
for (const writeData* ptr : objects_)
{
totalSize += iter()->size();
if (ptr) totalSize += ptr->size();
}
}
@ -287,17 +270,7 @@ void Foam::OFstreamCollator::waitForBufferSpace(const off_t wantedSize) const
Foam::OFstreamCollator::OFstreamCollator(const off_t maxBufferSize)
:
maxBufferSize_(maxBufferSize),
threadRunning_(false),
localComm_(UPstream::worldComm),
threadComm_
(
UPstream::allocateCommunicator
(
localComm_,
labelRange(UPstream::nProcs(localComm_))
)
)
OFstreamCollator(maxBufferSize, UPstream::worldComm)
{}
@ -312,6 +285,7 @@ Foam::OFstreamCollator::OFstreamCollator
localComm_(comm),
threadComm_
(
// dupComm
UPstream::allocateCommunicator
(
localComm_,
@ -345,7 +319,7 @@ bool Foam::OFstreamCollator::write
(
const word& objectType,
const fileName& fName,
const string& data,
DynamicList<char>&& localData,
IOstreamOption streamOpt,
IOstreamOption::atomicType atomic,
IOstreamOption::appendType append,
@ -355,78 +329,109 @@ bool Foam::OFstreamCollator::write
{
// Determine (on master) sizes to receive. Note: do NOT use thread
// communicator
labelList recvSizes;
decomposedBlockData::gather(localComm_, label(data.size()), recvSizes);
const labelList recvSizes
(
UPstream::listGatherValues<label>(localData.size(), localComm_)
);
off_t totalSize = 0;
label maxLocalSize = 0;
if (UPstream::master(localComm_))
{
if (UPstream::master(localComm_))
for (const label recvSize : recvSizes)
{
for (const label recvSize : recvSizes)
{
totalSize += recvSize;
maxLocalSize = max(maxLocalSize, recvSize);
}
totalSize += recvSize;
maxLocalSize = max(maxLocalSize, recvSize);
}
Pstream::broadcasts(localComm_, totalSize, maxLocalSize);
}
Pstream::broadcasts(localComm_, totalSize, maxLocalSize);
// Determine how things will be gathered and written...
enum class dispatchModes { GATHER_WRITE, PREFETCH_THREADED, FULL_THREADED };
dispatchModes dispatch(dispatchModes::GATHER_WRITE);
if (!useThread || maxBufferSize_ == 0 || maxLocalSize > maxBufferSize_)
{
dispatch = dispatchModes::GATHER_WRITE;
}
else if (totalSize <= maxBufferSize_)
{
// Total size can be stored locally
// - gather all data now and only do the writing in the thread
dispatch = dispatchModes::PREFETCH_THREADED;
}
else
{
// Gather data and write in the thread
dispatch = dispatchModes::FULL_THREADED;
if (!UPstream::haveThreads())
{
WarningInFunction
<< "MPI not initialized with thread support." << nl
<< " maxThreadFileBufferSize = 0 to disable threading" << nl
<< " or maxThreadFileBufferSize > " << totalSize
<< " to collate before threaded writing." << nl << nl;
dispatch = dispatchModes::GATHER_WRITE;
}
}
// -----------
// Dispatching
// -----------
if (dispatch == dispatchModes::GATHER_WRITE)
{
if (debug)
{
Pout<< "OFstreamCollator : non-thread gather and write of " << fName
<< " using local comm " << localComm_ << endl;
Pout<< "OFstreamCollator : non-thread gather/write "
<< "(local comm: " << localComm_ << ") of "
<< fName << endl;
}
// Direct collating and writing (so master blocks until all written!)
const PtrList<SubList<char>> dummySlaveData;
return writeFile
(
localComm_,
objectType,
fName,
data,
localData,
recvSizes,
dummySlaveData,
UList<stdFoam::span<char>>(), // dummy proc data
streamOpt,
atomic,
append,
headerEntries
);
}
else if (totalSize <= maxBufferSize_)
else if (dispatch == dispatchModes::PREFETCH_THREADED)
{
// Total size can be stored locally so receive all data now and only
// do the writing in the thread
if (debug)
{
Pout<< "OFstreamCollator : non-thread gather; thread write of "
<< fName << endl;
}
if (Pstream::master(localComm_))
if (UPstream::master(localComm_))
{
waitForBufferSpace(totalSize);
}
// Receive in chunks of labelMax (2^31-1) since this is the maximum
// size that a List can be
autoPtr<writeData> fileAndDataPtr
std::unique_ptr<writeData> fileAndDataPtr
(
new writeData
(
threadComm_, // Note: comm not actually used anymore
objectType,
fName,
(
Pstream::master(localComm_)
? data // Only used on master
: string::null
),
recvSizes,
streamOpt,
atomic,
@ -434,63 +439,81 @@ bool Foam::OFstreamCollator::write
headerEntries
)
);
writeData& fileAndData = fileAndDataPtr();
auto& fileAndData = *fileAndDataPtr;
PtrList<List<char>>& slaveData = fileAndData.slaveData_;
List<List<char>>& procData = fileAndData.procData_;
if (UPstream::master(localComm_))
{
// Move in local data (master only!)
fileAndData.transfer(localData);
UList<char> slice(const_cast<char*>(data.data()), label(data.size()));
// Storage for receive data
procData.resize(UPstream::nProcs(localComm_));
for (const int proci : UPstream::subProcs(localComm_))
{
procData[proci].resize(recvSizes[proci]);
}
}
else if (UPstream::is_subrank(localComm_))
{
// Requires a size for decomposedBlockData::writeBlocks() logic
procData.resize(UPstream::nProcs(localComm_));
}
slaveData.setSize(recvSizes.size());
// Gather all data onto master. Is done in local communicator since
// not in write thread. Note that we do not store in contiguous
// buffer since that would limit to 2G chars.
// not in write thread.
const label startOfRequests = UPstream::nRequests();
if (Pstream::master(localComm_))
if (UPstream::master(localComm_))
{
for (label proci = 1; proci < slaveData.size(); proci++)
for (const int proci : UPstream::subProcs(localComm_))
{
slaveData.set(proci, new List<char>(recvSizes[proci]));
List<char>& procSlice = procData[proci];
if (procSlice.empty()) continue;
UIPstream::read
(
UPstream::commsTypes::nonBlocking,
proci,
slaveData[proci].data(),
slaveData[proci].size_bytes(),
Pstream::msgType(),
procSlice.data_bytes(),
procSlice.size_bytes(),
UPstream::msgType(),
localComm_
);
}
}
else
else if (UPstream::is_subrank(localComm_) && !localData.empty())
{
if
(
!UOPstream::write
(
UPstream::commsTypes::nonBlocking,
0,
slice.cdata(),
slice.size_bytes(),
Pstream::msgType(),
UPstream::masterNo(),
localData.cdata_bytes(),
localData.size_bytes(),
UPstream::msgType(),
localComm_
)
)
{
FatalErrorInFunction
<< "Cannot send outgoing message. "
<< "to:" << 0 << " nBytes:"
<< label(slice.size_bytes())
<< "Cannot send outgoing message (size: "
<< localData.size() << ") to master" << nl
<< Foam::abort(FatalError);
}
}
UPstream::waitRequests(startOfRequests);
// The localData has been moved (master) or communicated
localData.clearStorage();
{
std::lock_guard<std::mutex> guard(mutex_);
// Append to thread buffer
objects_.push(fileAndDataPtr.ptr());
// Append to thread buffer (as FIFO), take ownership
objects_.push_back(fileAndDataPtr.release());
// Start thread if not running
if (!threadRunning_)
@ -517,49 +540,46 @@ bool Foam::OFstreamCollator::write
return true;
}
else
else if (dispatch == dispatchModes::FULL_THREADED)
{
if (debug)
{
Pout<< "OFstreamCollator : thread gather and write of " << fName
<< " using communicator " << threadComm_ << endl;
Pout<< "OFstreamCollator : thread gather and write "
<< "(thread comm: " << threadComm_
<< ") of " << fName << endl;
}
if (!UPstream::haveThreads())
if (UPstream::master(localComm_))
{
FatalErrorInFunction
<< "mpi does not seem to have thread support."
<< " Make sure to set buffer size 'maxThreadFileBufferSize'"
<< " to at least " << totalSize
<< " to be able to do the collating before threading."
<< exit(FatalError);
waitForBufferSpace(localData.size());
}
if (Pstream::master(localComm_))
{
waitForBufferSpace(data.size());
}
std::unique_ptr<writeData> fileAndDataPtr
(
new writeData
(
threadComm_,
objectType,
fName,
recvSizes,
streamOpt,
atomic,
append,
headerEntries
)
);
// Move in local data (all procs)
fileAndDataPtr->transfer(localData);
{
std::lock_guard<std::mutex> guard(mutex_);
// Push all file info on buffer. Note that no slave data provided
// Append to thread buffer (as FIFO), take ownership
objects_.push_back(fileAndDataPtr.release());
// Note: no proc data provided
// so it will trigger communication inside the thread
objects_.push
(
new writeData
(
threadComm_,
objectType,
fName,
data,
recvSizes,
streamOpt,
atomic,
append,
headerEntries
)
);
if (!threadRunning_)
{
@ -584,6 +604,12 @@ bool Foam::OFstreamCollator::write
return true;
}
FatalErrorInFunction
<< "Unknown dispatch mode: " << int(dispatch)
<< " - programming error?" << abort(FatalError);
return false;
}
@ -591,7 +617,7 @@ void Foam::OFstreamCollator::waitAll()
{
// Wait for all buffer space to be available i.e. wait for all jobs
// to finish
if (Pstream::master(localComm_))
if (UPstream::master(localComm_))
{
if (debug)
{

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2017-2018 OpenFOAM Foundation
Copyright (C) 2021-2022 OpenCFD Ltd.
Copyright (C) 2019-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -51,14 +51,14 @@ SourceFiles
#ifndef Foam_OFstreamCollator_H
#define Foam_OFstreamCollator_H
#include <thread>
#include <mutex>
#include "IOstream.H"
#include "labelList.H"
#include "FIFOStack.H"
#include "SubList.H"
#include "List.H"
#include "CircularBuffer.H" // As FIFO
#include "dictionary.H"
#include <mutex>
#include <thread>
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
@ -72,26 +72,33 @@ class OFstreamCollator
{
// Private Class
//- Holds data to be written
struct writeData
{
const label comm_;
const word objectType_;
const fileName pathName_;
const string data_;
DynamicList<char> localData_;
const labelList sizes_;
PtrList<List<char>> slaveData_;
List<List<char>> procData_;
const IOstreamOption streamOpt_;
IOstreamOption::atomicType atomic_;
IOstreamOption::appendType append_;
const dictionary headerEntries_;
writeData() = delete; // No default construct
writeData(const writeData&) = delete; // No copy construct
writeData(writeData&&) = delete; // No move construct
void operator=(const writeData&) = delete; // No copy assign
void operator=(writeData&&) = delete; // No move assign
//- Construct without local data
writeData
(
const label comm,
const word& objectType,
const fileName& pathName,
const string& data,
const labelList& sizes,
const labelUList& sizes,
IOstreamOption streamOpt,
IOstreamOption::atomicType atomic,
IOstreamOption::appendType append,
@ -101,27 +108,30 @@ class OFstreamCollator
comm_(comm),
objectType_(objectType),
pathName_(pathName),
data_(data),
localData_(),
sizes_(sizes),
slaveData_(),
procData_(),
streamOpt_(streamOpt),
atomic_(atomic),
append_(append),
headerEntries_(headerEntries)
{}
//- The (approximate) size of master + any optional slave data
//- Move reset local data
void transfer(DynamicList<char>& localData)
{
localData_.transfer(localData);
}
//- The (approximate) size of local + any optional proc data
off_t size() const
{
off_t totalSize = data_.size();
forAll(slaveData_, i)
off_t total = localData_.size();
for (const auto& data : procData_)
{
if (slaveData_.set(i))
{
totalSize += slaveData_[i].size();
}
total += data.size();
}
return totalSize;
return total;
}
};
@ -135,8 +145,8 @@ class OFstreamCollator
std::unique_ptr<std::thread> thread_;
//- Stack of files to write + contents
FIFOStack<writeData*> objects_;
//- FIFO of files to write and their contents
CircularBuffer<writeData*> objects_;
//- Whether thread is running (and not exited)
bool threadRunning_;
@ -156,9 +166,9 @@ class OFstreamCollator
const label comm,
const word& objectType,
const fileName& fName,
const string& masterData,
const UList<char>& localData,
const labelUList& recvSizes,
const UPtrList<SubList<char>>& slaveData,
const UList<stdFoam::span<char>>& procData,
IOstreamOption streamOpt,
IOstreamOption::atomicType atomic,
IOstreamOption::appendType append,
@ -181,7 +191,8 @@ public:
// Constructors
//- Construct from buffer size. 0 = do not use thread
//- Construct from buffer size (0 = do not use thread)
//- and with worldComm
explicit OFstreamCollator(const off_t maxBufferSize);
//- Construct from buffer size (0 = do not use thread)
@ -195,14 +206,15 @@ public:
// Member Functions
//- Write file with contents.
// Blocks until writethread has space available
//- Write file with contents, possibly taking ownership of the
//- content.
// Blocks until write-thread has space available
// (total file sizes < maxBufferSize)
bool write
(
const word& objectType,
const fileName&,
const string& data,
const fileName& fName,
DynamicList<char>&& localData,
IOstreamOption streamOpt,
IOstreamOption::atomicType atomic,
IOstreamOption::appendType append,
@ -210,6 +222,37 @@ public:
const dictionary& headerEntries = dictionary::null
);
//- Write file with contents.
FOAM_DEPRECATED_FOR(2023-09, "use write with movable content")
bool write
(
const word& objectType,
const fileName& fName,
const std::string& s,
IOstreamOption streamOpt,
IOstreamOption::atomicType atomic,
IOstreamOption::appendType append,
const bool useThread = true,
const dictionary& headerEntries = dictionary::null
)
{
DynamicList<char> charData;
charData.setCapacity(s.size());
std::copy(s.begin(), s.end(), charData.begin());
return write
(
objectType,
fName,
std::move(charData),
streamOpt,
atomic,
append,
useThread,
headerEntries
);
}
//- Wait for all thread actions to have finished
void waitAll();
};

View File

@ -116,7 +116,7 @@ void Foam::fileOperations::collatedFileOperation::printBanner
{
DetailInfo
<< " With non-blocking transfer,"
" buffer-size = " << maxMasterFileBufferSize << nl;
" buffer-size = " << maxMasterFileBufferSize << nl;
}
else
{

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2017-2018 OpenFOAM Foundation
Copyright (C) 2020-2022 OpenCFD Ltd.
Copyright (C) 2020-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -41,7 +41,7 @@ Foam::threadedCollatedOFstream::threadedCollatedOFstream
const bool useThread
)
:
OStringStream(streamOpt),
OCharStream(streamOpt),
writer_(writer),
pathName_(pathName),
atomic_(atomic),
@ -74,11 +74,22 @@ Foam::threadedCollatedOFstream::threadedCollatedOFstream
Foam::threadedCollatedOFstream::~threadedCollatedOFstream()
{
commit();
}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
void Foam::threadedCollatedOFstream::commit()
{
// Take ownership of serialized content, without copying or reallocation
DynamicList<char> charData(OCharStream::release());
writer_.write
(
decomposedBlockData::typeName,
pathName_,
str(),
std::move(charData),
IOstreamOption(IOstreamOption::BINARY, version(), compression_),
atomic_,
IOstreamOption::NON_APPEND,

View File

@ -6,7 +6,7 @@
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2017-2018 OpenFOAM Foundation
Copyright (C) 2021-2022 OpenCFD Ltd.
Copyright (C) 2021-2023 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
@ -39,7 +39,7 @@ SourceFiles
#define Foam_threadedCollatedOFstream_H
#include "dictionary.H"
#include "StringStream.H"
#include "SpanStream.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -55,7 +55,7 @@ class OFstreamCollator;
class threadedCollatedOFstream
:
public OStringStream
public OCharStream
{
// Private Data
@ -78,6 +78,11 @@ class threadedCollatedOFstream
dictionary headerEntries_;
// Private Member Functions
//- Commit buffered information
void commit();
public:
// Constructors
@ -102,12 +107,14 @@ public:
);
//- Destructor
//- Destructor - commits buffered information to file
~threadedCollatedOFstream();
// Member Functions
// -> using OCharStream::rewind
//- Define the header entries for the data block(s)
void setHeaderEntries(const dictionary& dict);
};

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