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