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 <iostream>
25 #include <vector>
26 
27 using Teuchos::null;
28 using Teuchos::Ptr;
29 using Teuchos::ptr_dynamic_cast;
30 using Teuchos::RCP;
31 using Teuchos::rcp;
32 using Teuchos::rcp_dynamic_cast;
33 using Teuchos::rcpFromRef;
34 
35 namespace Teko {
36 namespace TpetraHelpers {
37 
38 // const Teuchos::RCP<const Thyra::MultiVectorBase<double> >
39 // blockTpetraToThyra(int numVectors,const double * tpetraData,int leadingDim,const
40 // Teuchos::RCP<const Thyra::VectorSpaceBase<double> > & vs,int & localDim)
41 
42 void blockTpetraToThyra(int numVectors, Teuchos::ArrayRCP<const ST> tpetraData, int leadingDim,
43  const Teuchos::Ptr<Thyra::MultiVectorBase<ST> >& mv, int& localDim) {
44  localDim = 0;
45 
46  // check the base case
47  const Ptr<Thyra::ProductMultiVectorBase<ST> > prodMV =
48  ptr_dynamic_cast<Thyra::ProductMultiVectorBase<ST> >(mv);
49  if (prodMV == Teuchos::null) {
50  // VS object must be a SpmdMultiVector object
51  const Ptr<Thyra::SpmdMultiVectorBase<ST> > spmdX =
52  ptr_dynamic_cast<Thyra::SpmdMultiVectorBase<ST> >(mv, true);
53  const RCP<const Thyra::SpmdVectorSpaceBase<ST> > spmdVS = spmdX->spmdSpace();
54 
55  int localSubDim = spmdVS->localSubDim();
56 
57  Thyra::Ordinal thyraLeadingDim = 0;
58 
59  Teuchos::ArrayRCP<ST> thyraData_arcp;
60  Teuchos::ArrayView<ST> thyraData;
61  spmdX->getNonconstLocalData(Teuchos::outArg(thyraData_arcp), Teuchos::outArg(thyraLeadingDim));
62  thyraData = thyraData_arcp(); // build array view
63 
64  for (int i = 0; i < localSubDim; i++) {
65  // copy each vector
66  for (int v = 0; v < numVectors; v++)
67  thyraData[i + thyraLeadingDim * v] = tpetraData[i + leadingDim * v];
68  }
69 
70  // set the local dimension
71  localDim = localSubDim;
72 
73  return;
74  }
75 
76  // this keeps track of current location in the tpetraData vector
77  Teuchos::ArrayRCP<const ST> localData = tpetraData;
78 
79  // loop over all the blocks in the vector space
80  for (int blkIndex = 0; blkIndex < prodMV->productSpace()->numBlocks(); blkIndex++) {
81  int subDim = 0;
82  const RCP<Thyra::MultiVectorBase<ST> > blockVec = prodMV->getNonconstMultiVectorBlock(blkIndex);
83 
84  // perform the recusive copy
85  blockTpetraToThyra(numVectors, localData, leadingDim, blockVec.ptr(), subDim);
86 
87  // shift to the next block
88  localData += subDim;
89 
90  // account for the size of this subblock
91  localDim += subDim;
92  }
93 }
94 
95 // Convert a Tpetra_MultiVector with assumed block structure dictated by the
96 // vector space into a Thyra::MultiVectorBase object.
97 // const Teuchos::RCP<const Thyra::MultiVectorBase<double> > blockTpetraToThyra(const
98 // Tpetra_MultiVector & e,const Teuchos::RCP<const Thyra::VectorSpaceBase<double> > & vs)
99 void blockTpetraToThyra(const Tpetra::MultiVector<ST, LO, GO, NT>& tpetraX,
100  const Teuchos::Ptr<Thyra::MultiVectorBase<ST> >& thyraX) {
101  TEUCHOS_ASSERT((Tpetra::global_size_t)thyraX->range()->dim() == tpetraX.getGlobalLength());
102 
103  // extract local information from the Tpetra_MultiVector
104  LO leadingDim = 0, localDim = 0;
105  leadingDim = tpetraX.getStride();
106  Teuchos::ArrayRCP<const ST> tpetraData = tpetraX.get1dView();
107 
108  int numVectors = tpetraX.getNumVectors();
109 
110  blockTpetraToThyra(numVectors, tpetraData, leadingDim, thyraX.ptr(), localDim);
111 
112  TEUCHOS_ASSERT((size_t)localDim == tpetraX.getLocalLength());
113 }
114 
115 void blockThyraToTpetra(LO numVectors, Teuchos::ArrayRCP<ST> tpetraData, LO leadingDim,
116  const Teuchos::RCP<const Thyra::MultiVectorBase<ST> >& tX, LO& localDim) {
117  localDim = 0;
118 
119  // check the base case
120  const RCP<const Thyra::ProductMultiVectorBase<ST> > prodX =
121  rcp_dynamic_cast<const Thyra::ProductMultiVectorBase<ST> >(tX);
122  if (prodX == Teuchos::null) {
123  // the base case
124 
125  // VS object must be a SpmdMultiVector object
126  RCP<const Thyra::SpmdMultiVectorBase<ST> > spmdX =
127  rcp_dynamic_cast<const Thyra::SpmdMultiVectorBase<ST> >(tX, true);
128  RCP<const Thyra::SpmdVectorSpaceBase<ST> > spmdVS = spmdX->spmdSpace();
129 
130  Thyra::Ordinal thyraLeadingDim = 0;
131  Teuchos::ArrayView<const ST> thyraData;
132  Teuchos::ArrayRCP<const ST> thyraData_arcp;
133  spmdX->getLocalData(Teuchos::outArg(thyraData_arcp), Teuchos::outArg(thyraLeadingDim));
134  thyraData = thyraData_arcp(); // grab the array view
135 
136  LO localSubDim = spmdVS->localSubDim();
137  for (LO i = 0; i < localSubDim; i++) {
138  // copy each vector
139  for (LO v = 0; v < numVectors; v++) {
140  tpetraData[i + leadingDim * v] = thyraData[i + thyraLeadingDim * v];
141  }
142  }
143 
144  // set the local dimension
145  localDim = localSubDim;
146 
147  return;
148  }
149 
150  const RCP<const Thyra::ProductVectorSpaceBase<ST> > prodVS = prodX->productSpace();
151 
152  // this keeps track of current location in the tpetraData vector
153  Teuchos::ArrayRCP<ST> localData = tpetraData;
154 
155  // loop over all the blocks in the vector space
156  for (int blkIndex = 0; blkIndex < prodVS->numBlocks(); blkIndex++) {
157  int subDim = 0;
158 
159  // construct the block vector
160  blockThyraToTpetra(numVectors, localData, leadingDim, prodX->getMultiVectorBlock(blkIndex),
161  subDim);
162 
163  // shift to the next block
164  localData += subDim;
165 
166  // account for the size of this subblock
167  localDim += subDim;
168  }
169 
170  return;
171 }
172 
173 // Convert a Thyra::MultiVectorBase object to a Tpetra_MultiVector object with
174 // the map defined by the Tpetra_Map.
175 // const Teuchos::RCP<const Tpetra_MultiVector>
176 // blockThyraToTpetra(const Teuchos::RCP<const Thyra::MultiVectorBase<double> > & tX,const RCP<const
177 // Tpetra_Map> & map)
178 void blockThyraToTpetra(const Teuchos::RCP<const Thyra::MultiVectorBase<ST> >& thyraX,
179  Tpetra::MultiVector<ST, LO, GO, NT>& tpetraX) {
180  // build an Tpetra_MultiVector object
181  LO numVectors = thyraX->domain()->dim();
182 
183  // make sure the number of vectors are the same
184  TEUCHOS_ASSERT((size_t)numVectors == tpetraX.getNumVectors());
185  TEUCHOS_ASSERT((Tpetra::global_size_t)thyraX->range()->dim() == tpetraX.getGlobalLength());
186 
187  // extract local information from the Tpetra_MultiVector
188  LO leadingDim = 0, localDim = 0;
189  leadingDim = tpetraX.getStride();
190  Teuchos::ArrayRCP<ST> tpetraData = tpetraX.get1dViewNonConst();
191 
192  // perform recursive copy
193  blockThyraToTpetra(numVectors, tpetraData, leadingDim, thyraX, localDim);
194 
195  // sanity check
196  TEUCHOS_ASSERT((size_t)localDim == tpetraX.getLocalLength());
197 }
198 
199 void thyraVSToTpetraMap(std::vector<GO>& myIndicies, int blockOffset,
200  const Thyra::VectorSpaceBase<ST>& vs, int& localDim) {
201  // zero out set local dimension
202  localDim = 0;
203 
204  const RCP<const Thyra::ProductVectorSpaceBase<ST> > prodVS =
205  rcp_dynamic_cast<const Thyra::ProductVectorSpaceBase<ST> >(rcpFromRef(vs));
206 
207  // is more recursion needed?
208  if (prodVS == Teuchos::null) {
209  // base case
210 
211  // try to cast to an SPMD capable vector space
212  const RCP<const Thyra::SpmdVectorSpaceBase<ST> > spmdVS =
213  rcp_dynamic_cast<const Thyra::SpmdVectorSpaceBase<ST> >(rcpFromRef(vs));
214  TEUCHOS_TEST_FOR_EXCEPTION(spmdVS == Teuchos::null, std::runtime_error,
215  "thyraVSToTpetraMap requires all subblocks to be SPMD");
216 
217  // get local data storage information
218  int localOffset = spmdVS->localOffset();
219  int localSubDim = spmdVS->localSubDim();
220 
221  // add indicies to matrix
222  for (int i = 0; i < localSubDim; i++) myIndicies.push_back(blockOffset + localOffset + i);
223 
224  localDim += localSubDim;
225 
226  return;
227  }
228 
229  // loop over all the blocks in the vector space
230  for (int blkIndex = 0; blkIndex < prodVS->numBlocks(); blkIndex++) {
231  int subDim = 0;
232 
233  // construct the block vector
234  thyraVSToTpetraMap(myIndicies, blockOffset, *prodVS->getBlock(blkIndex), subDim);
235 
236  blockOffset += prodVS->getBlock(blkIndex)->dim();
237 
238  // account for the size of this subblock
239  localDim += subDim;
240  }
241 }
242 
243 // From a Thyra vector space create a compatable Tpetra_Map
244 const RCP<Tpetra::Map<LO, GO, NT> > thyraVSToTpetraMap(
245  const Thyra::VectorSpaceBase<ST>& vs,
246  const RCP<const Teuchos::Comm<Thyra::Ordinal> >& /* comm */) {
247  int localDim = 0;
248  std::vector<GO> myGIDs;
249 
250  // call recursive routine that constructs the mapping
251  thyraVSToTpetraMap(myGIDs, 0, vs, localDim);
252 
253  TEUCHOS_ASSERT(myGIDs.size() == (size_t)localDim);
254 
255  // FIXME (mfh 12 Jul 2018) This ignores the input comm, so it can't
256  // be right.
257 
258  // create the map
259  return rcp(new Tpetra::Map<LO, GO, NT>(vs.dim(), Teuchos::ArrayView<const GO>(myGIDs), 0,
260  Tpetra::getDefaultComm()));
261 }
262 
263 } // namespace TpetraHelpers
264 } // end namespace Teko