Teko Version of the Day
Loading...
Searching...
No Matches
Teko_BlockedReordering.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 <iostream>
11#include <string>
12#include <vector>
13#include <stack>
14
15#include "Teko_BlockedReordering.hpp"
16#include "Teko_Utilities.hpp"
17
18#include "Teuchos_VerboseObject.hpp"
19#include "Teuchos_RCP.hpp"
20#include "Teuchos_StrUtils.hpp"
21
22#include "Thyra_DefaultProductMultiVector.hpp"
23#include "Thyra_DefaultProductVectorSpace.hpp"
24
25using Teuchos::Array;
26using Teuchos::RCP;
27using Teuchos::rcp;
28using Teuchos::rcp_dynamic_cast;
29
30namespace Teko {
31
32void BlockReorderManager::SetBlock(int blockIndex, int reorder) {
33 TEUCHOS_ASSERT(blockIndex < (int)children_.size());
34
35 RCP<BlockReorderManager> child = rcp(new BlockReorderLeaf(reorder));
36
37 children_[blockIndex] = child;
38}
39
52void BlockReorderManager::SetBlock(int blockIndex, const RCP<BlockReorderManager> &reorder) {
53 TEUCHOS_ASSERT(blockIndex < (int)children_.size());
54
55 children_[blockIndex] = reorder;
56}
57
58const Teuchos::RCP<BlockReorderManager> BlockReorderManager::GetBlock(int blockIndex) {
59 TEUCHOS_ASSERT(blockIndex < (int)children_.size());
60
61 if (children_[blockIndex] == Teuchos::null)
62 children_[blockIndex] = rcp(new BlockReorderManager());
63
64 return children_[blockIndex];
65}
66
67const Teuchos::RCP<const BlockReorderManager> BlockReorderManager::GetBlock(int blockIndex) const {
68 TEUCHOS_ASSERT(blockIndex < (int)children_.size());
69
70 return children_[blockIndex];
71}
72
73std::string BlockReorderManager::toString() const {
74 // build the string by recursively calling each child
75 std::stringstream ss;
76 ss << "[";
77 for (unsigned int i = 0; i < children_.size(); i++) {
78 if (children_[i] == Teuchos::null)
79 ss << " <NULL> ";
80 else
81 ss << " " << children_[i]->toString() << " ";
82 }
83 ss << "]";
84
85 return ss.str();
86}
87
89 int max = 0;
90 for (unsigned int i = 0; i < children_.size(); i++) {
91 // see if current child is larger
92 if (children_[i] != Teuchos::null) {
93 int subMax = children_[i]->LargestIndex();
94 max = max > subMax ? max : subMax;
95 }
96 }
97
98 return max;
99}
100
101Teuchos::RCP<const Thyra::LinearOpBase<double> > buildReorderedLinearOp(
102 const BlockReorderManager &bmm,
103 const Teuchos::RCP<const Thyra::BlockedLinearOpBase<double> > &blkOp) {
104 return buildReorderedLinearOp(bmm, bmm, blkOp);
105}
106
107Teuchos::RCP<const Thyra::LinearOpBase<double> > buildReorderedLinearOp(
108 const BlockReorderManager &rowMgr, const BlockReorderManager &colMgr,
109 const Teuchos::RCP<const Thyra::BlockedLinearOpBase<double> > &blkOp) {
110 typedef RCP<const BlockReorderManager> BRMptr;
111
112 int rowSz = rowMgr.GetNumBlocks();
113 int colSz = colMgr.GetNumBlocks();
114
115 if (rowSz == 0 && colSz == 0) {
116 // both are leaf nodes
117 const BlockReorderLeaf &rowLeaf = dynamic_cast<const BlockReorderLeaf &>(rowMgr);
118 const BlockReorderLeaf &colLeaf = dynamic_cast<const BlockReorderLeaf &>(colMgr);
119
120 // simply return entry in matrix
121 Teko::LinearOp linOp = blkOp->getBlock(rowLeaf.GetIndex(), colLeaf.GetIndex());
122
123 // somehow we need to set this operator up
124 if (linOp == Teuchos::null) {
125 linOp = Thyra::zero(blkOp->productRange()->getBlock(rowLeaf.GetIndex()),
126 blkOp->productDomain()->getBlock(colLeaf.GetIndex()));
127 }
128
129 return linOp;
130 } else if (rowSz == 0) {
131 Teko::BlockedLinearOp reBlkOp = Teko::createBlockedOp();
132
133 // operator will be rowSz by colSz
134 reBlkOp->beginBlockFill(1, colSz);
135
136 // fill the column entries
137 for (int col = 0; col < colSz; col++) {
138 BRMptr colPtr = colMgr.GetBlock(col);
139
140 reBlkOp->setBlock(0, col, buildReorderedLinearOp(rowMgr, *colPtr, blkOp));
141 }
142
143 // done building
144 reBlkOp->endBlockFill();
145
146 return reBlkOp;
147 } else if (colSz == 0) {
148 Teko::BlockedLinearOp reBlkOp = Teko::createBlockedOp();
149
150 // operator will be rowSz by colSz
151 reBlkOp->beginBlockFill(rowSz, 1);
152
153 // fill the row entries
154 for (int row = 0; row < rowSz; row++) {
155 BRMptr rowPtr = rowMgr.GetBlock(row);
156
157 reBlkOp->setBlock(row, 0, buildReorderedLinearOp(*rowPtr, colMgr, blkOp));
158 }
159
160 // done building
161 reBlkOp->endBlockFill();
162
163 return reBlkOp;
164 } else {
165 Teko::BlockedLinearOp reBlkOp = Teko::createBlockedOp();
166
167 // this is the general case
168 TEUCHOS_ASSERT(rowSz > 0);
169 TEUCHOS_ASSERT(colSz > 0);
170
171 // operator will be rowSz by colSz
172 reBlkOp->beginBlockFill(rowSz, colSz);
173
174 for (int row = 0; row < rowSz; row++) {
175 BRMptr rowPtr = rowMgr.GetBlock(row);
176
177 for (int col = 0; col < colSz; col++) {
178 BRMptr colPtr = colMgr.GetBlock(col);
179
180 reBlkOp->setBlock(row, col, buildReorderedLinearOp(*rowPtr, *colPtr, blkOp));
181 }
182 }
183
184 // done building
185 reBlkOp->endBlockFill();
186
187 return reBlkOp;
188 }
189}
190
212Teuchos::RCP<const Thyra::VectorSpaceBase<double> > buildReorderedVectorSpace(
213 const BlockReorderManager &mgr,
214 const Teuchos::RCP<const Thyra::ProductVectorSpaceBase<double> > &blkSpc) {
215 typedef RCP<const BlockReorderManager> BRMptr;
216
217 int sz = mgr.GetNumBlocks();
218
219 if (sz == 0) {
220 // its a leaf nodes
221 const BlockReorderLeaf &leaf = dynamic_cast<const BlockReorderLeaf &>(mgr);
222
223 // simply return entry in matrix
224 return blkSpc->getBlock(leaf.GetIndex());
225 } else {
226 Array<RCP<const Thyra::VectorSpaceBase<double> > > vecSpaces;
227
228 // loop over each row
229 for (int i = 0; i < sz; i++) {
230 BRMptr blkMgr = mgr.GetBlock(i);
231
232 const RCP<const Thyra::VectorSpaceBase<double> > lvs =
233 buildReorderedVectorSpace(*blkMgr, blkSpc);
234
235 vecSpaces.push_back(lvs);
236 }
237
238 // build a vector space
239 const RCP<const Thyra::DefaultProductVectorSpace<double> > vs =
240 Thyra::productVectorSpace<double>(vecSpaces);
241
242 // build the vector
243 return vs;
244 }
245}
246
251Teuchos::RCP<Thyra::MultiVectorBase<double> > buildReorderedMultiVector(
252 const BlockReorderManager &mgr,
253 const Teuchos::RCP<Thyra::ProductMultiVectorBase<double> > &blkVec) {
254 typedef RCP<const BlockReorderManager> BRMptr;
255
256 int sz = mgr.GetNumBlocks();
257
258 if (sz == 0) {
259 // its a leaf nodes
260 const BlockReorderLeaf &leaf = dynamic_cast<const BlockReorderLeaf &>(mgr);
261
262 // simply return entry in matrix
263 return blkVec->getNonconstMultiVectorBlock(leaf.GetIndex());
264 } else {
265 Array<RCP<Thyra::MultiVectorBase<double> > > multiVecs;
266 Array<RCP<const Thyra::VectorSpaceBase<double> > > vecSpaces;
267
268 // loop over each row
269 for (int i = 0; i < sz; i++) {
270 BRMptr blkMgr = mgr.GetBlock(i);
271
272 const RCP<Thyra::MultiVectorBase<double> > lmv = buildReorderedMultiVector(*blkMgr, blkVec);
273 const RCP<const Thyra::VectorSpaceBase<double> > lvs = lmv->range();
274
275 multiVecs.push_back(lmv);
276 vecSpaces.push_back(lvs);
277 }
278
279 // build a vector space
280 const RCP<const Thyra::DefaultProductVectorSpace<double> > vs =
281 Thyra::productVectorSpace<double>(vecSpaces);
282
283 // build the vector
284 return Thyra::defaultProductMultiVector<double>(vs, multiVecs);
285 }
286}
287
292Teuchos::RCP<const Thyra::MultiVectorBase<double> > buildReorderedMultiVector(
293 const BlockReorderManager &mgr,
294 const Teuchos::RCP<const Thyra::ProductMultiVectorBase<double> > &blkVec) {
295 typedef RCP<const BlockReorderManager> BRMptr;
296
297 int sz = mgr.GetNumBlocks();
298
299 if (sz == 0) {
300 // its a leaf nodes
301 const BlockReorderLeaf &leaf = dynamic_cast<const BlockReorderLeaf &>(mgr);
302
303 // simply return entry in matrix
304 return blkVec->getMultiVectorBlock(leaf.GetIndex());
305 } else {
306 Array<RCP<const Thyra::MultiVectorBase<double> > > multiVecs;
307 Array<RCP<const Thyra::VectorSpaceBase<double> > > vecSpaces;
308
309 // loop over each row
310 for (int i = 0; i < sz; i++) {
311 BRMptr blkMgr = mgr.GetBlock(i);
312
313 const RCP<const Thyra::MultiVectorBase<double> > lmv =
314 buildReorderedMultiVector(*blkMgr, blkVec);
315 const RCP<const Thyra::VectorSpaceBase<double> > lvs = lmv->range();
316
317 multiVecs.push_back(lmv);
318 vecSpaces.push_back(lvs);
319 }
320
321 // build a vector space
322 const RCP<const Thyra::DefaultProductVectorSpace<double> > vs =
323 Thyra::productVectorSpace<double>(vecSpaces);
324
325 // build the vector
326 return Thyra::defaultProductMultiVector<double>(vs, multiVecs);
327 }
328}
329
333void buildNonconstFlatMultiVector(const BlockReorderManager &mgr,
334 const RCP<Thyra::MultiVectorBase<double> > &blkVec,
335 Array<RCP<Thyra::MultiVectorBase<double> > > &multivecs,
336 Array<RCP<const Thyra::VectorSpaceBase<double> > > &vecspaces) {
337 int sz = mgr.GetNumBlocks();
338
339 if (sz == 0) {
340 // its a leaf nodes
341 const BlockReorderLeaf &leaf = dynamic_cast<const BlockReorderLeaf &>(mgr);
342 int index = leaf.GetIndex();
343
344 // simply return entry in matrix
345 multivecs[index] = blkVec;
346 vecspaces[index] = blkVec->range();
347 } else {
348 const RCP<Thyra::ProductMultiVectorBase<double> > prodMV =
349 rcp_dynamic_cast<Thyra::ProductMultiVectorBase<double> >(blkVec);
350
351 // get flattened elements from each child
352 for (int i = 0; i < sz; i++) {
353 const RCP<Thyra::MultiVectorBase<double> > mv = prodMV->getNonconstMultiVectorBlock(i);
354 buildNonconstFlatMultiVector(*mgr.GetBlock(i), mv, multivecs, vecspaces);
355 }
356 }
357}
358
362void buildFlatMultiVector(const BlockReorderManager &mgr,
363 const RCP<const Thyra::MultiVectorBase<double> > &blkVec,
364 Array<RCP<const Thyra::MultiVectorBase<double> > > &multivecs,
365 Array<RCP<const Thyra::VectorSpaceBase<double> > > &vecspaces) {
366 int sz = mgr.GetNumBlocks();
367
368 if (sz == 0) {
369 // its a leaf nodes
370 const BlockReorderLeaf &leaf = dynamic_cast<const BlockReorderLeaf &>(mgr);
371 int index = leaf.GetIndex();
372
373 // simply return entry in matrix
374 multivecs[index] = blkVec;
375 vecspaces[index] = blkVec->range();
376 } else {
377 const RCP<const Thyra::ProductMultiVectorBase<double> > prodMV =
378 rcp_dynamic_cast<const Thyra::ProductMultiVectorBase<double> >(blkVec);
379
380 // get flattened elements from each child
381 for (int i = 0; i < sz; i++) {
382 RCP<const Thyra::MultiVectorBase<double> > mv = prodMV->getMultiVectorBlock(i);
383 buildFlatMultiVector(*mgr.GetBlock(i), mv, multivecs, vecspaces);
384 }
385 }
386}
387
392Teuchos::RCP<Thyra::MultiVectorBase<double> > buildFlatMultiVector(
393 const BlockReorderManager &mgr,
394 const Teuchos::RCP<Thyra::ProductMultiVectorBase<double> > &blkVec) {
395 int numBlocks = mgr.LargestIndex() + 1;
396
397 Array<RCP<Thyra::MultiVectorBase<double> > > multivecs(numBlocks);
398 Array<RCP<const Thyra::VectorSpaceBase<double> > > vecspaces(numBlocks);
399
400 // flatten everything into a vector first
401 buildNonconstFlatMultiVector(mgr, blkVec, multivecs, vecspaces);
402
403 // build a vector space
404 const RCP<Thyra::DefaultProductVectorSpace<double> > vs =
405 Thyra::productVectorSpace<double>(vecspaces);
406
407 // build the vector
408 return Thyra::defaultProductMultiVector<double>(vs, multivecs);
409}
410
415Teuchos::RCP<const Thyra::MultiVectorBase<double> > buildFlatMultiVector(
416 const BlockReorderManager &mgr,
417 const Teuchos::RCP<const Thyra::ProductMultiVectorBase<double> > &blkVec) {
418 int numBlocks = mgr.LargestIndex() + 1;
419
420 Array<RCP<const Thyra::MultiVectorBase<double> > > multivecs(numBlocks);
421 Array<RCP<const Thyra::VectorSpaceBase<double> > > vecspaces(numBlocks);
422
423 // flatten everything into a vector first
424 buildFlatMultiVector(mgr, blkVec, multivecs, vecspaces);
425
426 // build a vector space
427 const RCP<const Thyra::DefaultProductVectorSpace<double> > vs =
428 Thyra::productVectorSpace<double>(vecspaces);
429
430 // build the vector
431 return Thyra::defaultProductMultiVector<double>(vs, multivecs);
432}
433
437void buildFlatVectorSpace(const BlockReorderManager &mgr,
438 const RCP<const Thyra::VectorSpaceBase<double> > &blkSpc,
439 Array<RCP<const Thyra::VectorSpaceBase<double> > > &vecspaces) {
440 int sz = mgr.GetNumBlocks();
441
442 if (sz == 0) {
443 // its a leaf nodes
444 const BlockReorderLeaf &leaf = dynamic_cast<const BlockReorderLeaf &>(mgr);
445 int index = leaf.GetIndex();
446
447 // simply return entry in matrix
448 vecspaces[index] = blkSpc;
449 } else {
450 const RCP<const Thyra::ProductVectorSpaceBase<double> > prodSpc =
451 rcp_dynamic_cast<const Thyra::ProductVectorSpaceBase<double> >(blkSpc);
452
453 // get flattened elements from each child
454 for (int i = 0; i < sz; i++) {
455 RCP<const Thyra::VectorSpaceBase<double> > space = prodSpc->getBlock(i);
456 buildFlatVectorSpace(*mgr.GetBlock(i), space, vecspaces);
457 }
458 }
459}
460
463Teuchos::RCP<const Thyra::VectorSpaceBase<double> > buildFlatVectorSpace(
464 const BlockReorderManager &mgr,
465 const Teuchos::RCP<const Thyra::VectorSpaceBase<double> > &blkSpc) {
466 int numBlocks = mgr.LargestIndex() + 1;
467
468 Array<RCP<const Thyra::VectorSpaceBase<double> > > vecspaces(numBlocks);
469
470 // flatten everything into a vector first
471 buildFlatVectorSpace(mgr, blkSpc, vecspaces);
472
473 // build a vector space
474 return Thyra::productVectorSpace<double>(vecspaces);
475}
476
478// The next three functions are useful for parsing the string
479// description of a BlockReorderManager.
481
482// this function tokenizes a string, breaking out whitespace but saving the
483// brackets [,] as special tokens.
484static void tokenize(std::string srcInput, std::string whitespace, std::string prefer,
485 std::vector<std::string> &tokens) {
486 std::string input = srcInput;
487 std::vector<std::string> wsTokens;
488 std::size_t endPos = input.length() - 1;
489 while (endPos < input.length()) {
490 std::size_t next = input.find_first_of(whitespace);
491
492 // get the sub string
493 std::string s;
494 if (next != std::string::npos) {
495 s = input.substr(0, next);
496
497 // break out the old substring
498 input = input.substr(next + 1, endPos);
499 } else {
500 s = input;
501 input = "";
502 }
503
504 endPos = input.length() - 1;
505
506 // add it to the WS tokens list
507 if (s == "") continue;
508 wsTokens.push_back(s);
509 }
510
511 for (unsigned int i = 0; i < wsTokens.size(); i++) {
512 // get string to break up
513 input = wsTokens[i];
514
515 endPos = input.length() - 1;
516 while (endPos < input.length()) {
517 std::size_t next = input.find_first_of(prefer);
518
519 std::string s = input;
520 if (next > 0 && next < input.length()) {
521 // get the sub string
522 s = input.substr(0, next);
523
524 input = input.substr(next, endPos);
525 } else if (next == 0) {
526 // get the sub string
527 s = input.substr(0, next + 1);
528
529 input = input.substr(next + 1, endPos);
530 } else
531 input = "";
532
533 // break out the old substring
534 endPos = input.length() - 1;
535
536 // add it to the tokens list
537 tokens.push_back(s);
538 }
539 }
540}
541
542// this function takes a set of tokens and returns the first "block", i.e. those
543// values (including) brackets that correspond to the first block
544static std::vector<std::string>::const_iterator buildSubBlock(
545 std::vector<std::string>::const_iterator begin, std::vector<std::string>::const_iterator end,
546 std::vector<std::string> &subBlock) {
547 std::stack<std::string> matched;
548 std::vector<std::string>::const_iterator itr;
549 for (itr = begin; itr != end; ++itr) {
550 subBlock.push_back(*itr);
551
552 // push/pop brackets as they are discovered
553 if (*itr == "[")
554 matched.push("[");
555 else if (*itr == "]")
556 matched.pop();
557
558 // found all matching brackets
559 if (matched.empty()) return itr;
560 }
561
562 TEUCHOS_ASSERT(matched.empty());
563
564 return itr - 1;
565}
566
567// This function takes a tokenized vector and converts it to a block reorder manager
568static RCP<BlockReorderManager> blockedReorderFromTokens(const std::vector<std::string> &tokens) {
569 // base case
570 if (tokens.size() == 1)
571 return rcp(new Teko::BlockReorderLeaf(Teuchos::StrUtils::atoi(tokens[0])));
572
573 // check first and last character
574 TEUCHOS_ASSERT(*(tokens.begin()) == "[")
575 TEUCHOS_ASSERT(*(tokens.end() - 1) == "]");
576
577 std::vector<RCP<Teko::BlockReorderManager> > vecRMgr;
578 std::vector<std::string>::const_iterator itr = tokens.begin() + 1;
579 while (itr != tokens.end() - 1) {
580 // figure out which tokens are relevant for this block
581 std::vector<std::string> subBlock;
582 itr = buildSubBlock(itr, tokens.end() - 1, subBlock);
583
584 // build the child block reorder manager
585 vecRMgr.push_back(blockedReorderFromTokens(subBlock));
586
587 // move the iterator one more
588 itr++;
589 }
590
591 // build the parent reorder manager
592 RCP<Teko::BlockReorderManager> rMgr = rcp(new Teko::BlockReorderManager(vecRMgr.size()));
593 for (unsigned int i = 0; i < vecRMgr.size(); i++) rMgr->SetBlock(i, vecRMgr[i]);
594
595 return rMgr;
596}
597
599
611Teuchos::RCP<const BlockReorderManager> blockedReorderFromString(std::string &reorder) {
612 // vector of tokens to use
613 std::vector<std::string> tokens;
614
615 // manager to be returned
616
617 // build tokens vector
618 tokenize(reorder, " \t\n", "[]", tokens);
619
620 // parse recursively and build reorder manager
621 Teuchos::RCP<BlockReorderManager> mgr = blockedReorderFromTokens(tokens);
622
623 return mgr;
624}
625
626} // end namespace Teko
int GetIndex() const
Get the the index that is stored in this block.
Class that describes how a flat blocked operator should be reordered.
virtual std::string toString() const
For sanities sake, print a readable string.
Teuchos::RCP< Thyra::MultiVectorBase< double > > buildReorderedMultiVector(const BlockReorderManager &mgr, const Teuchos::RCP< Thyra::ProductMultiVectorBase< double > > &blkVec)
Convert a flat multi vector into a reordered multivector.
virtual void SetBlock(int blockIndex, int reorder)
Sets the sublock to a specific index value.
Teuchos::RCP< const BlockReorderManager > blockedReorderFromString(std::string &reorder)
Convert a string to a block reorder manager object.
virtual const Teuchos::RCP< BlockReorderManager > GetBlock(int blockIndex)
Get a particular block. If there is no block at this index location return a new one.
Teuchos::RCP< const Thyra::LinearOpBase< double > > buildReorderedLinearOp(const BlockReorderManager &bmm, const Teuchos::RCP< const Thyra::BlockedLinearOpBase< double > > &blkOp)
Use the BlockReorderManager to change a flat square blocked operator into a composite operator.
virtual int LargestIndex() const
Largest index in this manager.
BlockReorderManager()
Basic empty constructor.
std::vector< Teuchos::RCP< BlockReorderManager > > children_
Definitions of the subblocks.
virtual int GetNumBlocks() const
Gets the number of subblocks.
Teuchos::RCP< const Thyra::VectorSpaceBase< double > > buildReorderedVectorSpace(const BlockReorderManager &mgr, const Teuchos::RCP< const Thyra::ProductVectorSpaceBase< double > > &blkSpc)
Use the BlockReorderManager to change a flat vector space into a composite vector space.
Teuchos::RCP< Thyra::MultiVectorBase< double > > buildFlatMultiVector(const BlockReorderManager &mgr, const Teuchos::RCP< Thyra::ProductMultiVectorBase< double > > &blkVec)
Convert a reordered multivector into a flat multivector.