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.
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.