/* Copyright 2023 Equinor ASA. This file is part of the Open Porous Media project (OPM). OPM 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. OPM 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 OPM. If not, see . */ #include #include #include #include #include #include #include #include #include #include #include template Opm::ParallelPAvgDynamicSourceData:: ParallelPAvgDynamicSourceData(const Parallel::Communication& comm, const std::vector& sourceLocations, GlobalToLocal localCellIdx) : PAvgDynamicSourceData { sourceLocations } , comm_ { comm } { this->finaliseConstruction(sourceLocations, std::move(localCellIdx)); } template void Opm::ParallelPAvgDynamicSourceData::setToZero() { std::fill_n(this->localSrc_.begin(), this->localSrc_.size(), 0.0); } template void Opm::ParallelPAvgDynamicSourceData:: reconstruct(const std::vector& sourceLocations, GlobalToLocal localCellIdx) { PAvgDynamicSourceData::reconstruct(sourceLocations); // Reconstruct base this->finaliseConstruction(sourceLocations, std::move(localCellIdx)); } template void Opm::ParallelPAvgDynamicSourceData::collectLocalSources(Evaluator eval) { auto localIx = std::size_t{0}; for (const auto& location : this->locations_) { eval(location.cell, this->localSourceTerm(localIx++)); } } template void Opm::ParallelPAvgDynamicSourceData::synchroniseSources() { this->comm_.get() .allgatherv(this->localSrc_.data(), // Input (from) static_cast(this->localSrc_.size()), this->src_.data(), // Output (to) this->allSizes_.data(), // #elements per rank this->startPointers_.data()); // Output offsets } template typename std::vector::size_type Opm::ParallelPAvgDynamicSourceData:: storageIndex(const typename std::vector::size_type elemIndex) const { return this->storageIndex_[elemIndex]; } template void Opm::ParallelPAvgDynamicSourceData:: finaliseConstruction(const std::vector& sourceLocations, GlobalToLocal localCellIdx) { auto ix = std::size_t{0}; this->locations_.clear(); for (const auto& location : sourceLocations) { if (const auto cell = localCellIdx(location); cell >= 0) { this->locations_.push_back({ ix, cell }); } ix += 1; } this->localSrc_.assign(this->numSpanItems() * this->locations_.size(), 0.0); this->defineCommunication(); } template typename Opm::PAvgDynamicSourceData::template SourceDataSpan Opm::ParallelPAvgDynamicSourceData::localSourceTerm(const std::size_t localIx) { return this->sourceTerm(localIx, this->localSrc_); } template void Opm::ParallelPAvgDynamicSourceData::defineCommunication() { // 1) Determine origins/owning ranks for all source terms. auto ixVec = std::vector(this->locations_.size()); std::transform(this->locations_.begin(), this->locations_.end(), ixVec.begin(), [](const auto& location) { return location.ix; }); constexpr auto numItems = ParallelPAvgDynamicSourceData::numSpanItems(); const auto& [allIndices, allIxStart] = allGatherv(ixVec, this->comm_.get()); // ----------------------------------------------------------------------- // 2) Determine starting pointers/offsets/displacements for received // basic elements from each rank. There are 'numItems' basic data // elements for each source term. this->startPointers_.resize(allIxStart.size()); std::transform(allIxStart.begin(), allIxStart.end(), this->startPointers_.begin(), [](const int start) { return numItems * start; }); // ----------------------------------------------------------------------- // 3) Determine number of basic data elements to receive from each rank. this->allSizes_.resize(allIxStart.size() - 1); std::adjacent_difference(this->startPointers_.begin() + 1, this->startPointers_.end(), this->allSizes_.begin()); // ----------------------------------------------------------------------- // 4) Build translation mapping from source term element indices to // storage indices. // // Note that if the source terms aren't all active--e.g., if a well // is connected in deactivated cells--then allIndices is not a // permutation of 0..allIndices.size()-1 and the maximum source // location may exceed size()-1. Resize the storageIndex_ according // to the largest source location ID. if (auto maxIxPos = std::max_element(allIndices.begin(), allIndices.end()); maxIxPos != allIndices.end()) { // +1 for zero-based indices. this->storageIndex_.resize(*maxIxPos + 1); } auto storageIx = std::vector::size_type{0}; for (const auto& elemIndex : allIndices) { this->storageIndex_[elemIndex] = storageIx++; } } template class Opm::ParallelPAvgDynamicSourceData;