MueLu Version of the Day
Loading...
Searching...
No Matches
MueLu_ParameterListInterpreter_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
10#ifndef MUELU_PARAMETERLISTINTERPRETER_DEF_HPP
11#define MUELU_PARAMETERLISTINTERPRETER_DEF_HPP
12
13#include <Teuchos_XMLParameterListHelpers.hpp>
14
15#include <Xpetra_Matrix.hpp>
16#include <Xpetra_MatrixUtils.hpp>
17
18#include "MueLu_ConfigDefs.hpp"
19
21
22#include "MueLu_MasterList.hpp"
23#include "MueLu_Level.hpp"
24#include "MueLu_Hierarchy.hpp"
25#include "MueLu_FactoryManager.hpp"
26
27#include "MueLu_AggregationExportFactory.hpp"
28#include "MueLu_AggregateQualityEstimateFactory.hpp"
29#include "MueLu_AmalgamationFactory.hpp"
30#include "MueLu_BrickAggregationFactory.hpp"
31#include "MueLu_ClassicalMapFactory.hpp"
32#include "MueLu_ClassicalPFactory.hpp"
33#include "MueLu_CoalesceDropFactory.hpp"
34#include "MueLu_CoarseMapFactory.hpp"
35#include "MueLu_ConstraintFactory.hpp"
36#include "MueLu_CoordinatesTransferFactory.hpp"
37#include "MueLu_DirectSolver.hpp"
38#include "MueLu_EminPFactory.hpp"
39#include "MueLu_Exceptions.hpp"
40#include "MueLu_FacadeClassFactory.hpp"
41#include "MueLu_FactoryFactory.hpp"
42#include "MueLu_FilteredAFactory.hpp"
43#include "MueLu_GenericRFactory.hpp"
44#include "MueLu_InitialBlockNumberFactory.hpp"
45#include "MueLu_LineDetectionFactory.hpp"
46#include "MueLu_LocalOrdinalTransferFactory.hpp"
47#include "MueLu_MatrixAnalysisFactory.hpp"
48#include "MueLu_MultiVectorTransferFactory.hpp"
49#include "MueLu_NotayAggregationFactory.hpp"
50#include "MueLu_NullspaceFactory.hpp"
51#include "MueLu_PatternFactory.hpp"
52#include "MueLu_ReplicatePFactory.hpp"
53#include "MueLu_CombinePFactory.hpp"
54#include "MueLu_PgPFactory.hpp"
55#include "MueLu_RAPFactory.hpp"
56#include "MueLu_RAPShiftFactory.hpp"
57#include "MueLu_RebalanceAcFactory.hpp"
58#include "MueLu_RebalanceTransferFactory.hpp"
59#include "MueLu_RepartitionFactory.hpp"
60#include "MueLu_RepartitionHeuristicFactory.hpp"
61#include "MueLu_ReitzingerPFactory.hpp"
62#include "MueLu_SaPFactory.hpp"
63#include "MueLu_ScaledNullspaceFactory.hpp"
64#include "MueLu_SemiCoarsenPFactory.hpp"
65#include "MueLu_SmootherFactory.hpp"
66#include "MueLu_SmooVecCoalesceDropFactory.hpp"
67#include "MueLu_TentativePFactory.hpp"
68#include "MueLu_TogglePFactory.hpp"
69#include "MueLu_ToggleCoordinatesTransferFactory.hpp"
70#include "MueLu_TransPFactory.hpp"
71#include "MueLu_UncoupledAggregationFactory.hpp"
72#include "MueLu_ZoltanInterface.hpp"
73#include "MueLu_Zoltan2Interface.hpp"
74#include "MueLu_NodePartitionInterface.hpp"
75#include "MueLu_LowPrecisionFactory.hpp"
76
77#include "MueLu_CoalesceDropFactory_kokkos.hpp"
78#include "MueLu_SemiCoarsenPFactory_kokkos.hpp"
79#include "MueLu_TentativePFactory_kokkos.hpp"
80
81#ifdef HAVE_MUELU_MATLAB
82#include "../matlab/src/MueLu_MatlabSmoother_decl.hpp"
83#include "../matlab/src/MueLu_MatlabSmoother_def.hpp"
84#include "../matlab/src/MueLu_TwoLevelMatlabFactory_decl.hpp"
85#include "../matlab/src/MueLu_TwoLevelMatlabFactory_def.hpp"
86#include "../matlab/src/MueLu_SingleLevelMatlabFactory_decl.hpp"
87#include "../matlab/src/MueLu_SingleLevelMatlabFactory_def.hpp"
88#endif
89
90#ifdef HAVE_MUELU_INTREPID2
91#include "MueLu_IntrepidPCoarsenFactory.hpp"
92#endif
93
94#include <unordered_set>
95
96namespace MueLu {
97
98template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
99ParameterListInterpreter<Scalar, LocalOrdinal, GlobalOrdinal, Node>::ParameterListInterpreter(ParameterList& paramList, Teuchos::RCP<const Teuchos::Comm<int> > comm, Teuchos::RCP<FactoryFactory> factFact, Teuchos::RCP<FacadeClassFactory> facadeFact)
100 : factFact_(factFact) {
101 RCP<Teuchos::TimeMonitor> tM = rcp(new Teuchos::TimeMonitor(*Teuchos::TimeMonitor::getNewTimer(std::string("MueLu: ParameterListInterpreter (ParameterList)"))));
102 if (facadeFact == Teuchos::null)
103 facadeFact_ = Teuchos::rcp(new FacadeClassFactory());
104 else
105 facadeFact_ = facadeFact;
106
107 if (paramList.isParameter("xml parameter file")) {
108 std::string filename = paramList.get("xml parameter file", "");
109 if (filename.length() != 0) {
110 TEUCHOS_TEST_FOR_EXCEPTION(comm.is_null(), Exceptions::RuntimeError, "xml parameter file requires a valid comm");
111
112 ParameterList paramList2 = paramList;
113 Teuchos::updateParametersFromXmlFileAndBroadcast(filename, Teuchos::Ptr<Teuchos::ParameterList>(&paramList2), *comm);
114 SetParameterList(paramList2);
115
116 } else {
117 SetParameterList(paramList);
118 }
119
120 } else {
121 SetParameterList(paramList);
122 }
123}
124
125template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
126ParameterListInterpreter<Scalar, LocalOrdinal, GlobalOrdinal, Node>::ParameterListInterpreter(const std::string& xmlFileName, const Teuchos::Comm<int>& comm, Teuchos::RCP<FactoryFactory> factFact, Teuchos::RCP<FacadeClassFactory> facadeFact)
127 : factFact_(factFact) {
128 RCP<Teuchos::TimeMonitor> tM = rcp(new Teuchos::TimeMonitor(*Teuchos::TimeMonitor::getNewTimer(std::string("MueLu: ParameterListInterpreter (XML)"))));
129 if (facadeFact == Teuchos::null)
130 facadeFact_ = Teuchos::rcp(new FacadeClassFactory());
131 else
132 facadeFact_ = facadeFact;
133
134 ParameterList paramList;
135 Teuchos::updateParametersFromXmlFileAndBroadcast(xmlFileName, Teuchos::Ptr<ParameterList>(&paramList), comm);
136 SetParameterList(paramList);
137}
138
139template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
141
142template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
145 WCycleStartLevel_ = Hierarchy::GetDefaultCycleStartLevel();
146 scalingFactor_ = Teuchos::ScalarTraits<double>::one();
147 blockSize_ = 1;
148 dofOffset_ = 0;
149 hierarchyLabel_ = "";
150
151 if (paramList.isSublist("Hierarchy")) {
152 SetFactoryParameterList(paramList);
153
154 } else if (paramList.isParameter("MueLu preconditioner") == true) {
155 this->GetOStream(Runtime0) << "Use facade class: " << paramList.get<std::string>("MueLu preconditioner") << std::endl;
156 Teuchos::RCP<ParameterList> pp = facadeFact_->SetParameterList(paramList);
157 SetFactoryParameterList(*pp);
158
159 } else {
160 // The validator doesn't work correctly for non-serializable data (Hint: template parameters), so strip it out
161 ParameterList serialList, nonSerialList;
162
163 ExtractNonSerializableData(paramList, serialList, nonSerialList);
164 Validate(serialList);
165 SetEasyParameterList(paramList);
166 }
167}
168
169// =====================================================================================================
170// ====================================== EASY interpreter =============================================
171// =====================================================================================================
173static inline bool areSame(const ParameterList& list1, const ParameterList& list2);
174
175// Get value from one of the lists, or set it to default
176// Use case: check for a parameter value in a level-specific sublist, then in a root level list;
177// if it is absent from both, set it to default
178#define MUELU_SET_VAR_2LIST(paramList, defaultList, paramName, paramType, varName) \
179 paramType varName; \
180 if (paramList.isParameter(paramName)) \
181 varName = paramList.get<paramType>(paramName); \
182 else if (defaultList.isParameter(paramName)) \
183 varName = defaultList.get<paramType>(paramName); \
184 else \
185 varName = MasterList::getDefault<paramType>(paramName);
186
187#define MUELU_TEST_AND_SET_VAR(paramList, paramName, paramType, varName) \
188 (paramList.isParameter(paramName) ? varName = paramList.get<paramType>(paramName), true : false)
189
190// Set parameter in a list if it is present in any of two lists
191// User case: set factory specific parameter, first checking for a level-specific value, then cheking root level value
192#define MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, paramName, paramType, listWrite) \
193 try { \
194 if (paramList.isParameter(paramName)) \
195 listWrite.set(paramName, paramList.get<paramType>(paramName)); \
196 else if (defaultList.isParameter(paramName)) \
197 listWrite.set(paramName, defaultList.get<paramType>(paramName)); \
198 } catch (Teuchos::Exceptions::InvalidParameterType&) { \
199 TEUCHOS_TEST_FOR_EXCEPTION_PURE_MSG(true, Teuchos::Exceptions::InvalidParameterType, \
200 "Error: parameter \"" << paramName << "\" must be of type " << Teuchos::TypeNameTraits<paramType>::name()); \
201 }
202
203#define MUELU_TEST_PARAM_2LIST(paramList, defaultList, paramName, paramType, cmpValue) \
204 (cmpValue == (paramList.isParameter(paramName) ? paramList.get<paramType>(paramName) : (defaultList.isParameter(paramName) ? defaultList.get<paramType>(paramName) : MasterList::getDefault<paramType>(paramName))))
205
206#define MUELU_KOKKOS_FACTORY(varName, oldFactory, newFactory) \
207 RCP<Factory> varName; \
208 if (!useKokkos_) \
209 varName = rcp(new oldFactory()); \
210 else \
211 varName = rcp(new newFactory());
212#define MUELU_KOKKOS_FACTORY_NO_DECL(varName, oldFactory, newFactory) \
213 if (!useKokkos_) \
214 varName = rcp(new oldFactory()); \
215 else \
216 varName = rcp(new newFactory());
217
218template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
220 SetEasyParameterList(const ParameterList& constParamList) {
221 ParameterList paramList;
222
223 MUELU_SET_VAR_2LIST(constParamList, constParamList, "problem: type", std::string, problemType);
224 if (problemType != "unknown") {
225 paramList = *MasterList::GetProblemSpecificList(problemType);
226 paramList.setParameters(constParamList);
227 } else {
228 // Create a non const copy of the parameter list
229 // Working with a modifiable list is much much easier than with original one
230 paramList = constParamList;
231 }
232
233 // Check for Kokkos
234 useKokkos_ = !Node::is_serial;
235 (void)MUELU_TEST_AND_SET_VAR(paramList, "use kokkos refactor", bool, useKokkos_);
236
237 // Check for timer synchronization
238 MUELU_SET_VAR_2LIST(paramList, paramList, "synchronize factory timers", bool, syncTimers);
239 if (syncTimers)
241
242 // Translate cycle type parameter
243 if (paramList.isParameter("cycle type")) {
244 std::map<std::string, CycleType> cycleMap;
245 cycleMap["V"] = VCYCLE;
246 cycleMap["W"] = WCYCLE;
247
248 auto cycleType = paramList.get<std::string>("cycle type");
249 TEUCHOS_TEST_FOR_EXCEPTION(cycleMap.count(cycleType) == 0, Exceptions::RuntimeError,
250 "Invalid cycle type: \"" << cycleType << "\"");
251 Cycle_ = cycleMap[cycleType];
252 }
253
254 if (paramList.isParameter("W cycle start level")) {
255 WCycleStartLevel_ = paramList.get<int>("W cycle start level");
256 }
257
258 if (paramList.isParameter("hierarchy label")) {
259 this->hierarchyLabel_ = paramList.get<std::string>("hierarchy label");
260 }
261
262 if (paramList.isParameter("coarse grid correction scaling factor"))
263 scalingFactor_ = paramList.get<double>("coarse grid correction scaling factor");
264
265 this->maxCoarseSize_ = paramList.get<int>("coarse: max size", MasterList::getDefault<int>("coarse: max size"));
266 this->numDesiredLevel_ = paramList.get<int>("max levels", MasterList::getDefault<int>("max levels"));
267 blockSize_ = paramList.get<int>("number of equations", MasterList::getDefault<int>("number of equations"));
268
269 (void)MUELU_TEST_AND_SET_VAR(paramList, "debug: graph level", int, this->graphOutputLevel_);
270
271 // Generic data keeping (this keeps the data on all levels)
272 if (paramList.isParameter("keep data"))
273 this->dataToKeep_ = Teuchos::getArrayFromStringParameter<std::string>(paramList, "keep data");
274
275 // Export level data
276 if (paramList.isSublist("export data")) {
277 ParameterList printList = paramList.sublist("export data");
278
279 // Vectors, aggregates and other things that need special handling
280 if (printList.isParameter("Nullspace"))
281 this->nullspaceToPrint_ = Teuchos::getArrayFromStringParameter<int>(printList, "Nullspace");
282 if (printList.isParameter("Coordinates"))
283 this->coordinatesToPrint_ = Teuchos::getArrayFromStringParameter<int>(printList, "Coordinates");
284 if (printList.isParameter("Material"))
285 this->materialToPrint_ = Teuchos::getArrayFromStringParameter<int>(printList, "Material");
286 if (printList.isParameter("Aggregates"))
287 this->aggregatesToPrint_ = Teuchos::getArrayFromStringParameter<int>(printList, "Aggregates");
288 if (printList.isParameter("pcoarsen: element to node map"))
289 this->elementToNodeMapsToPrint_ = Teuchos::getArrayFromStringParameter<int>(printList, "pcoarsen: element to node map");
290
291 // If we asked for an arbitrary matrix to be printed, we do that here
292 for (auto iter = printList.begin(); iter != printList.end(); iter++) {
293 const std::string& name = printList.name(iter);
294 // Ignore the special cases
295 if (name == "Nullspace" || name == "Coordinates" || name == "Material" || name == "Aggregates" || name == "pcoarsen: element to node map")
296 continue;
297
298 this->matricesToPrint_[name] = Teuchos::getArrayFromStringParameter<int>(printList, name);
299 }
300 }
301
302 // Set verbosity parameter
304 {
305 MUELU_SET_VAR_2LIST(paramList, paramList, "verbosity", std::string, verbosityLevel);
306 this->verbosity_ = toVerbLevel(verbosityLevel);
307 VerboseObject::SetDefaultVerbLevel(this->verbosity_);
308 }
309
310 MUELU_SET_VAR_2LIST(paramList, paramList, "output filename", std::string, outputFilename);
311 if (outputFilename != "")
313
314 // Detect if we need to transfer coordinates to coarse levels. We do that iff
315 // - we use "distance laplacian" dropping on some level, or
316 // - we use a repartitioner on some level that needs coordinates
317 // - we use brick aggregation
318 // - we use Ifpack2 line partitioner
319 // This is not ideal, as we may have "repartition: enable" turned on by default
320 // and not present in the list, but it is better than nothing.
321 useCoordinates_ = false;
322 useBlockNumber_ = false;
323 if (MUELU_TEST_PARAM_2LIST(paramList, paramList, "aggregation: strength-of-connection: matrix", std::string, "distance laplacian"))
324 useCoordinates_ = true;
325 if (MUELU_TEST_PARAM_2LIST(paramList, paramList, "aggregation: use blocking", bool, true))
326 useBlockNumber_ = true;
327 if (MUELU_TEST_PARAM_2LIST(paramList, paramList, "aggregation: drop scheme", std::string, "distance laplacian") ||
328 MUELU_TEST_PARAM_2LIST(paramList, paramList, "aggregation: type", std::string, "brick") ||
329 MUELU_TEST_PARAM_2LIST(paramList, paramList, "aggregation: export visualization data", bool, true)) {
330 useCoordinates_ = true;
331 } else if (MUELU_TEST_PARAM_2LIST(paramList, paramList, "aggregation: drop scheme", std::string, "block diagonal distance laplacian")) {
332 useCoordinates_ = true;
333 useBlockNumber_ = true;
334 } else if (MUELU_TEST_PARAM_2LIST(paramList, paramList, "aggregation: drop scheme", std::string, "block diagonal") ||
335 MUELU_TEST_PARAM_2LIST(paramList, paramList, "aggregation: drop scheme", std::string, "block diagonal classical") ||
336 MUELU_TEST_PARAM_2LIST(paramList, paramList, "aggregation: drop scheme", std::string, "block diagonal signed classical") ||
337 MUELU_TEST_PARAM_2LIST(paramList, paramList, "aggregation: drop scheme", std::string, "block diagonal colored signed classical") ||
338 MUELU_TEST_PARAM_2LIST(paramList, paramList, "aggregation: drop scheme", std::string, "signed classical")) {
339 useBlockNumber_ = true;
340 } else if (paramList.isSublist("smoother: params")) {
341 const auto smooParamList = paramList.sublist("smoother: params");
342 if (smooParamList.isParameter("partitioner: type") &&
343 (smooParamList.get<std::string>("partitioner: type") == "line")) {
344 useCoordinates_ = true;
345 }
346 } else {
347 for (int levelID = 0; levelID < this->numDesiredLevel_; levelID++) {
348 std::string levelStr = "level " + toString(levelID);
349
350 if (paramList.isSublist(levelStr)) {
351 const ParameterList& levelList = paramList.sublist(levelStr);
352
353 if (MUELU_TEST_PARAM_2LIST(levelList, paramList, "aggregation: drop scheme", std::string, "distance laplacian") ||
354 MUELU_TEST_PARAM_2LIST(levelList, paramList, "aggregation: type", std::string, "brick") ||
355 MUELU_TEST_PARAM_2LIST(levelList, paramList, "aggregation: export visualization data", bool, true)) {
356 useCoordinates_ = true;
357 } else if (MUELU_TEST_PARAM_2LIST(levelList, paramList, "aggregation: drop scheme", std::string, "block diagonal distance laplacian")) {
358 useCoordinates_ = true;
359 useBlockNumber_ = true;
360 } else if (MUELU_TEST_PARAM_2LIST(levelList, paramList, "aggregation: drop scheme", std::string, "block diagonal") ||
361 MUELU_TEST_PARAM_2LIST(levelList, paramList, "aggregation: drop scheme", std::string, "block diagonal classical") ||
362 MUELU_TEST_PARAM_2LIST(paramList, paramList, "aggregation: drop scheme", std::string, "block diagonal signed classical") ||
363 MUELU_TEST_PARAM_2LIST(paramList, paramList, "aggregation: drop scheme", std::string, "block diagonal colored signed classical") ||
364 MUELU_TEST_PARAM_2LIST(paramList, paramList, "aggregation: drop scheme", std::string, "signed classical")) {
365 useBlockNumber_ = true;
366 }
367 }
368 }
369 }
370
371 useMaterial_ = false;
372 if (MUELU_TEST_PARAM_2LIST(paramList, paramList, "aggregation: distance laplacian metric", std::string, "material")) {
373 useMaterial_ = true;
374 }
375
376 if (MUELU_TEST_PARAM_2LIST(paramList, paramList, "repartition: enable", bool, true)) {
377 // We don't need coordinates if we're doing the in-place restriction
378 if (MUELU_TEST_PARAM_2LIST(paramList, paramList, "repartition: use subcommunicators", bool, true) &&
379 MUELU_TEST_PARAM_2LIST(paramList, paramList, "repartition: use subcommunicators in place", bool, true)) {
380 // do nothing --- these don't need coordinates
381 } else if (!paramList.isSublist("repartition: params")) {
382 useCoordinates_ = true;
383 } else {
384 const ParameterList& repParams = paramList.sublist("repartition: params");
385 if (repParams.isType<std::string>("algorithm")) {
386 const std::string algo = repParams.get<std::string>("algorithm");
387 if (algo == "multijagged" || algo == "rcb") {
388 useCoordinates_ = true;
389 }
390 } else {
391 useCoordinates_ = true;
392 }
393 }
394 }
395 for (int levelID = 0; levelID < this->numDesiredLevel_; levelID++) {
396 std::string levelStr = "level " + toString(levelID);
397
398 if (paramList.isSublist(levelStr)) {
399 const ParameterList& levelList = paramList.sublist(levelStr);
400
401 if (MUELU_TEST_PARAM_2LIST(levelList, paramList, "repartition: enable", bool, true)) {
402 if (!levelList.isSublist("repartition: params")) {
403 useCoordinates_ = true;
404 break;
405 } else {
406 const ParameterList& repParams = levelList.sublist("repartition: params");
407 if (repParams.isType<std::string>("algorithm")) {
408 const std::string algo = repParams.get<std::string>("algorithm");
409 if (algo == "multijagged" || algo == "rcb") {
410 useCoordinates_ = true;
411 break;
412 }
413 } else {
414 useCoordinates_ = true;
415 break;
416 }
417 }
418 }
419 }
420 }
421
422 // Detect if we do implicit P and R rebalance
423 changedPRrebalance_ = false;
424 changedPRViaCopyrebalance_ = false;
425 if (MUELU_TEST_PARAM_2LIST(paramList, paramList, "repartition: enable", bool, true)) {
426 changedPRrebalance_ = MUELU_TEST_AND_SET_VAR(paramList, "repartition: rebalance P and R", bool, this->doPRrebalance_);
427 changedPRViaCopyrebalance_ = MUELU_TEST_AND_SET_VAR(paramList, "repartition: explicit via new copy rebalance P and R", bool, this->doPRViaCopyrebalance_);
428 }
429
430 // Detect if we use implicit transpose
431 changedImplicitTranspose_ = MUELU_TEST_AND_SET_VAR(paramList, "transpose: use implicit", bool, this->implicitTranspose_);
432
433 // Detect if we use fuse prolongation and update
434 (void)MUELU_TEST_AND_SET_VAR(paramList, "fuse prolongation and update", bool, this->fuseProlongationAndUpdate_);
435
436 // Detect if we suppress the dimension check of the user-given nullspace
437 (void)MUELU_TEST_AND_SET_VAR(paramList, "nullspace: suppress dimension check", bool, this->suppressNullspaceDimensionCheck_);
438
439 if (paramList.isSublist("matvec params"))
440 this->matvecParams_ = Teuchos::parameterList(paramList.sublist("matvec params"));
441
442 // Create default manager
443 // FIXME: should it be here, or higher up
444 RCP<FactoryManager> defaultManager = rcp(new FactoryManager());
445 defaultManager->SetVerbLevel(this->verbosity_);
446 defaultManager->SetKokkosRefactor(useKokkos_);
447
448 // We will ignore keeps0
449 std::vector<keep_pair> keeps0;
450 UpdateFactoryManager(paramList, ParameterList(), *defaultManager, 0 /*levelID*/, keeps0);
451
452 // std::cout<<"*** Default Manager ***"<<std::endl;
453 // defaultManager->Print();
454
455 // Create level specific factory managers
456 for (int levelID = 0; levelID < this->numDesiredLevel_; levelID++) {
457 // Note, that originally if there were no level specific parameters, we
458 // simply copied the defaultManager However, with the introduction of
459 // levelID to UpdateFactoryManager (required for reuse), we can no longer
460 // guarantee that the kept variables are the same for each level even if
461 // dependency structure does not change.
462 RCP<FactoryManager> levelManager = rcp(new FactoryManager(*defaultManager));
463 levelManager->SetVerbLevel(defaultManager->GetVerbLevel());
464
465 std::vector<keep_pair> keeps;
466 if (paramList.isSublist("level " + toString(levelID))) {
467 // We do this so the parameters on the level get flagged correctly as "used"
468 ParameterList& levelList = paramList.sublist("level " + toString(levelID), true /*mustAlreadyExist*/);
469 UpdateFactoryManager(levelList, paramList, *levelManager, levelID, keeps);
470
471 } else {
472 ParameterList levelList;
473 UpdateFactoryManager(levelList, paramList, *levelManager, levelID, keeps);
474 }
475
476 this->keep_[levelID] = keeps;
477 this->AddFactoryManager(levelID, 1, levelManager);
478
479 // std::cout<<"*** Level "<<levelID<<" Manager ***"<<std::endl;
480 // levelManager->Print();
481 }
482
483 // FIXME: parameters passed to packages, like Ifpack2, are not touched by us, resulting in "[unused]" flag
484 // being displayed. On the other hand, we don't want to simply iterate through them touching. I don't know
485 // what a good solution looks like
486 if (MUELU_TEST_PARAM_2LIST(paramList, paramList, "print initial parameters", bool, true))
487 this->GetOStream(static_cast<MsgType>(Runtime1), 0) << paramList << std::endl;
488
489 if (MUELU_TEST_PARAM_2LIST(paramList, paramList, "print unused parameters", bool, true)) {
490 // Check unused parameters
491 ParameterList unusedParamList;
492
493 // Check for unused parameters that aren't lists
494 for (ParameterList::ConstIterator it = paramList.begin(); it != paramList.end(); it++) {
495 const ParameterEntry& entry = paramList.entry(it);
496
497 if (!entry.isList() && !entry.isUsed())
498 unusedParamList.setEntry(paramList.name(it), entry);
499 }
500
501 // Check for unused parameters in level-specific sublists
502 for (int levelID = 0; levelID < this->numDesiredLevel_; levelID++) {
503 std::string levelStr = "level " + toString(levelID);
504
505 if (paramList.isSublist(levelStr)) {
506 const ParameterList& levelList = paramList.sublist(levelStr);
507
508 for (ParameterList::ConstIterator itr = levelList.begin(); itr != levelList.end(); ++itr) {
509 const ParameterEntry& entry = levelList.entry(itr);
510
511 if (!entry.isList() && !entry.isUsed())
512 unusedParamList.sublist(levelStr).setEntry(levelList.name(itr), entry);
513 }
514 }
515 }
516
517 if (unusedParamList.numParams() > 0) {
518 std::ostringstream unusedParamsStream;
519 int indent = 4;
520 unusedParamList.print(unusedParamsStream, indent);
521
522 this->GetOStream(Warnings1) << "The following parameters were not used:\n"
523 << unusedParamsStream.str() << std::endl;
524 }
525 }
526
528}
529
530// =====================================================================================================
531// ==================================== UpdateFactoryManager ===========================================
532// =====================================================================================================
533template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
535 UpdateFactoryManager(ParameterList& paramList, const ParameterList& defaultList, FactoryManager& manager,
536 int levelID, std::vector<keep_pair>& keeps) const {
537 // NOTE: Factory::SetParameterList must be called prior to Factory::SetFactory, as
538 // SetParameterList sets default values for non mentioned parameters, including factories
539
540 using strings = std::unordered_set<std::string>;
541
542 // shortcut
543 if (paramList.numParams() == 0 && defaultList.numParams() > 0)
544 paramList = ParameterList(defaultList);
545
546 MUELU_SET_VAR_2LIST(paramList, defaultList, "reuse: type", std::string, reuseType);
547 TEUCHOS_TEST_FOR_EXCEPTION(strings({"none", "tP", "RP", "emin", "RAP", "full", "S"}).count(reuseType) == 0,
548 Exceptions::RuntimeError, "Unknown \"reuse: type\" value: \"" << reuseType << "\". Please consult User's Guide.");
549
550 MUELU_SET_VAR_2LIST(paramList, defaultList, "multigrid algorithm", std::string, multigridAlgo);
551 TEUCHOS_TEST_FOR_EXCEPTION(strings({"unsmoothed", "sa", "pg", "emin", "matlab", "pcoarsen", "classical", "smoothed reitzinger", "unsmoothed reitzinger", "replicate", "combine"}).count(multigridAlgo) == 0,
552 Exceptions::RuntimeError, "Unknown \"multigrid algorithm\" value: \"" << multigridAlgo << "\". Please consult User's Guide.");
553#ifndef HAVE_MUELU_MATLAB
554 TEUCHOS_TEST_FOR_EXCEPTION(multigridAlgo == "matlab", Exceptions::RuntimeError,
555 "Cannot use matlab for multigrid algorithm - MueLu was not configured with MATLAB support.");
556#endif
557#ifndef HAVE_MUELU_INTREPID2
558 TEUCHOS_TEST_FOR_EXCEPTION(multigridAlgo == "pcoarsen", Exceptions::RuntimeError,
559 "Cannot use IntrepidPCoarsen prolongator factory - MueLu was not configured with Intrepid support.");
560#endif
561
562 // Only some combinations of reuse and multigrid algorithms are tested, all
563 // other are considered invalid at the moment
564 if (reuseType == "none" || reuseType == "S" || reuseType == "RP" || reuseType == "RAP") {
565 // This works for all kinds of multigrid algorithms
566
567 } else if (reuseType == "tP" && (multigridAlgo != "sa" && multigridAlgo != "unsmoothed")) {
568 reuseType = "none";
569 this->GetOStream(Warnings0) << "Ignoring \"tP\" reuse option as it is only compatible with \"sa\", "
570 "or \"unsmoothed\" multigrid algorithms"
571 << std::endl;
572
573 } else if (reuseType == "emin" && multigridAlgo != "emin") {
574 reuseType = "none";
575 this->GetOStream(Warnings0) << "Ignoring \"emin\" reuse option it is only compatible with "
576 "\"emin\" multigrid algorithm"
577 << std::endl;
578 }
579
580 // == Non-serializable data ===
581 // Check both the parameter and the type
582 bool have_userP = false;
583 if (paramList.isParameter("P") && !paramList.get<RCP<Matrix> >("P").is_null())
584 have_userP = true;
585
586 // === Coarse solver ===
587 UpdateFactoryManager_CoarseSolvers(paramList, defaultList, manager, levelID, keeps);
588
589 // == Smoothers ==
590 UpdateFactoryManager_Smoothers(paramList, defaultList, manager, levelID, keeps);
591
592 // === BlockNumber ===
593 if (levelID == 0)
594 UpdateFactoryManager_BlockNumber(paramList, defaultList, manager, levelID, keeps);
595
596 // === Aggregation ===
597 if (multigridAlgo == "unsmoothed reitzinger" || multigridAlgo == "smoothed reitzinger")
598 UpdateFactoryManager_Reitzinger(paramList, defaultList, manager, levelID, keeps);
599 else
600 UpdateFactoryManager_Aggregation_TentativeP(paramList, defaultList, manager, levelID, keeps);
601
602 // === Nullspace ===
603 RCP<Factory> nullSpaceFactory; // Cache thcAN is guy for the combination of semi-coarsening & repartitioning
604 UpdateFactoryManager_Nullspace(paramList, defaultList, manager, levelID, keeps, nullSpaceFactory);
605
606 // === Prolongation ===
607 // NOTE: None of the UpdateFactoryManager routines called here check the
608 // multigridAlgo. This is intentional, to allow for reuse of components
609 // underneath. Thus, the multigridAlgo was checked in the beginning of the
610 // function.
611 if (have_userP) {
612 // User prolongator
613 manager.SetFactory("P", NoFactory::getRCP());
614
615 } else if (multigridAlgo == "unsmoothed" || multigridAlgo == "unsmoothed reitzinger") {
616 // Unsmoothed aggregation
617 manager.SetFactory("P", manager.GetFactory("Ptent"));
618
619 } else if (multigridAlgo == "classical") {
620 // Classical AMG
621 manager.SetFactory("P", manager.GetFactory("Ptent"));
622
623 } else if (multigridAlgo == "sa" || multigridAlgo == "smoothed reitzinger") {
624 // Smoothed aggregation
625 UpdateFactoryManager_SA(paramList, defaultList, manager, levelID, keeps);
626
627 } else if (multigridAlgo == "emin") {
628 // Energy minimization
629 UpdateFactoryManager_Emin(paramList, defaultList, manager, levelID, keeps);
630
631 } else if (multigridAlgo == "replicate") {
632 UpdateFactoryManager_Replicate(paramList, defaultList, manager, levelID, keeps);
633
634 } else if (multigridAlgo == "combine") {
635 UpdateFactoryManager_Combine(paramList, defaultList, manager, levelID, keeps);
636
637 } else if (multigridAlgo == "pg") {
638 // Petrov-Galerkin
639 UpdateFactoryManager_PG(paramList, defaultList, manager, levelID, keeps);
640
641 } else if (multigridAlgo == "matlab") {
642 // Matlab Coarsneing
643 UpdateFactoryManager_Matlab(paramList, defaultList, manager, levelID, keeps);
644
645 } else if (multigridAlgo == "pcoarsen") {
646 // P-Coarsening
647 UpdateFactoryManager_PCoarsen(paramList, defaultList, manager, levelID, keeps);
648 }
649
650 // === Semi-coarsening ===
651 UpdateFactoryManager_SemiCoarsen(paramList, defaultList, manager, levelID, keeps);
652
653 // === Restriction ===
654 UpdateFactoryManager_Restriction(paramList, defaultList, manager, levelID, keeps);
655
656 // === RAP ===
657 UpdateFactoryManager_RAP(paramList, defaultList, manager, levelID, keeps);
658
659 // == BlockNumber Transfer ==
660 UpdateFactoryManager_LocalOrdinalTransfer("BlockNumber", multigridAlgo, paramList, defaultList, manager, levelID, keeps);
661
662 // === Coordinates ===
663 UpdateFactoryManager_Coordinates(paramList, defaultList, manager, levelID, keeps);
664
665 // === Material ===
666 UpdateFactoryManager_Material(paramList, defaultList, manager, levelID, keeps);
667
668 // === Pre-Repartition Keeps for Reuse ===
669 if ((reuseType == "RP" || reuseType == "RAP" || reuseType == "full") && levelID)
670 keeps.push_back(keep_pair("Nullspace", manager.GetFactory("Nullspace").get()));
671
672 if (reuseType == "RP" && levelID) {
673 keeps.push_back(keep_pair("P", manager.GetFactory("P").get()));
674 if (!this->implicitTranspose_)
675 keeps.push_back(keep_pair("R", manager.GetFactory("R").get()));
676 }
677 if ((reuseType == "tP" || reuseType == "RP" || reuseType == "emin") && useCoordinates_ && levelID)
678 keeps.push_back(keep_pair("Coordinates", manager.GetFactory("Coordinates").get()));
679
680 // === Repartitioning ===
681 UpdateFactoryManager_Repartition(paramList, defaultList, manager, levelID, keeps, nullSpaceFactory);
682
683 // === Lower precision transfers ===
684 UpdateFactoryManager_LowPrecision(paramList, defaultList, manager, levelID, keeps);
685
686 // === Final Keeps for Reuse ===
687 if ((reuseType == "RAP" || reuseType == "full") && levelID) {
688 keeps.push_back(keep_pair("P", manager.GetFactory("P").get()));
689 if (!this->implicitTranspose_)
690 keeps.push_back(keep_pair("R", manager.GetFactory("R").get()));
691 keeps.push_back(keep_pair("A", manager.GetFactory("A").get()));
692 }
693
694 // In case you ever want to inspect the FactoryManager as it is generated for each level
695 /*std::cout<<"*** Factory Manager on level "<<levelID<<" ***"<<std::endl;
696 manager.Print(); */
697}
698
699// =====================================================================================================
700// ========================================= Smoothers =================================================
701// =====================================================================================================
702template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
704 UpdateFactoryManager_Smoothers(ParameterList& paramList, const ParameterList& defaultList,
705 FactoryManager& manager, int levelID, std::vector<keep_pair>& keeps) const {
706 MUELU_SET_VAR_2LIST(paramList, defaultList, "multigrid algorithm", std::string, multigridAlgo);
707 MUELU_SET_VAR_2LIST(paramList, defaultList, "reuse: type", std::string, reuseType);
708 MUELU_SET_VAR_2LIST(paramList, defaultList, "sa: use rowsumabs diagonal scaling", bool, useMaxAbsDiagonalScaling);
709
710 // === Smoothing ===
711 // FIXME: should custom smoother check default list too?
712 bool isCustomSmoother =
713 paramList.isParameter("smoother: pre or post") ||
714 paramList.isParameter("smoother: type") || paramList.isParameter("smoother: pre type") || paramList.isParameter("smoother: post type") ||
715 paramList.isSublist("smoother: params") || paramList.isSublist("smoother: pre params") || paramList.isSublist("smoother: post params") ||
716 paramList.isParameter("smoother: sweeps") || paramList.isParameter("smoother: pre sweeps") || paramList.isParameter("smoother: post sweeps") ||
717 paramList.isParameter("smoother: overlap") || paramList.isParameter("smoother: pre overlap") || paramList.isParameter("smoother: post overlap");
718
719 MUELU_SET_VAR_2LIST(paramList, defaultList, "smoother: pre or post", std::string, PreOrPost);
720 if (PreOrPost == "none") {
721 manager.SetFactory("Smoother", Teuchos::null);
722
723 } else if (isCustomSmoother) {
724 // FIXME: get default values from the factory
725 // NOTE: none of the smoothers at the moment use parameter validation framework, so we
726 // cannot get the default values from it.
727#define TEST_MUTUALLY_EXCLUSIVE(arg1, arg2) \
728 TEUCHOS_TEST_FOR_EXCEPTION(paramList.isParameter(#arg1) && paramList.isParameter(#arg2), \
729 Exceptions::InvalidArgument, "You cannot specify both \"" #arg1 "\" and \"" #arg2 "\"");
730#define TEST_MUTUALLY_EXCLUSIVE_S(arg1, arg2) \
731 TEUCHOS_TEST_FOR_EXCEPTION(paramList.isSublist(#arg1) && paramList.isSublist(#arg2), \
732 Exceptions::InvalidArgument, "You cannot specify both \"" #arg1 "\" and \"" #arg2 "\"");
733
734 TEST_MUTUALLY_EXCLUSIVE("smoother: type", "smoother: pre type");
735 TEST_MUTUALLY_EXCLUSIVE("smoother: type", "smoother: post type");
736 TEST_MUTUALLY_EXCLUSIVE("smoother: sweeps", "smoother: pre sweeps");
737 TEST_MUTUALLY_EXCLUSIVE("smoother: sweeps", "smoother: post sweeps");
738 TEST_MUTUALLY_EXCLUSIVE("smoother: overlap", "smoother: pre overlap");
739 TEST_MUTUALLY_EXCLUSIVE("smoother: overlap", "smoother: post overlap");
740 TEST_MUTUALLY_EXCLUSIVE_S("smoother: params", "smoother: pre params");
741 TEST_MUTUALLY_EXCLUSIVE_S("smoother: params", "smoother: post params");
742 TEUCHOS_TEST_FOR_EXCEPTION(PreOrPost == "both" && (paramList.isParameter("smoother: pre type") != paramList.isParameter("smoother: post type")),
743 Exceptions::InvalidArgument, "You must specify both \"smoother: pre type\" and \"smoother: post type\"");
744
745 // Default values
746 int overlap = 0;
747 ParameterList defaultSmootherParams;
748 defaultSmootherParams.set("relaxation: type", "Symmetric Gauss-Seidel");
749 defaultSmootherParams.set("relaxation: sweeps", Teuchos::OrdinalTraits<LO>::one());
750 defaultSmootherParams.set("relaxation: damping factor", Teuchos::ScalarTraits<Scalar>::one());
751
752 RCP<SmootherFactory> preSmoother = Teuchos::null, postSmoother = Teuchos::null;
753 std::string preSmootherType, postSmootherType;
754 ParameterList preSmootherParams, postSmootherParams;
755
756 auto setChebyshevSettings = [&](const std::string& smootherType, Teuchos::ParameterList& smootherParams) {
757 auto upperCaseSmootherType = smootherType;
758 std::transform(smootherType.begin(), smootherType.end(), upperCaseSmootherType.begin(), ::toupper);
759 if (upperCaseSmootherType != "CHEBYSHEV") return;
760
761 if (smootherParams.isParameter("chebyshev: use rowsumabs diagonal scaling")) {
762 bool useMaxAbsDiagonalScalingCheby = smootherParams.get<bool>("chebyshev: use rowsumabs diagonal scaling");
763 TEUCHOS_TEST_FOR_EXCEPTION(useMaxAbsDiagonalScaling != useMaxAbsDiagonalScalingCheby,
764 Exceptions::RuntimeError, "'chebyshev: use rowsumabs diagonal scaling' (" << std::boolalpha << useMaxAbsDiagonalScalingCheby << ") must match 'sa: use rowsumabs diagonal scaling' (" << std::boolalpha << useMaxAbsDiagonalScaling << ")\n");
765 } else {
766 if (useMaxAbsDiagonalScaling)
767 smootherParams.set("chebyshev: use rowsumabs diagonal scaling", useMaxAbsDiagonalScaling);
768 }
769 };
770
771 if (paramList.isParameter("smoother: overlap"))
772 overlap = paramList.get<int>("smoother: overlap");
773
774 if (PreOrPost == "pre" || PreOrPost == "both") {
775 if (paramList.isParameter("smoother: pre type")) {
776 preSmootherType = paramList.get<std::string>("smoother: pre type");
777 } else {
778 MUELU_SET_VAR_2LIST(paramList, defaultList, "smoother: type", std::string, preSmootherTypeTmp);
779 preSmootherType = preSmootherTypeTmp;
780 }
781 if (paramList.isParameter("smoother: pre overlap"))
782 overlap = paramList.get<int>("smoother: pre overlap");
783
784 if (paramList.isSublist("smoother: pre params"))
785 preSmootherParams = paramList.sublist("smoother: pre params");
786 else if (paramList.isSublist("smoother: params"))
787 preSmootherParams = paramList.sublist("smoother: params");
788 else if (defaultList.isSublist("smoother: params"))
789 preSmootherParams = defaultList.sublist("smoother: params");
790 else if (preSmootherType == "RELAXATION")
791 preSmootherParams = defaultSmootherParams;
792
793 setChebyshevSettings(preSmootherType, preSmootherParams);
794
795#ifdef HAVE_MUELU_INTREPID2
796 // Propagate P-coarsening for Topo smoothing
797 if (multigridAlgo == "pcoarsen" && preSmootherType == "TOPOLOGICAL" &&
798 defaultList.isParameter("pcoarsen: schedule") && defaultList.isParameter("pcoarsen: element")) {
799 // P-Coarsening by schedule (new interface)
800 // NOTE: levelID represents the *coarse* level in this case
801 auto pcoarsen_schedule = Teuchos::getArrayFromStringParameter<int>(defaultList, "pcoarsen: schedule");
802 auto pcoarsen_element = defaultList.get<std::string>("pcoarsen: element");
803
804 if (levelID < (int)pcoarsen_schedule.size()) {
805 // Topo info for P-Coarsening
806 auto lo = pcoarsen_element + std::to_string(pcoarsen_schedule[levelID]);
807 preSmootherParams.set("pcoarsen: hi basis", lo);
808 }
809 }
810#endif
811
812#ifdef HAVE_MUELU_MATLAB
813 if (preSmootherType == "matlab")
814 preSmoother = rcp(new SmootherFactory(rcp(new MatlabSmoother(preSmootherParams))));
815 else
816#endif
817 preSmoother = rcp(new SmootherFactory(rcp(new TrilinosSmoother(preSmootherType, preSmootherParams, overlap))));
818 }
819
820 if (PreOrPost == "post" || PreOrPost == "both") {
821 if (paramList.isParameter("smoother: post type"))
822 postSmootherType = paramList.get<std::string>("smoother: post type");
823 else {
824 MUELU_SET_VAR_2LIST(paramList, defaultList, "smoother: type", std::string, postSmootherTypeTmp);
825 postSmootherType = postSmootherTypeTmp;
826 }
827
828 if (paramList.isSublist("smoother: post params"))
829 postSmootherParams = paramList.sublist("smoother: post params");
830 else if (paramList.isSublist("smoother: params"))
831 postSmootherParams = paramList.sublist("smoother: params");
832 else if (defaultList.isSublist("smoother: params"))
833 postSmootherParams = defaultList.sublist("smoother: params");
834 else if (postSmootherType == "RELAXATION")
835 postSmootherParams = defaultSmootherParams;
836 if (paramList.isParameter("smoother: post overlap"))
837 overlap = paramList.get<int>("smoother: post overlap");
838
839 setChebyshevSettings(postSmootherType, postSmootherParams);
840
841 if (postSmootherType == preSmootherType && areSame(preSmootherParams, postSmootherParams))
842 postSmoother = preSmoother;
843 else {
844#ifdef HAVE_MUELU_INTREPID2
845 // Propagate P-coarsening for Topo smoothing
846 if (multigridAlgo == "pcoarsen" && preSmootherType == "TOPOLOGICAL" &&
847 defaultList.isParameter("pcoarsen: schedule") && defaultList.isParameter("pcoarsen: element")) {
848 // P-Coarsening by schedule (new interface)
849 // NOTE: levelID represents the *coarse* level in this case
850 auto pcoarsen_schedule = Teuchos::getArrayFromStringParameter<int>(defaultList, "pcoarsen: schedule");
851 auto pcoarsen_element = defaultList.get<std::string>("pcoarsen: element");
852
853 if (levelID < (int)pcoarsen_schedule.size()) {
854 // Topo info for P-Coarsening
855 auto lo = pcoarsen_element + std::to_string(pcoarsen_schedule[levelID]);
856 postSmootherParams.set("pcoarsen: hi basis", lo);
857 }
858 }
859#endif
860
861#ifdef HAVE_MUELU_MATLAB
862 if (postSmootherType == "matlab")
863 postSmoother = rcp(new SmootherFactory(rcp(new MatlabSmoother(postSmootherParams))));
864 else
865#endif
866 postSmoother = rcp(new SmootherFactory(rcp(new TrilinosSmoother(postSmootherType, postSmootherParams, overlap))));
867 }
868 }
869
870 if (preSmoother == postSmoother)
871 manager.SetFactory("Smoother", preSmoother);
872 else {
873 manager.SetFactory("PreSmoother", preSmoother);
874 manager.SetFactory("PostSmoother", postSmoother);
875 }
876 }
877
878 // The first clause is not necessary, but it is here for clarity Smoothers
879 // are reused if smoother explicitly said to reuse them, or if any other
880 // reuse option is enabled
881 bool reuseSmoothers = (reuseType == "S" || reuseType != "none");
882 if (reuseSmoothers) {
883 auto preSmootherFactory = rcp_const_cast<Factory>(rcp_dynamic_cast<const Factory>(manager.GetFactory("PreSmoother")));
884
885 if (preSmootherFactory != Teuchos::null) {
886 ParameterList postSmootherFactoryParams;
887 postSmootherFactoryParams.set("keep smoother data", true);
888 preSmootherFactory->SetParameterList(postSmootherFactoryParams);
889
890 keeps.push_back(keep_pair("PreSmoother data", preSmootherFactory.get()));
891 }
892
893 auto postSmootherFactory = rcp_const_cast<Factory>(rcp_dynamic_cast<const Factory>(manager.GetFactory("PostSmoother")));
894 if (postSmootherFactory != Teuchos::null) {
895 ParameterList postSmootherFactoryParams;
896 postSmootherFactoryParams.set("keep smoother data", true);
897 postSmootherFactory->SetParameterList(postSmootherFactoryParams);
898
899 keeps.push_back(keep_pair("PostSmoother data", postSmootherFactory.get()));
900 }
901
902 auto coarseFactory = rcp_const_cast<Factory>(rcp_dynamic_cast<const Factory>(manager.GetFactory("CoarseSolver")));
903 if (coarseFactory != Teuchos::null) {
904 ParameterList coarseFactoryParams;
905 coarseFactoryParams.set("keep smoother data", true);
906 coarseFactory->SetParameterList(coarseFactoryParams);
907
908 keeps.push_back(keep_pair("PreSmoother data", coarseFactory.get()));
909 }
910 }
911
912 if ((reuseType == "RAP" && levelID) || (reuseType == "full")) {
913 // The difference between "RAP" and "full" is keeping smoothers. However,
914 // as in both cases we keep coarse matrices, we do not need to update
915 // coarse smoothers. On the other hand, if a user changes fine level
916 // matrix, "RAP" would update the fine level smoother, while "full" would
917 // not
918 keeps.push_back(keep_pair("PreSmoother", manager.GetFactory("PreSmoother").get()));
919 keeps.push_back(keep_pair("PostSmoother", manager.GetFactory("PostSmoother").get()));
920
921 // We do keep_pair("PreSmoother", manager.GetFactory("CoarseSolver").get())
922 // as the coarse solver factory is in fact a smoothing factory, so the
923 // only pieces of data it generates are PreSmoother and PostSmoother
924 keeps.push_back(keep_pair("PreSmoother", manager.GetFactory("CoarseSolver").get()));
925 }
926}
927
928// =====================================================================================================
929// ====================================== Coarse Solvers ===============================================
930// =====================================================================================================
931template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
933 UpdateFactoryManager_CoarseSolvers(ParameterList& paramList, const ParameterList& defaultList,
934 FactoryManager& manager, int /* levelID */, std::vector<keep_pair>& /* keeps */) const {
935 // FIXME: should custom coarse solver check default list too?
936 bool isCustomCoarseSolver =
937 paramList.isParameter("coarse: type") ||
938 paramList.isParameter("coarse: params");
939 if (MUELU_TEST_PARAM_2LIST(paramList, defaultList, "coarse: type", std::string, "none")) {
940 manager.SetFactory("CoarseSolver", Teuchos::null);
941
942 } else if (isCustomCoarseSolver) {
943 // FIXME: get default values from the factory
944 // NOTE: none of the smoothers at the moment use parameter validation framework, so we
945 // cannot get the default values from it.
946 MUELU_SET_VAR_2LIST(paramList, defaultList, "coarse: type", std::string, coarseType);
947
948 int overlap = 0;
949 if (paramList.isParameter("coarse: overlap"))
950 overlap = paramList.get<int>("coarse: overlap");
951
952 ParameterList coarseParams;
953 if (paramList.isSublist("coarse: params"))
954 coarseParams = paramList.sublist("coarse: params");
955 else if (defaultList.isSublist("coarse: params"))
956 coarseParams = defaultList.sublist("coarse: params");
957
958 using strings = std::unordered_set<std::string>;
959
960 RCP<SmootherPrototype> coarseSmoother;
961 // TODO: this is not a proper place to check. If we consider direct solver to be a special
962 // case of smoother, we would like to unify Amesos and Ifpack2 smoothers in src/Smoothers, and
963 // have a single factory responsible for those. Then, this check would belong there.
964 if (strings({"RELAXATION", "CHEBYSHEV", "ILUT", "ILU", "RILUK", "SCHWARZ", "Amesos",
965 "BLOCK RELAXATION", "BLOCK_RELAXATION", "BLOCKRELAXATION",
966 "SPARSE BLOCK RELAXATION", "SPARSE_BLOCK_RELAXATION", "SPARSEBLOCKRELAXATION",
967 "LINESMOOTHING_BANDEDRELAXATION", "LINESMOOTHING_BANDED_RELAXATION", "LINESMOOTHING_BANDED RELAXATION",
968 "LINESMOOTHING_TRIDIRELAXATION", "LINESMOOTHING_TRIDI_RELAXATION", "LINESMOOTHING_TRIDI RELAXATION",
969 "LINESMOOTHING_TRIDIAGONALRELAXATION", "LINESMOOTHING_TRIDIAGONAL_RELAXATION", "LINESMOOTHING_TRIDIAGONAL RELAXATION",
970 "TOPOLOGICAL", "FAST_ILU", "FAST_IC", "FAST_ILDL", "HIPTMAIR"})
971 .count(coarseType)) {
972 coarseSmoother = rcp(new TrilinosSmoother(coarseType, coarseParams, overlap));
973 } else {
974#ifdef HAVE_MUELU_MATLAB
975 if (coarseType == "matlab")
976 coarseSmoother = rcp(new MatlabSmoother(coarseParams));
977 else
978#endif
979 coarseSmoother = rcp(new DirectSolver(coarseType, coarseParams));
980 }
981
982 manager.SetFactory("CoarseSolver", rcp(new SmootherFactory(coarseSmoother)));
983 }
984}
985
986// =====================================================================================================
987// ========================================= TentativeP=================================================
988// =====================================================================================================
989template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
991 UpdateFactoryManager_Reitzinger(ParameterList& paramList, const ParameterList& defaultList,
992 FactoryManager& manager, int levelID, std::vector<keep_pair>& keeps) const {
993 ParameterList rParams;
994 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "repartition: enable", bool, rParams);
995 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "repartition: use subcommunicators", bool, rParams);
996 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "tentative: constant column sums", bool, rParams);
997 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "tentative: calculate qr", bool, rParams);
998
999 RCP<Factory> rFactory = rcp(new ReitzingerPFactory());
1000 rFactory->SetParameterList(rParams);
1001
1002 // These are all going to be user provided, so NoFactory
1003 rFactory->SetFactory("Pnodal", NoFactory::getRCP());
1004 rFactory->SetFactory("NodeAggMatrix", NoFactory::getRCP());
1005 // rFactory->SetFactory("NodeMatrix", NoFactory::getRCP());
1006
1007 if (levelID > 1)
1008 rFactory->SetFactory("D0", this->GetFactoryManager(levelID - 1)->GetFactory("D0"));
1009 else
1010 rFactory->SetFactory("D0", NoFactory::getRCP());
1011
1012 manager.SetFactory("Ptent", rFactory);
1013 manager.SetFactory("D0", rFactory);
1014 manager.SetFactory("InPlaceMap", rFactory);
1015}
1016
1017// =====================================================================================================
1018// ========================================= TentativeP=================================================
1019// =====================================================================================================
1020template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1022 UpdateFactoryManager_Aggregation_TentativeP(ParameterList& paramList, const ParameterList& defaultList,
1023 FactoryManager& manager, int levelID, std::vector<keep_pair>& keeps) const {
1024 using strings = std::unordered_set<std::string>;
1025
1026 MUELU_SET_VAR_2LIST(paramList, defaultList, "reuse: type", std::string, reuseType);
1027
1028 MUELU_SET_VAR_2LIST(paramList, defaultList, "aggregation: type", std::string, aggType);
1029 TEUCHOS_TEST_FOR_EXCEPTION(!strings({"uncoupled", "coupled", "brick", "matlab", "notay", "classical"}).count(aggType),
1030 Exceptions::RuntimeError, "Unknown aggregation algorithm: \"" << aggType << "\". Please consult User's Guide.");
1031
1032 // Only doing this for classical because otherwise, the gold tests get broken badly
1033 RCP<AmalgamationFactory> amalgFact;
1034 if (aggType == "classical") {
1035 amalgFact = rcp(new AmalgamationFactory());
1036 manager.SetFactory("UnAmalgamationInfo", amalgFact);
1037 }
1038
1039 // Aggregation graph
1040 RCP<Factory> dropFactory;
1041
1042 if (MUELU_TEST_PARAM_2LIST(paramList, paramList, "aggregation: drop scheme", std::string, "matlab")) {
1043#ifdef HAVE_MUELU_MATLAB
1044 dropFactory = rcp(new SingleLevelMatlabFactory());
1045 ParameterList socParams = paramList.sublist("strength-of-connection: params");
1046 dropFactory->SetParameterList(socParams);
1047#else
1048 throw std::runtime_error("Cannot use MATLAB evolutionary strength-of-connection - MueLu was not configured with MATLAB support.");
1049#endif
1050 } else if (MUELU_TEST_PARAM_2LIST(paramList, paramList, "aggregation: drop scheme", std::string, "unsupported vector smoothing")) {
1052 ParameterList dropParams;
1053 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: drop scheme", std::string, dropParams);
1054 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: block diagonal: interleaved blocksize", int, dropParams);
1055 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: number of random vectors", int, dropParams);
1056 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: number of times to pre or post smooth", int, dropParams);
1057 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: penalty parameters", Teuchos::Array<double>, dropParams);
1058 dropFactory->SetParameterList(dropParams);
1059 } else {
1061 ParameterList dropParams;
1062 if (!rcp_dynamic_cast<CoalesceDropFactory>(dropFactory).is_null())
1063 dropParams.set("lightweight wrap", true);
1064 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: drop scheme", std::string, dropParams);
1065 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: row sum drop tol", double, dropParams);
1066 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: block diagonal: interleaved blocksize", int, dropParams);
1067 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: drop tol", double, dropParams);
1068 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: use ml scaling of drop tol", bool, dropParams);
1069
1070 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: Dirichlet threshold", double, dropParams);
1071 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: greedy Dirichlet", bool, dropParams);
1072 if (useKokkos_)
1073 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: distance laplacian metric", std::string, dropParams);
1074#ifdef HAVE_MUELU_COALESCEDROP_ALLOW_OLD_PARAMETERS
1075 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: distance laplacian algo", std::string, dropParams);
1076 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: classical algo", std::string, dropParams);
1077#endif
1078 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: distance laplacian directional weights", Teuchos::Array<double>, dropParams);
1079 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: coloring: localize color graph", bool, dropParams);
1080 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: dropping may create Dirichlet", bool, dropParams);
1081 if (useKokkos_) {
1082 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: use blocking", bool, dropParams);
1083 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: symmetrize graph after dropping", bool, dropParams);
1084 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: strength-of-connection: matrix", std::string, dropParams);
1085 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: strength-of-connection: measure", std::string, dropParams);
1086 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "filtered matrix: use lumping", bool, dropParams);
1087 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "filtered matrix: reuse graph", bool, dropParams);
1088 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "filtered matrix: reuse eigenvalue", bool, dropParams);
1089 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "filtered matrix: use root stencil", bool, dropParams);
1090 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "filtered matrix: Dirichlet threshold", double, dropParams);
1091 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "filtered matrix: use spread lumping", bool, dropParams);
1092 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "filtered matrix: lumping choice", std::string, dropParams);
1093 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "filtered matrix: spread lumping diag dom growth factor", double, dropParams);
1094 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "filtered matrix: spread lumping diag dom cap", double, dropParams);
1095 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "filtered matrix: count negative diagonals", bool, dropParams);
1096 }
1097
1098#ifdef HAVE_MUELU_COALESCEDROP_ALLOW_OLD_PARAMETERS
1099 if (!dropParams.isParameter("aggregation: drop scheme") ||
1100 (dropParams.isParameter("aggregation: drop scheme") &&
1101 ((dropParams.get<std::string>("aggregation: drop scheme") != "point-wise") && (dropParams.get<std::string>("aggregation: drop scheme") != "cut-drop")))) {
1102 Teuchos::ParameterList dropParamsWithDefaults(dropParams);
1103
1104#define MUELU_TEST_AND_SET_VAR_FROM_MASTERLIST(paramList, paramName, paramType) \
1105 if (!paramList.isParameter(paramName)) { \
1106 paramList.set(paramName, MasterList::getDefault<paramType>(paramName)); \
1107 }
1108
1109 MUELU_TEST_AND_SET_VAR_FROM_MASTERLIST(dropParamsWithDefaults, "aggregation: drop scheme", std::string);
1110 MUELU_TEST_AND_SET_VAR_FROM_MASTERLIST(dropParamsWithDefaults, "aggregation: strength-of-connection: matrix", std::string);
1111 MUELU_TEST_AND_SET_VAR_FROM_MASTERLIST(dropParamsWithDefaults, "aggregation: strength-of-connection: measure", std::string);
1112 MUELU_TEST_AND_SET_VAR_FROM_MASTERLIST(dropParamsWithDefaults, "aggregation: use blocking", bool);
1113
1114#undef MUELU_TEST_AND_SET_VAR_FROM_MASTERLIST
1115
1116 // We are using the old style of dropping params
1117 TEUCHOS_TEST_FOR_EXCEPTION(dropParams.isParameter("aggregation: strength-of-connection: matrix") ||
1118 dropParams.isParameter("aggregation: strength-of-connection: measure") ||
1119 dropParams.isParameter("aggregation: use blocking"),
1120 Teuchos::Exceptions::InvalidParameterType,
1121 "The inputs contain a mix of old and new dropping parameters:\n\n"
1122 << dropParams << "\n\nKeep in mind that defaults are set for old parameters, so this gets interpreted as\n\n"
1123 << dropParamsWithDefaults);
1124 }
1125#endif
1126
1127 if (!amalgFact.is_null())
1128 dropFactory->SetFactory("UnAmalgamationInfo", manager.GetFactory("UnAmalgamationInfo"));
1129
1130 if (dropParams.isParameter("aggregation: drop scheme")) {
1131 std::string drop_scheme = dropParams.get<std::string>("aggregation: drop scheme");
1132 if (drop_scheme == "block diagonal colored signed classical")
1133 manager.SetFactory("Coloring Graph", dropFactory);
1134 if ((MUELU_TEST_PARAM_2LIST(dropParams, defaultList, "aggregation: use blocking", bool, true)) ||
1135 (drop_scheme.find("block diagonal") != std::string::npos || drop_scheme == "signed classical")) {
1136 if (levelID > 0)
1137 dropFactory->SetFactory("BlockNumber", this->GetFactoryManager(levelID - 1)->GetFactory("BlockNumber"));
1138 else
1139 dropFactory->SetFactory("BlockNumber", manager.GetFactory("BlockNumber"));
1140 }
1141 }
1142
1143 dropFactory->SetParameterList(dropParams);
1144 }
1145 manager.SetFactory("Graph", dropFactory);
1146
1147// Aggregation scheme
1148#ifndef HAVE_MUELU_MATLAB
1149 if (aggType == "matlab")
1150 throw std::runtime_error("Cannot use MATLAB aggregation - MueLu was not configured with MATLAB support.");
1151#endif
1152 RCP<Factory> aggFactory;
1153 if (aggType == "uncoupled") {
1154 aggFactory = rcp(new UncoupledAggregationFactory());
1155 ParameterList aggParams;
1156 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: ordering", std::string, aggParams);
1157 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: min agg size", int, aggParams);
1158 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: max agg size", int, aggParams);
1159 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: max selected neighbors", int, aggParams);
1160 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: backend", std::string, aggParams);
1161 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: phase 1 algorithm", std::string, aggParams);
1162 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: deterministic", bool, aggParams);
1163 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: coloring algorithm", std::string, aggParams);
1164 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: enable phase 1", bool, aggParams);
1165 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: enable phase 2a", bool, aggParams);
1166 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: enable phase 2b", bool, aggParams);
1167 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: enable phase 3", bool, aggParams);
1168 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: match ML phase1", bool, aggParams);
1169 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: match ML phase2a", bool, aggParams);
1170 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: match ML phase2b", bool, aggParams);
1171 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: phase2a agg factor", double, aggParams);
1172 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: preserve Dirichlet points", bool, aggParams);
1173 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: error on nodes with no on-rank neighbors", bool, aggParams);
1174 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: phase3 avoid singletons", bool, aggParams);
1175 aggFactory->SetParameterList(aggParams);
1176 // make sure that the aggregation factory has all necessary data
1177 aggFactory->SetFactory("DofsPerNode", manager.GetFactory("Graph"));
1178 aggFactory->SetFactory("Graph", manager.GetFactory("Graph"));
1179 // aggFactory->SetFactory("UnAmalgamationInfo", manager.GetFactory("UnAmalgamationInfo"));
1180
1181 if (MUELU_TEST_PARAM_2LIST(paramList, defaultList, "aggregation: coloring algorithm", std::string, "mis2 aggregation") ||
1182 MUELU_TEST_PARAM_2LIST(paramList, defaultList, "aggregation: coloring algorithm", std::string, "mis2 coarsening")) {
1183 if (MUELU_TEST_PARAM_2LIST(paramList, defaultList, "aggregation: symmetrize graph after dropping", bool, false))
1184 TEUCHOS_TEST_FOR_EXCEPTION(true,
1186 "MIS2 algorithms require the use of a symmetrized graph. Please set \"aggregation: symmetrize graph after dropping\" to \"true\".");
1187 }
1188 } else if (aggType == "brick") {
1189 aggFactory = rcp(new BrickAggregationFactory());
1190 ParameterList aggParams;
1191 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: brick x size", int, aggParams);
1192 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: brick y size", int, aggParams);
1193 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: brick z size", int, aggParams);
1194 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: brick x Dirichlet", bool, aggParams);
1195 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: brick y Dirichlet", bool, aggParams);
1196 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: brick z Dirichlet", bool, aggParams);
1197 aggFactory->SetParameterList(aggParams);
1198
1199 // Unlike other factories, BrickAggregationFactory makes the Graph/DofsPerNode itself
1200 manager.SetFactory("Graph", aggFactory);
1201 manager.SetFactory("DofsPerNode", aggFactory);
1202 manager.SetFactory("Filtering", aggFactory);
1203 if (levelID > 1) {
1204 // We check for levelID > 0, as in the interpreter aggFactory for
1205 // levelID really corresponds to level 0. Managers are clunky, as they
1206 // contain factories for two different levels
1207 aggFactory->SetFactory("Coordinates", this->GetFactoryManager(levelID - 1)->GetFactory("Coordinates"));
1208 }
1209 } else if (aggType == "classical") {
1210 // Map and coloring
1211 RCP<Factory> mapFact = rcp(new ClassicalMapFactory());
1212 ParameterList mapParams;
1213 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: deterministic", bool, mapParams);
1214 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: coloring algorithm", std::string, mapParams);
1215
1216 ParameterList tempParams;
1217 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: drop scheme", std::string, tempParams);
1218 std::string drop_algo = tempParams.get<std::string>("aggregation: drop scheme");
1219 if (drop_algo == "block diagonal colored signed classical") {
1220 mapParams.set("aggregation: coloring: use color graph", true);
1221 mapFact->SetFactory("Coloring Graph", manager.GetFactory("Coloring Graph"));
1222 }
1223 mapFact->SetParameterList(mapParams);
1224 mapFact->SetFactory("Graph", manager.GetFactory("Graph"));
1225 mapFact->SetFactory("UnAmalgamationInfo", manager.GetFactory("UnAmalgamationInfo"));
1226
1227 manager.SetFactory("FC Splitting", mapFact);
1228 manager.SetFactory("CoarseMap", mapFact);
1229
1230 aggFactory = rcp(new ClassicalPFactory());
1231 ParameterList aggParams;
1232 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: classical scheme", std::string, aggParams);
1233 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: drop scheme", std::string, aggParams);
1234 aggFactory->SetParameterList(aggParams);
1235 aggFactory->SetFactory("FC Splitting", manager.GetFactory("FC Splitting"));
1236 aggFactory->SetFactory("CoarseMap", manager.GetFactory("CoarseMap"));
1237 aggFactory->SetFactory("DofsPerNode", manager.GetFactory("Graph"));
1238 aggFactory->SetFactory("Graph", manager.GetFactory("Graph"));
1239
1240 if (drop_algo.find("block diagonal") != std::string::npos || drop_algo == "signed classical") {
1241 if (levelID > 0)
1242 aggFactory->SetFactory("BlockNumber", this->GetFactoryManager(levelID - 1)->GetFactory("BlockNumber"));
1243 else
1244 aggFactory->SetFactory("BlockNumber", manager.GetFactory("BlockNumber"));
1245 }
1246
1247 // Now we short-circuit, because we neither need nor want TentativePFactory here
1248 manager.SetFactory("Ptent", aggFactory);
1249 manager.SetFactory("P Graph", aggFactory);
1250
1251 if (reuseType == "tP" && levelID) {
1252 // keeps.push_back(keep_pair("Nullspace", Ptent.get()));
1253 keeps.push_back(keep_pair("Ptent", aggFactory.get()));
1254 }
1255 return;
1256 } else if (aggType == "notay") {
1257 aggFactory = rcp(new NotayAggregationFactory());
1258 ParameterList aggParams;
1259 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: pairwise: size", int, aggParams);
1260 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: pairwise: tie threshold", double, aggParams);
1261 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: Dirichlet threshold", double, aggParams);
1262 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: ordering", std::string, aggParams);
1263 aggFactory->SetParameterList(aggParams);
1264 aggFactory->SetFactory("DofsPerNode", manager.GetFactory("Graph"));
1265 aggFactory->SetFactory("Graph", manager.GetFactory("Graph"));
1266 }
1267#ifdef HAVE_MUELU_MATLAB
1268 else if (aggType == "matlab") {
1269 ParameterList aggParams = paramList.sublist("aggregation: params");
1270 aggFactory = rcp(new SingleLevelMatlabFactory());
1271 aggFactory->SetParameterList(aggParams);
1272 }
1273#endif
1274
1275 manager.SetFactory("Aggregates", aggFactory);
1276
1277 // Coarse map
1278 RCP<Factory> coarseMap = rcp(new CoarseMapFactory());
1279 coarseMap->SetFactory("Aggregates", manager.GetFactory("Aggregates"));
1280 manager.SetFactory("CoarseMap", coarseMap);
1281
1282 // Tentative P
1284 ParameterList ptentParams;
1285 if (paramList.isSublist("matrixmatrix: kernel params"))
1286 ptentParams.sublist("matrixmatrix: kernel params", false) = paramList.sublist("matrixmatrix: kernel params");
1287 if (defaultList.isSublist("matrixmatrix: kernel params"))
1288 ptentParams.sublist("matrixmatrix: kernel params", false) = defaultList.sublist("matrixmatrix: kernel params");
1289 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "tentative: calculate qr", bool, ptentParams);
1290 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "tentative: build coarse coordinates", bool, ptentParams);
1291 Ptent->SetParameterList(ptentParams);
1292 Ptent->SetFactory("Aggregates", manager.GetFactory("Aggregates"));
1293 Ptent->SetFactory("CoarseMap", manager.GetFactory("CoarseMap"));
1294 manager.SetFactory("Ptent", Ptent);
1295
1296 if (reuseType == "tP" && levelID) {
1297 keeps.push_back(keep_pair("Nullspace", Ptent.get()));
1298 keeps.push_back(keep_pair("P", Ptent.get()));
1299 }
1300}
1301
1302// =====================================================================================================
1303// ============================================ RAP ====================================================
1304// =====================================================================================================
1305template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1307 UpdateFactoryManager_RAP(ParameterList& paramList, const ParameterList& defaultList, FactoryManager& manager,
1308 int levelID, std::vector<keep_pair>& keeps) const {
1309 if (paramList.isParameter("A") && !paramList.get<RCP<Matrix> >("A").is_null()) {
1310 // We have user matrix A
1311 manager.SetFactory("A", NoFactory::getRCP());
1312 return;
1313 }
1314
1315 ParameterList RAPparams;
1316
1317 RCP<RAPFactory> RAP;
1318 RCP<RAPShiftFactory> RAPs;
1319 // Allow for Galerkin or shifted RAP
1320 // FIXME: Should this not be some form of MUELU_SET_VAR_2LIST?
1321 std::string alg = paramList.get("rap: algorithm", "galerkin");
1322 if (alg == "shift" || alg == "non-galerkin") {
1323 RAPs = rcp(new RAPShiftFactory());
1324 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "rap: shift", double, RAPparams);
1325 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "rap: shift diagonal M", bool, RAPparams);
1326 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "rap: shift low storage", bool, RAPparams);
1327 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "rap: shift array", Teuchos::Array<double>, RAPparams);
1328 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "rap: cfl array", Teuchos::Array<double>, RAPparams);
1329
1330 } else {
1331 RAP = rcp(new RAPFactory());
1332 }
1333
1334 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "rap: relative diagonal floor", Teuchos::Array<double>, RAPparams);
1335
1336 if (paramList.isSublist("matrixmatrix: kernel params"))
1337 RAPparams.sublist("matrixmatrix: kernel params", false) = paramList.sublist("matrixmatrix: kernel params");
1338 if (defaultList.isSublist("matrixmatrix: kernel params"))
1339 RAPparams.sublist("matrixmatrix: kernel params", false) = defaultList.sublist("matrixmatrix: kernel params");
1340 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "transpose: use implicit", bool, RAPparams);
1341 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "rap: fix zero diagonals", bool, RAPparams);
1342 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "rap: fix zero diagonals threshold", double, RAPparams);
1343 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "rap: fix zero diagonals replacement", Scalar, RAPparams);
1344
1345 // if "rap: triple product" has not been set and algorithm is "unsmoothed" switch triple product on
1346 if (!paramList.isParameter("rap: triple product") &&
1347 paramList.isType<std::string>("multigrid algorithm") &&
1348 paramList.get<std::string>("multigrid algorithm") == "unsmoothed")
1349 paramList.set("rap: triple product", true);
1350 else
1351 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "rap: triple product", bool, RAPparams);
1352
1353 try {
1354 if (paramList.isParameter("aggregation: allow empty prolongator columns")) {
1355 RAPparams.set("CheckMainDiagonal", paramList.get<bool>("aggregation: allow empty prolongator columns"));
1356 RAPparams.set("RepairMainDiagonal", paramList.get<bool>("aggregation: allow empty prolongator columns"));
1357 } else if (defaultList.isParameter("aggregation: allow empty prolongator columns")) {
1358 RAPparams.set("CheckMainDiagonal", defaultList.get<bool>("aggregation: allow empty prolongator columns"));
1359 RAPparams.set("RepairMainDiagonal", defaultList.get<bool>("aggregation: allow empty prolongator columns"));
1360 }
1361
1362 } catch (Teuchos::Exceptions::InvalidParameterType&) {
1363 TEUCHOS_TEST_FOR_EXCEPTION_PURE_MSG(true, Teuchos::Exceptions::InvalidParameterType,
1364 "Error: parameter \"aggregation: allow empty prolongator columns\" must be of type " << Teuchos::TypeNameTraits<bool>::name());
1365 }
1366
1367 if (!RAP.is_null()) {
1368 RAP->SetParameterList(RAPparams);
1369 RAP->SetFactory("P", manager.GetFactory("P"));
1370 } else {
1371 RAPs->SetParameterList(RAPparams);
1372 RAPs->SetFactory("P", manager.GetFactory("P"));
1373 }
1374
1375 if (!this->implicitTranspose_) {
1376 if (!RAP.is_null())
1377 RAP->SetFactory("R", manager.GetFactory("R"));
1378 else
1379 RAPs->SetFactory("R", manager.GetFactory("R"));
1380 }
1381
1382 // Matrix analysis
1383 if (MUELU_TEST_PARAM_2LIST(paramList, defaultList, "matrix: compute analysis", bool, true)) {
1384 RCP<Factory> matrixAnalysisFact = rcp(new MatrixAnalysisFactory());
1385
1386 if (!RAP.is_null())
1387 RAP->AddTransferFactory(matrixAnalysisFact);
1388 else
1389 RAPs->AddTransferFactory(matrixAnalysisFact);
1390 }
1391
1392 // Aggregate qualities
1393 if (MUELU_TEST_PARAM_2LIST(paramList, defaultList, "aggregation: compute aggregate qualities", bool, true)) {
1394 RCP<Factory> aggQualityFact = rcp(new AggregateQualityEstimateFactory());
1395 ParameterList aggQualityParams;
1396 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregate qualities: good aggregate threshold", double, aggQualityParams);
1397 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregate qualities: file output", bool, aggQualityParams);
1398 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregate qualities: file base", std::string, aggQualityParams);
1399 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregate qualities: check symmetry", bool, aggQualityParams);
1400 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregate qualities: algorithm", std::string, aggQualityParams);
1401 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregate qualities: zero threshold", double, aggQualityParams);
1402 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregate qualities: percentiles", Teuchos::Array<double>, aggQualityParams);
1403 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregate qualities: mode", std::string, aggQualityParams);
1404 aggQualityFact->SetParameterList(aggQualityParams);
1405 aggQualityFact->SetFactory("Aggregates", manager.GetFactory("Aggregates"));
1406 aggQualityFact->SetFactory("CoarseMap", manager.GetFactory("CoarseMap"));
1407 manager.SetFactory("AggregateQualities", aggQualityFact);
1408
1409 if (!RAP.is_null())
1410 RAP->AddTransferFactory(aggQualityFact);
1411 else
1412 RAPs->AddTransferFactory(aggQualityFact);
1413 }
1414
1415 if (MUELU_TEST_PARAM_2LIST(paramList, defaultList, "aggregation: export visualization data", bool, true)) {
1416 RCP<AggregationExportFactory> aggExport = rcp(new AggregationExportFactory());
1417 ParameterList aggExportParams;
1418 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: output filename", std::string, aggExportParams);
1419 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: output file: agg style", std::string, aggExportParams);
1420 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: output file: iter", int, aggExportParams);
1421 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: output file: time step", int, aggExportParams);
1422 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: output file: fine graph edges", bool, aggExportParams);
1423 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: output file: coarse graph edges", bool, aggExportParams);
1424 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: output file: build colormap", bool, aggExportParams);
1425 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: output file: aggregate qualities", bool, aggExportParams);
1426 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: output file: material", bool, aggExportParams);
1427 aggExport->SetParameterList(aggExportParams);
1428 aggExport->SetFactory("AggregateQualities", manager.GetFactory("AggregateQualities"));
1429 aggExport->SetFactory("DofsPerNode", manager.GetFactory("DofsPerNode"));
1430 aggExport->SetFactory("Aggregates", manager.GetFactory("Aggregates"));
1431 aggExport->SetFactory("Graph", manager.GetFactory("Graph"));
1432
1433 if (!RAP.is_null())
1434 RAP->AddTransferFactory(aggExport);
1435 else
1436 RAPs->AddTransferFactory(aggExport);
1437 }
1438 if (!RAP.is_null())
1439 manager.SetFactory("A", RAP);
1440 else
1441 manager.SetFactory("A", RAPs);
1442
1443 MUELU_SET_VAR_2LIST(paramList, defaultList, "reuse: type", std::string, reuseType);
1444 MUELU_SET_VAR_2LIST(paramList, defaultList, "sa: use filtered matrix", bool, useFiltering);
1445 bool filteringChangesMatrix = useFiltering && !MUELU_TEST_PARAM_2LIST(paramList, defaultList, "aggregation: drop tol", double, 0);
1446
1447 if (reuseType == "RP" || (reuseType == "tP" && !filteringChangesMatrix)) {
1448 if (!RAP.is_null()) {
1449 keeps.push_back(keep_pair("AP reuse data", RAP.get()));
1450 keeps.push_back(keep_pair("RAP reuse data", RAP.get()));
1451
1452 } else {
1453 keeps.push_back(keep_pair("AP reuse data", RAPs.get()));
1454 keeps.push_back(keep_pair("RAP reuse data", RAPs.get()));
1455 }
1456 }
1457}
1458
1459// =====================================================================================================
1460// ======================================= Coordinates =================================================
1461// =====================================================================================================
1462template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1464 UpdateFactoryManager_Coordinates(ParameterList& paramList, const ParameterList& /* defaultList */,
1465 FactoryManager& manager, int /* levelID */, std::vector<keep_pair>& /* keeps */) const {
1466 bool have_userCO = false;
1467 if (paramList.isParameter("Coordinates") && !paramList.get<RCP<MultiVector> >("Coordinates").is_null())
1468 have_userCO = true;
1469
1470 if (useCoordinates_) {
1471 if (have_userCO) {
1472 manager.SetFactory("Coordinates", NoFactory::getRCP());
1473
1474 } else {
1475 RCP<Factory> coords = rcp(new CoordinatesTransferFactory());
1476 coords->SetFactory("Aggregates", manager.GetFactory("Aggregates"));
1477 coords->SetFactory("CoarseMap", manager.GetFactory("CoarseMap"));
1478 manager.SetFactory("Coordinates", coords);
1479
1480 auto RAP = rcp_const_cast<RAPFactory>(rcp_dynamic_cast<const RAPFactory>(manager.GetFactory("A")));
1481 if (!RAP.is_null()) {
1482 RAP->AddTransferFactory(manager.GetFactory("Coordinates"));
1483 } else {
1484 auto RAPs = rcp_const_cast<RAPShiftFactory>(rcp_dynamic_cast<const RAPShiftFactory>(manager.GetFactory("A")));
1485 RAPs->AddTransferFactory(manager.GetFactory("Coordinates"));
1486 }
1487 }
1488 }
1489}
1490
1491// ======================================================================================================
1492// ======================================== Material ==================================================
1493// =====================================================================================================
1494template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1496 UpdateFactoryManager_Material(ParameterList& paramList, const ParameterList& /* defaultList */,
1497 FactoryManager& manager, int /* levelID */, std::vector<keep_pair>& /* keeps */) const {
1498 bool have_userMaterial = false;
1499 if (paramList.isParameter("Material") && !paramList.get<RCP<MultiVector> >("Material").is_null())
1500 have_userMaterial = true;
1501
1502 if (useMaterial_) {
1503 if (have_userMaterial) {
1504 manager.SetFactory("Material", NoFactory::getRCP());
1505 } else {
1506 RCP<Factory> materialTransfer = rcp(new MultiVectorTransferFactory());
1507 ParameterList materialTransferParameters;
1508 materialTransferParameters.set("Vector name", "Material");
1509 materialTransferParameters.set("Transfer name", "Aggregates");
1510 materialTransferParameters.set("Normalize", true);
1511 materialTransfer->SetParameterList(materialTransferParameters);
1512 materialTransfer->SetFactory("Transfer factory", manager.GetFactory("Aggregates"));
1513 materialTransfer->SetFactory("CoarseMap", manager.GetFactory("CoarseMap"));
1514 manager.SetFactory("Material", materialTransfer);
1515
1516 auto RAP = rcp_const_cast<RAPFactory>(rcp_dynamic_cast<const RAPFactory>(manager.GetFactory("A")));
1517 if (!RAP.is_null()) {
1518 RAP->AddTransferFactory(manager.GetFactory("Material"));
1519 } else {
1520 auto RAPs = rcp_const_cast<RAPShiftFactory>(rcp_dynamic_cast<const RAPShiftFactory>(manager.GetFactory("A")));
1521 RAPs->AddTransferFactory(manager.GetFactory("Material"));
1522 }
1523 }
1524 }
1525}
1526
1527// =====================================================================================================
1528// ================================= LocalOrdinalTransfer =============================================
1529// =====================================================================================================
1530template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1532 UpdateFactoryManager_LocalOrdinalTransfer(const std::string& VarName, const std::string& multigridAlgo, ParameterList& paramList, const ParameterList& /* defaultList */,
1533 FactoryManager& manager, int levelID, std::vector<keep_pair>& /* keeps */) const {
1534 // NOTE: You would think this would be levelID > 0, but you'd be wrong, since the FactoryManager is basically
1535 // offset by a level from the things which actually do the work.
1536 if (useBlockNumber_ && (levelID > 0)) {
1537 auto RAP = rcp_const_cast<RAPFactory>(rcp_dynamic_cast<const RAPFactory>(manager.GetFactory("A")));
1538 auto RAPs = rcp_const_cast<RAPShiftFactory>(rcp_dynamic_cast<const RAPShiftFactory>(manager.GetFactory("A")));
1539 if (!RAP.is_null() || !RAPs.is_null()) {
1540 RCP<Factory> fact = rcp(new LocalOrdinalTransferFactory(VarName, multigridAlgo));
1541 if (multigridAlgo == "classical")
1542 fact->SetFactory("P Graph", manager.GetFactory("P Graph"));
1543 else
1544 fact->SetFactory("Aggregates", manager.GetFactory("Aggregates"));
1545 fact->SetFactory("CoarseMap", manager.GetFactory("CoarseMap"));
1546
1547 fact->SetFactory(VarName, this->GetFactoryManager(levelID - 1)->GetFactory(VarName));
1548
1549 manager.SetFactory(VarName, fact);
1550
1551 if (!RAP.is_null())
1552 RAP->AddTransferFactory(manager.GetFactory(VarName));
1553 else
1554 RAPs->AddTransferFactory(manager.GetFactory(VarName));
1555 }
1556 }
1557}
1558
1559// ======================================================================================================
1560// ====================================== BlockNumber =================================================
1561// =====================================================================================================
1562template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1564 UpdateFactoryManager_BlockNumber(ParameterList& paramList, const ParameterList& defaultList,
1565 FactoryManager& manager, int levelID, std::vector<keep_pair>& keeps) const {
1566 if (useBlockNumber_) {
1567 ParameterList myParams;
1568 RCP<Factory> fact = rcp(new InitialBlockNumberFactory());
1569 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "aggregation: block diagonal: interleaved blocksize", int, myParams);
1570 fact->SetParameterList(myParams);
1571 manager.SetFactory("BlockNumber", fact);
1572 }
1573}
1574
1575// =====================================================================================================
1576// =========================================== Restriction =============================================
1577// =====================================================================================================
1578template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1580 UpdateFactoryManager_Restriction(ParameterList& paramList, const ParameterList& defaultList, FactoryManager& manager,
1581 int levelID, std::vector<keep_pair>& /* keeps */) const {
1582 MUELU_SET_VAR_2LIST(paramList, defaultList, "multigrid algorithm", std::string, multigridAlgo);
1583 bool have_userR = false;
1584 if (paramList.isParameter("R") && !paramList.get<RCP<Matrix> >("R").is_null())
1585 have_userR = true;
1586
1587 // === Restriction ===
1588 RCP<Factory> R;
1589 if (!this->implicitTranspose_) {
1590 MUELU_SET_VAR_2LIST(paramList, defaultList, "problem: symmetric", bool, isSymmetric);
1591
1592 if (isSymmetric == false && (multigridAlgo == "unsmoothed" || multigridAlgo == "emin")) {
1593 this->GetOStream(Warnings0) << "Switching \"problem: symmetric\" parameter to symmetric as multigrid algorithm. " << multigridAlgo << " is primarily supposed to be used for symmetric problems.\n\n"
1594 << "Please note: if you are using \"unsmoothed\" transfer operators the \"problem: symmetric\" parameter "
1595 << "has no real mathematical meaning, i.e. you can use it for non-symmetric\n"
1596 << "problems, too. With \"problem: symmetric\"=\"symmetric\" you can use implicit transpose for building "
1597 << "the restriction operators which may drastically reduce the amount of consumed memory." << std::endl;
1598 isSymmetric = true;
1599 }
1600 TEUCHOS_TEST_FOR_EXCEPTION(multigridAlgo == "pg" && isSymmetric == true, Exceptions::RuntimeError,
1601 "Petrov-Galerkin smoothed transfer operators are only allowed for non-symmetric problems: Set \"problem: symmetric\" to false!\n"
1602 "While PG smoothed transfer operators generally would also work for symmetric problems this is an unusual use case. "
1603 "You can use the factory-based xml interface though if you need PG-AMG for symmetric problems.");
1604
1605 if (have_userR) {
1606 manager.SetFactory("R", NoFactory::getRCP());
1607 } else {
1608 if (isSymmetric)
1609 R = rcp(new TransPFactory());
1610 else
1611 R = rcp(new GenericRFactory());
1612
1613 R->SetFactory("P", manager.GetFactory("P"));
1614 manager.SetFactory("R", R);
1615 }
1616
1617 } else {
1618 manager.SetFactory("R", Teuchos::null);
1619 }
1620
1621 // === Restriction: Nullspace Scaling ===
1622 if (paramList.isParameter("restriction: scale nullspace") && paramList.get<bool>("restriction: scale nullspace")) {
1623 RCP<TentativePFactory> tentPFactory = rcp(new TentativePFactory());
1624 Teuchos::ParameterList tentPlist;
1625 tentPlist.set("Nullspace name", "Scaled Nullspace");
1626 tentPFactory->SetParameterList(tentPlist);
1627 tentPFactory->SetFactory("Aggregates", manager.GetFactory("Aggregates"));
1628 tentPFactory->SetFactory("CoarseMap", manager.GetFactory("CoarseMap"));
1629
1630 if (R.is_null()) R = rcp(new TransPFactory());
1631 R->SetFactory("P", tentPFactory);
1632 }
1633}
1634
1635// =====================================================================================================
1636// ========================================= Repartition ===============================================
1637// =====================================================================================================
1638template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1640 UpdateFactoryManager_Repartition(ParameterList& paramList, const ParameterList& defaultList, FactoryManager& manager,
1641 int levelID, std::vector<keep_pair>& keeps, RCP<Factory>& nullSpaceFactory) const {
1642 // === Repartitioning ===
1643 MUELU_SET_VAR_2LIST(paramList, defaultList, "reuse: type", std::string, reuseType);
1644 MUELU_SET_VAR_2LIST(paramList, defaultList, "repartition: enable", bool, enableRepart);
1645 if (enableRepart) {
1646#if defined(HAVE_MPI) && (defined(HAVE_MUELU_ZOLTAN) || defined(HAVE_MUELU_ZOLTAN2)) // skip to the end, print warning, and turn off repartitioning if we don't have MPI and Zoltan/Zoltan2
1647 MUELU_SET_VAR_2LIST(paramList, defaultList, "repartition: use subcommunicators in place", bool, enableInPlace);
1648 // Short summary of the issue: RebalanceTransferFactory shares ownership
1649 // of "P" with SaPFactory, and therefore, changes the stored version.
1650 // That means that if SaPFactory generated P, and stored it on the level,
1651 // then after rebalancing the value in that storage changed. It goes
1652 // against the concept of factories (I think), that every factory is
1653 // responsible for its own objects, and they are immutable outside.
1654 //
1655 // In reuse, this is what happens: as we reuse Importer across setups,
1656 // the order of factories changes, and coupled with shared ownership
1657 // leads to problems.
1658 // *First setup*
1659 // SaP builds P [and stores it]
1660 // TransP builds R [and stores it]
1661 // RAP builds A [and stores it]
1662 // RebalanceTransfer rebalances P [and changes the P stored by SaP] (*)
1663 // RebalanceTransfer rebalances R
1664 // RebalanceAc rebalances A
1665 // *Second setup* ("RP" reuse)
1666 // RebalanceTransfer rebalances P [which is incorrect due to (*)]
1667 // RebalanceTransfer rebalances R
1668 // RAP builds A [which is incorrect due to (*)]
1669 // RebalanceAc rebalances A [which throws due to map inconsistency]
1670 // ...
1671 // *Second setup* ("tP" reuse)
1672 // SaP builds P [and stores it]
1673 // RebalanceTransfer rebalances P [and changes the P stored by SaP] (**)
1674 // TransP builds R [which is incorrect due to (**)]
1675 // RebalanceTransfer rebalances R
1676 // ...
1677 //
1678 // Couple solutions to this:
1679 // 1. [implemented] Requre "tP" and "PR" reuse to only be used with
1680 // implicit rebalancing.
1681 // 2. Do deep copy of P, and changed domain map and importer there.
1682 // Need to investigate how expensive this is.
1683 TEUCHOS_TEST_FOR_EXCEPTION(this->doPRrebalance_ && (reuseType == "tP" || reuseType == "RP"), Exceptions::InvalidArgument,
1684 "Reuse types \"tP\" and \"PR\" require \"repartition: rebalance P and R\" set to \"false\"");
1685
1686 // TEUCHOS_TEST_FOR_EXCEPTION(aggType == "brick", Exceptions::InvalidArgument,
1687 // "Aggregation type \"brick\" requires \"repartition: enable\" set to \"false\"");
1688
1689 MUELU_SET_VAR_2LIST(paramList, defaultList, "repartition: partitioner", std::string, partName);
1690 TEUCHOS_TEST_FOR_EXCEPTION(partName != "zoltan" && partName != "zoltan2", Exceptions::InvalidArgument,
1691 "Invalid partitioner name: \"" << partName << "\". Valid options: \"zoltan\", \"zoltan2\"");
1692
1693#ifndef HAVE_MUELU_ZOLTAN
1694 bool switched = false;
1695 if (partName == "zoltan") {
1696 this->GetOStream(Warnings0) << "Zoltan interface is not available, trying to switch to Zoltan2" << std::endl;
1697 partName = "zoltan2";
1698 switched = true;
1699 }
1700#else
1701#ifndef HAVE_MUELU_ZOLTAN2
1702 bool switched = false;
1703#endif // HAVE_MUELU_ZOLTAN2
1704#endif // HAVE_MUELU_ZOLTAN
1705
1706#ifndef HAVE_MUELU_ZOLTAN2
1707 if (partName == "zoltan2" && !switched) {
1708 this->GetOStream(Warnings0) << "Zoltan2 interface is not available, trying to switch to Zoltan" << std::endl;
1709 partName = "zoltan";
1710 }
1711#endif // HAVE_MUELU_ZOLTAN2
1712
1713 MUELU_SET_VAR_2LIST(paramList, defaultList, "repartition: node repartition level", int, nodeRepartitionLevel);
1714
1715 // RepartitionHeuristic
1716 auto repartheurFactory = rcp(new RepartitionHeuristicFactory());
1717 ParameterList repartheurParams;
1718 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "repartition: node repartition level", int, repartheurParams);
1719 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "repartition: start level", int, repartheurParams);
1720 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "repartition: min rows per proc", int, repartheurParams);
1721 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "repartition: target rows per proc", int, repartheurParams);
1722 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "repartition: min rows per thread", int, repartheurParams);
1723 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "repartition: target rows per thread", int, repartheurParams);
1724 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "repartition: max imbalance", double, repartheurParams);
1725 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "repartition: put on single proc", int, repartheurParams);
1726 repartheurFactory->SetParameterList(repartheurParams);
1727 repartheurFactory->SetFactory("A", manager.GetFactory("A"));
1728 manager.SetFactory("number of partitions", repartheurFactory);
1729 manager.SetFactory("repartition: heuristic target rows per process", repartheurFactory);
1730
1731 // Partitioner
1732 RCP<Factory> partitioner;
1733 if (levelID == nodeRepartitionLevel) {
1734 // partitioner = rcp(new NodePartitionInterface());
1735 partitioner = rcp(new MueLu::NodePartitionInterface<SC, LO, GO, NO>());
1736 ParameterList partParams;
1737 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "repartition: node id", int, repartheurParams);
1738 partitioner->SetParameterList(partParams);
1739 partitioner->SetFactory("Node Comm", manager.GetFactory("Node Comm"));
1740 } else if (partName == "zoltan") {
1741#ifdef HAVE_MUELU_ZOLTAN
1742 partitioner = rcp(new ZoltanInterface());
1743 // NOTE: ZoltanInterface ("zoltan") does not support external parameters through ParameterList
1744#else
1745 throw Exceptions::RuntimeError("Zoltan interface is not available");
1746#endif // HAVE_MUELU_ZOLTAN
1747 } else if (partName == "zoltan2") {
1748#ifdef HAVE_MUELU_ZOLTAN2
1749 partitioner = rcp(new Zoltan2Interface());
1750 ParameterList partParams;
1751 RCP<const ParameterList> partpartParams = rcp(new ParameterList(paramList.sublist("repartition: params", false)));
1752 partParams.set("ParameterList", partpartParams);
1753 partitioner->SetParameterList(partParams);
1754 partitioner->SetFactory("repartition: heuristic target rows per process",
1755 manager.GetFactory("repartition: heuristic target rows per process"));
1756#else
1757 throw Exceptions::RuntimeError("Zoltan2 interface is not available");
1758#endif // HAVE_MUELU_ZOLTAN2
1759 }
1760
1761 partitioner->SetFactory("A", manager.GetFactory("A"));
1762 partitioner->SetFactory("number of partitions", manager.GetFactory("number of partitions"));
1763 if (useCoordinates_)
1764 partitioner->SetFactory("Coordinates", manager.GetFactory("Coordinates"));
1765 manager.SetFactory("Partition", partitioner);
1766
1767 // Repartitioner
1768 auto repartFactory = rcp(new RepartitionFactory());
1769 ParameterList repartParams;
1770 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "repartition: print partition distribution", bool, repartParams);
1771 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "repartition: remap parts", bool, repartParams);
1772 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "repartition: remap num values", int, repartParams);
1773 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "repartition: save importer", bool, repartParams);
1774 repartFactory->SetParameterList(repartParams);
1775 repartFactory->SetFactory("A", manager.GetFactory("A"));
1776 repartFactory->SetFactory("number of partitions", manager.GetFactory("number of partitions"));
1777 repartFactory->SetFactory("Partition", manager.GetFactory("Partition"));
1778 manager.SetFactory("Importer", repartFactory);
1779 if (reuseType != "none" && reuseType != "S" && levelID)
1780 keeps.push_back(keep_pair("Importer", manager.GetFactory("Importer").get()));
1781
1782 if (enableInPlace) {
1783 // Rebalanced A (in place)
1784 // NOTE: This is for when we want to constrain repartitioning to match some other idea of what's going on.
1785 // The major application is the (1,1) hierarchy in the Maxwell1 preconditioner.
1786 auto newA = rcp(new RebalanceAcFactory());
1787 ParameterList rebAcParams;
1788 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "repartition: use subcommunicators", bool, rebAcParams);
1789 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "repartition: use subcommunicators in place", bool, rebAcParams);
1790 newA->SetParameterList(rebAcParams);
1791 newA->SetFactory("A", manager.GetFactory("A"));
1792 newA->SetFactory("InPlaceMap", manager.GetFactory("InPlaceMap"));
1793 manager.SetFactory("A", newA);
1794 } else {
1795 // Rebalanced A
1796 auto newA = rcp(new RebalanceAcFactory());
1797 ParameterList rebAcParams;
1798 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "repartition: use subcommunicators", bool, rebAcParams);
1799 newA->SetParameterList(rebAcParams);
1800 newA->SetFactory("A", manager.GetFactory("A"));
1801 newA->SetFactory("Importer", manager.GetFactory("Importer"));
1802 manager.SetFactory("A", newA);
1803
1804 // Rebalanced P
1805 auto newP = rcp(new RebalanceTransferFactory());
1806 ParameterList newPparams;
1807 newPparams.set("type", "Interpolation");
1808 if (changedPRrebalance_)
1809 newPparams.set("repartition: rebalance P and R", this->doPRrebalance_);
1810 if (changedPRViaCopyrebalance_)
1811 newPparams.set("repartition: explicit via new copy rebalance P and R", true);
1812 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "repartition: use subcommunicators", bool, newPparams);
1813 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "repartition: send type", std::string, newPparams);
1814 newP->SetParameterList(newPparams);
1815 newP->SetFactory("Importer", manager.GetFactory("Importer"));
1816 newP->SetFactory("P", manager.GetFactory("P"));
1817 manager.SetFactory("P", newP);
1818 if (!paramList.isParameter("semicoarsen: number of levels"))
1819 newP->SetFactory("Nullspace", manager.GetFactory("Ptent"));
1820 else
1821 newP->SetFactory("Nullspace", manager.GetFactory("P")); // TogglePFactory
1822 if (useCoordinates_) {
1823 newP->SetFactory("Coordinates", manager.GetFactory("Coordinates"));
1824 manager.SetFactory("Coordinates", newP);
1825 }
1826 if (useMaterial_) {
1827 newP->SetFactory("Material", manager.GetFactory("Material"));
1828 manager.SetFactory("Material", newP);
1829 }
1830 if (useBlockNumber_ && (levelID > 0)) {
1831 newP->SetFactory("BlockNumber", manager.GetFactory("BlockNumber"));
1832 manager.SetFactory("BlockNumber", newP);
1833 }
1834
1835 // Rebalanced R
1836 auto newR = rcp(new RebalanceTransferFactory());
1837 ParameterList newRparams;
1838 newRparams.set("type", "Restriction");
1839 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "repartition: use subcommunicators", bool, newRparams);
1840 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "repartition: send type", std::string, newRparams);
1841 if (changedPRrebalance_)
1842 newRparams.set("repartition: rebalance P and R", this->doPRrebalance_);
1843 if (changedPRViaCopyrebalance_)
1844 newPparams.set("repartition: explicit via new copy rebalance P and R", true);
1845 if (changedImplicitTranspose_)
1846 newRparams.set("transpose: use implicit", this->implicitTranspose_);
1847 newR->SetParameterList(newRparams);
1848 newR->SetFactory("Importer", manager.GetFactory("Importer"));
1849 if (!this->implicitTranspose_) {
1850 newR->SetFactory("R", manager.GetFactory("R"));
1851 manager.SetFactory("R", newR);
1852 }
1853
1854 // NOTE: the role of NullspaceFactory is to provide nullspace on the finest
1855 // level if a user does not do that. For all other levels it simply passes
1856 // nullspace from a real factory to whoever needs it. If we don't use
1857 // repartitioning, that factory is "TentativePFactory"; if we do, it is
1858 // "RebalanceTransferFactory". But we still have to have NullspaceFactory as
1859 // the "Nullspace" of the manager
1860 // NOTE: This really needs to be set on the *NullSpaceFactory*, not manager.get("Nullspace").
1861 ParameterList newNullparams;
1862 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "nullspace: calculate rotations", bool, newNullparams);
1863 nullSpaceFactory->SetFactory("Nullspace", newP);
1864 nullSpaceFactory->SetParameterList(newNullparams);
1865 }
1866#else
1867 paramList.set("repartition: enable", false);
1868#ifndef HAVE_MPI
1869 this->GetOStream(Warnings0) << "No repartitioning available for a serial run\n";
1870#else
1871 this->GetOStream(Warnings0) << "Zoltan/Zoltan2 are unavailable for repartitioning\n";
1872#endif // HAVE_MPI
1873#endif // defined(HAVE_MPI) && (defined(HAVE_MUELU_ZOLTAN) || defined(HAVE_MUELU_ZOLTAN2))
1874 }
1875}
1876
1877// =====================================================================================================
1878// ========================================= Low precision transfers ===================================
1879// =====================================================================================================
1880template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1882 UpdateFactoryManager_LowPrecision(ParameterList& paramList, const ParameterList& defaultList, FactoryManager& manager,
1883 int levelID, std::vector<keep_pair>& keeps) const {
1884 MUELU_SET_VAR_2LIST(paramList, defaultList, "transfers: half precision", bool, enableLowPrecision);
1885
1886 if (enableLowPrecision) {
1887 // Low precision P
1888 auto newP = rcp(new LowPrecisionFactory());
1889 ParameterList newPparams;
1890 newPparams.set("matrix key", "P");
1891 newP->SetParameterList(newPparams);
1892 newP->SetFactory("P", manager.GetFactory("P"));
1893 manager.SetFactory("P", newP);
1894
1895 if (!this->implicitTranspose_) {
1896 // Low precision R
1897 auto newR = rcp(new LowPrecisionFactory());
1898 ParameterList newRparams;
1899 newRparams.set("matrix key", "R");
1900 newR->SetParameterList(newRparams);
1901 newR->SetFactory("R", manager.GetFactory("R"));
1902 manager.SetFactory("R", newR);
1903 }
1904 }
1905}
1906
1907// =====================================================================================================
1908// =========================================== Nullspace ===============================================
1909// =====================================================================================================
1910template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1912 UpdateFactoryManager_Nullspace(ParameterList& paramList, const ParameterList& defaultList, FactoryManager& manager,
1913 int /* levelID */, std::vector<keep_pair>& /* keeps */, RCP<Factory>& nullSpaceFactory) const {
1914 // Nullspace
1915 RCP<Factory> nullSpace = rcp(new NullspaceFactory());
1916
1917 bool have_userNS = false;
1918 if (paramList.isParameter("Nullspace") && !paramList.get<RCP<MultiVector> >("Nullspace").is_null())
1919 have_userNS = true;
1920
1921 if (!have_userNS) {
1922 ParameterList newNullparams;
1923 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "nullspace: calculate rotations", bool, newNullparams);
1924 nullSpace->SetParameterList(newNullparams);
1925 nullSpace->SetFactory("Nullspace", manager.GetFactory("Ptent"));
1926 manager.SetFactory("Nullspace", nullSpace);
1927 }
1928 nullSpaceFactory = nullSpace;
1929
1930 if (paramList.isParameter("restriction: scale nullspace") && paramList.get<bool>("restriction: scale nullspace")) {
1931 RCP<ScaledNullspaceFactory> scaledNSfactory = rcp(new ScaledNullspaceFactory());
1932 scaledNSfactory->SetFactory("Nullspace", nullSpaceFactory);
1933 manager.SetFactory("Scaled Nullspace", scaledNSfactory);
1934 }
1935}
1936
1937// =====================================================================================================
1938// ================================= Algorithm: SemiCoarsening =========================================
1939// =====================================================================================================
1940template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1942 UpdateFactoryManager_SemiCoarsen(ParameterList& paramList, const ParameterList& defaultList, FactoryManager& manager,
1943 int /* levelID */, std::vector<keep_pair>& /* keeps */) const {
1944 // === Semi-coarsening ===
1945 RCP<Factory> semicoarsenFactory = Teuchos::null;
1946 if (paramList.isParameter("semicoarsen: number of levels") &&
1947 paramList.get<int>("semicoarsen: number of levels") > 0) {
1948 ParameterList togglePParams;
1949 ParameterList semicoarsenPParams;
1950 ParameterList linedetectionParams;
1951 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "semicoarsen: number of levels", int, togglePParams);
1952 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "semicoarsen: coarsen rate", int, semicoarsenPParams);
1953 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "semicoarsen: piecewise constant", bool, semicoarsenPParams);
1954 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "semicoarsen: piecewise linear", bool, semicoarsenPParams);
1955 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "semicoarsen: calculate nonsym restriction", bool, semicoarsenPParams);
1956 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "linedetection: orientation", std::string, linedetectionParams);
1957 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "linedetection: num layers", int, linedetectionParams);
1958
1960 RCP<LineDetectionFactory> linedetectionFactory = rcp(new LineDetectionFactory());
1961 RCP<TogglePFactory> togglePFactory = rcp(new TogglePFactory());
1962
1963 linedetectionFactory->SetParameterList(linedetectionParams);
1964 semicoarsenFactory->SetParameterList(semicoarsenPParams);
1965 togglePFactory->SetParameterList(togglePParams);
1966
1967 togglePFactory->AddCoarseNullspaceFactory(semicoarsenFactory);
1968 togglePFactory->AddProlongatorFactory(semicoarsenFactory);
1969 togglePFactory->AddPtentFactory(semicoarsenFactory);
1970 togglePFactory->AddCoarseNullspaceFactory(manager.GetFactory("Ptent"));
1971 togglePFactory->AddProlongatorFactory(manager.GetFactory("P"));
1972 togglePFactory->AddPtentFactory(manager.GetFactory("Ptent"));
1973
1974 manager.SetFactory("CoarseNumZLayers", linedetectionFactory);
1975 manager.SetFactory("LineDetection_Layers", linedetectionFactory);
1976 manager.SetFactory("LineDetection_VertLineIds", linedetectionFactory);
1977
1978 manager.SetFactory("P", togglePFactory);
1979 manager.SetFactory("Ptent", togglePFactory);
1980 manager.SetFactory("Nullspace", togglePFactory);
1981 }
1982
1983 if (paramList.isParameter("semicoarsen: number of levels") &&
1984 paramList.get<int>("semicoarsen: number of levels") > 0) {
1985 auto tf = rcp(new ToggleCoordinatesTransferFactory());
1986 tf->SetFactory("Chosen P", manager.GetFactory("P"));
1987 tf->AddCoordTransferFactory(semicoarsenFactory);
1988
1989 RCP<Factory> coords = rcp(new CoordinatesTransferFactory());
1990 coords->SetFactory("Aggregates", manager.GetFactory("Aggregates"));
1991 coords->SetFactory("CoarseMap", manager.GetFactory("CoarseMap"));
1992 tf->AddCoordTransferFactory(coords);
1993 manager.SetFactory("Coordinates", tf);
1994 }
1995}
1996
1997// =====================================================================================================
1998// ================================== Algorithm: P-Coarsening ==========================================
1999// =====================================================================================================
2000template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2002 UpdateFactoryManager_PCoarsen(ParameterList& paramList, const ParameterList& defaultList, FactoryManager& manager,
2003 int levelID, std::vector<keep_pair>& keeps) const {
2004#ifdef HAVE_MUELU_INTREPID2
2005 // This only makes sense to invoke from the default list.
2006 if (defaultList.isParameter("pcoarsen: schedule") && defaultList.isParameter("pcoarsen: element")) {
2007 // P-Coarsening by schedule (new interface)
2008 // NOTE: levelID represents the *coarse* level in this case
2009 auto pcoarsen_schedule = Teuchos::getArrayFromStringParameter<int>(defaultList, "pcoarsen: schedule");
2010 auto pcoarsen_element = defaultList.get<std::string>("pcoarsen: element");
2011
2012 if (levelID >= (int)pcoarsen_schedule.size()) {
2013 // Past the p-coarsening levels, we do Smoothed Aggregation
2014 // NOTE: We should probably consider allowing other options past p-coarsening
2015 UpdateFactoryManager_SA(paramList, defaultList, manager, levelID, keeps);
2016
2017 } else {
2018 // P-Coarsening
2019 ParameterList Pparams;
2020 auto P = rcp(new IntrepidPCoarsenFactory());
2021 std::string lo = pcoarsen_element + std::to_string(pcoarsen_schedule[levelID]);
2022 std::string hi = (levelID ? pcoarsen_element + std::to_string(pcoarsen_schedule[levelID - 1]) : lo);
2023 Pparams.set("pcoarsen: hi basis", hi);
2024 Pparams.set("pcoarsen: lo basis", lo);
2025 P->SetParameterList(Pparams);
2026 manager.SetFactory("P", P);
2027
2028 // Add special nullspace handling
2029 rcp_dynamic_cast<Factory>(manager.GetFactoryNonConst("Nullspace"))->SetFactory("Nullspace", manager.GetFactory("P"));
2030 }
2031
2032 } else {
2033 // P-Coarsening by manual specification (old interface)
2034 ParameterList Pparams;
2035 auto P = rcp(new IntrepidPCoarsenFactory());
2036 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "pcoarsen: hi basis", std::string, Pparams);
2037 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "pcoarsen: lo basis", std::string, Pparams);
2038 P->SetParameterList(Pparams);
2039 manager.SetFactory("P", P);
2040
2041 // Add special nullspace handling
2042 rcp_dynamic_cast<Factory>(manager.GetFactoryNonConst("Nullspace"))->SetFactory("Nullspace", manager.GetFactory("P"));
2043 }
2044
2045#endif
2046}
2047
2048// =====================================================================================================
2049// ============================== Algorithm: Smoothed Aggregation ======================================
2050// =====================================================================================================
2051template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2053 UpdateFactoryManager_SA(ParameterList& paramList, const ParameterList& defaultList, FactoryManager& manager, int /* levelID */, std::vector<keep_pair>& keeps) const {
2054 // Smoothed aggregation
2055 RCP<Factory> P = rcp(new SaPFactory());
2056 ParameterList Pparams;
2057 if (paramList.isSublist("matrixmatrix: kernel params"))
2058 Pparams.sublist("matrixmatrix: kernel params", false) = paramList.sublist("matrixmatrix: kernel params");
2059 if (defaultList.isSublist("matrixmatrix: kernel params"))
2060 Pparams.sublist("matrixmatrix: kernel params", false) = defaultList.sublist("matrixmatrix: kernel params");
2061 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "sa: damping factor", double, Pparams);
2062 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "sa: calculate eigenvalue estimate", bool, Pparams);
2063 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "sa: max eigenvalue", double, Pparams);
2064 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "sa: eigenvalue estimate num iterations", int, Pparams);
2065 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "sa: use rowsumabs diagonal scaling", bool, Pparams);
2066 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "sa: rowsumabs diagonal replacement tolerance", double, Pparams);
2067 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "sa: rowsumabs diagonal replacement value", double, Pparams);
2068 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "sa: rowsumabs use automatic diagonal tolerance", bool, Pparams);
2069 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "sa: enforce constraints", bool, Pparams);
2070 // MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "sa: eigen-analysis type", std::string, Pparams);
2071 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "tentative: calculate qr", bool, Pparams);
2072
2073 P->SetParameterList(Pparams);
2074
2075 // Filtering
2076 MUELU_SET_VAR_2LIST(paramList, defaultList, "sa: use filtered matrix", bool, useFiltering);
2077 if (useFiltering) {
2078 // NOTE: Here, non-Kokkos and Kokkos versions diverge in the way the
2079 // dependency tree is setup. The Kokkos version has merged the the
2080 // FilteredAFactory into the CoalesceDropFactory.
2081 if (!useKokkos_) {
2082 RCP<Factory> filterFactory = rcp(new FilteredAFactory());
2083
2084 ParameterList fParams;
2085 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "filtered matrix: use lumping", bool, fParams);
2086 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "filtered matrix: reuse graph", bool, fParams);
2087 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "filtered matrix: reuse eigenvalue", bool, fParams);
2088 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "filtered matrix: use root stencil", bool, fParams);
2089 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "filtered matrix: Dirichlet threshold", double, fParams);
2090 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "filtered matrix: use spread lumping", bool, fParams);
2091 // MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "filtered matrix: lumping choice", std::string, fParams);
2092 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "filtered matrix: spread lumping diag dom growth factor", double, fParams);
2093 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "filtered matrix: spread lumping diag dom cap", double, fParams);
2094 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "filtered matrix: count negative diagonals", bool, fParams);
2095 filterFactory->SetParameterList(fParams);
2096 filterFactory->SetFactory("Graph", manager.GetFactory("Graph"));
2097 filterFactory->SetFactory("Aggregates", manager.GetFactory("Aggregates"));
2098 filterFactory->SetFactory("UnAmalgamationInfo", manager.GetFactory("UnAmalgamationInfo"));
2099 // I'm not sure why we need this line. See comments for DofsPerNode for UncoupledAggregation above
2100 filterFactory->SetFactory("Filtering", manager.GetFactory("Graph"));
2101
2102 P->SetFactory("A", filterFactory);
2103
2104 } else {
2105 P->SetFactory("A", manager.GetFactory("Graph"));
2106 }
2107 }
2108
2109 P->SetFactory("P", manager.GetFactory("Ptent"));
2110 manager.SetFactory("P", P);
2111
2112 bool filteringChangesMatrix = useFiltering && !MUELU_TEST_PARAM_2LIST(paramList, defaultList, "aggregation: drop tol", double, 0);
2113 MUELU_SET_VAR_2LIST(paramList, defaultList, "reuse: type", std::string, reuseType);
2114 if (reuseType == "tP" && !filteringChangesMatrix)
2115 keeps.push_back(keep_pair("AP reuse data", P.get()));
2116}
2117
2118// =====================================================================================================
2119// =============================== Algorithm: Energy Minimization ======================================
2120// =====================================================================================================
2121template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2123 UpdateFactoryManager_Emin(ParameterList& paramList, const ParameterList& defaultList, FactoryManager& manager,
2124 int /* levelID */, std::vector<keep_pair>& /* keeps */) const {
2125 MUELU_SET_VAR_2LIST(paramList, defaultList, "emin: pattern", std::string, patternType);
2126 MUELU_SET_VAR_2LIST(paramList, defaultList, "reuse: type", std::string, reuseType);
2127 TEUCHOS_TEST_FOR_EXCEPTION(patternType != "AkPtent", Exceptions::InvalidArgument,
2128 "Invalid pattern name: \"" << patternType << "\". Valid options: \"AkPtent\"");
2129 // Pattern
2130 auto patternFactory = rcp(new PatternFactory());
2131 ParameterList patternParams;
2132 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "emin: pattern order", int, patternParams);
2133 patternFactory->SetParameterList(patternParams);
2134 patternFactory->SetFactory("P", manager.GetFactory("Ptent"));
2135
2136 // Filtering
2137 MUELU_SET_VAR_2LIST(paramList, defaultList, "emin: use filtered matrix", bool, useFiltering);
2138 if (useFiltering) {
2139 // NOTE: Here, non-Kokkos and Kokkos versions diverge in the way the
2140 // dependency tree is setup. The Kokkos version has merged the the
2141 // FilteredAFactory into the CoalesceDropFactory.
2142 if (!useKokkos_) {
2143 RCP<Factory> filterFactory = rcp(new FilteredAFactory());
2144
2145 ParameterList fParams;
2146 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "filtered matrix: use lumping", bool, fParams);
2147 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "filtered matrix: reuse graph", bool, fParams);
2148 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "filtered matrix: reuse eigenvalue", bool, fParams);
2149 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "filtered matrix: use root stencil", bool, fParams);
2150 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "filtered matrix: Dirichlet threshold", double, fParams);
2151 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "filtered matrix: use spread lumping", bool, fParams);
2152 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "filtered matrix: lumping choice", std::string, fParams);
2153 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "filtered matrix: spread lumping diag dom growth factor", double, fParams);
2154 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "filtered matrix: spread lumping diag dom cap", double, fParams);
2155 filterFactory->SetParameterList(fParams);
2156 filterFactory->SetFactory("Graph", manager.GetFactory("Graph"));
2157 filterFactory->SetFactory("Aggregates", manager.GetFactory("Aggregates"));
2158 filterFactory->SetFactory("UnAmalgamationInfo", manager.GetFactory("UnAmalgamationInfo"));
2159 // I'm not sure why we need this line. See comments for DofsPerNode for UncoupledAggregation above
2160 filterFactory->SetFactory("Filtering", manager.GetFactory("Graph"));
2161
2162 patternFactory->SetFactory("A", filterFactory);
2163
2164 } else {
2165 patternFactory->SetFactory("A", manager.GetFactory("Graph"));
2166 }
2167 }
2168
2169 manager.SetFactory("Ppattern", patternFactory);
2170
2171 // Constraint
2172 auto constraintFactory = rcp(new ConstraintFactory());
2173 constraintFactory->SetFactory("Ppattern", manager.GetFactory("Ppattern"));
2174 constraintFactory->SetFactory("CoarseNullspace", manager.GetFactory("Ptent"));
2175 manager.SetFactory("Constraint", constraintFactory);
2176
2177 // Energy minimization
2178 ParameterList Pparams;
2179 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "emin: num iterations", int, Pparams);
2180 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "emin: iterative method", std::string, Pparams);
2181 if (reuseType == "emin") {
2182 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "emin: num reuse iterations", int, Pparams);
2183 Pparams.set("Keep P0", true);
2184 Pparams.set("Keep Constraint0", true);
2185 }
2186
2187 // Emin Factory
2188 auto P = rcp(new EminPFactory());
2189 P->SetParameterList(Pparams);
2190 P->SetFactory("P", manager.GetFactory("Ptent"));
2191 P->SetFactory("Constraint", manager.GetFactory("Constraint"));
2192 manager.SetFactory("P", P);
2193}
2194
2195// =====================================================================================================
2196// ================================= Algorithm: Petrov-Galerkin ========================================
2197// =====================================================================================================
2198template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2200 UpdateFactoryManager_PG(ParameterList& /* paramList */, const ParameterList& /* defaultList */, FactoryManager& manager,
2201 int /* levelID */, std::vector<keep_pair>& /* keeps */) const {
2202 TEUCHOS_TEST_FOR_EXCEPTION(this->implicitTranspose_, Exceptions::RuntimeError,
2203 "Implicit transpose not supported with Petrov-Galerkin smoothed transfer operators: Set \"transpose: use implicit\" to false!\n"
2204 "Petrov-Galerkin transfer operator smoothing for non-symmetric problems requires a separate handling of the restriction operator which "
2205 "does not allow the usage of implicit transpose easily.");
2206
2207 // Petrov-Galerkin
2208 auto P = rcp(new PgPFactory());
2209 P->SetFactory("P", manager.GetFactory("Ptent"));
2210 manager.SetFactory("P", P);
2211}
2212
2213// =====================================================================================================
2214// ================================= Algorithm: Replicate ========================================
2215// =====================================================================================================
2216template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2218 UpdateFactoryManager_Replicate(ParameterList& paramList, const ParameterList& defaultList, FactoryManager& manager, int /* levelID */, std::vector<keep_pair>& keeps) const {
2220
2221 ParameterList Pparams;
2222 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "replicate: npdes", int, Pparams);
2223
2224 P->SetParameterList(Pparams);
2225 manager.SetFactory("P", P);
2226}
2227
2228// =====================================================================================================
2229// ====================================== Algorithm: Combine ============================================
2230// =====================================================================================================
2231template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2233 UpdateFactoryManager_Combine(ParameterList& paramList, const ParameterList& defaultList, FactoryManager& manager, int /* levelID */, std::vector<keep_pair>& keeps) const {
2235
2236 ParameterList Pparams;
2237 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "combine: numBlks", int, Pparams);
2238 MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, "combine: useMaxLevels", bool, Pparams);
2239
2240 P->SetParameterList(Pparams);
2241 manager.SetFactory("P", P);
2242}
2243
2244// =====================================================================================================
2245// ====================================== Algorithm: Matlab ============================================
2246// =====================================================================================================
2247template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2249 UpdateFactoryManager_Matlab(ParameterList& paramList, const ParameterList& /* defaultList */, FactoryManager& manager,
2250 int /* levelID */, std::vector<keep_pair>& /* keeps */) const {
2251#ifdef HAVE_MUELU_MATLAB
2252 ParameterList Pparams = paramList.sublist("transfer: params");
2253 auto P = rcp(new TwoLevelMatlabFactory());
2254 P->SetParameterList(Pparams);
2255 P->SetFactory("P", manager.GetFactory("Ptent"));
2256 manager.SetFactory("P", P);
2257#else
2258 (void)paramList;
2259 (void)manager;
2260#endif
2261}
2262
2263#undef MUELU_SET_VAR_2LIST
2264#undef MUELU_TEST_AND_SET_VAR
2265#undef MUELU_TEST_AND_SET_PARAM_2LIST
2266#undef MUELU_TEST_PARAM_2LIST
2267#undef MUELU_KOKKOS_FACTORY
2268
2269size_t LevenshteinDistance(const char* s, size_t len_s, const char* t, size_t len_t);
2270
2271template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2273 ParameterList paramList = constParamList;
2274 const ParameterList& validList = *MasterList::List();
2275 // Validate up to maxLevels level specific parameter sublists
2276 const int maxLevels = 100;
2277
2278 // Extract level specific list
2279 std::vector<ParameterList> paramLists;
2280 for (int levelID = 0; levelID < maxLevels; levelID++) {
2281 std::string sublistName = "level " + toString(levelID);
2282 if (paramList.isSublist(sublistName)) {
2283 paramLists.push_back(paramList.sublist(sublistName));
2284 // paramLists.back().setName(sublistName);
2285 paramList.remove(sublistName);
2286 }
2287 }
2288 paramLists.push_back(paramList);
2289 // paramLists.back().setName("main");
2290#ifdef HAVE_MUELU_MATLAB
2291 // If Muemex is supported, hide custom level variables from validator by removing them from paramList's sublists
2292 for (size_t i = 0; i < paramLists.size(); i++) {
2293 std::vector<std::string> customVars; // list of names (keys) to be removed from list
2294
2295 for (Teuchos::ParameterList::ConstIterator it = paramLists[i].begin(); it != paramLists[i].end(); it++) {
2296 std::string paramName = paramLists[i].name(it);
2297
2298 if (IsParamMuemexVariable(paramName))
2299 customVars.push_back(paramName);
2300 }
2301
2302 // Remove the keys
2303 for (size_t j = 0; j < customVars.size(); j++)
2304 paramLists[i].remove(customVars[j], false);
2305 }
2306#endif
2307
2308 const int maxDepth = 0;
2309 for (size_t i = 0; i < paramLists.size(); i++) {
2310 // validate every sublist
2311 try {
2312 paramLists[i].validateParameters(validList, maxDepth);
2313
2314 } catch (const Teuchos::Exceptions::InvalidParameterName& e) {
2315 std::string eString = e.what();
2316
2317 // Parse name from: <Error, the parameter {name="smoothe: type",...>
2318 size_t nameStart = eString.find_first_of('"') + 1;
2319 size_t nameEnd = eString.find_first_of('"', nameStart);
2320 std::string name = eString.substr(nameStart, nameEnd - nameStart);
2321
2322 size_t bestScore = 100;
2323 std::string bestName = "";
2324 for (ParameterList::ConstIterator it = validList.begin(); it != validList.end(); it++) {
2325 const std::string& pName = validList.name(it);
2326 this->GetOStream(Runtime1) << "| " << pName;
2327 size_t score = LevenshteinDistance(name.c_str(), name.length(), pName.c_str(), pName.length());
2328 this->GetOStream(Runtime1) << " -> " << score << std::endl;
2329 if (score < bestScore) {
2330 bestScore = score;
2331 bestName = pName;
2332 }
2333 }
2334 if (bestScore < 10 && bestName != "") {
2335 TEUCHOS_TEST_FOR_EXCEPTION(true, Teuchos::Exceptions::InvalidParameterName,
2336 eString << "The parameter name \"" + name + "\" is not valid. Did you mean \"" + bestName << "\"?\n");
2337
2338 } else {
2339 TEUCHOS_TEST_FOR_EXCEPTION(true, Teuchos::Exceptions::InvalidParameterName,
2340 eString << "The parameter name \"" + name + "\" is not valid.\n");
2341 }
2342 }
2343 }
2344}
2345
2346// =====================================================================================================
2347// ==================================== FACTORY interpreter ============================================
2348// =====================================================================================================
2349template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2351 SetFactoryParameterList(const ParameterList& constParamList) {
2352 // Create a non const copy of the parameter list
2353 // Working with a modifiable list is much much easier than with original one
2354 ParameterList paramList = constParamList;
2355
2356 // Parameter List Parsing:
2357 // ---------
2358 // <ParameterList name="MueLu">
2359 // <ParameterList name="Matrix">
2360 // </ParameterList>
2361 if (paramList.isSublist("Matrix")) {
2362 blockSize_ = paramList.sublist("Matrix").get<int>("PDE equations", MasterList::getDefault<int>("number of equations"));
2363 dofOffset_ = paramList.sublist("Matrix").get<GlobalOrdinal>("DOF offset", 0); // undocumented parameter allowing to define a DOF offset of the global dofs of an operator (defaul = 0)
2364 }
2365
2366 // create new FactoryFactory object if necessary
2367 if (factFact_ == Teuchos::null)
2368 factFact_ = Teuchos::rcp(new FactoryFactory());
2369
2370 // Parameter List Parsing:
2371 // ---------
2372 // <ParameterList name="MueLu">
2373 // <ParameterList name="Factories"> <== call BuildFactoryMap() on this parameter list
2374 // ...
2375 // </ParameterList>
2376 // </ParameterList>
2377 FactoryMap factoryMap;
2378 FactoryManagerMap factoryManagers;
2379 if (paramList.isSublist("Factories"))
2380 this->BuildFactoryMap(paramList.sublist("Factories"), factoryMap, factoryMap, factoryManagers);
2381
2382 // Parameter List Parsing:
2383 // ---------
2384 // <ParameterList name="MueLu">
2385 // <ParameterList name="Hierarchy">
2386 // <Parameter name="verbose" type="string" value="Warnings"/> <== get
2387 // <Parameter name="numDesiredLevel" type="int" value="10"/> <== get
2388 //
2389 // <ParameterList name="firstLevel"> <== parse first args and call BuildFactoryMap() on the rest of this parameter list
2390 // ...
2391 // </ParameterList>
2392 // </ParameterList>
2393 // </ParameterList>
2394 if (paramList.isSublist("Hierarchy")) {
2395 ParameterList hieraList = paramList.sublist("Hierarchy"); // copy because list temporally modified (remove 'id')
2396
2397 // Get hierarchy options
2398 if (hieraList.isParameter("max levels")) {
2399 this->numDesiredLevel_ = hieraList.get<int>("max levels");
2400 hieraList.remove("max levels");
2401 }
2402
2403 if (hieraList.isParameter("coarse: max size")) {
2404 this->maxCoarseSize_ = hieraList.get<int>("coarse: max size");
2405 hieraList.remove("coarse: max size");
2406 }
2407
2408 if (hieraList.isParameter("repartition: rebalance P and R")) {
2409 this->doPRrebalance_ = hieraList.get<bool>("repartition: rebalance P and R");
2410 hieraList.remove("repartition: rebalance P and R");
2411 }
2412
2413 if (hieraList.isParameter("transpose: use implicit")) {
2414 this->implicitTranspose_ = hieraList.get<bool>("transpose: use implicit");
2415 hieraList.remove("transpose: use implicit");
2416 }
2417
2418 if (hieraList.isParameter("fuse prolongation and update")) {
2419 this->fuseProlongationAndUpdate_ = hieraList.get<bool>("fuse prolongation and update");
2420 hieraList.remove("fuse prolongation and update");
2421 }
2422
2423 if (hieraList.isParameter("nullspace: suppress dimension check")) {
2424 this->suppressNullspaceDimensionCheck_ = hieraList.get<bool>("nullspace: suppress dimension check");
2425 hieraList.remove("nullspace: suppress dimension check");
2426 }
2427
2428 if (hieraList.isParameter("number of vectors")) {
2429 this->sizeOfMultiVectors_ = hieraList.get<int>("number of vectors");
2430 hieraList.remove("number of vectors");
2431 }
2432
2433 if (hieraList.isSublist("matvec params"))
2434 this->matvecParams_ = Teuchos::parameterList(hieraList.sublist("matvec params"));
2435
2436 if (hieraList.isParameter("coarse grid correction scaling factor")) {
2437 this->scalingFactor_ = hieraList.get<double>("coarse grid correction scaling factor");
2438 hieraList.remove("coarse grid correction scaling factor");
2439 }
2440
2441 // Translate cycle type parameter
2442 if (hieraList.isParameter("cycle type")) {
2443 std::map<std::string, CycleType> cycleMap;
2444 cycleMap["V"] = VCYCLE;
2445 cycleMap["W"] = WCYCLE;
2446
2447 std::string cycleType = hieraList.get<std::string>("cycle type");
2448 TEUCHOS_TEST_FOR_EXCEPTION(cycleMap.count(cycleType) == 0, Exceptions::RuntimeError, "Invalid cycle type: \"" << cycleType << "\"");
2449 this->Cycle_ = cycleMap[cycleType];
2450 }
2451
2452 if (hieraList.isParameter("W cycle start level")) {
2453 this->WCycleStartLevel_ = hieraList.get<int>("W cycle start level");
2454 }
2455
2456 if (hieraList.isParameter("hierarchy label")) {
2457 this->hierarchyLabel_ = hieraList.get<std::string>("hierarchy label");
2458 }
2459
2460 if (hieraList.isParameter("verbosity")) {
2461 std::string vl = hieraList.get<std::string>("verbosity");
2462 hieraList.remove("verbosity");
2463 this->verbosity_ = toVerbLevel(vl);
2464 }
2465
2466 if (hieraList.isParameter("output filename"))
2467 VerboseObject::SetMueLuOFileStream(hieraList.get<std::string>("output filename"));
2468
2469 if (hieraList.isParameter("dependencyOutputLevel"))
2470 this->graphOutputLevel_ = hieraList.get<int>("dependencyOutputLevel");
2471
2472 // Check for the reuse case
2473 if (hieraList.isParameter("reuse"))
2475
2476 if (hieraList.isSublist("DataToWrite")) {
2477 // TODO We should be able to specify any data. If it exists, write it.
2478 // TODO This would requires something like std::set<dataName, Array<int> >
2479 ParameterList foo = hieraList.sublist("DataToWrite");
2480 std::string dataName = "Matrices";
2481 if (foo.isParameter(dataName))
2482 this->matricesToPrint_["A"] = Teuchos::getArrayFromStringParameter<int>(foo, dataName);
2483 dataName = "Prolongators";
2484 if (foo.isParameter(dataName))
2485 this->matricesToPrint_["P"] = Teuchos::getArrayFromStringParameter<int>(foo, dataName);
2486 dataName = "Restrictors";
2487 if (foo.isParameter(dataName))
2488 this->matricesToPrint_["R"] = Teuchos::getArrayFromStringParameter<int>(foo, dataName);
2489 dataName = "D0";
2490 if (foo.isParameter(dataName))
2491 this->matricesToPrint_["D0"] = Teuchos::getArrayFromStringParameter<int>(foo, dataName);
2492 }
2493
2494 // Get level configuration
2495 for (ParameterList::ConstIterator param = hieraList.begin(); param != hieraList.end(); ++param) {
2496 const std::string& paramName = hieraList.name(param);
2497
2498 if (paramName != "DataToWrite" && hieraList.isSublist(paramName)) {
2499 ParameterList levelList = hieraList.sublist(paramName); // copy because list temporally modified (remove 'id')
2500
2501 int startLevel = 0;
2502 if (levelList.isParameter("startLevel")) {
2503 startLevel = levelList.get<int>("startLevel");
2504 levelList.remove("startLevel");
2505 }
2506 int numDesiredLevel = 1;
2507 if (levelList.isParameter("numDesiredLevel")) {
2508 numDesiredLevel = levelList.get<int>("numDesiredLevel");
2509 levelList.remove("numDesiredLevel");
2510 }
2511
2512 // Parameter List Parsing:
2513 // ---------
2514 // <ParameterList name="firstLevel">
2515 // <Parameter name="startLevel" type="int" value="0"/>
2516 // <Parameter name="numDesiredLevel" type="int" value="1"/>
2517 // <Parameter name="verbose" type="string" value="Warnings"/>
2518 //
2519 // [] <== call BuildFactoryMap() on the rest of the parameter list
2520 //
2521 // </ParameterList>
2522 FactoryMap levelFactoryMap;
2523 BuildFactoryMap(levelList, factoryMap, levelFactoryMap, factoryManagers);
2524
2525 RCP<FactoryManager> m = rcp(new FactoryManager(levelFactoryMap));
2526 if (hieraList.isParameter("use kokkos refactor"))
2527 m->SetKokkosRefactor(hieraList.get<bool>("use kokkos refactor"));
2528
2529 if (startLevel >= 0)
2530 this->AddFactoryManager(startLevel, numDesiredLevel, m);
2531 else
2532 TEUCHOS_TEST_FOR_EXCEPTION(true, Exceptions::RuntimeError, "MueLu::ParameterListInterpreter():: invalid level id");
2533 } /* TODO: else { } */
2534 }
2535 }
2536}
2537
2538// TODO: static?
2572
2624
2661template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2663 BuildFactoryMap(const ParameterList& paramList, const FactoryMap& factoryMapIn, FactoryMap& factoryMapOut, FactoryManagerMap& factoryManagers) const {
2664 for (ParameterList::ConstIterator param = paramList.begin(); param != paramList.end(); ++param) {
2665 const std::string& paramName = paramList.name(param); //< paramName contains the user chosen factory name (e.g., "smootherFact1")
2666 const Teuchos::ParameterEntry& paramValue = paramList.entry(param); //< for factories, paramValue should be either a list or just a MueLu Factory (e.g., TrilinosSmoother)
2667
2668 // TODO: do not allow name of existing MueLu classes (can be tested using FactoryFactory)
2669
2670 if (paramValue.isList()) {
2671 ParameterList paramList1 = Teuchos::getValue<ParameterList>(paramValue);
2672 if (paramList1.isParameter("factory")) { // default: just a factory definition
2673 // New Factory is a sublist with internal parameters and/or data dependencies
2674 TEUCHOS_TEST_FOR_EXCEPTION(paramList1.isParameter("dependency for") == true, Exceptions::RuntimeError,
2675 "MueLu::ParameterListInterpreter(): It seems that in the parameter lists for defining " << paramName << " there is both a 'factory' and 'dependency for' parameter. This is not allowed. Please remove the 'dependency for' parameter.");
2676
2677 factoryMapOut[paramName] = factFact_->BuildFactory(paramValue, factoryMapIn, factoryManagers);
2678
2679 } else if (paramList1.isParameter("dependency for")) { // add more data dependencies to existing factory
2680 TEUCHOS_TEST_FOR_EXCEPTION(paramList1.isParameter("factory") == true, Exceptions::RuntimeError,
2681 "MueLu::ParameterListInterpreter(): It seems that in the parameter lists for defining " << paramName << " there is both a 'factory' and 'dependency for' parameter. This is not allowed.");
2682
2683 std::string factoryName = paramList1.get<std::string>("dependency for");
2684
2685 RCP<const FactoryBase> factbase = factoryMapIn.find(factoryName /*paramName*/)->second; // access previously defined factory
2686 TEUCHOS_TEST_FOR_EXCEPTION(factbase.is_null() == true, Exceptions::RuntimeError,
2687 "MueLu::ParameterListInterpreter(): could not find factory " + factoryName + " in factory map. Did you define it before?");
2688
2689 RCP<const Factory> factoryconst = Teuchos::rcp_dynamic_cast<const Factory>(factbase);
2690 RCP<Factory> factory = Teuchos::rcp_const_cast<Factory>(factoryconst);
2691
2692 // Read the RCP<Factory> parameters of the class T
2693 RCP<const ParameterList> validParamList = factory->GetValidParameterList();
2694 for (ParameterList::ConstIterator vparam = validParamList->begin(); vparam != validParamList->end(); ++vparam) {
2695 const std::string& pName = validParamList->name(vparam);
2696
2697 if (!paramList1.isParameter(pName)) {
2698 // Ignore unknown parameters
2699 continue;
2700 }
2701
2702 if (validParamList->isType<RCP<const FactoryBase> >(pName)) {
2703 // Generate or get factory described by pName and set dependency
2704 RCP<const FactoryBase> generatingFact = factFact_->BuildFactory(paramList1.getEntry(pName), factoryMapIn, factoryManagers);
2705 factory->SetFactory(pName, generatingFact.create_weak());
2706
2707 } else if (validParamList->isType<RCP<const ParameterList> >(pName)) {
2708 if (pName == "ParameterList") {
2709 // NOTE: we cannot use
2710 // subList = sublist(rcpFromRef(paramList), pName)
2711 // here as that would result in sublist also being a reference to a temporary object.
2712 // The resulting dereferencing in the corresponding factory would then segfault
2713 RCP<const ParameterList> subList = Teuchos::sublist(rcp(new ParameterList(paramList1)), pName);
2714 factory->SetParameter(pName, ParameterEntry(subList));
2715 }
2716 } else {
2717 factory->SetParameter(pName, paramList1.getEntry(pName));
2718 }
2719 }
2720
2721 } else if (paramList1.isParameter("group")) { // definitiion of a factory group (for a factory manager)
2722 // Define a new (sub) FactoryManager
2723 std::string groupType = paramList1.get<std::string>("group");
2724 TEUCHOS_TEST_FOR_EXCEPTION(groupType != "FactoryManager", Exceptions::RuntimeError,
2725 "group must be of type \"FactoryManager\".");
2726
2727 ParameterList groupList = paramList1; // copy because list temporally modified (remove 'id')
2728 groupList.remove("group");
2729
2730 bool setKokkosRefactor = false;
2731 bool kokkosRefactor = useKokkos_;
2732 if (groupList.isParameter("use kokkos refactor")) {
2733 kokkosRefactor = groupList.get<bool>("use kokkos refactor");
2734 groupList.remove("use kokkos refactor");
2735 setKokkosRefactor = true;
2736 }
2737
2738 FactoryMap groupFactoryMap;
2739 BuildFactoryMap(groupList, factoryMapIn, groupFactoryMap, factoryManagers);
2740
2741 // do not store groupFactoryMap in factoryMapOut
2742 // Create a factory manager object from groupFactoryMap
2743 RCP<FactoryManager> m = rcp(new FactoryManager(groupFactoryMap));
2744 if (setKokkosRefactor)
2745 m->SetKokkosRefactor(kokkosRefactor);
2746 factoryManagers[paramName] = m;
2747
2748 } else {
2749 this->GetOStream(Warnings0) << "Could not interpret parameter list " << paramList1 << std::endl;
2750 TEUCHOS_TEST_FOR_EXCEPTION(false, Exceptions::RuntimeError,
2751 "XML Parameter list must either be of type \"factory\" or of type \"group\".");
2752 }
2753 } else {
2754 // default: just a factory (no parameter list)
2755 factoryMapOut[paramName] = factFact_->BuildFactory(paramValue, factoryMapIn, factoryManagers);
2756 }
2757 }
2758}
2759
2760// =====================================================================================================
2761// ======================================= MISC functions ==============================================
2762// =====================================================================================================
2763template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2765 try {
2766 Matrix& A = dynamic_cast<Matrix&>(Op);
2767 if (A.IsFixedBlockSizeSet() && (A.GetFixedBlockSize() != blockSize_))
2768 this->GetOStream(Warnings0) << "Setting matrix block size to " << blockSize_ << " (value of the parameter in the list) "
2769 << "instead of " << A.GetFixedBlockSize() << " (provided matrix)." << std::endl
2770 << "You may want to check \"number of equations\" (or \"PDE equations\" for factory style list) parameter." << std::endl;
2771
2772 A.SetFixedBlockSize(blockSize_, dofOffset_);
2773
2774#ifdef HAVE_MUELU_DEBUG
2775 MatrixUtils::checkLocalRowMapMatchesColMap(A);
2776#endif // HAVE_MUELU_DEBUG
2777
2778 } catch (std::bad_cast&) {
2779 this->GetOStream(Warnings0) << "Skipping setting block size as the operator is not a matrix" << std::endl;
2780 }
2781}
2782
2783template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2785 H.SetCycle(Cycle_);
2786 H.SetCycleStartLevel(WCycleStartLevel_);
2787 H.SetProlongatorScalingFactor(scalingFactor_);
2788 H.SetLabel(hierarchyLabel_);
2790}
2791
2792static bool compare(const ParameterList& list1, const ParameterList& list2) {
2793 // First loop through and validate the parameters at this level.
2794 // In addition, we generate a list of sublists that we will search next
2795 for (ParameterList::ConstIterator it = list1.begin(); it != list1.end(); it++) {
2796 const std::string& name = it->first;
2797 const Teuchos::ParameterEntry& entry1 = it->second;
2798
2799 const Teuchos::ParameterEntry* entry2 = list2.getEntryPtr(name);
2800 if (!entry2) // entry is not present in the second list
2801 return false;
2802 if (entry1.isList() && entry2->isList()) { // sublist check
2803 compare(Teuchos::getValue<ParameterList>(entry1), Teuchos::getValue<ParameterList>(*entry2));
2804 continue;
2805 }
2806 if (entry1.getAny(false) != entry2->getAny(false)) // entries have different types or different values
2807 return false;
2808 }
2809
2810 return true;
2811}
2812
2813static inline bool areSame(const ParameterList& list1, const ParameterList& list2) {
2814 return compare(list1, list2) && compare(list2, list1);
2815}
2816
2817} // namespace MueLu
2818
2819#define MUELU_PARAMETERLISTINTERPRETER_SHORT
2820#endif /* MUELU_PARAMETERLISTINTERPRETER_DEF_HPP */
#define MUELU_TEST_AND_SET_VAR(paramList, paramName, paramType, varName)
#define MUELU_SET_VAR_2LIST(paramList, defaultList, paramName, paramType, varName)
#define TEST_MUTUALLY_EXCLUSIVE_S(arg1, arg2)
#define MUELU_KOKKOS_FACTORY_NO_DECL(varName, oldFactory, newFactory)
#define MUELU_TEST_PARAM_2LIST(paramList, defaultList, paramName, paramType, cmpValue)
#define MUELU_KOKKOS_FACTORY(varName, oldFactory, newFactory)
#define TEST_MUTUALLY_EXCLUSIVE(arg1, arg2)
#define MUELU_TEST_AND_SET_PARAM_2LIST(paramList, defaultList, paramName, paramType, listWrite)
MueLu::DefaultScalar Scalar
MueLu::DefaultGlobalOrdinal GlobalOrdinal
An factory which assigns each aggregate a quality estimate. Originally developed by Napov and Notay i...
Factory to export aggregation info or visualize aggregates using VTK.
AmalgamationFactory for subblocks of strided map based amalgamation data.
Factory for generating F/C-splitting and a coarse level map. Used by ClassicalPFactory.
Factory for creating a graph based on a given matrix.
Factory for creating a graph based on a given matrix.
Factory for generating coarse level map. Used by TentativePFactory.
Prolongator factory that replicates 'Psubblock' matrix to create new prolongator suitable for PDE sys...
Factory for building the constraint operator.
Class for transferring coordinates from a finer level to a coarser one.
Class that encapsulates direct solvers. Autoselection of AmesosSmoother or Amesos2Smoother according ...
Factory for building Energy Minimization prolongators.
Exception throws to report invalid user entry.
Exception throws to report errors in the internal logical of the program.
Factory that can generate other factories from.
static void EnableTimerSync()
static void DisableMultipleCheckGlobally()
This class specifies the default factory that should generate some data on a Level if the data does n...
void SetFactory(const std::string &varName, const RCP< const FactoryBase > &factory)
Set Factory.
const RCP< const FactoryBase > GetFactory(const std::string &varName) const
Get factory associated with a particular data name.
const RCP< FactoryBase > GetFactoryNonConst(const std::string &varName)
Get factory associated with a particular data name (NONCONST version)
Factory for building filtered matrices using filtered graphs.
Factory for building restriction operators using a prolongator factory.
Provides methods to build a multigrid hierarchy and apply multigrid cycles.
static CycleType GetDefaultCycle()
void SetCycleStartLevel(int cycleStart)
void SetLabel(const std::string &hierarchyLabel)
static int GetDefaultCycleStartLevel()
void SetCycle(CycleType Cycle)
Supports VCYCLE and WCYCLE types.
void SetProlongatorScalingFactor(double scalingFactor)
Specify damping factor alpha such that x = x + alpha*P*c, where c is the coarse grid correction.
virtual void SetupHierarchy(Hierarchy &H) const
Setup Hierarchy object.
Class for generating an initial LocalOrdinal-type BlockNumber vector, based on an input paraemter for...
Factory for building transfer operators based on coarsening in polynomial degree, following the Intre...
Factory for building line detection information.
Class for transferring a vector of local ordinals from a finer level to a coarser one,...
Factory for converting matrices to half precision operators.
static Teuchos::RCP< Teuchos::ParameterList > GetProblemSpecificList(std::string const &problemType)
Return default parameter settings for the specified problem type.
static Teuchos::RCP< const Teuchos::ParameterList > List()
Return a "master" list of all valid parameters and their default values.
Class that encapsulates Matlab smoothers.
This class checks matrix properties of A on current level. This factory can be plugged in everywhere ...
Class for restricting a MultiVector from a finer to a coarser level.
static const RCP< const NoFactory > getRCP()
Static Get() functions.
Factory for generating nullspace.
void UpdateFactoryManager_SA(Teuchos::ParameterList &paramList, const Teuchos::ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps) const
void UpdateFactoryManager_Nullspace(Teuchos::ParameterList &paramList, const Teuchos::ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps, RCP< Factory > &nullSpaceFactory) const
void UpdateFactoryManager_Reitzinger(Teuchos::ParameterList &paramList, const Teuchos::ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps) const
void UpdateFactoryManager_RAP(Teuchos::ParameterList &paramList, const Teuchos::ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps) const
void UpdateFactoryManager_Smoothers(Teuchos::ParameterList &paramList, const Teuchos::ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps) const
void UpdateFactoryManager_Aggregation_TentativeP(Teuchos::ParameterList &paramList, const Teuchos::ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps) const
void SetEasyParameterList(const Teuchos::ParameterList &paramList)
void UpdateFactoryManager_Coordinates(Teuchos::ParameterList &paramList, const Teuchos::ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps) const
void BuildFactoryMap(const Teuchos::ParameterList &paramList, const FactoryMap &factoryMapIn, FactoryMap &factoryMapOut, FactoryManagerMap &factoryManagers) const
Interpret "Factories" sublist.
void UpdateFactoryManager_Restriction(Teuchos::ParameterList &paramList, const Teuchos::ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps) const
virtual void SetupOperator(Operator &A) const
Setup Operator object.
void UpdateFactoryManager_Replicate(Teuchos::ParameterList &paramList, const Teuchos::ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps) const
void UpdateFactoryManager_LowPrecision(ParameterList &paramList, const ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps) const
void UpdateFactoryManager_PCoarsen(Teuchos::ParameterList &paramList, const Teuchos::ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps) const
Teuchos::RCP< MueLu::FacadeClassFactory< Scalar, LocalOrdinal, GlobalOrdinal, Node > > facadeFact_
FacadeClass factory.
std::pair< std::string, const FactoryBase * > keep_pair
void UpdateFactoryManager_PG(Teuchos::ParameterList &paramList, const Teuchos::ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps) const
void SetParameterList(const Teuchos::ParameterList &paramList)
Set parameter list for Parameter list interpreter.
void UpdateFactoryManager_Material(Teuchos::ParameterList &paramList, const Teuchos::ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps) const
void Validate(const Teuchos::ParameterList &paramList) const
void UpdateFactoryManager_Emin(Teuchos::ParameterList &paramList, const Teuchos::ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps) const
void UpdateFactoryManager_Combine(Teuchos::ParameterList &paramList, const Teuchos::ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps) const
void UpdateFactoryManager_Matlab(Teuchos::ParameterList &paramList, const Teuchos::ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps) const
std::map< std::string, RCP< FactoryManagerBase > > FactoryManagerMap
virtual ~ParameterListInterpreter()
Destructor.
void UpdateFactoryManager_LocalOrdinalTransfer(const std::string &VarName, const std::string &multigridAlgo, Teuchos::ParameterList &paramList, const Teuchos::ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps) const
void UpdateFactoryManager_SemiCoarsen(Teuchos::ParameterList &paramList, const Teuchos::ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps) const
void UpdateFactoryManager_BlockNumber(Teuchos::ParameterList &paramList, const Teuchos::ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps) const
void UpdateFactoryManager(Teuchos::ParameterList &paramList, const Teuchos::ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps) const
std::map< std::string, RCP< const FactoryBase > > FactoryMap
void SetupHierarchy(Hierarchy &H) const
Call the SetupHierarchy routine from the HiearchyManager object.
void SetFactoryParameterList(const Teuchos::ParameterList &paramList)
Factory interpreter stuff.
void UpdateFactoryManager_CoarseSolvers(Teuchos::ParameterList &paramList, const Teuchos::ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps) const
void UpdateFactoryManager_Repartition(Teuchos::ParameterList &paramList, const Teuchos::ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps, RCP< Factory > &nullSpaceFactory) const
Factory for building nonzero patterns for energy minimization.
Factory for building Petrov-Galerkin Smoothed Aggregation prolongators.
Factory for building coarse matrices.
Factory for building coarse grid matrices, when the matrix is of the form K+a*M. Useful when you want...
Factory for building coarse matrices.
Applies permutation to grid transfer operators.
Factory for building tentative prolongator.
Factory for building permutation matrix that can be be used to shuffle data (matrices,...
Factory for determing the number of partitions for rebalancing.
Prolongator factory that replicates 'Psubblock' matrix to create new prolongator suitable for PDE sys...
Factory for building Smoothed Aggregation prolongators.
Factory for generating a very special nullspace.
Prolongator factory performing semi-coarsening.
Prolongator factory performing semi-coarsening.
Factory for creating a graph base on a given matrix.
Generic Smoother Factory for generating the smoothers of the MG hierarchy.
Factory for building tentative prolongator.
Class for transferring coordinates from a finer level to a coarser one.
Prolongator factory which allows switching between two different prolongator strategies.
Factory for building restriction operators.
Class that encapsulates external library smoothers.
Factory for interacting with Matlab.
static VerbLevel GetDefaultVerbLevel()
Get the default (global) verbosity level.
static void SetDefaultVerbLevel(const VerbLevel defaultVerbLevel)
Set the default (global) verbosity level.
static void SetMueLuOFileStream(const std::string &filename)
Interface to Zoltan2 library.
Interface to Zoltan library.
Namespace for MueLu classes and methods.
bool IsParamMuemexVariable(const std::string &name)
long ExtractNonSerializableData(const Teuchos::ParameterList &inList, Teuchos::ParameterList &serialList, Teuchos::ParameterList &nonSerialList)
Extract non-serializable data from level-specific sublists and move it to a separate parameter list.
@ Warnings0
Important warning messages (one line)
@ Runtime0
One-liner description of what is happening.
@ Runtime1
Description of what is happening (more verbose)
@ Warnings1
Additional warnings.
size_t LevenshteinDistance(const char *s, size_t len_s, const char *t, size_t len_t)
MsgType toVerbLevel(const std::string &verbLevelStr)
static bool areSame(const ParameterList &list1, const ParameterList &list2)
Helper functions to compare two paramter lists.
static bool compare(const ParameterList &list1, const ParameterList &list2)
std::string toString(const T &what)
Little helper function to convert non-string types to strings.