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