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