/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | www.openfoam.com \\/ M anipulation | ------------------------------------------------------------------------------- Copyright (C) 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 "mapDistributeBase.H" #include "bitSet.H" #include "ListOps.H" // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * // namespace Foam { // Setup array of element masks to match maps sizes // // \param[out] masks Sized for each position in the maps // \param maps The element maps static void blankElementMasks(List& masks, const labelListList& maps) { // If base container not already sized if (masks.empty()) { masks.resize(maps.size()); } forAll(masks, proci) { masks[proci].reset(); // zero all bits masks[proci].resize(maps[proci].size()); } } // Calculate the element mask correspondig to allowedElems in the maps // // \param allowedElems Permissible mapped elements (true/false) // \param[out] masks True/false for each position within the maps // \param maps The element maps // \param hasFlip Map has flip indexing // // \return the max index used. static label calcElementMasks ( const bitSet& allowedElems, List& masks, // [out] - often presized before calling const labelListList& maps, const bool hasFlip ) { // Index after flipping const auto unflippedIndex = ( hasFlip ? [](label idx) -> label { return mag(idx)-1; } : [](label idx) -> label { return idx; } ); // If not already sized if (masks.empty()) { masks.resize(maps.size()); } label maxIndex = -1; forAll(masks, proci) { bitSet& mask = masks[proci]; const labelList& map = maps[proci]; mask.reset(); // zero all bits mask.resize(map.size()); forAll(map, i) { // Element is used (or not) const label index = unflippedIndex(map[i]); if (allowedElems.test(index)) { mask.set(i); maxIndex = max(maxIndex, index); } } } return maxIndex; } } // End namespace Foam // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * // void Foam::mapDistributeBase::exchangeMasks ( const UList& sendMasks, UList& recvMasks, const int tag, const label comm ) { // Require properly sized mask buffers. // The information *is* known from the maps, so always use that // instead having a needless all-to-all for the sizes. if (sendMasks.size() != recvMasks.size()) { FatalErrorInFunction << "Mismatched mask sizes: " << sendMasks.size() << " != " << recvMasks.size() << nl << Foam::abort(FatalError); } const label myRank = UPstream::myProcNo(comm); if (UPstream::parRun()) { #ifdef FULLDEBUG if (sendMasks.size() > UPstream::nProcs(comm)) { FatalErrorInFunction << "Mask sizes (" << sendMasks.size() << ") are larger than number of procs:" << UPstream::nProcs(comm) << nl << Foam::abort(FatalError); } #endif const label startOfRequests = UPstream::nRequests(); forAll(recvMasks, proci) { if (proci != myRank && recvMasks[proci].size()) { UIPstream::read ( UPstream::commsTypes::nonBlocking, proci, recvMasks[proci].data_bytes(), recvMasks[proci].size_bytes(), tag, comm ); } } forAll(sendMasks, proci) { if (proci != myRank && sendMasks[proci].size()) { UOPstream::write ( UPstream::commsTypes::nonBlocking, proci, sendMasks[proci].cdata_bytes(), sendMasks[proci].size_bytes(), tag, comm ); } } // Wait for outstanding requests UPstream::waitRequests(startOfRequests); } // Receiving myself is just a copy recvMasks[myRank] = sendMasks[myRank]; } void Foam::mapDistributeBase::unionCombineMasks ( UList& sendMasks, UList& recvMasks, const int tag, const label comm ) { // Require properly sized mask buffers. // The information *is* known from the maps, so always use that // instead having a needless all-to-all for the sizes. if (sendMasks.size() != recvMasks.size()) { FatalErrorInFunction << "Mismatched mask sizes: " << sendMasks.size() << " != " << recvMasks.size() << nl << Foam::abort(FatalError); } if (UPstream::parRun()) { // Scratch buffers for union operations List scratch(recvMasks.size()); // Size for receives forAll(scratch, proci) { scratch[proci].resize(recvMasks[proci].size()); } // Exchange: from sendMasks -> scratch (intermediate receive) exchangeMasks(sendMasks, scratch, tag, comm); // Update recvMasks (as union) forAll(recvMasks, proci) { recvMasks[proci] &= scratch[proci]; } // Size for sends forAll(scratch, proci) { scratch[proci].resize(sendMasks[proci].size()); } // Exchange: from recvMasks -> scratch (intermediate send) exchangeMasks(recvMasks, scratch, tag, comm); // Final synchronization forAll(sendMasks, proci) { sendMasks[proci] &= scratch[proci]; } } else { // Non-parallel: 'synchronize' myself const label myRank = UPstream::myProcNo(comm); recvMasks[myRank] &= sendMasks[myRank]; sendMasks[myRank] = recvMasks[myRank]; } // Done with parallel exchanges so can shrink the masks to // the min-size actually needed. for (auto& mask : sendMasks) { mask.resize_last(); } for (auto& mask : recvMasks) { mask.resize_last(); } } // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // Foam::label Foam::mapDistributeBase::renumberMap ( labelListList& mapElements, const labelUList& oldToNew, const bool hasFlip ) { label maxIndex = -1; // Transcribe the map if (hasFlip) { for (labelList& map : mapElements) { for (label& val : map) { // Unflip indexed value const label index = oldToNew[mag(val)-1]; if (index >= 0) // Not certain this check is needed { maxIndex = max(maxIndex, index); // Retain flip information from original val = (val < 0 ? (-index-1) : (index+1)); } } } } else { for (labelList& map : mapElements) { for (label& val : map) { // Get indexed value (no flipping) const label index = oldToNew[val]; if (index >= 0) // Not certain this check is needed { maxIndex = max(maxIndex, index); val = index; } } } } return (maxIndex+1); } Foam::label Foam::mapDistributeBase::renumberMap ( labelList& map, const label localSize, const label offset, const Map