Skip to content
Snippets Groups Projects
Commit a51b0a25 authored by Sergey Lesnik's avatar Sergey Lesnik
Browse files

ENH: Coherent enable reading surface fields in serial

- Looks good with serial runs. A restart from a
  time step with saved flux phi has small residual
  within the first iteration.
- The first residual in parallel runs looks bad.
  Needs investigation.
parent 01d52c14
No related merge requests found
......@@ -58,15 +58,18 @@ const globalIndex&
IFCstream::coherentInternalOffsets<fvsPatchField, surfaceMesh>() const;
//- Handling for coherent format
template<class Type>
struct is_coherentIOobject
<
GeometricField<Type, fvsPatchField, surfaceMesh>
> : std::true_type {};
/*---------------------------------------------------------------------------*\
Class IFCstream Declaration
\*---------------------------------------------------------------------------*/
// #ifdef Foam_coherentFormat_WIP_surfaceFieldRead
// #define Foam_coherentFormat_WIP_surfaceFieldRead
// #endif
#ifdef Foam_coherentFormat_WIP_surfaceFieldRead
template<class Type>
class IFCstream::reader<Type, fvsPatchField, surfaceMesh>
{
......@@ -74,8 +77,6 @@ public:
static void read(IFCstream&);
};
#endif // Foam_coherentFormat_WIP_surfaceFieldWrite
/*---------------------------------------------------------------------------*\
......
......@@ -27,18 +27,13 @@ License
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
#ifdef Foam_coherentFormat_WIP_surfaceFieldRead
template<class Type>
void Foam::IFCstream::reader<Type, Foam::fvsPatchField, Foam::surfaceMesh>::read
(
IFCstream& ifs
)
{
dictionary& dict = ifs.dict_;
ifs.readNonProcessorBoundaryFields();
// ifs.setConstraintTypes();
// Take care of internal and processor fields. Internal surface field in
// coherent format includes processor boundaries. If it is uniform, the
......@@ -46,217 +41,143 @@ void Foam::IFCstream::reader<Type, Foam::fvsPatchField, Foam::surfaceMesh>::read
// Otherwise, the coherent internal field needs to be mapped to FOAM's
// internal and processor fields.
typedef typename pTraits<Type>::cmptType cmptType;
const polyMesh& mesh = ifs.coherentMesh_.mesh();
const polyBoundaryMesh& bm = mesh.boundaryMesh();
// Internal field data
UList<Type> internalData;
// Field data in the coherent format holding internal and processor patch
// fields
List<Type> coherentData;
const polyBoundaryMesh& pbm = mesh.boundaryMesh();
ITstream& its = ifs.dict_.lookup("internalField");
dictionary& bfDict = ifs.dict_.subDict("boundaryField");
// Traverse the tokens of the internal field entry
while (true)
{
if (its.eof())
{
FatalErrorInFunction
<< "Expected 'uniform' or compoundToken in " << its
<< nl << " in file " << ifs.pathname_
<< abort(FatalError);
}
const globalIndex& gi =
ifs.coherentInternalOffsets<fvsPatchField, surfaceMesh>();
token currToken(its);
// Shortcut test for uniform coherent internal field
if (its.front().isWord("uniform"))
{
// The internal coherent field is uniform. Populate the values of
// processor patch fields with the same uniform value as the internal
// field.
if (currToken.isCompound()) // non-uniform
{
// Resize the compoundToken according to the mesh of the proc
token::compound& compToken = currToken.refCompoundToken();
compToken.resize(mesh.nInternalFaces());
dictionary procDict;
procDict.add("type", "processor");
// Store the data pointer in a UList for convenience
internalData.shallowCopy
// Deep copy of internalField "uniform tokens..."
procDict.add
(
new primitiveEntry
(
reinterpret_cast<Type*>(compToken.data_bytes()),
mesh.nInternalFaces()
);
"value",
tokenList(static_cast<const tokenList&>(its))
)
);
// Current token index points to the token after the compound
// ToDoIO Get rid of globalSize?
const label globalSize = its[its.tokenIndex()++].labelToken();
const string id = its[its.tokenIndex()++].stringToken();
if (false)
for (const auto& pp : pbm)
{
if (isA<processorPolyPatch>(pp))
{
Info<< globalSize;
} // Silence compiler warning
// Internal surface field in coherent format includes processor
// boundaries. Thus, find out the corresponding size.
const globalIndex& gi =
ifs.coherentInternalOffsets<fvsPatchField, surfaceMesh>();
const label localSize = gi.localSize();
const label elemOffset = gi.localStart();
const label nElems = gi.localSize();
int nCmpts = compToken.nComponents();
coherentData.resize(localSize);
bfDict.add(pp.name(), procDict);
}
}
labelList start({elemOffset});
labelList count({localSize});
return;
}
// ToDoIO Provide rank function in compound::token for
// identification of flat lists e.g. of type scalar, label
if (nCmpts < 2)
{
start.push_back(0);
count.push_back(nCmpts);
}
ifs.sliceStreamPtr_->access("fields", ifs.pathname_.path());
ifs.sliceStreamPtr_->get
(
id,
reinterpret_cast<cmptType*>(compToken.data_bytes()),
start,
count
);
// The internal coherent field is non-uniform
// Synchronizing IO engine ensures that the data is read from
// storage
ifs.sliceStreamPtr_->sync_buffer();
List<Type>* internalDataTokPtr = nullptr;
break;
}
else if (currToken.isWord() && currToken.wordToken() == "uniform")
for (label toki = its.tokenIndex(); toki < its.size(); ++toki)
{
if (its[toki].isCompound() && its[toki].compoundToken().pending())
{
// Create processor patch fields with the same uniform entry as the
// internal field.
forAll(bm, i)
if (its.peekToken(toki+1).isPunctuation(token::BEGIN_BLOCK))
{
const polyPatch& patch = bm[i];
const word& patchName = patch.name();
labelRange slice
(
its.find(token::BEGIN_BLOCK, token::END_BLOCK, toki+1)
);
// ToDoIO Make all the if(ppPatch) conditions consistent
if (patch.type() == processorPolyPatch::typeName)
if (!slice.good() || (slice.start() != toki+1))
{
dictionary dict;
dict.add("type", "processor");
dict.add("value", its);
bfDict.add(patchName, dict);
// Shouldn't actually fail...
continue;
}
}
// Closing the IO engine ensures that the data is read from storage
ifs.sliceStreamPtr_->sync_buffer();
ITstream sub(its.extract(slice));
dictionary attributes(sub);
return;
token::compound& compTok = its[toki].refCompoundToken();
internalDataTokPtr = dynamic_cast<List<Type>*>(&compTok);
ifs.populateCompound
(
compTok,
attributes,
gi
);
}
}
}
// Coherent internal field
List<Type>& coherentData = *internalDataTokPtr;
// The internal coherent field is non-uniform.
// Create dictionary entries for the processor patch fields with the
// correctly sized compound tokens.
// Size the processor patch fields according to the boundary mesh
const label nAllPatches = bm.size();
// ToDoIO Make it work with any type
List<UList<Type> > procPatchData(nAllPatches);
label nProcPatches = 0;
List<List<Type>> procPatchData(pbm.size());
forAll(bm, patchI)
forAll(pbm, patchi)
{
const polyPatch& patch = bm[patchI];
const polyPatch& pp = pbm[patchi];
if (isA<processorPolyPatch>(patch))
if (isA<processorPolyPatch>(pp))
{
const label patchSize = patch.size();
tokenList entryTokens(2);
entryTokens[0] = word("nonuniform");
// Create a compound token for the patch, resize and store in a list
autoPtr<token::compound> ctPtr =
token::compound::New
(
"List<" + word(pTraits<Type>::typeName) + '>'
);
ctPtr().resize(patchSize);
// Store the data pointer for the later mapping
procPatchData[nProcPatches++] =
UList<Type>
(
reinterpret_cast<Type*>(ctPtr().data_bytes()),
patchSize
);
// autoPtr is invalid after calling ptr()
entryTokens[1] = ctPtr.ptr();
dictionary dict;
dict.add("type", "processor");
// Xfer needed here, calls the corresponding primitiveEntry
// constructor
dict.add("value", std::move(entryTokens));
// No Xfer implemented for adding dictionary but copying is
// accomplished by cloning the pointers of the hash table and
// IDLList
bfDict.add(patch.name(), std::move(dict));
procPatchData[patchi].resize(pp.size(), Foam::zero{});
}
}
// Map from the coherent format to the internal and processor patch fields
const List<labelPair>& ifp = ifs.coherentMesh_.internalFaceProcMapping();
procPatchData.resize(nProcPatches);
const label nNonProcPatches = nAllPatches - nProcPatches;
// Closing the IO engine ensures that the data is read from disk
ifs.sliceStreamPtr_->sync_buffer();
if (ifp.empty())
{
// Use explicit assign(). An assignment operator would trigger a
// shallow copy by setting internalData data pointer to that of
// coherentData. But the latter is destroyed after returning and the
// data pointer would not be valid anymore.
internalData.assign(coherentData);
}
else
// Map processor face fields if there are any
if (!ifp.empty())
{
List<Type> internalData(mesh.nInternalFaces());
const label ifpSize = ifp.size();
labelList patchFaceI(nProcPatches, 0);
labelList nPatchFaces(procPatchData.size(), 0);
label internalFaceI = 0;
label pfI = 0;
forAll(coherentData, i)
{
const label procFaceI = ifp[pfI].first();
const label procFacePatchI = ifp[pfI].second();
if (pfI < ifpSize && i == procFaceI) // Processor field
// Coherent face proc mapping provides connections only to upper
// procs and thus might not cover the complete coherent internal
// field
if (pfI < ifpSize)
{
const label patchI = procFacePatchI - nNonProcPatches;
procPatchData[patchI][patchFaceI[patchI]] = coherentData[i];
pfI++;
patchFaceI[patchI]++;
const label procFaceI = ifp[pfI].first();
if (i == procFaceI) // Processor field
{
const label procFacePatchI = ifp[pfI].second();
procPatchData[procFacePatchI][nPatchFaces[procFacePatchI]] =
coherentData[i];
++pfI;
++nPatchFaces[procFacePatchI];
}
}
else // Internal field
{
internalData[internalFaceI] = coherentData[i];
internalFaceI++;
++internalFaceI;
}
}
// Move the internal field mapped from coherent field data to the
// original internal field compound
coherentData.swap(internalData);
}
// In coherent format only the lower neighbour procs have the processor
......@@ -264,9 +185,9 @@ void Foam::IFCstream::reader<Type, Foam::fvsPatchField, Foam::surfaceMesh>::read
// above.
// Send
forAll(bm, patchI)
forAll(pbm, patchI)
{
const polyPatch& patch = bm[patchI];
const polyPatch& patch = pbm[patchI];
if (isA<processorPolyPatch>(patch))
{
......@@ -280,15 +201,15 @@ void Foam::IFCstream::reader<Type, Foam::fvsPatchField, Foam::surfaceMesh>::read
Pstream::commsTypes::blocking,
procPp.neighbProcNo()
);
toProcNbr << procPatchData[patchI - nNonProcPatches];
toProcNbr << procPatchData[patchI];
}
}
}
// Receive
forAll(bm, patchI)
forAll(pbm, patchI)
{
const polyPatch& patch = bm[patchI];
const polyPatch& patch = pbm[patchI];
if (isA<processorPolyPatch>(patch))
{
......@@ -297,25 +218,53 @@ void Foam::IFCstream::reader<Type, Foam::fvsPatchField, Foam::surfaceMesh>::read
if (procPp.neighbProcNo() < procPp.myProcNo())
{
const label patchDataI = patchI - nNonProcPatches;
IPstream fromProcNbr
(
Pstream::commsTypes::blocking,
procPp.neighbProcNo()
);
fromProcNbr >> procPatchData[patchDataI];
fromProcNbr >> procPatchData[patchI];
// Flip the sign since the faces are oriented in the opposite
// direction
forAll(procPatchData[patchDataI], faceI)
forAll(procPatchData[patchI], faceI)
{
procPatchData[patchDataI][faceI] *= -1;
procPatchData[patchI][faceI] *= -1;
}
}
}
}
// Insert processor patch fields into the boundary field dictionary
forAll(pbm, patchi)
{
const polyPatch& pp = pbm[patchi];
if (isA<processorPolyPatch>(pp))
{
dictionary& dict = bfDict.subDictOrAdd(pp.name());
tokenList entryTokens(2);
entryTokens[0] = word("nonuniform");
entryTokens[1] =
token::Compound<List<Type>>::New
(
std::move(procPatchData[patchi])
).ptr();
dict.add("type", "processor");
dict.add
(
new primitiveEntry
(
"value",
std::move(entryTokens)
)
);
}
}
}
#endif // Foam_coherentFormat_WIP_surfaceFieldWrite
template<class Type>
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment