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 // ***********************************************************************
4 //
5 // MueLu: A package for multigrid based preconditioning
6 // Copyright 2012 Sandia Corporation
7 //
8 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // Questions? Contact
39 // Jonathan Hu (jhu@sandia.gov)
40 // Andrey Prokopenko (aprokop@sandia.gov)
41 // Ray Tuminaro (rstumin@sandia.gov)
42 //
43 // ***********************************************************************
44 //
45 // @HEADER
46 #ifndef MUELU_ZOLTAN2INTERFACE_DEF_HPP
47 #define MUELU_ZOLTAN2INTERFACE_DEF_HPP
48 
49 #include <sstream>
50 #include <set>
51 
53 #if defined(HAVE_MUELU_ZOLTAN2) && defined(HAVE_MPI)
54 
55 #include <Zoltan2_XpetraMultiVectorAdapter.hpp>
56 #include <Zoltan2_XpetraCrsGraphAdapter.hpp>
57 #include <Zoltan2_PartitioningProblem.hpp>
58 
59 #include <Teuchos_Utils.hpp>
61 #include <Teuchos_OpaqueWrapper.hpp>
62 
63 #include "MueLu_Level.hpp"
64 #include "MueLu_Exceptions.hpp"
65 #include "MueLu_Monitor.hpp"
66 
67 namespace MueLu {
68 
69 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
71  defaultZoltan2Params = rcp(new ParameterList());
72  defaultZoltan2Params->set("algorithm", "multijagged");
73  defaultZoltan2Params->set("partitioning_approach", "partition");
74 
75  // Improve scaling for communication bound algorithms by premigrating
76  // coordinates to a subset of processors.
77  // For more information, see Github issue #1538
78  defaultZoltan2Params->set("mj_premigration_option", 1);
79 }
80 
81 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
83  RCP<ParameterList> validParamList = rcp(new ParameterList());
84 
85  validParamList->set<RCP<const FactoryBase> >("A", Teuchos::null, "Factory of the matrix A");
86  validParamList->set<RCP<const FactoryBase> >("number of partitions", Teuchos::null, "Instance of RepartitionHeuristicFactory.");
87  validParamList->set<RCP<const FactoryBase> >("Coordinates", Teuchos::null, "Factory of the coordinates");
88  validParamList->set<RCP<const ParameterList> >("ParameterList", Teuchos::null, "Zoltan2 parameters");
89  validParamList->set<RCP<const FactoryBase> >("repartition: heuristic target rows per process", Teuchos::null, "Factory for number of rows per process to use with MultiJagged");
90 
91  return validParamList;
92 }
93 
94 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
96  Input(currentLevel, "A");
97  Input(currentLevel, "number of partitions");
98  const ParameterList& pL = GetParameterList();
99  // We do this dance, because we don't want "ParameterList" to be marked as used.
100  // Is there a better way?
101  Teuchos::ParameterEntry entry = pL.getEntry("ParameterList");
102  RCP<const Teuchos::ParameterList> providedList = Teuchos::any_cast<RCP<const Teuchos::ParameterList> >(entry.getAny(false));
103  if (providedList != Teuchos::null && providedList->isType<std::string>("algorithm")) {
104  const std::string algo = providedList->get<std::string>("algorithm");
105  if (algo == "multijagged") {
106  Input(currentLevel, "Coordinates");
107  Input(currentLevel, "repartition: heuristic target rows per process");
108  } else if (algo == "rcb") {
109  Input(currentLevel, "Coordinates");
110  }
111  } else {
112  Input(currentLevel, "repartition: heuristic target rows per process");
113  Input(currentLevel, "Coordinates");
114  }
115 }
116 
117 template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
119  FactoryMonitor m(*this, "Build", level);
120 
121  typedef typename Teuchos::ScalarTraits<SC>::coordinateType real_type;
122  typedef typename Xpetra::MultiVector<real_type, LO, GO, NO> RealValuedMultiVector;
123 
124  RCP<Matrix> A = Get<RCP<Matrix> >(level, "A");
125  RCP<const Map> rowMap = A->getRowMap();
126  LO blkSize = A->GetFixedBlockSize();
127 
128  int numParts = Get<int>(level, "number of partitions");
129  if (numParts == 1 || numParts == -1) {
130  // Single processor, decomposition is trivial: all zeros
132  Set(level, "Partition", decomposition);
133  return;
134  } /* else if (numParts == -1) {
135  // No repartitioning
136  RCP<Xpetra::Vector<GO,LO,GO,NO> > decomposition = Teuchos::null; //Xpetra::VectorFactory<GO, LO, GO, NO>::Build(rowMap, true);
137  //decomposition->putScalar(Teuchos::as<Scalar>(rowMap->getComm()->getRank()));
138  Set(level, "Partition", decomposition);
139  return;
140  }*/
141 
142  const ParameterList& pL = GetParameterList();
143 
144  RCP<const ParameterList> providedList = pL.get<RCP<const ParameterList> >("ParameterList");
145  ParameterList Zoltan2Params;
146  if (providedList != Teuchos::null)
147  Zoltan2Params = *providedList;
148 
149  // Merge defalt Zoltan2 parameters with user provided
150  // If default and user parameters contain the same parameter name, user one is always preferred
151  for (ParameterList::ConstIterator param = defaultZoltan2Params->begin(); param != defaultZoltan2Params->end(); param++) {
152  const std::string& pName = defaultZoltan2Params->name(param);
153  if (!Zoltan2Params.isParameter(pName))
154  Zoltan2Params.setEntry(pName, defaultZoltan2Params->getEntry(pName));
155  }
156  Zoltan2Params.set("num_global_parts", Teuchos::as<int>(numParts));
157 
158  GetOStream(Runtime0) << "Zoltan2 parameters:\n----------\n"
159  << Zoltan2Params << "----------" << std::endl;
160 
161  const std::string& algo = Zoltan2Params.get<std::string>("algorithm");
162 
163  if (algo == "multijagged" || algo == "rcb") {
164  RCP<RealValuedMultiVector> coords = Get<RCP<RealValuedMultiVector> >(level, "Coordinates");
165  RCP<const Map> map = coords->getMap();
166  GO numElements = map->getLocalNumElements();
167 
168  // Check that the number of local coordinates is consistent with the #rows in A
169  TEUCHOS_TEST_FOR_EXCEPTION(rowMap->getLocalNumElements() / blkSize != coords->getLocalLength(), Exceptions::Incompatible,
170  "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.");
171 #ifdef HAVE_MUELU_DEBUG
172  GO indexBase = rowMap->getIndexBase();
173  GetOStream(Runtime0) << "Checking consistence of row and coordinates maps" << std::endl;
174  // Make sure that logical blocks in row map coincide with logical nodes in coordinates map
175  ArrayView<const GO> rowElements = rowMap->getLocalElementList();
176  ArrayView<const GO> coordsElements = map->getLocalElementList();
177  for (LO i = 0; i < Teuchos::as<LO>(numElements); i++)
178  TEUCHOS_TEST_FOR_EXCEPTION((coordsElements[i] - indexBase) * blkSize + indexBase != rowElements[i * blkSize],
179  Exceptions::RuntimeError, "i = " << i << ", coords GID = " << coordsElements[i] << ", row GID = " << rowElements[i * blkSize] << ", blkSize = " << blkSize << std::endl);
180 #endif
181 
182  typedef Zoltan2::XpetraMultiVectorAdapter<RealValuedMultiVector> InputAdapterType;
183  typedef Zoltan2::PartitioningProblem<InputAdapterType> ProblemType;
184 
185  Array<real_type> weightsPerRow(numElements);
186  for (LO i = 0; i < numElements; i++) {
187  weightsPerRow[i] = 0.0;
188 
189  for (LO j = 0; j < blkSize; j++) {
190  weightsPerRow[i] += A->getNumEntriesInLocalRow(i * blkSize + j);
191  }
192  }
193 
194  // MultiJagged: Grab the target rows per process from the Heuristic to use unless the Zoltan2 list says otherwise
195  if (algo == "multijagged" && !Zoltan2Params.isParameter("mj_premigration_coordinate_count")) {
196  LO heuristicTargetRowsPerProcess = Get<LO>(level, "repartition: heuristic target rows per process");
197  Zoltan2Params.set("mj_premigration_coordinate_count", heuristicTargetRowsPerProcess);
198  }
199  const bool writeZoltan2DebuggingFiles = Zoltan2Params.get("mj_debug", false);
200  Zoltan2Params.remove("mj_debug");
201 
202  std::vector<int> strides;
203  std::vector<const real_type*> weights(1, weightsPerRow.getRawPtr());
204 
205  RCP<const Teuchos::MpiComm<int> > dupMpiComm = rcp_dynamic_cast<const Teuchos::MpiComm<int> >(rowMap->getComm()->duplicate());
206  RCP<const Teuchos::OpaqueWrapper<MPI_Comm> > zoltanComm = dupMpiComm->getRawMpiComm();
207 
208  InputAdapterType adapter(coords, weights, strides);
209  RCP<ProblemType> problem(new ProblemType(&adapter, &Zoltan2Params, (*zoltanComm)()));
210 
211  {
212  SubFactoryMonitor m1(*this, "Zoltan2 " + toString(algo), level);
213  if (writeZoltan2DebuggingFiles)
214  adapter.generateFiles(("mj_debug.lvl_" + std::to_string(level.GetLevelID())).c_str(), *(rowMap->getComm()));
215  problem->solve();
216  }
217 
219  ArrayRCP<GO> decompEntries = decomposition->getDataNonConst(0);
220 
221  const typename InputAdapterType::part_t* parts = problem->getSolution().getPartListView();
222 
223  for (GO i = 0; i < numElements; i++) {
224  int partNum = parts[i];
225 
226  for (LO j = 0; j < blkSize; j++)
227  decompEntries[i * blkSize + j] = partNum;
228  }
229 
230  Set(level, "Partition", decomposition);
231 
232  } else {
233  GO numElements = rowMap->getLocalNumElements();
234 
235  typedef Zoltan2::XpetraCrsGraphAdapter<CrsGraph> InputAdapterType;
236  typedef Zoltan2::PartitioningProblem<InputAdapterType> ProblemType;
237 
238  RCP<const Teuchos::MpiComm<int> > dupMpiComm = rcp_dynamic_cast<const Teuchos::MpiComm<int> >(rowMap->getComm()->duplicate());
239  RCP<const Teuchos::OpaqueWrapper<MPI_Comm> > zoltanComm = dupMpiComm->getRawMpiComm();
240 
241  InputAdapterType adapter(A->getCrsGraph());
242  RCP<ProblemType> problem(new ProblemType(&adapter, &Zoltan2Params, (*zoltanComm)()));
243 
244  {
245  SubFactoryMonitor m1(*this, "Zoltan2 " + toString(algo), level);
246  problem->solve();
247  }
248 
250  ArrayRCP<GO> decompEntries = decomposition->getDataNonConst(0);
251 
252  const typename InputAdapterType::part_t* parts = problem->getSolution().getPartListView();
253 
254  // For blkSize > 1, ignore solution for every row but the first ones in a block.
255  for (GO i = 0; i < numElements / blkSize; i++) {
256  int partNum = parts[i * blkSize];
257 
258  for (LO j = 0; j < blkSize; j++)
259  decompEntries[i * blkSize + j] = partNum;
260  }
261 
262  Set(level, "Partition", decomposition);
263  }
264 }
265 
266 } // namespace MueLu
267 
268 #endif // if defined(HAVE_MUELU_ZOLTAN2) && defined(HAVE_MPI)
269 
270 #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)
ParameterList & set(std::string const &name, T const &value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
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.
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:99
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.