Teko  Version of the Day
 All Classes Files Functions Variables Pages
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 
29 using Teuchos::null;
30 using Teuchos::Ptr;
31 using Teuchos::ptr_dynamic_cast;
32 using Teuchos::RCP;
33 using Teuchos::rcp;
34 using Teuchos::rcp_dynamic_cast;
35 using Teuchos::rcpFromRef;
36 
37 namespace Teko {
38 namespace 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 
44 void 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 
97 void 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)
122 void 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 
157 void 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 
215 void 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)
243 void 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 
283 void 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
328 const 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