MueLu  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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 
14 
15 #include "MueLu_ConfigDefs.hpp"
17 
18 /*****************************************************************************
19 
20 ****************************************************************************/
21 
22 namespace MueLu {
23 
24 template <class LocalOrdinal, class GlobalOrdinal, class Node>
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);
45 
46  offsets.resize(3);
50 
51 } // Constructor
52 
53 template <class LocalOrdinal, class GlobalOrdinal, class Node>
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];
101  }
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< GO > gCoarseNodesPerDir
global number of nodes per direction remaining after coarsening.
basic_FancyOStream & setShowProcRank(const bool showProcRank)
Array< GO > startIndices
lowest global tuple (i,j,k) of a node on the local process
Array< GO > startGhostedCoarseNode
lowest coarse global tuple (i,j,k) of a node remaing on the local process after coarsening.
Array< LO > offsets
distance between lowest (resp. highest) index to the lowest (resp. highest) ghostedNodeIndex in that ...
Array< LO > ghostedNodesPerDir
local number of ghosted nodes (i.e. ghost + coarse nodes) per direction
Array< int > coarseRate
coarsening rate in each direction
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
IndexManager()=default
Array< LO > lCoarseNodesPerDir
local number of nodes per direction remaing after coarsening.
Array< int > endRate
adapted coarsening rate at the edge of the mesh in each direction.
basic_FancyOStream & setShowAllFrontMatter(const bool showAllFrontMatter)
void resize(size_type new_size, const value_type &x=value_type())
Array< LO > coarseNodeOffsets
distance between lowest (resp. highest) index to the lowest (resp. highest) coarseNodeIndex in that d...