Teko  Version of the Day
 All Classes Files Functions Variables Pages
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 
25 using Teuchos::Array;
26 using Teuchos::RCP;
27 using Teuchos::rcp;
28 using Teuchos::rcp_dynamic_cast;
29 
30 namespace Teko {
31 
32 void 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 
52 void BlockReorderManager::SetBlock(int blockIndex, const RCP<BlockReorderManager> &reorder) {
53  TEUCHOS_ASSERT(blockIndex < (int)children_.size());
54 
55  children_[blockIndex] = reorder;
56 }
57 
58 const 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 
67 const Teuchos::RCP<const BlockReorderManager> BlockReorderManager::GetBlock(int blockIndex) const {
68  TEUCHOS_ASSERT(blockIndex < (int)children_.size());
69 
70  return children_[blockIndex];
71 }
72 
73 std::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 
101 Teuchos::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 
107 Teuchos::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 
212 Teuchos::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 
251 Teuchos::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 
292 Teuchos::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 
333 void 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 
362 void 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 
392 Teuchos::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 
415 Teuchos::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 
437 void 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 
463 Teuchos::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.
484 static 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
544 static 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
568 static 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 
611 Teuchos::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.
std::vector< Teuchos::RCP< BlockReorderManager > > children_
Definitions of the subblocks.
Class that describes how a flat blocked operator should be reordered.
virtual int GetNumBlocks() const
Gets the number of subblocks.
virtual int LargestIndex() const
Largest index in this manager.
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< Thyra::MultiVectorBase< double > > buildReorderedMultiVector(const BlockReorderManager &mgr, const Teuchos::RCP< Thyra::ProductMultiVectorBase< double > > &blkVec)
Convert a flat multi vector into a reordered multivector.
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...
virtual std::string toString() const
For sanities sake, print a readable string.
BlockReorderManager()
Basic empty constructor.
Teuchos::RCP< const BlockReorderManager > blockedReorderFromString(std::string &reorder)
Convert a string to a block reorder manager object.
virtual void SetBlock(int blockIndex, int reorder)
Sets the sublock to a specific index value.