MueLu Version of the Day
Loading...
Searching...
No Matches
MueLu_VariableDofLaplacianFactory_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 PACKAGES_MUELU_SRC_GRAPH_MUELU_VARIABLEDOFLAPLACIANFACTORY_DEF_HPP_
11#define PACKAGES_MUELU_SRC_GRAPH_MUELU_VARIABLEDOFLAPLACIANFACTORY_DEF_HPP_
12
13#include "MueLu_Monitor.hpp"
14
16
17namespace MueLu {
18
19template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
21 RCP<ParameterList> validParamList = rcp(new ParameterList());
22
23 validParamList->set<double>("Advanced Dirichlet: threshold", 1e-5, "Drop tolerance for Dirichlet detection");
24 validParamList->set<double>("Variable DOF amalgamation: threshold", 1.8e-9, "Drop tolerance for amalgamation process");
25 validParamList->set<int>("maxDofPerNode", 1, "Maximum number of DOFs per node");
26
27 validParamList->set<RCP<const FactoryBase> >("A", Teuchos::null, "Generating factory of the matrix A");
28 validParamList->set<RCP<const FactoryBase> >("Coordinates", Teuchos::null, "Generating factory for Coordinates");
29
30 return validParamList;
31}
32
33template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
35
36template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
38 Input(currentLevel, "A");
39 Input(currentLevel, "Coordinates");
40
41 // if (currentLevel.GetLevelID() == 0) // TODO check for finest level (special treatment)
42 if (currentLevel.IsAvailable("DofPresent", NoFactory::get())) {
43 currentLevel.DeclareInput("DofPresent", NoFactory::get(), this);
44 }
45}
46
47template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
49 FactoryMonitor m(*this, "Build", currentLevel);
50 typedef Teuchos::ScalarTraits<SC> STS;
51
52 const ParameterList& pL = GetParameterList();
53
54 RCP<Matrix> A = Get<RCP<Matrix> >(currentLevel, "A");
55
56 Teuchos::RCP<const Teuchos::Comm<int> > comm = A->getRowMap()->getComm();
57 Xpetra::UnderlyingLib lib = A->getRowMap()->lib();
58
59 typedef Xpetra::MultiVector<typename Teuchos::ScalarTraits<Scalar>::magnitudeType, LO, GO, NO> dxMV;
60 RCP<dxMV> Coords = Get<RCP<Xpetra::MultiVector<typename Teuchos::ScalarTraits<Scalar>::magnitudeType, LO, GO, NO> > >(currentLevel, "Coordinates");
61
62 int maxDofPerNode = pL.get<int>("maxDofPerNode");
63 Scalar dirDropTol = Teuchos::as<Scalar>(pL.get<double>("Advanced Dirichlet: threshold")); // "ML advnaced Dirichlet: threshold"
64 Scalar amalgDropTol = Teuchos::as<Scalar>(pL.get<double>("Variable DOF amalgamation: threshold")); //"variable DOF amalgamation: threshold")
65
66 bool bHasZeroDiagonal = false;
67 Teuchos::ArrayRCP<const bool> dirOrNot = MueLu::Utilities<Scalar, LocalOrdinal, GlobalOrdinal, Node>::DetectDirichletRowsExt(*A, bHasZeroDiagonal, STS::magnitude(dirDropTol));
68
69 // check availability of DofPresent array
70 Teuchos::ArrayRCP<LocalOrdinal> dofPresent;
71 if (currentLevel.IsAvailable("DofPresent", NoFactory::get())) {
72 dofPresent = currentLevel.Get<Teuchos::ArrayRCP<LocalOrdinal> >("DofPresent", NoFactory::get());
73 } else {
74 // TAW: not sure about size of array. We cannot determine the expected size in the non-padded case correctly...
75 dofPresent = Teuchos::ArrayRCP<LocalOrdinal>(A->getRowMap()->getLocalNumElements(), 1);
76 }
77
78 // map[k] indicates that the kth dof in the variable dof matrix A would
79 // correspond to the map[k]th dof in the padded system. If, i.e., it is
80 // map[35] = 39 then dof no 35 in the variable dof matrix A corresponds to
81 // row map id 39 in an imaginary padded matrix Apadded.
82 // The padded system is never built but would be the associated matrix if
83 // every node had maxDofPerNode dofs.
84 std::vector<LocalOrdinal> map(A->getLocalNumRows());
85 this->buildPaddedMap(dofPresent, map, A->getLocalNumRows());
86
87 // map of size of number of DOFs containing local node id (dof id -> node id, inclusive ghosted dofs/nodes)
88 std::vector<LocalOrdinal> myLocalNodeIds(A->getColMap()->getLocalNumElements()); // possible maximum (we need the ghost nodes, too)
89
90 // assign the local node ids for the ghosted nodes
91 size_t nLocalNodes, nLocalPlusGhostNodes;
92 this->assignGhostLocalNodeIds(A->getRowMap(), A->getColMap(), myLocalNodeIds, map, maxDofPerNode, nLocalNodes, nLocalPlusGhostNodes, comm);
93
94 // RCP<Teuchos::FancyOStream> fancy = Teuchos::fancyOStream(Teuchos::rcpFromRef(std::cout)," ",0,false,10,false, true);
95
96 TEUCHOS_TEST_FOR_EXCEPTION(Teuchos::as<size_t>(dofPresent.size()) != Teuchos::as<size_t>(nLocalNodes * maxDofPerNode), MueLu::Exceptions::RuntimeError, "VariableDofLaplacianFactory: size of provided DofPresent array is " << dofPresent.size() << " but should be " << nLocalNodes * maxDofPerNode << " on the current processor.");
97
98 // put content of assignGhostLocalNodeIds here...
99
100 // fill nodal maps
101
102 Teuchos::ArrayView<const GlobalOrdinal> myGids = A->getColMap()->getLocalElementList();
103
104 // vector containing row/col gids of amalgamated matrix (with holes)
105
106 size_t nLocalDofs = A->getRowMap()->getLocalNumElements();
107 size_t nLocalPlusGhostDofs = A->getColMap()->getLocalNumElements();
108
109 // myLocalNodeIds (dof -> node)
110
111 Teuchos::Array<GlobalOrdinal> amalgRowMapGIDs(nLocalNodes);
112 Teuchos::Array<GlobalOrdinal> amalgColMapGIDs(nLocalPlusGhostNodes);
113
114 // initialize
115 size_t count = 0;
116 if (nLocalDofs > 0) {
117 amalgRowMapGIDs[count] = myGids[0];
118 amalgColMapGIDs[count] = myGids[0];
119 count++;
120 }
121
122 for (size_t i = 1; i < nLocalDofs; i++) {
123 if (myLocalNodeIds[i] != myLocalNodeIds[i - 1]) {
124 amalgRowMapGIDs[count] = myGids[i];
125 amalgColMapGIDs[count] = myGids[i];
126 count++;
127 }
128 }
129
130 RCP<GOVector> tempAmalgColVec = GOVectorFactory::Build(A->getDomainMap());
131 {
132 Teuchos::ArrayRCP<GlobalOrdinal> tempAmalgColVecData = tempAmalgColVec->getDataNonConst(0);
133 for (size_t i = 0; i < A->getDomainMap()->getLocalNumElements(); i++)
134 tempAmalgColVecData[i] = amalgColMapGIDs[myLocalNodeIds[i]];
135 }
136
137 RCP<GOVector> tempAmalgColVecTarget = GOVectorFactory::Build(A->getColMap());
138 Teuchos::RCP<Import> dofImporter = ImportFactory::Build(A->getDomainMap(), A->getColMap());
139 tempAmalgColVecTarget->doImport(*tempAmalgColVec, *dofImporter, Xpetra::INSERT);
140
141 {
142 Teuchos::ArrayRCP<const GlobalOrdinal> tempAmalgColVecBData = tempAmalgColVecTarget->getData(0);
143 // copy from dof vector to nodal vector
144 for (size_t i = 0; i < myLocalNodeIds.size(); i++)
145 amalgColMapGIDs[myLocalNodeIds[i]] = tempAmalgColVecBData[i];
146 }
147
148 Teuchos::RCP<Map> amalgRowMap = MapFactory::Build(lib,
149 Teuchos::OrdinalTraits<GlobalOrdinal>::invalid(),
150 amalgRowMapGIDs(), // View,
151 A->getRowMap()->getIndexBase(),
152 comm);
153
154 Teuchos::RCP<Map> amalgColMap = MapFactory::Build(lib,
155 Teuchos::OrdinalTraits<GlobalOrdinal>::invalid(),
156 amalgColMapGIDs(), // View,
157 A->getRangeMap()->getIndexBase(),
158 comm);
159
160 // end fill nodal maps
161
162 // start variable dof amalgamation
163
164 Teuchos::RCP<CrsMatrix> Acrs = toCrsMatrix(A);
165 // Acrs->describe(*fancy, Teuchos::VERB_EXTREME);
166
167 size_t nNonZeros = 0;
168 std::vector<bool> isNonZero(nLocalPlusGhostDofs, false);
169 std::vector<size_t> nonZeroList(nLocalPlusGhostDofs); // ???
170
171 // also used in DetectDirichletExt
172 Teuchos::RCP<Vector> diagVecUnique = VectorFactory::Build(A->getRowMap());
173 Teuchos::RCP<Vector> diagVec = VectorFactory::Build(A->getColMap());
174 A->getLocalDiagCopy(*diagVecUnique);
175 diagVec->doImport(*diagVecUnique, *dofImporter, Xpetra::INSERT);
176 Teuchos::ArrayRCP<const Scalar> diagVecData = diagVec->getData(0);
177
178 Teuchos::ArrayRCP<const size_t> rowptr(Acrs->getLocalNumRows());
179 Teuchos::ArrayRCP<const LocalOrdinal> colind(Acrs->getLocalNumEntries());
180 Teuchos::ArrayRCP<const Scalar> values(Acrs->getLocalNumEntries());
181 Acrs->getAllValues(rowptr, colind, values);
182
183 // create arrays for amalgamated matrix
184 Teuchos::ArrayRCP<size_t> amalgRowPtr(nLocalNodes + 1);
185 Teuchos::ArrayRCP<LocalOrdinal> amalgCols(rowptr[rowptr.size() - 1]);
186
187 LocalOrdinal oldBlockRow = 0;
188 LocalOrdinal blockRow = 0;
189 LocalOrdinal blockColumn = 0;
190
191 size_t newNzs = 0;
192 amalgRowPtr[0] = newNzs;
193
194 bool doNotDrop = false;
195 if (amalgDropTol == Teuchos::ScalarTraits<Scalar>::zero()) doNotDrop = true;
196 if (values.size() == 0) doNotDrop = true;
197
198 for (decltype(rowptr.size()) i = 0; i < rowptr.size() - 1; i++) {
199 blockRow = std::floor<LocalOrdinal>(map[i] / maxDofPerNode);
200 if (blockRow != oldBlockRow) {
201 // zero out info recording nonzeros in oldBlockRow
202 for (size_t j = 0; j < nNonZeros; j++) isNonZero[nonZeroList[j]] = false;
203 nNonZeros = 0;
204 amalgRowPtr[blockRow] = newNzs; // record start of next row
205 }
206 for (size_t j = rowptr[i]; j < rowptr[i + 1]; j++) {
207 if (doNotDrop == true ||
208 (STS::magnitude(values[j] / STS::magnitude(sqrt(STS::magnitude(diagVecData[i]) * STS::magnitude(diagVecData[colind[j]])))) >= STS::magnitude(amalgDropTol))) {
209 blockColumn = myLocalNodeIds[colind[j]];
210 if (isNonZero[blockColumn] == false) {
211 isNonZero[blockColumn] = true;
212 nonZeroList[nNonZeros++] = blockColumn;
213 amalgCols[newNzs++] = blockColumn;
214 }
215 }
216 }
217 oldBlockRow = blockRow;
218 }
219 amalgRowPtr[blockRow + 1] = newNzs;
220
221 TEUCHOS_TEST_FOR_EXCEPTION((blockRow + 1 != Teuchos::as<LO>(nLocalNodes)) && (nLocalNodes != 0), MueLu::Exceptions::RuntimeError, "VariableDofsPerNodeAmalgamation: error, computed # block rows (" << blockRow + 1 << ") != nLocalNodes (" << nLocalNodes << ")");
222
223 amalgCols.resize(amalgRowPtr[nLocalNodes]);
224
225 // end variableDofAmalg
226
227 // begin rm differentDofsCrossings
228
229 // Remove matrix entries (i,j) where the ith node and the jth node have
230 // different dofs that are 'present'
231 // Specifically, on input:
232 // dofPresent[i*maxDofPerNode+k] indicates whether or not the kth
233 // dof at the ith node is present in the
234 // variable dof matrix (e.g., the ith node
235 // has an air pressure dof). true means
236 // the dof is present while false means it
237 // is not.
238 // We create a unique id for the ith node (i.e. uniqueId[i]) via
239 // sum_{k=0 to maxDofPerNode-1} dofPresent[i*maxDofPerNode+k]*2^k
240 // and use this unique idea to remove entries (i,j) when uniqueId[i]!=uniqueId[j]
241
242 Teuchos::ArrayRCP<LocalOrdinal> uniqueId(nLocalPlusGhostNodes); // unique id associated with DOF
243 std::vector<bool> keep(amalgRowPtr[amalgRowPtr.size() - 1], true); // keep connection associated with node
244
245 size_t ii = 0; // iteration index for present dofs
246 for (decltype(amalgRowPtr.size()) i = 0; i < amalgRowPtr.size() - 1; i++) {
247 LocalOrdinal temp = 1; // basis for dof-id
248 uniqueId[i] = 0;
249 for (decltype(maxDofPerNode) j = 0; j < maxDofPerNode; j++) {
250 if (dofPresent[ii++]) uniqueId[i] += temp; // encode dof to be present
251 temp = temp * 2; // check next dof
252 }
253 }
254
255 Teuchos::RCP<Import> nodeImporter = ImportFactory::Build(amalgRowMap, amalgColMap);
256
257 RCP<LOVector> nodeIdSrc = Xpetra::VectorFactory<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>::Build(amalgRowMap, true);
258 RCP<LOVector> nodeIdTarget = Xpetra::VectorFactory<LocalOrdinal, LocalOrdinal, GlobalOrdinal, Node>::Build(amalgColMap, true);
259
260 Teuchos::ArrayRCP<LocalOrdinal> nodeIdSrcData = nodeIdSrc->getDataNonConst(0);
261 for (decltype(amalgRowPtr.size()) i = 0; i < amalgRowPtr.size() - 1; i++) {
262 nodeIdSrcData[i] = uniqueId[i];
263 }
264
265 nodeIdTarget->doImport(*nodeIdSrc, *nodeImporter, Xpetra::INSERT);
266
267 Teuchos::ArrayRCP<const LocalOrdinal> nodeIdTargetData = nodeIdTarget->getData(0);
268 for (decltype(uniqueId.size()) i = 0; i < uniqueId.size(); i++) {
269 uniqueId[i] = nodeIdTargetData[i];
270 }
271
272 // nodal comm uniqueId, myLocalNodeIds
273
274 // uniqueId now should contain ghosted data
275
276 for (decltype(amalgRowPtr.size()) i = 0; i < amalgRowPtr.size() - 1; i++) {
277 for (size_t j = amalgRowPtr[i]; j < amalgRowPtr[i + 1]; j++) {
278 if (uniqueId[i] != uniqueId[amalgCols[j]]) keep[j] = false;
279 }
280 }
281
282 // squeeze out hard-coded zeros from CSR arrays
283 Teuchos::ArrayRCP<Scalar> amalgVals;
284 this->squeezeOutNnzs(amalgRowPtr, amalgCols, amalgVals, keep);
285
286 typedef Xpetra::MultiVectorFactory<typename Teuchos::ScalarTraits<Scalar>::magnitudeType, LO, GO, NO> dxMVf;
287 RCP<dxMV> ghostedCoords = dxMVf::Build(amalgColMap, Coords->getNumVectors());
288
289 TEUCHOS_TEST_FOR_EXCEPTION(amalgRowMap->getLocalNumElements() != Coords->getMap()->getLocalNumElements(), MueLu::Exceptions::RuntimeError, "MueLu::VariableDofLaplacianFactory: the number of Coordinates and amalgamated nodes is inconsistent.");
290
291 // Coords might live on a special nodeMap with consecutive ids (the natural numbering)
292 // The amalgRowMap might have the same number of entries, but with holes in the ids.
293 // e.g. 0,3,6,9,... as GIDs.
294 // We need the ghosted Coordinates in the buildLaplacian routine. But we access the data
295 // through getData only, i.e., the global ids are not interesting as long as we do not change
296 // the ordering of the entries
297 Coords->replaceMap(amalgRowMap);
298 ghostedCoords->doImport(*Coords, *nodeImporter, Xpetra::INSERT);
299
300 Teuchos::ArrayRCP<Scalar> lapVals(amalgRowPtr[nLocalNodes]);
301 this->buildLaplacian(amalgRowPtr, amalgCols, lapVals, Coords->getNumVectors(), ghostedCoords);
302
303 // sort column GIDs
304 for (decltype(amalgRowPtr.size()) i = 0; i < amalgRowPtr.size() - 1; i++) {
305 size_t j = amalgRowPtr[i];
306 this->MueLu_az_sort<LocalOrdinal>(&(amalgCols[j]), amalgRowPtr[i + 1] - j, NULL, &(lapVals[j]));
307 }
308
309 // Caluclate status array for next level
310 Teuchos::Array<char> status(nLocalNodes * maxDofPerNode);
311
312 // dir or not Teuchos::ArrayRCP<const bool> dirOrNot
313 for (decltype(status.size()) i = 0; i < status.size(); i++) status[i] = 's';
314 for (decltype(status.size()) i = 0; i < status.size(); i++) {
315 if (dofPresent[i] == false) status[i] = 'p';
316 }
317 if (dirOrNot.size() > 0) {
318 for (decltype(map.size()) i = 0; i < map.size(); i++) {
319 if (dirOrNot[i] == true) {
320 status[map[i]] = 'd';
321 }
322 }
323 }
324 Set(currentLevel, "DofStatus", status);
325
326 // end status array
327
328 Teuchos::RCP<CrsMatrix> lapCrsMat = CrsMatrixFactory::Build(amalgRowMap, amalgColMap, 10); // TODO better approx for max nnz per row
329
330 for (size_t i = 0; i < nLocalNodes; i++) {
331 lapCrsMat->insertLocalValues(i, amalgCols.view(amalgRowPtr[i], amalgRowPtr[i + 1] - amalgRowPtr[i]),
332 lapVals.view(amalgRowPtr[i], amalgRowPtr[i + 1] - amalgRowPtr[i]));
333 }
334 lapCrsMat->fillComplete(amalgRowMap, amalgRowMap);
335
336 // lapCrsMat->describe(*fancy, Teuchos::VERB_EXTREME);
337
338 Teuchos::RCP<Matrix> lapMat = Teuchos::rcp(new CrsMatrixWrap(lapCrsMat));
339 Set(currentLevel, "A", lapMat);
340}
341
342template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
343void VariableDofLaplacianFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::buildLaplacian(const Teuchos::ArrayRCP<size_t>& rowPtr, const Teuchos::ArrayRCP<LocalOrdinal>& cols, Teuchos::ArrayRCP<Scalar>& vals, const size_t& numdim, const RCP<Xpetra::MultiVector<typename Teuchos::ScalarTraits<Scalar>::magnitudeType, LocalOrdinal, GlobalOrdinal, Node> >& ghostedCoords) const {
344 TEUCHOS_TEST_FOR_EXCEPTION(numdim != 2 && numdim != 3, MueLu::Exceptions::RuntimeError, "buildLaplacian only works for 2d or 3d examples. numdim = " << numdim);
345
346 if (numdim == 2) { // 2d
347 Teuchos::ArrayRCP<const typename Teuchos::ScalarTraits<Scalar>::magnitudeType> x = ghostedCoords->getData(0);
348 Teuchos::ArrayRCP<const typename Teuchos::ScalarTraits<Scalar>::magnitudeType> y = ghostedCoords->getData(1);
349
350 for (decltype(rowPtr.size()) i = 0; i < rowPtr.size() - 1; i++) {
351 Scalar sum = Teuchos::ScalarTraits<Scalar>::zero();
352 LocalOrdinal diag = -1;
353 for (size_t j = rowPtr[i]; j < rowPtr[i + 1]; j++) {
354 if (cols[j] != Teuchos::as<LO>(i)) {
355 vals[j] = std::sqrt((x[i] - x[cols[j]]) * (x[i] - x[cols[j]]) +
356 (y[i] - y[cols[j]]) * (y[i] - y[cols[j]]));
357 TEUCHOS_TEST_FOR_EXCEPTION(vals[j] == Teuchos::ScalarTraits<Scalar>::zero(), MueLu::Exceptions::RuntimeError, "buildLaplacian: error, " << i << " and " << cols[j] << " have same coordinates: " << x[i] << " and " << y[i]);
358 vals[j] = -Teuchos::ScalarTraits<SC>::one() / vals[j];
359 sum = sum - vals[j];
360 } else
361 diag = j;
362 }
363 if (sum == Teuchos::ScalarTraits<Scalar>::zero()) sum = Teuchos::ScalarTraits<Scalar>::one();
364 TEUCHOS_TEST_FOR_EXCEPTION(diag == -1, MueLu::Exceptions::RuntimeError, "buildLaplacian: error, row " << i << " has zero diagonal!");
365
366 vals[diag] = sum;
367 }
368 } else { // 3d
369 Teuchos::ArrayRCP<const typename Teuchos::ScalarTraits<Scalar>::magnitudeType> x = ghostedCoords->getData(0);
370 Teuchos::ArrayRCP<const typename Teuchos::ScalarTraits<Scalar>::magnitudeType> y = ghostedCoords->getData(1);
371 Teuchos::ArrayRCP<const typename Teuchos::ScalarTraits<Scalar>::magnitudeType> z = ghostedCoords->getData(2);
372
373 for (decltype(rowPtr.size()) i = 0; i < rowPtr.size() - 1; i++) {
374 Scalar sum = Teuchos::ScalarTraits<Scalar>::zero();
375 LocalOrdinal diag = -1;
376 for (size_t j = rowPtr[i]; j < rowPtr[i + 1]; j++) {
377 if (cols[j] != Teuchos::as<LO>(i)) {
378 vals[j] = std::sqrt((x[i] - x[cols[j]]) * (x[i] - x[cols[j]]) +
379 (y[i] - y[cols[j]]) * (y[i] - y[cols[j]]) +
380 (z[i] - z[cols[j]]) * (z[i] - z[cols[j]]));
381
382 TEUCHOS_TEST_FOR_EXCEPTION(vals[j] == Teuchos::ScalarTraits<Scalar>::zero(), MueLu::Exceptions::RuntimeError, "buildLaplacian: error, " << i << " and " << cols[j] << " have same coordinates: " << x[i] << " and " << y[i] << " and " << z[i]);
383
384 vals[j] = -Teuchos::ScalarTraits<SC>::one() / vals[j];
385 sum = sum - vals[j];
386 } else
387 diag = j;
388 }
389 if (sum == Teuchos::ScalarTraits<Scalar>::zero()) sum = Teuchos::ScalarTraits<Scalar>::one();
390 TEUCHOS_TEST_FOR_EXCEPTION(diag == -1, MueLu::Exceptions::RuntimeError, "buildLaplacian: error, row " << i << " has zero diagonal!");
391
392 vals[diag] = sum;
393 }
394 }
395}
396
397template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
398void VariableDofLaplacianFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::squeezeOutNnzs(Teuchos::ArrayRCP<size_t>& rowPtr, Teuchos::ArrayRCP<LocalOrdinal>& cols, Teuchos::ArrayRCP<Scalar>& vals, const std::vector<bool>& keep) const {
399 // get rid of nonzero entries that have 0's in them and properly change
400 // the row ptr array to reflect this removal (either vals == NULL or vals != NULL)
401 // Note, the arrays are squeezed. No memory is freed.
402
403 size_t count = 0;
404
405 size_t nRows = rowPtr.size() - 1;
406 if (vals.size() > 0) {
407 for (size_t i = 0; i < nRows; i++) {
408 size_t newStart = count;
409 for (size_t j = rowPtr[i]; j < rowPtr[i + 1]; j++) {
410 if (vals[j] != Teuchos::ScalarTraits<Scalar>::zero()) {
411 cols[count] = cols[j];
412 vals[count++] = vals[j];
413 }
414 }
415 rowPtr[i] = newStart;
416 }
417 } else {
418 for (size_t i = 0; i < nRows; i++) {
419 size_t newStart = count;
420 for (size_t j = rowPtr[i]; j < rowPtr[i + 1]; j++) {
421 if (keep[j] == true) {
422 cols[count++] = cols[j];
423 }
424 }
425 rowPtr[i] = newStart;
426 }
427 }
428 rowPtr[nRows] = count;
429}
430
431template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
432void VariableDofLaplacianFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::buildPaddedMap(const Teuchos::ArrayRCP<const LocalOrdinal>& dofPresent, std::vector<LocalOrdinal>& map, size_t nDofs) const {
433 size_t count = 0;
434 for (decltype(dofPresent.size()) i = 0; i < dofPresent.size(); i++)
435 if (dofPresent[i] == 1) map[count++] = Teuchos::as<LocalOrdinal>(i);
436 TEUCHOS_TEST_FOR_EXCEPTION(nDofs != count, MueLu::Exceptions::RuntimeError, "VariableDofLaplacianFactory::buildPaddedMap: #dofs in dofPresent does not match the expected value (number of rows of A): " << nDofs << " vs. " << count);
437}
438
439template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
440void VariableDofLaplacianFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::assignGhostLocalNodeIds(const Teuchos::RCP<const Map>& rowDofMap, const Teuchos::RCP<const Map>& colDofMap, std::vector<LocalOrdinal>& myLocalNodeIds, const std::vector<LocalOrdinal>& dofMap, size_t maxDofPerNode, size_t& nLocalNodes, size_t& nLocalPlusGhostNodes, Teuchos::RCP<const Teuchos::Comm<int> > comm) const {
441 size_t nLocalDofs = rowDofMap->getLocalNumElements();
442 size_t nLocalPlusGhostDofs = colDofMap->getLocalNumElements(); // TODO remove parameters
443
444 // create importer for dof-based information
445 Teuchos::RCP<Import> importer = ImportFactory::Build(rowDofMap, colDofMap);
446
447 // create a vector living on column map of A (dof based)
448 Teuchos::RCP<LOVector> localNodeIdsTemp = LOVectorFactory::Build(rowDofMap, true);
449 Teuchos::RCP<LOVector> localNodeIds = LOVectorFactory::Build(colDofMap, true);
450
451 // fill local dofs (padded local ids)
452 {
453 Teuchos::ArrayRCP<LocalOrdinal> localNodeIdsTempData = localNodeIdsTemp->getDataNonConst(0);
454 for (size_t i = 0; i < localNodeIdsTemp->getLocalLength(); i++)
455 localNodeIdsTempData[i] = std::floor<LocalOrdinal>(dofMap[i] / maxDofPerNode);
456 }
457
458 localNodeIds->doImport(*localNodeIdsTemp, *importer, Xpetra::INSERT);
459 Teuchos::ArrayRCP<const LocalOrdinal> localNodeIdsData = localNodeIds->getData(0);
460
461 // Note: localNodeIds contains local ids for the padded version as vector values
462
463 // we use Scalar instead of int as type
464 Teuchos::RCP<LOVector> myProcTemp = LOVectorFactory::Build(rowDofMap, true);
465 Teuchos::RCP<LOVector> myProc = LOVectorFactory::Build(colDofMap, true);
466
467 // fill local dofs (padded local ids)
468 {
469 Teuchos::ArrayRCP<LocalOrdinal> myProcTempData = myProcTemp->getDataNonConst(0);
470 for (size_t i = 0; i < myProcTemp->getLocalLength(); i++)
471 myProcTempData[i] = Teuchos::as<LocalOrdinal>(comm->getRank());
472 }
473 myProc->doImport(*myProcTemp, *importer, Xpetra::INSERT);
474 Teuchos::ArrayRCP<LocalOrdinal> myProcData = myProc->getDataNonConst(0); // we have to modify the data (therefore the non-const version)
475
476 // At this point, the ghost part of localNodeIds corresponds to the local ids
477 // associated with the current owning processor. We want to convert these to
478 // local ids associated with the processor on which these are ghosts.
479 // Thus we have to re-number them. In doing this re-numbering we must make sure
480 // that we find all ghosts with the same id & proc and assign a unique local
481 // id to this group (id&proc). To do this find, we sort all ghost entries in
482 // localNodeIds that are owned by the same processor. Then we can look for
483 // duplicates (i.e., several ghost entries corresponding to dofs with the same
484 // node id) easily and make sure these are all assigned to the same local id.
485 // To do the sorting we'll make a temporary copy of the ghosts via tempId and
486 // tempProc and sort this multiple times for each group owned by the same proc.
487
488 std::vector<size_t> location(nLocalPlusGhostDofs - nLocalDofs + 1);
489 std::vector<size_t> tempId(nLocalPlusGhostDofs - nLocalDofs + 1);
490 std::vector<size_t> tempProc(nLocalPlusGhostDofs - nLocalDofs + 1);
491
492 size_t notProcessed = nLocalDofs; // iteration index over all ghosted dofs
493 size_t tempIndex = 0;
494 size_t first = tempIndex;
495 LocalOrdinal neighbor;
496
497 while (notProcessed < nLocalPlusGhostDofs) {
498 neighbor = myProcData[notProcessed]; // get processor id of not-processed element
499 first = tempIndex;
500 location[tempIndex] = notProcessed;
501 tempId[tempIndex++] = localNodeIdsData[notProcessed];
502 myProcData[notProcessed] = -1 - neighbor;
503
504 for (size_t i = notProcessed + 1; i < nLocalPlusGhostDofs; i++) {
505 if (myProcData[i] == neighbor) {
506 location[tempIndex] = i;
507 tempId[tempIndex++] = localNodeIdsData[i];
508 myProcData[i] = -1; // mark as visited
509 }
510 }
511 this->MueLu_az_sort<size_t>(&(tempId[first]), tempIndex - first, &(location[first]), NULL);
512 for (size_t i = first; i < tempIndex; i++) tempProc[i] = neighbor;
513
514 // increment index. Find next notProcessed dof index corresponding to first non-visited element
515 notProcessed++;
516 while ((notProcessed < nLocalPlusGhostDofs) && (myProcData[notProcessed] < 0))
517 notProcessed++;
518 }
519 TEUCHOS_TEST_FOR_EXCEPTION(tempIndex != nLocalPlusGhostDofs - nLocalDofs, MueLu::Exceptions::RuntimeError, "Number of nonzero ghosts is inconsistent.");
520
521 // Now assign ids to all ghost nodes (giving the same id to those with the
522 // same myProc[] and the same local id on the proc that actually owns the
523 // variable associated with the ghost
524
525 nLocalNodes = 0; // initialize return value
526 if (nLocalDofs > 0) nLocalNodes = localNodeIdsData[nLocalDofs - 1] + 1;
527
528 nLocalPlusGhostNodes = nLocalNodes; // initialize return value
529 if (nLocalDofs < nLocalPlusGhostDofs) nLocalPlusGhostNodes++; // 1st ghost node is unique (not accounted for). number will be increased later, if there are more ghost nodes
530
531 // check if two adjacent ghost dofs correspond to different nodes. To do this,
532 // check if they are from different processors or whether they have different
533 // local node ids
534
535 // loop over all (remaining) ghost dofs
536 for (size_t i = nLocalDofs + 1; i < nLocalPlusGhostDofs; i++) {
537 size_t lagged = nLocalPlusGhostNodes - 1;
538
539 // i is a new unique ghost node (not already accounted for)
540 if ((tempId[i - nLocalDofs] != tempId[i - 1 - nLocalDofs]) ||
541 (tempProc[i - nLocalDofs] != tempProc[i - 1 - nLocalDofs]))
542 nLocalPlusGhostNodes++; // update number of ghost nodes
543 tempId[i - 1 - nLocalDofs] = lagged;
544 }
545 if (nLocalPlusGhostDofs > nLocalDofs)
546 tempId[nLocalPlusGhostDofs - 1 - nLocalDofs] = nLocalPlusGhostNodes - 1;
547
548 // fill myLocalNodeIds array. Start with local part (not ghosted)
549 for (size_t i = 0; i < nLocalDofs; i++)
550 myLocalNodeIds[i] = std::floor<LocalOrdinal>(dofMap[i] / maxDofPerNode);
551
552 // copy ghosted nodal ids into myLocalNodeIds
553 for (size_t i = nLocalDofs; i < nLocalPlusGhostDofs; i++)
554 myLocalNodeIds[location[i - nLocalDofs]] = tempId[i - nLocalDofs];
555}
556
557} // namespace MueLu
558
559#endif /* PACKAGES_MUELU_SRC_GRAPH_MUELU_VARIABLEDOFLAPLACIANFACTORY_DEF_HPP_ */
MueLu::DefaultLocalOrdinal LocalOrdinal
MueLu::DefaultScalar Scalar
MueLu::DefaultGlobalOrdinal GlobalOrdinal
MueLu::DefaultNode Node
Exception throws to report errors in the internal logical of the program.
Timer to be used in factories. Similar to Monitor but with additional timers.
void Input(Level &level, const std::string &varName) const
T Get(Level &level, const std::string &varName) const
void Set(Level &level, const std::string &varName, const T &data) const
Class that holds all level-specific information.
bool IsAvailable(const std::string &ename, const FactoryBase *factory=NoFactory::get()) const
Test whether a need's value has been saved.
void DeclareInput(const std::string &ename, const FactoryBase *factory, const FactoryBase *requestedBy=NoFactory::get())
Callback from FactoryBase::CallDeclareInput() and FactoryBase::DeclareInput().
T & Get(const std::string &ename, const FactoryBase *factory=NoFactory::get())
Get data without decrementing associated storage counter (i.e., read-only access)....
static const NoFactory * get()
virtual const Teuchos::ParameterList & GetParameterList() const
static Teuchos::ArrayRCP< const bool > DetectDirichletRowsExt(const Xpetra::Matrix< Scalar, DefaultLocalOrdinal, DefaultGlobalOrdinal, DefaultNode > &A, bool &bHasZeroDiagonal, const Magnitude &tol=Teuchos::ScalarTraits< Scalar >::zero())
void Build(Level &currentLevel) const
Build an object with this factory.
void MueLu_az_sort(listType list[], size_t N, size_t list2[], Scalar list3[]) const
void squeezeOutNnzs(Teuchos::ArrayRCP< size_t > &rowPtr, Teuchos::ArrayRCP< LocalOrdinal > &cols, Teuchos::ArrayRCP< Scalar > &vals, const std::vector< bool > &keep) const
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
void buildLaplacian(const Teuchos::ArrayRCP< size_t > &rowPtr, const Teuchos::ArrayRCP< LocalOrdinal > &cols, Teuchos::ArrayRCP< Scalar > &vals, const size_t &numdim, const RCP< Xpetra::MultiVector< typename Teuchos::ScalarTraits< Scalar >::magnitudeType, LocalOrdinal, GlobalOrdinal, Node > > &ghostedCoords) const
void assignGhostLocalNodeIds(const Teuchos::RCP< const Map > &rowDofMap, const Teuchos::RCP< const Map > &colDofMap, std::vector< LocalOrdinal > &myLocalNodeIds, const std::vector< LocalOrdinal > &dofMap, size_t maxDofPerNode, size_t &nLocalNodes, size_t &nLocalPlusGhostNodes, Teuchos::RCP< const Teuchos::Comm< int > > comm) const
void buildPaddedMap(const Teuchos::ArrayRCP< const LocalOrdinal > &dofPresent, std::vector< LocalOrdinal > &map, size_t nDofs) const
Namespace for MueLu classes and methods.