MueLu Version of the Day
Loading...
Searching...
No Matches
MueLu_RAPShiftFactory_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
46#ifndef MUELU_RAPSHIFTFACTORY_DEF_HPP
47#define MUELU_RAPSHIFTFACTORY_DEF_HPP
48
49#include <sstream>
50
51#include <Xpetra_Matrix.hpp>
52#include <Xpetra_MatrixMatrix.hpp>
53#include <Xpetra_MatrixUtils.hpp>
54#include <Xpetra_Vector.hpp>
55#include <Xpetra_VectorFactory.hpp>
56
57
59#include "MueLu_MasterList.hpp"
60#include "MueLu_Monitor.hpp"
61#include "MueLu_PerfUtils.hpp"
62
63namespace MueLu {
64
65 /*********************************************************************************************************/
66 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
69
70
71 /*********************************************************************************************************/
72 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
74 RCP<ParameterList> validParamList = rcp(new ParameterList());
75
76#define SET_VALID_ENTRY(name) validParamList->setEntry(name, MasterList::getEntry(name))
77 SET_VALID_ENTRY("transpose: use implicit");
78 SET_VALID_ENTRY("rap: fix zero diagonals");
79 SET_VALID_ENTRY("rap: shift");
80 SET_VALID_ENTRY("rap: shift array");
81 SET_VALID_ENTRY("rap: cfl array");
82 SET_VALID_ENTRY("rap: shift diagonal M");
83 SET_VALID_ENTRY("rap: shift low storage");
84 SET_VALID_ENTRY("rap: relative diagonal floor");
85#undef SET_VALID_ENTRY
86
87 validParamList->set< RCP<const FactoryBase> >("A", Teuchos::null, "Generating factory of the matrix A used during the prolongator smoothing process");
88 validParamList->set< RCP<const FactoryBase> >("M", Teuchos::null, "Generating factory of the matrix M used during the non-Galerkin RAP");
89 validParamList->set< RCP<const FactoryBase> >("Mdiag", Teuchos::null, "Generating factory of the matrix Mdiag used during the non-Galerkin RAP");
90 validParamList->set< RCP<const FactoryBase> >("K", Teuchos::null, "Generating factory of the matrix K used during the non-Galerkin RAP");
91 validParamList->set< RCP<const FactoryBase> >("P", Teuchos::null, "Prolongator factory");
92 validParamList->set< RCP<const FactoryBase> >("R", Teuchos::null, "Restrictor factory");
93
94 validParamList->set< bool > ("CheckMainDiagonal", false, "Check main diagonal for zeros");
95 validParamList->set< bool > ("RepairMainDiagonal", false, "Repair zeros on main diagonal");
96
97 validParamList->set<RCP<const FactoryBase> > ("deltaT", Teuchos::null, "user deltaT");
98 validParamList->set<RCP<const FactoryBase> > ("cfl", Teuchos::null, "user cfl");
99 validParamList->set<RCP<const FactoryBase> > ("cfl-based shift array", Teuchos::null, "MueLu-generated shift array for CFL-based shifting");
100
101 // Make sure we don't recursively validate options for the matrixmatrix kernels
102 ParameterList norecurse;
103 norecurse.disableRecursiveValidation();
104 validParamList->set<ParameterList> ("matrixmatrix: kernel params", norecurse, "MatrixMatrix kernel parameters");
105
106 return validParamList;
107 }
108
109 /*********************************************************************************************************/
110 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
112 const Teuchos::ParameterList& pL = GetParameterList();
113
114 bool use_mdiag = false;
115 if(pL.isParameter("rap: shift diagonal M"))
116 use_mdiag = pL.get<bool>("rap: shift diagonal M");
117
118 // The low storage version requires mdiag
119 bool use_low_storage = false;
120 if(pL.isParameter("rap: shift low storage")) {
121 use_low_storage = pL.get<bool>("rap: shift low storage");
122 use_mdiag = use_low_storage ? true : use_mdiag;
123 }
124
125 if (implicitTranspose_ == false) {
126 Input(coarseLevel, "R");
127 }
128
129 if(!use_low_storage) Input(fineLevel, "K");
130 else Input(fineLevel, "A");
131 Input(coarseLevel, "P");
132
133 if(!use_mdiag) Input(fineLevel, "M");
134 else Input(fineLevel, "Mdiag");
135
136 // CFL array stuff
137 if(pL.isParameter("rap: cfl array") && pL.get<Teuchos::Array<double> >("rap: cfl array").size() > 0) {
138 if(fineLevel.GetLevelID() == 0) {
139 if(fineLevel.IsAvailable("deltaT", NoFactory::get())) {
140 fineLevel.DeclareInput("deltaT", NoFactory::get(), this);
141 } else {
142 TEUCHOS_TEST_FOR_EXCEPTION(fineLevel.IsAvailable("fine deltaT", NoFactory::get()),
144 "deltaT was not provided by the user on level0!");
145 }
146
147 if(fineLevel.IsAvailable("cfl", NoFactory::get())) {
148 fineLevel.DeclareInput("cfl", NoFactory::get(), this);
149 } else {
150 TEUCHOS_TEST_FOR_EXCEPTION(fineLevel.IsAvailable("fine cfl", NoFactory::get()),
152 "cfl was not provided by the user on level0!");
153 }
154 }
155 else {
156 Input(fineLevel,"cfl-based shift array");
157 }
158 }
159
160 // call DeclareInput of all user-given transfer factories
161 for(std::vector<RCP<const FactoryBase> >::const_iterator it = transferFacts_.begin(); it!=transferFacts_.end(); ++it) {
162 (*it)->CallDeclareInput(coarseLevel);
163 }
164 }
165
166 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
167 void RAPShiftFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(Level &fineLevel, Level &coarseLevel) const { // FIXME make fineLevel const
168 {
169 FactoryMonitor m(*this, "Computing Ac", coarseLevel);
170 const Teuchos::ParameterList& pL = GetParameterList();
171
172 bool M_is_diagonal = false;
173 if(pL.isParameter("rap: shift diagonal M"))
174 M_is_diagonal = pL.get<bool>("rap: shift diagonal M");
175
176 // The low storage version requires mdiag
177 bool use_low_storage = false;
178 if(pL.isParameter("rap: shift low storage")) {
179 use_low_storage = pL.get<bool>("rap: shift low storage");
180 M_is_diagonal = use_low_storage ? true : M_is_diagonal;
181 }
182
183 Teuchos::ArrayView<const double> doubleShifts;
184 Teuchos::ArrayRCP<double> myshifts;
185 if(pL.isParameter("rap: shift array") && pL.get<Teuchos::Array<double> >("rap: shift array").size() > 0 ) {
186 // Do we have an array of shifts? If so, we set doubleShifts_
187 doubleShifts = pL.get<Teuchos::Array<double> >("rap: shift array")();
188 }
189 if(pL.isParameter("rap: cfl array") && pL.get<Teuchos::Array<double> >("rap: cfl array").size() > 0) {
190 // Do we have an array of CFLs? If so, we calculated the shifts from them.
191 Teuchos::ArrayView<const double> CFLs = pL.get<Teuchos::Array<double> >("rap: cfl array")();
192 if(fineLevel.GetLevelID() == 0) {
193 double dt = Get<double>(fineLevel,"deltaT");
194 double cfl = Get<double>(fineLevel,"cfl");
195 double ts_at_cfl1 = dt / cfl;
196 myshifts.resize(CFLs.size());
197 Teuchos::Array<double> myCFLs(CFLs.size());
198 myCFLs[0] = cfl;
199
200 // Never make the CFL bigger
201 for(int i=1; i<(int)CFLs.size(); i++)
202 myCFLs[i] = (CFLs[i]> cfl) ? cfl : CFLs[i];
203
204 {
205 std::ostringstream ofs;
206 ofs<<"RAPShiftFactory: CFL schedule = ";
207 for(int i=0; i<(int)CFLs.size(); i++)
208 ofs<<" "<<myCFLs[i];
209 GetOStream(Statistics0) <<ofs.str() << std::endl;
210 }
211 GetOStream(Statistics0)<< "RAPShiftFactory: Timestep at CFL=1 is "<< ts_at_cfl1 << " " <<std::endl;
212
213 // The shift array needs to be 1/dt
214 for(int i=0; i<(int)myshifts.size(); i++)
215 myshifts[i] = 1.0 / (ts_at_cfl1*myCFLs[i]);
216 doubleShifts = myshifts();
217
218 {
219 std::ostringstream ofs;
220 ofs<<"RAPShiftFactory: shift schedule = ";
221 for(int i=0; i<(int)doubleShifts.size(); i++)
222 ofs<<" "<<doubleShifts[i];
223 GetOStream(Statistics0) <<ofs.str() << std::endl;
224 }
225 Set(coarseLevel,"cfl-based shift array",myshifts);
226 }
227 else {
228 myshifts = Get<Teuchos::ArrayRCP<double> > (fineLevel,"cfl-based shift array");
229 doubleShifts = myshifts();
230 Set(coarseLevel,"cfl-based shift array",myshifts);
231 // NOTE: If we're not on level zero, then we should have a shift array
232 }
233 }
234
235 // Inputs: K, M, P
236 // Note: In the low-storage case we do not keep a separate "K", we just use A
237 RCP<Matrix> K;
238 RCP<Matrix> M;
239 RCP<Vector> Mdiag;
240
241 if(use_low_storage) K = Get< RCP<Matrix> >(fineLevel, "A");
242 else K = Get< RCP<Matrix> >(fineLevel, "K");
243 if(!M_is_diagonal) M = Get< RCP<Matrix> >(fineLevel, "M");
244 else Mdiag = Get< RCP<Vector> >(fineLevel, "Mdiag");
245
246 RCP<Matrix> P = Get< RCP<Matrix> >(coarseLevel, "P");
247
248 // Build Kc = RKP, Mc = RMP
249 RCP<Matrix> KP, MP;
250
251 // Reuse pattern if available (multiple solve)
252 // FIXME: Old style reuse doesn't work any more
253 // if (IsAvailable(coarseLevel, "AP Pattern")) {
254 // KP = Get< RCP<Matrix> >(coarseLevel, "AP Pattern");
255 // MP = Get< RCP<Matrix> >(coarseLevel, "AP Pattern");
256 // }
257
258 {
259 SubFactoryMonitor subM(*this, "MxM: K x P", coarseLevel);
260 KP = Xpetra::MatrixMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Multiply(*K, false, *P, false, KP, GetOStream(Statistics2));
261 if(!M_is_diagonal) {
262 MP = Xpetra::MatrixMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Multiply(*M, false, *P, false, MP, GetOStream(Statistics2));
263 }
264 else {
265 MP = Xpetra::MatrixFactory2<Scalar, LocalOrdinal, GlobalOrdinal, Node>::BuildCopy(P);
266 MP->leftScale(*Mdiag);
267 }
268
269 Set(coarseLevel, "AP Pattern", KP);
270 }
271
272 bool doOptimizedStorage = true;
273
274 RCP<Matrix> Ac, Kc, Mc;
275
276 // Reuse pattern if available (multiple solve)
277 // if (IsAvailable(coarseLevel, "RAP Pattern"))
278 // Ac = Get< RCP<Matrix> >(coarseLevel, "RAP Pattern");
279
280 bool doFillComplete=true;
281 if (implicitTranspose_) {
282 SubFactoryMonitor m2(*this, "MxM: P' x (KP) (implicit)", coarseLevel);
283 Kc = Xpetra::MatrixMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Multiply(*P, true, *KP, false, Kc, GetOStream(Statistics2), doFillComplete, doOptimizedStorage);
284 Mc = Xpetra::MatrixMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Multiply(*P, true, *MP, false, Mc, GetOStream(Statistics2), doFillComplete, doOptimizedStorage);
285 }
286 else {
287 RCP<Matrix> R = Get< RCP<Matrix> >(coarseLevel, "R");
288 SubFactoryMonitor m2(*this, "MxM: R x (KP) (explicit)", coarseLevel);
289 Kc = Xpetra::MatrixMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Multiply(*R, false, *KP, false, Kc, GetOStream(Statistics2), doFillComplete, doOptimizedStorage);
290 Mc = Xpetra::MatrixMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Multiply(*R, false, *MP, false, Mc, GetOStream(Statistics2), doFillComplete, doOptimizedStorage);
291 }
292
293 // Get the shift
294 // FIXME - We should really get rid of the shifts array and drive this the same way everything else works
295 // If we're using the recursive "low storage" version, we need to shift by ( \prod_{i=1}^k shift[i] - \prod_{i=1}^{k-1} shift[i]) to
296 // get the recursive relationships correct
297 int level = coarseLevel.GetLevelID();
298 Scalar shift = Teuchos::ScalarTraits<Scalar>::zero();
299 if(!use_low_storage) {
300 // High Storage version
301 if(level < (int)shifts_.size()) shift = shifts_[level];
302 else shift = Teuchos::as<Scalar>(pL.get<double>("rap: shift"));
303 }
304 else {
305 // Low Storage Version
306 if(level < (int)shifts_.size()) {
307 if(level==1) shift = shifts_[level];
308 else {
309 Scalar prod1 = Teuchos::ScalarTraits<Scalar>::one();
310 for(int i=1; i < level-1; i++) {
311 prod1 *= shifts_[i];
312 }
313 shift = (prod1 * shifts_[level] - prod1);
314 }
315 }
316 else if(doubleShifts.size() != 0) {
317 double d_shift = 0.0;
318 if(level < doubleShifts.size())
319 d_shift = doubleShifts[level] - doubleShifts[level-1];
320
321 if(d_shift < 0.0)
322 GetOStream(Warnings1) << "WARNING: RAPShiftFactory has detected a negative shift... This implies a less stable coarse grid."<<std::endl;
323 shift = Teuchos::as<Scalar>(d_shift);
324 }
325 else {
326 double base_shift = pL.get<double>("rap: shift");
327 if(level == 1) shift = Teuchos::as<Scalar>(base_shift);
328 else shift = Teuchos::as<Scalar>(pow(base_shift,level) - pow(base_shift,level-1));
329 }
330 }
331 GetOStream(Runtime0) << "RAPShiftFactory: Using shift " << shift << std::endl;
332
333
334 // recombine to get K+shift*M
335 {
336 SubFactoryMonitor m2(*this, "Add: RKP + s*RMP", coarseLevel);
337 Xpetra::MatrixMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node>::TwoMatrixAdd(*Kc, false, Teuchos::ScalarTraits<Scalar>::one(), *Mc, false, shift, Ac, GetOStream(Statistics2));
338 Ac->fillComplete();
339 }
340
341 Teuchos::ArrayView<const double> relativeFloor = pL.get<Teuchos::Array<double> >("rap: relative diagonal floor")();
342 if(relativeFloor.size() > 0)
343 Xpetra::MatrixUtils<SC,LO,GO,NO>::RelativeDiagonalBoost(Ac, relativeFloor,GetOStream(Statistics2));
344
345
346 bool repairZeroDiagonals = pL.get<bool>("RepairMainDiagonal") || pL.get<bool>("rap: fix zero diagonals");
347 bool checkAc = pL.get<bool>("CheckMainDiagonal")|| pL.get<bool>("rap: fix zero diagonals"); ;
348 if (checkAc || repairZeroDiagonals)
349 Xpetra::MatrixUtils<SC,LO,GO,NO>::CheckRepairMainDiagonal(Ac, repairZeroDiagonals, GetOStream(Warnings1));
350
351 RCP<ParameterList> params = rcp(new ParameterList());;
352 params->set("printLoadBalancingInfo", true);
354
355 Set(coarseLevel, "A", Ac);
356 // We only need K in the 'high storage' mode
357 if(!use_low_storage)
358 Set(coarseLevel, "K", Kc);
359
360 if(!M_is_diagonal) {
361 Set(coarseLevel, "M", Mc);
362 }
363 else {
364 // If M is diagonal, then we only pass that part down the hierarchy
365 // NOTE: Should we be doing some kind of rowsum instead?
366 RCP<Vector> Mcv = Xpetra::VectorFactory<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Build(Mc->getRowMap(),false);
367 Mc->getLocalDiagCopy(*Mcv);
368 Set(coarseLevel, "Mdiag", Mcv);
369 }
370
371 // Set(coarseLevel, "RAP Pattern", Ac);
372 }
373
374 if (transferFacts_.begin() != transferFacts_.end()) {
375 SubFactoryMonitor m(*this, "Projections", coarseLevel);
376
377 // call Build of all user-given transfer factories
378 for (std::vector<RCP<const FactoryBase> >::const_iterator it = transferFacts_.begin(); it != transferFacts_.end(); ++it) {
379 RCP<const FactoryBase> fac = *it;
380 GetOStream(Runtime0) << "RAPShiftFactory: call transfer factory: " << fac->description() << std::endl;
381 fac->CallBuild(coarseLevel);
382 // AP (11/11/13): I am not sure exactly why we need to call Release, but we do need it to get rid
383 // of dangling data for CoordinatesTransferFactory
384 coarseLevel.Release(*fac);
385 }
386 }
387 }
388
389 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
391 // check if it's a TwoLevelFactoryBase based transfer factory
392 TEUCHOS_TEST_FOR_EXCEPTION(Teuchos::rcp_dynamic_cast<const TwoLevelFactoryBase>(factory) == Teuchos::null, Exceptions::BadCast, "MueLu::RAPShiftFactory::AddTransferFactory: Transfer factory is not derived from TwoLevelFactoryBase. This is very strange. (Note: you can remove this exception if there's a good reason for)");
393 transferFacts_.push_back(factory);
394 }
395
396} //namespace MueLu
397
398#define MUELU_RAPSHIFTFACTORY_SHORT
399#endif // MUELU_RAPSHIFTFACTORY_DEF_HPP
#define SET_VALID_ENTRY(name)
MueLu::DefaultScalar Scalar
Exception indicating invalid cast attempted.
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
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.
void DeclareInput(const std::string &ename, const FactoryBase *factory, const FactoryBase *requestedBy=NoFactory::get())
Callback from FactoryBase::CallDeclareInput() and FactoryBase::DeclareInput().
void Release(const FactoryBase &factory)
Decrement the storage counter for all the inputs of a factory.
int GetLevelID() const
Return level number.
static const NoFactory * get()
virtual const Teuchos::ParameterList & GetParameterList() const
static std::string PrintMatrixInfo(const Matrix &A, const std::string &msgTag, RCP< const Teuchos::ParameterList > params=Teuchos::null)
void DeclareInput(Level &fineLevel, Level &coarseLevel) const
Input.
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
void AddTransferFactory(const RCP< const FactoryBase > &factory)
Add transfer factory in the end of list of transfer factories in RepartitionAcFactory.
std::vector< RCP< const FactoryBase > > transferFacts_
list of user-defined transfer Factories
bool implicitTranspose_
If true, the action of the restriction operator action is implicitly defined by the transpose of the ...
void Build(Level &fineLevel, Level &coarseLevel) const
Build an object with this factory.
Timer to be used in factories. Similar to SubMonitor but adds a timer level by level.
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.
@ Statistics2
Print even more statistics.
@ Runtime0
One-liner description of what is happening.
@ Warnings1
Additional warnings.
@ Statistics0
Print statistics that do not involve significant additional computation.