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 // ***********************************************************************
4 //
5 // MueLu: A package for multigrid based preconditioning
6 // Copyright 2012 Sandia Corporation
7 //
8 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // Questions? Contact
39 // Jonathan Hu (jhu@sandia.gov)
40 // Ray Tuminaro (rstumin@sandia.gov)
41 // Luc Berger-Vergiat (lberge@sandia.gov)
42 //
43 // ***********************************************************************
44 //
45 // @HEADER
46 #ifndef MUELU_INDEXMANAGER_DEF_HPP
47 #define MUELU_INDEXMANAGER_DEF_HPP
48 
50 
51 #include "MueLu_ConfigDefs.hpp"
53 
54 /*****************************************************************************
55 
56 ****************************************************************************/
57 
58 namespace MueLu {
59 
60 template <class LocalOrdinal, class GlobalOrdinal, class Node>
63  const bool coupled,
64  const bool singleCoarsePoint,
65  const int NumDimensions,
66  const int interpolationOrder,
67  const Array<GO> GFineNodesPerDir,
68  const Array<LO> LFineNodesPerDir)
69  : comm_(comm)
70  , coupled_(coupled)
71  , singleCoarsePoint_(singleCoarsePoint)
72  , numDimensions(NumDimensions)
73  , interpolationOrder_(interpolationOrder)
74  , gFineNodesPerDir(GFineNodesPerDir)
75  , lFineNodesPerDir(LFineNodesPerDir) {
76  coarseRate.resize(3);
77  endRate.resize(3);
81 
82  offsets.resize(3);
86 
87 } // Constructor
88 
89 template <class LocalOrdinal, class GlobalOrdinal, class Node>
93  if (const char* dbg = std::getenv("MUELU_INDEXMANAGER_DEBUG")) {
94  out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
95  out->setShowAllFrontMatter(false).setShowProcRank(true);
96  } else {
97  out = Teuchos::getFancyOStream(rcp(new Teuchos::oblackholestream()));
98  }
99 
100  if (coupled_) {
101  gNumFineNodes10 = gFineNodesPerDir[1] * gFineNodesPerDir[0];
102  gNumFineNodes = gFineNodesPerDir[2] * gNumFineNodes10;
103  } else {
104  gNumFineNodes10 = Teuchos::OrdinalTraits<GO>::invalid();
105  gNumFineNodes = Teuchos::OrdinalTraits<GO>::invalid();
106  }
107  lNumFineNodes10 = lFineNodesPerDir[1] * lFineNodesPerDir[0];
108  lNumFineNodes = lFineNodesPerDir[2] * lNumFineNodes10;
109  for (int dim = 0; dim < 3; ++dim) {
110  if (dim < numDimensions) {
111  if (coupled_) {
112  if (startIndices[dim] == 0) {
113  meshEdge[2 * dim] = true;
114  }
115  if (startIndices[dim + 3] + 1 == gFineNodesPerDir[dim]) {
116  meshEdge[2 * dim + 1] = true;
117  endRate[dim] = startIndices[dim + 3] % coarseRate[dim];
118  }
119  } else { // With uncoupled problem each rank might require a different endRate
120  meshEdge[2 * dim] = true;
121  meshEdge[2 * dim + 1] = true;
122  endRate[dim] = (lFineNodesPerDir[dim] - 1) % coarseRate[dim];
123  }
124  if (endRate[dim] == 0) {
125  endRate[dim] = coarseRate[dim];
126  }
127 
128  // If uncoupled aggregation is used, offsets[dim] = 0, so nothing to do.
129  if (coupled_) {
130  offsets[dim] = Teuchos::as<LO>(startIndices[dim]) % coarseRate[dim];
131  if (offsets[dim] == 0) {
132  coarseNodeOffsets[dim] = 0;
133  } else if (startIndices[dim] + endRate[dim] == lFineNodesPerDir[dim]) {
134  coarseNodeOffsets[dim] = endRate[dim] - offsets[dim];
135  } else {
136  coarseNodeOffsets[dim] = coarseRate[dim] - offsets[dim];
137  }
138 
139  if (interpolationOrder_ == 0) {
140  int rem = startIndices[dim] % coarseRate[dim];
141  if ((rem != 0) && (rem <= Teuchos::as<double>(coarseRate[dim]) / 2.0)) {
142  ghostInterface[2 * dim] = true;
143  }
144  rem = startIndices[dim + 3] % coarseRate[dim];
145  // uncoupled by nature does not require ghosts nodes
146  if (coupled_ && (startIndices[dim + 3] != gFineNodesPerDir[dim] - 1) &&
147  (rem > Teuchos::as<double>(coarseRate[dim]) / 2.0)) {
148  ghostInterface[2 * dim + 1] = true;
149  }
150 
151  } else if (interpolationOrder_ == 1) {
152  if (coupled_ && (startIndices[dim] % coarseRate[dim] != 0 ||
153  startIndices[dim] == gFineNodesPerDir[dim] - 1)) {
154  ghostInterface[2 * dim] = true;
155  }
156  if (coupled_ && (startIndices[dim + 3] != gFineNodesPerDir[dim] - 1) &&
157  ((lFineNodesPerDir[dim] == 1) || (startIndices[dim + 3] % coarseRate[dim] != 0))) {
158  ghostInterface[2 * dim + 1] = true;
159  }
160  }
161  }
162  } else { // Default value for dim >= numDimensions
163  endRate[dim] = 1;
164  }
165  }
166 
167  *out << "singleCoarsePoint? " << singleCoarsePoint_ << std::endl;
168  *out << "gFineNodesPerDir: " << gFineNodesPerDir << std::endl;
169  *out << "lFineNodesPerDir: " << lFineNodesPerDir << std::endl;
170  *out << "endRate: " << endRate << std::endl;
171  *out << "ghostInterface: {" << ghostInterface[0] << ", " << ghostInterface[1] << ", "
172  << ghostInterface[2] << ", " << ghostInterface[3] << ", " << ghostInterface[4] << ", "
173  << ghostInterface[5] << "}" << std::endl;
174  *out << "meshEdge: {" << meshEdge[0] << ", " << meshEdge[1] << ", "
175  << meshEdge[2] << ", " << meshEdge[3] << ", " << meshEdge[4] << ", "
176  << meshEdge[5] << "}" << std::endl;
177  *out << "startIndices: " << startIndices << std::endl;
178  *out << "offsets: " << offsets << std::endl;
179  *out << "coarseNodeOffsets: " << coarseNodeOffsets << std::endl;
180 
181  // Here one element can represent either the degenerate case of one node or the more general
182  // case of two nodes, i.e. x---x is a 1D element with two nodes and x is a 1D element with
183  // one node. This helps generating a 3D space from tensorial products...
184  // A good way to handle this would be to generalize the algorithm to take into account the
185  // discretization order used in each direction, at least in the FEM sense, since a 0 degree
186  // discretization will have a unique node per element. This way 1D discretization can be
187  // viewed as a 3D problem with one 0 degree element in the y direction and one 0 degre
188  // element in the z direction.
189  // !!! Operations below are aftecting both local and global values that have two !!!
190  // different orientations. Orientations can be interchanged using mapDirG2L and mapDirL2G.
191  // coarseRate, endRate and offsets are in the global basis, as well as all the variables
192  // starting with a g.
193  // !!! while the variables starting with an l are in the local basis. !!!
194  for (int dim = 0; dim < 3; ++dim) {
195  if (dim < numDimensions) {
196  // Check whether the partition includes the "end" of the mesh which means that endRate
197  // will apply. Also make sure that endRate is not 0 which means that the mesh does not
198  // require a particular treatment at the boundaries.
199  if (meshEdge[2 * dim + 1]) {
200  lCoarseNodesPerDir[dim] = (lFineNodesPerDir[dim] - endRate[dim] + offsets[dim] - 1) / coarseRate[dim] + 1;
201  if (offsets[dim] == 0) {
202  ++lCoarseNodesPerDir[dim];
203  }
204  // We might want to coarsening the direction
205  // into a single layer if there are not enough
206  // points left to form two aggregates
207  if (singleCoarsePoint_ && lFineNodesPerDir[dim] - 1 < coarseRate[dim]) {
208  lCoarseNodesPerDir[dim] = 1;
209  }
210  } else {
211  lCoarseNodesPerDir[dim] = (lFineNodesPerDir[dim] + offsets[dim] - 1) / coarseRate[dim];
212  if (offsets[dim] == 0) {
213  ++lCoarseNodesPerDir[dim];
214  }
215  }
216 
217  // The first branch of this if-statement will be used if the rank contains only one layer
218  // of nodes in direction i, that layer must also coincide with the boundary of the mesh
219  // and coarseRate[i] == endRate[i]...
220  if (interpolationOrder_ == 0) {
221  startGhostedCoarseNode[dim] = startIndices[dim] / coarseRate[dim];
222  int rem = startIndices[dim] % coarseRate[dim];
223  if (rem > (Teuchos::as<double>(coarseRate[dim]) / 2.0)) {
224  ++startGhostedCoarseNode[dim];
225  }
226  } else {
227  if ((startIndices[dim] == gFineNodesPerDir[dim] - 1) &&
228  (startIndices[dim] % coarseRate[dim] == 0)) {
229  startGhostedCoarseNode[dim] = startIndices[dim] / coarseRate[dim] - 1;
230  } else {
231  startGhostedCoarseNode[dim] = startIndices[dim] / coarseRate[dim];
232  }
233  }
234 
235  // This array is passed to the RAPFactory and eventually becomes gFineNodePerDir on the next
236  // level.
237  gCoarseNodesPerDir[dim] = (gFineNodesPerDir[dim] - 1) / coarseRate[dim];
238  if ((gFineNodesPerDir[dim] - 1) % coarseRate[dim] == 0) {
239  ++gCoarseNodesPerDir[dim];
240  } else {
241  gCoarseNodesPerDir[dim] += 2;
242  }
243  } else { // Default value for dim >= numDimensions
244  // endRate[dim] = 1;
245  gCoarseNodesPerDir[dim] = 1;
246  lCoarseNodesPerDir[dim] = 1;
247  } // if (dim < numDimensions)
248 
249  // This would happen if the rank does not own any nodes but in that case a subcommunicator
250  // should be used so this should really not be a concern.
251  if (lFineNodesPerDir[dim] < 1) {
252  lCoarseNodesPerDir[dim] = 0;
253  }
254  ghostedNodesPerDir[dim] = lCoarseNodesPerDir[dim];
255  // Check whether face *low needs ghost nodes
256  if (ghostInterface[2 * dim]) {
257  ghostedNodesPerDir[dim] += 1;
258  }
259  // Check whether face *hi needs ghost nodes
260  if (ghostInterface[2 * dim + 1]) {
261  ghostedNodesPerDir[dim] += 1;
262  }
263  } // Loop for dim=0:3
264 
265  // With uncoupled aggregation we need to communicate to compute the global number of coarse points
266  if (!coupled_) {
267  for (int dim = 0; dim < 3; ++dim) {
268  gCoarseNodesPerDir[dim] = -1;
269  }
270  }
271 
272  // Compute cummulative values
273  lNumCoarseNodes10 = lCoarseNodesPerDir[0] * lCoarseNodesPerDir[1];
274  lNumCoarseNodes = lNumCoarseNodes10 * lCoarseNodesPerDir[2];
275  numGhostedNodes10 = ghostedNodesPerDir[1] * ghostedNodesPerDir[0];
276  numGhostedNodes = numGhostedNodes10 * ghostedNodesPerDir[2];
277  numGhostNodes = numGhostedNodes - lNumCoarseNodes;
278 
279  *out << "lCoarseNodesPerDir: " << lCoarseNodesPerDir << std::endl;
280  *out << "gCoarseNodesPerDir: " << gCoarseNodesPerDir << std::endl;
281  *out << "ghostedNodesPerDir: " << ghostedNodesPerDir << std::endl;
282  *out << "lNumCoarseNodes=" << lNumCoarseNodes << std::endl;
283  *out << "numGhostedNodes=" << numGhostedNodes << std::endl;
284 }
285 
286 } // namespace MueLu
287 
288 #define MUELU_INDEXMANAGER_SHORT
289 #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...