Teko Version of the Day
Loading...
Searching...
No Matches
Teko_TpetraThyraConverter.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_TpetraThyraConverter.hpp"
11#include "Tpetra_Core.hpp"
12
13// Teuchos includes
14#include "Teuchos_Array.hpp"
15#include "Teuchos_ArrayRCP.hpp"
16
17// Thyra includes
18#include "Thyra_DefaultProductVectorSpace.hpp"
19#include "Thyra_DefaultProductMultiVector.hpp"
20#include "Thyra_SpmdMultiVectorBase.hpp"
21#include "Thyra_SpmdVectorSpaceBase.hpp"
22#include "Thyra_MultiVectorStdOps.hpp"
23
24#include "Thyra_TpetraMultiVector.hpp"
25
26#include <iostream>
27#include <vector>
28
29using Teuchos::null;
30using Teuchos::Ptr;
31using Teuchos::ptr_dynamic_cast;
32using Teuchos::RCP;
33using Teuchos::rcp;
34using Teuchos::rcp_dynamic_cast;
35using Teuchos::rcpFromRef;
36
37namespace Teko {
38namespace TpetraHelpers {
39
40// const Teuchos::RCP<const Thyra::MultiVectorBase<double> >
41// blockTpetraToThyra(int numVectors,const double * tpetraData,int leadingDim,const
42// Teuchos::RCP<const Thyra::VectorSpaceBase<double> > & vs,int & localDim)
43
44void blockTpetraToThyra(int numVectors, Teuchos::ArrayRCP<const ST> tpetraData, int leadingDim,
45 const Teuchos::Ptr<Thyra::MultiVectorBase<ST>>& mv, int& localDim) {
46 localDim = 0;
47
48 // check the base case
49 const Ptr<Thyra::ProductMultiVectorBase<ST>> prodMV =
50 ptr_dynamic_cast<Thyra::ProductMultiVectorBase<ST>>(mv);
51 if (prodMV == Teuchos::null) {
52 // VS object must be a SpmdMultiVector object
53 const Ptr<Thyra::SpmdMultiVectorBase<ST>> spmdX =
54 ptr_dynamic_cast<Thyra::SpmdMultiVectorBase<ST>>(mv, true);
55 const RCP<const Thyra::SpmdVectorSpaceBase<ST>> spmdVS = spmdX->spmdSpace();
56
57 int localSubDim = spmdVS->localSubDim();
58
59 Thyra::Ordinal thyraLeadingDim = 0;
60
61 Teuchos::ArrayRCP<ST> thyraData_arcp;
62 Teuchos::ArrayView<ST> thyraData;
63 spmdX->getNonconstLocalData(Teuchos::outArg(thyraData_arcp), Teuchos::outArg(thyraLeadingDim));
64 thyraData = thyraData_arcp(); // build array view
65
66 for (int i = 0; i < localSubDim; i++) {
67 // copy each vector
68 for (int v = 0; v < numVectors; v++)
69 thyraData[i + thyraLeadingDim * v] = tpetraData[i + leadingDim * v];
70 }
71
72 // set the local dimension
73 localDim = localSubDim;
74
75 return;
76 }
77
78 // this keeps track of current location in the tpetraData vector
79 Teuchos::ArrayRCP<const ST> localData = tpetraData;
80
81 // loop over all the blocks in the vector space
82 for (int blkIndex = 0; blkIndex < prodMV->productSpace()->numBlocks(); blkIndex++) {
83 int subDim = 0;
84 const RCP<Thyra::MultiVectorBase<ST>> blockVec = prodMV->getNonconstMultiVectorBlock(blkIndex);
85
86 // perform the recusive copy
87 blockTpetraToThyra(numVectors, localData, leadingDim, blockVec.ptr(), subDim);
88
89 // shift to the next block
90 localData += subDim;
91
92 // account for the size of this subblock
93 localDim += subDim;
94 }
95}
96
97void blockTpetraToThyraTpetraVec(const Tpetra::MultiVector<ST, LO, GO, NT>& tpetraX,
98 const Teuchos::Ptr<Thyra::ProductMultiVectorBase<ST>>& prodMV) {
99 auto view = tpetraX.getLocalViewDevice(Tpetra::Access::ReadOnly);
100
101 // loop over all the blocks in the vector space
102 size_t offset = 0;
103 const auto numBlocks = prodMV->productSpace()->numBlocks();
104 for (int blkIndex = 0; blkIndex < numBlocks; blkIndex++) {
105 const auto blockVec = prodMV->getNonconstMultiVectorBlock(blkIndex);
106 const auto blockMV = rcp_dynamic_cast<Thyra::TpetraMultiVector<ST, LO, GO, NT>>(blockVec, true)
107 ->getTpetraMultiVector();
108
109 auto blockView = blockMV->getLocalViewDevice(Tpetra::Access::OverwriteAll);
110 auto subView =
111 Kokkos::subview(view, Kokkos::pair(offset, blockView.extent(0) + offset), Kokkos::ALL);
112 Kokkos::deep_copy(decltype(blockView)::execution_space{}, blockView, subView);
113
114 offset += blockView.extent(0);
115 }
116}
117
118// Convert a Tpetra_MultiVector with assumed block structure dictated by the
119// vector space into a Thyra::MultiVectorBase object.
120// const Teuchos::RCP<const Thyra::MultiVectorBase<double> > blockTpetraToThyra(const
121// Tpetra_MultiVector & e,const Teuchos::RCP<const Thyra::VectorSpaceBase<double> > & vs)
122void blockTpetraToThyra(const Tpetra::MultiVector<ST, LO, GO, NT>& tpetraX,
123 const Teuchos::Ptr<Thyra::MultiVectorBase<ST>>& thyraX) {
124 TEUCHOS_ASSERT((Tpetra::global_size_t)thyraX->range()->dim() == tpetraX.getGlobalLength());
125
126 const auto prodMV = ptr_dynamic_cast<Thyra::ProductMultiVectorBase<ST>>(thyraX);
127 bool allTpetra = [&]() {
128 if (prodMV == Teuchos::null) return false;
129
130 for (int blkIndex = 0; blkIndex < prodMV->productSpace()->numBlocks(); blkIndex++) {
131 const auto blockVec = prodMV->getNonconstMultiVectorBlock(blkIndex);
132 const auto blockMV =
133 Teuchos::rcp_dynamic_cast<Thyra::TpetraMultiVector<ST, LO, GO, NT>>(blockVec);
134 if (blockMV == Teuchos::null) return false;
135 }
136
137 return true;
138 }();
139
140 if (allTpetra) {
141 blockTpetraToThyraTpetraVec(tpetraX, prodMV);
142 return;
143 }
144
145 // extract local information from the Tpetra_MultiVector
146 LO leadingDim = 0, localDim = 0;
147 leadingDim = tpetraX.getStride();
148 Teuchos::ArrayRCP<const ST> tpetraData = tpetraX.get1dView();
149
150 int numVectors = tpetraX.getNumVectors();
151
152 blockTpetraToThyra(numVectors, tpetraData, leadingDim, thyraX.ptr(), localDim);
153
154 TEUCHOS_ASSERT((size_t)localDim == tpetraX.getLocalLength());
155}
156
157void blockThyraToTpetra(LO numVectors, Teuchos::ArrayRCP<ST> tpetraData, LO leadingDim,
158 const Teuchos::RCP<const Thyra::MultiVectorBase<ST>>& tX, LO& localDim) {
159 localDim = 0;
160
161 // check the base case
162 const RCP<const Thyra::ProductMultiVectorBase<ST>> prodX =
163 rcp_dynamic_cast<const Thyra::ProductMultiVectorBase<ST>>(tX);
164 if (prodX == Teuchos::null) {
165 // the base case
166
167 // VS object must be a SpmdMultiVector object
168 RCP<const Thyra::SpmdMultiVectorBase<ST>> spmdX =
169 rcp_dynamic_cast<const Thyra::SpmdMultiVectorBase<ST>>(tX, true);
170 RCP<const Thyra::SpmdVectorSpaceBase<ST>> spmdVS = spmdX->spmdSpace();
171
172 Thyra::Ordinal thyraLeadingDim = 0;
173 Teuchos::ArrayView<const ST> thyraData;
174 Teuchos::ArrayRCP<const ST> thyraData_arcp;
175 spmdX->getLocalData(Teuchos::outArg(thyraData_arcp), Teuchos::outArg(thyraLeadingDim));
176 thyraData = thyraData_arcp(); // grab the array view
177
178 LO localSubDim = spmdVS->localSubDim();
179 for (LO i = 0; i < localSubDim; i++) {
180 // copy each vector
181 for (LO v = 0; v < numVectors; v++) {
182 tpetraData[i + leadingDim * v] = thyraData[i + thyraLeadingDim * v];
183 }
184 }
185
186 // set the local dimension
187 localDim = localSubDim;
188
189 return;
190 }
191
192 const RCP<const Thyra::ProductVectorSpaceBase<ST>> prodVS = prodX->productSpace();
193
194 // this keeps track of current location in the tpetraData vector
195 Teuchos::ArrayRCP<ST> localData = tpetraData;
196
197 // loop over all the blocks in the vector space
198 for (int blkIndex = 0; blkIndex < prodVS->numBlocks(); blkIndex++) {
199 int subDim = 0;
200
201 // construct the block vector
202 blockThyraToTpetra(numVectors, localData, leadingDim, prodX->getMultiVectorBlock(blkIndex),
203 subDim);
204
205 // shift to the next block
206 localData += subDim;
207
208 // account for the size of this subblock
209 localDim += subDim;
210 }
211
212 return;
213}
214
215void blockThyraToTpetraTpetraVec(
216 const Teuchos::RCP<const Thyra::ProductMultiVectorBase<ST>>& prodMV,
217 Tpetra::MultiVector<ST, LO, GO, NT>& tpetraX) {
218 auto view = tpetraX.getLocalViewDevice(Tpetra::Access::OverwriteAll);
219
220 // loop over all the blocks in the vector space
221 size_t offset = 0;
222 const auto numBlocks = prodMV->productSpace()->numBlocks();
223 for (int blkIndex = 0; blkIndex < numBlocks; blkIndex++) {
224 const auto blockVec = prodMV->getMultiVectorBlock(blkIndex);
225 const auto blockMV =
226 rcp_dynamic_cast<const Thyra::TpetraMultiVector<ST, LO, GO, NT>>(blockVec, true)
227 ->getConstTpetraMultiVector();
228
229 auto blockView = blockMV->getLocalViewDevice(Tpetra::Access::ReadOnly);
230 auto subView =
231 Kokkos::subview(view, Kokkos::pair(offset, blockView.extent(0) + offset), Kokkos::ALL);
232 Kokkos::deep_copy(decltype(blockView)::execution_space{}, subView, blockView);
233
234 offset += blockView.extent(0);
235 }
236}
237
238// Convert a Thyra::MultiVectorBase object to a Tpetra_MultiVector object with
239// the map defined by the Tpetra_Map.
240// const Teuchos::RCP<const Tpetra_MultiVector>
241// blockThyraToTpetra(const Teuchos::RCP<const Thyra::MultiVectorBase<double> > & tX,const RCP<const
242// Tpetra_Map> & map)
243void blockThyraToTpetra(const Teuchos::RCP<const Thyra::MultiVectorBase<ST>>& thyraX,
244 Tpetra::MultiVector<ST, LO, GO, NT>& tpetraX) {
245 const auto prodMV = rcp_dynamic_cast<const Thyra::ProductMultiVectorBase<ST>>(thyraX);
246 bool allTpetra = [&]() {
247 if (prodMV == Teuchos::null) return false;
248
249 for (int blkIndex = 0; blkIndex < prodMV->productSpace()->numBlocks(); blkIndex++) {
250 const auto blockVec = prodMV->getMultiVectorBlock(blkIndex);
251 const auto blockMV =
252 Teuchos::rcp_dynamic_cast<const Thyra::TpetraMultiVector<ST, LO, GO, NT>>(blockVec);
253 if (blockMV == Teuchos::null) return false;
254 }
255
256 return true;
257 }();
258
259 if (allTpetra) {
260 blockThyraToTpetraTpetraVec(prodMV, tpetraX);
261 return;
262 }
263
264 // build an Tpetra_MultiVector object
265 LO numVectors = thyraX->domain()->dim();
266
267 // make sure the number of vectors are the same
268 TEUCHOS_ASSERT((size_t)numVectors == tpetraX.getNumVectors());
269 TEUCHOS_ASSERT((Tpetra::global_size_t)thyraX->range()->dim() == tpetraX.getGlobalLength());
270
271 // extract local information from the Tpetra_MultiVector
272 LO leadingDim = 0, localDim = 0;
273 leadingDim = tpetraX.getStride();
274 Teuchos::ArrayRCP<ST> tpetraData = tpetraX.get1dViewNonConst();
275
276 // perform recursive copy
277 blockThyraToTpetra(numVectors, tpetraData, leadingDim, thyraX, localDim);
278
279 // sanity check
280 TEUCHOS_ASSERT((size_t)localDim == tpetraX.getLocalLength());
281}
282
283void thyraVSToTpetraMap(std::vector<GO>& myIndicies, int blockOffset,
284 const Thyra::VectorSpaceBase<ST>& vs, int& localDim) {
285 // zero out set local dimension
286 localDim = 0;
287
288 const RCP<const Thyra::ProductVectorSpaceBase<ST>> prodVS =
289 rcp_dynamic_cast<const Thyra::ProductVectorSpaceBase<ST>>(rcpFromRef(vs));
290
291 // is more recursion needed?
292 if (prodVS == Teuchos::null) {
293 // base case
294
295 // try to cast to an SPMD capable vector space
296 const RCP<const Thyra::SpmdVectorSpaceBase<ST>> spmdVS =
297 rcp_dynamic_cast<const Thyra::SpmdVectorSpaceBase<ST>>(rcpFromRef(vs));
298 TEUCHOS_TEST_FOR_EXCEPTION(spmdVS == Teuchos::null, std::runtime_error,
299 "thyraVSToTpetraMap requires all subblocks to be SPMD");
300
301 // get local data storage information
302 int localOffset = spmdVS->localOffset();
303 int localSubDim = spmdVS->localSubDim();
304
305 // add indicies to matrix
306 for (int i = 0; i < localSubDim; i++) myIndicies.push_back(blockOffset + localOffset + i);
307
308 localDim += localSubDim;
309
310 return;
311 }
312
313 // loop over all the blocks in the vector space
314 for (int blkIndex = 0; blkIndex < prodVS->numBlocks(); blkIndex++) {
315 int subDim = 0;
316
317 // construct the block vector
318 thyraVSToTpetraMap(myIndicies, blockOffset, *prodVS->getBlock(blkIndex), subDim);
319
320 blockOffset += prodVS->getBlock(blkIndex)->dim();
321
322 // account for the size of this subblock
323 localDim += subDim;
324 }
325}
326
327// From a Thyra vector space create a compatable Tpetra_Map
328const RCP<Tpetra::Map<LO, GO, NT>> thyraVSToTpetraMap(
329 const Thyra::VectorSpaceBase<ST>& vs, const RCP<const Teuchos::Comm<Thyra::Ordinal>>& comm) {
330 int localDim = 0;
331 std::vector<GO> myGIDs;
332
333 // call recursive routine that constructs the mapping
334 thyraVSToTpetraMap(myGIDs, 0, vs, localDim);
335
336 TEUCHOS_ASSERT(myGIDs.size() == (size_t)localDim);
337
338 auto tpetraComm = Thyra::convertThyraToTpetraComm(comm);
339
340 // create the map
341 return rcp(
342 new Tpetra::Map<LO, GO, NT>(vs.dim(), Teuchos::ArrayView<const GO>(myGIDs), 0, tpetraComm));
343}
344
345} // namespace TpetraHelpers
346} // end namespace Teko