MueLu  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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 
17 namespace MueLu {
18 
19 template <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 
33 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
35 
36 template <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 
47 template <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 
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;
68 
69  // check availability of DofPresent array
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,
150  amalgRowMapGIDs(), // View,
151  A->getRowMap()->getIndexBase(),
152  comm);
153 
154  Teuchos::RCP<Map> amalgColMap = MapFactory::Build(lib,
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<CrsMatrixWrap> Awrap = Teuchos::rcp_dynamic_cast<CrsMatrixWrap>(A);
165  Teuchos::RCP<CrsMatrix> Acrs = Awrap->getCrsMatrix();
166  // Acrs->describe(*fancy, Teuchos::VERB_EXTREME);
167 
168  size_t nNonZeros = 0;
169  std::vector<bool> isNonZero(nLocalPlusGhostDofs, false);
170  std::vector<size_t> nonZeroList(nLocalPlusGhostDofs); // ???
171 
172  // also used in DetectDirichletExt
173  Teuchos::RCP<Vector> diagVecUnique = VectorFactory::Build(A->getRowMap());
174  Teuchos::RCP<Vector> diagVec = VectorFactory::Build(A->getColMap());
175  A->getLocalDiagCopy(*diagVecUnique);
176  diagVec->doImport(*diagVecUnique, *dofImporter, Xpetra::INSERT);
177  Teuchos::ArrayRCP<const Scalar> diagVecData = diagVec->getData(0);
178 
179  Teuchos::ArrayRCP<const size_t> rowptr(Acrs->getLocalNumRows());
180  Teuchos::ArrayRCP<const LocalOrdinal> colind(Acrs->getLocalNumEntries());
181  Teuchos::ArrayRCP<const Scalar> values(Acrs->getLocalNumEntries());
182  Acrs->getAllValues(rowptr, colind, values);
183 
184  // create arrays for amalgamated matrix
185  Teuchos::ArrayRCP<size_t> amalgRowPtr(nLocalNodes + 1);
186  Teuchos::ArrayRCP<LocalOrdinal> amalgCols(rowptr[rowptr.size() - 1]);
187 
188  LocalOrdinal oldBlockRow = 0;
189  LocalOrdinal blockRow = 0;
190  LocalOrdinal blockColumn = 0;
191 
192  size_t newNzs = 0;
193  amalgRowPtr[0] = newNzs;
194 
195  bool doNotDrop = false;
196  if (amalgDropTol == Teuchos::ScalarTraits<Scalar>::zero()) doNotDrop = true;
197  if (values.size() == 0) doNotDrop = true;
198 
199  for (decltype(rowptr.size()) i = 0; i < rowptr.size() - 1; i++) {
200  blockRow = std::floor<LocalOrdinal>(map[i] / maxDofPerNode);
201  if (blockRow != oldBlockRow) {
202  // zero out info recording nonzeros in oldBlockRow
203  for (size_t j = 0; j < nNonZeros; j++) isNonZero[nonZeroList[j]] = false;
204  nNonZeros = 0;
205  amalgRowPtr[blockRow] = newNzs; // record start of next row
206  }
207  for (size_t j = rowptr[i]; j < rowptr[i + 1]; j++) {
208  if (doNotDrop == true ||
209  (STS::magnitude(values[j] / STS::magnitude(sqrt(STS::magnitude(diagVecData[i]) * STS::magnitude(diagVecData[colind[j]])))) >= STS::magnitude(amalgDropTol))) {
210  blockColumn = myLocalNodeIds[colind[j]];
211  if (isNonZero[blockColumn] == false) {
212  isNonZero[blockColumn] = true;
213  nonZeroList[nNonZeros++] = blockColumn;
214  amalgCols[newNzs++] = blockColumn;
215  }
216  }
217  }
218  oldBlockRow = blockRow;
219  }
220  amalgRowPtr[blockRow + 1] = newNzs;
221 
222  TEUCHOS_TEST_FOR_EXCEPTION((blockRow + 1 != Teuchos::as<LO>(nLocalNodes)) && (nLocalNodes != 0), MueLu::Exceptions::RuntimeError, "VariableDofsPerNodeAmalgamation: error, computed # block rows (" << blockRow + 1 << ") != nLocalNodes (" << nLocalNodes << ")");
223 
224  amalgCols.resize(amalgRowPtr[nLocalNodes]);
225 
226  // end variableDofAmalg
227 
228  // begin rm differentDofsCrossings
229 
230  // Remove matrix entries (i,j) where the ith node and the jth node have
231  // different dofs that are 'present'
232  // Specifically, on input:
233  // dofPresent[i*maxDofPerNode+k] indicates whether or not the kth
234  // dof at the ith node is present in the
235  // variable dof matrix (e.g., the ith node
236  // has an air pressure dof). true means
237  // the dof is present while false means it
238  // is not.
239  // We create a unique id for the ith node (i.e. uniqueId[i]) via
240  // sum_{k=0 to maxDofPerNode-1} dofPresent[i*maxDofPerNode+k]*2^k
241  // and use this unique idea to remove entries (i,j) when uniqueId[i]!=uniqueId[j]
242 
243  Teuchos::ArrayRCP<LocalOrdinal> uniqueId(nLocalPlusGhostNodes); // unique id associated with DOF
244  std::vector<bool> keep(amalgRowPtr[amalgRowPtr.size() - 1], true); // keep connection associated with node
245 
246  size_t ii = 0; // iteration index for present dofs
247  for (decltype(amalgRowPtr.size()) i = 0; i < amalgRowPtr.size() - 1; i++) {
248  LocalOrdinal temp = 1; // basis for dof-id
249  uniqueId[i] = 0;
250  for (decltype(maxDofPerNode) j = 0; j < maxDofPerNode; j++) {
251  if (dofPresent[ii++]) uniqueId[i] += temp; // encode dof to be present
252  temp = temp * 2; // check next dof
253  }
254  }
255 
256  Teuchos::RCP<Import> nodeImporter = ImportFactory::Build(amalgRowMap, amalgColMap);
257 
260 
261  Teuchos::ArrayRCP<LocalOrdinal> nodeIdSrcData = nodeIdSrc->getDataNonConst(0);
262  for (decltype(amalgRowPtr.size()) i = 0; i < amalgRowPtr.size() - 1; i++) {
263  nodeIdSrcData[i] = uniqueId[i];
264  }
265 
266  nodeIdTarget->doImport(*nodeIdSrc, *nodeImporter, Xpetra::INSERT);
267 
268  Teuchos::ArrayRCP<const LocalOrdinal> nodeIdTargetData = nodeIdTarget->getData(0);
269  for (decltype(uniqueId.size()) i = 0; i < uniqueId.size(); i++) {
270  uniqueId[i] = nodeIdTargetData[i];
271  }
272 
273  // nodal comm uniqueId, myLocalNodeIds
274 
275  // uniqueId now should contain ghosted data
276 
277  for (decltype(amalgRowPtr.size()) i = 0; i < amalgRowPtr.size() - 1; i++) {
278  for (size_t j = amalgRowPtr[i]; j < amalgRowPtr[i + 1]; j++) {
279  if (uniqueId[i] != uniqueId[amalgCols[j]]) keep[j] = false;
280  }
281  }
282 
283  // squeeze out hard-coded zeros from CSR arrays
284  Teuchos::ArrayRCP<Scalar> amalgVals;
285  this->squeezeOutNnzs(amalgRowPtr, amalgCols, amalgVals, keep);
286 
288  RCP<dxMV> ghostedCoords = dxMVf::Build(amalgColMap, Coords->getNumVectors());
289 
290  TEUCHOS_TEST_FOR_EXCEPTION(amalgRowMap->getLocalNumElements() != Coords->getMap()->getLocalNumElements(), MueLu::Exceptions::RuntimeError, "MueLu::VariableDofLaplacianFactory: the number of Coordinates and amalgamated nodes is inconsistent.");
291 
292  // Coords might live on a special nodeMap with consecutive ids (the natural numbering)
293  // The amalgRowMap might have the same number of entries, but with holes in the ids.
294  // e.g. 0,3,6,9,... as GIDs.
295  // We need the ghosted Coordinates in the buildLaplacian routine. But we access the data
296  // through getData only, i.e., the global ids are not interesting as long as we do not change
297  // the ordering of the entries
298  Coords->replaceMap(amalgRowMap);
299  ghostedCoords->doImport(*Coords, *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 
343 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
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
350 
351  for (decltype(rowPtr.size()) i = 0; i < rowPtr.size() - 1; i++) {
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  }
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
373 
374  for (decltype(rowPtr.size()) i = 0; i < rowPtr.size() - 1; i++) {
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  }
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 
398 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
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 
432 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
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 
440 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
441 void 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_ */
void buildPaddedMap(const Teuchos::ArrayRCP< const LocalOrdinal > &dofPresent, std::vector< LocalOrdinal > &map, size_t nDofs) const
MueLu::DefaultLocalOrdinal LocalOrdinal
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
GlobalOrdinal GO
T & get(const std::string &name, T def_value)
Timer to be used in factories. Similar to Monitor but with additional timers.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
LocalOrdinal LO
ParameterList & set(std::string const &name, T &&value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
size_type size() const
void DeclareInput(Level &currentLevel) const
Input.
MueLu::DefaultNode Node
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
static const NoFactory * get()
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
MueLu::DefaultScalar Scalar
MueLu::DefaultGlobalOrdinal GlobalOrdinal
Class that holds all level-specific information.
Definition: MueLu_Level.hpp:63
void Build(Level &currentLevel) const
Build an object with this factory.
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)
static RCP< Vector > Build(const Teuchos::RCP< const Map > &map, bool zeroOut=true)
size_type size() const
void squeezeOutNnzs(Teuchos::ArrayRCP< size_t > &rowPtr, Teuchos::ArrayRCP< LocalOrdinal > &cols, Teuchos::ArrayRCP< Scalar > &vals, const std::vector< bool > &keep) const
Node NO
Exception throws to report errors in the internal logical of the program.
void DeclareInput(const std::string &ename, const FactoryBase *factory, const FactoryBase *requestedBy=NoFactory::get())
Callback from FactoryBase::CallDeclareInput() and FactoryBase::DeclareInput()
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
bool IsAvailable(const std::string &ename, const FactoryBase *factory=NoFactory::get()) const
Test whether a need&#39;s value has been saved.
ArrayView< T > view(size_type lowerOffset, size_type size) const