10#include "Teko_InterlacedTpetra.hpp"
11#include "Tpetra_Import.hpp"
12#include "Tpetra_Details_makeColMap_decl.hpp"
13#include "KokkosSparse_SortCrs.hpp"
21namespace TpetraHelpers {
27void buildSubMaps(GO numGlobals,
int numVars,
const Teuchos::Comm<int>& comm,
28 std::vector<std::pair<
int, RCP<Tpetra::Map<LO, GO, NT> > > >& subMaps) {
29 std::vector<int> vars;
32 for (
int i = 0; i < numVars; i++) vars.push_back(1);
35 buildSubMaps(numGlobals, vars, comm, subMaps);
39void buildSubMaps(
const Tpetra::Map<LO, GO, NT>& globalMap,
const std::vector<int>& vars,
40 const Teuchos::Comm<int>& comm,
41 std::vector<std::pair<
int, Teuchos::RCP<Tpetra::Map<LO, GO, NT> > > >& subMaps) {
42 buildSubMaps(globalMap.getGlobalNumElements(), globalMap.getLocalNumElements(),
43 globalMap.getMinGlobalIndex(), vars, comm, subMaps);
47void buildSubMaps(GO numGlobals,
const std::vector<int>& vars,
const Teuchos::Comm<int>& comm,
48 std::vector<std::pair<
int, Teuchos::RCP<Tpetra::Map<LO, GO, NT> > > >& subMaps) {
49 std::vector<int>::const_iterator varItr;
52 int numGlobalVars = 0;
53 for (varItr = vars.begin(); varItr != vars.end(); ++varItr) numGlobalVars += *varItr;
56 TEUCHOS_ASSERT((numGlobals % numGlobalVars) == 0);
58 Tpetra::Map<LO, GO, NT> sampleMap(numGlobals / numGlobalVars, 0, rcpFromRef(comm));
60 buildSubMaps(numGlobals, numGlobalVars * sampleMap.getLocalNumElements(),
61 numGlobalVars * sampleMap.getMinGlobalIndex(), vars, comm, subMaps);
65void buildSubMaps(GO numGlobals, LO numMyElements, GO minMyGID,
const std::vector<int>& vars,
66 const Teuchos::Comm<int>& comm,
67 std::vector<std::pair<
int, Teuchos::RCP<Tpetra::Map<LO, GO, NT> > > >& subMaps) {
68 std::vector<int>::const_iterator varItr;
71 int numGlobalVars = 0;
72 for (varItr = vars.begin(); varItr != vars.end(); ++varItr) numGlobalVars += *varItr;
75 TEUCHOS_ASSERT((numGlobals % numGlobalVars) == 0);
76 TEUCHOS_ASSERT((numMyElements % numGlobalVars) == 0);
77 TEUCHOS_ASSERT((minMyGID % numGlobalVars) == 0);
79 LO numBlocks = numMyElements / numGlobalVars;
80 GO minBlockID = minMyGID / numGlobalVars;
86 for (varItr = vars.begin(); varItr != vars.end(); ++varItr) {
87 LO numLocalVars = *varItr;
88 GO numAllElmts = numLocalVars * numGlobals / numGlobalVars;
90 LO numMyElmts = numLocalVars * numBlocks;
94 std::vector<GO> subGlobals;
95 std::vector<GO> contigGlobals;
99 for (LO blockNum = 0; blockNum < numBlocks; blockNum++) {
101 for (LO local = 0; local < numLocalVars; ++local) {
105 subGlobals.push_back((minBlockID + blockNum) * numGlobalVars + blockOffset + local);
108 contigGlobals.push_back(numLocalVars * minBlockID + count);
114 assert((
size_t)numMyElmts == subGlobals.size());
117 RCP<Tpetra::Map<LO, GO, NT> > subMap = rcp(
new Tpetra::Map<LO, GO, NT>(
118 numAllElmts, Teuchos::ArrayView<GO>(subGlobals), 0, rcpFromRef(comm)));
119 RCP<Tpetra::Map<LO, GO, NT> > contigMap = rcp(
new Tpetra::Map<LO, GO, NT>(
120 numAllElmts, Teuchos::ArrayView<GO>(contigGlobals), 0, rcpFromRef(comm)));
122 Teuchos::set_extra_data(contigMap,
"contigMap", Teuchos::inOutArg(subMap));
123 subMaps.push_back(std::make_pair(numLocalVars, subMap));
126 blockOffset += numLocalVars;
130void buildExportImport(
const Tpetra::Map<LO, GO, NT>& baseMap,
131 const std::vector<std::pair<
int, RCP<Tpetra::Map<LO, GO, NT> > > >& subMaps,
132 std::vector<RCP<Tpetra::Export<LO, GO, NT> > >& subExport,
133 std::vector<RCP<Tpetra::Import<LO, GO, NT> > >& subImport) {
134 std::vector<std::pair<int, RCP<Tpetra::Map<LO, GO, NT> > > >::const_iterator mapItr;
137 for (mapItr = subMaps.begin(); mapItr != subMaps.end(); ++mapItr) {
139 const Tpetra::Map<LO, GO, NT>& map = *(mapItr->second);
142 subImport.push_back(rcp(
new Tpetra::Import<LO, GO, NT>(rcpFromRef(baseMap), rcpFromRef(map))));
143 subExport.push_back(rcp(
new Tpetra::Export<LO, GO, NT>(rcpFromRef(map), rcpFromRef(baseMap))));
147void buildSubVectors(
const std::vector<std::pair<
int, RCP<Tpetra::Map<LO, GO, NT> > > >& subMaps,
148 std::vector<RCP<Tpetra::MultiVector<ST, LO, GO, NT> > >& subVectors,
150 std::vector<std::pair<int, RCP<Tpetra::Map<LO, GO, NT> > > >::const_iterator mapItr;
153 for (mapItr = subMaps.begin(); mapItr != subMaps.end(); ++mapItr) {
155 const Tpetra::Map<LO, GO, NT>& map =
156 *(Teuchos::get_extra_data<RCP<Tpetra::Map<LO, GO, NT> > >(mapItr->second,
"contigMap"));
159 RCP<Tpetra::MultiVector<ST, LO, GO, NT> > mv =
160 rcp(
new Tpetra::MultiVector<ST, LO, GO, NT>(rcpFromRef(map), count));
161 Teuchos::set_extra_data(mapItr->second,
"globalMap", Teuchos::inOutArg(mv));
162 subVectors.push_back(mv);
166void associateSubVectors(
167 const std::vector<std::pair<
int, RCP<Tpetra::Map<LO, GO, NT> > > >& subMaps,
168 std::vector<RCP<
const Tpetra::MultiVector<ST, LO, GO, NT> > >& subVectors) {
169 std::vector<std::pair<int, RCP<Tpetra::Map<LO, GO, NT> > > >::const_iterator mapItr;
170 std::vector<RCP<const Tpetra::MultiVector<ST, LO, GO, NT> > >::iterator vecItr;
172 TEUCHOS_ASSERT(subMaps.size() == subVectors.size());
175 for (mapItr = subMaps.begin(), vecItr = subVectors.begin(); mapItr != subMaps.end();
177 Teuchos::set_extra_data(mapItr->second,
"globalMap", Teuchos::inOutArg(*vecItr),
178 Teuchos::POST_DESTROY,
false);
182RCP<Tpetra::CrsMatrix<ST, LO, GO, NT> > buildSubBlock(
183 int i,
int j,
const RCP<
const Tpetra::CrsMatrix<ST, LO, GO, NT> >& A,
184 const std::vector<std::pair<
int, RCP<Tpetra::Map<LO, GO, NT> > > >& subMaps) {
186 int numVarFamily = subMaps.size();
188 TEUCHOS_ASSERT(i >= 0 && i < numVarFamily);
189 TEUCHOS_ASSERT(j >= 0 && j < numVarFamily);
191 const Tpetra::Map<LO, GO, NT>& gRowMap = *subMaps[i].second;
192 const RCP<const Tpetra::Map<LO, GO, NT> > rowMap =
193 Teuchos::get_extra_data<RCP<Tpetra::Map<LO, GO, NT> > >(subMaps[i].second,
"contigMap");
194 const RCP<const Tpetra::Map<LO, GO, NT> > domainMap =
195 Teuchos::get_extra_data<RCP<Tpetra::Map<LO, GO, NT> > >(subMaps[j].second,
"contigMap");
196 const RCP<const Tpetra::Map<LO, GO, NT> > rangeMap = rowMap;
197 GO colFamilyCnt = subMaps[j].first;
201 GO numGlobalVars = 0;
202 GO rowBlockOffset = 0;
203 GO colBlockOffset = 0;
204 for (
int k = 0; k < numVarFamily; k++) {
205 numGlobalVars += subMaps[k].first;
208 if (k < i) rowBlockOffset += subMaps[k].first;
209 if (k < j) colBlockOffset += subMaps[k].first;
220 LO numMyRows = rowMap->getLocalNumElements();
222 using local_matrix_type = Tpetra::CrsMatrix<ST, LO, GO, NT>::local_matrix_device_type;
223 using row_map_type = local_matrix_type::row_map_type::non_const_type;
224 using values_type = local_matrix_type::values_type::non_const_type;
225 using index_type = local_matrix_type::index_type::non_const_type;
226 using matrix_execution_space =
typename local_matrix_type::execution_space;
227 using device_type =
typename NT::device_type;
229 auto A_dev = A->getLocalMatrixDevice();
230 auto gRowMap_dev = gRowMap.getLocalMap();
231 auto A_rowmap_dev = A->getRowMap()->getLocalMap();
232 auto A_colmap_dev = A->getColMap()->getLocalMap();
236 auto prefixSumEntriesPerRow = row_map_type(
237 Kokkos::ViewAllocateWithoutInitializing(
"prefixSumEntriesPerRow"), numMyRows + 1);
239 LO totalNumOwnedCols = 0;
240 Kokkos::parallel_scan(
241 Kokkos::RangePolicy<Kokkos::Schedule<Kokkos::Dynamic>, matrix_execution_space>(0, numMyRows),
242 KOKKOS_LAMBDA(
const LO localRow, LO& sumNumEntries,
bool finalPass) {
243 GO globalRow = gRowMap_dev.getGlobalElement(localRow);
244 LO lid = A_rowmap_dev.getLocalElement(globalRow);
245 const auto sparseRowView = A_dev.row(lid);
248 for (
auto localCol = 0; localCol < sparseRowView.length; localCol++) {
249 GO globalCol = A_colmap_dev.getGlobalElement(sparseRowView.colidx(localCol));
250 GO block = globalCol / numGlobalVars;
251 bool inFamily = (block * numGlobalVars + colBlockOffset <= globalCol) &&
252 ((block * numGlobalVars + colBlockOffset + colFamilyCnt) > globalCol);
253 if (inFamily) numOwnedCols++;
257 prefixSumEntriesPerRow(localRow) = sumNumEntries;
258 if (localRow == (numMyRows - 1))
259 prefixSumEntriesPerRow(numMyRows) = sumNumEntries + numOwnedCols;
261 sumNumEntries += numOwnedCols;
265 auto columnIndices = Kokkos::View<GO*, device_type>(
266 Kokkos::ViewAllocateWithoutInitializing(
"columnIndices"), totalNumOwnedCols);
267 auto values = values_type(Kokkos::ViewAllocateWithoutInitializing(
"values"), totalNumOwnedCols);
270 LO maxNumEntriesSubblock = 0;
271 Kokkos::parallel_reduce(
272 Kokkos::RangePolicy<Kokkos::Schedule<Kokkos::Dynamic>, matrix_execution_space>(0, numMyRows),
273 KOKKOS_LAMBDA(
const LO localRow, LO& maxNumEntries) {
274 GO globalRow = gRowMap_dev.getGlobalElement(localRow);
275 LO lid = A_rowmap_dev.getLocalElement(globalRow);
276 const auto sparseRowView = A_dev.row(lid);
279 LO colIdStart = prefixSumEntriesPerRow[localRow];
280 for (
auto localCol = 0; localCol < sparseRowView.length; localCol++) {
281 GO globalCol = A_colmap_dev.getGlobalElement(sparseRowView.colidx(localCol));
282 GO block = globalCol / numGlobalVars;
283 bool inFamily = (block * numGlobalVars + colBlockOffset <= globalCol) &&
284 ((block * numGlobalVars + colBlockOffset + colFamilyCnt) > globalCol);
285 if (!inFamily)
continue;
287 GO familyOffset = globalCol - (block * numGlobalVars + colBlockOffset);
288 columnIndices(colId + colIdStart) = block * colFamilyCnt + familyOffset;
289 values(colId + colIdStart) = sparseRowView.value(localCol);
292 maxNumEntries = Kokkos::max(maxNumEntries, colId);
294 Kokkos::Max<LO>(maxNumEntriesSubblock));
298 Teuchos::RCP<const Tpetra::Map<LO, GO, NT> > colMap;
299 Tpetra::Details::makeColMap<LO, GO, NT>(colMap, domainMap, columnIndices);
300 TEUCHOS_ASSERT(colMap);
302 auto colMap_dev = colMap->getLocalMap();
303 auto localColumnIndices =
304 index_type(Kokkos::ViewAllocateWithoutInitializing(
"localColumnIndices"), totalNumOwnedCols);
305 Kokkos::parallel_for(
306 Kokkos::RangePolicy<Kokkos::Schedule<Kokkos::Dynamic>, matrix_execution_space>(
307 0, totalNumOwnedCols),
308 KOKKOS_LAMBDA(
const LO index) {
309 localColumnIndices(index) = colMap_dev.getLocalElement(columnIndices(index));
312 KokkosSparse::sort_crs_matrix<matrix_execution_space, row_map_type, index_type, values_type>(
313 prefixSumEntriesPerRow, localColumnIndices, values);
315 auto lcl_mat = Tpetra::CrsMatrix<ST, LO, GO, NT>::local_matrix_device_type(
316 "localMat", numMyRows, maxNumEntriesSubblock, totalNumOwnedCols, values,
317 prefixSumEntriesPerRow, localColumnIndices);
319 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT> > mat =
320 rcp(
new Tpetra::CrsMatrix<ST, LO, GO, NT>(lcl_mat, rowMap, colMap, domainMap, rangeMap));
326void rebuildSubBlock(
int i,
int j,
const RCP<
const Tpetra::CrsMatrix<ST, LO, GO, NT> >& A,
327 const std::vector<std::pair<
int, RCP<Tpetra::Map<LO, GO, NT> > > >& subMaps,
328 Tpetra::CrsMatrix<ST, LO, GO, NT>& mat) {
330 int numVarFamily = subMaps.size();
332 TEUCHOS_ASSERT(i >= 0 && i < numVarFamily);
333 TEUCHOS_ASSERT(j >= 0 && j < numVarFamily);
334 TEUCHOS_ASSERT(mat.isFillComplete());
336 const Tpetra::Map<LO, GO, NT>& gRowMap = *subMaps[i].second;
337 const Tpetra::Map<LO, GO, NT>& rowMap =
338 *Teuchos::get_extra_data<RCP<Tpetra::Map<LO, GO, NT> > >(subMaps[i].second,
"contigMap");
339 const Tpetra::Map<LO, GO, NT>& colMap =
340 *Teuchos::get_extra_data<RCP<Tpetra::Map<LO, GO, NT> > >(subMaps[j].second,
"contigMap");
341 GO colFamilyCnt = subMaps[j].first;
345 GO numGlobalVars = 0;
346 GO rowBlockOffset = 0;
347 GO colBlockOffset = 0;
348 for (
int k = 0; k < numVarFamily; k++) {
349 numGlobalVars += subMaps[k].first;
352 if (k < i) rowBlockOffset += subMaps[k].first;
353 if (k < j) colBlockOffset += subMaps[k].first;
358 mat.setAllToScalar(0.0);
361 LO numMyRows = rowMap.getLocalNumElements();
373 using matrix_execution_space =
374 typename Tpetra::CrsMatrix<ST, LO, GO, NT>::local_matrix_device_type::execution_space;
376 auto A_dev = A->getLocalMatrixDevice();
377 auto mat_dev = mat.getLocalMatrixDevice();
378 auto gRowMap_dev = gRowMap.getLocalMap();
379 auto A_rowmap_dev = A->getRowMap()->getLocalMap();
380 auto A_colmap_dev = A->getColMap()->getLocalMap();
381 auto matColMap_dev = mat.getColMap()->getLocalMap();
383 const auto invalidLO = Teuchos::OrdinalTraits<LO>::invalid();
385 Kokkos::parallel_for(
386 Kokkos::RangePolicy<Kokkos::Schedule<Kokkos::Dynamic>, matrix_execution_space>(0, numMyRows),
387 KOKKOS_LAMBDA(
const LO localRow) {
388 GO globalRow = gRowMap_dev.getGlobalElement(localRow);
389 LO lid = A_rowmap_dev.getLocalElement(globalRow);
390 const auto sparseRowView = A_dev.row(lid);
392 for (
auto localCol = 0; localCol < sparseRowView.length; localCol++) {
393 GO globalCol = A_colmap_dev.getGlobalElement(sparseRowView.colidx(localCol));
396 GO block = globalCol / numGlobalVars;
399 bool inFamily = (block * numGlobalVars + colBlockOffset <= globalCol) &&
400 ((block * numGlobalVars + colBlockOffset + colFamilyCnt) > globalCol);
401 if (!inFamily)
continue;
403 GO familyOffset = globalCol - (block * numGlobalVars + colBlockOffset);
404 GO contigCol = block * colFamilyCnt + familyOffset;
406 LO lidCol = matColMap_dev.getLocalElement(contigCol);
407 if (lidCol == invalidLO)
continue;
409 auto value = sparseRowView.value(localCol);
410 mat_dev.sumIntoValues(localRow, &lidCol, 1, &value,
true,
false);
414 mat.fillComplete(rcpFromRef(colMap), rcpFromRef(rowMap));
418void many2one(Tpetra::MultiVector<ST, LO, GO, NT>& one,
419 const std::vector<RCP<
const Tpetra::MultiVector<ST, LO, GO, NT> > >& many,
420 const std::vector<RCP<Tpetra::Export<LO, GO, NT> > >& subExport) {
422 std::vector<RCP<const Tpetra::MultiVector<ST, LO, GO, NT> > >::const_iterator vecItr;
423 std::vector<RCP<Tpetra::Export<LO, GO, NT> > >::const_iterator expItr;
426 for (vecItr = many.begin(), expItr = subExport.begin(); vecItr != many.end();
427 ++vecItr, ++expItr) {
429 RCP<const Tpetra::MultiVector<ST, LO, GO, NT> > srcVec = *vecItr;
432 const Tpetra::Map<LO, GO, NT>& globalMap =
433 *(Teuchos::get_extra_data<RCP<Tpetra::Map<LO, GO, NT> > >(srcVec,
"globalMap"));
436 GO lda = srcVec->getStride();
437 GO srcSize = srcVec->getGlobalLength() * srcVec->getNumVectors();
438 std::vector<ST> srcArray(srcSize);
439 Teuchos::ArrayView<ST> srcVals(srcArray);
440 srcVec->get1dCopy(srcVals, lda);
441 Tpetra::MultiVector<ST, LO, GO, NT> exportVector(rcpFromRef(globalMap), srcVals, lda,
442 srcVec->getNumVectors());
445 one.doExport(exportVector, **expItr, Tpetra::INSERT);
450void one2many(std::vector<RCP<Tpetra::MultiVector<ST, LO, GO, NT> > >& many,
451 const Tpetra::MultiVector<ST, LO, GO, NT>& single,
452 const std::vector<RCP<Tpetra::Import<LO, GO, NT> > >& subImport) {
454 std::vector<RCP<Tpetra::MultiVector<ST, LO, GO, NT> > >::const_iterator vecItr;
455 std::vector<RCP<Tpetra::Import<LO, GO, NT> > >::const_iterator impItr;
458 for (vecItr = many.begin(), impItr = subImport.begin(); vecItr != many.end();
459 ++vecItr, ++impItr) {
461 RCP<Tpetra::MultiVector<ST, LO, GO, NT> > destVec = *vecItr;
464 const Tpetra::Map<LO, GO, NT>& globalMap =
465 *(Teuchos::get_extra_data<RCP<Tpetra::Map<LO, GO, NT> > >(destVec,
"globalMap"));
468 GO destLDA = destVec->getStride();
469 GO destSize = destVec->getGlobalLength() * destVec->getNumVectors();
470 std::vector<ST> destArray(destSize);
471 Teuchos::ArrayView<ST> destVals(destArray);
472 destVec->get1dCopy(destVals, destLDA);
473 Tpetra::MultiVector<ST, LO, GO, NT> importVector(rcpFromRef(globalMap), destVals, destLDA,
474 destVec->getNumVectors());
477 importVector.doImport(single, **impItr, Tpetra::INSERT);
479 Tpetra::Import<LO, GO, NT> importer(destVec->getMap(), destVec->getMap());
480 importVector.replaceMap(destVec->getMap());
481 destVec->doImport(importVector, importer, Tpetra::INSERT);