MueLu Version of the Day
Loading...
Searching...
No Matches
MueLu_SmooVecCoalesceDropFactory_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
11#ifndef MUELU_SMOOVECCOALESCEDROPFACTORY_DEF_HPP
12#define MUELU_SMOOVECCOALESCEDROPFACTORY_DEF_HPP
13
14#include <Xpetra_CrsGraph.hpp>
15#include <Xpetra_ImportFactory.hpp>
16#include <Xpetra_MapFactory.hpp>
17#include <Xpetra_Map.hpp>
18#include <Xpetra_Matrix.hpp>
19#include <Xpetra_MultiVectorFactory.hpp>
20#include <Xpetra_MultiVector.hpp>
21#include <Xpetra_StridedMap.hpp>
22#include <Xpetra_VectorFactory.hpp>
23#include <Xpetra_Vector.hpp>
24
26
27#include "MueLu_Exceptions.hpp"
28#include "MueLu_LWGraph.hpp"
29
30#include "MueLu_Level.hpp"
31#include "MueLu_MasterList.hpp"
32#include "MueLu_Monitor.hpp"
33#include "MueLu_PreDropFunctionBaseClass.hpp"
34
35#include <Xpetra_IO.hpp>
36
37#include <algorithm>
38#include <cstdlib>
39#include <string>
40
41// If defined, read environment variables.
42// Should be removed once we are confident that this works.
43// #define DJS_READ_ENV_VARIABLES
44
45#include <stdio.h>
46#include <stdlib.h>
47#include <math.h>
48
49#define poly0thOrderCoef 0
50#define poly1stOrderCoef 1
51#define poly2ndOrderCoef 2
52#define poly3rdOrderCoef 3
53#define poly4thOrderCoef 4
54
55namespace MueLu {
56
57template <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 scheme");
63 {
64 validParamList->getEntry("aggregation: drop scheme").setValidator(rcp(new Teuchos::StringValidator(Teuchos::tuple<std::string>("classical", "distance laplacian", "unsupported vector smoothing"))));
65 }
66 SET_VALID_ENTRY("aggregation: number of random vectors");
67 SET_VALID_ENTRY("aggregation: number of times to pre or post smooth");
68 SET_VALID_ENTRY("aggregation: penalty parameters");
69#undef SET_VALID_ENTRY
70
71 validParamList->set<RCP<const FactoryBase> >("A", Teuchos::null, "Generating factory of the matrix A");
72 validParamList->set<RCP<const FactoryBase> >("PreSmoother", Teuchos::null, "Generating factory of the PreSmoother");
73 validParamList->set<RCP<const FactoryBase> >("PostSmoother", Teuchos::null, "Generating factory of the PostSmoother");
74
75 return validParamList;
76}
77
78template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
81
82template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
84 Input(currentLevel, "A");
85 if (currentLevel.IsAvailable("PreSmoother")) { // rst: totally unsure that this is legal
86 Input(currentLevel, "PreSmoother"); // my guess is that this is not yet available
87 } // so this always comes out false.
88 else if (currentLevel.IsAvailable("PostSmoother")) { // perhaps we can look on the param list?
89 Input(currentLevel, "PostSmoother");
90 }
91}
92
93template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
95 FactoryMonitor m(*this, "Build", currentLevel);
96
97 typedef Teuchos::ScalarTraits<SC> STS;
98
99 if (predrop_ != Teuchos::null)
100 GetOStream(Parameters0) << predrop_->description();
101
102 RCP<Matrix> A = Get<RCP<Matrix> >(currentLevel, "A");
103
104 const ParameterList& pL = GetParameterList();
105
106 LO nPDEs = A->GetFixedBlockSize();
107
108 RCP<MultiVector> testVecs;
109 RCP<MultiVector> nearNull;
110
111#ifdef takeOut
112 testVecs = Xpetra::IO<SC, LO, GO, Node>::ReadMultiVector("TpetraTVecs.mm", A->getRowMap());
113#endif
114 size_t numRandom = as<size_t>(pL.get<int>("aggregation: number of random vectors"));
115 testVecs = MultiVectorFactory::Build(A->getRowMap(), numRandom, true);
116 // use random test vectors but should be positive in order to not get
117 // crummy results ... so take abs() of randomize().
118 testVecs->randomize();
119 for (size_t kk = 0; kk < testVecs->getNumVectors(); kk++) {
120 Teuchos::ArrayRCP<Scalar> curVec = testVecs->getDataNonConst(kk);
121 for (size_t ii = kk; ii < as<size_t>(A->getRowMap()->getLocalNumElements()); ii++) curVec[ii] = Teuchos::ScalarTraits<SC>::magnitude(curVec[ii]);
122 }
123 nearNull = MultiVectorFactory::Build(A->getRowMap(), nPDEs, true);
124
125 // initialize null space to constants
126 for (size_t kk = 0; kk < nearNull->getNumVectors(); kk++) {
127 Teuchos::ArrayRCP<Scalar> curVec = nearNull->getDataNonConst(kk);
128 for (size_t ii = kk; ii < as<size_t>(A->getRowMap()->getLocalNumElements()); ii += nearNull->getNumVectors()) curVec[ii] = Teuchos::ScalarTraits<Scalar>::one();
129 }
130
131 RCP<MultiVector> zeroVec_TVecs;
132 RCP<MultiVector> zeroVec_Null;
133
134 zeroVec_TVecs = MultiVectorFactory::Build(A->getRowMap(), testVecs->getNumVectors(), true);
135 zeroVec_Null = MultiVectorFactory::Build(A->getRowMap(), nPDEs, true);
136 zeroVec_TVecs->putScalar(Teuchos::ScalarTraits<Scalar>::zero());
137 zeroVec_Null->putScalar(Teuchos::ScalarTraits<Scalar>::zero());
138
139 size_t nInvokeSmoother = as<size_t>(pL.get<int>("aggregation: number of times to pre or post smooth"));
140 if (currentLevel.IsAvailable("PreSmoother")) {
141 RCP<SmootherBase> preSmoo = currentLevel.Get<RCP<SmootherBase> >("PreSmoother");
142 for (size_t ii = 0; ii < nInvokeSmoother; ii++) preSmoo->Apply(*testVecs, *zeroVec_TVecs, false);
143 for (size_t ii = 0; ii < nInvokeSmoother; ii++) preSmoo->Apply(*nearNull, *zeroVec_Null, false);
144 } else if (currentLevel.IsAvailable("PostSmoother")) {
145 RCP<SmootherBase> postSmoo = currentLevel.Get<RCP<SmootherBase> >("PostSmoother");
146 for (size_t ii = 0; ii < nInvokeSmoother; ii++) postSmoo->Apply(*testVecs, *zeroVec_TVecs, false);
147 for (size_t ii = 0; ii < nInvokeSmoother; ii++) postSmoo->Apply(*nearNull, *zeroVec_Null, false);
148 } else
149 TEUCHOS_TEST_FOR_EXCEPTION(true, Exceptions::RuntimeError, "Must set a smoother");
150
151 Teuchos::ArrayRCP<Scalar> penaltyPolyCoef(5);
152 Teuchos::ArrayView<const double> inputPolyCoef;
153
154 penaltyPolyCoef[poly0thOrderCoef] = 12.;
155 penaltyPolyCoef[poly1stOrderCoef] = -.2;
156 penaltyPolyCoef[poly2ndOrderCoef] = 0.0;
157 penaltyPolyCoef[poly3rdOrderCoef] = 0.0;
158 penaltyPolyCoef[poly4thOrderCoef] = 0.0;
159
160 if (pL.isParameter("aggregation: penalty parameters") && pL.get<Teuchos::Array<double> >("aggregation: penalty parameters").size() > 0) {
161 if (pL.get<Teuchos::Array<double> >("aggregation: penalty parameters").size() > penaltyPolyCoef.size())
162 TEUCHOS_TEST_FOR_EXCEPTION(true, Exceptions::RuntimeError, "Number of penalty parameters must be " << penaltyPolyCoef.size() << " or less");
163 inputPolyCoef = pL.get<Teuchos::Array<double> >("aggregation: penalty parameters")();
164
165 for (size_t i = 0; i < as<size_t>(inputPolyCoef.size()); i++) penaltyPolyCoef[i] = as<Scalar>(inputPolyCoef[i]);
166 for (size_t i = as<size_t>(inputPolyCoef.size()); i < as<size_t>(penaltyPolyCoef.size()); i++) penaltyPolyCoef[i] = Teuchos::ScalarTraits<Scalar>::zero();
167 }
168
169 RCP<LWGraph> filteredGraph;
170 badGuysCoalesceDrop(*A, penaltyPolyCoef, nPDEs, *testVecs, *nearNull, filteredGraph);
171
172#ifdef takeOut
173 /* write out graph for serial debugging purposes only. */
174
175 FILE* fp = fopen("codeOutput", "w");
176 fprintf(fp, "%d %d %d\n", (int)filteredGraph->GetNodeNumVertices(), (int)filteredGraph->GetNodeNumVertices(),
177 (int)filteredGraph->GetNodeNumEdges());
178 for (size_t i = 0; i < filteredGraph->GetNodeNumVertices(); i++) {
179 auto inds = filteredGraph->getNeighborVertices(as<LO>(i));
180 for (size_t j = 0; j < as<size_t>(inds.size()); j++) {
181 fprintf(fp, "%d %d 1.00e+00\n", (int)i + 1, (int)inds[j] + 1);
182 }
183 }
184 fclose(fp);
185#endif
186
187 SC threshold = .01;
188 Set<bool>(currentLevel, "Filtering", (threshold != STS::zero()));
189 Set(currentLevel, "Graph", filteredGraph);
190 Set(currentLevel, "DofsPerNode", 1);
191
192} // Build
193
194template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
195void SmooVecCoalesceDropFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::badGuysCoalesceDrop(const Matrix& Amat, Teuchos::ArrayRCP<Scalar>& penaltyPolyCoef, LO nPDEs, const MultiVector& testVecs, const MultiVector& nearNull, RCP<LWGraph>& filteredGraph) const {
196 /*
197 * Compute coalesce/drop graph (in filteredGraph) for A. The basic idea is to
198 * balance trade-offs associated with
199 *
200 * (I - P inv(R P) R ) testVecs
201 *
202 * being worse for larger aggregates (less dropping) while MG cycle costs are
203 * cheaper with larger aggregates. MG costs are "penalties" in the
204 * optimization while (I - P inv(R P) R ) is the "fit" (how well a
205 * a fine grid function can be approximated on the coarse grid).
206 *
207 * For MG costs, we don't actually approximate the cost. Instead, we
208 * have just hardwired penalties below. Specifically,
209 *
210 * penalties[j] is the cost if aggregates are of size j+1, where right
211 * now a linear function of the form const*(60-j) is used.
212 *
213 * (I - P inv(P^T P) P^T ) testVecs is estimated by just looking locally at
214 * the vector portion corresponding to a possible aggregate defined by
215 * all non-dropped connections in the ith row. A tentative prolognator is
216 * used for P. This prolongator corresponds to a null space vector given
217 * by 'nearNull', which is provided to dropper(). In initial testing, nearNull is
218 * first set as a vector of all 1's and then smoothed with a relaxation
219 * method applied to a nice matrix (with the same sparsity pattern as A).
220 * Originally, nearNull was used to handle Dir bcs where relaxation of the
221 * vector of 1's has a more pronounced effect.
222 *
223 * For PDE systems, fit only considers the same dof at each node. That is,
224 * it effectively assumes that we have a tentative prolongator with no
225 * coupling between different dof types. When checking the fit for the kth
226 * dof at a paritcular node, it only considers the kth dof of this node
227 * and neighboring nodes.
228 *
229 * Note: testVecs is supplied by the user, but normally is the result of
230 * applying a relaxation scheme to Au = 0 where u is initial random.
231 */
232
233 GO numMyNnz = Teuchos::as<GO>(Amat.getLocalNumEntries());
234 size_t nLoc = Amat.getRowMap()->getLocalNumElements();
235
236 size_t nBlks = nLoc / nPDEs;
237 if (nBlks * nPDEs != nLoc)
238 TEUCHOS_TEST_FOR_EXCEPTION(true, Exceptions::RuntimeError, "Number of local dofs not divisible by BlkSize");
239
240 typename LWGraph::row_type::non_const_type newRowPtr("newRowPtr", nBlks + 1); /* coalesce & drop matrix */
241 Teuchos::ArrayRCP<LO> newCols(numMyNnz); /* arrays */
242
243 Teuchos::ArrayRCP<LO> bcols(nBlks); /* returned by dropfun(j,...) */
244 Teuchos::ArrayRCP<bool> keepOrNot(nBlks); /* gives cols for jth row and */
245 /* whether or not entry is */
246 /* kept or dropped. */
247
248 LO maxNzPerRow = 200;
249 Teuchos::ArrayRCP<Scalar> penalties(maxNzPerRow); /* Penalty function */
250 /* described above. */
251
252 Teuchos::ArrayRCP<bool> keepStatus(nBlks, true); /* accumulated keepOrNot info */
253 Teuchos::ArrayRCP<LO> bColList(nBlks); /* accumulated bcols info */
254 /* for an entire block as */
255 /* opposed to a single row */
256 /* Additionally, keepOrNot[j] */
257 /* refers to status of jth */
258 /* entry in a row while */
259 /* keepStatus[j] refers to */
260 /* whether the jth block is */
261 /* kept within the block row. */
262
263 Teuchos::ArrayRCP<bool> alreadyOnBColList(nBlks, false); /* used to avoid recording the*/
264 /* same block column when */
265 /* processing different pt */
266 /* rows within a block. */
267
268 typename LWGraph::boundary_nodes_type boundaryNodes("boundaryNodes", nBlks);
269 Kokkos::deep_copy(boundaryNodes, false);
270
271 for (LO i = 0; i < maxNzPerRow; i++)
272 penalties[i] = penaltyPolyCoef[poly0thOrderCoef] +
273 penaltyPolyCoef[poly1stOrderCoef] * (as<Scalar>(i)) +
274 penaltyPolyCoef[poly2ndOrderCoef] * (as<Scalar>(i * i)) +
275 (penaltyPolyCoef[poly3rdOrderCoef] * (as<Scalar>(i * i)) * (as<Scalar>(i))) + // perhaps avoids overflow?
276 (penaltyPolyCoef[poly4thOrderCoef] * (as<Scalar>(i * i)) * (as<Scalar>(i * i)));
277
278 LO nzTotal = 0, numBCols = 0, row = -1, Nbcols, bcol;
279 newRowPtr(0) = 0;
280
281 /* proceed block by block */
282 for (LO i = 0; i < as<LO>(nBlks); i++) {
283 newRowPtr[i + 1] = newRowPtr[i];
284 for (LO j = 0; j < nPDEs; j++) {
285 row = row + 1;
286
287 Teuchos::ArrayView<const LocalOrdinal> indices;
288 Teuchos::ArrayView<const Scalar> vals;
289
290 Amat.getLocalRowView(row, indices, vals);
291
292 if (indices.size() > maxNzPerRow) {
293 LO oldSize = maxNzPerRow;
294 maxNzPerRow = indices.size() + 100;
295 penalties.resize(as<size_t>(maxNzPerRow), 0.0);
296 for (LO k = oldSize; k < maxNzPerRow; k++)
297 penalties[k] = penaltyPolyCoef[poly0thOrderCoef] +
298 penaltyPolyCoef[poly1stOrderCoef] * (as<Scalar>(i)) +
299 penaltyPolyCoef[poly2ndOrderCoef] * (as<Scalar>(i * i)) +
300 (penaltyPolyCoef[poly3rdOrderCoef] * (as<Scalar>(i * i)) * (as<Scalar>(i))) +
301 (penaltyPolyCoef[poly4thOrderCoef] * (as<Scalar>(i * i)) * (as<Scalar>(i * i)));
302 }
303 badGuysDropfunc(row, indices, vals, testVecs, nPDEs, penalties, nearNull, bcols, keepOrNot, Nbcols, nLoc);
304 for (LO k = 0; k < Nbcols; k++) {
305 bcol = bcols[k];
306
307 /* add to bColList if not already on it */
308
309 if (alreadyOnBColList[bcol] == false) { /* for PDE systems only record */
310 bColList[numBCols++] = bcol; /* neighboring block one time */
311 alreadyOnBColList[bcol] = true;
312 }
313 /* drop if any pt row within block indicates entry should be dropped */
314
315 if (keepOrNot[k] == false) keepStatus[bcol] = false;
316
317 } /* for (k=0; k < Nbcols; k++) */
318 } /* for (j = 0; i < nPDEs; j++) */
319
320 /* finished with block row. Now record block entries that we keep */
321 /* and reset keepStatus, bColList, and alreadyOnBColList. */
322
323 if (numBCols < 2) boundaryNodes[i] = true;
324 for (LO j = 0; j < numBCols; j++) {
325 bcol = bColList[j];
326 if (keepStatus[bcol] == true) {
327 newCols[nzTotal] = bColList[j];
328 newRowPtr(i + 1)++;
329 nzTotal = nzTotal + 1;
330 }
331 keepStatus[bcol] = true;
332 alreadyOnBColList[bcol] = false;
333 bColList[j] = 0;
334 }
335 numBCols = 0;
336 } /* for (i = 0; i < nBlks; i++) */
337
338 /* create array of the correct size and copy over newCols to it */
339
340 typename LWGraph::entries_type::non_const_type finalCols("finalCols", nzTotal);
341 for (LO i = 0; i < nzTotal; i++) finalCols(i) = newCols[i];
342
343 // Not using column map because we do not allow for any off-proc stuff.
344 // Not sure if this is okay. FIXME
345
346 RCP<const Map> rowMap = Amat.getRowMap(); // , colMap = Amat.getColMap();
347
348 LO nAmalgNodesOnProc = rowMap->getLocalNumElements() / nPDEs;
349 Teuchos::Array<GO> nodalGIDs(nAmalgNodesOnProc);
350 typename Teuchos::ScalarTraits<Scalar>::coordinateType temp;
351 for (size_t i = 0; i < as<size_t>(nAmalgNodesOnProc); i++) {
352 GO gid = rowMap->getGlobalElement(i * nPDEs);
353 temp = ((typename Teuchos::ScalarTraits<Scalar>::coordinateType)(gid)) / ((typename Teuchos::ScalarTraits<Scalar>::coordinateType)(nPDEs));
354 nodalGIDs[i] = as<GO>(floor(temp));
355 }
356 GO nAmalgNodesGlobal = rowMap->getGlobalNumElements();
357 GO nBlkGlobal = nAmalgNodesGlobal / nPDEs;
358 if (nBlkGlobal * nPDEs != nAmalgNodesGlobal)
359 TEUCHOS_TEST_FOR_EXCEPTION(true, Exceptions::RuntimeError, "Number of global dofs not divisible by BlkSize");
360
361 Teuchos::RCP<Map> AmalgRowMap = MapFactory::Build(rowMap->lib(), nBlkGlobal,
362 nodalGIDs(), 0, rowMap->getComm());
363
364 filteredGraph = rcp(new LWGraph(newRowPtr, finalCols, AmalgRowMap, AmalgRowMap, "thresholded graph of A"));
365 filteredGraph->SetBoundaryNodeMap(boundaryNodes);
366}
367
368template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
369void SmooVecCoalesceDropFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::badGuysDropfunc(LO row, const Teuchos::ArrayView<const LocalOrdinal>& cols, const Teuchos::ArrayView<const Scalar>& vals, const MultiVector& testVecs, LO nPDEs, Teuchos::ArrayRCP<Scalar>& penalties, const MultiVector& nearNull, Teuchos::ArrayRCP<LO>& Bcols, Teuchos::ArrayRCP<bool>& keepOrNot, LO& Nbcols, LO nLoc) const {
370 using TST = Teuchos::ScalarTraits<Scalar>;
371
372 LO nLeng = cols.size();
373 typename TST::coordinateType temp;
374 temp = ((typename TST::coordinateType)(row)) / ((typename TST::coordinateType)(nPDEs));
375 LO blkRow = as<LO>(floor(temp));
376 Teuchos::ArrayRCP<Scalar> badGuy(nLeng, 0.0);
377 Teuchos::ArrayRCP<Scalar> subNull(nLeng, 0.0); /* subset of nearNull */
378 /* associated with current */
379 /* dof within node. */
380
381 /* Only consider testVecs associated with same dof & on processor. Further */
382 /* collapse testVecs to a single badGuy vector by basically taking the worst */
383 /* (least smooth) values for each of the off diags. In particular, we look at*/
384 /* the ratio of each off-diag test value / diag test value and compare this */
385 /* with the nearNull vector ratio. The further the testVec ratio is from the */
386 /* nearNull ratio, the harder is will be to accurately interpolate is these */
387 /* two guys are aggregated. So, the biggest ratio mismatch is used to choose */
388 /* the testVec entry associated with each off-diagonal entry. */
389
390 for (LO i = 0; i < nLeng; i++) keepOrNot[i] = false;
391
392 LO diagInd = -1;
393 Nbcols = 0;
394 LO rowDof = row - blkRow * nPDEs;
395 Teuchos::ArrayRCP<const Scalar> oneNull = nearNull.getData(as<size_t>(rowDof));
396
397 for (LO i = 0; i < nLeng; i++) {
398 if ((cols[i] < nLoc) && (TST::magnitude(vals[i]) != 0.0)) { /* on processor */
399 temp = ((typename TST::coordinateType)(cols[i])) / ((typename TST::coordinateType)(nPDEs));
400 LO colDof = cols[i] - (as<LO>(floor(temp))) * nPDEs;
401 if (colDof == rowDof) { /* same dof within node as row */
402 Bcols[Nbcols] = (cols[i] - colDof) / nPDEs;
403 subNull[Nbcols] = oneNull[cols[i]];
404
405 if (cols[i] != row) { /* not diagonal */
406 Scalar worstRatio = -TST::one();
407 Scalar targetRatio = subNull[Nbcols] / oneNull[row];
408 Scalar actualRatio;
409 for (size_t kk = 0; kk < testVecs.getNumVectors(); kk++) {
410 Teuchos::ArrayRCP<const Scalar> curVec = testVecs.getData(kk);
411 actualRatio = curVec[cols[i]] / curVec[row];
412 if (TST::magnitude(actualRatio - targetRatio) > TST::magnitude(worstRatio)) {
413 badGuy[Nbcols] = actualRatio;
414 worstRatio = Teuchos::ScalarTraits<SC>::magnitude(actualRatio - targetRatio);
415 }
416 }
417 } else {
418 badGuy[Nbcols] = 1.;
419 keepOrNot[Nbcols] = true;
420 diagInd = Nbcols;
421 }
422 (Nbcols)++;
423 }
424 }
425 }
426
427 /* Make sure that diagonal entry is in block col list */
428
429 if (diagInd == -1) {
430 Bcols[Nbcols] = (row - rowDof) / nPDEs;
431 subNull[Nbcols] = 1.;
432 badGuy[Nbcols] = 1.;
433 keepOrNot[Nbcols] = true;
434 diagInd = Nbcols;
435 (Nbcols)++;
436 }
437
438 Scalar currentRP = oneNull[row] * oneNull[row];
439 Scalar currentRTimesBadGuy = oneNull[row] * badGuy[diagInd];
440 Scalar currentScore = penalties[0]; /* (I - P inv(R*P)*R )=0 for size */
441 /* size 1 agg, so fit is perfect */
442
443 /* starting from a set that only includes the diagonal entry consider adding */
444 /* one off-diagonal at a time until the fitValue exceeds the penalty term. */
445 /* Here, the fit value is (I - P inv(R P) R ) and we always consider the */
446 /* lowest fitValue that is not currently in the set. R and P correspond to */
447 /* a simple tentaive grid transfer associated with an aggregate that */
448 /* includes the diagonal, all already determined neighbors, and the potential*/
449 /* new neighbor */
450
451 LO nKeep = 1, flag = 1, minId;
452 Scalar minFit, minFitRP = 0., minFitRTimesBadGuy = 0.;
453 Scalar newRP, newRTimesBadGuy;
454
455 while (flag == 1) {
456 /* compute a fit for each possible off-diagonal neighbor */
457 /* that has not already been added as a neighbor */
458
459 minFit = 1000000.;
460 minId = -1;
461
462 for (LO i = 0; i < Nbcols; i++) {
463 if (keepOrNot[i] == false) {
464 keepOrNot[i] = true; /* temporarily view i as non-dropped neighbor */
465 newRP = currentRP + subNull[i] * subNull[i];
466 newRTimesBadGuy = currentRTimesBadGuy + subNull[i] * badGuy[i];
467 Scalar ratio = newRTimesBadGuy / newRP;
468
469 Scalar newFit = 0.0;
470 for (LO k = 0; k < Nbcols; k++) {
471 if (keepOrNot[k] == true) {
472 Scalar diff = badGuy[k] - ratio * subNull[k];
473 newFit = newFit + diff * diff;
474 }
475 }
476 if (Teuchos::ScalarTraits<SC>::magnitude(newFit) < Teuchos::ScalarTraits<SC>::magnitude(minFit)) {
477 minId = i;
478 minFit = newFit;
479 minFitRP = newRP;
480 minFitRTimesBadGuy = newRTimesBadGuy;
481 }
482 keepOrNot[i] = false;
483 }
484 }
485 if (minId == -1)
486 flag = 0;
487 else {
488 minFit = sqrt(minFit);
489 Scalar newScore = penalties[nKeep] + minFit;
490 if (Teuchos::ScalarTraits<SC>::magnitude(newScore) < Teuchos::ScalarTraits<SC>::magnitude(currentScore)) {
491 nKeep = nKeep + 1;
492 keepOrNot[minId] = true;
493 currentScore = newScore;
494 currentRP = minFitRP;
495 currentRTimesBadGuy = minFitRTimesBadGuy;
496 } else
497 flag = 0;
498 }
499 }
500}
501
502} // namespace MueLu
503
504#endif // MUELU_SMOOVECCOALESCEDROPFACTORY_DEF_HPP
#define SET_VALID_ENTRY(name)
MueLu::DefaultScalar Scalar
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.
Kokkos::View< bool *, memory_space > boundary_nodes_type
Lightweight MueLu representation of a compressed row storage graph.
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.
T & Get(const std::string &ename, const FactoryBase *factory=NoFactory::get())
Get data without decrementing associated storage counter (i.e., read-only access)....
void Build(Level &currentLevel) const
Build an object with this factory.
void badGuysDropfunc(LO row, const Teuchos::ArrayView< const LocalOrdinal > &indices, const Teuchos::ArrayView< const Scalar > &vals, const MultiVector &smoothedTVecs, LO nPDEs, Teuchos::ArrayRCP< Scalar > &penalties, const MultiVector &smoothedNull, Teuchos::ArrayRCP< LO > &Bcols, Teuchos::ArrayRCP< bool > &keepOrNot, LO &Nbcols, LO nLoc) const
void badGuysCoalesceDrop(const Matrix &Amat, Teuchos::ArrayRCP< Scalar > &dropParams, LO nPDEs, const MultiVector &smoothedTVecs, const MultiVector &smoothedNull, RCP< LWGraph > &filteredGraph) const
Methods to support compatible-relaxation style dropping.
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
void DeclareInput(Level &currentLevel) const
Input.
Namespace for MueLu classes and methods.
@ Parameters0
Print class parameters.