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