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