/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2016-2017 Wikki Ltd Copyright (C) 2018-2023 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. OpenFOAM is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. OpenFOAM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenFOAM. If not, see . \*---------------------------------------------------------------------------*/ #include "faFieldReconstructor.H" #include "Time.H" #include "PtrList.H" #include "emptyFaPatch.H" #include "faPatchFields.H" #include "faePatchFields.H" // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // template Foam::tmp> Foam::faFieldReconstructor::reconstructField ( const IOobject& fieldObject, const PtrList>& procFields ) const { // Create the internalField Field internalField(mesh_.nFaces()); // Create the patch fields PtrList> patchFields(mesh_.boundary().size()); // Create global mesh patches starts labelList gStarts(mesh_.boundary().size(), -1); if (mesh_.boundary().size() > 0) { gStarts[0] = mesh_.nInternalEdges(); } for(label i=1; i& procField = procFields[procI]; // Set the face values in the reconstructed field internalField.rmap ( procField.internalField(), faceProcAddressing_[procI] ); // Set the boundary patch values in the reconstructed field labelList starts(procMeshes_[procI].boundary().size(), -1); if(procMeshes_[procI].boundary().size() > 0) { starts[0] = procMeshes_[procI].nInternalEdges(); } for(label i=1; i= 0) { // Regular patch. Fast looping if (!patchFields.set(curBPatch)) { patchFields.set ( curBPatch, faPatchField::New ( procField.boundaryField()[patchI], mesh_.boundary()[curBPatch], faPatchField::Internal::null(), faPatchFieldReconstructor ( mesh_.boundary()[curBPatch].size(), procField.boundaryField()[patchI].size() ) ) ); } const label curPatchStart = gStarts[curBPatch]; // mesh_.boundary()[curBPatch].start(); labelList reverseAddressing(cp.size()); forAll(cp, edgeI) { // Subtract one to take into account offsets for // face direction. // reverseAddressing[edgeI] = cp[edgeI] - 1 - curPatchStart; reverseAddressing[edgeI] = cp[edgeI] - curPatchStart; } patchFields[curBPatch].rmap ( procField.boundaryField()[patchI], reverseAddressing ); } else { const Field& curProcPatch = procField.boundaryField()[patchI]; // In processor patches, there's a mix of internal faces (some // of them turned) and possible cyclics. Slow loop forAll(cp, edgeI) { // Subtract one to take into account offsets for // face direction. // label curE = cp[edgeI] - 1; label curE = cp[edgeI]; // Is the face on the boundary? if (curE >= mesh_.nInternalEdges()) { // label curBPatch = mesh_.boundary().whichPatch(curE); label curBPatch = -1; forAll(mesh_.boundary(), pI) { if ( curE >= gStarts[pI] && curE < ( gStarts[pI] + mesh_.boundary()[pI].labelList::size() ) ) { curBPatch = pI; } } if (!patchFields.set(curBPatch)) { patchFields.set ( curBPatch, faPatchField::New ( mesh_.boundary()[curBPatch].type(), mesh_.boundary()[curBPatch], faPatchField::Internal::null() ) ); } // add the edge // label curPatchEdge = // mesh_.boundary() // [curBPatch].whichEdge(curE); label curPatchEdge = curE - gStarts[curBPatch]; patchFields[curBPatch][curPatchEdge] = curProcPatch[edgeI]; } } } } } forAll(mesh_.boundary(), patchI) { // add empty patches if ( isA(mesh_.boundary()[patchI]) && !patchFields.set(patchI) ) { patchFields.set ( patchI, faPatchField::New ( faPatchFieldBase::emptyType(), mesh_.boundary()[patchI], faPatchField::Internal::null() ) ); } } // Now construct and write the field // setting the internalField and patchFields return tmp>::New ( IOobject ( fieldObject.name(), mesh_.thisDb().time().timeName(), mesh_.thisDb(), IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, procFields[0].dimensions(), internalField, patchFields ); } template Foam::tmp> Foam::faFieldReconstructor::reconstructField ( const IOobject& fieldObject, const PtrList>& procFields ) const { // Create the internalField Field internalField(mesh_.nInternalEdges()); // Create the patch fields PtrList> patchFields(mesh_.boundary().size()); labelList gStarts(mesh_.boundary().size(), -1); if(mesh_.boundary().size() > 0) { gStarts[0] = mesh_.nInternalEdges(); } for(label i=1; i& procField = procFields[procI]; // Set the face values in the reconstructed field // It is necessary to create a copy of the addressing array to // take care of the face direction offset trick. // { labelList curAddr(edgeProcAddressing_[procI]); // forAll(curAddr, addrI) // { // curAddr[addrI] -= 1; // } internalField.rmap ( procField.internalField(), curAddr ); } // Set the boundary patch values in the reconstructed field labelList starts(procMeshes_[procI].boundary().size(), -1); if(procMeshes_[procI].boundary().size() > 0) { starts[0] = procMeshes_[procI].nInternalEdges(); } for(label i=1; i= 0) { // Regular patch. Fast looping if (!patchFields.set(curBPatch)) { patchFields.set ( curBPatch, faePatchField::New ( procField.boundaryField()[patchI], mesh_.boundary()[curBPatch], faePatchField::Internal::null(), faPatchFieldReconstructor ( mesh_.boundary()[curBPatch].size(), procField.boundaryField()[patchI].size() ) ) ); } const label curPatchStart = gStarts[curBPatch]; // mesh_.boundary()[curBPatch].start(); labelList reverseAddressing(cp.size()); forAll(cp, edgeI) { // Subtract one to take into account offsets for // face direction. // reverseAddressing[faceI] = cp[faceI] - 1 - curPatchStart; reverseAddressing[edgeI] = cp[edgeI] - curPatchStart; } patchFields[curBPatch].rmap ( procField.boundaryField()[patchI], reverseAddressing ); } else { const Field& curProcPatch = procField.boundaryField()[patchI]; // In processor patches, there's a mix of internal faces (some // of them turned) and possible cyclics. Slow loop forAll(cp, edgeI) { // label curF = cp[edgeI] - 1; label curE = cp[edgeI]; // Is the face turned the right side round if (curE >= 0) { // Is the face on the boundary? if (curE >= mesh_.nInternalEdges()) { // label curBPatch = // mesh_.boundary().whichPatch(curF); label curBPatch = -1; forAll(mesh_.boundary(), pI) { if ( curE >= gStarts[pI] && curE < ( gStarts[pI] + mesh_.boundary()[pI].labelList::size() ) ) { curBPatch = pI; } } if (!patchFields.set(curBPatch)) { patchFields.set ( curBPatch, faePatchField::New ( mesh_.boundary()[curBPatch].type(), mesh_.boundary()[curBPatch], faePatchField::Internal::null() ) ); } // add the face // label curPatchFace = // mesh_.boundary() // [curBPatch].whichEdge(curF); label curPatchEdge = curE - gStarts[curBPatch]; patchFields[curBPatch][curPatchEdge] = curProcPatch[edgeI]; } else { // Internal face internalField[curE] = curProcPatch[edgeI]; } } } } } } forAll(mesh_.boundary(), patchI) { // add empty patches if ( isA(mesh_.boundary()[patchI]) && !patchFields.set(patchI) ) { patchFields.set ( patchI, faePatchField::New ( faePatchFieldBase::emptyType(), mesh_.boundary()[patchI], faePatchField::Internal::null() ) ); } } // Now construct and write the field // setting the internalField and patchFields return tmp>::New ( IOobject ( fieldObject.name(), mesh_.thisDb().time().timeName(), mesh_.thisDb(), IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, procFields[0].dimensions(), internalField, patchFields ); } template Foam::tmp> Foam::faFieldReconstructor::reconstructAreaField ( const IOobject& fieldObject ) { // Read the field for all the processors PtrList> procFields ( procMeshes_.size() ); forAll(procMeshes_, proci) { procFields.set ( proci, new GeometricField ( IOobject ( fieldObject.name(), procMeshes_[proci].thisDb().time().timeName(), procMeshes_[proci].thisDb(), IOobject::MUST_READ, IOobject::NO_WRITE ), procMeshes_[proci] ) ); } return reconstructField ( IOobject ( fieldObject.name(), mesh_.thisDb().time().timeName(), mesh_.thisDb(), IOobject::NO_READ, IOobject::NO_WRITE ), procFields ); } template Foam::tmp> Foam::faFieldReconstructor::reconstructEdgeField ( const IOobject& fieldObject ) { // Read the field for all the processors PtrList> procFields ( procMeshes_.size() ); forAll(procMeshes_, proci) { procFields.set ( proci, new GeometricField ( IOobject ( fieldObject.name(), procMeshes_[proci].thisDb().time().timeName(), procMeshes_[proci].thisDb(), IOobject::MUST_READ, IOobject::NO_WRITE ), procMeshes_[proci] ) ); } return reconstructField ( IOobject ( fieldObject.name(), mesh_.thisDb().time().timeName(), mesh_.thisDb(), IOobject::NO_READ, IOobject::NO_WRITE ), procFields ); } template Foam::label Foam::faFieldReconstructor::reconstructAreaFields ( const UPtrList& fieldObjects ) { typedef GeometricField fieldType; label nFields = 0; for (const IOobject& io : fieldObjects) { if (io.isHeaderClass()) { if (verbose_) { if (!nFields) { Info<< " Reconstructing " << fieldType::typeName << "s\n" << nl; } Info<< " " << io.name() << endl; } ++nFields; reconstructAreaField(io)().write(); ++nReconstructed_; } } if (verbose_ && nFields) Info<< endl; return nFields; } template Foam::label Foam::faFieldReconstructor::reconstructEdgeFields ( const UPtrList& fieldObjects ) { typedef GeometricField fieldType; label nFields = 0; for (const IOobject& io : fieldObjects) { if (io.isHeaderClass()) { if (verbose_) { if (!nFields) { Info<< " Reconstructing " << fieldType::typeName << "s\n" << nl; } Info<< " " << io.name() << endl; } ++nFields; reconstructEdgeField(io)().write(); ++nReconstructed_; } } if (verbose_ && nFields) Info<< endl; return nFields; } template Foam::label Foam::faFieldReconstructor::reconstructAreaFields ( const IOobjectList& objects, const wordRes& selectedFields ) { typedef GeometricField fieldType; return reconstructAreaFields ( ( selectedFields.empty() ? objects.csorted() : objects.csorted(selectedFields) ) ); } template Foam::label Foam::faFieldReconstructor::reconstructEdgeFields ( const IOobjectList& objects, const wordRes& selectedFields ) { typedef GeometricField fieldType; return reconstructEdgeFields ( ( selectedFields.empty() ? objects.csorted() : objects.csorted(selectedFields) ) ); } // ************************************************************************* //