ENH: add parallel sync checks for finite-area

- reduce the amount of communication when checking zones and patches
  by performing the synchonization check on the gathered strings
  (master only) and reduce or broadcast the result.

STYLE: simplify coupled() checks depending only on parRun
This commit is contained in:
Mark Olesen
2022-04-02 20:38:43 +02:00
parent 90ba706b06
commit 94f201f956
14 changed files with 207 additions and 154 deletions

View File

@ -138,14 +138,7 @@ public:
//- Return true if running parallel
virtual bool coupled() const
{
if (Pstream::parRun())
{
return true;
}
else
{
return false;
}
return Pstream::parRun();
}
//- Does the patch field perform the transformation

View File

@ -142,14 +142,7 @@ public:
//- Return true if running parallel
virtual bool coupled() const
{
if (Pstream::parRun())
{
return true;
}
else
{
return false;
}
return Pstream::parRun();
}
//- Does the patch field perform the transformation

View File

@ -959,8 +959,8 @@ bool Foam::polyBoundaryMesh::checkParallelSync(const bool report) const
bool hasError = false;
// Collect non-proc patches and check proc patches are last.
wordList names(bm.size());
wordList types(bm.size());
wordList localNames(bm.size());
wordList localTypes(bm.size());
label nonProci = 0;
@ -970,65 +970,67 @@ bool Foam::polyBoundaryMesh::checkParallelSync(const bool report) const
{
if (nonProci != patchi)
{
// There is processor patch in between normal patches.
// A processor patch in between normal patches!
hasError = true;
if (debug || report)
{
Pout<< " ***Problem with boundary patch " << patchi
<< " named " << bm[patchi].name()
<< " of type " << bm[patchi].type()
<< ". The patch seems to be preceeded by processor"
<< " patches. This is can give problems."
<< endl;
<< " name:" << bm[patchi].name()
<< " type:" << bm[patchi].type()
<< " - seems to be preceeded by processor patches."
<< " This is usually a problem." << endl;
}
}
else
{
names[nonProci] = bm[patchi].name();
types[nonProci] = bm[patchi].type();
nonProci++;
localNames[nonProci] = bm[patchi].name();
localTypes[nonProci] = bm[patchi].type();
++nonProci;
}
}
}
names.setSize(nonProci);
types.setSize(nonProci);
localNames.resize(nonProci);
localTypes.resize(nonProci);
List<wordList> allNames(Pstream::nProcs());
allNames[Pstream::myProcNo()] = names;
Pstream::allGatherList(allNames);
// Check and report error(s) on master
List<wordList> allTypes(Pstream::nProcs());
allTypes[Pstream::myProcNo()] = types;
Pstream::allGatherList(allTypes);
// Have every processor check but print error on master
// (in processor sequence).
for (const int proci : Pstream::subProcs())
{
if
const globalIndex procAddr
(
(allNames[proci] != allNames.first())
|| (allTypes[proci] != allTypes.first())
)
// Don't need to collect master itself
(Pstream::master() ? 0 : nonProci),
globalIndex::gatherOnly{}
);
const wordList allNames(procAddr.gather(localNames));
const wordList allTypes(procAddr.gather(localTypes));
// Automatically restricted to master
for (const int proci : procAddr.subProcs())
{
const auto procNames(allNames.slice(procAddr.range(proci)));
const auto procTypes(allTypes.slice(procAddr.range(proci)));
if (procNames != localNames || procTypes != localTypes)
{
hasError = true;
if (debug || (report && Pstream::master()))
if (debug || report)
{
Info<< " ***Inconsistent patches across processors, "
"processor 0 has patch names:"
<< allNames.first()
<< " patch types:" << allTypes.first()
"processor0 has patch names:" << localNames
<< " patch types:" << localTypes
<< " processor" << proci
<< " has patch names:" << allNames[proci]
<< " patch types:" << allTypes[proci]
<< " has patch names:" << procNames
<< " patch types:" << procTypes
<< endl;
}
}
}
// Reduce (not broadcast) to respect local out-of-order errors (first loop)
reduce(hasError, orOp<bool>());
return hasError;
}

View File

