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 //- Return true if running parallel
virtual bool coupled() const virtual bool coupled() const
{ {
if (Pstream::parRun()) return Pstream::parRun();
{
return true;
}
else
{
return false;
}
} }
//- Does the patch field perform the transformation //- Does the patch field perform the transformation

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -395,25 +395,35 @@ void Foam::fvMeshDistribute::getFieldNames
// Check all procs have same names // Check all procs have same names
if (syncPar) if (syncPar && Pstream::parRun())
{ {
List<wordList> allNames(Pstream::nProcs()); // Check and report error(s) on master
allNames[Pstream::myProcNo()] = list;
Pstream::allGatherList(allNames);
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 FatalErrorInFunction
<< "When checking for equal " << "When checking for equal " << GeoField::typeName
<< GeoField::typeName
<< " :" << nl << " :" << nl
<< "processor0 has:" << allNames[0] << endl << "processor0 has:" << list << nl
<< "processor" << proci << " has:" << allNames[proci] << nl << "processor" << proci << " has:" << procNames << nl
<< GeoField::typeName << GeoField::typeName
<< " need to be synchronised on all processors." << " need to be synchronised on all processors."
<< exit(FatalError); << exit(FatalError);
break;
} }
} }
} }

View File

@ -28,7 +28,9 @@ License
#include "faBoundaryMesh.H" #include "faBoundaryMesh.H"
#include "faMesh.H" #include "faMesh.H"
#include "globalIndex.H"
#include "primitiveMesh.H" #include "primitiveMesh.H"
#include "processorFaPatch.H"
#include "PtrListOps.H" #include "PtrListOps.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // // * * * * * * * * * * * * * * 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 bool Foam::faBoundaryMesh::checkDefinition(const bool report) const
{ {
label nextPatchStart = mesh().nInternalEdges(); label nextPatchStart = mesh().nInternalEdges();

View File

@ -210,8 +210,13 @@ public:
void setGroup(const word& groupName, const labelUList& patchIDs); void setGroup(const word& groupName, const labelUList& patchIDs);
//- Check boundary definition //- Check boundary definition
// \return True if in error.
bool checkDefinition(const bool report = false) const; 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 // Edit

View File

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

View File

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

View File

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

View File

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

View File

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