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