MueLu  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MueLu_IsorropiaInterface_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 /*
11  * MueLu_IsorropiaInterface_def.hpp
12  *
13  * Created on: Jun 10, 2013
14  * Author: tobias
15  */
16 
17 #ifndef MUELU_ISORROPIAINTERFACE_DEF_HPP_
18 #define MUELU_ISORROPIAINTERFACE_DEF_HPP_
19 
21 
22 #include <Teuchos_Utils.hpp>
23 //#include <Teuchos_DefaultMpiComm.hpp> //TODO: fwd decl.
24 //#include <Teuchos_OpaqueWrapper.hpp> //TODO: fwd decl.
25 
26 #include <Xpetra_MapFactory.hpp>
28 #include <Xpetra_BlockedMap.hpp>
30 
31 #ifdef HAVE_MUELU_ISORROPIA
32 #include <Isorropia_Exception.hpp>
33 
34 #ifdef HAVE_MUELU_EPETRA
36 #include <Epetra_CrsGraph.h>
37 #include <Isorropia_EpetraPartitioner.hpp>
38 #endif
39 
40 #include <Xpetra_TpetraCrsGraph.hpp>
41 #endif // ENDIF HAVE_MUELU_ISORROPIA
42 
43 #include "MueLu_Level.hpp"
44 #include "MueLu_Exceptions.hpp"
45 #include "MueLu_Monitor.hpp"
46 
47 #include "MueLu_AmalgamationInfo.hpp"
48 
49 namespace MueLu {
50 
51 template <class LocalOrdinal, class GlobalOrdinal, class Node>
53  RCP<ParameterList> validParamList = rcp(new ParameterList());
54 
55  validParamList->set<RCP<const FactoryBase> >("A", Teuchos::null, "Factory of the matrix A");
56  validParamList->set<RCP<const FactoryBase> >("number of partitions", Teuchos::null, "Instance of RepartitionHeuristicFactory.");
57  validParamList->set<RCP<const FactoryBase> >("UnAmalgamationInfo", Teuchos::null, "Generating factory of UnAmalgamationInfo");
58 
59  return validParamList;
60 }
61 
62 template <class LocalOrdinal, class GlobalOrdinal, class Node>
64  Input(currentLevel, "A");
65  Input(currentLevel, "number of partitions");
66  Input(currentLevel, "UnAmalgamationInfo");
67 }
68 
69 template <class LocalOrdinal, class GlobalOrdinal, class Node>
71  FactoryMonitor m(*this, "Build", level);
73 
74  RCP<Matrix> A = Get<RCP<Matrix> >(level, "A");
75  RCP<AmalgamationInfo> amalInfo = Get<RCP<AmalgamationInfo> >(level, "UnAmalgamationInfo");
76  GO numParts = Get<int>(level, "number of partitions");
77 
78  RCP<const Map> rowMap = A->getRowMap();
79  RCP<const Map> colMap = A->getColMap();
80 
81  if (numParts == 1 || numParts == -1) {
82  // Running on one processor, so decomposition is the trivial one, all zeros.
84  Set(level, "AmalgamatedPartition", decomposition);
85  return;
86  }
87 
88  // ok, reconstruct graph information of matrix A
89  // Note, this is the non-rebalanced matrix A and we need the graph
90  // of the non-rebalanced matrix A. We cannot make use of the "Graph"
91  // that is/will be built for the aggregates later for several reasons
92  // 1) the "Graph" for the aggregates is meant to be based on the rebalanced matrix A
93  // 2) we cannot call a CoalesceDropFactory::Build here since this is very complicated and
94  // completely messes up the whole factory chain
95  // 3) CoalesceDropFactory is meant to provide some minimal Graph information for the aggregation
96  // (LWGraph), but here we need the full CrsGraph for Isorropia as input
97 
98  // That is, why this code is somewhat redundant to CoalesceDropFactory
99 
100  LO blockdim = 1; // block dim for fixed size blocks
101  GO indexBase = rowMap->getIndexBase(); // index base of maps
102  GO offset = 0;
103  LO blockid = -1; // block id in strided map
104  LO nStridedOffset = 0; // DOF offset for strided block id "blockid" (default = 0)
105  // LO stridedblocksize = blockdim; // size of strided block id "blockid" (default = fullblocksize, only if blockid!=-1 stridedblocksize <= fullblocksize)
106 
107  // 1) check for blocking/striding information
108  // fill above variables
109  if (A->IsView("stridedMaps") &&
110  Teuchos::rcp_dynamic_cast<const StridedMap>(A->getRowMap("stridedMaps")) != Teuchos::null) {
111  Xpetra::viewLabel_t oldView = A->SwitchToView("stridedMaps"); // note: "stridedMaps are always non-overlapping (correspond to range and domain maps!)
112  RCP<const StridedMap> strMap = Teuchos::rcp_dynamic_cast<const StridedMap>(A->getRowMap());
113  TEUCHOS_TEST_FOR_EXCEPTION(strMap == Teuchos::null, Exceptions::BadCast, "MueLu::IsorropiaInterface::Build: cast to strided row map failed.");
114  blockdim = strMap->getFixedBlockSize();
115  offset = strMap->getOffset();
116  blockid = strMap->getStridedBlockId();
117  if (blockid > -1) {
118  std::vector<size_t> stridingInfo = strMap->getStridingData();
119  for (size_t j = 0; j < Teuchos::as<size_t>(blockid); j++)
120  nStridedOffset += stridingInfo[j];
121  // stridedblocksize = Teuchos::as<LocalOrdinal>(stridingInfo[blockid]);
122 
123  } // else {
124  // stridedblocksize = blockdim;
125  //}
126  oldView = A->SwitchToView(oldView);
127  // GetOStream(Statistics0) << "IsorropiaInterface::Build():" << " found blockdim=" << blockdim << " from strided maps (blockid=" << blockid << ", strided block size=" << stridedblocksize << "). offset=" << offset << std::endl;
128  } else
129  GetOStream(Statistics0) << "IsorropiaInterface::Build(): no striding information available. Use blockdim=1 with offset=0" << std::endl;
130 
131  // 2) get row map for amalgamated matrix (graph of A)
132  // with same distribution over all procs as row map of A
133  RCP<const Map> nodeMap = amalInfo->getNodeRowMap();
134  RCP<const BlockedMap> bnodeMap = Teuchos::rcp_dynamic_cast<const BlockedMap>(nodeMap);
135  if (!bnodeMap.is_null()) nodeMap = bnodeMap->getMap();
136 
137  GetOStream(Statistics0) << "IsorropiaInterface:Build(): nodeMap " << nodeMap->getLocalNumElements() << "/" << nodeMap->getGlobalNumElements() << " elements" << std::endl;
138 
139  // 3) create graph of amalgamated matrix
140  RCP<CrsGraph> crsGraph = CrsGraphFactory::Build(nodeMap, A->getLocalMaxNumRowEntries() * blockdim);
141 
142  // 4) do amalgamation. generate graph of amalgamated matrix
143  for (LO row = 0; row < Teuchos::as<LO>(A->getRowMap()->getLocalNumElements()); row++) {
144  // get global DOF id
145  GO grid = rowMap->getGlobalElement(row);
146 
147  // translate grid to nodeid
148  // JHU 2019-20-May this is identical to AmalgamationFactory::DOFGid2NodeId(), and is done
149  // to break a circular dependence when libraries are built statically
150  GO nodeId = (grid - offset - indexBase) / blockdim + indexBase;
151 
152  size_t nnz = A->getNumEntriesInLocalRow(row);
155  A->getLocalRowView(row, indices, vals);
156 
157  RCP<std::vector<GO> > cnodeIds = Teuchos::rcp(new std::vector<GO>); // global column block ids
158  LO realnnz = 0;
159  for (LO col = 0; col < Teuchos::as<LO>(nnz); col++) {
160  GO gcid = colMap->getGlobalElement(indices[col]); // global column id
161 
162  if (vals[col] != 0.0) {
163  // JHU 2019-20-May this is identical to AmalgamationFactory::DOFGid2NodeId(), and is done
164  // to break a circular dependence when libraries are built statically
165  GO cnodeId = (gcid - offset - indexBase) / blockdim + indexBase;
166  cnodeIds->push_back(cnodeId);
167  realnnz++; // increment number of nnz in matrix row
168  }
169  }
170 
171  Teuchos::ArrayRCP<GO> arr_cnodeIds = Teuchos::arcp(cnodeIds);
172 
173  if (arr_cnodeIds.size() > 0)
174  crsGraph->insertGlobalIndices(nodeId, arr_cnodeIds());
175  }
176  // fill matrix graph
177  crsGraph->fillComplete(nodeMap, nodeMap);
178 
179 #ifdef HAVE_MPI
180 #ifdef HAVE_MUELU_ISORROPIA
181 
182  // prepare parameter list for Isorropia
183  Teuchos::ParameterList paramlist;
184  paramlist.set("NUM PARTS", toString(numParts));
185 
186  /*STRUCTURALLY SYMMETRIC [NO/yes] (is symmetrization required?)
187  PARTITIONING METHOD [block/cyclic/random/rcb/rib/hsfc/graph/HYPERGRAPH]
188  NUM PARTS [int k] (global number of parts)
189  IMBALANCE TOL [float tol] (1.0 is perfect balance)
190  BALANCE OBJECTIVE [ROWS/nonzeros]
191  */
192  Teuchos::ParameterList& sublist = paramlist.sublist("Zoltan");
193  sublist.set("LB_APPROACH", "PARTITION");
194 
195 #ifdef HAVE_MUELU_EPETRA
196  RCP<Xpetra::EpetraCrsGraphT<GO, Node> > epCrsGraph = Teuchos::rcp_dynamic_cast<Xpetra::EpetraCrsGraphT<GO, Node> >(crsGraph);
197  if (epCrsGraph != Teuchos::null) {
198  RCP<const Epetra_CrsGraph> epetraCrsGraph = epCrsGraph->getEpetra_CrsGraph();
199 
200  RCP<Isorropia::Epetra::Partitioner> isoPart = Teuchos::rcp(new Isorropia::Epetra::Partitioner(epetraCrsGraph, paramlist));
201 
202  int size = 0;
203  const int* array = NULL;
204  isoPart->extractPartsView(size, array);
205 
206  TEUCHOS_TEST_FOR_EXCEPTION(size != Teuchos::as<int>(nodeMap->getLocalNumElements()), Exceptions::RuntimeError, "length of array returned from extractPartsView does not match local length of rowMap");
207 
209  ArrayRCP<GO> decompEntries = decomposition->getDataNonConst(0);
210 
211  // fill vector with amalgamated information about partitioning
212  for (int i = 0; i < size; i++) {
213  decompEntries[i] = Teuchos::as<GO>(array[i]);
214  }
215 
216  Set(level, "AmalgamatedPartition", decomposition);
217  }
218 #endif // ENDIF HAVE_MUELU_EPETRA
219 
220 #ifdef HAVE_MUELU_INST_DOUBLE_INT_INT
221  RCP<Xpetra::TpetraCrsGraph<LO, GO, Node> > tpCrsGraph = Teuchos::rcp_dynamic_cast<Xpetra::TpetraCrsGraph<LO, GO, Node> >(crsGraph);
222  TEUCHOS_TEST_FOR_EXCEPTION(tpCrsGraph != Teuchos::null, Exceptions::RuntimeError, "Tpetra is not supported with Isorropia.");
223 #else
224  TEUCHOS_TEST_FOR_EXCEPTION(false, Exceptions::RuntimeError, "Isorropia is an interface to Zoltan which only has support for LO=GO=int and SC=double.");
225 #endif // ENDIF HAVE_MUELU_INST_DOUBLE_INT_INT
226 #endif // HAVE_MUELU_ISORROPIA
227 #else // if we don't have MPI
228 
229  // Running on one processor, so decomposition is the trivial one, all zeros.
231  Set(level, "AmalgamatedPartition", decomposition);
232 
233 #endif // HAVE_MPI
234  // throw a more helpful error message if something failed
235  // TEUCHOS_TEST_FOR_EXCEPTION(!level.IsAvailable("AmalgamatedPartition"), Exceptions::RuntimeError, "IsorropiaInterface::Build : no \'Partition\' vector available on level. Isorropia failed to build a partition of the non-repartitioned graph of A. Please make sure, that Isorropia is correctly compiled (Epetra/Tpetra).");
236 
237 } // Build()
238 
239 } // namespace MueLu
240 
241 //#endif //if defined(HAVE_MUELU_ISORROPIA) && defined(HAVE_MPI)
242 
243 #endif /* MUELU_ISORROPIAINTERFACE_DEF_HPP_ */
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
Exception indicating invalid cast attempted.
std::string toString(const T &what)
Little helper function to convert non-string types to strings.
GlobalOrdinal GO
void Build(Level &level) const
Build an object with this factory.
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
ParameterList & set(std::string const &name, T &&value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
size_type size() const
Print statistics that do not involve significant additional computation.
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
std::string viewLabel_t
static RCP< Vector > Build(const Teuchos::RCP< const Map > &map, bool zeroOut=true)
void DeclareInput(Level &level) const
Specifies the data that this class needs, and the factories that generate that data.
ParameterList & sublist(const std::string &name, bool mustAlreadyExist=false, const std::string &docString="")
Exception throws to report errors in the internal logical of the program.
bool is_null() const