MueLu Version of the Day
Loading...
Searching...
No Matches
MueLu_BrickAggregationFactory_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_BRICKAGGREGATIONFACTORY_DEF_HPP_
11#define MUELU_BRICKAGGREGATIONFACTORY_DEF_HPP_
12
14#ifdef HAVE_MPI
15#include <Teuchos_DefaultMpiComm.hpp>
16#include <Teuchos_CommHelpers.hpp>
17#endif
18#include <Teuchos_OrdinalTraits.hpp>
19
20#include <Xpetra_Import.hpp>
21#include <Xpetra_ImportFactory.hpp>
22#include <Xpetra_Map.hpp>
23#include <Xpetra_MapFactory.hpp>
24#include <Xpetra_Matrix.hpp>
25#include <Xpetra_MultiVector.hpp>
26#include <Xpetra_MultiVectorFactory.hpp>
27
28#include "MueLu_Aggregates.hpp"
29#include "MueLu_Level.hpp"
30#include "MueLu_MasterList.hpp"
31#include "MueLu_Monitor.hpp"
32#include "MueLu_Utilities.hpp"
33#include "MueLu_LWGraph.hpp"
34
35namespace MueLu {
36
37template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
39 RCP<ParameterList> validParamList = rcp(new ParameterList());
40
41#define SET_VALID_ENTRY(name) validParamList->setEntry(name, MasterList::getEntry(name))
42 SET_VALID_ENTRY("aggregation: brick x size");
43 SET_VALID_ENTRY("aggregation: brick y size");
44 SET_VALID_ENTRY("aggregation: brick z size");
45 SET_VALID_ENTRY("aggregation: brick x Dirichlet");
46 SET_VALID_ENTRY("aggregation: brick y Dirichlet");
47 SET_VALID_ENTRY("aggregation: brick z Dirichlet");
48#undef SET_VALID_ENTRY
49
50 validParamList->set<RCP<const FactoryBase> >("A", Teuchos::null, "Generating factory for matrix");
51 validParamList->set<RCP<const FactoryBase> >("Coordinates", Teuchos::null, "Generating factory for coordinates");
52 return validParamList;
53}
54
55template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
57 Input(currentLevel, "A");
58 Input(currentLevel, "Coordinates");
59}
60
61// The current implementation cannot deal with bricks larger than 3x3(x3) in
62// parallel. The reason is that aggregation infrastructure in place has
63// major drawbacks.
64//
65// Aggregates class is constructed with a help of a provided map, either
66// taken from a graph, or provided directly. This map is usually taken to be
67// a column map of a matrix. The reason for that is that if we have an
68// overlapped aggregation, we want the processor owning aggregates to store
69// agg id for all nodes in this aggregate. If we used row map, there would
70// be no way for the processor to know whether there are some other nodes on
71// a different processor which belong to its aggregate. On the other hand,
72// using column map allows both vertex2AggId and procWinner arrays in
73// Aggregates class to store some extra data, such as whether nodes belonging
74// to a different processor belong to this processor aggregate.
75//
76// The drawback of this is that it stores only overlap=1 data. For aggressive
77// coarsening, such a brick aggregation with a large single dimension of
78// brick, it could happen that we need to know depth two or more extra nodes
79// in the other processor subdomain.
80//
81// Another issue is that we may have some implicit connection between
82// aggregate map and maps of A used in the construction of a tentative
83// prolongator.
84//
85// Another issue is that it seems that some info is unused or not required.
86// Specifically, it seems that if a node belongs to an aggregate on a
87// different processor, we don't actually need to set vertex2AggId and
88// procWinner, despite the following comment in
89// Aggregates decl:
90// vertex2AggId[k] gives a local id
91// corresponding to the aggregate to which
92// local id k has been assigned. While k
93// is the local id on my processor (MyPID)
94// vertex2AggId[k] is the local id on the
95// processor which actually owns the
96// aggregate. This owning processor has id
97// given by procWinner[k].
98// It is possible that that info is only used during arbitration in
99// CoupledAggregationFactory.
100//
101// The steps that we need to do to resolve this issue:
102// - Break the link between maps in TentativePFactory, allowing any maps in Aggregates
103// - Allow Aggregates to construct their own maps, if necessary, OR
104// - construct aggregates based on row map
105template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
107 FactoryMonitor m(*this, "Build", currentLevel);
108
109 typedef Xpetra::MultiVector<typename Teuchos::ScalarTraits<Scalar>::magnitudeType, LO, GO, NO> MultiVector_d;
110
111 const ParameterList& pL = GetParameterList();
112 RCP<MultiVector_d> coords = Get<RCP<MultiVector_d> >(currentLevel, "Coordinates");
113 RCP<Matrix> A = Get<RCP<Matrix> >(currentLevel, "A");
114 RCP<const Map> rowMap = A->getRowMap();
115 RCP<const Map> colMap = A->getColMap();
116 GO GO_INVALID = Teuchos::OrdinalTraits<GO>::invalid();
117
118 RCP<const Teuchos::Comm<int> > comm = rowMap->getComm();
119 int numProcs = comm->getSize();
120 int myRank = comm->getRank();
121
122 int numPoints = colMap->getLocalNumElements();
123
124 bx_ = pL.get<int>("aggregation: brick x size");
125 by_ = pL.get<int>("aggregation: brick y size");
126 bz_ = pL.get<int>("aggregation: brick z size");
127
128 dirichletX_ = pL.get<bool>("aggregation: brick x Dirichlet");
129 dirichletY_ = pL.get<bool>("aggregation: brick y Dirichlet");
130 dirichletZ_ = pL.get<bool>("aggregation: brick z Dirichlet");
131 if (dirichletX_) GetOStream(Runtime0) << "Dirichlet boundaries in the x direction" << std::endl;
132 if (dirichletY_) GetOStream(Runtime0) << "Dirichlet boundaries in the y direction" << std::endl;
133 if (dirichletZ_) GetOStream(Runtime0) << "Dirichlet boundaries in the z direction" << std::endl;
134
135 if (numProcs > 1) {
136 // TODO: deal with block size > 1 (see comments above)
137 // TEUCHOS_TEST_FOR_EXCEPTION(bx_ > 3 || by_ > 3 || bz_ > 3, Exceptions::RuntimeError, "Currently cannot deal with brick size > 3");
138 }
139
140 RCP<MultiVector_d> overlappedCoords = coords;
141 RCP<const Import> importer = ImportFactory::Build(coords->getMap(), colMap);
142 if (!importer.is_null()) {
143 overlappedCoords = Xpetra::MultiVectorFactory<typename Teuchos::ScalarTraits<Scalar>::magnitudeType, LO, GO, NO>::Build(colMap, coords->getNumVectors());
144 overlappedCoords->doImport(*coords, *importer, Xpetra::INSERT);
145 }
146
147 // Setup misc structures
148 // Logically, we construct enough data to query topological information of a rectangular grid
149 Setup(comm, overlappedCoords, colMap);
150
151 GetOStream(Runtime0) << "Using brick size: " << bx_
152 << (nDim_ > 1 ? "x " + toString(by_) : "")
153 << (nDim_ > 2 ? "x " + toString(bz_) : "") << std::endl;
154
155 // Build the graph
156 BuildGraph(currentLevel, A);
157
158 // Construct aggregates
159 RCP<Aggregates> aggregates = rcp(new Aggregates(colMap));
160 aggregates->setObjectLabel("Brick");
161
162 ArrayRCP<LO> vertex2AggId = aggregates->GetVertex2AggId()->getDataNonConst(0);
163 ArrayRCP<LO> procWinner = aggregates->GetProcWinner()->getDataNonConst(0);
164
165 // In the first pass, we set a mapping from a vertex to aggregate global id. We deal with a structured
166 // rectangular mesh, therefore we know the structure of aggregates. For each vertex we can tell exactly
167 // which aggregate it belongs to.
168 // If we determine that the aggregate does not belong to us (i.e. the root vertex does not belong to this
169 // processor, or is outside and we lost "" arbitration), we record the global aggregate id in order to
170 // fetch the local info from the processor owning the aggregate. This is required for aggregates, as it
171 // uses the local aggregate ids of the owning processor.
172 std::set<GO> myAggGIDs, remoteAggGIDs;
173 for (LO LID = 0; LID < numPoints; LID++) {
174 GO aggGID = getAggGID(LID);
175 // printf("[%d] (%d,%d,%d) => agg %d\n",LID,(int)(*xMap_)[x_[LID]],nDim_ > 1 ? (int)(*yMap_)[y_[LID]] : -1,nDim_ > 2 ? (int)(*zMap_)[z_[LID]] : -1,(int)aggGID);
176 if (aggGID == GO_INVALID) continue;
177 // printf("[%d] getRoot = %d\n",(int)LID,(int)getRoot(LID));
178
179 if ((revMap_.find(getRoot(LID)) != revMap_.end()) && rowMap->isNodeGlobalElement(colMap->getGlobalElement(revMap_[getRoot(LID)]))) {
180 // Root of the brick aggregate containing GID (<- LID) belongs to us
181 vertex2AggId[LID] = aggGID;
182 myAggGIDs.insert(aggGID);
183
184 if (isRoot(LID))
185 aggregates->SetIsRoot(LID);
186 // printf("[%d] initial vertex2AggId = %d\n",(int)LID,(int)vertex2AggId[LID]);
187 } else {
188 remoteAggGIDs.insert(aggGID);
189 }
190 }
191 size_t numAggregates = myAggGIDs.size();
192 size_t numRemote = remoteAggGIDs.size();
193 aggregates->SetNumAggregates(numAggregates);
194
195 std::map<GO, LO> AggG2L; // Map: Agg GID -> Agg LID (possibly on a different processor)
196 std::map<GO, int> AggG2R; // Map: Agg GID -> processor rank owning aggregate
197
198 Array<GO> myAggGIDsArray(numAggregates), remoteAggGIDsArray(numRemote);
199
200 // Fill in the maps for aggregates that we own
201 size_t ind = 0;
202 for (typename std::set<GO>::const_iterator it = myAggGIDs.begin(); it != myAggGIDs.end(); it++) {
203 AggG2L[*it] = ind;
204 AggG2R[*it] = myRank;
205
206 myAggGIDsArray[ind++] = *it;
207 }
208
209 // The map is a convenient way to fetch remote local indices from global indices.
210 RCP<Map> aggMap = MapFactory::Build(rowMap->lib(), Teuchos::OrdinalTraits<Xpetra::global_size_t>::invalid(),
211 myAggGIDsArray, 0, comm);
212
213 ind = 0;
214 for (typename std::set<GO>::const_iterator it = remoteAggGIDs.begin(); it != remoteAggGIDs.end(); it++)
215 remoteAggGIDsArray[ind++] = *it;
216
217 // Fetch the required aggregate local ids and ranks
218 Array<int> remoteProcIDs(numRemote);
219 Array<LO> remoteLIDs(numRemote);
220 aggMap->getRemoteIndexList(remoteAggGIDsArray, remoteProcIDs, remoteLIDs);
221
222 // Fill in the maps for aggregates that we don't own but which have some of our vertices
223 for (size_t i = 0; i < numRemote; i++) {
224 AggG2L[remoteAggGIDsArray[i]] = remoteLIDs[i];
225 AggG2R[remoteAggGIDsArray[i]] = remoteProcIDs[i];
226 }
227
228 // Remap aggregate GIDs to LIDs and set up owning processors
229 for (LO LID = 0; LID < numPoints; LID++) {
230 if (revMap_.find(getRoot(LID)) != revMap_.end() && rowMap->isNodeGlobalElement(colMap->getGlobalElement(revMap_[getRoot(LID)]))) {
231 GO aggGID = vertex2AggId[LID];
232 if (aggGID != MUELU_UNAGGREGATED) {
233 vertex2AggId[LID] = AggG2L[aggGID];
234 procWinner[LID] = AggG2R[aggGID];
235 }
236 }
237 }
238
239 GO numGlobalRemote;
240 MueLu_sumAll(comm, as<GO>(numRemote), numGlobalRemote);
241 aggregates->AggregatesCrossProcessors(numGlobalRemote);
242
243 Set(currentLevel, "Aggregates", aggregates);
244
245 GetOStream(Statistics1) << aggregates->description() << std::endl;
246}
247
248template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
250 Setup(const RCP<const Teuchos::Comm<int> >& comm, const RCP<Xpetra::MultiVector<typename Teuchos::ScalarTraits<Scalar>::magnitudeType, LO, GO, NO> >& coords, const RCP<const Map>& /* map */) const {
251 nDim_ = coords->getNumVectors();
252
253 x_ = coords->getData(0);
254 xMap_ = Construct1DMap(comm, x_);
255 nx_ = xMap_->size();
256
257 ny_ = 1;
258 if (nDim_ > 1) {
259 y_ = coords->getData(1);
260 yMap_ = Construct1DMap(comm, y_);
261 ny_ = yMap_->size();
262 }
263
264 nz_ = 1;
265 if (nDim_ > 2) {
266 z_ = coords->getData(2);
267 zMap_ = Construct1DMap(comm, z_);
268 nz_ = zMap_->size();
269 }
270
271 for (size_t ind = 0; ind < coords->getLocalLength(); ind++) {
272 GO i = (*xMap_)[(coords->getData(0))[ind]], j = 0, k = 0;
273 if (nDim_ > 1)
274 j = (*yMap_)[(coords->getData(1))[ind]];
275 if (nDim_ > 2)
276 k = (*zMap_)[(coords->getData(2))[ind]];
277
278 revMap_[k * ny_ * nx_ + j * nx_ + i] = ind;
279 }
280
281 // Get the number of aggregates in each direction, correcting for Dirichlet
282 int xboost = dirichletX_ ? 1 : 0;
283 int yboost = dirichletY_ ? 1 : 0;
284 int zboost = dirichletZ_ ? 1 : 0;
285 naggx_ = (nx_ - 2 * xboost) / bx_ + ((nx_ - 2 * xboost) % bx_ ? 1 : 0);
286
287 if (nDim_ > 1)
288 naggy_ = (ny_ - 2 * yboost) / by_ + ((ny_ - 2 * yboost) % by_ ? 1 : 0);
289 else
290 naggy_ = 1;
291
292 if (nDim_ > 2)
293 naggz_ = (nz_ - 2 * zboost) / bz_ + ((nz_ - 2 * zboost) % bz_ ? 1 : 0);
294 else
295 naggz_ = 1;
296}
297
298template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
299RCP<typename BrickAggregationFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::container>
301 Construct1DMap(const RCP<const Teuchos::Comm<int> >& comm,
302 const ArrayRCP<const typename Teuchos::ScalarTraits<Scalar>::magnitudeType>& x) const {
303 int n = x.size();
304
305 // Step 1: Create a local vector with unique coordinate points
306 RCP<container> gMap = rcp(new container);
307 for (int i = 0; i < n; i++)
308 (*gMap)[x[i]] = 0;
309
310#ifdef HAVE_MPI
311 // Step 2: exchange coordinates
312 // NOTE: we assume the coordinates are double, or double compatible
313 // That means that for complex case, we assume that all imaginary parts are zeros
314 int numProcs = comm->getSize();
315 if (numProcs > 1) {
316 RCP<const Teuchos::MpiComm<int> > dupMpiComm = rcp_dynamic_cast<const Teuchos::MpiComm<int> >(comm->duplicate());
317
318 MPI_Comm rawComm = (*dupMpiComm->getRawMpiComm())();
319
320 int sendCnt = gMap->size(), cnt = 0, recvSize;
321 Array<int> recvCnt(numProcs), Displs(numProcs);
322 Array<double> sendBuf, recvBuf;
323
324 sendBuf.resize(sendCnt);
325 for (typename container::const_iterator cit = gMap->begin(); cit != gMap->end(); cit++)
326 sendBuf[cnt++] = Teuchos::as<double>(STS::real(cit->first));
327
328 MPI_Allgather(&sendCnt, 1, MPI_INT, recvCnt.getRawPtr(), 1, MPI_INT, rawComm);
329 Displs[0] = 0;
330 for (int i = 0; i < numProcs - 1; i++)
331 Displs[i + 1] = Displs[i] + recvCnt[i];
332 recvSize = Displs[numProcs - 1] + recvCnt[numProcs - 1];
333 recvBuf.resize(recvSize);
334 MPI_Allgatherv(sendBuf.getRawPtr(), sendCnt, MPI_DOUBLE, recvBuf.getRawPtr(), recvCnt.getRawPtr(), Displs.getRawPtr(), MPI_DOUBLE, rawComm);
335
336 for (int i = 0; i < recvSize; i++)
337 (*gMap)[as<SC>(recvBuf[i])] = 0;
338 }
339#endif
340
341 GO cnt = 0;
342 for (typename container::iterator it = gMap->begin(); it != gMap->end(); it++)
343 it->second = cnt++;
344
345 return gMap;
346}
347
348template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
350 int i, j, k;
351 getIJK(LID, i, j, k);
352
353 return (k * ny_ * nx_ + j * nx_ + i) == getRoot(LID);
354}
355
356template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
358 bool boundary = false;
359 int i, j, k;
360 getIJK(LID, i, j, k);
361 if (dirichletX_ && (i == 0 || i == nx_ - 1))
362 boundary = true;
363 if (nDim_ > 1 && dirichletY_ && (j == 0 || j == ny_ - 1))
364 boundary = true;
365 if (nDim_ > 2 && dirichletZ_ && (k == 0 || k == nz_ - 1))
366 boundary = true;
367
368 return boundary;
369}
370
371template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
373 if (isDirichlet(LID))
374 return Teuchos::OrdinalTraits<GlobalOrdinal>::invalid();
375
376 int aggI, aggJ, aggK;
377 getAggIJK(LID, aggI, aggJ, aggK);
378 int xboost = dirichletX_ ? 1 : 0;
379 int yboost = dirichletY_ ? 1 : 0;
380 int zboost = dirichletZ_ ? 1 : 0;
381
382 int i = xboost + aggI * bx_ + (bx_ - 1) / 2;
383 int j = (nDim_ > 1) ? yboost + aggJ * by_ + (by_ - 1) / 2 : 0;
384 int k = (nDim_ > 2) ? zboost + aggK * bz_ + (bz_ - 1) / 2 : 0;
385
386 return k * ny_ * nx_ + j * nx_ + i;
387}
388
389template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
391 i = (*xMap_)[x_[LID]];
392 j = (nDim_ > 1) ? (*yMap_)[y_[LID]] : 0;
393 k = (nDim_ > 2) ? (*zMap_)[z_[LID]] : 0;
394}
395
396template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
398 int xboost = dirichletX_ ? 1 : 0;
399 int yboost = dirichletY_ ? 1 : 0;
400 int zboost = dirichletZ_ ? 1 : 0;
401 int pointI, pointJ, pointK;
402 getIJK(LID, pointI, pointJ, pointK);
403 i = (pointI - xboost) / bx_;
404
405 if (nDim_ > 1)
406 j = (pointJ - yboost) / by_;
407 else
408 j = 0;
409
410 if (nDim_ > 2)
411 k = (pointK - zboost) / bz_;
412 else
413 k = 0;
414}
415
416template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
418 bool boundary = false;
419
420 int i, j, k;
421 getIJK(LID, i, j, k);
422 int ii, jj, kk;
423 getAggIJK(LID, ii, jj, kk);
424
425 if (dirichletX_ && (i == 0 || i == nx_ - 1)) boundary = true;
426 if (nDim_ > 1 && dirichletY_ && (j == 0 || j == ny_ - 1)) boundary = true;
427 if (nDim_ > 2 && dirichletZ_ && (k == 0 || k == nz_ - 1)) boundary = true;
428
429 /*
430 if(boundary)
431 printf("[%d] coord = (%d,%d,%d) {%d,%d,%d} agg = (%d,%d,%d) {%d,%d,%d} => agg %s\n",LID,i,j,k,nx_,ny_,nz_,ii,jj,kk,naggx_,naggy_,naggz_,"BOUNDARY");
432 else
433 printf("[%d] coord = (%d,%d,%d) {%d,%d,%d} agg = (%d,%d,%d) {%d,%d,%d} => agg %d\n",LID,i,j,k,nx_,ny_,nz_,ii,jj,kk,naggx_,naggy_,naggz_,kk*naggy_*naggx_ + jj*naggx_ + ii);
434 */
435
436 if (boundary)
437 return Teuchos::OrdinalTraits<GlobalOrdinal>::invalid();
438 else
439 return Teuchos::as<GlobalOrdinal>(kk * naggy_ * naggx_) + Teuchos::as<GlobalOrdinal>(jj * naggx_) + ii;
440}
441
442template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
444 // TODO: Currently only works w/ 1 DOF per node
445 double dirichletThreshold = 0.0;
446
447 if (bx_ > 1 && (nDim_ <= 1 || by_ > 1) && (nDim_ <= 2 || bz_ > 1)) {
448 FactoryMonitor m(*this, "Generating Graph (trivial)", currentLevel);
449 /*** Case 1: Use the matrix is the graph ***/
450 // Bricks are of non-trivial size in all active dimensions
451 RCP<LWGraph> graph = rcp(new LWGraph(A->getCrsGraph(), "graph of A"));
452 auto boundaryNodes = MueLu::Utilities<SC, LO, GO, NO>::DetectDirichletRows_kokkos_host(*A, dirichletThreshold);
453 graph->SetBoundaryNodeMap(boundaryNodes);
454
455 if (GetVerbLevel() & Statistics1) {
456 GO numLocalBoundaryNodes = 0;
457 GO numGlobalBoundaryNodes = 0;
458 for (size_t i = 0; i < boundaryNodes.size(); ++i)
459 if (boundaryNodes(i))
460 numLocalBoundaryNodes++;
461 RCP<const Teuchos::Comm<int> > comm = A->getRowMap()->getComm();
462 MueLu_sumAll(comm, numLocalBoundaryNodes, numGlobalBoundaryNodes);
463 GetOStream(Statistics1) << "Detected " << numGlobalBoundaryNodes << " Dirichlet nodes" << std::endl;
464 }
465 Set(currentLevel, "DofsPerNode", 1);
466 Set(currentLevel, "Graph", graph);
467 Set(currentLevel, "Filtering", false);
468 } else {
469 FactoryMonitor m(*this, "Generating Graph", currentLevel);
470 /*** Case 2: Dropping required ***/
471 // There is at least one active dimension in which we are not coarsening.
472 // Those connections need to be dropped
473 bool drop_x = (bx_ == 1);
474 bool drop_y = (nDim_ > 1 && by_ == 1);
475 bool drop_z = (nDim_ > 2 && bz_ == 1);
476
477 typename LWGraph::row_type::non_const_type rows("rows", A->getLocalNumRows() + 1);
478 typename LWGraph::entries_type::non_const_type columns("columns", A->getLocalNumEntries());
479
480 size_t N = A->getRowMap()->getLocalNumElements();
481
482 // FIXME: Do this on the host because indexing functions are host functions
483 auto G = A->getLocalMatrixHost().graph;
484 auto rowptr = G.row_map;
485 auto colind = G.entries;
486
487 int ct = 0;
488 rows(0) = 0;
489 for (size_t row = 0; row < N; row++) {
490 // NOTE: Assumes that the first part of the colmap is the rowmap
491 int ir, jr, kr;
492 LO row2 = A->getColMap()->getLocalElement(A->getRowMap()->getGlobalElement(row));
493 getIJK(row2, ir, jr, kr);
494
495 for (size_t cidx = rowptr[row]; cidx < rowptr[row + 1]; cidx++) {
496 int ic, jc, kc;
497 LO col = colind[cidx];
498 getIJK(col, ic, jc, kc);
499
500 if ((row2 != col) && ((drop_x && ir != ic) || (drop_y && jr != jc) || (drop_z && kr != kc))) {
501 // Drop it
502 // printf("[%4d] DROP row = (%d,%d,%d) col = (%d,%d,%d)\n",(int)row,ir,jr,kr,ic,jc,kc);
503 } else {
504 // Keep it
505 // printf("[%4d] KEEP row = (%d,%d,%d) col = (%d,%d,%d)\n",(int)row,ir,jr,kr,ic,jc,kc);
506 columns(ct) = col;
507 ct++;
508 }
509 }
510 rows(row + 1) = ct;
511 } // end for
512
513 RCP<LWGraph> graph = rcp(new LWGraph(rows, columns, A->getRowMap(), A->getColMap(), "thresholded graph of A"));
514
515 auto boundaryNodes = MueLu::Utilities<SC, LO, GO, NO>::DetectDirichletRows_kokkos_host(*A, dirichletThreshold);
516 graph->SetBoundaryNodeMap(boundaryNodes);
517
518 if (GetVerbLevel() & Statistics1) {
519 GO numLocalBoundaryNodes = 0;
520 GO numGlobalBoundaryNodes = 0;
521 for (size_t i = 0; i < boundaryNodes.size(); ++i)
522 if (boundaryNodes(i))
523 numLocalBoundaryNodes++;
524 RCP<const Teuchos::Comm<int> > comm = A->getRowMap()->getComm();
525 MueLu_sumAll(comm, numLocalBoundaryNodes, numGlobalBoundaryNodes);
526 GetOStream(Statistics1) << "Detected " << numGlobalBoundaryNodes << " Dirichlet nodes" << std::endl;
527 }
528 Set(currentLevel, "DofsPerNode", 1);
529 Set(currentLevel, "Graph", graph);
530 Set(currentLevel, "Filtering", true);
531 } // end else
532
533} // end BuildGraph
534
535} // namespace MueLu
536
537#endif /* MUELU_BRICKAGGREGATIONFACTORY_DEF_HPP_ */
#define MUELU_UNAGGREGATED
#define SET_VALID_ENTRY(name)
#define MueLu_sumAll(rcpComm, in, out)
MueLu::DefaultLocalOrdinal LocalOrdinal
MueLu::DefaultGlobalOrdinal GlobalOrdinal
Container class for aggregation information.
void Setup(const RCP< const Teuchos::Comm< int > > &comm, const RCP< Xpetra::MultiVector< typename Teuchos::ScalarTraits< Scalar >::magnitudeType, LO, GO, NO > > &coords, const RCP< const Map > &map) const
std::map< Scalar, GlobalOrdinal, compare > container
GlobalOrdinal getRoot(LocalOrdinal LID) const
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
GlobalOrdinal getAggGID(LocalOrdinal LID) const
void DeclareInput(Level &currentLevel) const
Input.
void Build(Level &currentLevel) const
Build aggregates.
void BuildGraph(Level &currentLevel, const RCP< Matrix > &A) const
void getAggIJK(LocalOrdinal LID, int &i, int &j, int &k) const
RCP< container > Construct1DMap(const RCP< const Teuchos::Comm< int > > &comm, const ArrayRCP< const typename Teuchos::ScalarTraits< Scalar >::magnitudeType > &x) const
void getIJK(LocalOrdinal LID, int &i, int &j, int &k) const
Timer to be used in factories. Similar to Monitor but with additional timers.
Lightweight MueLu representation of a compressed row storage graph.
Class that holds all level-specific information.
static Kokkos::View< bool *, typename Kokkos::HostSpace > DetectDirichletRows_kokkos_host(const Matrix &A, const Magnitude &tol=Teuchos::ScalarTraits< typename Teuchos::ScalarTraits< SC >::magnitudeType >::zero(), const bool count_twos_as_dirichlet=false)
Namespace for MueLu classes and methods.
@ Statistics1
Print more statistics.
@ Runtime0
One-liner description of what is happening.
std::string toString(const T &what)
Little helper function to convert non-string types to strings.