MueLu  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MueLu_Zoltan2Interface_def.hpp
Go to the documentation of this file.
1 // @HEADER
2 // *****************************************************************************
3 // MueLu: A package for multigrid based preconditioning
4 //
5 // Copyright 2012 NTESS and the MueLu contributors.
6 // SPDX-License-Identifier: BSD-3-Clause
7 // *****************************************************************************
8 // @HEADER
9 
10 #ifndef MUELU_ZOLTAN2INTERFACE_DEF_HPP
11 #define MUELU_ZOLTAN2INTERFACE_DEF_HPP
12 
13 #include <sstream>
14 #include <set>
15 
17 #if defined(HAVE_MUELU_ZOLTAN2) && defined(HAVE_MPI)
18 
19 #include <Zoltan2_XpetraMultiVectorAdapter.hpp>
20 #include <Zoltan2_XpetraCrsGraphAdapter.hpp>
21 #include <Zoltan2_PartitioningProblem.hpp>
22 
23 #include <Teuchos_Utils.hpp>
25 #include <Teuchos_OpaqueWrapper.hpp>
26 
27 #include "MueLu_Level.hpp"
28 #include "MueLu_Exceptions.hpp"
29 #include "MueLu_Monitor.hpp"
30 
31 namespace MueLu {
32 
33 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
35  defaultZoltan2Params = rcp(new ParameterList());
36  defaultZoltan2Params->set("algorithm", "multijagged");
37  defaultZoltan2Params->set("partitioning_approach", "partition");
38 
39  // Improve scaling for communication bound algorithms by premigrating
40  // coordinates to a subset of processors.
41  // For more information, see Github issue #1538
42  defaultZoltan2Params->set("mj_premigration_option", 1);
43 }
44 
45 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
47  RCP<ParameterList> validParamList = rcp(new ParameterList());
48 
49  validParamList->set<RCP<const FactoryBase> >("A", Teuchos::null, "Factory of the matrix A");
50  validParamList->set<RCP<const FactoryBase> >("number of partitions", Teuchos::null, "Instance of RepartitionHeuristicFactory.");
51  validParamList->set<RCP<const FactoryBase> >("Coordinates", Teuchos::null, "Factory of the coordinates");
52  validParamList->set<RCP<const ParameterList> >("ParameterList", Teuchos::null, "Zoltan2 parameters");
53  validParamList->set<RCP<const FactoryBase> >("repartition: heuristic target rows per process", Teuchos::null, "Factory for number of rows per process to use with MultiJagged");
54 
55  return validParamList;
56 }
57 
58 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
60  Input(currentLevel, "A");
61  Input(currentLevel, "number of partitions");
62  const ParameterList& pL = GetParameterList();
63  // We do this dance, because we don't want "ParameterList" to be marked as used.
64  // Is there a better way?
65  Teuchos::ParameterEntry entry = pL.getEntry("ParameterList");
66  RCP<const Teuchos::ParameterList> providedList = Teuchos::any_cast<RCP<const Teuchos::ParameterList> >(entry.getAny(false));
67  if (providedList != Teuchos::null && providedList->isType<std::string>("algorithm")) {
68  const std::string algo = providedList->get<std::string>("algorithm");
69  if (algo == "multijagged") {
70  Input(currentLevel, "Coordinates");
71  Input(currentLevel, "repartition: heuristic target rows per process");
72  } else if (algo == "rcb") {
73  Input(currentLevel, "Coordinates");
74  }
75  } else {
76  Input(currentLevel, "repartition: heuristic target rows per process");
77  Input(currentLevel, "Coordinates");
78  }
79 }
80 
81 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
83  FactoryMonitor m(*this, "Build", level);
84 
85  typedef typename Teuchos::ScalarTraits<SC>::coordinateType real_type;
86  typedef typename Xpetra::MultiVector<real_type, LO, GO, NO> RealValuedMultiVector;
87 
88  RCP<Matrix> A = Get<RCP<Matrix> >(level, "A");
89  RCP<const Map> rowMap = A->getRowMap();
90  LO blkSize = A->GetFixedBlockSize();
91 
92  int numParts = Get<int>(level, "number of partitions");
93  if (numParts == 1 || numParts == -1) {
94  // Single processor, decomposition is trivial: all zeros
96  Set(level, "Partition", decomposition);
97  return;
98  } /* else if (numParts == -1) {
99  // No repartitioning
100  RCP<Xpetra::Vector<GO,LO,GO,NO> > decomposition = Teuchos::null; //Xpetra::VectorFactory<GO, LO, GO, NO>::Build(rowMap, true);
101  //decomposition->putScalar(Teuchos::as<Scalar>(rowMap->getComm()->getRank()));
102  Set(level, "Partition", decomposition);
103  return;
104  }*/
105 
106  const ParameterList& pL = GetParameterList();
107 
108  RCP<const ParameterList> providedList = pL.get<RCP<const ParameterList> >("ParameterList");
109  ParameterList Zoltan2Params;
110  if (providedList != Teuchos::null)
111  Zoltan2Params = *providedList;
112 
113  // Merge defalt Zoltan2 parameters with user provided
114  // If default and user parameters contain the same parameter name, user one is always preferred
115  for (ParameterList::ConstIterator param = defaultZoltan2Params->begin(); param != defaultZoltan2Params->end(); param++) {
116  const std::string& pName = defaultZoltan2Params->name(param);
117  if (!Zoltan2Params.isParameter(pName))
118  Zoltan2Params.setEntry(pName, defaultZoltan2Params->getEntry(pName));
119  }
120  Zoltan2Params.set("num_global_parts", Teuchos::as<int>(numParts));
121 
122  GetOStream(Runtime0) << "Zoltan2 parameters:\n----------\n"
123  << Zoltan2Params << "----------" << std::endl;
124 
125  const std::string& algo = Zoltan2Params.get<std::string>("algorithm");
126 
127  if (algo == "multijagged" || algo == "rcb") {
128  RCP<RealValuedMultiVector> coords = Get<RCP<RealValuedMultiVector> >(level, "Coordinates");
129  RCP<const Map> map = coords->getMap();
130  GO numElements = map->getLocalNumElements();
131 
132  // Check that the number of local coordinates is consistent with the #rows in A
133  TEUCHOS_TEST_FOR_EXCEPTION(rowMap->getLocalNumElements() / blkSize != coords->getLocalLength(), Exceptions::Incompatible,
134  "Coordinate vector length (" + toString(coords->getLocalLength()) << " is incompatible with number of block rows in A (" + toString(rowMap->getLocalNumElements() / blkSize) + "The vector length should be the same as the number of mesh points.");
135 #ifdef HAVE_MUELU_DEBUG
136  GO indexBase = rowMap->getIndexBase();
137  GetOStream(Runtime0) << "Checking consistence of row and coordinates maps" << std::endl;
138  // Make sure that logical blocks in row map coincide with logical nodes in coordinates map
139  ArrayView<const GO> rowElements = rowMap->getLocalElementList();
140  ArrayView<const GO> coordsElements = map->getLocalElementList();
141  for (LO i = 0; i < Teuchos::as<LO>(numElements); i++)
142  TEUCHOS_TEST_FOR_EXCEPTION((coordsElements[i] - indexBase) * blkSize + indexBase != rowElements[i * blkSize],
143  Exceptions::RuntimeError, "i = " << i << ", coords GID = " << coordsElements[i] << ", row GID = " << rowElements[i * blkSize] << ", blkSize = " << blkSize << std::endl);
144 #endif
145 
146  typedef Zoltan2::XpetraMultiVectorAdapter<RealValuedMultiVector> InputAdapterType;
147  typedef Zoltan2::PartitioningProblem<InputAdapterType> ProblemType;
148 
149  Array<real_type> weightsPerRow(numElements);
150  for (LO i = 0; i < numElements; i++) {
151  weightsPerRow[i] = 0.0;
152 
153  for (LO j = 0; j < blkSize; j++) {
154  weightsPerRow[i] += A->getNumEntriesInLocalRow(i * blkSize + j);
155  }
156  }
157 
158  // MultiJagged: Grab the target rows per process from the Heuristic to use unless the Zoltan2 list says otherwise
159  if (algo == "multijagged" && !Zoltan2Params.isParameter("mj_premigration_coordinate_count")) {
160  LO heuristicTargetRowsPerProcess = Get<LO>(level, "repartition: heuristic target rows per process");
161  Zoltan2Params.set("mj_premigration_coordinate_count", heuristicTargetRowsPerProcess);
162  }
163  const bool writeZoltan2DebuggingFiles = Zoltan2Params.get("mj_debug", false);
164  Zoltan2Params.remove("mj_debug");
165 
166  std::vector<int> strides;
167  std::vector<const real_type*> weights(1, weightsPerRow.getRawPtr());
168 
169  RCP<const Teuchos::MpiComm<int> > dupMpiComm = rcp_dynamic_cast<const Teuchos::MpiComm<int> >(rowMap->getComm()->duplicate());
170  RCP<const Teuchos::OpaqueWrapper<MPI_Comm> > zoltanComm = dupMpiComm->getRawMpiComm();
171 
172  InputAdapterType adapter(coords, weights, strides);
173  RCP<ProblemType> problem(new ProblemType(&adapter, &Zoltan2Params, (*zoltanComm)()));
174 
175  {
176  SubFactoryMonitor m1(*this, "Zoltan2 " + toString(algo), level);
177  if (writeZoltan2DebuggingFiles)
178  adapter.generateFiles(("mj_debug.lvl_" + std::to_string(level.GetLevelID())).c_str(), *(rowMap->getComm()));
179  problem->solve();
180  }
181 
183  ArrayRCP<GO> decompEntries = decomposition->getDataNonConst(0);
184 
185  const typename InputAdapterType::part_t* parts = problem->getSolution().getPartListView();
186 
187  for (GO i = 0; i < numElements; i++) {
188  int partNum = parts[i];
189 
190  for (LO j = 0; j < blkSize; j++)
191  decompEntries[i * blkSize + j] = partNum;
192  }
193 
194  Set(level, "Partition", decomposition);
195 
196  } else {
197  GO numElements = rowMap->getLocalNumElements();
198 
199  typedef Zoltan2::XpetraCrsGraphAdapter<CrsGraph> InputAdapterType;
200  typedef Zoltan2::PartitioningProblem<InputAdapterType> ProblemType;
201 
202  RCP<const Teuchos::MpiComm<int> > dupMpiComm = rcp_dynamic_cast<const Teuchos::MpiComm<int> >(rowMap->getComm()->duplicate());
203  RCP<const Teuchos::OpaqueWrapper<MPI_Comm> > zoltanComm = dupMpiComm->getRawMpiComm();
204 
205  InputAdapterType adapter(A->getCrsGraph());
206  RCP<ProblemType> problem(new ProblemType(&adapter, &Zoltan2Params, (*zoltanComm)()));
207 
208  {
209  SubFactoryMonitor m1(*this, "Zoltan2 " + toString(algo), level);
210  problem->solve();
211  }
212 
214  ArrayRCP<GO> decompEntries = decomposition->getDataNonConst(0);
215 
216  const typename InputAdapterType::part_t* parts = problem->getSolution().getPartListView();
217 
218  // For blkSize > 1, ignore solution for every row but the first ones in a block.
219  for (GO i = 0; i < numElements / blkSize; i++) {
220  int partNum = parts[i * blkSize];
221 
222  for (LO j = 0; j < blkSize; j++)
223  decompEntries[i * blkSize + j] = partNum;
224  }
225 
226  Set(level, "Partition", decomposition);
227  }
228 }
229 
230 } // namespace MueLu
231 
232 #endif // if defined(HAVE_MUELU_ZOLTAN2) && defined(HAVE_MPI)
233 
234 #endif // MUELU_ZOLTAN2INTERFACE_DEF_HPP
const std::string & name() const
std::string toString(const T &what)
Little helper function to convert non-string types to strings.
GlobalOrdinal GO
T & get(const std::string &name, T def_value)
Timer to be used in factories. Similar to Monitor but with additional timers.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
LocalOrdinal LO
One-liner description of what is happening.
T * get() const
void Build(Level &currentLevel) const
Build an object with this factory.
ParameterList & set(std::string const &name, T &&value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
Exception throws to report incompatible objects (like maps).
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Class that holds all level-specific information.
Definition: MueLu_Level.hpp:63
Timer to be used in factories. Similar to SubMonitor but adds a timer level by level.
params_t::ConstIterator ConstIterator
static RCP< Vector > Build(const Teuchos::RCP< const Map > &map, bool zeroOut=true)
any & getAny(bool activeQry=true)
bool isType(const std::string &name) const
Exception throws to report errors in the internal logical of the program.
ParameterEntry & getEntry(const std::string &name)
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
void DeclareInput(Level &currentLevel) const
Specifies the data that this class needs, and the factories that generate that data.