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 RCP<dxMV> CoordsCopy = dxMVf::Build(Coords, Teuchos::Copy);
298 CoordsCopy->replaceMap(amalgRowMap);
299 ghostedCoords->doImport(*CoordsCopy, *nodeImporter, Xpetra::INSERT);
300
301 Teuchos::ArrayRCP<Scalar> lapVals(amalgRowPtr[nLocalNodes]);
302 this->buildLaplacian(amalgRowPtr, amalgCols, lapVals, Coords->getNumVectors(), ghostedCoords);
303
304 // sort column GIDs
305 for (decltype(amalgRowPtr.size()) i = 0; i < amalgRowPtr.size() - 1; i++) {
306 size_t j = amalgRowPtr[i];
307 this->MueLu_az_sort<LocalOrdinal>(&(amalgCols[j]), amalgRowPtr[i + 1] - j, NULL, &(lapVals[j]));
308 }
309
310 // Caluclate status array for next level
311 Teuchos::Array<char> status(nLocalNodes * maxDofPerNode);
312
313 // dir or not Teuchos::ArrayRCP<const bool> dirOrNot
314 for (decltype(status.size()) i = 0; i < status.size(); i++) status[i] = 's';
315 for (decltype(status.size()) i = 0; i < status.size(); i++) {
316 if (dofPresent[i] == false) status[i] = 'p';
317 }
318 if (dirOrNot.size() > 0) {
319 for (decltype(map.size()) i = 0; i < map.size(); i++) {
320 if (dirOrNot[i] == true) {
321 status[map[i]] = 'd';
322 }
323 }
324 }
325 Set(currentLevel, "DofStatus", status);
326
327 // end status array
328
329 Teuchos::RCP<CrsMatrix> lapCrsMat = CrsMatrixFactory::Build(amalgRowMap, amalgColMap, 10); // TODO better approx for max nnz per row
330
331 for (size_t i = 0; i < nLocalNodes; i++) {
332 lapCrsMat->insertLocalValues(i, amalgCols.view(amalgRowPtr[i], amalgRowPtr[i + 1] - amalgRowPtr[i]),
333 lapVals.view(amalgRowPtr[i], amalgRowPtr[i + 1] - amalgRowPtr[i]));
334 }
335 lapCrsMat->fillComplete(amalgRowMap, amalgRowMap);
336
337 // lapCrsMat->describe(*fancy, Teuchos::VERB_EXTREME);
338
339 Teuchos::RCP<Matrix> lapMat = Teuchos::rcp(new CrsMatrixWrap(lapCrsMat));
340 Set(currentLevel, "A", lapMat);
341}
342
343template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
344void 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 {
345 TEUCHOS_TEST_FOR_EXCEPTION(numdim != 2 && numdim != 3, MueLu::Exceptions::RuntimeError, "buildLaplacian only works for 2d or 3d examples. numdim = " << numdim);
346
347 if (numdim == 2) { // 2d
348 Teuchos::ArrayRCP<const typename Teuchos::ScalarTraits<Scalar>::magnitudeType> x = ghostedCoords->getData(0);
349 Teuchos::ArrayRCP<const typename Teuchos::ScalarTraits<Scalar>::magnitudeType> y = ghostedCoords->getData(1);
350
351 for (decltype(rowPtr.size()) i = 0; i < rowPtr.size() - 1; i++) {
352 Scalar sum = Teuchos::ScalarTraits<Scalar>::zero();
353 LocalOrdinal diag = -1;
354 for (size_t j = rowPtr[i]; j < rowPtr[i + 1]; j++) {
355 if (cols[j] != Teuchos::as<LO>(i)) {
356 vals[j] = std::sqrt((x[i] - x[cols[j]]) * (x[i] - x[cols[j]]) +
357 (y[i] - y[cols[j]]) * (y[i] - y[cols[j]]));
358 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]);
359 vals[j] = -Teuchos::ScalarTraits<SC>::one() / vals[j];
360 sum = sum - vals[j];
361 } else
362 diag = j;
363 }
364 if (sum == Teuchos::ScalarTraits<Scalar>::zero()) sum = Teuchos::ScalarTraits<Scalar>::one();
365 TEUCHOS_TEST_FOR_EXCEPTION(diag == -1, MueLu::Exceptions::RuntimeError, "buildLaplacian: error, row " << i << " has zero diagonal!");
366
367 vals[diag] = sum;
368 }
369 } else { // 3d
370 Teuchos::ArrayRCP<const typename Teuchos::ScalarTraits<Scalar>::magnitudeType> x = ghostedCoords->getData(0);
371 Teuchos::ArrayRCP<const typename Teuchos::ScalarTraits<Scalar>::magnitudeType> y = ghostedCoords->getData(1);
372 Teuchos::ArrayRCP<const typename Teuchos::ScalarTraits<Scalar>::magnitudeType> z = ghostedCoords->getData(2);
373
374 for (decltype(rowPtr.size()) i = 0; i < rowPtr.size() - 1; i++) {
375 Scalar sum = Teuchos::ScalarTraits<Scalar>::zero();
376 LocalOrdinal diag = -1;
377 for (size_t j = rowPtr[i]; j < rowPtr[i + 1]; j++) {
378 if (cols[j] != Teuchos::as<LO>(i)) {
379 vals[j] = std::sqrt((x[i] - x[cols[j]]) * (x[i] - x[cols[j]]) +
380 (y[i] - y[cols[j]]) * (y[i] - y[cols[j]]) +
381 (z[i] - z[cols[j]]) * (z[i] - z[cols[j]]));
382
383 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]);
384
385 vals[j] = -Teuchos::ScalarTraits<SC>::one() / vals[j];
386 sum = sum - vals[j];
387 } else
388 diag = j;
389 }
390 if (sum == Teuchos::ScalarTraits<Scalar>::zero()) sum = Teuchos::ScalarTraits<Scalar>::one();
391 TEUCHOS_TEST_FOR_EXCEPTION(diag == -1, MueLu::Exceptions::RuntimeError, "buildLaplacian: error, row " << i << " has zero diagonal!");
392
393 vals[diag] = sum;
394 }
395 }
396}
397
398template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
399void 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 {
400 // get rid of nonzero entries that have 0's in them and properly change
401 // the row ptr array to reflect this removal (either vals == NULL or vals != NULL)
402 // Note, the arrays are squeezed. No memory is freed.
403
404 size_t count = 0;
405
406 size_t nRows = rowPtr.size() - 1;
407 if (vals.size() > 0) {
408 for (size_t i = 0; i < nRows; i++) {
409 size_t newStart = count;
410 for (size_t j = rowPtr[i]; j < rowPtr[i + 1]; j++) {
411 if (vals[j] != Teuchos::ScalarTraits<Scalar>::zero()) {
412 cols[count] = cols[j];
413 vals[count++] = vals[j];
414 }
415 }
416 rowPtr[i] = newStart;
417 }
418 } else {
419 for (size_t i = 0; i < nRows; i++) {
420 size_t newStart = count;
421 for (size_t j = rowPtr[i]; j < rowPtr[i + 1]; j++) {
422 if (keep[j] == true) {
423 cols[count++] = cols[j];
424 }
425 }
426 rowPtr[i] = newStart;
427 }
428 }
429 rowPtr[nRows] = count;
430}
431
432template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
433void VariableDofLaplacianFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::buildPaddedMap(const Teuchos::ArrayRCP<const LocalOrdinal>& dofPresent, std::vector<LocalOrdinal>& map, size_t nDofs) const {
434 size_t count = 0;
435 for (decltype(dofPresent.size()) i = 0; i < dofPresent.size(); i++)
436 if (dofPresent[i] == 1) map[count++] = Teuchos::as<LocalOrdinal>(i);
437 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);
438}
439
440template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
441void 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 {
442 size_t nLocalDofs = rowDofMap->getLocalNumElements();
443 size_t nLocalPlusGhostDofs = colDofMap->getLocalNumElements(); // TODO remove parameters
444
445 // create importer for dof-based information
446 Teuchos::RCP<Import> importer = ImportFactory::Build(rowDofMap, colDofMap);
447
448 // create a vector living on column map of A (dof based)
449 Teuchos::RCP<LOVector> localNodeIdsTemp = LOVectorFactory::Build(rowDofMap, true);
450 Teuchos::RCP<LOVector> localNodeIds = LOVectorFactory::Build(colDofMap, true);
451
452 // fill local dofs (padded local ids)
453 {
454 Teuchos::ArrayRCP<LocalOrdinal> localNodeIdsTempData = localNodeIdsTemp->getDataNonConst(0);
455 for (size_t i = 0; i < localNodeIdsTemp->getLocalLength(); i++)
456 localNodeIdsTempData[i] = std::floor<LocalOrdinal>(dofMap[i] / maxDofPerNode);
457 }
458
459 localNodeIds->doImport(*localNodeIdsTemp, *importer, Xpetra::INSERT);
460 Teuchos::ArrayRCP<const LocalOrdinal> localNodeIdsData = localNodeIds->getData(0);
461
462 // Note: localNodeIds contains local ids for the padded version as vector values
463
464 // we use Scalar instead of int as type
465 Teuchos::RCP<LOVector> myProcTemp = LOVectorFactory::Build(rowDofMap, true);
466 Teuchos::RCP<LOVector> myProc = LOVectorFactory::Build(colDofMap, true);
467
468 // fill local dofs (padded local ids)
469 {
470 Teuchos::ArrayRCP<LocalOrdinal> myProcTempData = myProcTemp->getDataNonConst(0);
471 for (size_t i = 0; i < myProcTemp->getLocalLength(); i++)
472 myProcTempData[i] = Teuchos::as<LocalOrdinal>(comm->getRank());
473 }
474 myProc->doImport(*myProcTemp, *importer, Xpetra::INSERT);
475 Teuchos::ArrayRCP<LocalOrdinal> myProcData = myProc->getDataNonConst(0); // we have to modify the data (therefore the non-const version)
476
477 // At this point, the ghost part of localNodeIds corresponds to the local ids
478 // associated with the current owning processor. We want to convert these to
479 // local ids associated with the processor on which these are ghosts.
480 // Thus we have to re-number them. In doing this re-numbering we must make sure
481 // that we find all ghosts with the same id & proc and assign a unique local
482 // id to this group (id&proc). To do this find, we sort all ghost entries in
483 // localNodeIds that are owned by the same processor. Then we can look for
484 // duplicates (i.e., several ghost entries corresponding to dofs with the same
485 // node id) easily and make sure these are all assigned to the same local id.
486 // To do the sorting we'll make a temporary copy of the ghosts via tempId and
487 // tempProc and sort this multiple times for each group owned by the same proc.
488
489 std::vector<size_t> location(nLocalPlusGhostDofs - nLocalDofs + 1);
490 std::vector<size_t> tempId(nLocalPlusGhostDofs - nLocalDofs + 1);
491 std::vector<size_t> tempProc(nLocalPlusGhostDofs - nLocalDofs + 1);
492
493 size_t notProcessed = nLocalDofs; // iteration index over all ghosted dofs
494 size_t tempIndex = 0;
495 size_t first = tempIndex;
496 LocalOrdinal neighbor;
497
498 while (notProcessed < nLocalPlusGhostDofs) {
499 neighbor = myProcData[notProcessed]; // get processor id of not-processed element
500 first = tempIndex;
501 location[tempIndex] = notProcessed;
502 tempId[tempIndex++] = localNodeIdsData[notProcessed];
503 myProcData[notProcessed] = -1 - neighbor;
504
505 for (size_t i = notProcessed + 1; i < nLocalPlusGhostDofs; i++) {
506 if (myProcData[i] == neighbor) {
507 location[tempIndex] = i;
508 tempId[tempIndex++] = localNodeIdsData[i];
509 myProcData[i] = -1; // mark as visited
510 }
511 }
512 this->MueLu_az_sort<size_t>(&(tempId[first]), tempIndex - first, &(location[first]), NULL);
513 for (size_t i = first; i < tempIndex; i++) tempProc[i] = neighbor;
514
515 // increment index. Find next notProcessed dof index corresponding to first non-visited element
516 notProcessed++;
517 while ((notProcessed < nLocalPlusGhostDofs) && (myProcData[notProcessed] < 0))
518 notProcessed++;
519 }
520 TEUCHOS_TEST_FOR_EXCEPTION(tempIndex != nLocalPlusGhostDofs - nLocalDofs, MueLu::Exceptions::RuntimeError, "Number of nonzero ghosts is inconsistent.");
521
522 // Now assign ids to all ghost nodes (giving the same id to those with the
523 // same myProc[] and the same local id on the proc that actually owns the
524 // variable associated with the ghost
525
526 nLocalNodes = 0; // initialize return value
527 if (nLocalDofs > 0) nLocalNodes = localNodeIdsData[nLocalDofs - 1] + 1;
528
529 nLocalPlusGhostNodes = nLocalNodes; // initialize return value
530 if (nLocalDofs < nLocalPlusGhostDofs) nLocalPlusGhostNodes++; // 1st ghost node is unique (not accounted for). number will be increased later, if there are more ghost nodes
531
532 // check if two adjacent ghost dofs correspond to different nodes. To do this,
533 // check if they are from different processors or whether they have different
534 // local node ids
535
536 // loop over all (remaining) ghost dofs
537 for (size_t i = nLocalDofs + 1; i < nLocalPlusGhostDofs; i++) {
538 size_t lagged = nLocalPlusGhostNodes - 1;
539
540 // i is a new unique ghost node (not already accounted for)
541 if ((tempId[i - nLocalDofs] != tempId[i - 1 - nLocalDofs]) ||
542 (tempProc[i - nLocalDofs] != tempProc[i - 1 - nLocalDofs]))
543 nLocalPlusGhostNodes++; // update number of ghost nodes
544 tempId[i - 1 - nLocalDofs] = lagged;
545 }
546 if (nLocalPlusGhostDofs > nLocalDofs)
547 tempId[nLocalPlusGhostDofs - 1 - nLocalDofs] = nLocalPlusGhostNodes - 1;
548
549 // fill myLocalNodeIds array. Start with local part (not ghosted)
550 for (size_t i = 0; i < nLocalDofs; i++)
551 myLocalNodeIds[i] = std::floor<LocalOrdinal>(dofMap[i] / maxDofPerNode);
552
553 // copy ghosted nodal ids into myLocalNodeIds
554 for (size_t i = nLocalDofs; i < nLocalPlusGhostDofs; i++)
555 myLocalNodeIds[location[i - nLocalDofs]] = tempId[i - nLocalDofs];
556}
557
558} // namespace MueLu
559
560#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.
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()
static Teuchos::ArrayRCP< const bool > DetectDirichletRowsExt(const Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > &A, bool &bHasZeroDiagonal, const Magnitude &tol=Teuchos::ScalarTraits< Scalar >::zero())
Detect Dirichlet rows (extended version)
void Build(Level &currentLevel) const
Build an object with this factory.
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.