/* 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 namespace Opm { void RSTConv::init(const std::size_t numCells, const RSTConfig& rst_config, const std::array& compIdx) { const auto kw = rst_config.keywords.find("CONV"); if (kw == rst_config.keywords.end()) { N_ = 0; cnv_X_.clear(); return; } N_ = kw->second; compIdx_ = compIdx; cnv_X_.resize(6); for (std::size_t i = 0; i < 6; ++i) { if (compIdx_[i] > -1) { cnv_X_[i].resize(numCells); } } } template void RSTConv::update(const ResidualVector& resid) { if (N_ == 0) { return; } std::vector cix(resid.size()); std::iota(cix.begin(), cix.end(), 0); for (std::size_t i = 0; i < cnv_X_.size(); ++i) { if (cnv_X_[i].empty()) { continue; } std::partial_sort(cix.begin(), cix.begin() + N_, cix.end(), [&resid,c = compIdx_[i]](const int a, const int b) { return std::abs(resid[a][c]) > std::abs(resid[b][c]); }); this->gatherAndAccumulate(cix, resid, i); } } template void RSTConv::gatherAndAccumulate(const std::vector& lIdx, const ResidualVector& resid, int comp) { if (comm_.size() == 1) { for (int n = 0; n < N_; ++n) { ++cnv_X_[comp][lIdx[n]]; } return; } std::vector send_values(N_); std::vector values(comm_.rank() == 0 ? comm_.size() * N_ : 0); std::vector send_idx(N_); std::vector gIdx(comm_.rank() == 0 ? comm_.size() * N_ : 0); for (int i = 0; i < N_; ++i) { send_values[i] = std::abs(resid[lIdx[i]][compIdx_[comp]]); send_idx[i] = globalCell_[lIdx[i]]; } comm_.gather(send_idx.data(), gIdx.data(), N_, 0); comm_.gather(send_values.data(), values.data(), N_, 0); if (comm_.rank() != 0) { return; } std::vector valIdx(values.size()); std::iota(valIdx.begin(), valIdx.end(), 0); std::partial_sort(valIdx.begin(), valIdx.begin() + N_, valIdx.end(), [&values](const int i1, const int i2) { return values[i1] > values[i2]; }); for (int n = 0; n < N_; ++n) { ++cnv_X_[comp][gIdx[valIdx[n]]]; } } template using BFV = Dune::BlockVector>; #define INSTANCE(SIZE) \ template void RSTConv::update>(const BFV&); \ template void RSTConv::gatherAndAccumulate>(const std::vector&, \ const BFV&, int); INSTANCE(1) INSTANCE(2) INSTANCE(3) INSTANCE(4) INSTANCE(5) INSTANCE(6) } // namespace Opm