LgrOutputTransGather.hpp
Go to the documentation of this file.
1// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2// vi: set et ts=4 sw=4 sts=4:
3/*
4 This file is part of the Open Porous Media project (OPM).
5
6 OPM is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 2 of the License, or
9 (at your option) any later version.
10
11 OPM is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with OPM. If not, see <http://www.gnu.org/licenses/>.
18
19 Consult the COPYING file in the top-level source directory of this
20 module for the precise wording of the license and the list of
21 copyright holders.
22*/
23#ifndef OPM_LGR_OUTPUT_TRANS_GATHER_HPP
24#define OPM_LGR_OUTPUT_TRANS_GATHER_HPP
25
26#include <dune/grid/common/mcmgmapper.hh>
27#include <dune/grid/common/partitionset.hh>
28
29#include <opm/grid/common/CommunicationUtils.hpp>
30#include <opm/grid/cpgrid/LevelCartesianIndexMapper.hpp>
31
32#include <algorithm>
33#include <array>
34#include <cassert>
35#include <cstddef>
36#include <utility>
37#include <vector>
38
39namespace Opm {
40
47template <std::size_t N>
49{
50public:
51 using Key = std::array<int, N>;
52
53 LgrTransIndex() = default;
54
57 explicit LgrTransIndex(std::vector<std::pair<Key, double>> records)
58 : records_(std::move(records))
59 {
60 std::sort(records_.begin(), records_.end(),
61 [](const auto& a, const auto& b) { return a.first < b.first; });
62 assert(std::adjacent_find(records_.begin(), records_.end(),
63 [](const auto& a, const auto& b) { return a.first == b.first; })
64 == records_.end() && "duplicate LGR transmissibility key");
65 }
66
68 const double* find(const Key& key) const
69 {
70 const auto it = std::lower_bound(records_.begin(), records_.end(), key,
71 [](const auto& record, const Key& k) { return record.first < k; });
72 return (it != records_.end() && it->first == key) ? &it->second : nullptr;
73 }
74
75private:
76 std::vector<std::pair<Key, double>> records_;
77};
78
92{
95};
96
116template <class GridView, class TransFn>
118gatherLgrOutputTrans(const Dune::CpGrid& grid,
119 const GridView& gridView,
120 TransFn&& transFn)
121{
122 // Build the final (key, value) records directly -- no separate flat key/value
123 // buffers, no zip pass afterwards.
124 std::vector<std::pair<std::array<int,3>, double>> same; // level, minCart, maxCart
125 std::vector<std::pair<std::array<int,4>, double>> cross; // smallLevel, smallCart, largeLevel, largeCart
126
127 const LevelCartesianIndexMapper<Dune::CpGrid> levelCartMapp(grid);
128 const Dune::MultipleCodimMultipleGeomTypeMapper<GridView>
129 elemMapper(gridView, Dune::mcmgElementLayout());
130
131 for (const auto& elem : elements(gridView, Dune::Partitions::interior)) {
132 // The inside cell is the same for every intersection of this element.
133 const int levelIn = elem.level();
134 const int cartIn = levelCartMapp.cartesianIndex(elem.getLevelElem().index(), levelIn);
135 const auto idxIn = elemMapper.index(elem);
136
137 for (const auto& is : intersections(gridView, elem)) {
138 if (!is.neighbor()) {
139 continue;
140 }
141
142 const auto outside = is.outside();
143 const int levelOut = outside.level();
144
145 if (levelIn != levelOut) {
146 if (levelIn > levelOut) {
147 continue; // recorded exactly once, from the smaller-level side
148 }
149
150 cross.emplace_back(
151 std::array<int,4>{levelIn, cartIn, levelOut,
152 levelCartMapp.cartesianIndex(outside.getLevelElem().index(), levelOut)},
153 transFn(idxIn, elemMapper.index(outside)));
154 continue;
155 }
156
157 const int cartOut = levelCartMapp.cartesianIndex(
158 outside.getLevelElem().index(), levelIn);
159
160 if (cartIn > cartOut) {
161 // Record each connection once, in canonical direction. The comparison
162 // is rank-independent, so at a rank boundary exactly one of the two
163 // owner ranks records the connection.
164 continue;
165 }
166
167 same.emplace_back(std::array<int,3>{levelIn, cartIn, cartOut},
168 transFn(idxIn, elemMapper.index(outside)));
169 }
170 }
171
172 // Gather each record vector directly to the I/O rank -- one collective per kind.
173 // gatherv is generic; Dune's
174 // MPITraits<std::pair<std::array<int,N>,double>> composes a byte-blob array with
175 // MPI_DOUBLE, so the record moves as a single MPI datatype. gatherv is collective
176 // and returns empty vectors on the non-root ranks. MPI's int counts/displacements
177 // bound the total record count across ALL ranks at ~2^31 records -- a shared
178 // MPI-wide ceiling, not a per-rank one.
179 const auto& comm = grid.comm();
180 auto allSame = gatherv(same, comm, 0).first;
181 auto allCross = gatherv(cross, comm, 0).first;
182
183 // Index the gathered records on the I/O rank; empty on the others.
184 GatheredLgrOutputTrans gathered;
185 gathered.sameLevel = LgrTransIndex<3>(std::move(allSame));
186 gathered.crossLevel = LgrTransIndex<4>(std::move(allCross));
187 return gathered;
188}
189
190} // namespace Opm
191
192#endif // OPM_LGR_OUTPUT_TRANS_GATHER_HPP
Definition: EclGenericWriter.hpp:54
Definition: LgrOutputTransGather.hpp:49
LgrTransIndex()=default
LgrTransIndex(std::vector< std::pair< Key, double > > records)
Definition: LgrOutputTransGather.hpp:57
std::array< int, N > Key
Definition: LgrOutputTransGather.hpp:51
const double * find(const Key &key) const
Definition: LgrOutputTransGather.hpp:68
Definition: blackoilbioeffectsmodules.hh:45
GatheredLgrOutputTrans gatherLgrOutputTrans(const Dune::CpGrid &grid, const GridView &gridView, TransFn &&transFn)
Definition: LgrOutputTransGather.hpp:118
Definition: LgrOutputTransGather.hpp:92
LgrTransIndex< 3 > sameLevel
Definition: LgrOutputTransGather.hpp:93
LgrTransIndex< 4 > crossLevel
Definition: LgrOutputTransGather.hpp:94