Teko  Version of the Day
 All Classes Files Functions Variables Pages
Teko_TpetraBlockedMappingStrategy.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_TpetraBlockedMappingStrategy.hpp"
11 #include "Teko_TpetraHelpers.hpp"
12 
13 #include "Thyra_TpetraThyraWrappers.hpp"
14 #include "Thyra_TpetraLinearOp.hpp"
15 #include "Thyra_DefaultProductMultiVector.hpp"
16 #include "Thyra_DefaultProductVectorSpace.hpp"
17 #include "Thyra_DefaultSpmdMultiVector.hpp"
18 #include "Thyra_DefaultBlockedLinearOp.hpp"
19 
20 using Teuchos::RCP;
21 using Teuchos::rcp;
22 using Teuchos::rcp_dynamic_cast;
23 
24 namespace Teko {
25 namespace TpetraHelpers {
26 
27 // Creates a strided mapping strategy. This class is useful
28 // for breaking up nodally ordered matrices (i.e. the unknowns
29 // in a FEM problem are ordered [u0,v0,p0,u1,v1,p1,...]). Current
30 // implimentation only supports a fixed number of variables
31 //
32 // arguments:
33 // vars - Number of different variables
34 // map - original Tpetra::Map<LO,GO,NT> to be broken up
35 // comm - Teuchos::RCP<Teuchos::Comm<int> > object related to the map
36 //
37 TpetraBlockedMappingStrategy::TpetraBlockedMappingStrategy(
38  const std::vector<std::vector<GO>>& vars,
39  const Teuchos::RCP<const Tpetra::Map<LO, GO, NT>>& map, const Teuchos::Comm<int>& comm) {
40  rangeMap_ = map;
41  domainMap_ = map;
42  buildBlockTransferData(vars, rangeMap_, comm);
43 }
44 
45 // Virtual function defined in MappingStrategy. This copies
46 // an Tpetra::MultiVector<ST,LO,GO,NT> into a Thyra::MultiVectorBase with
47 // blocking handled by the strides defined in the constructor.
48 //
49 // arguments:
50 // X - source Tpetra::MultiVector<ST,LO,GO,NT>
51 // thyra_X - destination Thyra::MultiVectorBase
52 //
53 void TpetraBlockedMappingStrategy::copyTpetraIntoThyra(
54  const Tpetra::MultiVector<ST, LO, GO, NT>& X,
55  const Teuchos::Ptr<Thyra::MultiVectorBase<ST>>& thyra_X) const {
56  if (blockMaps_.empty()) {
57  auto prod_X = Teuchos::ptr_dynamic_cast<Thyra::ProductMultiVectorBase<ST>>(thyra_X);
58  auto vec = rcp_dynamic_cast<Thyra::TpetraMultiVector<ST, LO, GO, NT>>(
59  prod_X->getNonconstMultiVectorBlock(0), true);
60 
61  Teuchos::RCP<Tpetra::MultiVector<ST, LO, GO, NT>> X_rcp_nonconst =
62  Teuchos::rcp_const_cast<Tpetra::MultiVector<ST, LO, GO, NT>>(Teuchos::rcpFromRef(X));
63  fillDefaultSpmdMultiVector(vec, X_rcp_nonconst);
64  return;
65  }
66 
67  int count = X.getNumVectors();
68 
69  std::vector<RCP<Tpetra::MultiVector<ST, LO, GO, NT>>> subX;
70 
71  // allocate vectors to copy into
72  Blocking::buildSubVectors(blockMaps_, subX, count);
73 
74  // copy source vector to X vector
75  Blocking::one2many(subX, X, blockImport_);
76 
77  // convert subX to an array of multi vectors
78  Teuchos::Array<RCP<Thyra::MultiVectorBase<ST>>> thyra_subX;
79  Teuchos::Ptr<Thyra::ProductMultiVectorBase<ST>> prod_X =
80  Teuchos::ptr_dynamic_cast<Thyra::ProductMultiVectorBase<ST>>(thyra_X);
81  for (unsigned int i = 0; i < blockMaps_.size(); i++) {
82  RCP<Thyra::TpetraMultiVector<ST, LO, GO, NT>> vec =
83  rcp_dynamic_cast<Thyra::TpetraMultiVector<ST, LO, GO, NT>>(
84  prod_X->getNonconstMultiVectorBlock(i), true);
85 
86  fillDefaultSpmdMultiVector(vec, subX[i]);
87  }
88 }
89 
90 // Virtual function defined in MappingStrategy. This copies
91 // an Tpetra::MultiVector<ST,LO,GO,NT> into a Thyra::MultiVectorBase with
92 // blocking handled by the strides defined in the constructor.
93 //
94 // arguments:
95 // thyra_Y - source Thyra::MultiVectorBase
96 // Y - destination Tpetra::MultiVector<ST,LO,GO,NT>
97 //
98 void TpetraBlockedMappingStrategy::copyThyraIntoTpetra(
99  const RCP<const Thyra::MultiVectorBase<ST>>& thyra_Y,
100  Tpetra::MultiVector<ST, LO, GO, NT>& Y) const {
101  if (blockMaps_.empty()) {
102  auto prod_Y = rcp_dynamic_cast<const Thyra::DefaultProductMultiVector<ST>>(thyra_Y);
103  auto tmv = rcp_dynamic_cast<const Thyra::TpetraMultiVector<ST, LO, GO, NT>>(
104  prod_Y->getMultiVectorBlock(0), true)
105  ->getConstTpetraMultiVector();
106  Y.assign(*tmv);
107  return;
108  }
109 
110  std::vector<RCP<const Tpetra::MultiVector<ST, LO, GO, NT>>> subY;
111  RCP<const Thyra::DefaultProductMultiVector<ST>> prod_Y =
112  rcp_dynamic_cast<const Thyra::DefaultProductMultiVector<ST>>(thyra_Y);
113 
114  // convert thyra product vector to subY
115  for (unsigned int i = 0; i < blockMaps_.size(); i++) {
116  RCP<const Thyra::TpetraMultiVector<ST, LO, GO, NT>> tmv =
117  rcp_dynamic_cast<const Thyra::TpetraMultiVector<ST, LO, GO, NT>>(
118  prod_Y->getMultiVectorBlock(i), true);
119  subY.push_back(tmv->getConstTpetraMultiVector());
120  }
121 
122  // endow the subVectors with required information about the maps
123  // Blocking::associateSubVectors(blockMaps_,subY);
124 
125  // copy solution vectors to Y vector
126  Blocking::many2one(Y, subY, blockExport_);
127 }
128 
129 // this is the core routine that builds the maps
130 // and importers/exporters neccessary for all the
131 // transfers. Currently it simply calls out to the
132 // interlaced tpetra functions. (Comment: this
133 // routine should probably be private or protected
134 // ... it is basically the meat of the constructor)
135 //
136 // arguments:
137 // vars - Vector describing the blocking of variables
138 // baseMap - basic map to use in the transfers
139 // comm - Teuchos::RCP<Teuchos::Comm<int> > object
140 //
141 void TpetraBlockedMappingStrategy::buildBlockTransferData(
142  const std::vector<std::vector<GO>>& vars,
143  const Teuchos::RCP<const Tpetra::Map<LO, GO, NT>>& baseMap, const Teuchos::Comm<int>& comm) {
144  if (vars.size() == 1) return;
145 
146  // build block for each vector
147  for (std::size_t i = 0; i < vars.size(); i++) {
148  // build maps and exporters/importers
149  Blocking::MapPair mapPair = Blocking::buildSubMap(vars[i], comm);
150  Blocking::ImExPair iePair = Blocking::buildExportImport(*baseMap, mapPair);
151 
152  blockMaps_.push_back(mapPair);
153  blockImport_.push_back(iePair.first);
154  blockExport_.push_back(iePair.second);
155  }
156 }
157 
158 // Builds a blocked Thyra operator that uses the strided
159 // mapping strategy to define sub blocks.
160 //
161 // arguments:
162 // mat - Tpetra::CrsMatrix<ST,LO,GO,NT> with FillComplete called, this
163 // matrix is assumed to be square, with the same
164 // range and domain maps
165 // returns: Blocked Thyra linear operator with sub blocks
166 // defined by this mapping strategy
167 //
168 const Teuchos::RCP<Thyra::BlockedLinearOpBase<ST>>
169 TpetraBlockedMappingStrategy::buildBlockedThyraOp(
170  const RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>>& crsContent,
171  const std::string& label) const {
172  if (blockMaps_.empty()) {
173  RCP<Thyra::DefaultBlockedLinearOp<ST>> A = Thyra::defaultBlockedLinearOp<ST>();
174 
175  auto crsCopy = Teuchos::make_rcp<Tpetra::CrsMatrix<ST, LO, GO, NT>>(*crsContent,
176  Teuchos::DataAccess::View);
177 
178  A->beginBlockFill(1, 1);
179  A->setNonconstBlock(
180  0, 0,
181  Thyra::tpetraLinearOp<ST, LO, GO, NT>(
182  Thyra::tpetraVectorSpace<ST, LO, GO, NT>(crsCopy->getRangeMap()),
183  Thyra::tpetraVectorSpace<ST, LO, GO, NT>(crsCopy->getDomainMap()), crsCopy));
184  A->endBlockFill();
185 
186  return A;
187  }
188 
189  int dim = blockMaps_.size();
190 
191  plocal2ContigGIDs.resize(dim);
192  for (int j = 0; j < dim; j++) {
193  plocal2ContigGIDs[j] = Blocking::getSubBlockColumnGIDs(*crsContent, blockMaps_[j]);
194  }
195 
196  RCP<Thyra::DefaultBlockedLinearOp<ST>> A = Thyra::defaultBlockedLinearOp<ST>();
197 
198  A->beginBlockFill(dim, dim);
199  for (int i = 0; i < dim; i++) {
200  for (int j = 0; j < dim; j++) {
201  // label block correctly
202  std::stringstream ss;
203  ss << label << "_" << i << "," << j;
204 
205  // build the blocks and place it the right location
206  RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> blk =
207  Blocking::buildSubBlock(i, j, crsContent, blockMaps_, plocal2ContigGIDs[j]);
208  A->setNonconstBlock(i, j,
209  Thyra::tpetraLinearOp<ST, LO, GO, NT>(
210  Thyra::tpetraVectorSpace<ST, LO, GO, NT>(blk->getRangeMap()),
211  Thyra::tpetraVectorSpace<ST, LO, GO, NT>(blk->getDomainMap()), blk));
212  }
213  } // end for i
214  A->endBlockFill();
215 
216  return A;
217 }
218 
219 // Rebuilds a blocked Thyra operator that uses the strided
220 // mapping strategy to define sub blocks.
221 //
222 // arguments:
223 // crsContent - Tpetra::CrsMatrix<ST,LO,GO,NT> with FillComplete called, this
224 // matrix is assumed to be square, with the same
225 // range and domain maps
226 // A - Destination block linear op composed of blocks of
227 // Tpetra::CrsMatrix<ST,LO,GO,NT> at all relevant locations
228 //
229 void TpetraBlockedMappingStrategy::rebuildBlockedThyraOp(
230  const RCP<const Tpetra::CrsMatrix<ST, LO, GO, NT>>& crsContent,
231  const RCP<Thyra::BlockedLinearOpBase<ST>>& A) const {
232  if (blockMaps_.empty()) {
233  auto Aij = A->getNonconstBlock(0, 0);
234  auto tAij = rcp_dynamic_cast<Thyra::TpetraLinearOp<ST, LO, GO, NT>>(Aij, true);
235  auto eAij =
236  rcp_dynamic_cast<Tpetra::CrsMatrix<ST, LO, GO, NT>>(tAij->getTpetraOperator(), true);
237  auto values_dest = eAij->getLocalMatrixDevice().values;
238  const auto values_src = crsContent->getLocalMatrixDevice().values;
239  TEUCHOS_DEBUG_ASSERT(eAij->getCrsGraph()->isIdenticalTo(*crsContent->getCrsGraph()));
240  TEUCHOS_DEBUG_ASSERT(values_dest.extent(0) == values_src.extent(0));
241  Kokkos::deep_copy(values_dest, values_src);
242  return;
243  }
244 
245  int dim = blockMaps_.size();
246 
247  for (int i = 0; i < dim; i++) {
248  for (int j = 0; j < dim; j++) {
249  // get Tpetra version of desired block
250  RCP<Thyra::LinearOpBase<ST>> Aij = A->getNonconstBlock(i, j);
251  RCP<Thyra::TpetraLinearOp<ST, LO, GO, NT>> tAij =
252  rcp_dynamic_cast<Thyra::TpetraLinearOp<ST, LO, GO, NT>>(Aij, true);
253  RCP<Tpetra::CrsMatrix<ST, LO, GO, NT>> eAij =
254  rcp_dynamic_cast<Tpetra::CrsMatrix<ST, LO, GO, NT>>(tAij->getTpetraOperator(), true);
255 
256  // rebuild the blocks and place it the right location
257  Blocking::rebuildSubBlock(i, j, crsContent, blockMaps_, *eAij, plocal2ContigGIDs[j]);
258  }
259  } // end for i
260 }
261 
262 } // namespace TpetraHelpers
263 } // end namespace Teko