MueLu Version of the Day
Loading...
Searching...
No Matches
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>
27#include <Xpetra_CrsGraphFactory.hpp>
28#include <Xpetra_BlockedMap.hpp>
29#include <Xpetra_BlockedCrsMatrix.hpp>
30
31#ifdef HAVE_MUELU_ISORROPIA
32#include <Isorropia_Exception.hpp>
33
34#ifdef HAVE_MUELU_EPETRA
35#include <Xpetra_EpetraCrsGraph.hpp>
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
49namespace MueLu {
50
51template <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
62template <class LocalOrdinal, class GlobalOrdinal, class Node>
64 Input(currentLevel, "A");
65 Input(currentLevel, "number of partitions");
66 Input(currentLevel, "UnAmalgamationInfo");
67}
68
69template <class LocalOrdinal, class GlobalOrdinal, class Node>
71 FactoryMonitor m(*this, "Build", level);
72 typedef Xpetra::BlockedMap<LocalOrdinal, GlobalOrdinal, Node> BlockMap;
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.
83 RCP<Xpetra::Vector<GO, LO, GO, NO> > decomposition = Xpetra::VectorFactory<GO, LO, GO, NO>::Build(rowMap, true);
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);
153 Teuchos::ArrayView<const LO> indices;
154 Teuchos::ArrayView<const SC> vals;
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
208 RCP<Xpetra::Vector<GO, LO, GO, NO> > decomposition = Xpetra::VectorFactory<GO, LO, GO, NO>::Build(nodeMap, false);
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.
230 RCP<Xpetra::Vector<GO, LO, GO, NO> > decomposition = Xpetra::VectorFactory<GO, LO, GO, NO>::Build(rowMap, true);
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_ */
Exception indicating invalid cast attempted.
Exception throws to report errors in the internal logical of the program.
Timer to be used in factories. Similar to Monitor but with additional timers.
void DeclareInput(Level &level) const
Specifies the data that this class needs, and the factories that generate that data.
void Build(Level &level) const
Build an object with this factory.
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
Class that holds all level-specific information.
Namespace for MueLu classes and methods.
@ Statistics0
Print statistics that do not involve significant additional computation.
std::string toString(const T &what)
Little helper function to convert non-string types to strings.