/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | Copyright held by original author \\/ M anipulation | ------------------------------------------------------------------------------- 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 2 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, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA \*---------------------------------------------------------------------------*/ #include "fvFieldReconstructor.H" #include "Time.H" #include "PtrList.H" #include "fvPatchFields.H" #include "emptyFvPatch.H" #include "emptyFvPatchField.H" #include "emptyFvsPatchField.H" // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // template Foam::tmp > Foam::fvFieldReconstructor::reconstructFvVolumeField ( const IOobject& fieldIoObject ) { // Read the field for all the processors PtrList > procFields ( procMeshes_.size() ); forAll (procMeshes_, procI) { procFields.set ( procI, new GeometricField ( IOobject ( fieldIoObject.name(), procMeshes_[procI].time().timeName(), procMeshes_[procI], IOobject::MUST_READ, IOobject::NO_WRITE ), procMeshes_[procI] ) ); } // Create the internalField Field internalField(mesh_.nCells()); // Create the patch fields PtrList > patchFields(mesh_.boundary().size()); forAll (procMeshes_, procI) { const GeometricField& procField = procFields[procI]; // Set the cell values in the reconstructed field internalField.rmap ( procField.internalField(), cellProcAddressing_[procI] ); // Set the boundary patch values in the reconstructed field forAll(boundaryProcAddressing_[procI], patchI) { // Get patch index of the original patch const label curBPatch = boundaryProcAddressing_[procI][patchI]; // Get addressing slice for this patch const labelList::subList cp = procMeshes_[procI].boundary()[patchI].patchSlice ( faceProcAddressing_[procI] ); // check if the boundary patch is not a processor patch if (curBPatch >= 0) { // Regular patch. Fast looping if (!patchFields(curBPatch)) { patchFields.set ( curBPatch, fvPatchField::New ( procField.boundaryField()[patchI], mesh_.boundary()[curBPatch], DimensionedField::null(), fvPatchFieldReconstructor ( mesh_.boundary()[curBPatch].size(), procField.boundaryField()[patchI].size() ) ) ); } const label curPatchStart = mesh_.boundaryMesh()[curBPatch].start(); labelList reverseAddressing(cp.size()); forAll(cp, faceI) { // Subtract one to take into account offsets for // face direction. reverseAddressing[faceI] = cp[faceI] - 1 - 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, faceI) { // Subtract one to take into account offsets for // face direction. label curF = cp[faceI] - 1; // Is the face on the boundary? if (curF >= mesh_.nInternalFaces()) { label curBPatch = mesh_.boundaryMesh().whichPatch(curF); if (!patchFields(curBPatch)) { patchFields.set ( curBPatch, fvPatchField::New ( mesh_.boundary()[curBPatch].type(), mesh_.boundary()[curBPatch], DimensionedField::null() ) ); } // add the face label curPatchFace = mesh_.boundaryMesh() [curBPatch].whichFace(curF); patchFields[curBPatch][curPatchFace] = curProcPatch[faceI]; } } } } } forAll(mesh_.boundary(), patchI) { // add empty patches if ( isType(mesh_.boundary()[patchI]) && !patchFields(patchI) ) { patchFields.set ( patchI, fvPatchField::New ( emptyFvPatchField::typeName, mesh_.boundary()[patchI], DimensionedField::null() ) ); } } // Now construct and write the field // setting the internalField and patchFields return tmp > ( new GeometricField ( IOobject ( fieldIoObject.name(), mesh_.time().timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, procFields[0].dimensions(), internalField, patchFields ) ); } template Foam::tmp > Foam::fvFieldReconstructor::reconstructFvSurfaceField ( const IOobject& fieldIoObject ) { // Read the field for all the processors PtrList > procFields ( procMeshes_.size() ); forAll (procMeshes_, procI) { procFields.set ( procI, new GeometricField ( IOobject ( fieldIoObject.name(), procMeshes_[procI].time().timeName(), procMeshes_[procI], IOobject::MUST_READ, IOobject::NO_WRITE ), procMeshes_[procI] ) ); } // Create the internalField Field internalField(mesh_.nInternalFaces()); // Create the patch fields PtrList > patchFields(mesh_.boundary().size()); forAll (procMeshes_, procI) { const GeometricField& 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(faceProcAddressing_[procI]); forAll (curAddr, addrI) { curAddr[addrI] -= 1; } internalField.rmap ( procField.internalField(), curAddr ); } // Set the boundary patch values in the reconstructed field forAll(boundaryProcAddressing_[procI], patchI) { // Get patch index of the original patch const label curBPatch = boundaryProcAddressing_[procI][patchI]; // Get addressing slice for this patch const labelList::subList cp = procMeshes_[procI].boundary()[patchI].patchSlice ( faceProcAddressing_[procI] ); // check if the boundary patch is not a processor patch if (curBPatch >= 0) { // Regular patch. Fast looping if (!patchFields(curBPatch)) { patchFields.set ( curBPatch, fvsPatchField::New ( procField.boundaryField()[patchI], mesh_.boundary()[curBPatch], DimensionedField::null(), fvPatchFieldReconstructor ( mesh_.boundary()[curBPatch].size(), procField.boundaryField()[patchI].size() ) ) ); } const label curPatchStart = mesh_.boundaryMesh()[curBPatch].start(); labelList reverseAddressing(cp.size()); forAll(cp, faceI) { // Subtract one to take into account offsets for // face direction. reverseAddressing[faceI] = cp[faceI] - 1 - 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, faceI) { label curF = cp[faceI] - 1; // Is the face turned the right side round if (curF >= 0) { // Is the face on the boundary? if (curF >= mesh_.nInternalFaces()) { label curBPatch = mesh_.boundaryMesh().whichPatch(curF); if (!patchFields(curBPatch)) { patchFields.set ( curBPatch, fvsPatchField::New ( mesh_.boundary()[curBPatch].type(), mesh_.boundary()[curBPatch], DimensionedField ::null() ) ); } // add the face label curPatchFace = mesh_.boundaryMesh() [curBPatch].whichFace(curF); patchFields[curBPatch][curPatchFace] = curProcPatch[faceI]; } else { // Internal face internalField[curF] = curProcPatch[faceI]; } } } } } } forAll(mesh_.boundary(), patchI) { // add empty patches if ( isType(mesh_.boundary()[patchI]) && !patchFields(patchI) ) { patchFields.set ( patchI, fvsPatchField::New ( emptyFvsPatchField::typeName, mesh_.boundary()[patchI], DimensionedField::null() ) ); } } // Now construct and write the field // setting the internalField and patchFields return tmp > ( new GeometricField ( IOobject ( fieldIoObject.name(), mesh_.time().timeName(), mesh_, IOobject::NO_READ, IOobject::NO_WRITE ), mesh_, procFields[0].dimensions(), internalField, patchFields ) ); } // Reconstruct and write all/selected volume fields template void Foam::fvFieldReconstructor::reconstructFvVolumeFields ( const IOobjectList& objects, const HashSet& selectedFields ) { const word& fieldClassName = GeometricField::typeName; IOobjectList fields = objects.lookupClass(fieldClassName); if (fields.size()) { Info<< " Reconstructing " << fieldClassName << "s\n" << endl; forAllConstIter(IOobjectList, fields, fieldIter) { if ( !selectedFields.size() || selectedFields.found(fieldIter()->name()) ) { Info<< " " << fieldIter()->name() << endl; reconstructFvVolumeField(*fieldIter())().write(); } } Info<< endl; } } // Reconstruct and write all/selected surface fields template void Foam::fvFieldReconstructor::reconstructFvSurfaceFields ( const IOobjectList& objects, const HashSet& selectedFields ) { const word& fieldClassName = GeometricField::typeName; IOobjectList fields = objects.lookupClass(fieldClassName); if (fields.size()) { Info<< " Reconstructing " << fieldClassName << "s\n" << endl; forAllConstIter(IOobjectList, fields, fieldIter) { if ( !selectedFields.size() || selectedFields.found(fieldIter()->name()) ) { Info<< " " << fieldIter()->name() << endl; reconstructFvSurfaceField(*fieldIter())().write(); } } Info<< endl; } } // ************************************************************************* //