/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 2013-2017 OpenFOAM Foundation Copyright (C) 2019-2022 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 "globalIndex.H" // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * // template Foam::labelList Foam::globalIndex::calcListOffsets ( const List& lists, const bool checkOverflow ) { labelList values; const label len = lists.size(); if (len) { values.resize(len+1); label start = 0; for (label i = 0; i < len; ++i) { values[i] = start; start += lists[i].size(); if (checkOverflow && start < values[i]) { reportOverflowAndExit(i); } } values[len] = start; } return values; } template void Foam::globalIndex::gather ( const labelUList& off, // needed on master only const label comm, const ProcIDsContainer& procIDs, const UList& fld, List& allFld, const int tag, const Pstream::commsTypes commsType ) { // low-level: no parRun guard if ( !is_contiguous::value && commsType == Pstream::commsTypes::nonBlocking ) { FatalErrorInFunction << "Cannot use nonBlocking with non-contiguous data" << exit(FatalError); // Could also warn and change to scheduled etc... } const label startOfRequests = UPstream::nRequests(); if (Pstream::myProcNo(comm) == procIDs[0]) { allFld.resize_nocopy(off.last()); // == totalSize() // Assign my local data - respect offset information // so that we can request 0 entries to be copied. // Also handle the case where we have a slice of the full // list. SubList(allFld, off[1]-off[0], off[0]) = SubList(fld, off[1]-off[0]); for (label i = 1; i < procIDs.size(); ++i) { SubList procSlot(allFld, off[i+1]-off[i], off[i]); if (is_contiguous::value) { IPstream::read ( commsType, procIDs[i], procSlot.data_bytes(), procSlot.size_bytes(), tag, comm ); } else { IPstream fromProc ( commsType, procIDs[i], 0, tag, comm ); fromProc >> procSlot; } } } else { if (is_contiguous::value) { OPstream::write ( commsType, procIDs[0], fld.cdata_bytes(), fld.size_bytes(), tag, comm ); } else { OPstream toMaster ( commsType, procIDs[0], 0, tag, comm ); toMaster << fld; } } if (commsType == Pstream::commsTypes::nonBlocking) { // Wait for all to finish UPstream::waitRequests(startOfRequests); } } template void Foam::globalIndex::gather ( const labelUList& off, // needed on master only const label comm, const UList& procIDs, const IndirectListBase& fld, List& allFld, const int tag, const Pstream::commsTypes commsType ) { // low-level: no parRun guard if (commsType == Pstream::commsTypes::nonBlocking) { WarningInFunction << "Cannot use nonBlocking with indirect list of data" << exit(FatalError); // Could also warn and change to scheduled etc... } if (Pstream::myProcNo(comm) == procIDs[0]) { allFld.resize_nocopy(off.last()); // == totalSize() // Assign my local data - respect offset information // so that we can request 0 entries to be copied SubList localSlot(allFld, off[1]-off[0], off[0]); if (!localSlot.empty()) { localSlot = fld; } // Already verified commsType != nonBlocking for (label i = 1; i < procIDs.size(); ++i) { SubList procSlot(allFld, off[i+1]-off[i], off[i]); IPstream fromProc ( commsType, procIDs[i], 0, tag, comm ); fromProc >> procSlot; } } else { OPstream toMaster ( commsType, procIDs[0], 0, tag, comm ); toMaster << fld; } } template void Foam::globalIndex::gather ( const labelUList& off, // needed on master only const label comm, const ProcIDsContainer& procIDs, List& fld, const int tag, const Pstream::commsTypes commsType ) { // low-level: no parRun guard List allData; gather(off, comm, procIDs, fld, allData, tag, commsType); if (Pstream::myProcNo(comm) == procIDs[0]) { fld.transfer(allData); } } // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // template void Foam::globalIndex::gather ( const UList& sendData, List& allData, const int tag, const Pstream::commsTypes commsType, const label comm ) const { if (UPstream::parRun()) { gather ( offsets_, // needed on master only comm, UPstream::procID(comm), sendData, allData, tag, commsType ); if (!UPstream::master(comm)) { allData.clear(); // safety: zero-size on non-master } } else { // Serial: direct copy allData = sendData; } } template void Foam::globalIndex::gather ( const IndirectListBase& sendData, List& allData, const int tag, const Pstream::commsTypes commsType, const label comm ) const { if (UPstream::parRun()) { gather ( offsets_, // needed on master only comm, UPstream::procID(comm), sendData, allData, tag, commsType ); if (!UPstream::master(comm)) { allData.clear(); // safety: zero-size on non-master } } else { // Serial: direct copy allData = List(sendData); } } template OutputContainer Foam::globalIndex::gather ( const UList& sendData, const int tag, const Pstream::commsTypes commsType, const label comm ) const { OutputContainer allData; gather(sendData, allData, tag, commsType, comm); return allData; } template OutputContainer Foam::globalIndex::gather ( const IndirectListBase& sendData, const int tag, const Pstream::commsTypes commsType, const label comm ) const { OutputContainer allData; gather(sendData, allData, tag, commsType, comm); return allData; } template void Foam::globalIndex::gatherInplace ( List& fld, const int tag, const Pstream::commsTypes commsType, const label comm ) const { if (UPstream::parRun()) { List allData; gather ( comm, UPstream::procID(comm), fld, allData, tag, commsType ); if (UPstream::master(comm)) { fld.transfer(allData); } else { fld.clear(); // zero-size on non-master } } // Serial: (no-op) } template void Foam::globalIndex::mpiGather ( const UList& sendData, OutputContainer& allData, const label comm ) const { if (!UPstream::parRun()) { // Serial: direct copy allData = sendData; return; } if (!is_contiguous::value) { FatalErrorInFunction << "Cannot be called for non-contiguous data" << nl << abort(FatalError); } auto nSendBytes = sendData.size_bytes(); List recvSizes; List recvOffsets; if (UPstream::master(comm)) { const globalIndex& globalAddr = *this; // Must be the same as Pstream::nProcs(comm), at least on master!! const label nproc = globalAddr.nProcs(); // Allow request of 0 entries to be sent on master if (!globalAddr.localSize(0)) { nSendBytes = 0; } allData.resize_nocopy(globalAddr.totalSize()); recvSizes.resize(nproc); recvOffsets.resize(nproc+1); for (label proci = 0; proci < nproc; ++proci) { recvSizes[proci] = globalAddr.localSize(proci) * sizeof(Type); recvOffsets[proci] = globalAddr.localStart(proci) * sizeof(Type); } recvOffsets[nproc] = globalAddr.totalSize() * sizeof(Type); } else { allData.clear(); // safety: zero-size on non-master } UPstream::gather ( sendData.cdata_bytes(), nSendBytes, allData.data_bytes(), recvSizes, recvOffsets, comm ); } template OutputContainer Foam::globalIndex::mpiGather ( const UList& sendData, const label comm ) const { OutputContainer allData; mpiGather(sendData, allData, comm); return allData; } template void Foam::globalIndex::mpiGatherInplace ( List& fld, const label comm ) const { if (UPstream::parRun()) { List allData; mpiGather(fld, allData, comm); if (UPstream::master(comm)) { fld.transfer(allData); } else { fld.clear(); // zero-size on non-master } } // Serial: (no-op) } template void Foam::globalIndex::mpiGatherOp ( const UList& sendData, OutputContainer& allData, const label comm ) { if (UPstream::parRun()) { // Gather sizes - only needed on master globalIndex(sendData.size(), globalIndex::gatherOnly{}, comm) .mpiGather(sendData, allData, comm); } else { // Serial: direct copy allData = sendData; } } template OutputContainer Foam::globalIndex::mpiGatherOp ( const UList& sendData, const label comm ) { OutputContainer allData; mpiGatherOp(sendData, allData, comm); return allData; } template void Foam::globalIndex::mpiGatherInplaceOp ( List& fld, const label comm ) { if (UPstream::parRun()) { List allData; mpiGatherOp(fld, allData, comm); if (UPstream::master(comm)) { fld.transfer(allData); } else { fld.clear(); // zero-size on non-master } } // Serial: (no-op) } template void Foam::globalIndex::gatherOp ( const UList& sendData, List& allData, const int tag, const Pstream::commsTypes commsType, const label comm ) { if (UPstream::parRun()) { // Gather sizes - only needed on master globalIndex(sendData.size(), globalIndex::gatherOnly{}, comm) .gather(sendData, allData, tag, commsType, comm); } else { // Serial: direct copy allData = sendData; } } template void Foam::globalIndex::gatherOp ( const IndirectListBase& sendData, List& allData, const int tag, const Pstream::commsTypes commsType, const label comm ) { if (UPstream::parRun()) { // Gather sizes - only needed on master globalIndex(sendData.size(), globalIndex::gatherOnly{}, comm) .gather(sendData, allData, tag, commsType, comm); } else { // Serial: direct copy allData = List(sendData); } } template OutputContainer Foam::globalIndex::gatherOp ( const UList& sendData, const int tag, const Pstream::commsTypes commsType, const label comm ) { OutputContainer allData; gatherOp(sendData, allData, tag, commsType, comm); return allData; } template OutputContainer Foam::globalIndex::gatherOp ( const IndirectListBase& sendData, const int tag, const Pstream::commsTypes commsType, const label comm ) { OutputContainer allData; gatherOp(sendData, allData, tag, commsType, comm); return allData; } template void Foam::globalIndex::gatherInplaceOp ( List& fld, const int tag, const Pstream::commsTypes commsType, const label comm ) { if (UPstream::parRun()) { // Gather sizes - only needed on master globalIndex(fld.size(), globalIndex::gatherOnly{}, comm) .gather(fld, tag, commsType, comm); } // Serial: (no-op) } template void Foam::globalIndex::scatter ( const labelUList& off, // needed on master only const label comm, const ProcIDsContainer& procIDs, const UList& allFld, UList& fld, const int tag, const Pstream::commsTypes commsType ) { if ( !is_contiguous::value && commsType == Pstream::commsTypes::nonBlocking ) { FatalErrorInFunction << "Cannot use nonBlocking with non-contiguous data" << exit(FatalError); // Could also warn and change to scheduled etc... } const label startOfRequests = UPstream::nRequests(); if (Pstream::myProcNo(comm) == procIDs[0]) { const SubList localSlot(allFld, off[1]-off[0], off[0]); if (!localSlot.empty()) { fld.deepCopy(localSlot); } for (label i = 1; i < procIDs.size(); ++i) { const SubList procSlot(allFld, off[i+1]-off[i], off[i]); if (is_contiguous::value) { OPstream::write ( commsType, procIDs[i], procSlot.cdata_bytes(), procSlot.size_bytes(), tag, comm ); } else { OPstream toProc ( commsType, procIDs[i], 0, tag, comm ); toProc << procSlot; } } } else { if (is_contiguous::value) { IPstream::read ( commsType, procIDs[0], fld.data_bytes(), fld.size_bytes(), tag, comm ); } else { IPstream fromMaster ( commsType, procIDs[0], 0, tag, comm ); fromMaster >> fld; } } if (commsType == Pstream::commsTypes::nonBlocking) { // Wait for all to finish UPstream::waitRequests(startOfRequests); } } template void Foam::globalIndex::scatter ( const UList& allFld, UList& fld, const int tag, const Pstream::commsTypes commsType, const label comm ) const { // TBD: protection and special handling for serial? { scatter ( offsets_, // needed on master only comm, UPstream::procID(comm), allFld, fld, tag, commsType ); } } template void Foam::globalIndex::get ( List& allFld, const labelUList& globalIds, const CombineOp& cop, const label comm, const int tag ) const { allFld.resize_nocopy(globalIds.size()); if (globalIds.size()) { // Sort according to processor labelList order; CompactListList