MueLu Version of the Day
Loading...
Searching...
No Matches
MueLu_IndexManager_def.hpp
Go to the documentation of this file.
1// @HEADER
2// *****************************************************************************
3// MueLu: A package for multigrid based preconditioning
4//
5// Copyright 2012 NTESS and the MueLu contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10#ifndef MUELU_INDEXMANAGER_DEF_HPP
11#define MUELU_INDEXMANAGER_DEF_HPP
12
13#include "Teuchos_OrdinalTraits.hpp"
14
15#include "MueLu_ConfigDefs.hpp"
17
18/*****************************************************************************
19
20****************************************************************************/
21
22namespace MueLu {
23
24template <class LocalOrdinal, class GlobalOrdinal, class Node>
26 IndexManager(const RCP<const Teuchos::Comm<int> > comm,
27 const bool coupled,
28 const bool singleCoarsePoint,
29 const int NumDimensions,
30 const int interpolationOrder,
31 const Array<GO> GFineNodesPerDir,
32 const Array<LO> LFineNodesPerDir)
33 : comm_(comm)
34 , coupled_(coupled)
35 , singleCoarsePoint_(singleCoarsePoint)
36 , numDimensions(NumDimensions)
37 , interpolationOrder_(interpolationOrder)
38 , gFineNodesPerDir(GFineNodesPerDir)
39 , lFineNodesPerDir(LFineNodesPerDir) {
40 coarseRate.resize(3);
41 endRate.resize(3);
42 gCoarseNodesPerDir.resize(3);
43 lCoarseNodesPerDir.resize(3);
44 ghostedNodesPerDir.resize(3);
45
46 offsets.resize(3);
47 coarseNodeOffsets.resize(3);
48 startIndices.resize(6);
49 startGhostedCoarseNode.resize(3);
50
51} // Constructor
52
53template <class LocalOrdinal, class GlobalOrdinal, class Node>
56 RCP<Teuchos::FancyOStream> out;
57 if (const char* dbg = std::getenv("MUELU_INDEXMANAGER_DEBUG")) {
58 out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
59 out->setShowAllFrontMatter(false).setShowProcRank(true);
60 } else {
61 out = Teuchos::getFancyOStream(rcp(new Teuchos::oblackholestream()));
62 }
63
64 if (coupled_) {
65 gNumFineNodes10 = gFineNodesPerDir[1] * gFineNodesPerDir[0];
66 gNumFineNodes = gFineNodesPerDir[2] * gNumFineNodes10;
67 } else {
68 gNumFineNodes10 = Teuchos::OrdinalTraits<GO>::invalid();
69 gNumFineNodes = Teuchos::OrdinalTraits<GO>::invalid();
70 }
71 lNumFineNodes10 = lFineNodesPerDir[1] * lFineNodesPerDir[0];
72 lNumFineNodes = lFineNodesPerDir[2] * lNumFineNodes10;
73 for (int dim = 0; dim < 3; ++dim) {
74 if (dim < numDimensions) {
75 if (coupled_) {
76 if (startIndices[dim] == 0) {
77 meshEdge[2 * dim] = true;
78 }
79 if (startIndices[dim + 3] + 1 == gFineNodesPerDir[dim]) {
80 meshEdge[2 * dim + 1] = true;
81 endRate[dim] = startIndices[dim + 3] % coarseRate[dim];
82 }
83 } else { // With uncoupled problem each rank might require a different endRate
84 meshEdge[2 * dim] = true;
85 meshEdge[2 * dim + 1] = true;
86 endRate[dim] = (lFineNodesPerDir[dim] - 1) % coarseRate[dim];
87 }
88 if (endRate[dim] == 0) {
89 endRate[dim] = coarseRate[dim];
90 }
91
92 // If uncoupled aggregation is used, offsets[dim] = 0, so nothing to do.
93 if (coupled_) {
94 offsets[dim] = Teuchos::as<LO>(startIndices[dim]) % coarseRate[dim];
95 if (offsets[dim] == 0) {
96 coarseNodeOffsets[dim] = 0;
97 } else if (startIndices[dim] + endRate[dim] == lFineNodesPerDir[dim]) {
98 coarseNodeOffsets[dim] = endRate[dim] - offsets[dim];
99 } else {
100 coarseNodeOffsets[dim] = coarseRate[dim] - offsets[dim];
102
103 if (interpolationOrder_ == 0) {
104 int rem = startIndices[dim] % coarseRate[dim];
105 if ((rem != 0) && (rem <= Teuchos::as<double>(coarseRate[dim]) / 2.0)) {
106 ghostInterface[2 * dim] = true;
107 }
108 rem = startIndices[dim + 3] % coarseRate[dim];
109 // uncoupled by nature does not require ghosts nodes
110 if (coupled_ && (startIndices[dim + 3] != gFineNodesPerDir[dim] - 1) &&
111 (rem > Teuchos::as<double>(coarseRate[dim]) / 2.0)) {
112 ghostInterface[2 * dim + 1] = true;
113 }
114
115 } else if (interpolationOrder_ == 1) {
116 if (coupled_ && (startIndices[dim] % coarseRate[dim] != 0 ||
117 startIndices[dim] == gFineNodesPerDir[dim] - 1)) {
118 ghostInterface[2 * dim] = true;
119 }
120 if (coupled_ && (startIndices[dim + 3] != gFineNodesPerDir[dim] - 1) &&
121 ((lFineNodesPerDir[dim] == 1) || (startIndices[dim + 3] % coarseRate[dim] != 0))) {
122 ghostInterface[2 * dim + 1] = true;
123 }
124 }
125 }
126 } else { // Default value for dim >= numDimensions
127 endRate[dim] = 1;
128 }
129 }
130
131 *out << "singleCoarsePoint? " << singleCoarsePoint_ << std::endl;
132 *out << "gFineNodesPerDir: " << gFineNodesPerDir << std::endl;
133 *out << "lFineNodesPerDir: " << lFineNodesPerDir << std::endl;
134 *out << "endRate: " << endRate << std::endl;
135 *out << "ghostInterface: {" << ghostInterface[0] << ", " << ghostInterface[1] << ", "
136 << ghostInterface[2] << ", " << ghostInterface[3] << ", " << ghostInterface[4] << ", "
137 << ghostInterface[5] << "}" << std::endl;
138 *out << "meshEdge: {" << meshEdge[0] << ", " << meshEdge[1] << ", "
139 << meshEdge[2] << ", " << meshEdge[3] << ", " << meshEdge[4] << ", "
140 << meshEdge[5] << "}" << std::endl;
141 *out << "startIndices: " << startIndices << std::endl;
142 *out << "offsets: " << offsets << std::endl;
143 *out << "coarseNodeOffsets: " << coarseNodeOffsets << std::endl;
144
145 // Here one element can represent either the degenerate case of one node or the more general
146 // case of two nodes, i.e. x---x is a 1D element with two nodes and x is a 1D element with
147 // one node. This helps generating a 3D space from tensorial products...
148 // A good way to handle this would be to generalize the algorithm to take into account the
149 // discretization order used in each direction, at least in the FEM sense, since a 0 degree
150 // discretization will have a unique node per element. This way 1D discretization can be
151 // viewed as a 3D problem with one 0 degree element in the y direction and one 0 degre
152 // element in the z direction.
153 // !!! Operations below are aftecting both local and global values that have two !!!
154 // different orientations. Orientations can be interchanged using mapDirG2L and mapDirL2G.
155 // coarseRate, endRate and offsets are in the global basis, as well as all the variables
156 // starting with a g.
157 // !!! while the variables starting with an l are in the local basis. !!!
158 for (int dim = 0; dim < 3; ++dim) {
159 if (dim < numDimensions) {
160 // Check whether the partition includes the "end" of the mesh which means that endRate
161 // will apply. Also make sure that endRate is not 0 which means that the mesh does not
162 // require a particular treatment at the boundaries.
163 if (meshEdge[2 * dim + 1]) {
164 lCoarseNodesPerDir[dim] = (lFineNodesPerDir[dim] - endRate[dim] + offsets[dim] - 1) / coarseRate[dim] + 1;
165 if (offsets[dim] == 0) {
166 ++lCoarseNodesPerDir[dim];
167 }
168 // We might want to coarsening the direction
169 // into a single layer if there are not enough
170 // points left to form two aggregates
171 if (singleCoarsePoint_ && lFineNodesPerDir[dim] - 1 < coarseRate[dim]) {
172 lCoarseNodesPerDir[dim] = 1;
173 }
174 } else {
175 lCoarseNodesPerDir[dim] = (lFineNodesPerDir[dim] + offsets[dim] - 1) / coarseRate[dim];
176 if (offsets[dim] == 0) {
177 ++lCoarseNodesPerDir[dim];
178 }
179 }
180
181 // The first branch of this if-statement will be used if the rank contains only one layer
182 // of nodes in direction i, that layer must also coincide with the boundary of the mesh
183 // and coarseRate[i] == endRate[i]...
184 if (interpolationOrder_ == 0) {
185 startGhostedCoarseNode[dim] = startIndices[dim] / coarseRate[dim];
186 int rem = startIndices[dim] % coarseRate[dim];
187 if (rem > (Teuchos::as<double>(coarseRate[dim]) / 2.0)) {
188 ++startGhostedCoarseNode[dim];
189 }
190 } else {
191 if ((startIndices[dim] == gFineNodesPerDir[dim] - 1) &&
192 (startIndices[dim] % coarseRate[dim] == 0)) {
193 startGhostedCoarseNode[dim] = startIndices[dim] / coarseRate[dim] - 1;
194 } else {
195 startGhostedCoarseNode[dim] = startIndices[dim] / coarseRate[dim];
196 }
197 }
198
199 // This array is passed to the RAPFactory and eventually becomes gFineNodePerDir on the next
200 // level.
201 gCoarseNodesPerDir[dim] = (gFineNodesPerDir[dim] - 1) / coarseRate[dim];
202 if ((gFineNodesPerDir[dim] - 1) % coarseRate[dim] == 0) {
203 ++gCoarseNodesPerDir[dim];
204 } else {
205 gCoarseNodesPerDir[dim] += 2;
206 }
207 } else { // Default value for dim >= numDimensions
208 // endRate[dim] = 1;
209 gCoarseNodesPerDir[dim] = 1;
210 lCoarseNodesPerDir[dim] = 1;
211 } // if (dim < numDimensions)
212
213 // This would happen if the rank does not own any nodes but in that case a subcommunicator
214 // should be used so this should really not be a concern.
215 if (lFineNodesPerDir[dim] < 1) {
216 lCoarseNodesPerDir[dim] = 0;
217 }
218 ghostedNodesPerDir[dim] = lCoarseNodesPerDir[dim];
219 // Check whether face *low needs ghost nodes
220 if (ghostInterface[2 * dim]) {
221 ghostedNodesPerDir[dim] += 1;
222 }
223 // Check whether face *hi needs ghost nodes
224 if (ghostInterface[2 * dim + 1]) {
225 ghostedNodesPerDir[dim] += 1;
226 }
227 } // Loop for dim=0:3
228
229 // With uncoupled aggregation we need to communicate to compute the global number of coarse points
230 if (!coupled_) {
231 for (int dim = 0; dim < 3; ++dim) {
232 gCoarseNodesPerDir[dim] = -1;
233 }
234 }
235
236 // Compute cummulative values
237 lNumCoarseNodes10 = lCoarseNodesPerDir[0] * lCoarseNodesPerDir[1];
238 lNumCoarseNodes = lNumCoarseNodes10 * lCoarseNodesPerDir[2];
239 numGhostedNodes10 = ghostedNodesPerDir[1] * ghostedNodesPerDir[0];
240 numGhostedNodes = numGhostedNodes10 * ghostedNodesPerDir[2];
241 numGhostNodes = numGhostedNodes - lNumCoarseNodes;
242
243 *out << "lCoarseNodesPerDir: " << lCoarseNodesPerDir << std::endl;
244 *out << "gCoarseNodesPerDir: " << gCoarseNodesPerDir << std::endl;
245 *out << "ghostedNodesPerDir: " << ghostedNodesPerDir << std::endl;
246 *out << "lNumCoarseNodes=" << lNumCoarseNodes << std::endl;
247 *out << "numGhostedNodes=" << numGhostedNodes << std::endl;
248}
249
250} // namespace MueLu
251
252#define MUELU_INDEXMANAGER_SHORT
253#endif // MUELU_INDEXMANAGER_DEF_HPP
Array< LO > offsets
distance between lowest (resp. highest) index to the lowest (resp. highest) ghostedNodeIndex in that ...
Array< LO > coarseNodeOffsets
distance between lowest (resp. highest) index to the lowest (resp. highest) coarseNodeIndex in that d...
Array< LO > ghostedNodesPerDir
local number of ghosted nodes (i.e. ghost + coarse nodes) per direction
Array< GO > startGhostedCoarseNode
lowest coarse global tuple (i,j,k) of a node remaing on the local process after coarsening.
Array< GO > gCoarseNodesPerDir
global number of nodes per direction remaining after coarsening.
Array< GO > startIndices
lowest global tuple (i,j,k) of a node on the local process
Array< int > coarseRate
coarsening rate in each direction
IndexManager()=default
Array< int > endRate
adapted coarsening rate at the edge of the mesh in each direction.
Array< LO > lCoarseNodesPerDir
local number of nodes per direction remaing after coarsening.
Namespace for MueLu classes and methods.