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