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>
157 WCycleStartLevel_ = Hierarchy::GetDefaultCycleStartLevel();
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);
169 SetFactoryParameterList(*pp);
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);
591 VerboseObject::SetDefaultVerbLevel(this->verbosity_);
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;
611 changedPRViaCopyrebalance_ = 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 if (saDampingFactor != 0.0)
855 UpdateFactoryManager_MatrixTransfer("CurlCurl", paramList, defaultList, manager, levelID, keeps);
856 }
857
858 // == BlockNumber Transfer ==
859 UpdateFactoryManager_LocalOrdinalTransfer("BlockNumber", multigridAlgo, paramList, defaultList, manager, levelID, keeps);
860
861 // === Coordinates ===
862 UpdateFactoryManager_Coordinates(paramList, defaultList, manager, levelID, keeps);
863
864 // === Material ===
865 UpdateFactoryManager_Material(paramList, defaultList, manager, levelID, keeps);
866
867 // === Pre-Repartition Keeps for Reuse ===
868 if ((reuseType == "RP" || reuseType == "RAP" || reuseType == "full") && levelID)
869 keeps.push_back(keep_pair("Nullspace", manager.GetFactory("Nullspace").get()));
870
871 if (reuseType == "RP" && levelID) {
872 keeps.push_back(keep_pair("P", manager.GetFactory("P").get()));
873 if (!this->implicitTranspose_)
874 keeps.push_back(keep_pair("R", manager.GetFactory("R").get()));
875 }
876 if ((reuseType == "tP" || reuseType == "RP" || reuseType == "emin") && useCoordinates_ && levelID)
877 keeps.push_back(keep_pair("Coordinates", manager.GetFactory("Coordinates").get()));
878
879 // === Repartitioning ===
880 UpdateFactoryManager_Repartition(paramList, defaultList, manager, levelID, keeps, nullSpaceFactory);
881
882 // === Auxiliary mass matrix for MinvA ===
883 auto socMatrix = set_var_2list<std::string>(paramList, defaultList, "aggregation: strength-of-connection: matrix");
884 if (socMatrix == "MinvA") {
885 // we can either project MinvA or Minv or M to coarse levels. If we decide to project M, then
886 // it must be provided as "user data". If we decide to project Minv, then either Minv or M
887 // must be provided as "user data". In the later case, Minv will be created from M and then
888 // projected. Projecting MinvA is handled in a similar fashion to Minv. It can be provided
889 // as user data, or either M or Minv can be provided as user data. In these later cases,
890 // MinvA will be computed in CaolesceDrop factory.
891
892 // Default: M is provided on finest level and that Minv and MinvA are computed by CoalesceDrop.
893 std::string MinvFactory = "CoalesceDrop";
894 std::string MinvAFactory = "CoalesceDrop";
895 if (paramList.isSublist("project auxiliary matrices")) {
896 auto projectList = paramList.sublist("project auxiliary matrices");
897 if (projectList.isParameter("M")) {
898 TEUCHOS_TEST_FOR_EXCEPTION(projectList.get("M", "") != "NoFactory", Exceptions::InvalidArgument, "Must specify \"NoFactory\" when projecting M");
899 }
900 if (projectList.isParameter("Minv")) {
901 MinvFactory = projectList.get("Minv", "");
902 TEUCHOS_TEST_FOR_EXCEPTION((MinvFactory != "NoFactory") && (MinvFactory != "CoalesceDrop"), Exceptions::InvalidArgument, "Must specify \"NoFactory\" or \"CoalesceDrop\"");
903 }
904 if (projectList.isParameter("MinvA")) {
905 MinvAFactory = projectList.get("MinvA", "");
906 TEUCHOS_TEST_FOR_EXCEPTION((MinvAFactory != "NoFactory") && (MinvAFactory != "CoalesceDrop"), Exceptions::InvalidArgument, "Must specify \"NoFactory\" or \"CoalesceDrop\"");
907 }
908 }
909
910 // 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.
911 // If Minv is a parameter of sublist("project auxiliary matrices") and MinvFactory == NoFactory, Minv must be user-supplied. If MinvA is a parameter of
912 // sublist("project auxiliary matrices") and MinvAFactory == NoFactory, MinvA must be user-supplied. However, M might be supplied even though it is not
913 // 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")
914 // 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
915 // to NoFactory. The tricky part is when MinvA is parameter of sublist("project auxiliary matrices") and MinvAFactory == CoalesceDrop. In this case, there are
916 // 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
917 // don't know what the user has supplied, it is safest to set the level 0 manager for both M and Minv to NoFactory.
918
919 if (projectM_) UpdateFactoryManager_MatrixTransfer("M", paramList, defaultList, manager, levelID, keeps);
920 if (!projectM_ && projectMinv_ && (MinvFactory == "CoalesceDrop") && (levelID == 0)) manager.SetFactory("M", NoFactory::getRCP()); // need to get M to created Minv
921 if (!projectM_ && !projectMinv_ && (MinvAFactory == "CoalesceDrop") && projectMinvA_ && (levelID == 0)) {
922 manager.SetFactory("M", NoFactory::getRCP()); // might need M to compute MinvA
923 manager.SetFactory("Minv", NoFactory::getRCP()); // might need Minv to compute MinvA
924 }
925 if (projectMinvA_) {
926 if ((levelID > 0) || (MinvAFactory == "NoFactory"))
927 UpdateFactoryManager_MatrixTransfer("MinvA", paramList, defaultList, manager, levelID, keeps);
928 else {
929 auto coalFact = rcp(new CoalesceDropFactory_kokkos());
930 manager.SetFactory("MinvA", coalFact);
931 } // kokkos guard ?????
932 }
933 if (projectMinv_) {
934 if ((levelID > 0) || (MinvFactory == "NoFactory"))
935 UpdateFactoryManager_MatrixTransfer("Minv", paramList, defaultList, manager, levelID, keeps);
936 else {
937 auto coalFact = rcp(new CoalesceDropFactory_kokkos());
938 manager.SetFactory("Minv", coalFact);
939 } // kokkos guard ?????
940 }
941 }
942
943 // === Lower precision transfers ===
944 UpdateFactoryManager_LowPrecision(paramList, defaultList, manager, levelID, keeps);
945
946 // === Final Keeps for Reuse ===
947 if ((reuseType == "RAP" || reuseType == "full") && levelID) {
948 keeps.push_back(keep_pair("P", manager.GetFactory("P").get()));
949 if (!this->implicitTranspose_)
950 keeps.push_back(keep_pair("R", manager.GetFactory("R").get()));
951 keeps.push_back(keep_pair("A", manager.GetFactory("A").get()));
952 }
953
954 // In case you ever want to inspect the FactoryManager as it is generated for each level
955 /*std::cout<<"*** Factory Manager on level "<<levelID<<" ***"<<std::endl;
956 manager.Print(); */
957}
958
959// =====================================================================================================
960// ========================================= Smoothers =================================================
961// =====================================================================================================
962template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
964 UpdateFactoryManager_Smoothers(ParameterList& paramList, const ParameterList& defaultList,
965 FactoryManager& manager, int levelID, std::vector<keep_pair>& keeps) const {
966 auto multigridAlgo = set_var_2list<std::string>(paramList, defaultList, "multigrid algorithm");
967 auto reuseType = set_var_2list<std::string>(paramList, defaultList, "reuse: type");
968 auto useMaxAbsDiagonalScaling = set_var_2list<bool>(paramList, defaultList, "sa: use rowsumabs diagonal scaling");
969
970 // === Smoothing ===
971 // FIXME: should custom smoother check default list too?
972 bool isCustomSmoother =
973 paramList.isParameter("smoother: pre or post") ||
974 paramList.isParameter("smoother: type") || paramList.isParameter("smoother: pre type") || paramList.isParameter("smoother: post type") ||
975 paramList.isSublist("smoother: params") || paramList.isSublist("smoother: pre params") || paramList.isSublist("smoother: post params") ||
976 paramList.isParameter("smoother: sweeps") || paramList.isParameter("smoother: pre sweeps") || paramList.isParameter("smoother: post sweeps") ||
977 paramList.isParameter("smoother: overlap") || paramList.isParameter("smoother: pre overlap") || paramList.isParameter("smoother: post overlap");
978
979 auto PreOrPost = set_var_2list<std::string>(paramList, defaultList, "smoother: pre or post");
980 if (PreOrPost == "none") {
981 manager.SetFactory("Smoother", Teuchos::null);
982
983 } else if (isCustomSmoother) {
984 // FIXME: get default values from the factory
985 // NOTE: none of the smoothers at the moment use parameter validation framework, so we
986 // cannot get the default values from it.
987#define TEST_MUTUALLY_EXCLUSIVE(arg1, arg2) \
988 TEUCHOS_TEST_FOR_EXCEPTION(paramList.isParameter(#arg1) && paramList.isParameter(#arg2), \
989 Exceptions::InvalidArgument, "You cannot specify both \"" #arg1 "\" and \"" #arg2 "\"");
990#define TEST_MUTUALLY_EXCLUSIVE_S(arg1, arg2) \
991 TEUCHOS_TEST_FOR_EXCEPTION(paramList.isSublist(#arg1) && paramList.isSublist(#arg2), \
992 Exceptions::InvalidArgument, "You cannot specify both \"" #arg1 "\" and \"" #arg2 "\"");
993
994 TEST_MUTUALLY_EXCLUSIVE("smoother: type", "smoother: pre type");
995 TEST_MUTUALLY_EXCLUSIVE("smoother: type", "smoother: post type");
996 TEST_MUTUALLY_EXCLUSIVE("smoother: sweeps", "smoother: pre sweeps");
997 TEST_MUTUALLY_EXCLUSIVE("smoother: sweeps", "smoother: post sweeps");
998 TEST_MUTUALLY_EXCLUSIVE("smoother: overlap", "smoother: pre overlap");
999 TEST_MUTUALLY_EXCLUSIVE("smoother: overlap", "smoother: post overlap");
1000 TEST_MUTUALLY_EXCLUSIVE_S("smoother: params", "smoother: pre params");
1001 TEST_MUTUALLY_EXCLUSIVE_S("smoother: params", "smoother: post params");
1002 TEUCHOS_TEST_FOR_EXCEPTION(PreOrPost == "both" && (paramList.isParameter("smoother: pre type") != paramList.isParameter("smoother: post type")),
1003 Exceptions::InvalidArgument, "You must specify both \"smoother: pre type\" and \"smoother: post type\"");
1004
1005 // Default values
1006 int overlap = 0;
1007 ParameterList defaultSmootherParams;
1008 defaultSmootherParams.set("relaxation: type", "Symmetric Gauss-Seidel");
1009 defaultSmootherParams.set("relaxation: sweeps", Teuchos::OrdinalTraits<LO>::one());
1010 defaultSmootherParams.set("relaxation: damping factor", Teuchos::ScalarTraits<Scalar>::one());
1011
1012 RCP<SmootherFactory> preSmoother = Teuchos::null, postSmoother = Teuchos::null;
1013 std::string preSmootherType, postSmootherType;
1014 ParameterList preSmootherParams, postSmootherParams;
1015
1016 auto setChebyshevSettings = [&](const std::string& smootherType, Teuchos::ParameterList& smootherParams) {
1017 auto upperCaseSmootherType = smootherType;
1018 std::transform(smootherType.begin(), smootherType.end(), upperCaseSmootherType.begin(), ::toupper);
1019 if (upperCaseSmootherType != "CHEBYSHEV") return;
1020
1021 if (smootherParams.isParameter("chebyshev: use rowsumabs diagonal scaling")) {
1022 bool useMaxAbsDiagonalScalingCheby = smootherParams.get<bool>("chebyshev: use rowsumabs diagonal scaling");
1023 TEUCHOS_TEST_FOR_EXCEPTION(useMaxAbsDiagonalScaling != useMaxAbsDiagonalScalingCheby,
1024 Exceptions::RuntimeError, "'chebyshev: use rowsumabs diagonal scaling' (" << std::boolalpha << useMaxAbsDiagonalScalingCheby << ") must match 'sa: use rowsumabs diagonal scaling' (" << std::boolalpha << useMaxAbsDiagonalScaling << ")\n");
1025 } else {
1026 if (useMaxAbsDiagonalScaling)
1027 smootherParams.set("chebyshev: use rowsumabs diagonal scaling", useMaxAbsDiagonalScaling);
1028 }
1029 };
1030
1031 if (paramList.isParameter("smoother: overlap"))
1032 overlap = paramList.get<int>("smoother: overlap");
1033
1034 if (PreOrPost == "pre" || PreOrPost == "both") {
1035 if (paramList.isParameter("smoother: pre type")) {
1036 preSmootherType = paramList.get<std::string>("smoother: pre type");
1037 } else {
1038 auto preSmootherTypeTmp = set_var_2list<std::string>(paramList, defaultList, "smoother: type");
1039 preSmootherType = preSmootherTypeTmp;
1040 }
1041 if (paramList.isParameter("smoother: pre overlap"))
1042 overlap = paramList.get<int>("smoother: pre overlap");
1043
1044 if (paramList.isSublist("smoother: pre params"))
1045 preSmootherParams = paramList.sublist("smoother: pre params");
1046 else if (paramList.isSublist("smoother: params"))
1047 preSmootherParams = paramList.sublist("smoother: params");
1048 else if (defaultList.isSublist("smoother: params"))
1049 preSmootherParams = defaultList.sublist("smoother: params");
1050 else if (preSmootherType == "RELAXATION")
1051 preSmootherParams = defaultSmootherParams;
1052
1053 setChebyshevSettings(preSmootherType, preSmootherParams);
1054
1055#if defined(HAVE_MUELU_INTREPID2) && defined(HAVE_MUELU_EXPERIMENTAL)
1056 // Propagate P-coarsening for Topo smoothing
1057 if (multigridAlgo == "pcoarsen" && preSmootherType == "TOPOLOGICAL" &&
1058 defaultList.isParameter("pcoarsen: schedule") && defaultList.isParameter("pcoarsen: element")) {
1059 // P-Coarsening by schedule (new interface)
1060 // NOTE: levelID represents the *coarse* level in this case
1061 auto pcoarsen_schedule = Teuchos::getArrayFromStringParameter<int>(defaultList, "pcoarsen: schedule");
1062 auto pcoarsen_element = defaultList.get<std::string>("pcoarsen: element");
1063
1064 if (levelID < (int)pcoarsen_schedule.size()) {
1065 // Topo info for P-Coarsening
1066 auto lo = pcoarsen_element + std::to_string(pcoarsen_schedule[levelID]);
1067 preSmootherParams.set("pcoarsen: hi basis", lo);
1068 }
1069 }
1070#endif
1071
1072#ifdef HAVE_MUELU_MATLAB
1073 if (preSmootherType == "matlab")
1074 preSmoother = rcp(new SmootherFactory(rcp(new MatlabSmoother(preSmootherParams))));
1075 else
1076#endif
1077#ifdef HAVE_MUELU_TEKO
1078 if (preSmootherType == "teko")
1079 preSmoother = rcp(new SmootherFactory(rcp(new TekoSmoother(preSmootherParams))));
1080 else
1081#endif
1082 preSmoother = rcp(new SmootherFactory(rcp(new TrilinosSmoother(preSmootherType, preSmootherParams, overlap))));
1083 }
1084
1085 if (PreOrPost == "post" || PreOrPost == "both") {
1086 if (paramList.isParameter("smoother: post type"))
1087 postSmootherType = paramList.get<std::string>("smoother: post type");
1088 else {
1089 auto postSmootherTypeTmp = set_var_2list<std::string>(paramList, defaultList, "smoother: type");
1090 postSmootherType = postSmootherTypeTmp;
1091 }
1092
1093 if (paramList.isSublist("smoother: post params"))
1094 postSmootherParams = paramList.sublist("smoother: post params");
1095 else if (paramList.isSublist("smoother: params"))
1096 postSmootherParams = paramList.sublist("smoother: params");
1097 else if (defaultList.isSublist("smoother: params"))
1098 postSmootherParams = defaultList.sublist("smoother: params");
1099 else if (postSmootherType == "RELAXATION")
1100 postSmootherParams = defaultSmootherParams;
1101 if (paramList.isParameter("smoother: post overlap"))
1102 overlap = paramList.get<int>("smoother: post overlap");
1103
1104 setChebyshevSettings(postSmootherType, postSmootherParams);
1105
1106 if (postSmootherType == preSmootherType && areSame(preSmootherParams, postSmootherParams))
1107 postSmoother = preSmoother;
1108 else {
1109#if defined(HAVE_MUELU_INTREPID2) && defined(HAVE_MUELU_EXPERIMENTAL)
1110 // Propagate P-coarsening for Topo smoothing
1111 if (multigridAlgo == "pcoarsen" && preSmootherType == "TOPOLOGICAL" &&
1112 defaultList.isParameter("pcoarsen: schedule") && defaultList.isParameter("pcoarsen: element")) {
1113 // P-Coarsening by schedule (new interface)
1114 // NOTE: levelID represents the *coarse* level in this case
1115 auto pcoarsen_schedule = Teuchos::getArrayFromStringParameter<int>(defaultList, "pcoarsen: schedule");
1116 auto pcoarsen_element = defaultList.get<std::string>("pcoarsen: element");
1117
1118 if (levelID < (int)pcoarsen_schedule.size()) {
1119 // Topo info for P-Coarsening
1120 auto lo = pcoarsen_element + std::to_string(pcoarsen_schedule[levelID]);
1121 postSmootherParams.set("pcoarsen: hi basis", lo);
1122 }
1123 }
1124#endif
1125
1126#ifdef HAVE_MUELU_MATLAB
1127 if (postSmootherType == "matlab")
1128 postSmoother = rcp(new SmootherFactory(rcp(new MatlabSmoother(postSmootherParams))));
1129 else
1130#endif
1131#ifdef HAVE_MUELU_TEKO
1132 if (postSmootherType == "teko")
1133 postSmoother = rcp(new SmootherFactory(rcp(new TekoSmoother(postSmootherParams))));
1134 else
1135#endif
1136 postSmoother = rcp(new SmootherFactory(rcp(new TrilinosSmoother(postSmootherType, postSmootherParams, overlap))));
1137 }
1138 }
1139
1140 if (preSmoother == postSmoother)
1141 manager.SetFactory("Smoother", preSmoother);
1142 else {
1143 manager.SetFactory("PreSmoother", preSmoother);
1144 manager.SetFactory("PostSmoother", postSmoother);
1145 }
1146 }
1147
1148 // The first clause is not necessary, but it is here for clarity Smoothers
1149 // are reused if smoother explicitly said to reuse them, or if any other
1150 // reuse option is enabled
1151 bool reuseSmoothers = (reuseType == "S" || reuseType != "none");
1152 if (reuseSmoothers) {
1153 auto preSmootherFactory = rcp_const_cast<Factory>(rcp_dynamic_cast<const Factory>(manager.GetFactory("PreSmoother")));
1154
1155 if (preSmootherFactory != Teuchos::null) {
1156 ParameterList postSmootherFactoryParams;
1157 postSmootherFactoryParams.set("keep smoother data", true);
1158 preSmootherFactory->SetParameterList(postSmootherFactoryParams);
1159
1160 keeps.push_back(keep_pair("PreSmoother data", preSmootherFactory.get()));
1161 }
1162
1163 auto postSmootherFactory = rcp_const_cast<Factory>(rcp_dynamic_cast<const Factory>(manager.GetFactory("PostSmoother")));
1164 if (postSmootherFactory != Teuchos::null) {
1165 ParameterList postSmootherFactoryParams;
1166 postSmootherFactoryParams.set("keep smoother data", true);
1167 postSmootherFactory->SetParameterList(postSmootherFactoryParams);
1168
1169 keeps.push_back(keep_pair("PostSmoother data", postSmootherFactory.get()));
1170 }
1171
1172 auto coarseFactory = rcp_const_cast<Factory>(rcp_dynamic_cast<const Factory>(manager.GetFactory("CoarseSolver")));
1173 if (coarseFactory != Teuchos::null) {
1174 ParameterList coarseFactoryParams;
1175 coarseFactoryParams.set("keep smoother data", true);
1176 coarseFactory->SetParameterList(coarseFactoryParams);
1177
1178 keeps.push_back(keep_pair("PreSmoother data", coarseFactory.get()));
1179 }
1180 }
1181
1182 if ((reuseType == "RAP" && levelID) || (reuseType == "full")) {
1183 // The difference between "RAP" and "full" is keeping smoothers. However,
1184 // as in both cases we keep coarse matrices, we do not need to update
1185 // coarse smoothers. On the other hand, if a user changes fine level
1186 // matrix, "RAP" would update the fine level smoother, while "full" would
1187 // not
1188 keeps.push_back(keep_pair("PreSmoother", manager.GetFactory("PreSmoother").get()));
1189 keeps.push_back(keep_pair("PostSmoother", manager.GetFactory("PostSmoother").get()));
1190
1191 // We do keep_pair("PreSmoother", manager.GetFactory("CoarseSolver").get())
1192 // as the coarse solver factory is in fact a smoothing factory, so the
1193 // only pieces of data it generates are PreSmoother and PostSmoother
1194 keeps.push_back(keep_pair("PreSmoother", manager.GetFactory("CoarseSolver").get()));
1195 }
1196}
1197
1198// =====================================================================================================
1199// ====================================== Coarse Solvers ===============================================
1200// =====================================================================================================
1201template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1203 UpdateFactoryManager_CoarseSolvers(ParameterList& paramList, const ParameterList& defaultList,
1204 FactoryManager& manager, int /* levelID */, std::vector<keep_pair>& /* keeps */) const {
1205 // FIXME: should custom coarse solver check default list too?
1206 bool isCustomCoarseSolver =
1207 paramList.isParameter("coarse: type") ||
1208 paramList.isParameter("coarse: params");
1209 if (test_param_2list<std::string>(paramList, defaultList, "coarse: type", "none")) {
1210 manager.SetFactory("CoarseSolver", Teuchos::null);
1211
1212 } else if (isCustomCoarseSolver) {
1213 // FIXME: get default values from the factory
1214 // NOTE: none of the smoothers at the moment use parameter validation framework, so we
1215 // cannot get the default values from it.
1216 auto coarseType = set_var_2list<std::string>(paramList, defaultList, "coarse: type");
1217
1218 int overlap = 0;
1219 if (paramList.isParameter("coarse: overlap"))
1220 overlap = paramList.get<int>("coarse: overlap");
1221
1222 ParameterList coarseParams;
1223 if (paramList.isSublist("coarse: params"))
1224 coarseParams = paramList.sublist("coarse: params");
1225 else if (defaultList.isSublist("coarse: params"))
1226 coarseParams = defaultList.sublist("coarse: params");
1227
1228 using strings = std::unordered_set<std::string>;
1229
1230 RCP<SmootherPrototype> coarseSmoother;
1231 // TODO: this is not a proper place to check. If we consider direct solver to be a special
1232 // case of smoother, we would like to unify Amesos and Ifpack2 smoothers in src/Smoothers, and
1233 // have a single factory responsible for those. Then, this check would belong there.
1234 if (strings({"RELAXATION", "CHEBYSHEV", "ILUT", "ILU", "RILUK", "SCHWARZ", "Amesos",
1235 "BLOCK RELAXATION", "BLOCK_RELAXATION", "BLOCKRELAXATION",
1236 "SPARSE BLOCK RELAXATION", "SPARSE_BLOCK_RELAXATION", "SPARSEBLOCKRELAXATION",
1237 "LINESMOOTHING_BANDEDRELAXATION", "LINESMOOTHING_BANDED_RELAXATION", "LINESMOOTHING_BANDED RELAXATION",
1238 "LINESMOOTHING_TRIDIRELAXATION", "LINESMOOTHING_TRIDI_RELAXATION", "LINESMOOTHING_TRIDI RELAXATION",
1239 "LINESMOOTHING_TRIDIAGONALRELAXATION", "LINESMOOTHING_TRIDIAGONAL_RELAXATION", "LINESMOOTHING_TRIDIAGONAL RELAXATION",
1240 "TOPOLOGICAL", "FAST_ILU", "FAST_IC", "FAST_ILDL", "HIPTMAIR"})
1241 .count(coarseType)) {
1242 coarseSmoother = rcp(new TrilinosSmoother(coarseType, coarseParams, overlap));
1243 } else {
1244#ifdef HAVE_MUELU_MATLAB
1245 if (coarseType == "matlab")
1246 coarseSmoother = rcp(new MatlabSmoother(coarseParams));
1247 else
1248#endif
1249#ifdef HAVE_MUELU_TEKO
1250 if (coarseType == "teko")
1251 coarseSmoother = rcp(new TekoSmoother(coarseParams));
1252 else
1253#endif
1254 coarseSmoother = rcp(new DirectSolver(coarseType, coarseParams));
1255 }
1256
1257 manager.SetFactory("CoarseSolver", rcp(new SmootherFactory(coarseSmoother)));
1258 }
1259}
1260
1261// =====================================================================================================
1262// ========================================= Reitzinger =================================================
1263// =====================================================================================================
1264template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1266 UpdateFactoryManager_Reitzinger(ParameterList& paramList, const ParameterList& defaultList,
1267 FactoryManager& manager, int levelID, std::vector<keep_pair>& /*keeps*/) const {
1268 ParameterList rParams;
1269 test_and_set_param_2list<bool>(paramList, defaultList, "repartition: enable", rParams);
1270 test_and_set_param_2list<bool>(paramList, defaultList, "repartition: use subcommunicators", rParams);
1271 test_and_set_param_2list<bool>(paramList, defaultList, "tentative: constant column sums", rParams);
1272 test_and_set_param_2list<bool>(paramList, defaultList, "tentative: calculate qr", rParams);
1273
1274 RCP<Factory> rFactory = rcp(new ReitzingerPFactory());
1275 rFactory->SetParameterList(rParams);
1276
1277 // These are all going to be user provided, so NoFactory
1278 rFactory->SetFactory("Pnodal", NoFactory::getRCP());
1279 rFactory->SetFactory("NodeAggMatrix", NoFactory::getRCP());
1280 // rFactory->SetFactory("NodeMatrix", NoFactory::getRCP());
1281
1282 if (levelID > 1)
1283 rFactory->SetFactory("D0", this->GetFactoryManager(levelID - 1)->GetFactory("D0"));
1284 else
1285 rFactory->SetFactory("D0", NoFactory::getRCP());
1286
1287 manager.SetFactory("Ptent", rFactory);
1288 manager.SetFactory("D0", rFactory);
1289 manager.SetFactory("InPlaceMap", rFactory);
1290}
1291
1292// =====================================================================================================
1293// =============================== Algorithm: Energy Minimization Reitzinger ===========================
1294// =====================================================================================================
1295template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1297 UpdateFactoryManager_EminReitzinger(ParameterList& paramList, const ParameterList& defaultList, FactoryManager& manager,
1298 int levelID, std::vector<keep_pair>& /*keeps*/) const {
1299 ParameterList rParams;
1300 test_and_set_param_2list<bool>(paramList, defaultList, "repartition: enable", rParams);
1301 test_and_set_param_2list<bool>(paramList, defaultList, "repartition: use subcommunicators", rParams);
1302 test_and_set_param_2list<bool>(paramList, defaultList, "tentative: constant column sums", rParams);
1303 test_and_set_param_2list<bool>(paramList, defaultList, "tentative: calculate qr", rParams);
1304
1305 RCP<Factory> rFactory = rcp(new ReitzingerPFactory());
1306 rFactory->SetParameterList(rParams);
1307
1308 // These are all going to be user provided, so NoFactory
1309 rFactory->SetFactory("Pnodal", NoFactory::getRCP());
1310 rFactory->SetFactory("NodeAggMatrix", NoFactory::getRCP());
1311 // rFactory->SetFactory("NodeMatrix", NoFactory::getRCP());
1312
1313 if (levelID > 1)
1314 rFactory->SetFactory("D0", this->GetFactoryManager(levelID - 1)->GetFactory("D0"));
1315 else
1316 rFactory->SetFactory("D0", NoFactory::getRCP());
1317
1318 manager.SetFactory("Ptent", rFactory);
1319 manager.SetFactory("D0", rFactory);
1320 manager.SetFactory("InPlaceMap", rFactory);
1321
1322 auto reuseType = set_var_2list<std::string>(paramList, defaultList, "reuse: type");
1323
1324 // Pattern
1325 auto patternFactory = rcp(new EdgeProlongatorPatternFactory());
1326 manager.SetFactory("Ppattern", patternFactory);
1327
1328 // Constraint
1329 auto constraintFactory = rcp(new ConstraintFactory());
1330 ParameterList constraintParams;
1331 constraintFactory->SetFactory("Ppattern", manager.GetFactory("Ppattern"));
1332 test_and_set_param_2list<std::string>(paramList, defaultList, "emin: least squares solver type", constraintParams);
1333 constraintParams.set("emin: constraint type", "maxwell");
1334 constraintFactory->SetParameterList(constraintParams);
1335 manager.SetFactory("Constraint", constraintFactory);
1336
1337 // Emin Factory
1338 auto P = rcp(new EminPFactory());
1339
1340 // Energy minimization
1341 ParameterList Pparams;
1342 test_and_set_param_2list<int>(paramList, defaultList, "emin: num iterations", Pparams);
1343 test_and_set_param_2list<std::string>(paramList, defaultList, "emin: iterative method", Pparams);
1344 if (reuseType == "emin") {
1345 test_and_set_param_2list<int>(paramList, defaultList, "emin: num reuse iterations", Pparams);
1346 Pparams.set("Keep P0", true);
1347 Pparams.set("Keep Constraint0", true);
1348 }
1349 P->SetParameterList(Pparams);
1350 P->SetFactory("P", constraintFactory);
1351 P->SetFactory("Constraint", constraintFactory);
1352 manager.SetFactory("P", P);
1353}
1354
1355// =====================================================================================================
1356// ========================================= TentativeP=================================================
1357// =====================================================================================================
1358template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1360 UpdateFactoryManager_Aggregation_TentativeP(ParameterList& paramList, const ParameterList& defaultList,
1361 FactoryManager& manager, int levelID, std::vector<keep_pair>& keeps) const {
1362 using strings = std::unordered_set<std::string>;
1363
1364 auto reuseType = set_var_2list<std::string>(paramList, defaultList, "reuse: type");
1365
1366 auto aggType = set_var_2list<std::string>(paramList, defaultList, "aggregation: type");
1367 TEUCHOS_TEST_FOR_EXCEPTION(!strings({"uncoupled", "coupled", "brick", "matlab", "notay", "classical"}).count(aggType),
1368 Exceptions::RuntimeError, "Unknown aggregation algorithm: \"" << aggType << "\". Please consult User's Guide.");
1369
1370 // Only doing this for classical because otherwise, the gold tests get broken badly
1371 RCP<AmalgamationFactory> amalgFact;
1372 if (aggType == "classical") {
1373 amalgFact = rcp(new AmalgamationFactory());
1374 manager.SetFactory("UnAmalgamationInfo", amalgFact);
1375 }
1376
1377 // Aggregation graph
1378 RCP<Factory> dropFactory;
1379
1380 if (test_param_2list<std::string>(paramList, paramList, "aggregation: drop scheme", "matlab")) {
1381#ifdef HAVE_MUELU_MATLAB
1382 dropFactory = rcp(new SingleLevelMatlabFactory());
1383 ParameterList socParams = paramList.sublist("strength-of-connection: params");
1384 dropFactory->SetParameterList(socParams);
1385#else
1386 throw std::runtime_error("Cannot use MATLAB evolutionary strength-of-connection - MueLu was not configured with MATLAB support.");
1387#endif
1388 } else if (test_param_2list<std::string>(paramList, paramList, "aggregation: drop scheme", "unsupported vector smoothing")) {
1390 ParameterList dropParams;
1391 test_and_set_param_2list<std::string>(paramList, defaultList, "aggregation: drop scheme", dropParams);
1392 test_and_set_param_2list<int>(paramList, defaultList, "aggregation: block diagonal: interleaved blocksize", dropParams);
1393 test_and_set_param_2list<int>(paramList, defaultList, "aggregation: number of random vectors", dropParams);
1394 test_and_set_param_2list<int>(paramList, defaultList, "aggregation: number of times to pre or post smooth", dropParams);
1395 test_and_set_param_2list<Teuchos::Array<double>>(paramList, defaultList, "aggregation: penalty parameters", dropParams);
1396 dropFactory->SetParameterList(dropParams);
1397 } else {
1399 ParameterList dropParams;
1400 if (!rcp_dynamic_cast<CoalesceDropFactory>(dropFactory).is_null())
1401 dropParams.set("lightweight wrap", true);
1402 test_and_set_param_2list<std::string>(paramList, defaultList, "aggregation: drop scheme", dropParams);
1403 test_and_set_param_2list<double>(paramList, defaultList, "aggregation: row sum drop tol", dropParams);
1404 test_and_set_param_2list<int>(paramList, defaultList, "aggregation: block diagonal: interleaved blocksize", dropParams);
1405 test_and_set_param_2list<double>(paramList, defaultList, "aggregation: drop tol", dropParams);
1406 test_and_set_param_2list<bool>(paramList, defaultList, "aggregation: use ml scaling of drop tol", dropParams);
1407
1408 test_and_set_param_2list<double>(paramList, defaultList, "aggregation: Dirichlet threshold", dropParams);
1409 test_and_set_param_2list<bool>(paramList, defaultList, "aggregation: greedy Dirichlet", dropParams);
1410 if (useKokkos_)
1411 test_and_set_param_2list<std::string>(paramList, defaultList, "aggregation: distance laplacian metric", dropParams);
1412 if (useKokkos_)
1413 test_and_set_param_2list<std::string>(paramList, defaultList, "aggregation: Minv scheme", dropParams);
1414
1415#ifdef HAVE_MUELU_COALESCEDROP_ALLOW_OLD_PARAMETERS
1416 test_and_set_param_2list<std::string>(paramList, defaultList, "aggregation: distance laplacian algo", dropParams);
1417 test_and_set_param_2list<std::string>(paramList, defaultList, "aggregation: classical algo", dropParams);
1418#endif
1419 test_and_set_param_2list<Teuchos::Array<double>>(paramList, defaultList, "aggregation: distance laplacian directional weights", dropParams);
1420 test_and_set_param_2list<bool>(paramList, defaultList, "aggregation: coloring: localize color graph", dropParams);
1421 test_and_set_param_2list<bool>(paramList, defaultList, "aggregation: dropping may create Dirichlet", dropParams);
1422 if (useKokkos_) {
1423 test_and_set_param_2list<bool>(paramList, defaultList, "aggregation: use blocking", dropParams);
1424 test_and_set_param_2list<bool>(paramList, defaultList, "aggregation: symmetrize graph after dropping", dropParams);
1425 test_and_set_param_2list<std::string>(paramList, defaultList, "aggregation: strength-of-connection: matrix", dropParams);
1426 test_and_set_param_2list<std::string>(paramList, defaultList, "aggregation: strength-of-connection: measure", dropParams);
1427 test_and_set_param_2list<bool>(paramList, defaultList, "filtered matrix: use lumping", dropParams);
1428 test_and_set_param_2list<bool>(paramList, defaultList, "filtered matrix: reuse graph", dropParams);
1429 test_and_set_param_2list<bool>(paramList, defaultList, "filtered matrix: reuse eigenvalue", dropParams);
1430 test_and_set_param_2list<bool>(paramList, defaultList, "filtered matrix: use root stencil", dropParams);
1431 test_and_set_param_2list<double>(paramList, defaultList, "filtered matrix: Dirichlet threshold", dropParams);
1432 test_and_set_param_2list<bool>(paramList, defaultList, "filtered matrix: use spread lumping", dropParams);
1433 test_and_set_param_2list<std::string>(paramList, defaultList, "filtered matrix: lumping choice", dropParams);
1434 test_and_set_param_2list<double>(paramList, defaultList, "filtered matrix: spread lumping diag dom growth factor", dropParams);
1435 test_and_set_param_2list<double>(paramList, defaultList, "filtered matrix: spread lumping diag dom cap", dropParams);
1436 test_and_set_param_2list<bool>(paramList, defaultList, "filtered matrix: count negative diagonals", dropParams);
1437 }
1438
1439#ifdef HAVE_MUELU_COALESCEDROP_ALLOW_OLD_PARAMETERS
1440 if (!dropParams.isParameter("aggregation: drop scheme") ||
1441 (dropParams.isParameter("aggregation: drop scheme") &&
1442 ((dropParams.get<std::string>("aggregation: drop scheme") != "point-wise") && (dropParams.get<std::string>("aggregation: drop scheme") != "cut-drop")))) {
1443 Teuchos::ParameterList dropParamsWithDefaults(dropParams);
1444
1445 test_and_set_var_from_masterlist<std::string>(dropParamsWithDefaults, "aggregation: drop scheme");
1446 test_and_set_var_from_masterlist<std::string>(dropParamsWithDefaults, "aggregation: strength-of-connection: matrix");
1447 test_and_set_var_from_masterlist<std::string>(dropParamsWithDefaults, "aggregation: strength-of-connection: measure");
1448 test_and_set_var_from_masterlist<bool>(dropParamsWithDefaults, "aggregation: use blocking");
1449
1450 // We are using the old style of dropping params
1451 TEUCHOS_TEST_FOR_EXCEPTION(dropParams.isParameter("aggregation: strength-of-connection: matrix") ||
1452 dropParams.isParameter("aggregation: strength-of-connection: measure") ||
1453 dropParams.isParameter("aggregation: use blocking"),
1454 Teuchos::Exceptions::InvalidParameterType,
1455 "The inputs contain a mix of old and new dropping parameters:\n\n"
1456 << dropParams << "\n\nKeep in mind that defaults are set for old parameters, so this gets interpreted as\n\n"
1457 << dropParamsWithDefaults);
1458 }
1459#endif
1460
1461 if (!amalgFact.is_null())
1462 dropFactory->SetFactory("UnAmalgamationInfo", manager.GetFactory("UnAmalgamationInfo"));
1463
1464 if (dropParams.isParameter("aggregation: drop scheme")) {
1465 std::string drop_scheme = dropParams.get<std::string>("aggregation: drop scheme");
1466 if (drop_scheme == "block diagonal colored signed classical")
1467 manager.SetFactory("Coloring Graph", dropFactory);
1468 if ((test_param_2list<bool>(dropParams, defaultList, "aggregation: use blocking", true)) ||
1469 (drop_scheme.find("block diagonal") != std::string::npos || drop_scheme == "signed classical")) {
1470 if (levelID > 0)
1471 dropFactory->SetFactory("BlockNumber", this->GetFactoryManager(levelID - 1)->GetFactory("BlockNumber"));
1472 else
1473 dropFactory->SetFactory("BlockNumber", manager.GetFactory("BlockNumber"));
1474 }
1475 }
1476
1477 if (useKokkos_ && (levelID > 0)) {
1478 if (dropParams.isParameter("aggregation: strength-of-connection: matrix") && dropParams.get<std::string>("aggregation: strength-of-connection: matrix") == "MinvA") {
1479 if (projectM_) dropFactory->SetFactory("M", this->GetFactoryManager(levelID - 1)->GetFactory("M"));
1480 if (projectMinv_) dropFactory->SetFactory("Minv", this->GetFactoryManager(levelID - 1)->GetFactory("Minv"));
1481 if (projectMinvA_) dropFactory->SetFactory("MinvA", this->GetFactoryManager(levelID - 1)->GetFactory("MinvA"));
1482 }
1483 }
1484
1485 auto socMatrix = set_var_2list<std::string>(paramList, defaultList, "aggregation: strength-of-connection: matrix");
1486 if ((socMatrix == "MinvA") && (paramList.isSublist("project auxiliary matrices"))) {
1487 auto projectList = paramList.sublist("project auxiliary matrices");
1488 dropParams.set("project auxiliary matrices", projectList);
1489 }
1490 dropFactory->SetParameterList(dropParams);
1491 }
1492 manager.SetFactory("Graph", dropFactory);
1493
1494// Aggregation scheme
1495#ifndef HAVE_MUELU_MATLAB
1496 if (aggType == "matlab")
1497 throw std::runtime_error("Cannot use MATLAB aggregation - MueLu was not configured with MATLAB support.");
1498#endif
1499 RCP<Factory> aggFactory;
1500 if (aggType == "uncoupled") {
1501 aggFactory = rcp(new UncoupledAggregationFactory());
1502 ParameterList aggParams;
1503 test_and_set_param_2list<std::string>(paramList, defaultList, "aggregation: ordering", aggParams);
1504 test_and_set_param_2list<int>(paramList, defaultList, "aggregation: min agg size", aggParams);
1505 test_and_set_param_2list<int>(paramList, defaultList, "aggregation: max agg size", aggParams);
1506 test_and_set_param_2list<int>(paramList, defaultList, "aggregation: max selected neighbors", aggParams);
1507 test_and_set_param_2list<std::string>(paramList, defaultList, "aggregation: backend", aggParams);
1508 test_and_set_param_2list<std::string>(paramList, defaultList, "aggregation: phase 1 algorithm", aggParams);
1509 test_and_set_param_2list<bool>(paramList, defaultList, "aggregation: deterministic", aggParams);
1510 test_and_set_param_2list<std::string>(paramList, defaultList, "aggregation: coloring algorithm", aggParams);
1511 test_and_set_param_2list<bool>(paramList, defaultList, "aggregation: enable phase 1", aggParams);
1512 test_and_set_param_2list<bool>(paramList, defaultList, "aggregation: enable phase 2a", aggParams);
1513 test_and_set_param_2list<bool>(paramList, defaultList, "aggregation: enable phase 2b", aggParams);
1514 test_and_set_param_2list<bool>(paramList, defaultList, "aggregation: enable phase 3", aggParams);
1515 test_and_set_param_2list<bool>(paramList, defaultList, "aggregation: match ML phase1", aggParams);
1516 test_and_set_param_2list<bool>(paramList, defaultList, "aggregation: match ML phase2a", aggParams);
1517 test_and_set_param_2list<bool>(paramList, defaultList, "aggregation: match ML phase2b", aggParams);
1518 test_and_set_param_2list<double>(paramList, defaultList, "aggregation: phase2a agg factor", aggParams);
1519 test_and_set_param_2list<bool>(paramList, defaultList, "aggregation: preserve Dirichlet points", aggParams);
1520 test_and_set_param_2list<bool>(paramList, defaultList, "aggregation: error on nodes with no on-rank neighbors", aggParams);
1521 test_and_set_param_2list<bool>(paramList, defaultList, "aggregation: phase3 avoid singletons", aggParams);
1522 aggFactory->SetParameterList(aggParams);
1523 // make sure that the aggregation factory has all necessary data
1524 aggFactory->SetFactory("DofsPerNode", manager.GetFactory("Graph"));
1525 aggFactory->SetFactory("Graph", manager.GetFactory("Graph"));
1526 // aggFactory->SetFactory("UnAmalgamationInfo", manager.GetFactory("UnAmalgamationInfo"));
1527
1528 if (test_param_2list<std::string>(paramList, defaultList, "aggregation: coloring algorithm", "mis2 aggregation") ||
1529 test_param_2list<std::string>(paramList, defaultList, "aggregation: coloring algorithm", "mis2 coarsening")) {
1530 if (test_param_2list<bool>(paramList, defaultList, "aggregation: symmetrize graph after dropping", false))
1531 TEUCHOS_TEST_FOR_EXCEPTION(true,
1533 "MIS2 algorithms require the use of a symmetrized graph. Please set \"aggregation: symmetrize graph after dropping\" to \"true\".");
1534 }
1535 } else if (aggType == "brick") {
1536 aggFactory = rcp(new BrickAggregationFactory());
1537 ParameterList aggParams;
1538 test_and_set_param_2list<int>(paramList, defaultList, "aggregation: brick x size", aggParams);
1539 test_and_set_param_2list<int>(paramList, defaultList, "aggregation: brick y size", aggParams);
1540 test_and_set_param_2list<int>(paramList, defaultList, "aggregation: brick z size", aggParams);
1541 test_and_set_param_2list<bool>(paramList, defaultList, "aggregation: brick x Dirichlet", aggParams);
1542 test_and_set_param_2list<bool>(paramList, defaultList, "aggregation: brick y Dirichlet", aggParams);
1543 test_and_set_param_2list<bool>(paramList, defaultList, "aggregation: brick z Dirichlet", aggParams);
1544 aggFactory->SetParameterList(aggParams);
1545
1546 // Unlike other factories, BrickAggregationFactory makes the Graph/DofsPerNode itself
1547 manager.SetFactory("Graph", aggFactory);
1548 manager.SetFactory("DofsPerNode", aggFactory);
1549 manager.SetFactory("Filtering", aggFactory);
1550 if (levelID > 1) {
1551 // We check for levelID > 0, as in the interpreter aggFactory for
1552 // levelID really corresponds to level 0. Managers are clunky, as they
1553 // contain factories for two different levels
1554 aggFactory->SetFactory("Coordinates", this->GetFactoryManager(levelID - 1)->GetFactory("Coordinates"));
1555 }
1556 } else if (aggType == "classical") {
1557 // Map and coloring
1558 RCP<Factory> mapFact = rcp(new ClassicalMapFactory());
1559 ParameterList mapParams;
1560 test_and_set_param_2list<bool>(paramList, defaultList, "aggregation: deterministic", mapParams);
1561 test_and_set_param_2list<std::string>(paramList, defaultList, "aggregation: coloring algorithm", mapParams);
1562
1563 ParameterList tempParams;
1564 test_and_set_param_2list<std::string>(paramList, defaultList, "aggregation: drop scheme", tempParams);
1565 std::string drop_algo = tempParams.get<std::string>("aggregation: drop scheme");
1566 if (drop_algo == "block diagonal colored signed classical") {
1567 mapParams.set("aggregation: coloring: use color graph", true);
1568 mapFact->SetFactory("Coloring Graph", manager.GetFactory("Coloring Graph"));
1569 }
1570 mapFact->SetParameterList(mapParams);
1571 mapFact->SetFactory("Graph", manager.GetFactory("Graph"));
1572 mapFact->SetFactory("UnAmalgamationInfo", manager.GetFactory("UnAmalgamationInfo"));
1573
1574 manager.SetFactory("FC Splitting", mapFact);
1575 manager.SetFactory("CoarseMap", mapFact);
1576
1577 aggFactory = rcp(new ClassicalPFactory());
1578 ParameterList aggParams;
1579 test_and_set_param_2list<std::string>(paramList, defaultList, "aggregation: classical scheme", aggParams);
1580 test_and_set_param_2list<std::string>(paramList, defaultList, "aggregation: drop scheme", aggParams);
1581 aggFactory->SetParameterList(aggParams);
1582 aggFactory->SetFactory("FC Splitting", manager.GetFactory("FC Splitting"));
1583 aggFactory->SetFactory("CoarseMap", manager.GetFactory("CoarseMap"));
1584 aggFactory->SetFactory("DofsPerNode", manager.GetFactory("Graph"));
1585 aggFactory->SetFactory("Graph", manager.GetFactory("Graph"));
1586
1587 if (drop_algo.find("block diagonal") != std::string::npos || drop_algo == "signed classical") {
1588 if (levelID > 0)
1589 aggFactory->SetFactory("BlockNumber", this->GetFactoryManager(levelID - 1)->GetFactory("BlockNumber"));
1590 else
1591 aggFactory->SetFactory("BlockNumber", manager.GetFactory("BlockNumber"));
1592 }
1593
1594 // Now we short-circuit, because we neither need nor want TentativePFactory here
1595 manager.SetFactory("Ptent", aggFactory);
1596 manager.SetFactory("P Graph", aggFactory);
1597
1598 if (reuseType == "tP" && levelID) {
1599 // keeps.push_back(keep_pair("Nullspace", Ptent.get()));
1600 keeps.push_back(keep_pair("Ptent", aggFactory.get()));
1601 }
1602 return;
1603 } else if (aggType == "notay") {
1604 aggFactory = rcp(new NotayAggregationFactory());
1605 ParameterList aggParams;
1606 test_and_set_param_2list<int>(paramList, defaultList, "aggregation: pairwise: size", aggParams);
1607 test_and_set_param_2list<double>(paramList, defaultList, "aggregation: pairwise: tie threshold", aggParams);
1608 test_and_set_param_2list<double>(paramList, defaultList, "aggregation: Dirichlet threshold", aggParams);
1609 test_and_set_param_2list<std::string>(paramList, defaultList, "aggregation: ordering", aggParams);
1610 aggFactory->SetParameterList(aggParams);
1611 aggFactory->SetFactory("DofsPerNode", manager.GetFactory("Graph"));
1612 aggFactory->SetFactory("Graph", manager.GetFactory("Graph"));
1613 }
1614#ifdef HAVE_MUELU_MATLAB
1615 else if (aggType == "matlab") {
1616 ParameterList aggParams = paramList.sublist("aggregation: params");
1617 aggFactory = rcp(new SingleLevelMatlabFactory());
1618 aggFactory->SetParameterList(aggParams);
1619 }
1620#endif
1621
1622 manager.SetFactory("Aggregates", aggFactory);
1623
1624 // Coarse map
1625 RCP<Factory> coarseMap = rcp(new CoarseMapFactory());
1626 coarseMap->SetFactory("Aggregates", manager.GetFactory("Aggregates"));
1627 manager.SetFactory("CoarseMap", coarseMap);
1628
1629 // Tentative P
1631 ParameterList ptentParams;
1632 if (paramList.isSublist("matrixmatrix: kernel params"))
1633 ptentParams.sublist("matrixmatrix: kernel params", false) = paramList.sublist("matrixmatrix: kernel params");
1634 if (defaultList.isSublist("matrixmatrix: kernel params"))
1635 ptentParams.sublist("matrixmatrix: kernel params", false) = defaultList.sublist("matrixmatrix: kernel params");
1636 test_and_set_param_2list<bool>(paramList, defaultList, "tentative: calculate qr", ptentParams);
1637 test_and_set_param_2list<bool>(paramList, defaultList, "tentative: build coarse coordinates", ptentParams);
1638 test_and_set_param_2list<bool>(paramList, defaultList, "sa: keep tentative prolongator", ptentParams);
1639 Ptent->SetParameterList(ptentParams);
1640 Ptent->SetFactory("Aggregates", manager.GetFactory("Aggregates"));
1641 Ptent->SetFactory("CoarseMap", manager.GetFactory("CoarseMap"));
1642 manager.SetFactory("Ptent", Ptent);
1643
1644 if (reuseType == "tP" && levelID) {
1645 keeps.push_back(keep_pair("Nullspace", Ptent.get()));
1646 keeps.push_back(keep_pair("P", Ptent.get()));
1647 }
1648}
1649
1650// =====================================================================================================
1651// ============================================ RAP ====================================================
1652// =====================================================================================================
1653template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1655 UpdateFactoryManager_RAP(ParameterList& paramList, const ParameterList& defaultList, FactoryManager& manager,
1656 int /*levelID*/, std::vector<keep_pair>& keeps) const {
1657 if (paramList.isParameter("A") && !paramList.get<RCP<Matrix>>("A").is_null()) {
1658 // We have user matrix A
1659 manager.SetFactory("A", NoFactory::getRCP());
1660 return;
1661 }
1662
1663 ParameterList RAPparams;
1664
1665 RCP<RAPFactory> RAP;
1666 RCP<RAPShiftFactory> RAPs;
1667 // Allow for Galerkin or shifted RAP
1668 // FIXME: Should this not be some form of set_var_2list?
1669 std::string alg = paramList.get("rap: algorithm", "galerkin");
1670 if (alg == "shift" || alg == "non-galerkin") {
1671 RAPs = rcp(new RAPShiftFactory());
1672 test_and_set_param_2list<double>(paramList, defaultList, "rap: shift", RAPparams);
1673 test_and_set_param_2list<bool>(paramList, defaultList, "rap: shift diagonal M", RAPparams);
1674 test_and_set_param_2list<bool>(paramList, defaultList, "rap: shift low storage", RAPparams);
1675 test_and_set_param_2list<Teuchos::Array<double>>(paramList, defaultList, "rap: shift array", RAPparams);
1676 test_and_set_param_2list<Teuchos::Array<double>>(paramList, defaultList, "rap: cfl array", RAPparams);
1677
1678 } else {
1679 RAP = rcp(new RAPFactory());
1680 }
1681
1682 test_and_set_param_2list<Teuchos::Array<double>>(paramList, defaultList, "rap: relative diagonal floor", RAPparams);
1683
1684 if (paramList.isSublist("matrixmatrix: kernel params"))
1685 RAPparams.sublist("matrixmatrix: kernel params", false) = paramList.sublist("matrixmatrix: kernel params");
1686 if (defaultList.isSublist("matrixmatrix: kernel params"))
1687 RAPparams.sublist("matrixmatrix: kernel params", false) = defaultList.sublist("matrixmatrix: kernel params");
1688 test_and_set_param_2list<bool>(paramList, defaultList, "transpose: use implicit", RAPparams);
1689 test_and_set_param_2list<bool>(paramList, defaultList, "rap: fix zero diagonals", RAPparams);
1690 test_and_set_param_2list<double>(paramList, defaultList, "rap: fix zero diagonals threshold", RAPparams);
1691 test_and_set_param_2list<Scalar>(paramList, defaultList, "rap: fix zero diagonals replacement", RAPparams);
1692
1693 // if "rap: triple product" has not been set and algorithm is "unsmoothed" switch triple product on
1694 if (!paramList.isParameter("rap: triple product") &&
1695 paramList.isType<std::string>("multigrid algorithm") &&
1696 paramList.get<std::string>("multigrid algorithm") == "unsmoothed")
1697 paramList.set("rap: triple product", true);
1698 else
1699 test_and_set_param_2list<bool>(paramList, defaultList, "rap: triple product", RAPparams);
1700
1701 try {
1702 if (paramList.isParameter("aggregation: allow empty prolongator columns")) {
1703 RAPparams.set("CheckMainDiagonal", paramList.get<bool>("aggregation: allow empty prolongator columns"));
1704 RAPparams.set("RepairMainDiagonal", paramList.get<bool>("aggregation: allow empty prolongator columns"));
1705 } else if (defaultList.isParameter("aggregation: allow empty prolongator columns")) {
1706 RAPparams.set("CheckMainDiagonal", defaultList.get<bool>("aggregation: allow empty prolongator columns"));
1707 RAPparams.set("RepairMainDiagonal", defaultList.get<bool>("aggregation: allow empty prolongator columns"));
1708 }
1709
1710 } catch (Teuchos::Exceptions::InvalidParameterType&) {
1711 TEUCHOS_TEST_FOR_EXCEPTION_PURE_MSG(true, Teuchos::Exceptions::InvalidParameterType,
1712 "Error: parameter \"aggregation: allow empty prolongator columns\" must be of type " << Teuchos::TypeNameTraits<bool>::name());
1713 }
1714
1715 if (!RAP.is_null()) {
1716 RAP->SetParameterList(RAPparams);
1717 RAP->SetFactory("P", manager.GetFactory("P"));
1718 } else {
1719 RAPs->SetParameterList(RAPparams);
1720 RAPs->SetFactory("P", manager.GetFactory("P"));
1721 }
1722
1723 if (!this->implicitTranspose_) {
1724 if (!RAP.is_null())
1725 RAP->SetFactory("R", manager.GetFactory("R"));
1726 else
1727 RAPs->SetFactory("R", manager.GetFactory("R"));
1728 }
1729
1730 // Matrix analysis
1731 if (test_param_2list<bool>(paramList, defaultList, "matrix: compute analysis", true)) {
1732 RCP<Factory> matrixAnalysisFact = rcp(new MatrixAnalysisFactory());
1733
1734 if (!RAP.is_null())
1735 RAP->AddTransferFactory(matrixAnalysisFact);
1736 else
1737 RAPs->AddTransferFactory(matrixAnalysisFact);
1738 }
1739
1740 // Aggregate qualities
1741 if (test_param_2list<bool>(paramList, defaultList, "aggregation: compute aggregate qualities", true)) {
1742 RCP<Factory> aggQualityFact = rcp(new AggregateQualityEstimateFactory());
1743 ParameterList aggQualityParams;
1744 test_and_set_param_2list<double>(paramList, defaultList, "aggregate qualities: good aggregate threshold", aggQualityParams);
1745 test_and_set_param_2list<bool>(paramList, defaultList, "aggregate qualities: file output", aggQualityParams);
1746 test_and_set_param_2list<std::string>(paramList, defaultList, "aggregate qualities: file base", aggQualityParams);
1747 test_and_set_param_2list<bool>(paramList, defaultList, "aggregate qualities: check symmetry", aggQualityParams);
1748 test_and_set_param_2list<std::string>(paramList, defaultList, "aggregate qualities: algorithm", aggQualityParams);
1749 test_and_set_param_2list<double>(paramList, defaultList, "aggregate qualities: zero threshold", aggQualityParams);
1750 test_and_set_param_2list<Teuchos::Array<double>>(paramList, defaultList, "aggregate qualities: percentiles", aggQualityParams);
1751 test_and_set_param_2list<std::string>(paramList, defaultList, "aggregate qualities: mode", aggQualityParams);
1752 aggQualityFact->SetParameterList(aggQualityParams);
1753 aggQualityFact->SetFactory("Aggregates", manager.GetFactory("Aggregates"));
1754 aggQualityFact->SetFactory("CoarseMap", manager.GetFactory("CoarseMap"));
1755 manager.SetFactory("AggregateQualities", aggQualityFact);
1756
1757 if (!RAP.is_null())
1758 RAP->AddTransferFactory(aggQualityFact);
1759 else
1760 RAPs->AddTransferFactory(aggQualityFact);
1761 }
1762
1763 if (test_param_2list<bool>(paramList, defaultList, "aggregation: export visualization data", true)) {
1764 RCP<AggregationExportFactory> aggExport = rcp(new AggregationExportFactory());
1765 ParameterList aggExportParams;
1766 test_and_set_param_2list<std::string>(paramList, defaultList, "aggregation: output filename", aggExportParams);
1767 test_and_set_param_2list<std::string>(paramList, defaultList, "aggregation: output file: agg style", aggExportParams);
1768 test_and_set_param_2list<int>(paramList, defaultList, "aggregation: output file: iter", aggExportParams);
1769 test_and_set_param_2list<int>(paramList, defaultList, "aggregation: output file: time step", aggExportParams);
1770 test_and_set_param_2list<bool>(paramList, defaultList, "aggregation: output file: fine graph edges", aggExportParams);
1771 test_and_set_param_2list<bool>(paramList, defaultList, "aggregation: output file: coarse graph edges", aggExportParams);
1772 test_and_set_param_2list<bool>(paramList, defaultList, "aggregation: output file: build colormap", aggExportParams);
1773 test_and_set_param_2list<bool>(paramList, defaultList, "aggregation: output file: aggregate qualities", aggExportParams);
1774 test_and_set_param_2list<bool>(paramList, defaultList, "aggregation: output file: material", aggExportParams);
1775 aggExport->SetParameterList(aggExportParams);
1776 aggExport->SetFactory("AggregateQualities", manager.GetFactory("AggregateQualities"));
1777 aggExport->SetFactory("DofsPerNode", manager.GetFactory("DofsPerNode"));
1778 aggExport->SetFactory("Aggregates", manager.GetFactory("Aggregates"));
1779 aggExport->SetFactory("Graph", manager.GetFactory("Graph"));
1780
1781 if (!RAP.is_null())
1782 RAP->AddTransferFactory(aggExport);
1783 else
1784 RAPs->AddTransferFactory(aggExport);
1785 }
1786 if (!RAP.is_null())
1787 manager.SetFactory("A", RAP);
1788 else
1789 manager.SetFactory("A", RAPs);
1790
1791 auto reuseType = set_var_2list<std::string>(paramList, defaultList, "reuse: type");
1792 auto useFiltering = set_var_2list<bool>(paramList, defaultList, "sa: use filtered matrix");
1793 bool filteringChangesMatrix = useFiltering && !test_param_2list<double>(paramList, defaultList, "aggregation: drop tol", 0);
1794
1795 if (reuseType == "RP" || (reuseType == "tP" && !filteringChangesMatrix)) {
1796 if (!RAP.is_null()) {
1797 keeps.push_back(keep_pair("AP reuse data", RAP.get()));
1798 keeps.push_back(keep_pair("RAP reuse data", RAP.get()));
1799
1800 } else {
1801 keeps.push_back(keep_pair("AP reuse data", RAPs.get()));
1802 keeps.push_back(keep_pair("RAP reuse data", RAPs.get()));
1803 }
1804 }
1805}
1806
1807// =====================================================================================================
1808// ======================================= Coordinates =================================================
1809// =====================================================================================================
1810template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1812 UpdateFactoryManager_Coordinates(ParameterList& paramList, const ParameterList& /* defaultList */,
1813 FactoryManager& manager, int /* levelID */, std::vector<keep_pair>& /* keeps */) const {
1814 bool have_userCO = false;
1815 if (paramList.isParameter("Coordinates") && !paramList.get<RCP<MultiVector>>("Coordinates").is_null())
1816 have_userCO = true;
1817
1818 if (useCoordinates_) {
1819 if (have_userCO) {
1820 manager.SetFactory("Coordinates", NoFactory::getRCP());
1821
1822 } else {
1823 RCP<Factory> coords = rcp(new CoordinatesTransferFactory());
1824 coords->SetFactory("Aggregates", manager.GetFactory("Aggregates"));
1825 coords->SetFactory("CoarseMap", manager.GetFactory("CoarseMap"));
1826 manager.SetFactory("Coordinates", coords);
1827
1828 auto RAP = rcp_const_cast<RAPFactory>(rcp_dynamic_cast<const RAPFactory>(manager.GetFactory("A")));
1829 if (!RAP.is_null()) {
1830 RAP->AddTransferFactory(manager.GetFactory("Coordinates"));
1831 } else {
1832 auto RAPs = rcp_const_cast<RAPShiftFactory>(rcp_dynamic_cast<const RAPShiftFactory>(manager.GetFactory("A")));
1833 RAPs->AddTransferFactory(manager.GetFactory("Coordinates"));
1834 }
1835 }
1836 }
1837}
1838
1839// ======================================================================================================
1840// ======================================== Material ==================================================
1841// =====================================================================================================
1842template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1844 UpdateFactoryManager_Material(ParameterList& paramList, const ParameterList& /* defaultList */,
1845 FactoryManager& manager, int /* levelID */, std::vector<keep_pair>& /* keeps */) const {
1846 bool have_userMaterial = false;
1847 if (paramList.isParameter("Material") && !paramList.get<RCP<MultiVector>>("Material").is_null())
1848 have_userMaterial = true;
1849
1850 if (useMaterial_) {
1851 if (have_userMaterial) {
1852 manager.SetFactory("Material", NoFactory::getRCP());
1853 } else {
1854 RCP<Factory> materialTransfer = rcp(new MultiVectorTransferFactory());
1855 ParameterList materialTransferParameters;
1856 materialTransferParameters.set("Vector name", "Material");
1857 materialTransferParameters.set("Transfer name", "Aggregates");
1858 materialTransferParameters.set("Normalize", true);
1859 materialTransfer->SetParameterList(materialTransferParameters);
1860 materialTransfer->SetFactory("Transfer factory", manager.GetFactory("Aggregates"));
1861 materialTransfer->SetFactory("CoarseMap", manager.GetFactory("CoarseMap"));
1862 manager.SetFactory("Material", materialTransfer);
1863
1864 auto RAP = rcp_const_cast<RAPFactory>(rcp_dynamic_cast<const RAPFactory>(manager.GetFactory("A")));
1865 if (!RAP.is_null()) {
1866 RAP->AddTransferFactory(manager.GetFactory("Material"));
1867 } else {
1868 auto RAPs = rcp_const_cast<RAPShiftFactory>(rcp_dynamic_cast<const RAPShiftFactory>(manager.GetFactory("A")));
1869 RAPs->AddTransferFactory(manager.GetFactory("Material"));
1870 }
1871 }
1872 }
1873}
1874
1875// =====================================================================================================
1876// ================================= LocalOrdinalTransfer =============================================
1877// =====================================================================================================
1878template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1880 UpdateFactoryManager_LocalOrdinalTransfer(const std::string& VarName, const std::string& multigridAlgo, ParameterList& /*paramList*/, const ParameterList& /* defaultList */,
1881 FactoryManager& manager, int levelID, std::vector<keep_pair>& /* keeps */) const {
1882 // NOTE: You would think this would be levelID > 0, but you'd be wrong, since the FactoryManager is basically
1883 // offset by a level from the things which actually do the work.
1884 if (useBlockNumber_ && (levelID > 0)) {
1885 auto RAP = rcp_const_cast<RAPFactory>(rcp_dynamic_cast<const RAPFactory>(manager.GetFactory("A")));
1886 auto RAPs = rcp_const_cast<RAPShiftFactory>(rcp_dynamic_cast<const RAPShiftFactory>(manager.GetFactory("A")));
1887 if (!RAP.is_null() || !RAPs.is_null()) {
1888 RCP<Factory> fact = rcp(new LocalOrdinalTransferFactory(VarName, multigridAlgo));
1889 if (multigridAlgo == "classical")
1890 fact->SetFactory("P Graph", manager.GetFactory("P Graph"));
1891 else
1892 fact->SetFactory("Aggregates", manager.GetFactory("Aggregates"));
1893 fact->SetFactory("CoarseMap", manager.GetFactory("CoarseMap"));
1894
1895 fact->SetFactory(VarName, this->GetFactoryManager(levelID - 1)->GetFactory(VarName));
1896
1897 manager.SetFactory(VarName, fact);
1898
1899 if (!RAP.is_null())
1900 RAP->AddTransferFactory(manager.GetFactory(VarName));
1901 else
1902 RAPs->AddTransferFactory(manager.GetFactory(VarName));
1903 }
1904 }
1905}
1906
1907// =====================================================================================================
1908// ================================= MatrixTransferFactory ============================================
1909// =====================================================================================================
1910template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1912 UpdateFactoryManager_MatrixTransfer(const std::string& VarName, ParameterList& paramList, const ParameterList& defaultList,
1913 FactoryManager& manager, int levelID, std::vector<keep_pair>& /* keeps */) const {
1914 // NOTE: You would think this would be levelID > 0, but you'd be wrong, since the FactoryManager is basically
1915 // offset by a level from the things which actually do the work.
1916 if (levelID == 0)
1917 manager.SetFactory(VarName, NoFactory::getRCP());
1918 else if (levelID > 0) {
1919 auto Afact = manager.GetFactory("A");
1920 auto RebalAc = rcp_const_cast<RebalanceAcFactory>(rcp_dynamic_cast<const RebalanceAcFactory>(Afact));
1921 RCP<RAPFactory> RAP;
1922 RCP<RAPShiftFactory> RAPs;
1923 if (!RebalAc.is_null()) {
1924 auto Afact2 = RebalAc->GetFactory("A");
1925 RAP = rcp_const_cast<RAPFactory>(rcp_dynamic_cast<const RAPFactory>(Afact2));
1926 RAPs = rcp_const_cast<RAPShiftFactory>(rcp_dynamic_cast<const RAPShiftFactory>(Afact2));
1927 } else {
1928 RAP = rcp_const_cast<RAPFactory>(rcp_dynamic_cast<const RAPFactory>(Afact));
1929 RAPs = rcp_const_cast<RAPShiftFactory>(rcp_dynamic_cast<const RAPShiftFactory>(Afact));
1930 }
1931
1932 if (!RAP.is_null() || !RAPs.is_null()) {
1933 RCP<Factory> mtf = rcp(new MatrixTransferFactory());
1934
1935 ParameterList transferParameters;
1936 transferParameters.set("Matrix name", VarName);
1937 transferParameters.set("transpose: use implicit", this->implicitTranspose_);
1938 mtf->SetParameterList(transferParameters);
1939
1940 if (!RAP.is_null()) {
1941 mtf->SetFactory("P", RAP->GetFactory("P"));
1942 if (!this->implicitTranspose_)
1943 mtf->SetFactory("R", RAP->GetFactory("R"));
1944 RAP->AddTransferFactory(mtf);
1945 } else {
1946 mtf->SetFactory("P", RAPs->GetFactory("P"));
1947 if (!this->implicitTranspose_)
1948 mtf->SetFactory("R", RAPs->GetFactory("R"));
1949 RAPs->AddTransferFactory(mtf);
1950 }
1951
1952 auto enableRepart = set_var_2list<bool>(paramList, defaultList, "repartition: enable");
1953 if (!enableRepart) {
1954 manager.SetFactory(VarName, mtf);
1955 } else {
1956 auto rebalFact = rcp(new RebalanceAcFactory());
1957 Teuchos::ParameterList rebalParams;
1958 rebalParams.set("Matrix name", VarName);
1959 auto useSubCommInPlace = set_var_2list<bool>(paramList, defaultList, "repartition: use subcommunicators in place");
1960 rebalParams.set("repartition: use subcommunicators in place", useSubCommInPlace);
1961 if (useSubCommInPlace) {
1962 auto inPlaceMapFact = manager.GetFactory("InPlaceMap");
1963 rebalFact->SetFactory("InPlaceMap", inPlaceMapFact);
1964 } else {
1965 TEUCHOS_ASSERT(!RebalAc.is_null());
1966 RCP<const FactoryBase> importerFact;
1967 importerFact = RebalAc->GetFactory("Importer");
1968 rebalFact->SetFactory("Importer", importerFact);
1969 RebalAc->AddRebalanceFactory(rebalFact);
1970 }
1971
1972 rebalFact->SetParameterList(rebalParams);
1973 rebalFact->SetFactory("A", mtf);
1974
1975 manager.SetFactory(VarName, rebalFact);
1976 }
1977 }
1978 }
1979}
1980
1981// ======================================================================================================
1982// ====================================== BlockNumber =================================================
1983// =====================================================================================================
1984template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
1986 UpdateFactoryManager_BlockNumber(ParameterList& paramList, const ParameterList& defaultList,
1987 FactoryManager& manager, int /*levelID*/, std::vector<keep_pair>& /*keeps*/) const {
1988 if (useBlockNumber_) {
1989 ParameterList myParams;
1990 RCP<Factory> fact = rcp(new InitialBlockNumberFactory());
1991 test_and_set_param_2list<int>(paramList, defaultList, "aggregation: block diagonal: interleaved blocksize", myParams);
1992 fact->SetParameterList(myParams);
1993 manager.SetFactory("BlockNumber", fact);
1994 }
1995}
1996
1997// =====================================================================================================
1998// =========================================== Restriction =============================================
1999// =====================================================================================================
2000template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2002 UpdateFactoryManager_Restriction(ParameterList& paramList, const ParameterList& defaultList, FactoryManager& manager,
2003 int /*levelID*/, std::vector<keep_pair>& /* keeps */) const {
2004 auto multigridAlgo = set_var_2list<std::string>(paramList, defaultList, "multigrid algorithm");
2005 bool have_userR = false;
2006 if (paramList.isParameter("R") && !paramList.get<RCP<Matrix>>("R").is_null())
2007 have_userR = true;
2008
2009 // === Restriction ===
2010 RCP<Factory> R;
2011 if (!this->implicitTranspose_) {
2012 auto isSymmetric = set_var_2list<bool>(paramList, defaultList, "problem: symmetric");
2013
2014 if (isSymmetric == false && (multigridAlgo == "unsmoothed" || multigridAlgo == "emin")) {
2015 this->GetOStream(Warnings0) << "Switching \"problem: symmetric\" parameter to symmetric as multigrid algorithm. " << multigridAlgo << " is primarily supposed to be used for symmetric problems.\n\n"
2016 << "Please note: if you are using \"unsmoothed\" transfer operators the \"problem: symmetric\" parameter "
2017 << "has no real mathematical meaning, i.e. you can use it for non-symmetric\n"
2018 << "problems, too. With \"problem: symmetric\"=\"symmetric\" you can use implicit transpose for building "
2019 << "the restriction operators which may drastically reduce the amount of consumed memory." << std::endl;
2020 isSymmetric = true;
2021 }
2022 TEUCHOS_TEST_FOR_EXCEPTION(multigridAlgo == "pg" && isSymmetric == true, Exceptions::RuntimeError,
2023 "Petrov-Galerkin smoothed transfer operators are only allowed for non-symmetric problems: Set \"problem: symmetric\" to false!\n"
2024 "While PG smoothed transfer operators generally would also work for symmetric problems this is an unusual use case. "
2025 "You can use the factory-based xml interface though if you need PG-AMG for symmetric problems.");
2026
2027 if (have_userR) {
2028 manager.SetFactory("R", NoFactory::getRCP());
2029 } else {
2030 if (isSymmetric)
2031 R = rcp(new TransPFactory());
2032 else
2033 R = rcp(new GenericRFactory());
2034
2035 R->SetFactory("P", manager.GetFactory("P"));
2036 manager.SetFactory("R", R);
2037 }
2038
2039 } else {
2040 manager.SetFactory("R", Teuchos::null);
2041 }
2042
2043 // === Restriction: Nullspace Scaling ===
2044 if (paramList.isParameter("restriction: scale nullspace") && paramList.get<bool>("restriction: scale nullspace")) {
2045 RCP<TentativePFactory> tentPFactory = rcp(new TentativePFactory());
2046 Teuchos::ParameterList tentPlist;
2047 tentPlist.set("Nullspace name", "Scaled Nullspace");
2048 tentPFactory->SetParameterList(tentPlist);
2049 tentPFactory->SetFactory("Aggregates", manager.GetFactory("Aggregates"));
2050 tentPFactory->SetFactory("CoarseMap", manager.GetFactory("CoarseMap"));
2051
2052 if (R.is_null()) R = rcp(new TransPFactory());
2053 R->SetFactory("P", tentPFactory);
2054 }
2055}
2056
2057// =====================================================================================================
2058// ========================================= Repartition ===============================================
2059// =====================================================================================================
2060template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2062 UpdateFactoryManager_Repartition(ParameterList& paramList, const ParameterList& defaultList, FactoryManager& manager,
2063 int levelID, std::vector<keep_pair>& keeps, RCP<Factory>& nullSpaceFactory) const {
2064 // === Repartitioning ===
2065 auto reuseType = set_var_2list<std::string>(paramList, defaultList, "reuse: type");
2066 auto enableRepart = set_var_2list<bool>(paramList, defaultList, "repartition: enable");
2067 if (enableRepart) {
2068#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
2069 auto enableInPlace = set_var_2list<bool>(paramList, defaultList, "repartition: use subcommunicators in place");
2070 // Short summary of the issue: RebalanceTransferFactory shares ownership
2071 // of "P" with SaPFactory, and therefore, changes the stored version.
2072 // That means that if SaPFactory generated P, and stored it on the level,
2073 // then after rebalancing the value in that storage changed. It goes
2074 // against the concept of factories (I think), that every factory is
2075 // responsible for its own objects, and they are immutable outside.
2076 //
2077 // In reuse, this is what happens: as we reuse Importer across setups,
2078 // the order of factories changes, and coupled with shared ownership
2079 // leads to problems.
2080 // *First setup*
2081 // SaP builds P [and stores it]
2082 // TransP builds R [and stores it]
2083 // RAP builds A [and stores it]
2084 // RebalanceTransfer rebalances P [and changes the P stored by SaP] (*)
2085 // RebalanceTransfer rebalances R
2086 // RebalanceAc rebalances A
2087 // *Second setup* ("RP" reuse)
2088 // RebalanceTransfer rebalances P [which is incorrect due to (*)]
2089 // RebalanceTransfer rebalances R
2090 // RAP builds A [which is incorrect due to (*)]
2091 // RebalanceAc rebalances A [which throws due to map inconsistency]
2092 // ...
2093 // *Second setup* ("tP" reuse)
2094 // SaP builds P [and stores it]
2095 // RebalanceTransfer rebalances P [and changes the P stored by SaP] (**)
2096 // TransP builds R [which is incorrect due to (**)]
2097 // RebalanceTransfer rebalances R
2098 // ...
2099 //
2100 // Couple solutions to this:
2101 // 1. [implemented] Requre "tP" and "PR" reuse to only be used with
2102 // implicit rebalancing.
2103 // 2. Do deep copy of P, and changed domain map and importer there.
2104 // Need to investigate how expensive this is.
2105 TEUCHOS_TEST_FOR_EXCEPTION(this->doPRrebalance_ && (reuseType == "tP" || reuseType == "RP"), Exceptions::InvalidArgument,
2106 "Reuse types \"tP\" and \"PR\" require \"repartition: rebalance P and R\" set to \"false\"");
2107
2108 // TEUCHOS_TEST_FOR_EXCEPTION(aggType == "brick", Exceptions::InvalidArgument,
2109 // "Aggregation type \"brick\" requires \"repartition: enable\" set to \"false\"");
2110
2111 auto partName = set_var_2list<std::string>(paramList, defaultList, "repartition: partitioner");
2112 TEUCHOS_TEST_FOR_EXCEPTION(partName != "zoltan" && partName != "zoltan2", Exceptions::InvalidArgument,
2113 "Invalid partitioner name: \"" << partName << "\". Valid options: \"zoltan\", \"zoltan2\"");
2114
2115#ifndef HAVE_MUELU_ZOLTAN
2116 bool switched = false;
2117 if (partName == "zoltan") {
2118 this->GetOStream(Warnings0) << "Zoltan interface is not available, trying to switch to Zoltan2" << std::endl;
2119 partName = "zoltan2";
2120 switched = true;
2121 }
2122#else
2123#ifndef HAVE_MUELU_ZOLTAN2
2124 bool switched = false;
2125#endif // HAVE_MUELU_ZOLTAN2
2126#endif // HAVE_MUELU_ZOLTAN
2127
2128#ifndef HAVE_MUELU_ZOLTAN2
2129 if (partName == "zoltan2" && !switched) {
2130 this->GetOStream(Warnings0) << "Zoltan2 interface is not available, trying to switch to Zoltan" << std::endl;
2131 partName = "zoltan";
2132 }
2133#endif // HAVE_MUELU_ZOLTAN2
2134
2135 auto nodeRepartitionLevel = set_var_2list<int>(paramList, defaultList, "repartition: node repartition level");
2136
2137 // RepartitionHeuristic
2138 auto repartheurFactory = rcp(new RepartitionHeuristicFactory());
2139 ParameterList repartheurParams;
2140 test_and_set_param_2list<int>(paramList, defaultList, "repartition: node repartition level", repartheurParams);
2141 test_and_set_param_2list<int>(paramList, defaultList, "repartition: start level", repartheurParams);
2142 test_and_set_param_2list<int>(paramList, defaultList, "repartition: min rows per proc", repartheurParams);
2143 test_and_set_param_2list<int>(paramList, defaultList, "repartition: target rows per proc", repartheurParams);
2144 test_and_set_param_2list<int>(paramList, defaultList, "repartition: min rows per thread", repartheurParams);
2145 test_and_set_param_2list<int>(paramList, defaultList, "repartition: target rows per thread", repartheurParams);
2146 test_and_set_param_2list<double>(paramList, defaultList, "repartition: max imbalance", repartheurParams);
2147 test_and_set_param_2list<int>(paramList, defaultList, "repartition: put on single proc", repartheurParams);
2148 repartheurFactory->SetParameterList(repartheurParams);
2149 repartheurFactory->SetFactory("A", manager.GetFactory("A"));
2150 manager.SetFactory("number of partitions", repartheurFactory);
2151 manager.SetFactory("repartition: heuristic target rows per process", repartheurFactory);
2152
2153 // Partitioner
2154 RCP<Factory> partitioner;
2155 if (levelID == nodeRepartitionLevel) {
2156 // partitioner = rcp(new NodePartitionInterface());
2157 partitioner = rcp(new MueLu::NodePartitionInterface<SC, LO, GO, NO>());
2158 ParameterList partParams;
2159 test_and_set_param_2list<int>(paramList, defaultList, "repartition: node id", partParams);
2160 partitioner->SetParameterList(partParams);
2161 partitioner->SetFactory("Node Comm", manager.GetFactory("Node Comm"));
2162 } else if (partName == "zoltan") {
2163#ifdef HAVE_MUELU_ZOLTAN
2164 partitioner = rcp(new ZoltanInterface());
2165 // NOTE: ZoltanInterface ("zoltan") does not support external parameters through ParameterList
2166#else
2167 throw Exceptions::RuntimeError("Zoltan interface is not available");
2168#endif // HAVE_MUELU_ZOLTAN
2169 } else if (partName == "zoltan2") {
2170#ifdef HAVE_MUELU_ZOLTAN2
2171 partitioner = rcp(new Zoltan2Interface());
2172 ParameterList partParams;
2173 RCP<const ParameterList> partpartParams = rcp(new ParameterList(paramList.sublist("repartition: params", false)));
2174 partParams.set("ParameterList", partpartParams);
2175 partitioner->SetParameterList(partParams);
2176 partitioner->SetFactory("repartition: heuristic target rows per process",
2177 manager.GetFactory("repartition: heuristic target rows per process"));
2178#else
2179 throw Exceptions::RuntimeError("Zoltan2 interface is not available");
2180#endif // HAVE_MUELU_ZOLTAN2
2181 }
2182
2183 partitioner->SetFactory("A", manager.GetFactory("A"));
2184 partitioner->SetFactory("number of partitions", manager.GetFactory("number of partitions"));
2185 if (useCoordinates_)
2186 partitioner->SetFactory("Coordinates", manager.GetFactory("Coordinates"));
2187 manager.SetFactory("Partition", partitioner);
2188
2189 // Repartitioner
2190 auto repartFactory = rcp(new RepartitionFactory());
2191 ParameterList repartParams;
2192 test_and_set_param_2list<bool>(paramList, defaultList, "repartition: print partition distribution", repartParams);
2193 test_and_set_param_2list<bool>(paramList, defaultList, "repartition: remap parts", repartParams);
2194 test_and_set_param_2list<int>(paramList, defaultList, "repartition: remap num values", repartParams);
2195 test_and_set_param_2list<bool>(paramList, defaultList, "repartition: save importer", repartParams);
2196 repartFactory->SetParameterList(repartParams);
2197 repartFactory->SetFactory("A", manager.GetFactory("A"));
2198 repartFactory->SetFactory("number of partitions", manager.GetFactory("number of partitions"));
2199 repartFactory->SetFactory("Partition", manager.GetFactory("Partition"));
2200 manager.SetFactory("Importer", repartFactory);
2201 if (reuseType != "none" && reuseType != "S" && levelID)
2202 keeps.push_back(keep_pair("Importer", manager.GetFactory("Importer").get()));
2203
2204 if (enableInPlace) {
2205 // Rebalanced A (in place)
2206 // NOTE: This is for when we want to constrain repartitioning to match some other idea of what's going on.
2207 // The major application is the (1,1) hierarchy in the Maxwell1 preconditioner.
2208 auto newA = rcp(new RebalanceAcFactory());
2209 ParameterList rebAcParams;
2210 test_and_set_param_2list<bool>(paramList, defaultList, "repartition: use subcommunicators", rebAcParams);
2211 test_and_set_param_2list<bool>(paramList, defaultList, "repartition: use subcommunicators in place", rebAcParams);
2212 newA->SetParameterList(rebAcParams);
2213 newA->SetFactory("A", manager.GetFactory("A"));
2214 newA->SetFactory("InPlaceMap", manager.GetFactory("InPlaceMap"));
2215 manager.SetFactory("A", newA);
2216 } else {
2217 // Rebalanced A
2218 auto newA = rcp(new RebalanceAcFactory());
2219 ParameterList rebAcParams;
2220 test_and_set_param_2list<bool>(paramList, defaultList, "repartition: use subcommunicators", rebAcParams);
2221 newA->SetParameterList(rebAcParams);
2222 newA->SetFactory("A", manager.GetFactory("A"));
2223 newA->SetFactory("Importer", manager.GetFactory("Importer"));
2224 manager.SetFactory("A", newA);
2225
2226 // Rebalanced P
2227 auto newP = rcp(new RebalanceTransferFactory());
2228 ParameterList newPparams;
2229 newPparams.set("type", "Interpolation");
2230 if (changedPRrebalance_)
2231 newPparams.set("repartition: rebalance P and R", this->doPRrebalance_);
2232 if (changedPRViaCopyrebalance_)
2233 newPparams.set("repartition: explicit via new copy rebalance P and R", true);
2234 test_and_set_param_2list<bool>(paramList, defaultList, "repartition: use subcommunicators", newPparams);
2235 test_and_set_param_2list<std::string>(paramList, defaultList, "repartition: send type", newPparams);
2236 newP->SetParameterList(newPparams);
2237 newP->SetFactory("Importer", manager.GetFactory("Importer"));
2238 newP->SetFactory("P", manager.GetFactory("P"));
2239 manager.SetFactory("P", newP);
2240 if (!paramList.isParameter("semicoarsen: number of levels"))
2241 newP->SetFactory("Nullspace", manager.GetFactory("Ptent"));
2242 else
2243 newP->SetFactory("Nullspace", manager.GetFactory("P")); // TogglePFactory
2244 if (useCoordinates_) {
2245 newP->SetFactory("Coordinates", manager.GetFactory("Coordinates"));
2246 manager.SetFactory("Coordinates", newP);
2247 }
2248 if (useMaterial_) {
2249 newP->SetFactory("Material", manager.GetFactory("Material"));
2250 manager.SetFactory("Material", newP);
2251 }
2252 if (useBlockNumber_ && (levelID > 0)) {
2253 newP->SetFactory("BlockNumber", manager.GetFactory("BlockNumber"));
2254 manager.SetFactory("BlockNumber", newP);
2255 }
2256
2257 // Rebalanced R
2258 auto newR = rcp(new RebalanceTransferFactory());
2259 ParameterList newRparams;
2260 newRparams.set("type", "Restriction");
2261 test_and_set_param_2list<bool>(paramList, defaultList, "repartition: use subcommunicators", newRparams);
2262 test_and_set_param_2list<std::string>(paramList, defaultList, "repartition: send type", newRparams);
2263 if (changedPRrebalance_)
2264 newRparams.set("repartition: rebalance P and R", this->doPRrebalance_);
2265 if (changedPRViaCopyrebalance_)
2266 newPparams.set("repartition: explicit via new copy rebalance P and R", true);
2267 if (changedImplicitTranspose_)
2268 newRparams.set("transpose: use implicit", this->implicitTranspose_);
2269 newR->SetParameterList(newRparams);
2270 newR->SetFactory("Importer", manager.GetFactory("Importer"));
2271 if (!this->implicitTranspose_) {
2272 newR->SetFactory("R", manager.GetFactory("R"));
2273 manager.SetFactory("R", newR);
2274 }
2275
2276 // NOTE: the role of NullspaceFactory is to provide nullspace on the finest
2277 // level if a user does not do that. For all other levels it simply passes
2278 // nullspace from a real factory to whoever needs it. If we don't use
2279 // repartitioning, that factory is "TentativePFactory"; if we do, it is
2280 // "RebalanceTransferFactory". But we still have to have NullspaceFactory as
2281 // the "Nullspace" of the manager
2282 // NOTE: This really needs to be set on the *NullSpaceFactory*, not manager.get("Nullspace").
2283 ParameterList newNullparams;
2284 test_and_set_param_2list<bool>(paramList, defaultList, "nullspace: calculate rotations", newNullparams);
2285 nullSpaceFactory->SetFactory("Nullspace", newP);
2286 nullSpaceFactory->SetParameterList(newNullparams);
2287 }
2288#else
2289 paramList.set("repartition: enable", false);
2290#ifndef HAVE_MPI
2291 this->GetOStream(Warnings0) << "No repartitioning available for a serial run\n";
2292#else
2293 this->GetOStream(Warnings0) << "Zoltan/Zoltan2 are unavailable for repartitioning\n";
2294#endif // HAVE_MPI
2295#endif // defined(HAVE_MPI) && (defined(HAVE_MUELU_ZOLTAN) || defined(HAVE_MUELU_ZOLTAN2))
2296 }
2297}
2298
2299// =====================================================================================================
2300// ========================================= Low precision transfers ===================================
2301// =====================================================================================================
2302template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2304 UpdateFactoryManager_LowPrecision(ParameterList& paramList, const ParameterList& defaultList, FactoryManager& manager,
2305 int /*levelID*/, std::vector<keep_pair>& /*keeps*/) const {
2306 auto enableLowPrecision = set_var_2list<bool>(paramList, defaultList, "transfers: half precision");
2307
2308 if (enableLowPrecision) {
2309 // Low precision P
2310 auto newP = rcp(new LowPrecisionFactory());
2311 ParameterList newPparams;
2312 newPparams.set("matrix key", "P");
2313 newP->SetParameterList(newPparams);
2314 newP->SetFactory("P", manager.GetFactory("P"));
2315 manager.SetFactory("P", newP);
2316
2317 if (!this->implicitTranspose_) {
2318 // Low precision R
2319 auto newR = rcp(new LowPrecisionFactory());
2320 ParameterList newRparams;
2321 newRparams.set("matrix key", "R");
2322 newR->SetParameterList(newRparams);
2323 newR->SetFactory("R", manager.GetFactory("R"));
2324 manager.SetFactory("R", newR);
2325 }
2326 }
2327}
2328
2329// =====================================================================================================
2330// =========================================== Nullspace ===============================================
2331// =====================================================================================================
2332template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2334 UpdateFactoryManager_Nullspace(ParameterList& paramList, const ParameterList& defaultList, FactoryManager& manager,
2335 int /* levelID */, std::vector<keep_pair>& /* keeps */, RCP<Factory>& nullSpaceFactory) const {
2336 // Nullspace
2337 RCP<Factory> nullSpace = rcp(new NullspaceFactory());
2338
2339 bool have_userNS = false;
2340 if (paramList.isParameter("Nullspace") && !paramList.get<RCP<MultiVector>>("Nullspace").is_null())
2341 have_userNS = true;
2342
2343 if (!have_userNS) {
2344 ParameterList newNullparams;
2345 test_and_set_param_2list<bool>(paramList, defaultList, "nullspace: calculate rotations", newNullparams);
2346 nullSpace->SetParameterList(newNullparams);
2347 nullSpace->SetFactory("Nullspace", manager.GetFactory("Ptent"));
2348 manager.SetFactory("Nullspace", nullSpace);
2349 }
2350 nullSpaceFactory = nullSpace;
2351
2352 if (paramList.isParameter("restriction: scale nullspace") && paramList.get<bool>("restriction: scale nullspace")) {
2353 RCP<ScaledNullspaceFactory> scaledNSfactory = rcp(new ScaledNullspaceFactory());
2354 scaledNSfactory->SetFactory("Nullspace", nullSpaceFactory);
2355 manager.SetFactory("Scaled Nullspace", scaledNSfactory);
2356 }
2357}
2358
2359// =====================================================================================================
2360// ================================= Algorithm: SemiCoarsening =========================================
2361// =====================================================================================================
2362template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2364 UpdateFactoryManager_SemiCoarsen(ParameterList& paramList, const ParameterList& defaultList, FactoryManager& manager,
2365 int /* levelID */, std::vector<keep_pair>& /* keeps */) const {
2366 // === Semi-coarsening ===
2367 RCP<Factory> semicoarsenFactory = Teuchos::null;
2368 if (paramList.isParameter("semicoarsen: number of levels") &&
2369 paramList.get<int>("semicoarsen: number of levels") > 0) {
2370 ParameterList togglePParams;
2371 ParameterList semicoarsenPParams;
2372 ParameterList linedetectionParams;
2373 test_and_set_param_2list<int>(paramList, defaultList, "semicoarsen: number of levels", togglePParams);
2374 test_and_set_param_2list<int>(paramList, defaultList, "semicoarsen: coarsen rate", semicoarsenPParams);
2375 test_and_set_param_2list<bool>(paramList, defaultList, "semicoarsen: piecewise constant", semicoarsenPParams);
2376 test_and_set_param_2list<bool>(paramList, defaultList, "semicoarsen: piecewise linear", semicoarsenPParams);
2377 test_and_set_param_2list<bool>(paramList, defaultList, "semicoarsen: calculate nonsym restriction", semicoarsenPParams);
2378 test_and_set_param_2list<std::string>(paramList, defaultList, "linedetection: orientation", linedetectionParams);
2379 test_and_set_param_2list<int>(paramList, defaultList, "linedetection: num layers", linedetectionParams);
2380
2382 RCP<LineDetectionFactory> linedetectionFactory = rcp(new LineDetectionFactory());
2383 RCP<TogglePFactory> togglePFactory = rcp(new TogglePFactory());
2384
2385 linedetectionFactory->SetParameterList(linedetectionParams);
2386 semicoarsenFactory->SetParameterList(semicoarsenPParams);
2387 togglePFactory->SetParameterList(togglePParams);
2388
2389 togglePFactory->AddCoarseNullspaceFactory(semicoarsenFactory);
2390 togglePFactory->AddProlongatorFactory(semicoarsenFactory);
2391 togglePFactory->AddPtentFactory(semicoarsenFactory);
2392 togglePFactory->AddCoarseNullspaceFactory(manager.GetFactory("Ptent"));
2393 togglePFactory->AddProlongatorFactory(manager.GetFactory("P"));
2394 togglePFactory->AddPtentFactory(manager.GetFactory("Ptent"));
2395
2396 manager.SetFactory("CoarseNumZLayers", linedetectionFactory);
2397 manager.SetFactory("LineDetection_Layers", linedetectionFactory);
2398 manager.SetFactory("LineDetection_VertLineIds", linedetectionFactory);
2399
2400 manager.SetFactory("P", togglePFactory);
2401 manager.SetFactory("Ptent", togglePFactory);
2402 manager.SetFactory("Nullspace", togglePFactory);
2403 }
2404
2405 if (paramList.isParameter("semicoarsen: number of levels") &&
2406 paramList.get<int>("semicoarsen: number of levels") > 0) {
2407 auto tf = rcp(new ToggleCoordinatesTransferFactory());
2408 tf->SetFactory("Chosen P", manager.GetFactory("P"));
2409 tf->AddCoordTransferFactory(semicoarsenFactory);
2410
2411 RCP<Factory> coords = rcp(new CoordinatesTransferFactory());
2412 coords->SetFactory("Aggregates", manager.GetFactory("Aggregates"));
2413 coords->SetFactory("CoarseMap", manager.GetFactory("CoarseMap"));
2414 tf->AddCoordTransferFactory(coords);
2415 manager.SetFactory("Coordinates", tf);
2416 }
2417}
2418
2419// =====================================================================================================
2420// ================================== Algorithm: P-Coarsening ==========================================
2421// =====================================================================================================
2422template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2424 UpdateFactoryManager_PCoarsen(ParameterList& paramList, const ParameterList& defaultList, FactoryManager& manager,
2425 int levelID, std::vector<keep_pair>& keeps) const {
2426#if defined(HAVE_MUELU_INTREPID2) && defined(HAVE_MUELU_EXPERIMENTAL)
2427 // This only makes sense to invoke from the default list.
2428 if (defaultList.isParameter("pcoarsen: schedule") && defaultList.isParameter("pcoarsen: element")) {
2429 // P-Coarsening by schedule (new interface)
2430 // NOTE: levelID represents the *coarse* level in this case
2431 auto pcoarsen_schedule = Teuchos::getArrayFromStringParameter<int>(defaultList, "pcoarsen: schedule");
2432 auto pcoarsen_element = defaultList.get<std::string>("pcoarsen: element");
2433
2434 if (levelID >= (int)pcoarsen_schedule.size()) {
2435 // Past the p-coarsening levels, we do Smoothed Aggregation
2436 // NOTE: We should probably consider allowing other options past p-coarsening
2437 std::string multigridAlgo = "SA";
2438 UpdateFactoryManager_SA(multigridAlgo, paramList, defaultList, manager, levelID, keeps);
2439
2440 } else {
2441 // P-Coarsening
2442 ParameterList Pparams;
2443 auto P = rcp(new IntrepidPCoarsenFactory());
2444 std::string lo = pcoarsen_element + std::to_string(pcoarsen_schedule[levelID]);
2445 std::string hi = (levelID ? pcoarsen_element + std::to_string(pcoarsen_schedule[levelID - 1]) : lo);
2446 Pparams.set("pcoarsen: hi basis", hi);
2447 Pparams.set("pcoarsen: lo basis", lo);
2448 P->SetParameterList(Pparams);
2449 manager.SetFactory("P", P);
2450
2451 // Add special nullspace handling
2452 rcp_dynamic_cast<Factory>(manager.GetFactoryNonConst("Nullspace"))->SetFactory("Nullspace", manager.GetFactory("P"));
2453 }
2454
2455 } else {
2456 // P-Coarsening by manual specification (old interface)
2457 ParameterList Pparams;
2458 auto P = rcp(new IntrepidPCoarsenFactory());
2459 test_and_set_param_2list<std::string>(paramList, defaultList, "pcoarsen: hi basis", Pparams);
2460 test_and_set_param_2list<std::string>(paramList, defaultList, "pcoarsen: lo basis", Pparams);
2461 P->SetParameterList(Pparams);
2462 manager.SetFactory("P", P);
2463
2464 // Add special nullspace handling
2465 rcp_dynamic_cast<Factory>(manager.GetFactoryNonConst("Nullspace"))->SetFactory("Nullspace", manager.GetFactory("P"));
2466 }
2467
2468#endif
2469}
2470
2471// =====================================================================================================
2472// ============================== Algorithm: Smoothed Aggregation ======================================
2473// =====================================================================================================
2474template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2476 UpdateFactoryManager_SA(std::string& multigridAlgo, ParameterList& paramList, const ParameterList& defaultList, FactoryManager& manager, int levelID, std::vector<keep_pair>& keeps) const {
2477 // Smoothed aggregation
2478 RCP<Factory> P = rcp(new SaPFactory());
2479 ParameterList Pparams;
2480 if (paramList.isSublist("matrixmatrix: kernel params"))
2481 Pparams.sublist("matrixmatrix: kernel params", false) = paramList.sublist("matrixmatrix: kernel params");
2482 if (defaultList.isSublist("matrixmatrix: kernel params"))
2483 Pparams.sublist("matrixmatrix: kernel params", false) = defaultList.sublist("matrixmatrix: kernel params");
2484 test_and_set_param_2list<double>(paramList, defaultList, "sa: damping factor", Pparams);
2485 test_and_set_param_2list<double>(paramList, defaultList, "sa: nodal damping factor", Pparams);
2486 test_and_set_param_2list<bool>(paramList, defaultList, "sa: calculate eigenvalue estimate", Pparams);
2487 test_and_set_param_2list<double>(paramList, defaultList, "sa: max eigenvalue", Pparams);
2488 test_and_set_param_2list<int>(paramList, defaultList, "sa: eigenvalue estimate num iterations", Pparams);
2489 test_and_set_param_2list<double>(paramList, defaultList, "sa: diagonal replacement tolerance", Pparams);
2490 test_and_set_param_2list<bool>(paramList, defaultList, "sa: use rowsumabs diagonal scaling", Pparams);
2491 test_and_set_param_2list<double>(paramList, defaultList, "sa: rowsumabs diagonal replacement tolerance", Pparams);
2492 test_and_set_param_2list<double>(paramList, defaultList, "sa: rowsumabs diagonal replacement value", Pparams);
2493 test_and_set_param_2list<bool>(paramList, defaultList, "sa: rowsumabs use automatic diagonal tolerance", Pparams);
2494 test_and_set_param_2list<bool>(paramList, defaultList, "sa: enforce constraints", Pparams);
2495 // test_and_set_param_2list<std::string>(paramList, defaultList, "sa: eigen-analysis type", Pparams);
2496 test_and_set_param_2list<bool>(paramList, defaultList, "tentative: calculate qr", Pparams);
2497
2498 if ((multigridAlgo == "smoothed reitzinger") && (levelID > 0)) {
2499 Pparams.set("sa: maxwell1 smoothing", true);
2500 if (!Pparams.isType<double>("sa: damping factor") || (Pparams.get<double>("sa: damping factor") != 0.0))
2501 P->SetFactory("CurlCurl", this->GetFactoryManager(levelID - 1)->GetFactory("CurlCurl"));
2502 }
2503
2504 P->SetParameterList(Pparams);
2505
2506 // Filtering
2507 auto useFiltering = set_var_2list<bool>(paramList, defaultList, "sa: use filtered matrix");
2508 if (useFiltering) {
2509 // NOTE: Here, non-Kokkos and Kokkos versions diverge in the way the
2510 // dependency tree is setup. The Kokkos version has merged the the
2511 // FilteredAFactory into the CoalesceDropFactory.
2512 if (!useKokkos_) {
2513 RCP<Factory> filterFactory = rcp(new FilteredAFactory());
2514
2515 ParameterList fParams;
2516 test_and_set_param_2list<bool>(paramList, defaultList, "filtered matrix: use lumping", fParams);
2517 test_and_set_param_2list<bool>(paramList, defaultList, "filtered matrix: reuse graph", fParams);
2518 test_and_set_param_2list<bool>(paramList, defaultList, "filtered matrix: reuse eigenvalue", fParams);
2519 test_and_set_param_2list<bool>(paramList, defaultList, "filtered matrix: use root stencil", fParams);
2520 test_and_set_param_2list<double>(paramList, defaultList, "filtered matrix: Dirichlet threshold", fParams);
2521 test_and_set_param_2list<bool>(paramList, defaultList, "filtered matrix: use spread lumping", fParams);
2522 // test_and_set_param_2list<std::string>(paramList, defaultList, "filtered matrix: lumping choice", fParams);
2523 test_and_set_param_2list<double>(paramList, defaultList, "filtered matrix: spread lumping diag dom growth factor", fParams);
2524 test_and_set_param_2list<double>(paramList, defaultList, "filtered matrix: spread lumping diag dom cap", fParams);
2525 test_and_set_param_2list<bool>(paramList, defaultList, "filtered matrix: count negative diagonals", fParams);
2526 filterFactory->SetParameterList(fParams);
2527 filterFactory->SetFactory("Graph", manager.GetFactory("Graph"));
2528 filterFactory->SetFactory("Aggregates", manager.GetFactory("Aggregates"));
2529 filterFactory->SetFactory("UnAmalgamationInfo", manager.GetFactory("UnAmalgamationInfo"));
2530 // I'm not sure why we need this line. See comments for DofsPerNode for UncoupledAggregation above
2531 filterFactory->SetFactory("Filtering", manager.GetFactory("Graph"));
2532
2533 P->SetFactory("A", filterFactory);
2534
2535 } else {
2536 P->SetFactory("A", manager.GetFactory("Graph"));
2537 }
2538 }
2539
2540 P->SetFactory("P", manager.GetFactory("Ptent"));
2541 manager.SetFactory("P", P);
2542
2543 bool filteringChangesMatrix = useFiltering && !test_param_2list<double>(paramList, defaultList, "aggregation: drop tol", 0);
2544 auto reuseType = set_var_2list<std::string>(paramList, defaultList, "reuse: type");
2545 if (reuseType == "tP" && !filteringChangesMatrix)
2546 keeps.push_back(keep_pair("AP reuse data", P.get()));
2547}
2548
2549// =====================================================================================================
2550// =============================== Algorithm: Energy Minimization ======================================
2551// =====================================================================================================
2552template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2554 UpdateFactoryManager_Emin(ParameterList& paramList, const ParameterList& defaultList, FactoryManager& manager,
2555 int /* levelID */, std::vector<keep_pair>& /* keeps */) const {
2556 auto patternType = set_var_2list<std::string>(paramList, defaultList, "emin: pattern");
2557 auto reuseType = set_var_2list<std::string>(paramList, defaultList, "reuse: type");
2558 TEUCHOS_TEST_FOR_EXCEPTION(patternType != "AkPtent", Exceptions::InvalidArgument,
2559 "Invalid pattern name: \"" << patternType << "\". Valid options: \"AkPtent\"");
2560 // Pattern
2561 auto patternFactory = rcp(new PatternFactory());
2562 ParameterList patternParams;
2563 test_and_set_param_2list<int>(paramList, defaultList, "emin: pattern order", patternParams);
2564 patternFactory->SetParameterList(patternParams);
2565 patternFactory->SetFactory("P", manager.GetFactory("Ptent"));
2566
2567 // Filtering
2568 auto useFiltering = set_var_2list<bool>(paramList, defaultList, "emin: use filtered matrix");
2569 if (useFiltering) {
2570 // NOTE: Here, non-Kokkos and Kokkos versions diverge in the way the
2571 // dependency tree is setup. The Kokkos version has merged the the
2572 // FilteredAFactory into the CoalesceDropFactory.
2573 if (!useKokkos_) {
2574 RCP<Factory> filterFactory = rcp(new FilteredAFactory());
2575
2576 ParameterList fParams;
2577 test_and_set_param_2list<bool>(paramList, defaultList, "filtered matrix: use lumping", fParams);
2578 test_and_set_param_2list<bool>(paramList, defaultList, "filtered matrix: reuse graph", fParams);
2579 test_and_set_param_2list<bool>(paramList, defaultList, "filtered matrix: reuse eigenvalue", fParams);
2580 test_and_set_param_2list<bool>(paramList, defaultList, "filtered matrix: use root stencil", fParams);
2581 test_and_set_param_2list<double>(paramList, defaultList, "filtered matrix: Dirichlet threshold", fParams);
2582 test_and_set_param_2list<bool>(paramList, defaultList, "filtered matrix: use spread lumping", fParams);
2583 test_and_set_param_2list<std::string>(paramList, defaultList, "filtered matrix: lumping choice", fParams);
2584 test_and_set_param_2list<double>(paramList, defaultList, "filtered matrix: spread lumping diag dom growth factor", fParams);
2585 test_and_set_param_2list<double>(paramList, defaultList, "filtered matrix: spread lumping diag dom cap", fParams);
2586 filterFactory->SetParameterList(fParams);
2587 filterFactory->SetFactory("Graph", manager.GetFactory("Graph"));
2588 filterFactory->SetFactory("Aggregates", manager.GetFactory("Aggregates"));
2589 filterFactory->SetFactory("UnAmalgamationInfo", manager.GetFactory("UnAmalgamationInfo"));
2590 // I'm not sure why we need this line. See comments for DofsPerNode for UncoupledAggregation above
2591 filterFactory->SetFactory("Filtering", manager.GetFactory("Graph"));
2592
2593 patternFactory->SetFactory("A", filterFactory);
2594
2595 } else {
2596 patternFactory->SetFactory("A", manager.GetFactory("Graph"));
2597 }
2598 }
2599
2600 manager.SetFactory("Ppattern", patternFactory);
2601
2602 // Constraint
2603 auto constraintFactory = rcp(new ConstraintFactory());
2604 Teuchos::ParameterList constraintParams;
2605 test_and_set_param_2list<std::string>(paramList, defaultList, "emin: least squares solver type", constraintParams);
2606 constraintParams.set("emin: constraint type", "nullspace");
2607 constraintFactory->SetFactory("Ppattern", manager.GetFactory("Ppattern"));
2608 constraintFactory->SetFactory("CoarseNullspace", manager.GetFactory("Ptent"));
2609 manager.SetFactory("Constraint", constraintFactory);
2610
2611 // Energy minimization
2612 ParameterList Pparams;
2613 test_and_set_param_2list<int>(paramList, defaultList, "emin: num iterations", Pparams);
2614 test_and_set_param_2list<std::string>(paramList, defaultList, "emin: iterative method", Pparams);
2615 if (reuseType == "emin") {
2616 test_and_set_param_2list<int>(paramList, defaultList, "emin: num reuse iterations", Pparams);
2617 Pparams.set("Keep P0", true);
2618 Pparams.set("Keep Constraint0", true);
2619 }
2620
2621 // Emin Factory
2622 auto P = rcp(new EminPFactory());
2623 P->SetParameterList(Pparams);
2624 P->SetFactory("P", manager.GetFactory("Ptent"));
2625 P->SetFactory("Constraint", manager.GetFactory("Constraint"));
2626 manager.SetFactory("P", P);
2627}
2628
2629// =====================================================================================================
2630// ================================= Algorithm: Petrov-Galerkin ========================================
2631// =====================================================================================================
2632template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2634 UpdateFactoryManager_PG(ParameterList& /* paramList */, const ParameterList& /* defaultList */, FactoryManager& manager,
2635 int /* levelID */, std::vector<keep_pair>& /* keeps */) const {
2636 TEUCHOS_TEST_FOR_EXCEPTION(this->implicitTranspose_, Exceptions::RuntimeError,
2637 "Implicit transpose not supported with Petrov-Galerkin smoothed transfer operators: Set \"transpose: use implicit\" to false!\n"
2638 "Petrov-Galerkin transfer operator smoothing for non-symmetric problems requires a separate handling of the restriction operator which "
2639 "does not allow the usage of implicit transpose easily.");
2640
2641 // Petrov-Galerkin
2642 auto P = rcp(new PgPFactory());
2643 P->SetFactory("P", manager.GetFactory("Ptent"));
2644 manager.SetFactory("P", P);
2645}
2646
2647// =====================================================================================================
2648// ================================= Algorithm: Replicate ========================================
2649// =====================================================================================================
2650template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2652 UpdateFactoryManager_Replicate(ParameterList& paramList, const ParameterList& defaultList, FactoryManager& manager, int /* levelID */, std::vector<keep_pair>& /*keeps*/) const {
2654
2655 ParameterList Pparams;
2656 test_and_set_param_2list<int>(paramList, defaultList, "replicate: npdes", Pparams);
2657
2658 P->SetParameterList(Pparams);
2659 manager.SetFactory("P", P);
2660}
2661
2662// =====================================================================================================
2663// ====================================== Algorithm: Combine ============================================
2664// =====================================================================================================
2665template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2667 UpdateFactoryManager_Combine(ParameterList& paramList, const ParameterList& defaultList, FactoryManager& manager, int /* levelID */, std::vector<keep_pair>& /*keeps*/) const {
2669
2670 ParameterList Pparams;
2671 test_and_set_param_2list<int>(paramList, defaultList, "combine: numBlks", Pparams);
2672 test_and_set_param_2list<bool>(paramList, defaultList, "combine: useMaxLevels", Pparams);
2673
2674 P->SetParameterList(Pparams);
2675 manager.SetFactory("P", P);
2676}
2677
2678// =====================================================================================================
2679// ====================================== Algorithm: Matlab ============================================
2680// =====================================================================================================
2681template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2683 UpdateFactoryManager_Matlab(ParameterList& paramList, const ParameterList& /* defaultList */, FactoryManager& manager,
2684 int /* levelID */, std::vector<keep_pair>& /* keeps */) const {
2685#ifdef HAVE_MUELU_MATLAB
2686 ParameterList Pparams = paramList.sublist("transfer: params");
2687 auto P = rcp(new TwoLevelMatlabFactory());
2688 P->SetParameterList(Pparams);
2689 P->SetFactory("P", manager.GetFactory("Ptent"));
2690 manager.SetFactory("P", P);
2691#else
2692 (void)paramList;
2693 (void)manager;
2694#endif
2695}
2696
2697#undef MUELU_KOKKOS_FACTORY
2698
2699size_t LevenshteinDistance(const char* s, size_t len_s, const char* t, size_t len_t);
2700
2701template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2703 ParameterList paramList = constParamList;
2704 const ParameterList& validList = *MasterList::List();
2705 // Validate up to maxLevels level specific parameter sublists
2706 const int maxLevels = 100;
2707
2708 // Extract level specific list
2709 std::vector<ParameterList> paramLists;
2710 for (int levelID = 0; levelID < maxLevels; levelID++) {
2711 std::string sublistName = "level " + toString(levelID);
2712 if (paramList.isSublist(sublistName)) {
2713 paramLists.push_back(paramList.sublist(sublistName));
2714 // paramLists.back().setName(sublistName);
2715 paramList.remove(sublistName);
2716 }
2717 }
2718 paramLists.push_back(paramList);
2719 // paramLists.back().setName("main");
2720#ifdef HAVE_MUELU_MATLAB
2721 // If Muemex is supported, hide custom level variables from validator by removing them from paramList's sublists
2722 for (size_t i = 0; i < paramLists.size(); i++) {
2723 std::vector<std::string> customVars; // list of names (keys) to be removed from list
2724
2725 for (Teuchos::ParameterList::ConstIterator it = paramLists[i].begin(); it != paramLists[i].end(); it++) {
2726 std::string paramName = paramLists[i].name(it);
2727
2728 if (IsParamMuemexVariable(paramName))
2729 customVars.push_back(paramName);
2730 }
2731
2732 // Remove the keys
2733 for (size_t j = 0; j < customVars.size(); j++)
2734 paramLists[i].remove(customVars[j], false);
2735 }
2736#endif
2737
2738 const int maxDepth = 0;
2739 for (size_t i = 0; i < paramLists.size(); i++) {
2740 // validate every sublist
2741 try {
2742 paramLists[i].validateParameters(validList, maxDepth);
2743
2744 } catch (const Teuchos::Exceptions::InvalidParameterName& e) {
2745 std::string eString = e.what();
2746
2747 // Parse name from: <Error, the parameter {name="smoothe: type",...>
2748 size_t nameStart = eString.find_first_of('"') + 1;
2749 size_t nameEnd = eString.find_first_of('"', nameStart);
2750 std::string name = eString.substr(nameStart, nameEnd - nameStart);
2751
2752 size_t bestScore = 100;
2753 std::string bestName = "";
2754 for (ParameterList::ConstIterator it = validList.begin(); it != validList.end(); it++) {
2755 const std::string& pName = validList.name(it);
2756 this->GetOStream(Runtime1) << "| " << pName;
2757 size_t score = LevenshteinDistance(name.c_str(), name.length(), pName.c_str(), pName.length());
2758 this->GetOStream(Runtime1) << " -> " << score << std::endl;
2759 if (score < bestScore) {
2760 bestScore = score;
2761 bestName = pName;
2762 }
2763 }
2764 if (bestScore < 10 && bestName != "") {
2765 TEUCHOS_TEST_FOR_EXCEPTION(true, Teuchos::Exceptions::InvalidParameterName,
2766 eString << "The parameter name \"" + name + "\" is not valid. Did you mean \"" + bestName << "\"?\n");
2767
2768 } else {
2769 TEUCHOS_TEST_FOR_EXCEPTION(true, Teuchos::Exceptions::InvalidParameterName,
2770 eString << "The parameter name \"" + name + "\" is not valid.\n");
2771 }
2772 }
2773 }
2774}
2775
2776// =====================================================================================================
2777// ==================================== FACTORY interpreter ============================================
2778// =====================================================================================================
2779template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
2781 SetFactoryParameterList(const ParameterList& constParamList) {
2782 // Create a non const copy of the parameter list
2783 // Working with a modifiable list is much much easier than with original one
2784 ParameterList paramList = constParamList;
2785
2786 // Parameter List Parsing:
2787 // ---------
2788 // <ParameterList name="MueLu">
2789 // <ParameterList name="Matrix">
2790 // </ParameterList>
2791 if (paramList.isSublist("Matrix")) {
2792 blockSize_ = paramList.sublist("Matrix").get<int>("PDE equations", MasterList::getDefault<int>("number of equations"));
2793 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)
2794 }
2795
2796 // create new FactoryFactory object if necessary
2797 if (factFact_ == Teuchos::null)
2798 factFact_ = Teuchos::rcp(new FactoryFactory());
2799
2800 // Parameter List Parsing:
2801 // ---------
2802 // <ParameterList name="MueLu">
2803 // <ParameterList name="Factories"> <== call BuildFactoryMap() on this parameter list
2804 // ...
2805 // </ParameterList>
2806 // </ParameterList>
2807 FactoryMap factoryMap;
2808 FactoryManagerMap factoryManagers;
2809 if (paramList.isSublist("Factories"))
2810 this->BuildFactoryMap(paramList.sublist("Factories"), factoryMap, factoryMap, factoryManagers);
2811
2812 // Parameter List Parsing:
2813 // ---------
2814 // <ParameterList name="MueLu">
2815 // <ParameterList name="Hierarchy">
2816 // <Parameter name="verbose" type="string" value="Warnings"/> <== get
2817 // <Parameter name="numDesiredLevel" type="int" value="10"/> <== get
2818 //
2819 // <ParameterList name="firstLevel"> <== parse first args and call BuildFactoryMap() on the rest of this parameter list
2820 // ...
2821 // </ParameterList>
2822 // </ParameterList>
2823 // </ParameterList>
2824 if (paramList.isSublist("Hierarchy")) {
2825 ParameterList hieraList = paramList.sublist("Hierarchy"); // copy because list temporally modified (remove 'id')
2826
2827 // Get hierarchy options
2828 if (hieraList.isParameter("max levels")) {
2829 this->numDesiredLevel_ = hieraList.get<int>("max levels");
2830 hieraList.remove("max levels");
2831 }
2832
2833 if (hieraList.isParameter("coarse: max size")) {
2834 this->maxCoarseSize_ = hieraList.get<int>("coarse: max size");
2835 hieraList.remove("coarse: max size");
2836 }
2837
2838 if (hieraList.isParameter("repartition: rebalance P and R")) {
2839 this->doPRrebalance_ = hieraList.get<bool>("repartition: rebalance P and R");
2840 hieraList.remove("repartition: rebalance P and R");
2841 }
2842
2843 if (hieraList.isParameter("transpose: use implicit")) {
2844 this->implicitTranspose_ = hieraList.get<bool>("transpose: use implicit");
2845 hieraList.remove("transpose: use implicit");
2846 }
2847
2848 if (hieraList.isParameter("fuse prolongation and update")) {
2849 this->fuseProlongationAndUpdate_ = hieraList.get<bool>("fuse prolongation and update");
2850 hieraList.remove("fuse prolongation and update");
2851 }
2852
2853 if (hieraList.isParameter("nullspace: suppress dimension check")) {
2854 this->suppressNullspaceDimensionCheck_ = hieraList.get<bool>("nullspace: suppress dimension check");
2855 hieraList.remove("nullspace: suppress dimension check");
2856 }
2857
2858 if (hieraList.isParameter("number of vectors")) {
2859 this->sizeOfMultiVectors_ = hieraList.get<int>("number of vectors");
2860 hieraList.remove("number of vectors");
2861 }
2862
2863 if (hieraList.isSublist("matvec params"))
2864 this->matvecParams_ = Teuchos::parameterList(hieraList.sublist("matvec params"));
2865
2866 if (hieraList.isParameter("coarse grid correction scaling factor")) {
2867 this->scalingFactor_ = hieraList.get<double>("coarse grid correction scaling factor");
2868 hieraList.remove("coarse grid correction scaling factor");
2869 }
2870
2871 // Translate cycle type parameter
2872 if (hieraList.isParameter("cycle type")) {
2873 std::map<std::string, CycleType> cycleMap;
2874 cycleMap["V"] = VCYCLE;
2875 cycleMap["W"] = WCYCLE;
2876
2877 std::string cycleType = hieraList.get<std::string>("cycle type");
2878 TEUCHOS_TEST_FOR_EXCEPTION(cycleMap.count(cycleType) == 0, Exceptions::RuntimeError, "Invalid cycle type: \"" << cycleType << "\"");
2879 this->Cycle_ = cycleMap[cycleType];
2880 }
2881
2882 if (hieraList.isParameter("W cycle start level")) {
2883 this->WCycleStartLevel_ = hieraList.get<int>("W cycle start level");
2884 }
2885
2886 if (hieraList.isParameter("hierarchy label")) {
2887 this->hierarchyLabel_ = hieraList.get<std::string>("hierarchy label");
2888 }
2889
2890 if (hieraList.isParameter("verbosity")) {
2891 std::string vl = hieraList.get<std::string>("verbosity");
2892 hieraList.remove("verbosity");
2893 this->verbosity_ = toVerbLevel(vl);
2894 }
2895
2896 if (hieraList.isParameter("output filename"))
2897 VerboseObject::SetMueLuOFileStream(hieraList.get<std::string>("output filename"));
2898
2899 if (hieraList.isParameter("dependencyOutputLevel"))
2900 this->graphOutputLevel_ = hieraList.get<int>("dependencyOutputLevel");
2901
2902 // Check for the reuse case
2903 if (hieraList.isParameter("reuse"))
2905
2906 if (hieraList.isSublist("DataToWrite")) {
2907 // TODO We should be able to specify any data. If it exists, write it.
2908 // TODO This would requires something like std::set<dataName, Array<int> >
2909 ParameterList foo = hieraList.sublist("DataToWrite");
2910 std::string dataName = "Matrices";
2911 if (foo.isParameter(dataName))
2912 this->matricesToPrint_["A"] = Teuchos::getArrayFromStringParameter<int>(foo, dataName);
2913 dataName = "Prolongators";
2914 if (foo.isParameter(dataName))
2915 this->matricesToPrint_["P"] = Teuchos::getArrayFromStringParameter<int>(foo, dataName);
2916 dataName = "Restrictors";
2917 if (foo.isParameter(dataName))
2918 this->matricesToPrint_["R"] = Teuchos::getArrayFromStringParameter<int>(foo, dataName);
2919 dataName = "D0";
2920 if (foo.isParameter(dataName))
2921 this->matricesToPrint_["D0"] = Teuchos::getArrayFromStringParameter<int>(foo, dataName);
2922 }
2923
2924 // Get level configuration
2925 for (ParameterList::ConstIterator param = hieraList.begin(); param != hieraList.end(); ++param) {
2926 const std::string& paramName = hieraList.name(param);
2927
2928 if (paramName != "DataToWrite" && hieraList.isSublist(paramName)) {
2929 ParameterList levelList = hieraList.sublist(paramName); // copy because list temporally modified (remove 'id')
2930
2931 int startLevel = 0;
2932 if (levelList.isParameter("startLevel")) {
2933 startLevel = levelList.get<int>("startLevel");
2934 levelList.remove("startLevel");
2935 }
2936 int numDesiredLevel = 1;
2937 if (levelList.isParameter("numDesiredLevel")) {
2938 numDesiredLevel = levelList.get<int>("numDesiredLevel");
2939 levelList.remove("numDesiredLevel");
2940 }
2941
2942 // Parameter List Parsing:
2943 // ---------
2944 // <ParameterList name="firstLevel">
2945 // <Parameter name="startLevel" type="int" value="0"/>
2946 // <Parameter name="numDesiredLevel" type="int" value="1"/>
2947 // <Parameter name="verbose" type="string" value="Warnings"/>
2948 //
2949 // [] <== call BuildFactoryMap() on the rest of the parameter list
2950 //
2951 // </ParameterList>
2952 FactoryMap levelFactoryMap;
2953 BuildFactoryMap(levelList, factoryMap, levelFactoryMap, factoryManagers);
2954
2955 RCP<FactoryManager> m = rcp(new FactoryManager(levelFactoryMap));
2956 if (hieraList.isParameter("use kokkos refactor"))
2957 m->SetKokkosRefactor(hieraList.get<bool>("use kokkos refactor"));
2958
2959 if (startLevel >= 0)
2960 this->AddFactoryManager(startLevel, numDesiredLevel, m);
2961 else
2962 TEUCHOS_TEST_FOR_EXCEPTION(true, Exceptions::RuntimeError, "MueLu::ParameterListInterpreter():: invalid level id");
2963 } /* TODO: else { } */
2964 }
2965 }
2966}
2967
2968// TODO: static?
3002
3054
3091template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
3093 BuildFactoryMap(const ParameterList& paramList, const FactoryMap& factoryMapIn, FactoryMap& factoryMapOut, FactoryManagerMap& factoryManagers) const {
3094 for (ParameterList::ConstIterator param = paramList.begin(); param != paramList.end(); ++param) {
3095 const std::string& paramName = paramList.name(param); //< paramName contains the user chosen factory name (e.g., "smootherFact1")
3096 const Teuchos::ParameterEntry& paramValue = paramList.entry(param); //< for factories, paramValue should be either a list or just a MueLu Factory (e.g., TrilinosSmoother)
3097
3098 // TODO: do not allow name of existing MueLu classes (can be tested using FactoryFactory)
3099
3100 if (paramValue.isList()) {
3101 ParameterList paramList1 = Teuchos::getValue<ParameterList>(paramValue);
3102 if (paramList1.isParameter("factory")) { // default: just a factory definition
3103 // New Factory is a sublist with internal parameters and/or data dependencies
3104 TEUCHOS_TEST_FOR_EXCEPTION(paramList1.isParameter("dependency for") == true, Exceptions::RuntimeError,
3105 "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.");
3106
3107 factoryMapOut[paramName] = factFact_->BuildFactory(paramValue, factoryMapIn, factoryManagers);
3108
3109 } else if (paramList1.isParameter("dependency for")) { // add more data dependencies to existing factory
3110 TEUCHOS_TEST_FOR_EXCEPTION(paramList1.isParameter("factory") == true, Exceptions::RuntimeError,
3111 "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.");
3112
3113 std::string factoryName = paramList1.get<std::string>("dependency for");
3114
3115 RCP<const FactoryBase> factbase = factoryMapIn.find(factoryName /*paramName*/)->second; // access previously defined factory
3116 TEUCHOS_TEST_FOR_EXCEPTION(factbase.is_null() == true, Exceptions::RuntimeError,
3117 "MueLu::ParameterListInterpreter(): could not find factory " + factoryName + " in factory map. Did you define it before?");
3118
3119 RCP<const Factory> factoryconst = Teuchos::rcp_dynamic_cast<const Factory>(factbase);
3120 RCP<Factory> factory = Teuchos::rcp_const_cast<Factory>(factoryconst);
3121
3122 // Read the RCP<Factory> parameters of the class T
3123 RCP<const ParameterList> validParamList = factory->GetValidParameterList();
3124 for (ParameterList::ConstIterator vparam = validParamList->begin(); vparam != validParamList->end(); ++vparam) {
3125 const std::string& pName = validParamList->name(vparam);
3126
3127 if (!paramList1.isParameter(pName)) {
3128 // Ignore unknown parameters
3129 continue;
3130 }
3131
3132 if (validParamList->isType<RCP<const FactoryBase>>(pName)) {
3133 // Generate or get factory described by pName and set dependency
3134 RCP<const FactoryBase> generatingFact = factFact_->BuildFactory(paramList1.getEntry(pName), factoryMapIn, factoryManagers);
3135 factory->SetFactory(pName, generatingFact.create_weak());
3136
3137 } else if (validParamList->isType<RCP<const ParameterList>>(pName)) {
3138 if (pName == "ParameterList") {
3139 // NOTE: we cannot use
3140 // subList = sublist(rcpFromRef(paramList), pName)
3141 // here as that would result in sublist also being a reference to a temporary object.
3142 // The resulting dereferencing in the corresponding factory would then segfault
3143 RCP<const ParameterList> subList = Teuchos::sublist(rcp(new ParameterList(paramList1)), pName);
3144 factory->SetParameter(pName, ParameterEntry(subList));
3145 }
3146 } else {
3147 factory->SetParameter(pName, paramList1.getEntry(pName));
3148 }
3149 }
3150
3151 } else if (paramList1.isParameter("group")) { // definitiion of a factory group (for a factory manager)
3152 // Define a new (sub) FactoryManager
3153 std::string groupType = paramList1.get<std::string>("group");
3154 TEUCHOS_TEST_FOR_EXCEPTION(groupType != "FactoryManager", Exceptions::RuntimeError,
3155 "group must be of type \"FactoryManager\".");
3156
3157 ParameterList groupList = paramList1; // copy because list temporally modified (remove 'id')
3158 groupList.remove("group");
3159
3160 bool setKokkosRefactor = false;
3161 bool kokkosRefactor = useKokkos_;
3162 if (groupList.isParameter("use kokkos refactor")) {
3163 kokkosRefactor = groupList.get<bool>("use kokkos refactor");
3164 groupList.remove("use kokkos refactor");
3165 setKokkosRefactor = true;
3166 }
3167
3168 FactoryMap groupFactoryMap;
3169 BuildFactoryMap(groupList, factoryMapIn, groupFactoryMap, factoryManagers);
3170
3171 // do not store groupFactoryMap in factoryMapOut
3172 // Create a factory manager object from groupFactoryMap
3173 RCP<FactoryManager> m = rcp(new FactoryManager(groupFactoryMap));
3174 if (setKokkosRefactor)
3175 m->SetKokkosRefactor(kokkosRefactor);
3176 factoryManagers[paramName] = m;
3177
3178 } else {
3179 this->GetOStream(Warnings0) << "Could not interpret parameter list " << paramList1 << std::endl;
3180 TEUCHOS_TEST_FOR_EXCEPTION(false, Exceptions::RuntimeError,
3181 "XML Parameter list must either be of type \"factory\" or of type \"group\".");
3182 }
3183 } else {
3184 // default: just a factory (no parameter list)
3185 factoryMapOut[paramName] = factFact_->BuildFactory(paramValue, factoryMapIn, factoryManagers);
3186 }
3187 }
3188}
3189
3190// =====================================================================================================
3191// ======================================= MISC functions ==============================================
3192// =====================================================================================================
3193template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
3195 try {
3196 Matrix& A = dynamic_cast<Matrix&>(Op);
3197 if (A.IsFixedBlockSizeSet() && (A.GetFixedBlockSize() != blockSize_))
3198 this->GetOStream(Warnings0) << "Setting matrix block size to " << blockSize_ << " (value of the parameter in the list) "
3199 << "instead of " << A.GetFixedBlockSize() << " (provided matrix)." << std::endl
3200 << "You may want to check \"number of equations\" (or \"PDE equations\" for factory style list) parameter." << std::endl;
3201
3202 if ((blockSize_ != 1) || (dofOffset_ != 0))
3203 A.SetFixedBlockSize(blockSize_, dofOffset_);
3204
3205 if (Behavior::debug())
3206 MatrixUtils::checkLocalRowMapMatchesColMap(A);
3207
3208 } catch (std::bad_cast&) {
3209 this->GetOStream(Warnings0) << "Skipping setting block size as the operator is not a matrix" << std::endl;
3210 }
3211}
3212
3213template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
3215 H.SetCycle(Cycle_);
3216 H.SetCycleStartLevel(WCycleStartLevel_);
3217 H.SetProlongatorScalingFactor(scalingFactor_);
3218 H.SetLabel(hierarchyLabel_);
3220}
3221
3222static bool compare(const ParameterList& list1, const ParameterList& list2) {
3223 // First loop through and validate the parameters at this level.
3224 // In addition, we generate a list of sublists that we will search next
3225 for (ParameterList::ConstIterator it = list1.begin(); it != list1.end(); it++) {
3226 const std::string& name = it->first;
3227 const Teuchos::ParameterEntry& entry1 = it->second;
3228
3229 const Teuchos::ParameterEntry* entry2 = list2.getEntryPtr(name);
3230 if (!entry2) // entry is not present in the second list
3231 return false;
3232 if (entry1.isList() && entry2->isList()) { // sublist check
3233 compare(Teuchos::getValue<ParameterList>(entry1), Teuchos::getValue<ParameterList>(*entry2));
3234 continue;
3235 }
3236 if (entry1.getAny(false) != entry2->getAny(false)) // entries have different types or different values
3237 return false;
3238 }
3239
3240 return true;
3241}
3242
3243static inline bool areSame(const ParameterList& list1, const ParameterList& list2) {
3244 return compare(list1, list2) && compare(list2, list1);
3245}
3246
3247} // namespace MueLu
3248
3249#define MUELU_PARAMETERLISTINTERPRETER_SHORT
3250#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.
virtual void SetupHierarchy(Hierarchy &H) const
Setup Hierarchy object.
Class for generating an initial LocalOrdinal-type BlockNumber vector, based on an input paraemter for...
Factory for building transfer operators based on coarsening in polynomial degree, following the Intre...
Factory for building line detection information.
Class for transferring a vector of local ordinals from a finer level to a coarser one,...
Factory for converting matrices to half precision operators.
static Teuchos::RCP< Teuchos::ParameterList > GetProblemSpecificList(std::string const &problemType)
Return default parameter settings for the specified problem type.
static Teuchos::RCP< const Teuchos::ParameterList > List()
Return a "master" list of all valid parameters and their default values.
Class that encapsulates Matlab smoothers.
This class checks matrix properties of A on current level. This factory can be plugged in everywhere ...
Class for restricting a Matrix from a finer to a coarser level.
Class for restricting a MultiVector from a finer to a coarser level.
static const RCP< const NoFactory > getRCP()
Static Get() functions.
Factory for generating nullspace.
void UpdateFactoryManager_Nullspace(Teuchos::ParameterList &paramList, const Teuchos::ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps, RCP< Factory > &nullSpaceFactory) const
void UpdateFactoryManager_Reitzinger(Teuchos::ParameterList &paramList, const Teuchos::ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps) const
void UpdateFactoryManager_RAP(Teuchos::ParameterList &paramList, const Teuchos::ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps) const
void UpdateFactoryManager_Smoothers(Teuchos::ParameterList &paramList, const Teuchos::ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps) const
void 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)
void UpdateFactoryManager_MatrixTransfer(const std::string &VarName, Teuchos::ParameterList &paramList, const Teuchos::ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps) const
void UpdateFactoryManager_EminReitzinger(Teuchos::ParameterList &paramList, const Teuchos::ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps) const
void UpdateFactoryManager_Coordinates(Teuchos::ParameterList &paramList, const Teuchos::ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps) const
void BuildFactoryMap(const Teuchos::ParameterList &paramList, const FactoryMap &factoryMapIn, FactoryMap &factoryMapOut, FactoryManagerMap &factoryManagers) const
Interpret "Factories" sublist.
void UpdateFactoryManager_Restriction(Teuchos::ParameterList &paramList, const Teuchos::ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps) const
virtual void SetupOperator(Operator &A) const
Setup Operator object.
void UpdateFactoryManager_Replicate(Teuchos::ParameterList &paramList, const Teuchos::ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps) const
void UpdateFactoryManager_LowPrecision(ParameterList &paramList, const ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps) const
void UpdateFactoryManager_PCoarsen(Teuchos::ParameterList &paramList, const Teuchos::ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps) const
Teuchos::RCP< MueLu::FacadeClassFactory< Scalar, LocalOrdinal, GlobalOrdinal, Node > > facadeFact_
FacadeClass factory.
std::pair< std::string, const FactoryBase * > keep_pair
void UpdateFactoryManager_PG(Teuchos::ParameterList &paramList, const Teuchos::ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps) const
void SetParameterList(const Teuchos::ParameterList &paramList)
Set parameter list for Parameter list interpreter.
void UpdateFactoryManager_Material(Teuchos::ParameterList &paramList, const Teuchos::ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps) const
void Validate(const Teuchos::ParameterList &paramList) const
void UpdateFactoryManager_Emin(Teuchos::ParameterList &paramList, const Teuchos::ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps) const
void UpdateFactoryManager_Combine(Teuchos::ParameterList &paramList, const Teuchos::ParameterList &defaultList, FactoryManager &manager, int levelID, std::vector< keep_pair > &keeps) const
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)
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.
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)