@ -274,11 +274,12 @@ public:
labelHashSet& nonGroupPatches
) const;
//- Check whether all procs have all patches and in same order. Return
// true if in error.
//- Check whether all procs have all patches and in same order.
// \return True if in error.
bool checkParallelSync(const bool report = false) const;
//- Check boundary definition. Return true if in error.
//- Check boundary definition.
// \return True if in error.
bool checkDefinition(const bool report = false) const;
//- Correct polyBoundaryMesh after moving points

View File

@ -255,14 +255,7 @@ public:
//- Return true only if this is a parallel run
virtual bool coupled() const
{
if (Pstream::parRun())
{
return true;
}
else
{
return false;
}
return Pstream::parRun();
}
//- Return processor number

View File

@ -31,6 +31,7 @@ License
#include "DynamicList.H"
#include "Pstream.H"
#include "PtrListOps.H"
#include "globalIndex.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -760,41 +761,47 @@ bool Foam::ZoneMesh<ZoneType, MeshType>::checkParallelSync
bool hasError = false;
// Collect all names
List<wordList> allNames(Pstream::nProcs());
allNames[Pstream::myProcNo()] = this->names();
Pstream::allGatherList(allNames);
const wordList localNames(this->names());
const wordList localTypes(this->types());
List<wordList> allTypes(Pstream::nProcs());
allTypes[Pstream::myProcNo()] = this->types();
Pstream::allGatherList(allTypes);
// Check and report error(s) on master
// Have every processor check but only master print error.
for (label proci = 1; proci < allNames.size(); ++proci)
{
if
const globalIndex procAddr
(
(allNames[proci] != allNames[0])
|| (allTypes[proci] != allTypes[0])
)
// Don't need to collect master itself
(Pstream::master() ? 0 : localNames.size()),
globalIndex::gatherOnly{}
);
const wordList allNames(procAddr.gather(localNames));
const wordList allTypes(procAddr.gather(localTypes));
// Automatically restricted to master
for (const int proci : procAddr.subProcs())
{
const auto procNames(allNames.slice(procAddr.range(proci)));
const auto procTypes(allTypes.slice(procAddr.range(proci)));
if (procNames != localNames || procTypes != localTypes)
{
hasError = true;
if (debug || (report && Pstream::master()))
if (debug || report)
{
Info<< " ***Inconsistent zones across processors, "
"processor 0 has zone names:" << allNames[0]
<< " zone types:" << allTypes[0]
<< " processor " << proci << " has zone names:"
<< allNames[proci]
<< " zone types:" << allTypes[proci]
"processor 0 has zone names:" << localNames
<< " zone types:" << localTypes
<< " processor " << proci
<< " has zone names:" << procNames
<< " zone types:" << procTypes
<< endl;
}
}
}
// Check contents
Pstream::broadcast(hasError);
// Check local contents
if (!hasError)
{
for (const ZoneType& zn : zones)

View File

@ -395,25 +395,35 @@ void Foam::fvMeshDistribute::getFieldNames
// Check all procs have same names
if (syncPar)
if (syncPar && Pstream::parRun())
{
List<wordList> allNames(Pstream::nProcs());
allNames[Pstream::myProcNo()] = list;
Pstream::allGatherList(allNames);
// Check and report error(s) on master
for (const int proci : Pstream::subProcs())
const globalIndex procAddr
(
// Don't need to collect master itself
(Pstream::master() ? 0 : list.size()),
globalIndex::gatherOnly{}
);
const wordList allNames(procAddr.gather(list));
// Automatically restricted to master
for (const int proci : procAddr.subProcs())
{
if (allNames[proci] != allNames[0])
const auto procNames(allNames.slice(procAddr.range(proci)));
if (procNames != list)
{
FatalErrorInFunction
<< "When checking for equal "
<< GeoField::typeName
<< "When checking for equal " << GeoField::typeName
<< " :" << nl
<< "processor0 has:" << allNames[0] << endl
<< "processor" << proci << " has:" << allNames[proci] << nl
<< "processor0 has:" << list << nl
<< "processor" << proci << " has:" << procNames << nl
<< GeoField::typeName
<< " need to be synchronised on all processors."
<< exit(FatalError);
break;
}
}
}

View File

@ -28,7 +28,9 @@ License
#include "faBoundaryMesh.H"
#include "faMesh.H"
#include "globalIndex.H"
#include "primitiveMesh.H"
#include "processorFaPatch.H"
#include "PtrListOps.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -625,6 +627,94 @@ Foam::label Foam::faBoundaryMesh::whichPatch(const label edgeIndex) const
}
bool Foam::faBoundaryMesh::checkParallelSync(const bool report) const
{
if (!Pstream::parRun())
{
return false;
}
const faBoundaryMesh& bm = *this;
bool hasError = false;
// Collect non-proc patches and check proc patches are last.
wordList localNames(bm.size());
wordList localTypes(bm.size());
label nonProci = 0;
forAll(bm, patchi)
{
if (!isA<processorFaPatch>(bm[patchi]))
{
if (nonProci != patchi)
{
// A processor patch in between normal patches!
hasError = true;
if (debug || report)
{
Pout<< " ***Problem with boundary patch " << patchi
<< " name:" << bm[patchi].name()
<< " type:" << bm[patchi].type()
<< " - seems to be preceeded by processor patches."
<< " This is usually a problem." << endl;
}
}
else
{
localNames[nonProci] = bm[patchi].name();
localTypes[nonProci] = bm[patchi].type();
++nonProci;
}
}
}
localNames.resize(nonProci);
localTypes.resize(nonProci);
// Check and report error(s) on master
const globalIndex procAddr
(
// Don't need to collect master itself
(Pstream::master() ? 0 : nonProci),
globalIndex::gatherOnly{}
);
const wordList allNames(procAddr.gather(localNames));
const wordList allTypes(procAddr.gather(localTypes));
// Automatically restricted to master
for (const int proci : procAddr.subProcs())
{
const auto procNames(allNames.slice(procAddr.range(proci)));
const auto procTypes(allTypes.slice(procAddr.range(proci)));
if (procNames != localNames || procTypes != localTypes)
{
hasError = true;
if (debug || report)
{
Info<< " ***Inconsistent patches across processors, "
"processor0 has patch names:" << localNames
<< " patch types:" << localTypes
<< " processor" << proci
<< " has patch names:" << procNames
<< " patch types:" << procTypes
<< endl;
}
}
}
// Reduce (not broadcast) to respect local out-of-order errors (first loop)
reduce(hasError, orOp<bool>());
return hasError;
}
bool Foam::faBoundaryMesh::checkDefinition(const bool report) const
{
label nextPatchStart = mesh().nInternalEdges();

View File

@ -210,8 +210,13 @@ public:
void setGroup(const word& groupName, const labelUList& patchIDs);
//- Check boundary definition
// \return True if in error.
bool checkDefinition(const bool report = false) const;
//- Check whether all procs have all patches and in same order.
// \return True if in error.
bool checkParallelSync(const bool report = false) const;
// Edit

View File

@ -151,14 +151,7 @@ public:
//- Return true if running parallel
virtual bool coupled() const
{
if (Pstream::parRun())
{
return true;
}
else
{
return false;
}
return Pstream::parRun();
}
//- Return neighbour field given internal field

View File

@ -139,21 +139,12 @@ public:
virtual ~processorFaePatchField();
// Member functions
// Access
// Member Functions
//- Return true if running parallel
virtual bool coupled() const
{
if (Pstream::parRun())
{
return true;
}
else
{
return false;
}
return Pstream::parRun();
}
};

View File

@ -171,21 +171,14 @@ public:
~processorFvPatchField() = default;
// Member functions
// Member Functions
// Access
//- Return true if running parallel
virtual bool coupled() const
{
if (Pstream::parRun())
{
return true;
}
else
{
return false;
}
return Pstream::parRun();
}
//- Return neighbour field given internal field

View File

@ -136,21 +136,12 @@ public:
virtual ~processorFvsPatchField();
// Member functions
// Access
// Member Functions
//- Return true if running parallel
virtual bool coupled() const
{
if (Pstream::parRun())
{
return true;
}
else
{
return false;
}
return Pstream::parRun();
}
};

View File

@ -137,21 +137,12 @@ public:
virtual ~processorCyclicFvsPatchField();
// Member functions
// Access
// Member Functions
//- Return true if running parallel
virtual bool coupled() const
{
if (Pstream::parRun())
{
return true;
}
else
{
return false;
}
return Pstream::parRun();
}
};