/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2015 OpenFOAM Foundation Copyright (C) 2016-2024 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 "parFvFieldDistributor.H" #include "Time.H" #include "PtrList.H" #include "fvPatchFields.H" #include "fvsPatchFields.H" #include "emptyFvPatch.H" #include "IOobjectList.H" #include "mapDistributePolyMesh.H" #include "processorFvPatch.H" #include "distributedFieldMapper.H" #include "distributedFvPatchFieldMapper.H" // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // template Foam::tmp> Foam::parFvFieldDistributor::distributeField ( const DimensionedField& fld ) const { // Create internalField by remote mapping distributedFieldMapper mapper ( labelUList::null(), distMap_.cellMap() ); auto tfield = tmp>::New ( IOobject ( fld.name(), tgtMesh_.time().timeName(), fld.local(), tgtMesh_, IOobject::NO_READ, IOobject::NO_WRITE ), tgtMesh_, fld.dimensions(), Field(fld, mapper) ); tfield.ref().oriented() = fld.oriented(); return tfield; } template Foam::tmp> Foam::parFvFieldDistributor::distributeField ( const GeometricField& fld ) const { // Create internalField by remote mapping distributedFieldMapper mapper ( labelUList::null(), distMap_.cellMap() ); DimensionedField internalField ( IOobject ( fld.name(), tgtMesh_.time().timeName(), fld.local(), tgtMesh_, IOobject::NO_READ, IOobject::NO_WRITE ), tgtMesh_, fld.dimensions(), Field(fld.internalField(), mapper) ); internalField.oriented() = fld.oriented(); // Create patchFields by remote mapping // Note: patchFields still on source mesh, not target mesh PtrList> oldPatchFields(fld.mesh().boundary().size()); const auto& bfld = fld.boundaryField(); forAll(bfld, patchi) { if (patchFaceMaps_.set(patchi)) { distributedFvPatchFieldMapper mapper ( labelUList::null(), patchFaceMaps_[patchi] ); // Clone local patch field oldPatchFields.set ( patchi, bfld[patchi].clone(fld.internalField()) ); // Map into local copy oldPatchFields[patchi].autoMap(mapper); } } // Clone the oldPatchFields onto the target patches. This is just to reset // the reference to the patch, size and content stay the same. PtrList> newPatchFields(tgtMesh_.boundary().size()); forAll(oldPatchFields, patchi) { if (oldPatchFields.set(patchi)) { const auto& pfld = oldPatchFields[patchi]; labelList dummyMap(identity(pfld.size())); directFvPatchFieldMapper dummyMapper(dummyMap); newPatchFields.set ( patchi, fvPatchField::New ( pfld, tgtMesh_.boundary()[patchi], fvPatchField::Internal::null(), dummyMapper ) ); } } // Add some empty patches on remaining patches // (... probably processor patches) forAll(newPatchFields, patchi) { if (!newPatchFields.set(patchi)) { newPatchFields.set ( patchi, fvPatchField::New ( fvPatchFieldBase::emptyType(), tgtMesh_.boundary()[patchi], fvPatchField::Internal::null() ) ); } } // Return geometric field return tmp>::New ( std::move(internalField), newPatchFields ); } template Foam::tmp> Foam::parFvFieldDistributor::distributeField ( const GeometricField& fld ) const { // Create internalField by remote mapping distributedFieldMapper mapper ( labelUList::null(), distMap_.faceMap() ); Field primitiveField; { // Create flat field of internalField + all patch fields Field flatFld(fld.mesh().nFaces(), Type(Zero)); SubList(flatFld, fld.internalField().size()) = fld.internalField(); for (const fvsPatchField& fvp : fld.boundaryField()) { SubList(flatFld, fvp.size(), fvp.patch().start()) = fvp; } // Map all faces primitiveField = Field(flatFld, mapper, fld.is_oriented()); // Trim to internal faces (note: could also have special mapper) primitiveField.resize ( min ( primitiveField.size(), tgtMesh_.nInternalFaces() ) ); } DimensionedField internalField ( IOobject ( fld.name(), tgtMesh_.time().timeName(), fld.local(), tgtMesh_, IOobject::NO_READ, IOobject::NO_WRITE ), tgtMesh_, fld.dimensions(), std::move(primitiveField) ); internalField.oriented() = fld.oriented(); // Create patchFields by remote mapping // Note: patchFields still on source mesh, not target mesh PtrList> oldPatchFields(fld.mesh().boundary().size()); const auto& bfld = fld.boundaryField(); forAll(bfld, patchi) { if (patchFaceMaps_.set(patchi)) { distributedFvPatchFieldMapper mapper ( labelUList::null(), patchFaceMaps_[patchi] ); // Clone local patch field oldPatchFields.set ( patchi, bfld[patchi].clone(fld.internalField()) ); // Map into local copy oldPatchFields[patchi].autoMap(mapper); } } PtrList> newPatchFields(tgtMesh_.boundary().size()); // Clone the patchFields onto the base patches. This is just to reset // the reference to the patch, size and content stay the same. forAll(oldPatchFields, patchi) { if (oldPatchFields.set(patchi)) { const fvsPatchField& pfld = oldPatchFields[patchi]; labelList dummyMap(identity(pfld.size())); directFvPatchFieldMapper dummyMapper(dummyMap); newPatchFields.set ( patchi, fvsPatchField::New ( pfld, tgtMesh_.boundary()[patchi], fvsPatchField::Internal::null(), dummyMapper ) ); } } // Add some empty patches on remaining patches // (... probably processor patches) forAll(newPatchFields, patchi) { if (!newPatchFields.set(patchi)) { newPatchFields.set ( patchi, fvsPatchField::New ( fvsPatchFieldBase::emptyType(), tgtMesh_.boundary()[patchi], fvsPatchField::Internal::null() ) ); } } // Return geometric field return tmp>::New ( std::move(internalField), newPatchFields ); } template Foam::tmp> Foam::parFvFieldDistributor::distributeInternalField ( const IOobject& fieldObject ) const { // Read field DimensionedField fld ( fieldObject, srcMesh_ ); // Distribute return distributeField(fld); } template Foam::tmp> Foam::parFvFieldDistributor::distributeVolumeField ( const IOobject& fieldObject ) const { // Read field GeometricField fld ( fieldObject, srcMesh_ ); // Distribute return distributeField(fld); } template Foam::tmp> Foam::parFvFieldDistributor::distributeSurfaceField ( const IOobject& fieldObject ) const { // Read field GeometricField fld ( fieldObject, srcMesh_ ); // Distribute return distributeField(fld); } template Foam::label Foam::parFvFieldDistributor::distributeInternalFields ( const IOobjectList& objects, const wordRes& selectedFields ) const { typedef DimensionedField fieldType; label nFields = 0; for ( const IOobject& io : ( selectedFields.empty() ? objects.csorted() : objects.csorted(selectedFields) ) ) { if ("cellDist" == io.name()) { // Ignore cellDist (internal or volume) field continue; } if (verbose_) { if (!nFields) { Info<< " Reconstructing " << fieldType::typeName << "s\n" << nl; } Info<< " " << io.name() << nl; } ++nFields; tmp tfld ( distributeInternalField(io) ); if (isWriteProc_.good()) { if (isWriteProc_) { tfld().write(); } } else if (writeHandler_ && writeHandler_->good()) { auto oldHandler = fileOperation::fileHandler(writeHandler_); const label oldComm = UPstream::commWorld(fileHandler().comm()); tfld().write(); writeHandler_ = fileOperation::fileHandler(oldHandler); UPstream::commWorld(oldComm); } } if (nFields && verbose_) Info<< endl; return nFields; } template Foam::label Foam::parFvFieldDistributor::distributeVolumeFields ( const IOobjectList& objects, const wordRes& selectedFields ) const { typedef GeometricField fieldType; label nFields = 0; for ( const IOobject& io : ( selectedFields.empty() ? objects.csorted() : objects.csorted(selectedFields) ) ) { if ("cellDist" == io.name()) { // Ignore cellDist (internal or volume) field continue; } if (verbose_) { if (!nFields) { Info<< " Reconstructing " << fieldType::typeName << "s\n" << nl; } Info<< " " << io.name() << nl; } ++nFields; tmp tfld ( distributeVolumeField(io) ); if (isWriteProc_.good()) { if (isWriteProc_) { tfld().write(); } } else if (writeHandler_ && writeHandler_->good()) { auto oldHandler = fileOperation::fileHandler(writeHandler_); const label oldComm = UPstream::commWorld(fileHandler().comm()); tfld().write(); writeHandler_ = fileOperation::fileHandler(oldHandler); UPstream::commWorld(oldComm); } } if (nFields && verbose_) Info<< endl; return nFields; } template Foam::label Foam::parFvFieldDistributor::distributeSurfaceFields ( const IOobjectList& objects, const wordRes& selectedFields ) const { typedef GeometricField fieldType; label nFields = 0; for ( const IOobject& io : ( selectedFields.empty() ? objects.csorted() : objects.csorted(selectedFields) ) ) { if (verbose_) { if (!nFields) { Info<< " Reconstructing " << fieldType::typeName << "s\n" << nl; } Info<< " " << io.name() << nl; } ++nFields; tmp tfld ( distributeSurfaceField(io) ); if (isWriteProc_.good()) { if (isWriteProc_) { tfld().write(); } } else if (writeHandler_ && writeHandler_->good()) { auto oldHandler = fileOperation::fileHandler(writeHandler_); const label oldComm = UPstream::commWorld(fileHandler().comm()); tfld().write(); writeHandler_ = fileOperation::fileHandler(oldHandler); UPstream::commWorld(oldComm); } } if (nFields && verbose_) Info<< endl; return nFields; } // ************************************************************************* //