Teko Version of the Day
Loading...
Searching...
No Matches
Teko_InterlacedTpetra.cpp
1// @HEADER
2// *****************************************************************************
3// Teko: A package for block and physics based preconditioning
4//
5// Copyright 2010 NTESS and the Teko contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10#include "Teko_InterlacedTpetra.hpp"
11#include "Tpetra_Import.hpp"
12#include "Tpetra_Details_makeColMap_decl.hpp"
13#include "KokkosSparse_SortCrs.hpp"
14
15#include <vector>
16
17using Teuchos::RCP;
18using Teuchos::rcp;
19
20namespace Teko {
21namespace TpetraHelpers {
22namespace Strided {
23
24// this assumes that there are numGlobals with numVars each interlaced
25// i.e. for numVars = 2 (u,v) then the vector is
26// [u_0,v_0,u_1,v_1,u_2,v_2, ..., u_(numGlobals-1),v_(numGlobals-1)]
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;
30
31 // build vector describing the sub maps
32 for (int i = 0; i < numVars; i++) vars.push_back(1);
33
34 // build all the submaps
35 buildSubMaps(numGlobals, vars, comm, subMaps);
36}
37
38// build maps to make other conversions
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);
44}
45
46// build maps to make other conversions
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;
50
51 // compute total number of variables
52 int numGlobalVars = 0;
53 for (varItr = vars.begin(); varItr != vars.end(); ++varItr) numGlobalVars += *varItr;
54
55 // must be an even number of globals
56 TEUCHOS_ASSERT((numGlobals % numGlobalVars) == 0);
57
58 Tpetra::Map<LO, GO, NT> sampleMap(numGlobals / numGlobalVars, 0, rcpFromRef(comm));
59
60 buildSubMaps(numGlobals, numGlobalVars * sampleMap.getLocalNumElements(),
61 numGlobalVars * sampleMap.getMinGlobalIndex(), vars, comm, subMaps);
62}
63
64// build maps to make other conversions
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;
69
70 // compute total number of variables
71 int numGlobalVars = 0;
72 for (varItr = vars.begin(); varItr != vars.end(); ++varItr) numGlobalVars += *varItr;
73
74 // must be an even number of globals
75 TEUCHOS_ASSERT((numGlobals % numGlobalVars) == 0);
76 TEUCHOS_ASSERT((numMyElements % numGlobalVars) == 0);
77 TEUCHOS_ASSERT((minMyGID % numGlobalVars) == 0);
78
79 LO numBlocks = numMyElements / numGlobalVars;
80 GO minBlockID = minMyGID / numGlobalVars;
81
82 subMaps.clear();
83
84 // index into local block in strided map
85 GO blockOffset = 0;
86 for (varItr = vars.begin(); varItr != vars.end(); ++varItr) {
87 LO numLocalVars = *varItr;
88 GO numAllElmts = numLocalVars * numGlobals / numGlobalVars;
89#ifndef NDEBUG
90 LO numMyElmts = numLocalVars * numBlocks;
91#endif
92
93 // create global arrays describing the as of yet uncreated maps
94 std::vector<GO> subGlobals;
95 std::vector<GO> contigGlobals; // the contiguous globals
96
97 // loop over each block of variables
98 LO count = 0;
99 for (LO blockNum = 0; blockNum < numBlocks; blockNum++) {
100 // loop over each local variable in the block
101 for (LO local = 0; local < numLocalVars; ++local) {
102 // global block number = minGID+blockNum
103 // block begin global id = numGlobalVars*(minGID+blockNum)
104 // global id block offset = blockOffset+local
105 subGlobals.push_back((minBlockID + blockNum) * numGlobalVars + blockOffset + local);
106
107 // also build the contiguous IDs
108 contigGlobals.push_back(numLocalVars * minBlockID + count);
109 count++;
110 }
111 }
112
113 // sanity check
114 assert((size_t)numMyElmts == subGlobals.size());
115
116 // create the map with contiguous elements and the map with global elements
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)));
121
122 Teuchos::set_extra_data(contigMap, "contigMap", Teuchos::inOutArg(subMap));
123 subMaps.push_back(std::make_pair(numLocalVars, subMap));
124
125 // update the block offset
126 blockOffset += numLocalVars;
127 }
128}
129
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;
135
136 // build importers and exporters
137 for (mapItr = subMaps.begin(); mapItr != subMaps.end(); ++mapItr) {
138 // exctract basic map
139 const Tpetra::Map<LO, GO, NT>& map = *(mapItr->second);
140
141 // add new elements to vectors
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))));
144 }
145}
146
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,
149 int count) {
150 std::vector<std::pair<int, RCP<Tpetra::Map<LO, GO, NT> > > >::const_iterator mapItr;
151
152 // build vectors
153 for (mapItr = subMaps.begin(); mapItr != subMaps.end(); ++mapItr) {
154 // exctract basic map
155 const Tpetra::Map<LO, GO, NT>& map =
156 *(Teuchos::get_extra_data<RCP<Tpetra::Map<LO, GO, NT> > >(mapItr->second, "contigMap"));
157
158 // add new elements to vectors
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);
163 }
164}
165
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;
171
172 TEUCHOS_ASSERT(subMaps.size() == subVectors.size());
173
174 // associate the sub vectors with the subMaps
175 for (mapItr = subMaps.begin(), vecItr = subVectors.begin(); mapItr != subMaps.end();
176 ++mapItr, ++vecItr)
177 Teuchos::set_extra_data(mapItr->second, "globalMap", Teuchos::inOutArg(*vecItr),
178 Teuchos::POST_DESTROY, false);
179}
180
181// build a single subblock Tpetra::CrsMatrix
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) {
185 // get the number of variables families
186 int numVarFamily = subMaps.size();
187
188 TEUCHOS_ASSERT(i >= 0 && i < numVarFamily);
189 TEUCHOS_ASSERT(j >= 0 && j < numVarFamily);
190
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;
198
199 // compute the number of global variables
200 // and the row and column block offset
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;
206
207 // compute block offsets
208 if (k < i) rowBlockOffset += subMaps[k].first;
209 if (k < j) colBlockOffset += subMaps[k].first;
210 }
211
212 // Build the sub-block on the device, mirroring the Blocking path.
213 //
214 // The sub-block's rows are a subset of A's rows owned by this same process,
215 // so we read A's local device matrix directly (mapping sub-block global row
216 // -> A local row) instead of importing all rows into a temporary CrsMatrix.
217 // The interlaced column-membership test and contiguous-column renumbering
218 // are pure arithmetic, so the entire extraction runs on the device with no
219 // host<->device transfers and no host-side insertGlobalValues loop.
220 LO numMyRows = rowMap->getLocalNumElements();
221
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;
228
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();
233
234 // Count the entries owned by this sub-block in each row and build the
235 // row-pointer prefix sum in a single scan.
236 auto prefixSumEntriesPerRow = row_map_type(
237 Kokkos::ViewAllocateWithoutInitializing("prefixSumEntriesPerRow"), numMyRows + 1);
238
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);
246
247 LO numOwnedCols = 0;
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++;
254 }
255
256 if (finalPass) {
257 prefixSumEntriesPerRow(localRow) = sumNumEntries;
258 if (localRow == (numMyRows - 1))
259 prefixSumEntriesPerRow(numMyRows) = sumNumEntries + numOwnedCols;
260 }
261 sumNumEntries += numOwnedCols;
262 },
263 totalNumOwnedCols);
264
265 auto columnIndices = Kokkos::View<GO*, device_type>(
266 Kokkos::ViewAllocateWithoutInitializing("columnIndices"), totalNumOwnedCols);
267 auto values = values_type(Kokkos::ViewAllocateWithoutInitializing("values"), totalNumOwnedCols);
268
269 // Extract the contiguous column GIDs and values for each row.
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);
277
278 LO colId = 0;
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;
286
287 GO familyOffset = globalCol - (block * numGlobalVars + colBlockOffset);
288 columnIndices(colId + colIdStart) = block * colFamilyCnt + familyOffset;
289 values(colId + colIdStart) = sparseRowView.value(localCol);
290 colId++;
291 }
292 maxNumEntries = Kokkos::max(maxNumEntries, colId);
293 },
294 Kokkos::Max<LO>(maxNumEntriesSubblock));
295
296 // Build the column map from the contiguous column GIDs, convert to local
297 // column indices, and sort each row.
298 Teuchos::RCP<const Tpetra::Map<LO, GO, NT> > colMap;
299 Tpetra::Details::makeColMap<LO, GO, NT>(colMap, domainMap, columnIndices);
300 TEUCHOS_ASSERT(colMap);
301
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));
310 });
311
312 KokkosSparse::sort_crs_matrix<matrix_execution_space, row_map_type, index_type, values_type>(
313 prefixSumEntriesPerRow, localColumnIndices, values);
314
315 auto lcl_mat = Tpetra::CrsMatrix<ST, LO, GO, NT>::local_matrix_device_type(
316 "localMat", numMyRows, maxNumEntriesSubblock, totalNumOwnedCols, values,
317 prefixSumEntriesPerRow, localColumnIndices);
318
319 RCP<Tpetra::CrsMatrix<ST, LO, GO, NT> > mat =
320 rcp(new Tpetra::CrsMatrix<ST, LO, GO, NT>(lcl_mat, rowMap, colMap, domainMap, rangeMap));
321
322 return mat;
323}
324
325// rebuild a single subblock Tpetra::CrsMatrix
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) {
329 // get the number of variables families
330 int numVarFamily = subMaps.size();
331
332 TEUCHOS_ASSERT(i >= 0 && i < numVarFamily);
333 TEUCHOS_ASSERT(j >= 0 && j < numVarFamily);
334 TEUCHOS_ASSERT(mat.isFillComplete());
335
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;
342
343 // compute the number of global variables
344 // and the row and column block offset
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;
350
351 // compute block offsets
352 if (k < i) rowBlockOffset += subMaps[k].first;
353 if (k < j) colBlockOffset += subMaps[k].first;
354 }
355
356 // clear out the old matrix
357 mat.resumeFill();
358 mat.setAllToScalar(0.0);
359
360 // get entry information
361 LO numMyRows = rowMap.getLocalNumElements();
362
363 // Perform the re-assembly on the device, mirroring the Blocking path.
364 //
365 // The sub-block's rows are a subset of A's rows and are owned by this same
366 // process, so we can read them directly out of A's local device matrix
367 // (mapping sub-block global row -> A local row) instead of doing a redundant
368 // doImport into a temporary CrsMatrix on every rebuild. The interlaced
369 // column-membership test and the contiguous-column renumbering are pure
370 // arithmetic, so the whole loop runs in a single parallel_for with no
371 // host<->device transfers of A's values (which is what made the old,
372 // getGlobalRowCopy/sumIntoGlobalValues host loop expensive on GPU builds).
373 using matrix_execution_space =
374 typename Tpetra::CrsMatrix<ST, LO, GO, NT>::local_matrix_device_type::execution_space;
375
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();
382
383 const auto invalidLO = Teuchos::OrdinalTraits<LO>::invalid();
384
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);
391
392 for (auto localCol = 0; localCol < sparseRowView.length; localCol++) {
393 GO globalCol = A_colmap_dev.getGlobalElement(sparseRowView.colidx(localCol));
394
395 // determine which block this column ID is in
396 GO block = globalCol / numGlobalVars;
397
398 // is this column in the variable family
399 bool inFamily = (block * numGlobalVars + colBlockOffset <= globalCol) &&
400 ((block * numGlobalVars + colBlockOffset + colFamilyCnt) > globalCol);
401 if (!inFamily) continue;
402
403 GO familyOffset = globalCol - (block * numGlobalVars + colBlockOffset);
404 GO contigCol = block * colFamilyCnt + familyOffset;
405
406 LO lidCol = matColMap_dev.getLocalElement(contigCol);
407 if (lidCol == invalidLO) continue;
408
409 auto value = sparseRowView.value(localCol);
410 mat_dev.sumIntoValues(localRow, &lidCol, 1, &value, true, false);
411 }
412 });
413
414 mat.fillComplete(rcpFromRef(colMap), rcpFromRef(rowMap));
415}
416
417// collect subvectors into a single global vector
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) {
421 // std::vector<RCP<const Tpetra::Vector> >::const_iterator vecItr;
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;
424
425 // using Exporters fill the empty vector from the sub-vectors
426 for (vecItr = many.begin(), expItr = subExport.begin(); vecItr != many.end();
427 ++vecItr, ++expItr) {
428 // for ease of access to the source
429 RCP<const Tpetra::MultiVector<ST, LO, GO, NT> > srcVec = *vecItr;
430
431 // extract the map with global indicies from the current vector
432 const Tpetra::Map<LO, GO, NT>& globalMap =
433 *(Teuchos::get_extra_data<RCP<Tpetra::Map<LO, GO, NT> > >(srcVec, "globalMap"));
434
435 // build the export vector as a view of the destination
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());
443
444 // perform the export
445 one.doExport(exportVector, **expItr, Tpetra::INSERT);
446 }
447}
448
449// distribute one global vector into a many subvectors
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) {
453 // std::vector<RCP<Tpetra::Vector> >::const_iterator vecItr;
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;
456
457 // using Importers fill the sub vectors from the mama vector
458 for (vecItr = many.begin(), impItr = subImport.begin(); vecItr != many.end();
459 ++vecItr, ++impItr) {
460 // for ease of access to the destination
461 RCP<Tpetra::MultiVector<ST, LO, GO, NT> > destVec = *vecItr;
462
463 // extract the map with global indicies from the current vector
464 const Tpetra::Map<LO, GO, NT>& globalMap =
465 *(Teuchos::get_extra_data<RCP<Tpetra::Map<LO, GO, NT> > >(destVec, "globalMap"));
466
467 // build the import vector as a view on the destination
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());
475
476 // perform the import
477 importVector.doImport(single, **impItr, Tpetra::INSERT);
478
479 Tpetra::Import<LO, GO, NT> importer(destVec->getMap(), destVec->getMap());
480 importVector.replaceMap(destVec->getMap());
481 destVec->doImport(importVector, importer, Tpetra::INSERT);
482 }
483}
484
485} // namespace Strided
486} // namespace TpetraHelpers
487} // end namespace Teko