MueLu Version of the Day
Loading...
Searching...
No Matches
MueLu_RAPFactory_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_RAPFACTORY_DEF_HPP
47#define MUELU_RAPFACTORY_DEF_HPP
48
49
50#include <sstream>
51
52#include <Xpetra_Matrix.hpp>
53#include <Xpetra_MatrixFactory.hpp>
54#include <Xpetra_MatrixMatrix.hpp>
55#include <Xpetra_MatrixUtils.hpp>
56#include <Xpetra_TripleMatrixMultiply.hpp>
57#include <Xpetra_Vector.hpp>
58#include <Xpetra_VectorFactory.hpp>
59#include <Xpetra_IO.hpp>
60
62
63#include "MueLu_MasterList.hpp"
64#include "MueLu_Monitor.hpp"
65#include "MueLu_PerfUtils.hpp"
66//#include "MueLu_Utilities.hpp"
67
68namespace MueLu {
69
70 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
73
74 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
76 RCP<ParameterList> validParamList = rcp(new ParameterList());
77
78#define SET_VALID_ENTRY(name) validParamList->setEntry(name, MasterList::getEntry(name))
79 SET_VALID_ENTRY("transpose: use implicit");
80 SET_VALID_ENTRY("rap: triple product");
81 SET_VALID_ENTRY("rap: fix zero diagonals");
82 SET_VALID_ENTRY("rap: fix zero diagonals threshold");
83 SET_VALID_ENTRY("rap: fix zero diagonals replacement");
84 SET_VALID_ENTRY("rap: relative diagonal floor");
85#undef SET_VALID_ENTRY
86 validParamList->set< RCP<const FactoryBase> >("A", null, "Generating factory of the matrix A used during the prolongator smoothing process");
87 validParamList->set< RCP<const FactoryBase> >("P", null, "Prolongator factory");
88 validParamList->set< RCP<const FactoryBase> >("R", null, "Restrictor factory");
89
90 validParamList->set< bool > ("CheckMainDiagonal", false, "Check main diagonal for zeros");
91 validParamList->set< bool > ("RepairMainDiagonal", false, "Repair zeros on main diagonal");
92
93 // Make sure we don't recursively validate options for the matrixmatrix kernels
94 ParameterList norecurse;
95 norecurse.disableRecursiveValidation();
96 validParamList->set<ParameterList> ("matrixmatrix: kernel params", norecurse, "MatrixMatrix kernel parameters");
97
98 return validParamList;
99 }
100
101 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
103 const Teuchos::ParameterList& pL = GetParameterList();
104 if (pL.get<bool>("transpose: use implicit") == false)
105 Input(coarseLevel, "R");
106
107 Input(fineLevel, "A");
108 Input(coarseLevel, "P");
109
110 // call DeclareInput of all user-given transfer factories
111 for (std::vector<RCP<const FactoryBase> >::const_iterator it = transferFacts_.begin(); it != transferFacts_.end(); ++it)
112 (*it)->CallDeclareInput(coarseLevel);
113
114 hasDeclaredInput_ = true;
115 }
116
117 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
119 const bool doTranspose = true;
120 const bool doFillComplete = true;
121 const bool doOptimizeStorage = true;
122 RCP<Matrix> Ac;
123 {
124 FactoryMonitor m(*this, "Computing Ac", coarseLevel);
125 std::ostringstream levelstr;
126 levelstr << coarseLevel.GetLevelID();
127 std::string labelstr = FormattingHelper::getColonLabel(coarseLevel.getObjectLabel());
128
129 TEUCHOS_TEST_FOR_EXCEPTION(hasDeclaredInput_ == false, Exceptions::RuntimeError,
130 "MueLu::RAPFactory::Build(): CallDeclareInput has not been called before Build!");
131
132 const Teuchos::ParameterList& pL = GetParameterList();
133 RCP<Matrix> A = Get< RCP<Matrix> >(fineLevel, "A");
134 RCP<Matrix> P = Get< RCP<Matrix> >(coarseLevel, "P"), AP;
135 // We don't have a valid P (e.g., # global aggregates = 0) so we bail.
136 // This level will ultimately be removed in MueLu_Hierarchy_defs.h via a resize()
137 if (P == Teuchos::null) {
138 Ac = Teuchos::null;
139 Set(coarseLevel, "A", Ac);
140 return;
141 }
142
143 bool isEpetra = A->getRowMap()->lib() == Xpetra::UseEpetra;
144 bool isGPU =
145#ifdef KOKKOS_ENABLE_CUDA
146 (typeid(Node).name() == typeid(Tpetra::KokkosCompat::KokkosCudaWrapperNode).name()) ||
147#endif
148#ifdef KOKKOS_ENABLE_HIP
149 (typeid(Node).name() == typeid(Tpetra::KokkosCompat::KokkosHIPWrapperNode).name()) ||
150#endif
151#ifdef KOKKOS_ENABLE_SYCL
152 (typeid(Node).name() == typeid(Tpetra::KokkosCompat::KokkosSYCLWrapperNode).name()) ||
153#endif
154 false;
155
156 if (pL.get<bool>("rap: triple product") == false || isEpetra || isGPU) {
157 if (pL.get<bool>("rap: triple product") && isEpetra)
158 GetOStream(Warnings1) << "Switching from triple product to R x (A x P) since triple product has not been implemented for Epetra.\n";
159#if defined(KOKKOS_ENABLE_CUDA) || defined(KOKKOS_ENABLE_HIP) || defined(KOKKOS_ENABLE_SYCL)
160 if (pL.get<bool>("rap: triple product") && isGPU)
161 GetOStream(Warnings1) << "Switching from triple product to R x (A x P) since triple product has not been implemented for "
162 << Node::execution_space::name() << std::endl;
163#endif
164
165 // Reuse pattern if available (multiple solve)
166 RCP<ParameterList> APparams = rcp(new ParameterList);
167 if(pL.isSublist("matrixmatrix: kernel params"))
168 APparams->sublist("matrixmatrix: kernel params") = pL.sublist("matrixmatrix: kernel params");
169
170 // By default, we don't need global constants for A*P
171 APparams->set("compute global constants: temporaries",APparams->get("compute global constants: temporaries",false));
172 APparams->set("compute global constants",APparams->get("compute global constants",false));
173
174 if (coarseLevel.IsAvailable("AP reuse data", this)) {
175 GetOStream(static_cast<MsgType>(Runtime0 | Test)) << "Reusing previous AP data" << std::endl;
176
177 APparams = coarseLevel.Get< RCP<ParameterList> >("AP reuse data", this);
178
179 if (APparams->isParameter("graph"))
180 AP = APparams->get< RCP<Matrix> >("graph");
181 }
182
183 {
184 SubFactoryMonitor subM(*this, "MxM: A x P", coarseLevel);
185
186 AP = MatrixMatrix::Multiply(*A, !doTranspose, *P, !doTranspose, AP, GetOStream(Statistics2),
187 doFillComplete, doOptimizeStorage, labelstr+std::string("MueLu::A*P-")+levelstr.str(), APparams);
188 }
189
190 // Reuse coarse matrix memory if available (multiple solve)
191 RCP<ParameterList> RAPparams = rcp(new ParameterList);
192 if(pL.isSublist("matrixmatrix: kernel params"))
193 RAPparams->sublist("matrixmatrix: kernel params") = pL.sublist("matrixmatrix: kernel params");
194
195 if (coarseLevel.IsAvailable("RAP reuse data", this)) {
196 GetOStream(static_cast<MsgType>(Runtime0 | Test)) << "Reusing previous RAP data" << std::endl;
197
198 RAPparams = coarseLevel.Get< RCP<ParameterList> >("RAP reuse data", this);
199
200 if (RAPparams->isParameter("graph"))
201 Ac = RAPparams->get< RCP<Matrix> >("graph");
202
203 // Some eigenvalue may have been cached with the matrix in the previous run.
204 // As the matrix values will be updated, we need to reset the eigenvalue.
205 Ac->SetMaxEigenvalueEstimate(-Teuchos::ScalarTraits<SC>::one());
206 }
207
208 // We *always* need global constants for the RAP, but not for the temps
209 RAPparams->set("compute global constants: temporaries",RAPparams->get("compute global constants: temporaries",false));
210 RAPparams->set("compute global constants",true);
211
212 // Allow optimization of storage.
213 // This is necessary for new faster Epetra MM kernels.
214 // Seems to work with matrix modifications to repair diagonal entries.
215
216 if (pL.get<bool>("transpose: use implicit") == true) {
217 SubFactoryMonitor m2(*this, "MxM: P' x (AP) (implicit)", coarseLevel);
218
219 Ac = MatrixMatrix::Multiply(*P, doTranspose, *AP, !doTranspose, Ac, GetOStream(Statistics2),
220 doFillComplete, doOptimizeStorage, labelstr+std::string("MueLu::R*(AP)-implicit-")+levelstr.str(), RAPparams);
221
222 } else {
223 RCP<Matrix> R = Get< RCP<Matrix> >(coarseLevel, "R");
224
225 SubFactoryMonitor m2(*this, "MxM: R x (AP) (explicit)", coarseLevel);
226
227 Ac = MatrixMatrix::Multiply(*R, !doTranspose, *AP, !doTranspose, Ac, GetOStream(Statistics2),
228 doFillComplete, doOptimizeStorage, labelstr+std::string("MueLu::R*(AP)-explicit-")+levelstr.str(), RAPparams);
229 }
230
231 Teuchos::ArrayView<const double> relativeFloor = pL.get<Teuchos::Array<double> >("rap: relative diagonal floor")();
232 if(relativeFloor.size() > 0) {
233 Xpetra::MatrixUtils<SC,LO,GO,NO>::RelativeDiagonalBoost(Ac, relativeFloor,GetOStream(Statistics2));
234 }
235
236 bool repairZeroDiagonals = pL.get<bool>("RepairMainDiagonal") || pL.get<bool>("rap: fix zero diagonals");
237 bool checkAc = pL.get<bool>("CheckMainDiagonal")|| pL.get<bool>("rap: fix zero diagonals"); ;
238 if (checkAc || repairZeroDiagonals) {
239 using magnitudeType = typename Teuchos::ScalarTraits<Scalar>::magnitudeType;
240 magnitudeType threshold;
241 if (pL.isType<magnitudeType>("rap: fix zero diagonals threshold"))
242 threshold = pL.get<magnitudeType>("rap: fix zero diagonals threshold");
243 else
244 threshold = Teuchos::as<magnitudeType>(pL.get<double>("rap: fix zero diagonals threshold"));
245 Scalar replacement = Teuchos::as<Scalar>(pL.get<double>("rap: fix zero diagonals replacement"));
246 Xpetra::MatrixUtils<SC,LO,GO,NO>::CheckRepairMainDiagonal(Ac, repairZeroDiagonals, GetOStream(Warnings1), threshold, replacement);
247 }
248
249 if (IsPrint(Statistics2)) {
250 RCP<ParameterList> params = rcp(new ParameterList());;
251 params->set("printLoadBalancingInfo", true);
252 params->set("printCommInfo", true);
254 }
255
256 if(!Ac.is_null()) {std::ostringstream oss; oss << "A_" << coarseLevel.GetLevelID(); Ac->setObjectLabel(oss.str());}
257 Set(coarseLevel, "A", Ac);
258
259 if (!isGPU) {
260 APparams->set("graph", AP);
261 Set(coarseLevel, "AP reuse data", APparams);
262 }
263 if (!isGPU) {
264 RAPparams->set("graph", Ac);
265 Set(coarseLevel, "RAP reuse data", RAPparams);
266 }
267 } else {
268 RCP<ParameterList> RAPparams = rcp(new ParameterList);
269 if(pL.isSublist("matrixmatrix: kernel params"))
270 RAPparams->sublist("matrixmatrix: kernel params") = pL.sublist("matrixmatrix: kernel params");
271
272 if (coarseLevel.IsAvailable("RAP reuse data", this)) {
273 GetOStream(static_cast<MsgType>(Runtime0 | Test)) << "Reusing previous RAP data" << std::endl;
274
275 RAPparams = coarseLevel.Get< RCP<ParameterList> >("RAP reuse data", this);
276
277 if (RAPparams->isParameter("graph"))
278 Ac = RAPparams->get< RCP<Matrix> >("graph");
279
280 // Some eigenvalue may have been cached with the matrix in the previous run.
281 // As the matrix values will be updated, we need to reset the eigenvalue.
282 Ac->SetMaxEigenvalueEstimate(-Teuchos::ScalarTraits<SC>::one());
283 }
284
285 // We *always* need global constants for the RAP, but not for the temps
286 RAPparams->set("compute global constants: temporaries",RAPparams->get("compute global constants: temporaries",false));
287 RAPparams->set("compute global constants",true);
288
289 if (pL.get<bool>("transpose: use implicit") == true) {
290
291 Ac = MatrixFactory::Build(P->getDomainMap(), Teuchos::as<LO>(0));
292
293 SubFactoryMonitor m2(*this, "MxMxM: R x A x P (implicit)", coarseLevel);
294
295 Xpetra::TripleMatrixMultiply<SC,LO,GO,NO>::
296 MultiplyRAP(*P, doTranspose, *A, !doTranspose, *P, !doTranspose, *Ac, doFillComplete,
297 doOptimizeStorage, labelstr+std::string("MueLu::R*A*P-implicit-")+levelstr.str(),
298 RAPparams);
299 } else {
300 RCP<Matrix> R = Get< RCP<Matrix> >(coarseLevel, "R");
301 Ac = MatrixFactory::Build(R->getRowMap(), Teuchos::as<LO>(0));
302
303 SubFactoryMonitor m2(*this, "MxMxM: R x A x P (explicit)", coarseLevel);
304
305 Xpetra::TripleMatrixMultiply<SC,LO,GO,NO>::
306 MultiplyRAP(*R, !doTranspose, *A, !doTranspose, *P, !doTranspose, *Ac, doFillComplete,
307 doOptimizeStorage, labelstr+std::string("MueLu::R*A*P-explicit-")+levelstr.str(),
308 RAPparams);
309 }
310
311 Teuchos::ArrayView<const double> relativeFloor = pL.get<Teuchos::Array<double> >("rap: relative diagonal floor")();
312 if(relativeFloor.size() > 0) {
313 Xpetra::MatrixUtils<SC,LO,GO,NO>::RelativeDiagonalBoost(Ac, relativeFloor,GetOStream(Statistics2));
314 }
315
316 bool repairZeroDiagonals = pL.get<bool>("RepairMainDiagonal") || pL.get<bool>("rap: fix zero diagonals");
317 bool checkAc = pL.get<bool>("CheckMainDiagonal")|| pL.get<bool>("rap: fix zero diagonals"); ;
318 if (checkAc || repairZeroDiagonals) {
319 using magnitudeType = typename Teuchos::ScalarTraits<Scalar>::magnitudeType;
320 magnitudeType threshold;
321 if (pL.isType<magnitudeType>("rap: fix zero diagonals threshold"))
322 threshold = pL.get<magnitudeType>("rap: fix zero diagonals threshold");
323 else
324 threshold = Teuchos::as<magnitudeType>(pL.get<double>("rap: fix zero diagonals threshold"));
325 Scalar replacement = Teuchos::as<Scalar>(pL.get<double>("rap: fix zero diagonals replacement"));
326 Xpetra::MatrixUtils<SC,LO,GO,NO>::CheckRepairMainDiagonal(Ac, repairZeroDiagonals, GetOStream(Warnings1), threshold, replacement);
327 }
328
329
330 if (IsPrint(Statistics2)) {
331 RCP<ParameterList> params = rcp(new ParameterList());;
332 params->set("printLoadBalancingInfo", true);
333 params->set("printCommInfo", true);
335 }
336
337 if(!Ac.is_null()) {std::ostringstream oss; oss << "A_" << coarseLevel.GetLevelID(); Ac->setObjectLabel(oss.str());}
338 Set(coarseLevel, "A", Ac);
339
340 if (!isGPU) {
341 RAPparams->set("graph", Ac);
342 Set(coarseLevel, "RAP reuse data", RAPparams);
343 }
344 }
345
346
347 }
348
349#ifdef HAVE_MUELU_DEBUG
350 MatrixUtils::checkLocalRowMapMatchesColMap(*Ac);
351#endif // HAVE_MUELU_DEBUG
352
353 if (transferFacts_.begin() != transferFacts_.end()) {
354 SubFactoryMonitor m(*this, "Projections", coarseLevel);
355
356 // call Build of all user-given transfer factories
357 for (std::vector<RCP<const FactoryBase> >::const_iterator it = transferFacts_.begin(); it != transferFacts_.end(); ++it) {
358 RCP<const FactoryBase> fac = *it;
359 GetOStream(Runtime0) << "RAPFactory: call transfer factory: " << fac->description() << std::endl;
360 fac->CallBuild(coarseLevel);
361 // Coordinates transfer is marginally different from all other operations
362 // because it is *optional*, and not required. For instance, we may need
363 // coordinates only on level 4 if we start repartitioning from that level,
364 // but we don't need them on level 1,2,3. As our current Hierarchy setup
365 // assumes propagation of dependencies only through three levels, this
366 // means that we need to rely on other methods to propagate optional data.
367 //
368 // The method currently used is through RAP transfer factories, which are
369 // simply factories which are called at the end of RAP with a single goal:
370 // transfer some fine data to coarser level. Because these factories are
371 // kind of outside of the mainline factories, they behave different. In
372 // particular, we call their Build method explicitly, rather than through
373 // Get calls. This difference is significant, as the Get call is smart
374 // enough to know when to release all factory dependencies, and Build is
375 // dumb. This led to the following CoordinatesTransferFactory sequence:
376 // 1. Request level 0
377 // 2. Request level 1
378 // 3. Request level 0
379 // 4. Release level 0
380 // 5. Release level 1
381 //
382 // The problem is missing "6. Release level 0". Because it was missing,
383 // we had outstanding request on "Coordinates", "Aggregates" and
384 // "CoarseMap" on level 0.
385 //
386 // This was fixed by explicitly calling Release on transfer factories in
387 // RAPFactory. I am still unsure how exactly it works, but now we have
388 // clear data requests for all levels.
389 coarseLevel.Release(*fac);
390 }
391 }
392
393 }
394
395 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
397 // check if it's a TwoLevelFactoryBase based transfer factory
398 TEUCHOS_TEST_FOR_EXCEPTION(Teuchos::rcp_dynamic_cast<const TwoLevelFactoryBase>(factory) == Teuchos::null, Exceptions::BadCast,
399 "MueLu::RAPFactory::AddTransferFactory: Transfer factory is not derived from TwoLevelFactoryBase. "
400 "This is very strange. (Note: you can remove this exception if there's a good reason for)");
401 TEUCHOS_TEST_FOR_EXCEPTION(hasDeclaredInput_, Exceptions::RuntimeError, "MueLu::RAPFactory::AddTransferFactory: Factory is being added after we have already declared input");
402 transferFacts_.push_back(factory);
403 }
404
405} //namespace MueLu
406
407#define MUELU_RAPFACTORY_SHORT
408#endif // MUELU_RAPFACTORY_DEF_HPP
#define SET_VALID_ENTRY(name)
MueLu::DefaultScalar Scalar
MueLu::DefaultNode Node
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.
void Release(const FactoryBase &factory)
Decrement the storage counter for all the inputs of a factory.
int GetLevelID() const
Return level number.
virtual const Teuchos::ParameterList & GetParameterList() const
static std::string PrintMatrixInfo(const Matrix &A, const std::string &msgTag, RCP< const Teuchos::ParameterList > params=Teuchos::null)
std::vector< RCP< const FactoryBase > > transferFacts_
list of user-defined transfer Factories
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
void DeclareInput(Level &fineLevel, Level &coarseLevel) const
Input.
void AddTransferFactory(const RCP< const FactoryBase > &factory)
Add transfer factory in the end of list of transfer factories in RepartitionAcFactory.
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.
bool IsPrint(MsgType type, int thisProcRankOnly=-1) const
Find out whether we need to print out information for a specific message type.
Namespace for MueLu classes and methods.
@ Statistics2
Print even more statistics.
@ Runtime0
One-liner description of what is happening.
@ Warnings1
Additional warnings.
static std::string getColonLabel(const std::string &label)
Helper function for object label.