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