MueLu Version of the Day
Loading...
Searching...
No Matches
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
49#include "Teuchos_OrdinalTraits.hpp"
50
51#include "MueLu_ConfigDefs.hpp"
53
54/*****************************************************************************
55
56****************************************************************************/
57
58namespace MueLu {
59
60 template<class LocalOrdinal, class GlobalOrdinal, class Node>
62 IndexManager(const RCP<const Teuchos::Comm<int> > comm,
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), coupled_(coupled), singleCoarsePoint_(singleCoarsePoint),
70 numDimensions(NumDimensions), interpolationOrder_(interpolationOrder),
71 gFineNodesPerDir(GFineNodesPerDir), lFineNodesPerDir(LFineNodesPerDir) {
72
73 coarseRate.resize(3);
74 endRate.resize(3);
75 gCoarseNodesPerDir.resize(3);
76 lCoarseNodesPerDir.resize(3);
77 ghostedNodesPerDir.resize(3);
78
79 offsets.resize(3);
80 coarseNodeOffsets.resize(3);
81 startIndices.resize(6);
82 startGhostedCoarseNode.resize(3);
83
84 } // Constructor
85
86 template<class LocalOrdinal, class GlobalOrdinal, class Node>
89
90 RCP<Teuchos::FancyOStream> out;
91 if(const char* dbg = std::getenv("MUELU_INDEXMANAGER_DEBUG")) {
92 out = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout));
93 out->setShowAllFrontMatter(false).setShowProcRank(true);
94 } else {
95 out = Teuchos::getFancyOStream(rcp(new Teuchos::oblackholestream()));
96 }
97
98 if(coupled_) {
101 } else {
102 gNumFineNodes10 = Teuchos::OrdinalTraits<GO>::invalid();
103 gNumFineNodes = Teuchos::OrdinalTraits<GO>::invalid();
104 }
107 for(int dim = 0; dim < 3; ++dim) {
108 if(dim < numDimensions) {
109 if(coupled_) {
110 if(startIndices[dim] == 0) {
111 meshEdge[2*dim] = true;
112 }
113 if(startIndices[dim + 3] + 1 == gFineNodesPerDir[dim]) {
114 meshEdge[2*dim + 1] = true;
115 endRate[dim] = startIndices[dim + 3] % coarseRate[dim];
116 }
117 } else { // With uncoupled problem each rank might require a different endRate
118 meshEdge[2*dim] = true;
119 meshEdge[2*dim + 1] = true;
120 endRate[dim] = (lFineNodesPerDir[dim] - 1) % coarseRate[dim];
121 }
122 if(endRate[dim] == 0) {endRate[dim] = coarseRate[dim];}
123
124 // If uncoupled aggregation is used, offsets[dim] = 0, so nothing to do.
125 if(coupled_) {
126 offsets[dim] = Teuchos::as<LO>(startIndices[dim]) % coarseRate[dim];
127 if(offsets[dim] == 0) {
128 coarseNodeOffsets[dim] = 0;
129 } else if(startIndices[dim] + endRate[dim] == lFineNodesPerDir[dim]) {
130 coarseNodeOffsets[dim] = endRate[dim] - offsets[dim];
131 } else {
132 coarseNodeOffsets[dim] = coarseRate[dim] - offsets[dim];
133 }
134
135 if(interpolationOrder_ == 0) {
136 int rem = startIndices[dim] % coarseRate[dim];
137 if( (rem != 0) && (rem <= Teuchos::as<double>(coarseRate[dim]) / 2.0)) {
138 ghostInterface[2*dim] = true;
139 }
140 rem = startIndices[dim + 3] % coarseRate[dim];
141 // uncoupled by nature does not require ghosts nodes
142 if(coupled_ && (startIndices[dim + 3] != gFineNodesPerDir[dim] - 1) &&
143 (rem > Teuchos::as<double>(coarseRate[dim]) / 2.0)) {
144 ghostInterface[2*dim + 1] = true;
145 }
146
147 } else if(interpolationOrder_ == 1) {
148 if(coupled_ && (startIndices[dim] % coarseRate[dim] != 0 ||
149 startIndices[dim] == gFineNodesPerDir[dim]-1)) {
150 ghostInterface[2*dim] = true;
151 }
152 if(coupled_ && (startIndices[dim + 3] != gFineNodesPerDir[dim] - 1) &&
153 ((lFineNodesPerDir[dim] == 1) || (startIndices[dim + 3] % coarseRate[dim] != 0))) {
154 ghostInterface[2*dim+1] = true;
155 }
156 }
157 }
158 } else { // Default value for dim >= numDimensions
159 endRate[dim] = 1;
160 }
161 }
162
163 *out << "singleCoarsePoint? " << singleCoarsePoint_ << std::endl;
164 *out << "gFineNodesPerDir: " << gFineNodesPerDir << std::endl;
165 *out << "lFineNodesPerDir: " << lFineNodesPerDir << std::endl;
166 *out << "endRate: " << endRate << std::endl;
167 *out << "ghostInterface: {" << ghostInterface[0] << ", " << ghostInterface[1] << ", "
168 << ghostInterface[2] << ", " << ghostInterface[3] << ", " << ghostInterface[4] << ", "
169 << ghostInterface[5] << "}" << std::endl;
170 *out << "meshEdge: {" << meshEdge[0] << ", " << meshEdge[1] << ", "
171 << meshEdge[2] << ", " << meshEdge[3] << ", " << meshEdge[4] << ", "
172 << meshEdge[5] << "}" << std::endl;
173 *out << "startIndices: " << startIndices << std::endl;
174 *out << "offsets: " << offsets << std::endl;
175 *out << "coarseNodeOffsets: " << coarseNodeOffsets << std::endl;
176
177 // Here one element can represent either the degenerate case of one node or the more general
178 // case of two nodes, i.e. x---x is a 1D element with two nodes and x is a 1D element with
179 // one node. This helps generating a 3D space from tensorial products...
180 // A good way to handle this would be to generalize the algorithm to take into account the
181 // discretization order used in each direction, at least in the FEM sense, since a 0 degree
182 // discretization will have a unique node per element. This way 1D discretization can be
183 // viewed as a 3D problem with one 0 degree element in the y direction and one 0 degre
184 // element in the z direction.
185 // !!! Operations below are aftecting both local and global values that have two !!!
186 // different orientations. Orientations can be interchanged using mapDirG2L and mapDirL2G.
187 // coarseRate, endRate and offsets are in the global basis, as well as all the variables
188 // starting with a g.
189 // !!! while the variables starting with an l are in the local basis. !!!
190 for(int dim = 0; dim < 3; ++dim) {
191 if(dim < numDimensions) {
192 // Check whether the partition includes the "end" of the mesh which means that endRate
193 // will apply. Also make sure that endRate is not 0 which means that the mesh does not
194 // require a particular treatment at the boundaries.
195 if( meshEdge[2*dim + 1] ) {
196 lCoarseNodesPerDir[dim] = (lFineNodesPerDir[dim] - endRate[dim] + offsets[dim] - 1)
197 / coarseRate[dim] + 1;
198 if(offsets[dim] == 0) {++lCoarseNodesPerDir[dim];}
199 // We might want to coarsening the direction
200 // into a single layer if there are not enough
201 // points left to form two aggregates
202 if(singleCoarsePoint_ && lFineNodesPerDir[dim] - 1 < coarseRate[dim]) {
203 lCoarseNodesPerDir[dim] =1;
204 }
205 } else {
206 lCoarseNodesPerDir[dim] = (lFineNodesPerDir[dim] + offsets[dim] - 1) / coarseRate[dim];
207 if(offsets[dim] == 0) {++lCoarseNodesPerDir[dim];}
208 }
209
210 // The first branch of this if-statement will be used if the rank contains only one layer
211 // of nodes in direction i, that layer must also coincide with the boundary of the mesh
212 // and coarseRate[i] == endRate[i]...
213 if(interpolationOrder_ == 0) {
214 startGhostedCoarseNode[dim] = startIndices[dim] / coarseRate[dim];
215 int rem = startIndices[dim] % coarseRate[dim];
216 if(rem > (Teuchos::as<double>(coarseRate[dim]) / 2.0) ) {
217 ++startGhostedCoarseNode[dim];
218 }
219 } else {
220 if((startIndices[dim] == gFineNodesPerDir[dim] - 1) &&
221 (startIndices[dim] % coarseRate[dim] == 0)) {
222 startGhostedCoarseNode[dim] = startIndices[dim] / coarseRate[dim] - 1;
223 } else {
224 startGhostedCoarseNode[dim] = startIndices[dim] / coarseRate[dim];
225 }
226 }
227
228 // This array is passed to the RAPFactory and eventually becomes gFineNodePerDir on the next
229 // level.
230 gCoarseNodesPerDir[dim] = (gFineNodesPerDir[dim] - 1) / coarseRate[dim];
231 if((gFineNodesPerDir[dim] - 1) % coarseRate[dim] == 0) {
232 ++gCoarseNodesPerDir[dim];
233 } else {
234 gCoarseNodesPerDir[dim] += 2;
235 }
236 } else { // Default value for dim >= numDimensions
237 // endRate[dim] = 1;
238 gCoarseNodesPerDir[dim] = 1;
239 lCoarseNodesPerDir[dim] = 1;
240 } // if (dim < numDimensions)
241
242 // This would happen if the rank does not own any nodes but in that case a subcommunicator
243 // should be used so this should really not be a concern.
244 if(lFineNodesPerDir[dim] < 1) {lCoarseNodesPerDir[dim] = 0;}
245 ghostedNodesPerDir[dim] = lCoarseNodesPerDir[dim];
246 // Check whether face *low needs ghost nodes
247 if(ghostInterface[2*dim]) {ghostedNodesPerDir[dim] += 1;}
248 // Check whether face *hi needs ghost nodes
249 if(ghostInterface[2*dim + 1]) {ghostedNodesPerDir[dim] += 1;}
250 } // Loop for dim=0:3
251
252 // With uncoupled aggregation we need to communicate to compute the global number of coarse points
253 if(!coupled_) {
254 for(int dim = 0; dim < 3; ++dim) {
255 gCoarseNodesPerDir[dim] = -1;
256 }
257 }
258
259 // Compute cummulative values
260 lNumCoarseNodes10 = lCoarseNodesPerDir[0]*lCoarseNodesPerDir[1];
261 lNumCoarseNodes = lNumCoarseNodes10*lCoarseNodesPerDir[2];
262 numGhostedNodes10 = ghostedNodesPerDir[1]*ghostedNodesPerDir[0];
263 numGhostedNodes = numGhostedNodes10*ghostedNodesPerDir[2];
264 numGhostNodes = numGhostedNodes - lNumCoarseNodes;
265
266 *out << "lCoarseNodesPerDir: " << lCoarseNodesPerDir << std::endl;
267 *out << "gCoarseNodesPerDir: " << gCoarseNodesPerDir << std::endl;
268 *out << "ghostedNodesPerDir: " << ghostedNodesPerDir << std::endl;
269 *out << "lNumCoarseNodes=" << lNumCoarseNodes << std::endl;
270 *out << "numGhostedNodes=" << numGhostedNodes << std::endl;
271 }
272
273} //namespace MueLu
274
275#define MUELU_INDEXMANAGER_SHORT
276#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...
const int interpolationOrder_
Interpolation order used by grid transfer operators using these aggregates.
const bool coupled_
Flag for coupled vs uncoupled aggregation mode, if true aggregation is coupled.
GO gNumFineNodes
global number of nodes.
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.
const Array< LO > lFineNodesPerDir
local number of nodes per direction.
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
GO gNumFineNodes10
global number of nodes per 0-1 slice.
Array< int > coarseRate
coarsening rate in each direction
IndexManager()=default
bool meshEdge[6]
flags indicating if we run into the edge of the mesh in ilo, ihi, jlo, jhi, klo or khi.
bool ghostInterface[6]
flags indicating if ghost points are needed at ilo, ihi, jlo, jhi, klo and khi boundaries.
const bool singleCoarsePoint_
Flag telling us if can reduce dimensions to a single layer.
const int numDimensions
Number of spacial dimensions in the problem.
LO lNumFineNodes10
local number of nodes per 0-1 slice.
LO lNumFineNodes
local number of nodes.
const RCP< const Teuchos::Comm< int > > comm_
Communicator used by uncoupled aggregation.
Array< int > endRate
adapted coarsening rate at the edge of the mesh in each direction.
const Array< GO > gFineNodesPerDir
global number of nodes per direction.
Array< LO > lCoarseNodesPerDir
local number of nodes per direction remaing after coarsening.
Namespace for MueLu classes and methods.