Teko  Version of the Day
Teko_Utilities.cpp
1 /*
2 // @HEADER
3 //
4 // ***********************************************************************
5 //
6 // Teko: A package for block and physics based preconditioning
7 // Copyright 2010 Sandia Corporation
8 //
9 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
10 // the U.S. Government retains certain rights in this software.
11 //
12 // Redistribution and use in source and binary forms, with or without
13 // modification, are permitted provided that the following conditions are
14 // met:
15 //
16 // 1. Redistributions of source code must retain the above copyright
17 // notice, this list of conditions and the following disclaimer.
18 //
19 // 2. Redistributions in binary form must reproduce the above copyright
20 // notice, this list of conditions and the following disclaimer in the
21 // documentation and/or other materials provided with the distribution.
22 //
23 // 3. Neither the name of the Corporation nor the names of the
24 // contributors may be used to endorse or promote products derived from
25 // this software without specific prior written permission.
26 //
27 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
28 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
31 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
32 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
33 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
34 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
35 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
36 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 //
39 // Questions? Contact Eric C. Cyr (eccyr@sandia.gov)
40 //
41 // ***********************************************************************
42 //
43 // @HEADER
44 
45 */
46 
47 #include "Teko_Config.h"
48 #include "Teko_Utilities.hpp"
49 
50 // Thyra includes
51 #include "Thyra_MultiVectorStdOps.hpp"
52 #include "Thyra_ZeroLinearOpBase.hpp"
53 #include "Thyra_DefaultDiagonalLinearOp.hpp"
54 #include "Thyra_DefaultAddedLinearOp.hpp"
55 #include "Thyra_EpetraExtDiagScaledMatProdTransformer.hpp"
56 #include "Thyra_EpetraExtDiagScalingTransformer.hpp"
57 #include "Thyra_EpetraExtAddTransformer.hpp"
58 #include "Thyra_DefaultScaledAdjointLinearOp.hpp"
59 #include "Thyra_DefaultMultipliedLinearOp.hpp"
60 #include "Thyra_DefaultZeroLinearOp.hpp"
61 #include "Thyra_DefaultProductMultiVector.hpp"
62 #include "Thyra_DefaultProductVectorSpace.hpp"
63 #include "Thyra_MultiVectorStdOps.hpp"
64 #include "Thyra_VectorStdOps.hpp"
65 #include "Thyra_SpmdVectorBase.hpp"
66 #include "Thyra_get_Epetra_Operator.hpp"
67 #include "Thyra_EpetraThyraWrappers.hpp"
68 #include "Thyra_EpetraOperatorWrapper.hpp"
69 #include "Thyra_EpetraLinearOp.hpp"
70 
71 // Teuchos includes
72 #include "Teuchos_Array.hpp"
73 
74 // Epetra includes
75 #include "Epetra_Operator.h"
76 #include "Epetra_CrsGraph.h"
77 #include "Epetra_CrsMatrix.h"
78 #include "Epetra_Vector.h"
79 #include "Epetra_Map.h"
80 
81 #include "EpetraExt_Transpose_RowMatrix.h"
82 #include "EpetraExt_MatrixMatrix.h"
83 
84 // Anasazi includes
85 #include "AnasaziBasicEigenproblem.hpp"
86 #include "AnasaziThyraAdapter.hpp"
87 #include "AnasaziBlockKrylovSchurSolMgr.hpp"
88 #include "AnasaziBlockKrylovSchur.hpp"
89 #include "AnasaziStatusTestMaxIters.hpp"
90 
91 // Isorropia includes
92 #ifdef Teko_ENABLE_Isorropia
93 #include "Isorropia_EpetraProber.hpp"
94 #endif
95 
96 // Teko includes
97 #include "Teko_EpetraHelpers.hpp"
98 #include "Teko_EpetraOperatorWrapper.hpp"
99 #include "Teko_TpetraHelpers.hpp"
100 #include "Teko_TpetraOperatorWrapper.hpp"
101 
102 // Tpetra
103 #include "Thyra_TpetraLinearOp.hpp"
104 #include "Tpetra_CrsMatrix.hpp"
105 #include "Tpetra_Vector.hpp"
106 #include "Thyra_TpetraThyraWrappers.hpp"
107 #include "TpetraExt_MatrixMatrix.hpp"
108 #include "Tpetra_RowMatrixTransposer.hpp"
109 
110 #include <cmath>
111 
112 namespace Teko {
113 
114 using Teuchos::rcp;
115 using Teuchos::rcp_dynamic_cast;
116 using Teuchos::RCP;
117 #ifdef Teko_ENABLE_Isorropia
118 using Isorropia::Epetra::Prober;
119 #endif
120 
121 const Teuchos::RCP<Teuchos::FancyOStream> getOutputStream()
122 {
123  Teuchos::RCP<Teuchos::FancyOStream> os =
124  Teuchos::VerboseObjectBase::getDefaultOStream();
125 
126  //os->setShowProcRank(true);
127  //os->setOutputToRootOnly(-1);
128  return os;
129 }
130 
131 // distance function...not parallel...entirely internal to this cpp file
132 inline double dist(int dim,double * coords,int row,int col)
133 {
134  double value = 0.0;
135  for(int i=0;i<dim;i++)
136  value += std::pow(coords[dim*row+i]-coords[dim*col+i],2.0);
137 
138  // the distance between the two
139  return std::sqrt(value);
140 }
141 
142 // distance function...not parallel...entirely internal to this cpp file
143 inline double dist(double * x,double * y,double * z,int stride,int row,int col)
144 {
145  double value = 0.0;
146  if(x!=0) value += std::pow(x[stride*row]-x[stride*col],2.0);
147  if(y!=0) value += std::pow(y[stride*row]-y[stride*col],2.0);
148  if(z!=0) value += std::pow(z[stride*row]-z[stride*col],2.0);
149 
150  // the distance between the two
151  return std::sqrt(value);
152 }
153 
172 RCP<Epetra_CrsMatrix> buildGraphLaplacian(int dim,double * coords,const Epetra_CrsMatrix & stencil)
173 {
174  // allocate a new matrix with storage for the laplacian...in case of diagonals add one extra storage
175  RCP<Epetra_CrsMatrix> gl = rcp(new Epetra_CrsMatrix(Copy,stencil.RowMap(),stencil.ColMap(),
176  stencil.MaxNumEntries()+1),true);
177 
178  // allocate an additional value for the diagonal, if neccessary
179  std::vector<double> rowData(stencil.GlobalMaxNumEntries()+1);
180  std::vector<int> rowInd(stencil.GlobalMaxNumEntries()+1);
181 
182  // loop over all the rows
183  for(int j=0;j<gl->NumMyRows();j++) {
184  int row = gl->GRID(j);
185  double diagValue = 0.0;
186  int diagInd = -1;
187  int rowSz = 0;
188 
189  // extract a copy of this row...put it in rowData, rowIndicies
190  stencil.ExtractGlobalRowCopy(row,stencil.MaxNumEntries(),rowSz,&rowData[0],&rowInd[0]);
191 
192  // loop over elements of row
193  for(int i=0;i<rowSz;i++) {
194  int col = rowInd[i];
195 
196  // is this a 0 entry masquerading as some thing else?
197  double value = rowData[i];
198  if(value==0) continue;
199 
200  // for nondiagonal entries
201  if(row!=col) {
202  double d = dist(dim,coords,row,col);
203  rowData[i] = -1.0/d;
204  diagValue += rowData[i];
205  }
206  else
207  diagInd = i;
208  }
209 
210  // handle diagonal entry
211  if(diagInd<0) { // diagonal not in row
212  rowData[rowSz] = -diagValue;
213  rowInd[rowSz] = row;
214  rowSz++;
215  }
216  else { // diagonal in row
217  rowData[diagInd] = -diagValue;
218  rowInd[diagInd] = row;
219  }
220 
221  // insert row data into graph Laplacian matrix
222  TEUCHOS_TEST_FOR_EXCEPT(gl->InsertGlobalValues(row,rowSz,&rowData[0],&rowInd[0]));
223  }
224 
225  gl->FillComplete();
226 
227  return gl;
228 }
229 
230 RCP<Tpetra::CrsMatrix<ST,LO,GO,NT> > buildGraphLaplacian(int dim,ST * coords,const Tpetra::CrsMatrix<ST,LO,GO,NT> & stencil)
231 {
232  // allocate a new matrix with storage for the laplacian...in case of diagonals add one extra storage
233  RCP<Tpetra::CrsMatrix<ST,LO,GO,NT> > gl = rcp(new Tpetra::CrsMatrix<ST,LO,GO,NT>(stencil.getRowMap(),stencil.getColMap(),
234  stencil.getGlobalMaxNumRowEntries()+1));
235 
236  // allocate an additional value for the diagonal, if neccessary
237  auto rowInd = typename Tpetra::CrsMatrix<ST,LO,GO,NT>::nonconst_global_inds_host_view_type(Kokkos::ViewAllocateWithoutInitializing("rowIndices"),stencil.getGlobalMaxNumRowEntries()+1);
238  auto rowData = typename Tpetra::CrsMatrix<ST,LO,GO,NT>::nonconst_values_host_view_type(Kokkos::ViewAllocateWithoutInitializing("rowIndices"),stencil.getGlobalMaxNumRowEntries()+1);
239 
240  // loop over all the rows
241  for(LO j=0;j< (LO) gl->getNodeNumRows();j++) {
242  GO row = gl->getRowMap()->getGlobalElement(j);
243  ST diagValue = 0.0;
244  GO diagInd = -1;
245  size_t rowSz = 0;
246 
247  // extract a copy of this row...put it in rowData, rowIndicies
248  stencil.getGlobalRowCopy(row,rowInd,rowData,rowSz);
249 
250  // loop over elements of row
251  for(size_t i=0;i<rowSz;i++) {
252  GO col = rowInd(i);
253 
254  // is this a 0 entry masquerading as some thing else?
255  ST value = rowData[i];
256  if(value==0) continue;
257 
258  // for nondiagonal entries
259  if(row!=col) {
260  ST d = dist(dim,coords,row,col);
261  rowData[i] = -1.0/d;
262  diagValue += rowData(i);
263  }
264  else
265  diagInd = i;
266  }
267 
268  // handle diagonal entry
269  if(diagInd<0) { // diagonal not in row
270  rowData(rowSz) = -diagValue;
271  rowInd(rowSz) = row;
272  rowSz++;
273  }
274  else { // diagonal in row
275  rowData(diagInd) = -diagValue;
276  rowInd(diagInd) = row;
277  }
278 
279  // insert row data into graph Laplacian matrix
280  gl->replaceGlobalValues(row,rowInd,rowData);
281  }
282 
283  gl->fillComplete();
284 
285  return gl;
286 }
287 
310 RCP<Epetra_CrsMatrix> buildGraphLaplacian(double * x,double * y,double * z,int stride,const Epetra_CrsMatrix & stencil)
311 {
312  // allocate a new matrix with storage for the laplacian...in case of diagonals add one extra storage
313  RCP<Epetra_CrsMatrix> gl = rcp(new Epetra_CrsMatrix(Copy,stencil.RowMap(),stencil.ColMap(),
314  stencil.MaxNumEntries()+1),true);
315 
316  // allocate an additional value for the diagonal, if neccessary
317  std::vector<double> rowData(stencil.GlobalMaxNumEntries()+1);
318  std::vector<int> rowInd(stencil.GlobalMaxNumEntries()+1);
319 
320  // loop over all the rows
321  for(int j=0;j<gl->NumMyRows();j++) {
322  int row = gl->GRID(j);
323  double diagValue = 0.0;
324  int diagInd = -1;
325  int rowSz = 0;
326 
327  // extract a copy of this row...put it in rowData, rowIndicies
328  stencil.ExtractGlobalRowCopy(row,stencil.MaxNumEntries(),rowSz,&rowData[0],&rowInd[0]);
329 
330  // loop over elements of row
331  for(int i=0;i<rowSz;i++) {
332  int col = rowInd[i];
333 
334  // is this a 0 entry masquerading as some thing else?
335  double value = rowData[i];
336  if(value==0) continue;
337 
338  // for nondiagonal entries
339  if(row!=col) {
340  double d = dist(x,y,z,stride,row,col);
341  rowData[i] = -1.0/d;
342  diagValue += rowData[i];
343  }
344  else
345  diagInd = i;
346  }
347 
348  // handle diagonal entry
349  if(diagInd<0) { // diagonal not in row
350  rowData[rowSz] = -diagValue;
351  rowInd[rowSz] = row;
352  rowSz++;
353  }
354  else { // diagonal in row
355  rowData[diagInd] = -diagValue;
356  rowInd[diagInd] = row;
357  }
358 
359  // insert row data into graph Laplacian matrix
360  TEUCHOS_TEST_FOR_EXCEPT(gl->InsertGlobalValues(row,rowSz,&rowData[0],&rowInd[0]));
361  }
362 
363  gl->FillComplete();
364 
365  return gl;
366 }
367 
368 RCP<Tpetra::CrsMatrix<ST,LO,GO,NT> > buildGraphLaplacian(ST * x,ST * y,ST * z,GO stride,const Tpetra::CrsMatrix<ST,LO,GO,NT> & stencil)
369 {
370  // allocate a new matrix with storage for the laplacian...in case of diagonals add one extra storage
371  RCP<Tpetra::CrsMatrix<ST,LO,GO,NT> > gl = rcp(new Tpetra::CrsMatrix<ST,LO,GO,NT>(stencil.getRowMap(),stencil.getColMap(),
372  stencil.getGlobalMaxNumRowEntries()+1),true);
373 
374  // allocate an additional value for the diagonal, if neccessary
375  auto rowInd = typename Tpetra::CrsMatrix<ST,LO,GO,NT>::nonconst_global_inds_host_view_type(Kokkos::ViewAllocateWithoutInitializing("rowIndices"),stencil.getGlobalMaxNumRowEntries()+1);
376  auto rowData = typename Tpetra::CrsMatrix<ST,LO,GO,NT>::nonconst_values_host_view_type(Kokkos::ViewAllocateWithoutInitializing("rowIndices"),stencil.getGlobalMaxNumRowEntries()+1);
377 
378  // loop over all the rows
379  for(LO j=0;j<(LO) gl->getNodeNumRows();j++) {
380  GO row = gl->getRowMap()->getGlobalElement(j);
381  ST diagValue = 0.0;
382  GO diagInd = -1;
383  size_t rowSz = 0;
384 
385  // extract a copy of this row...put it in rowData, rowIndicies
386  stencil.getGlobalRowCopy(row,rowInd,rowData,rowSz);
387 
388  // loop over elements of row
389  for(size_t i=0;i<rowSz;i++) {
390  GO col = rowInd(i);
391 
392  // is this a 0 entry masquerading as some thing else?
393  ST value = rowData[i];
394  if(value==0) continue;
395 
396  // for nondiagonal entries
397  if(row!=col) {
398  ST d = dist(x,y,z,stride,row,col);
399  rowData[i] = -1.0/d;
400  diagValue += rowData(i);
401  }
402  else
403  diagInd = i;
404  }
405 
406  // handle diagonal entry
407  if(diagInd<0) { // diagonal not in row
408  rowData(rowSz) = -diagValue;
409  rowInd(rowSz) = row;
410  rowSz++;
411  }
412  else { // diagonal in row
413  rowData(diagInd) = -diagValue;
414  rowInd(diagInd) = row;
415  }
416 
417  // insert row data into graph Laplacian matrix
418  gl->replaceGlobalValues(row,rowInd,rowData);
419  }
420 
421  gl->fillComplete();
422 
423  return gl;
424 }
425 
441 void applyOp(const LinearOp & A,const MultiVector & x,MultiVector & y,double alpha,double beta)
442 {
443  Thyra::apply(*A,Thyra::NOTRANS,*x,y.ptr(),alpha,beta);
444 }
445 
461 void applyTransposeOp(const LinearOp & A,const MultiVector & x,MultiVector & y,double alpha,double beta)
462 {
463  Thyra::apply(*A,Thyra::TRANS,*x,y.ptr(),alpha,beta);
464 }
465 
468 void update(double alpha,const MultiVector & x,double beta,MultiVector & y)
469 {
470  Teuchos::Array<double> scale;
471  Teuchos::Array<Teuchos::Ptr<const Thyra::MultiVectorBase<double> > > vec;
472 
473  // build arrays needed for linear combo
474  scale.push_back(alpha);
475  vec.push_back(x.ptr());
476 
477  // compute linear combination
478  Thyra::linear_combination<double>(scale,vec,beta,y.ptr());
479 }
480 
482 BlockedLinearOp getUpperTriBlocks(const BlockedLinearOp & blo,bool callEndBlockFill)
483 {
484  int rows = blockRowCount(blo);
485 
486  TEUCHOS_ASSERT(rows==blockColCount(blo));
487 
488  RCP<const Thyra::ProductVectorSpaceBase<double> > range = blo->productRange();
489  RCP<const Thyra::ProductVectorSpaceBase<double> > domain = blo->productDomain();
490 
491  // allocate new operator
492  BlockedLinearOp upper = createBlockedOp();
493 
494  // build new operator
495  upper->beginBlockFill(rows,rows);
496 
497  for(int i=0;i<rows;i++) {
498  // put zero operators on the diagonal
499  // this gurantees the vector space of
500  // the new operator are fully defined
501  RCP<const Thyra::LinearOpBase<double> > zed
502  = Thyra::zero<double>(range->getBlock(i),domain->getBlock(i));
503  upper->setBlock(i,i,zed);
504 
505  for(int j=i+1;j<rows;j++) {
506  // get block i,j
507  LinearOp uij = blo->getBlock(i,j);
508 
509  // stuff it in U
510  if(uij!=Teuchos::null)
511  upper->setBlock(i,j,uij);
512  }
513  }
514  if(callEndBlockFill)
515  upper->endBlockFill();
516 
517  return upper;
518 }
519 
521 BlockedLinearOp getLowerTriBlocks(const BlockedLinearOp & blo,bool callEndBlockFill)
522 {
523  int rows = blockRowCount(blo);
524 
525  TEUCHOS_ASSERT(rows==blockColCount(blo));
526 
527  RCP<const Thyra::ProductVectorSpaceBase<double> > range = blo->productRange();
528  RCP<const Thyra::ProductVectorSpaceBase<double> > domain = blo->productDomain();
529 
530  // allocate new operator
531  BlockedLinearOp lower = createBlockedOp();
532 
533  // build new operator
534  lower->beginBlockFill(rows,rows);
535 
536  for(int i=0;i<rows;i++) {
537  // put zero operators on the diagonal
538  // this gurantees the vector space of
539  // the new operator are fully defined
540  RCP<const Thyra::LinearOpBase<double> > zed
541  = Thyra::zero<double>(range->getBlock(i),domain->getBlock(i));
542  lower->setBlock(i,i,zed);
543 
544  for(int j=0;j<i;j++) {
545  // get block i,j
546  LinearOp uij = blo->getBlock(i,j);
547 
548  // stuff it in U
549  if(uij!=Teuchos::null)
550  lower->setBlock(i,j,uij);
551  }
552  }
553  if(callEndBlockFill)
554  lower->endBlockFill();
555 
556  return lower;
557 }
558 
578 BlockedLinearOp zeroBlockedOp(const BlockedLinearOp & blo)
579 {
580  int rows = blockRowCount(blo);
581 
582  TEUCHOS_ASSERT(rows==blockColCount(blo)); // assert that matrix is square
583 
584  RCP<const Thyra::ProductVectorSpaceBase<double> > range = blo->productRange();
585  RCP<const Thyra::ProductVectorSpaceBase<double> > domain = blo->productDomain();
586 
587  // allocate new operator
588  BlockedLinearOp zeroOp = createBlockedOp();
589 
590  // build new operator
591  zeroOp->beginBlockFill(rows,rows);
592 
593  for(int i=0;i<rows;i++) {
594  // put zero operators on the diagonal
595  // this gurantees the vector space of
596  // the new operator are fully defined
597  RCP<const Thyra::LinearOpBase<double> > zed
598  = Thyra::zero<double>(range->getBlock(i),domain->getBlock(i));
599  zeroOp->setBlock(i,i,zed);
600  }
601 
602  return zeroOp;
603 }
604 
606 bool isZeroOp(const LinearOp op)
607 {
608  // if operator is null...then its zero!
609  if(op==Teuchos::null) return true;
610 
611  // try to cast it to a zero linear operator
612  LinearOp test = rcp_dynamic_cast<const Thyra::ZeroLinearOpBase<double> >(op);
613 
614  // if it works...then its zero...otherwise its null
615  if(test!=Teuchos::null) return true;
616 
617  // See if the operator is a wrapped zero op
618  ST scalar = 0.0;
619  Thyra::EOpTransp transp = Thyra::NOTRANS;
620  RCP<const Thyra::LinearOpBase<ST> > wrapped_op;
621  Thyra::unwrap(op, &scalar, &transp, &wrapped_op);
622  test = rcp_dynamic_cast<const Thyra::ZeroLinearOpBase<double> >(wrapped_op);
623  return test!=Teuchos::null;
624 }
625 
634 ModifiableLinearOp getAbsRowSumMatrix(const LinearOp & op)
635 {
636  bool isTpetra = false;
637  RCP<const Epetra_CrsMatrix> eCrsOp;
638  RCP<const Tpetra::CrsMatrix<ST,LO,GO,NT> > tCrsOp;
639 
640  try {
641  // get Epetra or Tpetra Operator
642  RCP<const Thyra::EpetraLinearOp > eOp = rcp_dynamic_cast<const Thyra::EpetraLinearOp >(op);
643  RCP<const Thyra::TpetraLinearOp<ST,LO,GO,NT> > tOp = rcp_dynamic_cast<const Thyra::TpetraLinearOp<ST,LO,GO,NT> >(op);
644 
645  // cast it to a CrsMatrix
646  RCP<Teuchos::FancyOStream> out = Teuchos::VerboseObjectBase::getDefaultOStream();
647  if (!eOp.is_null()){
648  eCrsOp = rcp_dynamic_cast<const Epetra_CrsMatrix>(eOp->epetra_op(),true);
649  }
650  else if (!tOp.is_null()){
651  tCrsOp = rcp_dynamic_cast<const Tpetra::CrsMatrix<ST,LO,GO,NT> >(tOp->getConstTpetraOperator(),true);
652  isTpetra = true;
653  }
654  else
655  throw std::logic_error("Neither Epetra nor Tpetra");
656  }
657  catch (std::exception & e) {
658  RCP<Teuchos::FancyOStream> out = Teuchos::VerboseObjectBase::getDefaultOStream();
659 
660  *out << "Teko: getAbsRowSumMatrix requires an Epetra_CrsMatrix or a Tpetra::CrsMatrix\n";
661  *out << " Could not extract an Epetra_Operator or a Tpetra_Operator from a \"" << op->description() << std::endl;
662  *out << " OR\n";
663  *out << " Could not cast an Epetra_Operator to a Epetra_CrsMatrix or a Tpetra_Operator to a Tpetra::CrsMatrix\n";
664  *out << std::endl;
665  *out << "*** THROWN EXCEPTION ***\n";
666  *out << e.what() << std::endl;
667  *out << "************************\n";
668 
669  throw e;
670  }
671 
672  if(!isTpetra){
673  // extract diagonal
674  const RCP<Epetra_Vector> ptrDiag = rcp(new Epetra_Vector(eCrsOp->RowMap()));
675  Epetra_Vector & diag = *ptrDiag;
676 
677  // compute absolute value row sum
678  diag.PutScalar(0.0);
679  for(int i=0;i<eCrsOp->NumMyRows();i++) {
680  double * values = 0;
681  int numEntries;
682  eCrsOp->ExtractMyRowView(i,numEntries,values);
683 
684  // build abs value row sum
685  for(int j=0;j<numEntries;j++)
686  diag[i] += std::abs(values[j]);
687  }
688 
689  // build Thyra diagonal operator
690  return Teko::Epetra::thyraDiagOp(ptrDiag,eCrsOp->RowMap(),"absRowSum( " + op->getObjectLabel() + " )");
691  }
692  else {
693  // extract diagonal
694  const RCP<Tpetra::Vector<ST,LO,GO,NT> > ptrDiag = Tpetra::createVector<ST,LO,GO,NT>(tCrsOp->getRowMap());
695  Tpetra::Vector<ST,LO,GO,NT> & diag = *ptrDiag;
696 
697  // compute absolute value row sum
698  diag.putScalar(0.0);
699  for(LO i=0;i<(LO) tCrsOp->getNodeNumRows();i++) {
700  LO numEntries = tCrsOp->getNumEntriesInLocalRow (i);
701  typename Tpetra::CrsMatrix<ST,LO,GO,NT>::local_inds_host_view_type indices;
702  typename Tpetra::CrsMatrix<ST,LO,GO,NT>::values_host_view_type values;
703  tCrsOp->getLocalRowView(i,indices,values);
704 
705  // build abs value row sum
706  for(LO j=0;j<numEntries;j++)
707  diag.sumIntoLocalValue(i,std::abs(values(j)));
708  }
709 
710  // build Thyra diagonal operator
711  return Teko::TpetraHelpers::thyraDiagOp(ptrDiag,*tCrsOp->getRowMap(),"absRowSum( " + op->getObjectLabel() + " ))");
712 
713  }
714 
715 }
716 
725 ModifiableLinearOp getAbsRowSumInvMatrix(const LinearOp & op)
726 {
727  // if this is a blocked operator, extract diagonals block by block
728  // FIXME: this does not add in values from off-diagonal blocks
729  RCP<const Thyra::PhysicallyBlockedLinearOpBase<double> > blocked_op = rcp_dynamic_cast<const Thyra::PhysicallyBlockedLinearOpBase<double> >(op);
730  if(blocked_op != Teuchos::null){
731  int numRows = blocked_op->productRange()->numBlocks();
732  TEUCHOS_ASSERT(blocked_op->productDomain()->numBlocks() == numRows);
733  RCP<Thyra::PhysicallyBlockedLinearOpBase<double> > blocked_diag = Thyra::defaultBlockedLinearOp<double>();
734  blocked_diag->beginBlockFill(numRows,numRows);
735  for(int r = 0; r < numRows; ++r){
736  for(int c = 0; c < numRows; ++c){
737  if(r==c)
738  blocked_diag->setNonconstBlock(r,c,getAbsRowSumInvMatrix(blocked_op->getBlock(r,c)));
739  else
740  blocked_diag->setBlock(r,c,Thyra::zero<double>(blocked_op->getBlock(r,c)->range(),blocked_op->getBlock(r,c)->domain()));
741  }
742  }
743  blocked_diag->endBlockFill();
744  return blocked_diag;
745  }
746 
747  if(Teko::TpetraHelpers::isTpetraLinearOp(op)) {
748  ST scalar = 0.0;
749  bool transp = false;
750  RCP<const Tpetra::CrsMatrix<ST,LO,GO,NT> > tCrsOp = Teko::TpetraHelpers::getTpetraCrsMatrix(op, &scalar, &transp);
751 
752  // extract diagonal
753  const RCP<Tpetra::Vector<ST,LO,GO,NT> > ptrDiag = Tpetra::createVector<ST,LO,GO,NT>(tCrsOp->getRowMap());
754  Tpetra::Vector<ST,LO,GO,NT> & diag = *ptrDiag;
755 
756  // compute absolute value row sum
757  diag.putScalar(0.0);
758  for(LO i=0;i<(LO) tCrsOp->getNodeNumRows();i++) {
759  LO numEntries = tCrsOp->getNumEntriesInLocalRow (i);
760  typename Tpetra::CrsMatrix<ST,LO,GO,NT>::local_inds_host_view_type indices;
761  typename Tpetra::CrsMatrix<ST,LO,GO,NT>::values_host_view_type values;
762  tCrsOp->getLocalRowView(i,indices,values);
763 
764  // build abs value row sum
765  for(LO j=0;j<numEntries;j++)
766  diag.sumIntoLocalValue(i,std::abs(values(j)));
767  }
768  diag.scale(scalar);
769  diag.reciprocal(diag); // invert entries
770 
771  // build Thyra diagonal operator
772  return Teko::TpetraHelpers::thyraDiagOp(ptrDiag,*tCrsOp->getRowMap(),"absRowSum( " + op->getObjectLabel() + " ))");
773 
774  }
775  else{
776  RCP<const Thyra::EpetraLinearOp > eOp = rcp_dynamic_cast<const Thyra::EpetraLinearOp >(op,true);
777  RCP<const Epetra_CrsMatrix> eCrsOp = rcp_dynamic_cast<const Epetra_CrsMatrix>(eOp->epetra_op(),true);
778 
779  // extract diagonal
780  const RCP<Epetra_Vector> ptrDiag = rcp(new Epetra_Vector(eCrsOp->RowMap()));
781  Epetra_Vector & diag = *ptrDiag;
782 
783  // compute absolute value row sum
784  diag.PutScalar(0.0);
785  for(int i=0;i<eCrsOp->NumMyRows();i++) {
786  double * values = 0;
787  int numEntries;
788  eCrsOp->ExtractMyRowView(i,numEntries,values);
789 
790  // build abs value row sum
791  for(int j=0;j<numEntries;j++)
792  diag[i] += std::abs(values[j]);
793  }
794  diag.Reciprocal(diag); // invert entries
795 
796  // build Thyra diagonal operator
797  return Teko::Epetra::thyraDiagOp(ptrDiag,eCrsOp->RowMap(),"absRowSum( " + op->getObjectLabel() + " )");
798  }
799 
800 }
801 
809 ModifiableLinearOp getLumpedMatrix(const LinearOp & op)
810 {
811  RCP<Thyra::VectorBase<ST> > ones = Thyra::createMember(op->domain());
812  RCP<Thyra::VectorBase<ST> > diag = Thyra::createMember(op->range());
813 
814  // set to all ones
815  Thyra::assign(ones.ptr(),1.0);
816 
817  // compute lumped diagonal
818  // Thyra::apply(*op,Thyra::NONCONJ_ELE,*ones,&*diag);
819  Thyra::apply(*op,Thyra::NOTRANS,*ones,diag.ptr());
820 
821  return rcp(new Thyra::DefaultDiagonalLinearOp<ST>(diag));
822 }
823 
832 ModifiableLinearOp getInvLumpedMatrix(const LinearOp & op)
833 {
834  RCP<Thyra::VectorBase<ST> > ones = Thyra::createMember(op->domain());
835  RCP<Thyra::VectorBase<ST> > diag = Thyra::createMember(op->range());
836 
837  // set to all ones
838  Thyra::assign(ones.ptr(),1.0);
839 
840  // compute lumped diagonal
841  Thyra::apply(*op,Thyra::NOTRANS,*ones,diag.ptr());
842  Thyra::reciprocal(*diag,diag.ptr());
843 
844  return rcp(new Thyra::DefaultDiagonalLinearOp<ST>(diag));
845 }
846 
858 const ModifiableLinearOp getDiagonalOp(const LinearOp & op)
859 {
860  bool isTpetra = false;
861  RCP<const Epetra_CrsMatrix> eCrsOp;
862  RCP<const Tpetra::CrsMatrix<ST,LO,GO,NT> > tCrsOp;
863 
864  try {
865  // get Epetra or Tpetra Operator
866  RCP<const Thyra::EpetraLinearOp > eOp = rcp_dynamic_cast<const Thyra::EpetraLinearOp >(op);
867  RCP<const Thyra::TpetraLinearOp<ST,LO,GO,NT> > tOp = rcp_dynamic_cast<const Thyra::TpetraLinearOp<ST,LO,GO,NT> >(op);
868 
869  // cast it to a CrsMatrix
870  RCP<Teuchos::FancyOStream> out = Teuchos::VerboseObjectBase::getDefaultOStream();
871  if (!eOp.is_null()){
872  eCrsOp = rcp_dynamic_cast<const Epetra_CrsMatrix>(eOp->epetra_op(),true);
873  }
874  else if (!tOp.is_null()){
875  tCrsOp = rcp_dynamic_cast<const Tpetra::CrsMatrix<ST,LO,GO,NT> >(tOp->getConstTpetraOperator(),true);
876  isTpetra = true;
877  }
878  else
879  throw std::logic_error("Neither Epetra nor Tpetra");
880  }
881  catch (std::exception & e) {
882  RCP<Teuchos::FancyOStream> out = Teuchos::VerboseObjectBase::getDefaultOStream();
883 
884  *out << "Teko: getDiagonalOp requires an Epetra_CrsMatrix or a Tpetra::CrsMatrix\n";
885  *out << " Could not extract an Epetra_Operator or a Tpetra_Operator from a \"" << op->description() << std::endl;
886  *out << " OR\n";
887  *out << " Could not cast an Epetra_Operator to a Epetra_CrsMatrix or a Tpetra_Operator to a Tpetra::CrsMatrix\n";
888  *out << std::endl;
889  *out << "*** THROWN EXCEPTION ***\n";
890  *out << e.what() << std::endl;
891  *out << "************************\n";
892 
893  throw e;
894  }
895 
896  if(!isTpetra){
897  // extract diagonal
898  const RCP<Epetra_Vector> diag = rcp(new Epetra_Vector(eCrsOp->RowMap()));
899  TEUCHOS_TEST_FOR_EXCEPT(eCrsOp->ExtractDiagonalCopy(*diag));
900 
901  // build Thyra diagonal operator
902  return Teko::Epetra::thyraDiagOp(diag,eCrsOp->RowMap(),"inv(diag( " + op->getObjectLabel() + " ))");
903  }
904  else {
905  // extract diagonal
906  const RCP<Tpetra::Vector<ST,LO,GO,NT> > diag = Tpetra::createVector<ST,LO,GO,NT>(tCrsOp->getRowMap());
907  tCrsOp->getLocalDiagCopy(*diag);
908 
909  // build Thyra diagonal operator
910  return Teko::TpetraHelpers::thyraDiagOp(diag,*tCrsOp->getRowMap(),"inv(diag( " + op->getObjectLabel() + " ))");
911 
912  }
913 }
914 
915 const MultiVector getDiagonal(const LinearOp & op)
916 {
917  bool isTpetra = false;
918  RCP<const Epetra_CrsMatrix> eCrsOp;
919  RCP<const Tpetra::CrsMatrix<ST,LO,GO,NT> > tCrsOp;
920 
921  try {
922  // get Epetra or Tpetra Operator
923  RCP<const Thyra::EpetraLinearOp > eOp = rcp_dynamic_cast<const Thyra::EpetraLinearOp >(op);
924  RCP<const Thyra::TpetraLinearOp<ST,LO,GO,NT> > tOp = rcp_dynamic_cast<const Thyra::TpetraLinearOp<ST,LO,GO,NT> >(op);
925 
926  // cast it to a CrsMatrix
927  RCP<Teuchos::FancyOStream> out = Teuchos::VerboseObjectBase::getDefaultOStream();
928  if (!eOp.is_null()){
929  eCrsOp = rcp_dynamic_cast<const Epetra_CrsMatrix>(eOp->epetra_op(),true);
930  }
931  else if (!tOp.is_null()){
932  tCrsOp = rcp_dynamic_cast<const Tpetra::CrsMatrix<ST,LO,GO,NT> >(tOp->getConstTpetraOperator(),true);
933  isTpetra = true;
934  }
935  else
936  throw std::logic_error("Neither Epetra nor Tpetra");
937  }
938  catch (std::exception & e) {
939  RCP<Teuchos::FancyOStream> out = Teuchos::VerboseObjectBase::getDefaultOStream();
940 
941  RCP<const Thyra::EpetraLinearOp > eOp = rcp_dynamic_cast<const Thyra::EpetraLinearOp >(op);
942  RCP<const Thyra::TpetraLinearOp<ST,LO,GO,NT> > tOp = rcp_dynamic_cast<const Thyra::TpetraLinearOp<ST,LO,GO,NT> >(op);
943  *out << eOp;
944  *out << tOp;
945 
946  *out << "Teko: getDiagonal requires an Epetra_CrsMatrix or a Tpetra::CrsMatrix\n";
947  *out << " Could not extract an Epetra_Operator or a Tpetra_Operator from a \"" << op->description() << std::endl;
948  *out << " OR\n";
949  *out << " Could not cast an Epetra_Operator to a Epetra_CrsMatrix or a Tpetra_Operator to a Tpetra::CrsMatrix\n";
950  *out << std::endl;
951  *out << "*** THROWN EXCEPTION ***\n";
952  *out << e.what() << std::endl;
953  *out << "************************\n";
954 
955  throw e;
956  }
957 
958  if(!isTpetra){
959  // extract diagonal
960  const RCP<Epetra_Vector> diag = rcp(new Epetra_Vector(eCrsOp->RowMap()));
961  TEUCHOS_TEST_FOR_EXCEPT(eCrsOp->ExtractDiagonalCopy(*diag));
962 
963  return Thyra::create_Vector(diag,Thyra::create_VectorSpace(Teuchos::rcpFromRef(eCrsOp->RowMap())));
964  }
965  else {
966  // extract diagonal
967  const RCP<Tpetra::Vector<ST,LO,GO,NT> > diag = Tpetra::createVector<ST,LO,GO,NT>(tCrsOp->getRowMap());
968  tCrsOp->getLocalDiagCopy(*diag);
969 
970  // build Thyra diagonal operator
971  return Thyra::createVector<ST,LO,GO,NT>(diag,Thyra::createVectorSpace<ST,LO,GO,NT>(tCrsOp->getRowMap()));
972 
973  }
974 }
975 
976 const MultiVector getDiagonal(const Teko::LinearOp & A,const DiagonalType & dt)
977 {
978  LinearOp diagOp = Teko::getDiagonalOp(A,dt);
979 
980  Teuchos::RCP<const Thyra::MultiVectorBase<double> > v =
981  Teuchos::rcp_dynamic_cast<const Thyra::DiagonalLinearOpBase<double> >(diagOp)->getDiag();
982  return Teuchos::rcp_const_cast<Thyra::MultiVectorBase<double> >(v);
983 }
984 
996 const ModifiableLinearOp getInvDiagonalOp(const LinearOp & op)
997 {
998  // if this is a diagonal linear op already, just take the reciprocal
999  auto diagonal_op = rcp_dynamic_cast<const Thyra::DiagonalLinearOpBase<double>>(op);
1000  if(diagonal_op != Teuchos::null){
1001  auto diag = diagonal_op->getDiag();
1002  auto inv_diag = diag->clone_v();
1003  Thyra::reciprocal(*diag,inv_diag.ptr());
1004  return rcp(new Thyra::DefaultDiagonalLinearOp<double>(inv_diag));
1005  }
1006 
1007  // if this is a blocked operator, extract diagonals block by block
1008  RCP<const Thyra::PhysicallyBlockedLinearOpBase<double> > blocked_op = rcp_dynamic_cast<const Thyra::PhysicallyBlockedLinearOpBase<double> >(op);
1009  if(blocked_op != Teuchos::null){
1010  int numRows = blocked_op->productRange()->numBlocks();
1011  TEUCHOS_ASSERT(blocked_op->productDomain()->numBlocks() == numRows);
1012  RCP<Thyra::PhysicallyBlockedLinearOpBase<double> > blocked_diag = Thyra::defaultBlockedLinearOp<double>();
1013  blocked_diag->beginBlockFill(numRows,numRows);
1014  for(int r = 0; r < numRows; ++r){
1015  for(int c = 0; c < numRows; ++c){
1016  if(r==c)
1017  blocked_diag->setNonconstBlock(r,c,getInvDiagonalOp(blocked_op->getBlock(r,c)));
1018  else
1019  blocked_diag->setBlock(r,c,Thyra::zero<double>(blocked_op->getBlock(r,c)->range(),blocked_op->getBlock(r,c)->domain()));
1020  }
1021  }
1022  blocked_diag->endBlockFill();
1023  return blocked_diag;
1024  }
1025 
1026  if (Teko::TpetraHelpers::isTpetraLinearOp(op)){
1027  ST scalar = 0.0;
1028  bool transp = false;
1029  RCP<const Tpetra::CrsMatrix<ST,LO,GO,NT> > tCrsOp = Teko::TpetraHelpers::getTpetraCrsMatrix(op, &scalar, &transp);
1030 
1031  // extract diagonal
1032  const RCP<Tpetra::Vector<ST,LO,GO,NT> > diag = Tpetra::createVector<ST,LO,GO,NT>(tCrsOp->getRowMap());
1033  diag->scale(scalar);
1034  tCrsOp->getLocalDiagCopy(*diag);
1035  diag->reciprocal(*diag);
1036 
1037  // build Thyra diagonal operator
1038  return Teko::TpetraHelpers::thyraDiagOp(diag,*tCrsOp->getRowMap(),"inv(diag( " + op->getObjectLabel() + " ))");
1039 
1040  }
1041  else {
1042  RCP<const Thyra::EpetraLinearOp > eOp = rcp_dynamic_cast<const Thyra::EpetraLinearOp >(op,true);
1043  RCP<const Epetra_CrsMatrix> eCrsOp = rcp_dynamic_cast<const Epetra_CrsMatrix>(eOp->epetra_op(),true);
1044 
1045  // extract diagonal
1046  const RCP<Epetra_Vector> diag = rcp(new Epetra_Vector(eCrsOp->RowMap()));
1047  TEUCHOS_TEST_FOR_EXCEPT(eCrsOp->ExtractDiagonalCopy(*diag));
1048  diag->Reciprocal(*diag);
1049 
1050  // build Thyra diagonal operator
1051  return Teko::Epetra::thyraDiagOp(diag,eCrsOp->RowMap(),"inv(diag( " + op->getObjectLabel() + " ))");
1052  }
1053 }
1054 
1067 const LinearOp explicitMultiply(const LinearOp & opl,const LinearOp & opm,const LinearOp & opr)
1068 {
1069  // if this is a blocked operator, multiply block by block
1070  // it is possible that not every factor in the product is blocked and these situations are handled separately
1071 
1072  bool isBlockedL = isPhysicallyBlockedLinearOp(opl);
1073  bool isBlockedM = isPhysicallyBlockedLinearOp(opm);
1074  bool isBlockedR = isPhysicallyBlockedLinearOp(opr);
1075 
1076  // all factors blocked
1077  if((isBlockedL && isBlockedM && isBlockedR)){
1078 
1079  double scalarl = 0.0;
1080  bool transpl = false;
1081  RCP<const Thyra::PhysicallyBlockedLinearOpBase<double> > blocked_opl = getPhysicallyBlockedLinearOp(opl,&scalarl,&transpl);
1082  double scalarm = 0.0;
1083  bool transpm = false;
1084  RCP<const Thyra::PhysicallyBlockedLinearOpBase<double> > blocked_opm = getPhysicallyBlockedLinearOp(opm,&scalarm,&transpm);
1085  double scalarr = 0.0;
1086  bool transpr = false;
1087  RCP<const Thyra::PhysicallyBlockedLinearOpBase<double> > blocked_opr = getPhysicallyBlockedLinearOp(opr,&scalarr,&transpr);
1088  double scalar = scalarl*scalarm*scalarr;
1089 
1090  int numRows = blocked_opl->productRange()->numBlocks();
1091  int numCols = blocked_opr->productDomain()->numBlocks();
1092  int numMiddle = blocked_opm->productRange()->numBlocks();
1093 
1094  // Assume that the middle block is block nxn and that it's diagonal. Otherwise use the two argument explicitMultiply twice
1095  TEUCHOS_ASSERT(blocked_opm->productDomain()->numBlocks() == numMiddle);
1096  TEUCHOS_ASSERT(blocked_opl->productDomain()->numBlocks() == numMiddle);
1097  TEUCHOS_ASSERT(blocked_opr->productRange()->numBlocks() == numMiddle);
1098 
1099  RCP<Thyra::PhysicallyBlockedLinearOpBase<double> > blocked_product = Thyra::defaultBlockedLinearOp<double>();
1100  blocked_product->beginBlockFill(numRows,numCols);
1101  for(int r = 0; r < numRows; ++r){
1102  for(int c = 0; c < numCols; ++c){
1103  LinearOp product_rc = explicitMultiply(blocked_opl->getBlock(r,0),blocked_opm->getBlock(0,0),blocked_opr->getBlock(0,c));
1104  for(int m = 1; m < numMiddle; ++m){
1105  LinearOp product_m = explicitMultiply(blocked_opl->getBlock(r,m),blocked_opm->getBlock(m,m),blocked_opr->getBlock(m,c));
1106  product_rc = explicitAdd(product_rc,product_m);
1107  }
1108  blocked_product->setBlock(r,c,product_rc);
1109  }
1110  }
1111  blocked_product->endBlockFill();
1112  return Thyra::scale<double>(scalar,blocked_product.getConst());
1113  }
1114 
1115  // left and right factors blocked
1116  if(isBlockedL && !isBlockedM && isBlockedR){
1117  double scalarl = 0.0;
1118  bool transpl = false;
1119  RCP<const Thyra::PhysicallyBlockedLinearOpBase<double> > blocked_opl = getPhysicallyBlockedLinearOp(opl,&scalarl,&transpl);
1120  double scalarr = 0.0;
1121  bool transpr = false;
1122  RCP<const Thyra::PhysicallyBlockedLinearOpBase<double> > blocked_opr = getPhysicallyBlockedLinearOp(opr,&scalarr,&transpr);
1123  double scalar = scalarl*scalarr;
1124 
1125  int numRows = blocked_opl->productRange()->numBlocks();
1126  int numCols = blocked_opr->productDomain()->numBlocks();
1127  int numMiddle = 1;
1128 
1129  // Assume that the middle block is 1x1 diagonal. Left must be rx1, right 1xc
1130  TEUCHOS_ASSERT(blocked_opl->productDomain()->numBlocks() == numMiddle);
1131  TEUCHOS_ASSERT(blocked_opr->productRange()->numBlocks() == numMiddle);
1132 
1133  RCP<Thyra::PhysicallyBlockedLinearOpBase<double> > blocked_product = Thyra::defaultBlockedLinearOp<double>();
1134  blocked_product->beginBlockFill(numRows,numCols);
1135  for(int r = 0; r < numRows; ++r){
1136  for(int c = 0; c < numCols; ++c){
1137  LinearOp product_rc = explicitMultiply(blocked_opl->getBlock(r,0),opm,blocked_opr->getBlock(0,c));
1138  blocked_product->setBlock(r,c,product_rc);
1139  }
1140  }
1141  blocked_product->endBlockFill();
1142  return Thyra::scale<double>(scalar,blocked_product.getConst());
1143  }
1144 
1145  // only right factor blocked
1146  if(!isBlockedL && !isBlockedM && isBlockedR){
1147  double scalarr = 0.0;
1148  bool transpr = false;
1149  RCP<const Thyra::PhysicallyBlockedLinearOpBase<double> > blocked_opr = getPhysicallyBlockedLinearOp(opr,&scalarr,&transpr);
1150  double scalar = scalarr;
1151 
1152  int numRows = 1;
1153  int numCols = blocked_opr->productDomain()->numBlocks();
1154  int numMiddle = 1;
1155 
1156  // Assume that the middle block is 1x1 diagonal, left is 1x1. Right must be 1xc
1157  TEUCHOS_ASSERT(blocked_opr->productRange()->numBlocks() == numMiddle);
1158 
1159  RCP<Thyra::PhysicallyBlockedLinearOpBase<double> > blocked_product = Thyra::defaultBlockedLinearOp<double>();
1160  blocked_product->beginBlockFill(numRows,numCols);
1161  for(int c = 0; c < numCols; ++c){
1162  LinearOp product_c = explicitMultiply(opl,opm,blocked_opr->getBlock(0,c));
1163  blocked_product->setBlock(0,c,product_c);
1164  }
1165  blocked_product->endBlockFill();
1166  return Thyra::scale<double>(scalar,blocked_product.getConst());
1167  }
1168 
1169  //TODO: three more cases (only non-blocked - blocked - non-blocked not possible)
1170 
1171  bool isTpetral = Teko::TpetraHelpers::isTpetraLinearOp(opl);
1172  bool isTpetram = Teko::TpetraHelpers::isTpetraLinearOp(opm);
1173  bool isTpetrar = Teko::TpetraHelpers::isTpetraLinearOp(opr);
1174 
1175  if(isTpetral && isTpetram && isTpetrar){ // Both operators are Tpetra matrices so explicitly multiply them
1176 
1177  // Get left and right Tpetra crs operators
1178  ST scalarl = 0.0;
1179  bool transpl = false;
1180  RCP<const Tpetra::CrsMatrix<ST,LO,GO,NT> > tCrsOpl = Teko::TpetraHelpers::getTpetraCrsMatrix(opl, &scalarl, &transpl);
1181  ST scalarm = 0.0;
1182  bool transpm = false;
1183  RCP<const Tpetra::CrsMatrix<ST,LO,GO,NT> > tCrsOpm = Teko::TpetraHelpers::getTpetraCrsMatrix(opl, &scalarm, &transpm);
1184  ST scalarr = 0.0;
1185  bool transpr = false;
1186  RCP<const Tpetra::CrsMatrix<ST,LO,GO,NT> > tCrsOpr = Teko::TpetraHelpers::getTpetraCrsMatrix(opr, &scalarr, &transpr);
1187 
1188  // Build output operator
1189  RCP<Thyra::LinearOpBase<ST> > explicitOp = rcp(new Thyra::TpetraLinearOp<ST,LO,GO,NT>());
1190  RCP<Thyra::TpetraLinearOp<ST,LO,GO,NT> > tExplicitOp = rcp_dynamic_cast<Thyra::TpetraLinearOp<ST,LO,GO,NT> >(explicitOp);
1191 
1192  // Do explicit matrix-matrix multiply
1193  RCP<Tpetra::CrsMatrix<ST,LO,GO,NT> > tCrsOplm = Tpetra::createCrsMatrix<ST,LO,GO,NT>(tCrsOpl->getRowMap());
1194  RCP<Tpetra::CrsMatrix<ST,LO,GO,NT> > explicitCrsOp = Tpetra::createCrsMatrix<ST,LO,GO,NT>(tCrsOpl->getRowMap());
1195  Tpetra::MatrixMatrix::Multiply<ST,LO,GO,NT>(*tCrsOpl,transpl,*tCrsOpm,transpm,*tCrsOplm);
1196  Tpetra::MatrixMatrix::Multiply<ST,LO,GO,NT>(*tCrsOplm,false,*tCrsOpr,transpr,*explicitCrsOp);
1197  explicitCrsOp->resumeFill();
1198  explicitCrsOp->scale(scalarl*scalarm*scalarr);
1199  explicitCrsOp->fillComplete(tCrsOpr->getDomainMap(),tCrsOpl->getRangeMap());
1200  tExplicitOp->initialize(Thyra::tpetraVectorSpace<ST,LO,GO,NT>(explicitCrsOp->getRangeMap()),Thyra::tpetraVectorSpace<ST,LO,GO,NT>(explicitCrsOp->getDomainMap()),explicitCrsOp);
1201  return tExplicitOp;
1202 
1203  } else if (isTpetral && !isTpetram && isTpetrar){ // Assume that the middle operator is diagonal
1204 
1205  // Get left and right Tpetra crs operators
1206  ST scalarl = 0.0;
1207  bool transpl = false;
1208  RCP<const Tpetra::CrsMatrix<ST,LO,GO,NT> > tCrsOpl = Teko::TpetraHelpers::getTpetraCrsMatrix(opl, &scalarl, &transpl);
1209  ST scalarr = 0.0;
1210  bool transpr = false;
1211  RCP<const Tpetra::CrsMatrix<ST,LO,GO,NT> > tCrsOpr = Teko::TpetraHelpers::getTpetraCrsMatrix(opr, &scalarr, &transpr);
1212 
1213  RCP<const Tpetra::Vector<ST,LO,GO,NT> > diagPtr;
1214 
1215  // Cast middle operator as DiagonalLinearOp and extract diagonal as Vector
1216  RCP<const Thyra::DiagonalLinearOpBase<ST> > dOpm = rcp_dynamic_cast<const Thyra::DiagonalLinearOpBase<ST> >(opm);
1217  if(dOpm != Teuchos::null){
1218  RCP<const Thyra::TpetraVector<ST,LO,GO,NT> > tPtr = rcp_dynamic_cast<const Thyra::TpetraVector<ST,LO,GO,NT> >(dOpm->getDiag(),true);
1219  diagPtr = rcp_dynamic_cast<const Tpetra::Vector<ST,LO,GO,NT> >(tPtr->getConstTpetraVector(),true);
1220  }
1221  // If it's not diagonal, maybe it's zero
1222  else if(rcp_dynamic_cast<const Thyra::ZeroLinearOpBase<ST> >(opm) != Teuchos::null){
1223  diagPtr = rcp(new Tpetra::Vector<ST,LO,GO,NT>(tCrsOpl->getDomainMap()));
1224  }
1225  else
1226  TEUCHOS_ASSERT(false);
1227 
1228  RCP<Tpetra::CrsMatrix<ST,LO,GO,NT> > tCrsOplm = Tpetra::importAndFillCompleteCrsMatrix<Tpetra::CrsMatrix<ST,LO,GO,NT> >(tCrsOpl, Tpetra::Import<LO,GO,NT>(tCrsOpl->getRowMap(),tCrsOpl->getRowMap()));
1229 
1230  // Do the diagonal scaling
1231  tCrsOplm->rightScale(*diagPtr);
1232 
1233  // Build output operator
1234  RCP<Thyra::LinearOpBase<ST> > explicitOp = rcp(new Thyra::TpetraLinearOp<ST,LO,GO,NT>());
1235  RCP<Thyra::TpetraLinearOp<ST,LO,GO,NT> > tExplicitOp = rcp_dynamic_cast<Thyra::TpetraLinearOp<ST,LO,GO,NT> >(explicitOp);
1236 
1237  // Do explicit matrix-matrix multiply
1238  RCP<Tpetra::CrsMatrix<ST,LO,GO,NT> > explicitCrsOp = Tpetra::createCrsMatrix<ST,LO,GO,NT>(tCrsOpl->getRowMap());
1239  Tpetra::MatrixMatrix::Multiply<ST,LO,GO,NT>(*tCrsOplm,false,*tCrsOpr,transpr,*explicitCrsOp);
1240  explicitCrsOp->resumeFill();
1241  explicitCrsOp->scale(scalarl*scalarr);
1242  explicitCrsOp->fillComplete(tCrsOpr->getDomainMap(),tCrsOpl->getRangeMap());
1243  tExplicitOp->initialize(Thyra::tpetraVectorSpace<ST,LO,GO,NT>(explicitCrsOp->getRangeMap()),Thyra::tpetraVectorSpace<ST,LO,GO,NT>(explicitCrsOp->getDomainMap()),explicitCrsOp);
1244  return tExplicitOp;
1245 
1246  } else { // Assume Epetra and we can use transformers
1247 
1248  // build implicit multiply
1249  const LinearOp implicitOp = Thyra::multiply(opl,opm,opr);
1250 
1251  // build transformer
1252  const RCP<Thyra::LinearOpTransformerBase<double> > prodTrans =
1253  Thyra::epetraExtDiagScaledMatProdTransformer();
1254 
1255  // build operator and multiply
1256  const RCP<Thyra::LinearOpBase<double> > explicitOp = prodTrans->createOutputOp();
1257  prodTrans->transform(*implicitOp,explicitOp.ptr());
1258  explicitOp->setObjectLabel("explicit( " + opl->getObjectLabel() +
1259  " * " + opm->getObjectLabel() +
1260  " * " + opr->getObjectLabel() + " )");
1261 
1262  return explicitOp;
1263 
1264  }
1265 }
1266 
1281 const ModifiableLinearOp explicitMultiply(const LinearOp & opl,const LinearOp & opm,const LinearOp & opr,
1282  const ModifiableLinearOp & destOp)
1283 {
1284  bool isTpetral = Teko::TpetraHelpers::isTpetraLinearOp(opl);
1285  bool isTpetram = Teko::TpetraHelpers::isTpetraLinearOp(opm);
1286  bool isTpetrar = Teko::TpetraHelpers::isTpetraLinearOp(opr);
1287 
1288  if(isTpetral && isTpetram && isTpetrar){ // Both operators are Tpetra matrices so explicitly multiply them
1289 
1290  // Get left and right Tpetra crs operators
1291  ST scalarl = 0.0;
1292  bool transpl = false;
1293  RCP<const Tpetra::CrsMatrix<ST,LO,GO,NT> > tCrsOpl = Teko::TpetraHelpers::getTpetraCrsMatrix(opl, &scalarl, &transpl);
1294  ST scalarm = 0.0;
1295  bool transpm = false;
1296  RCP<const Tpetra::CrsMatrix<ST,LO,GO,NT> > tCrsOpm = Teko::TpetraHelpers::getTpetraCrsMatrix(opm, &scalarm, &transpm);
1297  ST scalarr = 0.0;
1298  bool transpr = false;
1299  RCP<const Tpetra::CrsMatrix<ST,LO,GO,NT> > tCrsOpr = Teko::TpetraHelpers::getTpetraCrsMatrix(opr, &scalarr, &transpr);
1300 
1301  // Build output operator
1302  auto tExplicitOp = rcp_dynamic_cast<Thyra::TpetraLinearOp<ST,LO,GO,NT> >(destOp);
1303  if(tExplicitOp.is_null())
1304  tExplicitOp = rcp(new Thyra::TpetraLinearOp<ST,LO,GO,NT>());
1305 
1306  // Do explicit matrix-matrix multiply
1307  RCP<Tpetra::CrsMatrix<ST,LO,GO,NT> > tCrsOplm = Tpetra::createCrsMatrix<ST,LO,GO,NT>(tCrsOpl->getRowMap());
1308  RCP<Tpetra::CrsMatrix<ST,LO,GO,NT> > explicitCrsOp = Tpetra::createCrsMatrix<ST,LO,GO,NT>(tCrsOpl->getRowMap());
1309  Tpetra::MatrixMatrix::Multiply<ST,LO,GO,NT>(*tCrsOpl,transpl,*tCrsOpm,transpm,*tCrsOplm);
1310  Tpetra::MatrixMatrix::Multiply<ST,LO,GO,NT>(*tCrsOplm,false,*tCrsOpr,transpr,*explicitCrsOp);
1311  explicitCrsOp->resumeFill();
1312  explicitCrsOp->scale(scalarl*scalarm*scalarr);
1313  explicitCrsOp->fillComplete(tCrsOpr->getDomainMap(),tCrsOpl->getRangeMap());
1314  tExplicitOp->initialize(Thyra::tpetraVectorSpace<ST,LO,GO,NT>(explicitCrsOp->getRangeMap()),Thyra::tpetraVectorSpace<ST,LO,GO,NT>(explicitCrsOp->getDomainMap()),explicitCrsOp);
1315  return tExplicitOp;
1316 
1317  } else if (isTpetral && !isTpetram && isTpetrar){ // Assume that the middle operator is diagonal
1318 
1319  // Get left and right Tpetra crs operators
1320  ST scalarl = 0.0;
1321  bool transpl = false;
1322  RCP<const Tpetra::CrsMatrix<ST,LO,GO,NT> > tCrsOpl = Teko::TpetraHelpers::getTpetraCrsMatrix(opl, &scalarl, &transpl);
1323  ST scalarr = 0.0;
1324  bool transpr = false;
1325  RCP<const Tpetra::CrsMatrix<ST,LO,GO,NT> > tCrsOpr = Teko::TpetraHelpers::getTpetraCrsMatrix(opr, &scalarr, &transpr);
1326 
1327  // Cast middle operator as DiagonalLinearOp and extract diagonal as Vector
1328  RCP<const Thyra::DiagonalLinearOpBase<ST> > dOpm = rcp_dynamic_cast<const Thyra::DiagonalLinearOpBase<ST> >(opm,true);
1329  RCP<const Thyra::TpetraVector<ST,LO,GO,NT> > tPtr = rcp_dynamic_cast<const Thyra::TpetraVector<ST,LO,GO,NT> >(dOpm->getDiag(),true);
1330  RCP<const Tpetra::Vector<ST,LO,GO,NT> > diagPtr = rcp_dynamic_cast<const Tpetra::Vector<ST,LO,GO,NT> >(tPtr->getConstTpetraVector(),true);
1331  RCP<Tpetra::CrsMatrix<ST,LO,GO,NT> > tCrsOplm = Tpetra::importAndFillCompleteCrsMatrix<Tpetra::CrsMatrix<ST,LO,GO,NT> >(tCrsOpl, Tpetra::Import<LO,GO,NT>(tCrsOpl->getRowMap(),tCrsOpl->getRowMap()));
1332 
1333  // Do the diagonal scaling
1334  tCrsOplm->rightScale(*diagPtr);
1335 
1336  // Build output operator
1337  RCP<Thyra::LinearOpBase<ST> > explicitOp = rcp(new Thyra::TpetraLinearOp<ST,LO,GO,NT>());
1338  RCP<Thyra::TpetraLinearOp<ST,LO,GO,NT> > tExplicitOp = rcp_dynamic_cast<Thyra::TpetraLinearOp<ST,LO,GO,NT> >(explicitOp);
1339 
1340  // Do explicit matrix-matrix multiply
1341  RCP<Tpetra::CrsMatrix<ST,LO,GO,NT> > explicitCrsOp = Tpetra::createCrsMatrix<ST,LO,GO,NT>(tCrsOpl->getRowMap());
1342  Tpetra::MatrixMatrix::Multiply<ST,LO,GO,NT>(*tCrsOplm,false,*tCrsOpr,transpr,*explicitCrsOp);
1343  explicitCrsOp->resumeFill();
1344  explicitCrsOp->scale(scalarl*scalarr);
1345  explicitCrsOp->fillComplete(tCrsOpr->getDomainMap(),tCrsOpl->getRangeMap());
1346  tExplicitOp->initialize(Thyra::tpetraVectorSpace<ST,LO,GO,NT>(explicitCrsOp->getRangeMap()),Thyra::tpetraVectorSpace<ST,LO,GO,NT>(explicitCrsOp->getDomainMap()),explicitCrsOp);
1347  return tExplicitOp;
1348 
1349  } else { // Assume Epetra and we can use transformers
1350 
1351  // build implicit multiply
1352  const LinearOp implicitOp = Thyra::multiply(opl,opm,opr);
1353 
1354  // build transformer
1355  const RCP<Thyra::LinearOpTransformerBase<double> > prodTrans =
1356  Thyra::epetraExtDiagScaledMatProdTransformer();
1357 
1358  // build operator destination operator
1359  ModifiableLinearOp explicitOp;
1360 
1361  // if neccessary build a operator to put the explicit multiply into
1362  if(destOp==Teuchos::null)
1363  explicitOp = prodTrans->createOutputOp();
1364  else
1365  explicitOp = destOp;
1366 
1367  // perform multiplication
1368  prodTrans->transform(*implicitOp,explicitOp.ptr());
1369 
1370  // label it
1371  explicitOp->setObjectLabel("explicit( " + opl->getObjectLabel() +
1372  " * " + opm->getObjectLabel() +
1373  " * " + opr->getObjectLabel() + " )");
1374 
1375  return explicitOp;
1376 
1377  }
1378 }
1379 
1390 const LinearOp explicitMultiply(const LinearOp & opl,const LinearOp & opr)
1391 {
1392  // if this is a blocked operator, multiply block by block
1393  // it is possible that not every factor in the product is blocked and these situations are handled separately
1394 
1395  bool isBlockedL = isPhysicallyBlockedLinearOp(opl);
1396  bool isBlockedR = isPhysicallyBlockedLinearOp(opr);
1397 
1398  // both factors blocked
1399  if((isBlockedL && isBlockedR)){
1400  double scalarl = 0.0;
1401  bool transpl = false;
1402  RCP<const Thyra::PhysicallyBlockedLinearOpBase<double> > blocked_opl = getPhysicallyBlockedLinearOp(opl,&scalarl,&transpl);
1403  double scalarr = 0.0;
1404  bool transpr = false;
1405  RCP<const Thyra::PhysicallyBlockedLinearOpBase<double> > blocked_opr = getPhysicallyBlockedLinearOp(opr,&scalarr,&transpr);
1406  double scalar = scalarl*scalarr;
1407 
1408  int numRows = blocked_opl->productRange()->numBlocks();
1409  int numCols = blocked_opr->productDomain()->numBlocks();
1410  int numMiddle = blocked_opl->productDomain()->numBlocks();
1411 
1412  TEUCHOS_ASSERT(blocked_opr->productRange()->numBlocks() == numMiddle);
1413 
1414  RCP<Thyra::PhysicallyBlockedLinearOpBase<double> > blocked_product = Thyra::defaultBlockedLinearOp<double>();
1415  blocked_product->beginBlockFill(numRows,numCols);
1416  for(int r = 0; r < numRows; ++r){
1417  for(int c = 0; c < numCols; ++c){
1418  LinearOp product_rc = explicitMultiply(blocked_opl->getBlock(r,0),blocked_opr->getBlock(0,c));
1419  for(int m = 1; m < numMiddle; ++m){
1420  LinearOp product_m = explicitMultiply(blocked_opl->getBlock(r,m),blocked_opr->getBlock(m,c));
1421  product_rc = explicitAdd(product_rc,product_m);
1422  }
1423  blocked_product->setBlock(r,c,Thyra::scale(scalar,product_rc));
1424  }
1425  }
1426  blocked_product->endBlockFill();
1427  return blocked_product;
1428  }
1429 
1430  // only left factor blocked
1431  if((isBlockedL && !isBlockedR)){
1432  double scalarl = 0.0;
1433  bool transpl = false;
1434  RCP<const Thyra::PhysicallyBlockedLinearOpBase<double> > blocked_opl = getPhysicallyBlockedLinearOp(opl,&scalarl,&transpl);
1435  double scalar = scalarl;
1436 
1437  int numRows = blocked_opl->productRange()->numBlocks();
1438  int numCols = 1;
1439  int numMiddle = 1;
1440 
1441  TEUCHOS_ASSERT(blocked_opl->productDomain()->numBlocks() == numMiddle);
1442 
1443  RCP<Thyra::PhysicallyBlockedLinearOpBase<double> > blocked_product = Thyra::defaultBlockedLinearOp<double>();
1444  blocked_product->beginBlockFill(numRows,numCols);
1445  for(int r = 0; r < numRows; ++r){
1446  LinearOp product_r = explicitMultiply(blocked_opl->getBlock(r,0),opr);
1447  blocked_product->setBlock(r,0,Thyra::scale(scalar,product_r));
1448  }
1449  blocked_product->endBlockFill();
1450  return blocked_product;
1451  }
1452 
1453  // only right factor blocked
1454  if((!isBlockedL && isBlockedR)){
1455  double scalarr = 0.0;
1456  bool transpr = false;
1457  RCP<const Thyra::PhysicallyBlockedLinearOpBase<double> > blocked_opr = getPhysicallyBlockedLinearOp(opr,&scalarr,&transpr);
1458  double scalar = scalarr;
1459 
1460  int numRows = 1;
1461  int numCols = blocked_opr->productDomain()->numBlocks();
1462  int numMiddle = 1;
1463 
1464  TEUCHOS_ASSERT(blocked_opr->productRange()->numBlocks() == numMiddle);
1465 
1466  RCP<Thyra::PhysicallyBlockedLinearOpBase<double> > blocked_product = Thyra::defaultBlockedLinearOp<double>();
1467  blocked_product->beginBlockFill(numRows,numCols);
1468  for(int c = 0; c < numCols; ++c){
1469  LinearOp product_c = explicitMultiply(opl,blocked_opr->getBlock(0,c));
1470  blocked_product->setBlock(0,c,Thyra::scale(scalar,product_c));
1471  }
1472  blocked_product->endBlockFill();
1473  return blocked_product;
1474  }
1475 
1476  bool isTpetral = Teko::TpetraHelpers::isTpetraLinearOp(opl);
1477  bool isTpetrar = Teko::TpetraHelpers::isTpetraLinearOp(opr);
1478 
1479  if(isTpetral && isTpetrar){ // Both operators are Tpetra matrices so explicitly multiply them
1480  // Get left and right Tpetra crs operators
1481  ST scalarl = 0.0;
1482  bool transpl = false;
1483  RCP<const Tpetra::CrsMatrix<ST,LO,GO,NT> > tCrsOpl = Teko::TpetraHelpers::getTpetraCrsMatrix(opl, &scalarl, &transpl);
1484  ST scalarr = 0.0;
1485  bool transpr = false;
1486  RCP<const Tpetra::CrsMatrix<ST,LO,GO,NT> > tCrsOpr = Teko::TpetraHelpers::getTpetraCrsMatrix(opr, &scalarr, &transpr);
1487 
1488  // Build output operator
1489  RCP<Thyra::LinearOpBase<ST> > explicitOp = rcp(new Thyra::TpetraLinearOp<ST,LO,GO,NT>());
1490  RCP<Thyra::TpetraLinearOp<ST,LO,GO,NT> > tExplicitOp = rcp_dynamic_cast<Thyra::TpetraLinearOp<ST,LO,GO,NT> >(explicitOp);
1491 
1492  // Do explicit matrix-matrix multiply
1493  RCP<Tpetra::CrsMatrix<ST,LO,GO,NT> > explicitCrsOp = Tpetra::createCrsMatrix<ST,LO,GO,NT>(tCrsOpl->getRowMap());
1494  Tpetra::MatrixMatrix::Multiply<ST,LO,GO,NT>(*tCrsOpl,transpl,*tCrsOpr,transpr,*explicitCrsOp);
1495  explicitCrsOp->resumeFill();
1496  explicitCrsOp->scale(scalarl*scalarr);
1497  explicitCrsOp->fillComplete(tCrsOpr->getDomainMap(),tCrsOpl->getRangeMap());
1498  tExplicitOp->initialize(Thyra::tpetraVectorSpace<ST,LO,GO,NT>(explicitCrsOp->getRangeMap()),Thyra::tpetraVectorSpace<ST,LO,GO,NT>(explicitCrsOp->getDomainMap()),explicitCrsOp);
1499  return tExplicitOp;
1500 
1501  } else if (isTpetral && !isTpetrar){ // Assume that the right operator is diagonal
1502 
1503  // Get left Tpetra crs operator
1504  ST scalarl = 0.0;
1505  bool transpl = false;
1506  RCP<const Tpetra::CrsMatrix<ST,LO,GO,NT> > tCrsOpl = Teko::TpetraHelpers::getTpetraCrsMatrix(opl, &scalarl, &transpl);
1507 
1508  // Cast right operator as DiagonalLinearOp and extract diagonal as Vector
1509  RCP<const Thyra::DiagonalLinearOpBase<ST> > dOpr = rcp_dynamic_cast<const Thyra::DiagonalLinearOpBase<ST> >(opr,true);
1510  RCP<const Thyra::TpetraVector<ST,LO,GO,NT> > tPtr = rcp_dynamic_cast<const Thyra::TpetraVector<ST,LO,GO,NT> >(dOpr->getDiag(),true);
1511  RCP<const Tpetra::Vector<ST,LO,GO,NT> > diagPtr = rcp_dynamic_cast<const Tpetra::Vector<ST,LO,GO,NT> >(tPtr->getConstTpetraVector(),true);
1512  RCP<Tpetra::CrsMatrix<ST,LO,GO,NT> > explicitCrsOp = Tpetra::importAndFillCompleteCrsMatrix<Tpetra::CrsMatrix<ST,LO,GO,NT> >(tCrsOpl, Tpetra::Import<LO,GO,NT>(tCrsOpl->getRowMap(),tCrsOpl->getRowMap()));
1513 
1514  explicitCrsOp->rightScale(*diagPtr);
1515  explicitCrsOp->resumeFill();
1516  explicitCrsOp->scale(scalarl);
1517  explicitCrsOp->fillComplete(tCrsOpl->getDomainMap(),tCrsOpl->getRangeMap());
1518 
1519  return Thyra::constTpetraLinearOp<ST,LO,GO,NT>(Thyra::tpetraVectorSpace<ST,LO,GO,NT>(explicitCrsOp->getRangeMap()),Thyra::tpetraVectorSpace<ST,LO,GO,NT>(explicitCrsOp->getDomainMap()),explicitCrsOp);
1520 
1521  } else if (!isTpetral && isTpetrar){ // Assume that the left operator is diagonal
1522 
1523  // Get right Tpetra crs operator
1524  ST scalarr = 0.0;
1525  bool transpr = false;
1526  RCP<const Tpetra::CrsMatrix<ST,LO,GO,NT> > tCrsOpr = Teko::TpetraHelpers::getTpetraCrsMatrix(opr, &scalarr, &transpr);
1527 
1528  RCP<const Tpetra::Vector<ST,LO,GO,NT> > diagPtr;
1529 
1530  // Cast left operator as DiagonalLinearOp and extract diagonal as Vector
1531  RCP<const Thyra::DiagonalLinearOpBase<ST> > dOpl = rcp_dynamic_cast<const Thyra::DiagonalLinearOpBase<ST> >(opl);
1532  if(dOpl != Teuchos::null){
1533  RCP<const Thyra::TpetraVector<ST,LO,GO,NT> > tPtr = rcp_dynamic_cast<const Thyra::TpetraVector<ST,LO,GO,NT> >(dOpl->getDiag(),true);
1534  diagPtr = rcp_dynamic_cast<const Tpetra::Vector<ST,LO,GO,NT> >(tPtr->getConstTpetraVector(),true);
1535  }
1536  // If it's not diagonal, maybe it's zero
1537  else if(rcp_dynamic_cast<const Thyra::ZeroLinearOpBase<ST> >(opl) != Teuchos::null){
1538  diagPtr = rcp(new Tpetra::Vector<ST,LO,GO,NT>(tCrsOpr->getRangeMap()));
1539  }
1540  else
1541  TEUCHOS_ASSERT(false);
1542 
1543  RCP<Tpetra::CrsMatrix<ST,LO,GO,NT> > explicitCrsOp = Tpetra::importAndFillCompleteCrsMatrix<Tpetra::CrsMatrix<ST,LO,GO,NT> >(tCrsOpr, Tpetra::Import<LO,GO,NT>(tCrsOpr->getRowMap(),tCrsOpr->getRowMap()));
1544 
1545  explicitCrsOp->leftScale(*diagPtr);
1546  explicitCrsOp->resumeFill();
1547  explicitCrsOp->scale(scalarr);
1548  explicitCrsOp->fillComplete(tCrsOpr->getDomainMap(),tCrsOpr->getRangeMap());
1549 
1550  return Thyra::constTpetraLinearOp<ST,LO,GO,NT>(Thyra::tpetraVectorSpace<ST,LO,GO,NT>(explicitCrsOp->getRangeMap()),Thyra::tpetraVectorSpace<ST,LO,GO,NT>(explicitCrsOp->getDomainMap()),explicitCrsOp);
1551 
1552  } else { // Assume Epetra and we can use transformers
1553 
1554  // build implicit multiply
1555  const LinearOp implicitOp = Thyra::multiply(opl,opr);
1556 
1557  // build a scaling transformer
1558  RCP<Thyra::LinearOpTransformerBase<double> > prodTrans
1559  = Thyra::epetraExtDiagScalingTransformer();
1560 
1561  // check to see if a scaling transformer works: if not use the
1562  // DiagScaledMatrixProduct transformer
1563  if(not prodTrans->isCompatible(*implicitOp))
1564  prodTrans = Thyra::epetraExtDiagScaledMatProdTransformer();
1565 
1566  // build operator and multiply
1567  const RCP<Thyra::LinearOpBase<double> > explicitOp = prodTrans->createOutputOp();
1568  prodTrans->transform(*implicitOp,explicitOp.ptr());
1569  explicitOp->setObjectLabel("explicit( " + opl->getObjectLabel() +
1570  " * " + opr->getObjectLabel() + " )");
1571 
1572  return explicitOp;
1573  }
1574 }
1575 
1589 const ModifiableLinearOp explicitMultiply(const LinearOp & opl,const LinearOp & opr,
1590  const ModifiableLinearOp & destOp)
1591 {
1592  // if this is a blocked operator, multiply block by block
1593  // it is possible that not every factor in the product is blocked and these situations are handled separately
1594 
1595  bool isBlockedL = isPhysicallyBlockedLinearOp(opl);
1596  bool isBlockedR = isPhysicallyBlockedLinearOp(opr);
1597 
1598  // both factors blocked
1599  if((isBlockedL && isBlockedR)){
1600  double scalarl = 0.0;
1601  bool transpl = false;
1602  RCP<const Thyra::PhysicallyBlockedLinearOpBase<double> > blocked_opl = getPhysicallyBlockedLinearOp(opl,&scalarl,&transpl);
1603  double scalarr = 0.0;
1604  bool transpr = false;
1605  RCP<const Thyra::PhysicallyBlockedLinearOpBase<double> > blocked_opr = getPhysicallyBlockedLinearOp(opr,&scalarr,&transpr);
1606  double scalar = scalarl*scalarr;
1607 
1608  int numRows = blocked_opl->productRange()->numBlocks();
1609  int numCols = blocked_opr->productDomain()->numBlocks();
1610  int numMiddle = blocked_opl->productDomain()->numBlocks();
1611 
1612  TEUCHOS_ASSERT(blocked_opr->productRange()->numBlocks() == numMiddle);
1613 
1614  RCP<Thyra::PhysicallyBlockedLinearOpBase<double> > blocked_product = Thyra::defaultBlockedLinearOp<double>();
1615  blocked_product->beginBlockFill(numRows,numCols);
1616  for(int r = 0; r < numRows; ++r){
1617  for(int c = 0; c < numCols; ++c){
1618 
1619  LinearOp product_rc = explicitMultiply(blocked_opl->getBlock(r,0),blocked_opr->getBlock(0,c));
1620  for(int m = 1; m < numMiddle; ++m){
1621  LinearOp product_m = explicitMultiply(blocked_opl->getBlock(r,m),blocked_opr->getBlock(m,c));
1622  product_rc = explicitAdd(product_rc,product_m);
1623  }
1624  blocked_product->setBlock(r,c,Thyra::scale(scalar,product_rc));
1625  }
1626  }
1627  blocked_product->endBlockFill();
1628  return blocked_product;
1629  }
1630 
1631  // only left factor blocked
1632  if((isBlockedL && !isBlockedR)){
1633  double scalarl = 0.0;
1634  bool transpl = false;
1635  RCP<const Thyra::PhysicallyBlockedLinearOpBase<double> > blocked_opl = getPhysicallyBlockedLinearOp(opl,&scalarl,&transpl);
1636  double scalar = scalarl;
1637 
1638  int numRows = blocked_opl->productRange()->numBlocks();
1639  int numCols = 1;
1640  int numMiddle = 1;
1641 
1642  TEUCHOS_ASSERT(blocked_opl->productDomain()->numBlocks() == numMiddle);
1643 
1644  RCP<Thyra::PhysicallyBlockedLinearOpBase<double> > blocked_product = Thyra::defaultBlockedLinearOp<double>();
1645  blocked_product->beginBlockFill(numRows,numCols);
1646  for(int r = 0; r < numRows; ++r){
1647  LinearOp product_r = explicitMultiply(blocked_opl->getBlock(r,0),opr);
1648  blocked_product->setBlock(r,0,Thyra::scale(scalar,product_r));
1649  }
1650  blocked_product->endBlockFill();
1651  return blocked_product;
1652  }
1653 
1654  // only right factor blocked
1655  if((!isBlockedL && isBlockedR)){
1656  double scalarr = 0.0;
1657  bool transpr = false;
1658  RCP<const Thyra::PhysicallyBlockedLinearOpBase<double> > blocked_opr = getPhysicallyBlockedLinearOp(opr,&scalarr,&transpr);
1659  double scalar = scalarr;
1660 
1661  int numRows = 1;
1662  int numCols = blocked_opr->productDomain()->numBlocks();
1663  int numMiddle = 1;
1664 
1665  TEUCHOS_ASSERT(blocked_opr->productRange()->numBlocks() == numMiddle);
1666 
1667  RCP<Thyra::PhysicallyBlockedLinearOpBase<double> > blocked_product = Thyra::defaultBlockedLinearOp<double>();
1668  blocked_product->beginBlockFill(numRows,numCols);
1669  for(int c = 0; c < numCols; ++c){
1670  LinearOp product_c = explicitMultiply(opl,blocked_opr->getBlock(0,c));
1671  blocked_product->setBlock(0,c,Thyra::scale(scalar,product_c));
1672  }
1673  blocked_product->endBlockFill();
1674  return blocked_product;
1675  }
1676 
1677  bool isTpetral = Teko::TpetraHelpers::isTpetraLinearOp(opl);
1678  bool isTpetrar = Teko::TpetraHelpers::isTpetraLinearOp(opr);
1679 
1680  if(isTpetral && isTpetrar){ // Both operators are Tpetra matrices so use the explicit Tpetra matrix-matrix multiply
1681 
1682  // Get left and right Tpetra crs operators
1683  ST scalarl = 0.0;
1684  bool transpl = false;
1685  RCP<const Tpetra::CrsMatrix<ST,LO,GO,NT> > tCrsOpl = Teko::TpetraHelpers::getTpetraCrsMatrix(opl, &scalarl, &transpl);
1686  ST scalarr = 0.0;
1687  bool transpr = false;
1688  RCP<const Tpetra::CrsMatrix<ST,LO,GO,NT> > tCrsOpr = Teko::TpetraHelpers::getTpetraCrsMatrix(opr, &scalarr, &transpr);
1689 
1690  // Build output operator
1691  RCP<Thyra::LinearOpBase<ST> > explicitOp;
1692  if(destOp!=Teuchos::null)
1693  explicitOp = destOp;
1694  else
1695  explicitOp = rcp(new Thyra::TpetraLinearOp<ST,LO,GO,NT>());
1696  RCP<Thyra::TpetraLinearOp<ST,LO,GO,NT> > tExplicitOp = rcp_dynamic_cast<Thyra::TpetraLinearOp<ST,LO,GO,NT> >(explicitOp);
1697 
1698  // Do explicit matrix-matrix multiply
1699  RCP<Tpetra::CrsMatrix<ST,LO,GO,NT> > explicitCrsOp = Tpetra::createCrsMatrix<ST,LO,GO,NT>(tCrsOpl->getRowMap());
1700  Tpetra::MatrixMatrix::Multiply<ST,LO,GO,NT>(*tCrsOpl,transpl,*tCrsOpr,transpr,*explicitCrsOp);
1701  explicitCrsOp->resumeFill();
1702  explicitCrsOp->scale(scalarl*scalarr);
1703  explicitCrsOp->fillComplete(tCrsOpr->getDomainMap(),tCrsOpl->getRangeMap());
1704  tExplicitOp->initialize(Thyra::tpetraVectorSpace<ST,LO,GO,NT>(explicitCrsOp->getRangeMap()),Thyra::tpetraVectorSpace<ST,LO,GO,NT>(explicitCrsOp->getDomainMap()),explicitCrsOp);
1705  return tExplicitOp;
1706 
1707  } else if (isTpetral && !isTpetrar){ // Assume that the right operator is diagonal
1708 
1709  // Get left Tpetra crs operator
1710  ST scalarl = 0.0;
1711  bool transpl = false;
1712  RCP<const Tpetra::CrsMatrix<ST,LO,GO,NT> > tCrsOpl = Teko::TpetraHelpers::getTpetraCrsMatrix(opl, &scalarl, &transpl);
1713 
1714  // Cast right operator as DiagonalLinearOp and extract diagonal as Vector
1715  RCP<const Thyra::DiagonalLinearOpBase<ST> > dOpr = rcp_dynamic_cast<const Thyra::DiagonalLinearOpBase<ST> >(opr);
1716  RCP<const Thyra::TpetraVector<ST,LO,GO,NT> > tPtr = rcp_dynamic_cast<const Thyra::TpetraVector<ST,LO,GO,NT> >(dOpr->getDiag(),true);
1717  RCP<const Tpetra::Vector<ST,LO,GO,NT> > diagPtr = rcp_dynamic_cast<const Tpetra::Vector<ST,LO,GO,NT> >(tPtr->getConstTpetraVector(),true);
1718 
1719  // Scale by the diagonal operator
1720  RCP<Tpetra::CrsMatrix<ST,LO,GO,NT> > explicitCrsOp = Tpetra::importAndFillCompleteCrsMatrix<Tpetra::CrsMatrix<ST,LO,GO,NT> >(tCrsOpl, Tpetra::Import<LO,GO,NT>(tCrsOpl->getRowMap(),tCrsOpl->getRowMap()));
1721  explicitCrsOp->rightScale(*diagPtr);
1722  explicitCrsOp->resumeFill();
1723  explicitCrsOp->scale(scalarl);
1724  explicitCrsOp->fillComplete(tCrsOpl->getDomainMap(),tCrsOpl->getRangeMap());
1725  return Thyra::tpetraLinearOp<ST,LO,GO,NT>(Thyra::tpetraVectorSpace<ST,LO,GO,NT>(explicitCrsOp->getRangeMap()),Thyra::tpetraVectorSpace<ST,LO,GO,NT>(explicitCrsOp->getDomainMap()),explicitCrsOp);
1726 
1727  } else if (!isTpetral && isTpetrar){ // Assume that the left operator is diagonal
1728 
1729  // Get right Tpetra crs operator
1730  ST scalarr = 0.0;
1731  bool transpr = false;
1732  RCP<const Tpetra::CrsMatrix<ST,LO,GO,NT> > tCrsOpr = Teko::TpetraHelpers::getTpetraCrsMatrix(opr, &scalarr, &transpr);
1733 
1734  // Cast leftt operator as DiagonalLinearOp and extract diagonal as Vector
1735  RCP<const Thyra::DiagonalLinearOpBase<ST> > dOpl = rcp_dynamic_cast<const Thyra::DiagonalLinearOpBase<ST> >(opl,true);
1736  RCP<const Thyra::TpetraVector<ST,LO,GO,NT> > tPtr = rcp_dynamic_cast<const Thyra::TpetraVector<ST,LO,GO,NT> >(dOpl->getDiag(),true);
1737  RCP<const Tpetra::Vector<ST,LO,GO,NT> > diagPtr = rcp_dynamic_cast<const Tpetra::Vector<ST,LO,GO,NT> >(tPtr->getConstTpetraVector(),true);
1738 
1739  // Scale by the diagonal operator
1740  RCP<Tpetra::CrsMatrix<ST,LO,GO,NT> > explicitCrsOp = Tpetra::importAndFillCompleteCrsMatrix<Tpetra::CrsMatrix<ST,LO,GO,NT> >(tCrsOpr, Tpetra::Import<LO,GO,NT>(tCrsOpr->getRowMap(),tCrsOpr->getRowMap()));
1741  explicitCrsOp->leftScale(*diagPtr);
1742  explicitCrsOp->resumeFill();
1743  explicitCrsOp->scale(scalarr);
1744  explicitCrsOp->fillComplete(tCrsOpr->getDomainMap(),tCrsOpr->getRangeMap());
1745  return Thyra::tpetraLinearOp<ST,LO,GO,NT>(Thyra::tpetraVectorSpace<ST,LO,GO,NT>(explicitCrsOp->getRangeMap()),Thyra::tpetraVectorSpace<ST,LO,GO,NT>(explicitCrsOp->getDomainMap()),explicitCrsOp);
1746 
1747  } else { // Assume Epetra and we can use transformers
1748 
1749  // build implicit multiply
1750  const LinearOp implicitOp = Thyra::multiply(opl,opr);
1751 
1752  // build a scaling transformer
1753 
1754  RCP<Thyra::LinearOpTransformerBase<double> > prodTrans
1755  = Thyra::epetraExtDiagScalingTransformer();
1756 
1757  // check to see if a scaling transformer works: if not use the
1758  // DiagScaledMatrixProduct transformer
1759  if(not prodTrans->isCompatible(*implicitOp))
1760  prodTrans = Thyra::epetraExtDiagScaledMatProdTransformer();
1761 
1762  // build operator destination operator
1763  ModifiableLinearOp explicitOp;
1764 
1765  // if neccessary build a operator to put the explicit multiply into
1766  if(destOp==Teuchos::null)
1767  explicitOp = prodTrans->createOutputOp();
1768  else
1769  explicitOp = destOp;
1770 
1771  // perform multiplication
1772  prodTrans->transform(*implicitOp,explicitOp.ptr());
1773 
1774  // label it
1775  explicitOp->setObjectLabel("explicit( " + opl->getObjectLabel() +
1776  " * " + opr->getObjectLabel() + " )");
1777 
1778  return explicitOp;
1779  }
1780 }
1781 
1792 const LinearOp explicitAdd(const LinearOp & opl_in,const LinearOp & opr_in)
1793 {
1794  // if both blocked, add block by block
1795  if(isPhysicallyBlockedLinearOp(opl_in) && isPhysicallyBlockedLinearOp(opr_in)){
1796  double scalarl = 0.0;
1797  bool transpl = false;
1798  RCP<const Thyra::PhysicallyBlockedLinearOpBase<double> > blocked_opl = getPhysicallyBlockedLinearOp(opl_in, &scalarl, &transpl);
1799 
1800  double scalarr = 0.0;
1801  bool transpr = false;
1802  RCP<const Thyra::PhysicallyBlockedLinearOpBase<double> > blocked_opr = getPhysicallyBlockedLinearOp(opr_in, &scalarr, &transpr);
1803 
1804  int numRows = blocked_opl->productRange()->numBlocks();
1805  int numCols = blocked_opl->productDomain()->numBlocks();
1806  TEUCHOS_ASSERT(blocked_opr->productRange()->numBlocks() == numRows);
1807  TEUCHOS_ASSERT(blocked_opr->productDomain()->numBlocks() == numCols);
1808 
1809  RCP<Thyra::PhysicallyBlockedLinearOpBase<double> > blocked_sum = Thyra::defaultBlockedLinearOp<double>();
1810  blocked_sum->beginBlockFill(numRows,numCols);
1811  for(int r = 0; r < numRows; ++r)
1812  for(int c = 0; c < numCols; ++c)
1813  blocked_sum->setBlock(r,c,explicitAdd(Thyra::scale(scalarl,blocked_opl->getBlock(r,c)),Thyra::scale(scalarr,blocked_opr->getBlock(r,c))));
1814  blocked_sum->endBlockFill();
1815  return blocked_sum;
1816  }
1817 
1818  // if only one is blocked, it must be 1x1
1819  LinearOp opl = opl_in;
1820  LinearOp opr = opr_in;
1821  if(isPhysicallyBlockedLinearOp(opl_in)){
1822  double scalarl = 0.0;
1823  bool transpl = false;
1824  RCP<const Thyra::PhysicallyBlockedLinearOpBase<double> > blocked_opl = getPhysicallyBlockedLinearOp(opl_in, &scalarl, &transpl);
1825  TEUCHOS_ASSERT(blocked_opl->productRange()->numBlocks() == 1);
1826  TEUCHOS_ASSERT(blocked_opl->productDomain()->numBlocks() == 1);
1827  opl = Thyra::scale(scalarl,blocked_opl->getBlock(0,0));
1828  }
1829  if(isPhysicallyBlockedLinearOp(opr_in)){
1830  double scalarr = 0.0;
1831  bool transpr = false;
1832  RCP<const Thyra::PhysicallyBlockedLinearOpBase<double> > blocked_opr = getPhysicallyBlockedLinearOp(opr_in, &scalarr, &transpr);
1833  TEUCHOS_ASSERT(blocked_opr->productRange()->numBlocks() == 1);
1834  TEUCHOS_ASSERT(blocked_opr->productDomain()->numBlocks() == 1);
1835  opr = Thyra::scale(scalarr,blocked_opr->getBlock(0,0));
1836  }
1837 
1838  bool isTpetral = Teko::TpetraHelpers::isTpetraLinearOp(opl);
1839  bool isTpetrar = Teko::TpetraHelpers::isTpetraLinearOp(opr);
1840 
1841  // if one of the operators in the sum is a thyra zero op
1842  if(isZeroOp(opl)){
1843  if(isZeroOp(opr))
1844  return opr; // return a zero op if both are zero
1845  if(isTpetrar){ // if other op is tpetra, replace this with a zero crs matrix
1846  ST scalar = 0.0;
1847  bool transp = false;
1848  auto crs_op = Teko::TpetraHelpers::getTpetraCrsMatrix(opr, &scalar, &transp);
1849  auto zero_crs = Tpetra::createCrsMatrix<ST,LO,GO,NT>(crs_op->getRowMap());
1850  zero_crs->fillComplete();
1851  opl = Thyra::constTpetraLinearOp<ST,LO,GO,NT>(Thyra::tpetraVectorSpace<ST,LO,GO,NT>(crs_op->getRangeMap()),Thyra::tpetraVectorSpace<ST,LO,GO,NT>(crs_op->getDomainMap()),zero_crs);
1852  isTpetral = true;
1853  } else
1854  return opr->clone();
1855  }
1856  if(isZeroOp(opr)){
1857  if(isTpetral){ // if other op is tpetra, replace this with a zero crs matrix
1858  ST scalar = 0.0;
1859  bool transp = false;
1860  auto crs_op = Teko::TpetraHelpers::getTpetraCrsMatrix(opr, &scalar, &transp);
1861  auto zero_crs = Tpetra::createCrsMatrix<ST,LO,GO,NT>(crs_op->getRowMap());
1862  zero_crs->fillComplete();
1863  opr = Thyra::constTpetraLinearOp<ST,LO,GO,NT>(Thyra::tpetraVectorSpace<ST,LO,GO,NT>(crs_op->getRangeMap()),Thyra::tpetraVectorSpace<ST,LO,GO,NT>(crs_op->getDomainMap()),zero_crs);
1864  isTpetrar = true;
1865  } else
1866  return opl->clone();
1867  }
1868 
1869  if(isTpetral && isTpetrar){ // Both operators are Tpetra matrices so use the explicit Tpetra matrix-matrix add
1870 
1871  // Get left and right Tpetra crs operators
1872  ST scalarl = 0.0;
1873  bool transpl = false;
1874  RCP<const Tpetra::CrsMatrix<ST,LO,GO,NT> > tCrsOpl = Teko::TpetraHelpers::getTpetraCrsMatrix(opl, &scalarl, &transpl);
1875  ST scalarr = 0.0;
1876  bool transpr = false;
1877  RCP<const Tpetra::CrsMatrix<ST,LO,GO,NT> > tCrsOpr = Teko::TpetraHelpers::getTpetraCrsMatrix(opr, &scalarr, &transpr);
1878 
1879  // Build output operator
1880  RCP<Thyra::LinearOpBase<ST> > explicitOp = rcp(new Thyra::TpetraLinearOp<ST,LO,GO,NT>());
1881  RCP<Thyra::TpetraLinearOp<ST,LO,GO,NT> > tExplicitOp = rcp_dynamic_cast<Thyra::TpetraLinearOp<ST,LO,GO,NT> >(explicitOp);
1882 
1883  // Do explicit matrix-matrix add
1884  RCP<Tpetra::CrsMatrix<ST,LO,GO,NT> > explicitCrsOp = Tpetra::MatrixMatrix::add<ST,LO,GO,NT>(scalarl,transpl,*tCrsOpl,scalarr,transpr,*tCrsOpr);
1885  tExplicitOp->initialize(Thyra::tpetraVectorSpace<ST,LO,GO,NT>(explicitCrsOp->getRangeMap()),Thyra::tpetraVectorSpace<ST,LO,GO,NT>(explicitCrsOp->getDomainMap()),explicitCrsOp);
1886  return tExplicitOp;
1887 
1888  }else{//Assume Epetra
1889  // build implicit add
1890  const LinearOp implicitOp = Thyra::add(opl,opr);
1891 
1892  // build transformer
1893  const RCP<Thyra::LinearOpTransformerBase<double> > prodTrans =
1894  Thyra::epetraExtAddTransformer();
1895 
1896  // build operator and add
1897  const RCP<Thyra::LinearOpBase<double> > explicitOp = prodTrans->createOutputOp();
1898  prodTrans->transform(*implicitOp,explicitOp.ptr());
1899  explicitOp->setObjectLabel("explicit( " + opl->getObjectLabel() +
1900  " + " + opr->getObjectLabel() + " )");
1901 
1902  return explicitOp;
1903  }
1904 }
1905 
1918 const ModifiableLinearOp explicitAdd(const LinearOp & opl,const LinearOp & opr,
1919  const ModifiableLinearOp & destOp)
1920 {
1921  // if blocked, add block by block
1922  if(isPhysicallyBlockedLinearOp(opl)){
1923  TEUCHOS_ASSERT(isPhysicallyBlockedLinearOp(opr));
1924 
1925  double scalarl = 0.0;
1926  bool transpl = false;
1927  RCP<const Thyra::PhysicallyBlockedLinearOpBase<double> > blocked_opl = getPhysicallyBlockedLinearOp(opl, &scalarl, &transpl);
1928 
1929  double scalarr = 0.0;
1930  bool transpr = false;
1931  RCP<const Thyra::PhysicallyBlockedLinearOpBase<double> > blocked_opr = getPhysicallyBlockedLinearOp(opr, &scalarr, &transpr);
1932 
1933  int numRows = blocked_opl->productRange()->numBlocks();
1934  int numCols = blocked_opl->productDomain()->numBlocks();
1935  TEUCHOS_ASSERT(blocked_opr->productRange()->numBlocks() == numRows);
1936  TEUCHOS_ASSERT(blocked_opr->productDomain()->numBlocks() == numCols);
1937 
1938  RCP<Thyra::PhysicallyBlockedLinearOpBase<double> > blocked_sum = Teuchos::rcp_dynamic_cast<Thyra::DefaultBlockedLinearOp<double>>(destOp);
1939  if(blocked_sum.is_null()) {
1940  // take care of the null case, this means we must alllocate memory
1941  blocked_sum = Thyra::defaultBlockedLinearOp<double>();
1942 
1943  blocked_sum->beginBlockFill(numRows,numCols);
1944  for(int r = 0; r < numRows; ++r) {
1945  for(int c = 0; c < numCols; ++c) {
1946  auto block = explicitAdd(Thyra::scale(scalarl,blocked_opl->getBlock(r,c)),Thyra::scale(scalarr,blocked_opr->getBlock(r,c)),Teuchos::null);
1947  blocked_sum->setNonconstBlock(r,c,block);
1948  }
1949  }
1950  blocked_sum->endBlockFill();
1951 
1952  }
1953  else {
1954  // in this case memory can be reused
1955  for(int r = 0; r < numRows; ++r)
1956  for(int c = 0; c < numCols; ++c)
1957  explicitAdd(Thyra::scale(scalarl,blocked_opl->getBlock(r,c)),Thyra::scale(scalarr,blocked_opr->getBlock(r,c)),blocked_sum->getNonconstBlock(r,c));
1958  }
1959 
1960  return blocked_sum;
1961  }
1962 
1963  bool isTpetral = Teko::TpetraHelpers::isTpetraLinearOp(opl);
1964  bool isTpetrar = Teko::TpetraHelpers::isTpetraLinearOp(opr);
1965 
1966  if(isTpetral && isTpetrar){ // Both operators are Tpetra matrices so use the explicit Tpetra matrix-matrix add
1967 
1968  // Get left and right Tpetra crs operators
1969  ST scalarl = 0.0;
1970  bool transpl = false;
1971  RCP<const Tpetra::CrsMatrix<ST,LO,GO,NT> > tCrsOpl = Teko::TpetraHelpers::getTpetraCrsMatrix(opl, &scalarl, &transpl);
1972  ST scalarr = 0.0;
1973  bool transpr = false;
1974  RCP<const Tpetra::CrsMatrix<ST,LO,GO,NT> > tCrsOpr = Teko::TpetraHelpers::getTpetraCrsMatrix(opr, &scalarr, &transpr);
1975 
1976  // Build output operator
1977  RCP<Thyra::LinearOpBase<ST> > explicitOp;
1978  if(destOp!=Teuchos::null)
1979  explicitOp = destOp;
1980  else
1981  explicitOp = rcp(new Thyra::TpetraLinearOp<ST,LO,GO,NT>());
1982  RCP<Thyra::TpetraLinearOp<ST,LO,GO,NT> > tExplicitOp = rcp_dynamic_cast<Thyra::TpetraLinearOp<ST,LO,GO,NT> >(explicitOp);
1983 
1984  // Do explicit matrix-matrix add
1985  RCP<Tpetra::CrsMatrix<ST,LO,GO,NT> > explicitCrsOp = Tpetra::MatrixMatrix::add<ST,LO,GO,NT>(scalarl,transpl,*tCrsOpl,scalarr,transpr,*tCrsOpr);
1986  tExplicitOp->initialize(Thyra::tpetraVectorSpace<ST,LO,GO,NT>(explicitCrsOp->getRangeMap()),Thyra::tpetraVectorSpace<ST,LO,GO,NT>(explicitCrsOp->getDomainMap()),explicitCrsOp);
1987  return tExplicitOp;
1988 
1989  }else{ // Assume Epetra
1990 
1991  // build implicit add
1992  const LinearOp implicitOp = Thyra::add(opl,opr);
1993 
1994  // build transformer
1995  const RCP<Thyra::LinearOpTransformerBase<double> > prodTrans =
1996  Thyra::epetraExtAddTransformer();
1997 
1998  // build or reuse destination operator
1999  RCP<Thyra::LinearOpBase<double> > explicitOp;
2000  if(destOp!=Teuchos::null)
2001  explicitOp = destOp;
2002  else
2003  explicitOp = prodTrans->createOutputOp();
2004 
2005  // perform add
2006  prodTrans->transform(*implicitOp,explicitOp.ptr());
2007  explicitOp->setObjectLabel("explicit( " + opl->getObjectLabel() +
2008  " + " + opr->getObjectLabel() + " )");
2009 
2010  return explicitOp;
2011  }
2012 }
2013 
2018 const ModifiableLinearOp explicitSum(const LinearOp & op,
2019  const ModifiableLinearOp & destOp)
2020 {
2021  // convert operators to Epetra_CrsMatrix
2022  const RCP<const Epetra_CrsMatrix> epetraOp =
2023  rcp_dynamic_cast<const Epetra_CrsMatrix>(get_Epetra_Operator(*op), true);
2024 
2025  if(destOp==Teuchos::null) {
2026  Teuchos::RCP<Epetra_Operator> epetraDest = Teuchos::rcp(new Epetra_CrsMatrix(*epetraOp));
2027 
2028  return Thyra::nonconstEpetraLinearOp(epetraDest);
2029  }
2030 
2031  const RCP<Epetra_CrsMatrix> epetraDest =
2032  rcp_dynamic_cast<Epetra_CrsMatrix>(get_Epetra_Operator(*destOp), true);
2033 
2034  EpetraExt::MatrixMatrix::Add(*epetraOp,false,1.0,*epetraDest,1.0);
2035 
2036  return destOp;
2037 }
2038 
2039 const LinearOp explicitTranspose(const LinearOp & op)
2040 {
2041  if(Teko::TpetraHelpers::isTpetraLinearOp(op)){
2042 
2043  RCP<const Thyra::TpetraLinearOp<ST,LO,GO,NT> > tOp = rcp_dynamic_cast<const Thyra::TpetraLinearOp<ST,LO,GO,NT> >(op,true);
2044  RCP<const Tpetra::CrsMatrix<ST,LO,GO,NT> > tCrsOp = rcp_dynamic_cast<const Tpetra::CrsMatrix<ST,LO,GO,NT> >(tOp->getConstTpetraOperator(),true);
2045 
2046  Tpetra::RowMatrixTransposer<ST,LO,GO,NT> transposer(tCrsOp);
2047  RCP<const Tpetra::CrsMatrix<ST,LO,GO,NT> > transOp = transposer.createTranspose();
2048 
2049  return Thyra::constTpetraLinearOp<ST,LO,GO,NT>(Thyra::tpetraVectorSpace<ST,LO,GO,NT>(transOp->getRangeMap()),Thyra::tpetraVectorSpace<ST,LO,GO,NT>(transOp->getDomainMap()),transOp);
2050 
2051  } else {
2052 
2053  RCP<const Epetra_Operator> eOp = Thyra::get_Epetra_Operator(*op);
2054  TEUCHOS_TEST_FOR_EXCEPTION(eOp==Teuchos::null,std::logic_error,
2055  "Teko::explicitTranspose Not an Epetra_Operator");
2056  RCP<const Epetra_RowMatrix> eRowMatrixOp
2057  = Teuchos::rcp_dynamic_cast<const Epetra_RowMatrix>(eOp);
2058  TEUCHOS_TEST_FOR_EXCEPTION(eRowMatrixOp==Teuchos::null,std::logic_error,
2059  "Teko::explicitTranspose Not an Epetra_RowMatrix");
2060 
2061  // we now have a delete transpose operator
2062  EpetraExt::RowMatrix_Transpose tranposeOp;
2063  Epetra_RowMatrix & eMat = tranposeOp(const_cast<Epetra_RowMatrix &>(*eRowMatrixOp));
2064 
2065  // this copy is because of a poor implementation of the EpetraExt::Transform
2066  // implementation
2067  Teuchos::RCP<Epetra_CrsMatrix> crsMat
2068  = Teuchos::rcp(new Epetra_CrsMatrix(dynamic_cast<Epetra_CrsMatrix &>(eMat)));
2069 
2070  return Thyra::epetraLinearOp(crsMat);
2071  }
2072 }
2073 
2074 double frobeniusNorm(const LinearOp & op_in)
2075 {
2076  LinearOp op;
2077  double scalar = 1.0;
2078 
2079  // if blocked, must be 1x1
2080  if(isPhysicallyBlockedLinearOp(op_in)){
2081  bool transp = false;
2082  RCP<const Thyra::PhysicallyBlockedLinearOpBase<double> > blocked_op = getPhysicallyBlockedLinearOp(op_in,&scalar,&transp);
2083  TEUCHOS_ASSERT(blocked_op->productRange()->numBlocks() == 1);
2084  TEUCHOS_ASSERT(blocked_op->productDomain()->numBlocks() == 1);
2085  op = blocked_op->getBlock(0,0);
2086  } else
2087  op = op_in;
2088 
2089  if(Teko::TpetraHelpers::isTpetraLinearOp(op)){
2090  const RCP<const Thyra::TpetraLinearOp<ST,LO,GO,NT> > tOp = rcp_dynamic_cast<const Thyra::TpetraLinearOp<ST,LO,GO,NT> >(op);
2091  const RCP<const Tpetra::CrsMatrix<ST,LO,GO,NT> > crsOp = rcp_dynamic_cast<const Tpetra::CrsMatrix<ST,LO,GO,NT> >(tOp->getConstTpetraOperator(),true);
2092  return crsOp->getFrobeniusNorm();
2093  } else {
2094  const RCP<const Epetra_Operator> epOp = Thyra::get_Epetra_Operator(*op);
2095  const RCP<const Epetra_CrsMatrix> crsOp = rcp_dynamic_cast<const Epetra_CrsMatrix>(epOp,true);
2096  return crsOp->NormFrobenius();
2097  }
2098 }
2099 
2100 double oneNorm(const LinearOp & op)
2101 {
2102  if(Teko::TpetraHelpers::isTpetraLinearOp(op)){
2103  TEUCHOS_TEST_FOR_EXCEPTION(true,std::logic_error,"One norm not currently implemented for Tpetra matrices");
2104 
2105  } else {
2106  const RCP<const Epetra_Operator> epOp = Thyra::get_Epetra_Operator(*op);
2107  const RCP<const Epetra_CrsMatrix> crsOp = rcp_dynamic_cast<const Epetra_CrsMatrix>(epOp,true);
2108  return crsOp->NormOne();
2109  }
2110 }
2111 
2112 double infNorm(const LinearOp & op)
2113 {
2114  if(Teko::TpetraHelpers::isTpetraLinearOp(op)){
2115  ST scalar = 0.0;
2116  bool transp = false;
2117  RCP<const Tpetra::CrsMatrix<ST,LO,GO,NT> > tCrsOp = Teko::TpetraHelpers::getTpetraCrsMatrix(op, &scalar, &transp);
2118 
2119  // extract diagonal
2120  const RCP<Tpetra::Vector<ST,LO,GO,NT> > ptrDiag = Tpetra::createVector<ST,LO,GO,NT>(tCrsOp->getRowMap());
2121  Tpetra::Vector<ST,LO,GO,NT> & diag = *ptrDiag;
2122 
2123  // compute absolute value row sum
2124  diag.putScalar(0.0);
2125  for(LO i=0;i<(LO) tCrsOp->getNodeNumRows();i++) {
2126  LO numEntries = tCrsOp->getNumEntriesInLocalRow (i);
2127  typename Tpetra::CrsMatrix<ST,LO,GO,NT>::local_inds_host_view_type indices;
2128  typename Tpetra::CrsMatrix<ST,LO,GO,NT>::values_host_view_type values;
2129  tCrsOp->getLocalRowView(i,indices,values);
2130 
2131  // build abs value row sum
2132  for(LO j=0;j<numEntries;j++)
2133  diag.sumIntoLocalValue(i,std::abs(values(j)));
2134  }
2135  return diag.normInf()*scalar;
2136 
2137  } else {
2138  const RCP<const Epetra_Operator> epOp = Thyra::get_Epetra_Operator(*op);
2139  const RCP<const Epetra_CrsMatrix> crsOp = rcp_dynamic_cast<const Epetra_CrsMatrix>(epOp,true);
2140  return crsOp->NormInf();
2141  }
2142 }
2143 
2144 const LinearOp buildDiagonal(const MultiVector & src,const std::string & lbl)
2145 {
2146  RCP<Thyra::VectorBase<double> > dst = Thyra::createMember(src->range());
2147  Thyra::copy(*src->col(0),dst.ptr());
2148 
2149  return Thyra::diagonal<double>(dst,lbl);
2150 }
2151 
2152 const LinearOp buildInvDiagonal(const MultiVector & src,const std::string & lbl)
2153 {
2154  const RCP<const Thyra::VectorBase<double> > srcV = src->col(0);
2155  RCP<Thyra::VectorBase<double> > dst = Thyra::createMember(srcV->range());
2156  Thyra::reciprocal<double>(*srcV,dst.ptr());
2157 
2158  return Thyra::diagonal<double>(dst,lbl);
2159 }
2160 
2162 BlockedMultiVector buildBlockedMultiVector(const std::vector<MultiVector> & mvv)
2163 {
2164  Teuchos::Array<MultiVector> mvA;
2165  Teuchos::Array<VectorSpace> vsA;
2166 
2167  // build arrays of multi vectors and vector spaces
2168  std::vector<MultiVector>::const_iterator itr;
2169  for(itr=mvv.begin();itr!=mvv.end();++itr) {
2170  mvA.push_back(*itr);
2171  vsA.push_back((*itr)->range());
2172  }
2173 
2174  // construct the product vector space
2175  const RCP<const Thyra::DefaultProductVectorSpace<double> > vs
2176  = Thyra::productVectorSpace<double>(vsA);
2177 
2178  return Thyra::defaultProductMultiVector<double>(vs,mvA);
2179 }
2180 
2191 Teuchos::RCP<Thyra::VectorBase<double> > indicatorVector(
2192  const std::vector<int> & indices,
2193  const VectorSpace & vs,
2194  double onValue, double offValue)
2195 
2196 {
2197  using Teuchos::RCP;
2198 
2199  // create a new vector
2200  RCP<Thyra::VectorBase<double> > v = Thyra::createMember<double>(vs);
2201  Thyra::put_scalar<double>(offValue,v.ptr()); // fill it with "off" values
2202 
2203  // set on values
2204  for(std::size_t i=0;i<indices.size();i++)
2205  Thyra::set_ele<double>(indices[i],onValue,v.ptr());
2206 
2207  return v;
2208 }
2209 
2234 double computeSpectralRad(const RCP<const Thyra::LinearOpBase<double> > & A, double tol,
2235  bool isHermitian,int numBlocks,int restart,int verbosity)
2236 {
2237  typedef Thyra::LinearOpBase<double> OP;
2238  typedef Thyra::MultiVectorBase<double> MV;
2239 
2240  int startVectors = 1;
2241 
2242  // construct an initial guess
2243  const RCP<MV> ivec = Thyra::createMember(A->domain());
2244  Thyra::randomize(-1.0,1.0,ivec.ptr());
2245 
2246  RCP<Anasazi::BasicEigenproblem<double,MV,OP> > eigProb
2247  = rcp(new Anasazi::BasicEigenproblem<double,MV,OP>(A,ivec));
2248  eigProb->setNEV(1);
2249  eigProb->setHermitian(isHermitian);
2250 
2251  // set the problem up
2252  if(not eigProb->setProblem()) {
2253  // big time failure!
2254  return Teuchos::ScalarTraits<double>::nan();
2255  }
2256 
2257  // we want largert magnitude eigenvalue
2258  std::string which("LM"); // largest magnitude
2259 
2260  // Create the parameter list for the eigensolver
2261  // verbosity+=Anasazi::TimingDetails;
2262  Teuchos::ParameterList MyPL;
2263  MyPL.set( "Verbosity", verbosity );
2264  MyPL.set( "Which", which );
2265  MyPL.set( "Block Size", startVectors );
2266  MyPL.set( "Num Blocks", numBlocks );
2267  MyPL.set( "Maximum Restarts", restart );
2268  MyPL.set( "Convergence Tolerance", tol );
2269 
2270  // build status test manager
2271  // RCP<Anasazi::StatusTestMaxIters<double,MV,OP> > statTest
2272  // = rcp(new Anasazi::StatusTestMaxIters<double,MV,OP>(numBlocks*(restart+1)));
2273 
2274  // Create the Block Krylov Schur solver
2275  // This takes as inputs the eigenvalue problem and the solver parameters
2276  Anasazi::BlockKrylovSchurSolMgr<double,MV,OP> MyBlockKrylovSchur(eigProb, MyPL );
2277 
2278  // Solve the eigenvalue problem, and save the return code
2279  Anasazi::ReturnType solverreturn = MyBlockKrylovSchur.solve();
2280 
2281  if(solverreturn==Anasazi::Unconverged) {
2282  double real = MyBlockKrylovSchur.getRitzValues().begin()->realpart;
2283  double comp = MyBlockKrylovSchur.getRitzValues().begin()->imagpart;
2284 
2285  return -std::abs(std::sqrt(real*real+comp*comp));
2286 
2287  // cout << "Anasazi::BlockKrylovSchur::solve() did not converge!" << std::endl;
2288  // return -std::abs(MyBlockKrylovSchur.getRitzValues().begin()->realpart);
2289  }
2290  else { // solverreturn==Anasazi::Converged
2291  double real = eigProb->getSolution().Evals.begin()->realpart;
2292  double comp = eigProb->getSolution().Evals.begin()->imagpart;
2293 
2294  return std::abs(std::sqrt(real*real+comp*comp));
2295 
2296  // cout << "Anasazi::BlockKrylovSchur::solve() converged!" << endl;
2297  // return std::abs(eigProb->getSolution().Evals.begin()->realpart);
2298  }
2299 }
2300 
2324 double computeSmallestMagEig(const RCP<const Thyra::LinearOpBase<double> > & A, double tol,
2325  bool isHermitian,int numBlocks,int restart,int verbosity)
2326 {
2327  typedef Thyra::LinearOpBase<double> OP;
2328  typedef Thyra::MultiVectorBase<double> MV;
2329 
2330  int startVectors = 1;
2331 
2332  // construct an initial guess
2333  const RCP<MV> ivec = Thyra::createMember(A->domain());
2334  Thyra::randomize(-1.0,1.0,ivec.ptr());
2335 
2336  RCP<Anasazi::BasicEigenproblem<double,MV,OP> > eigProb
2337  = rcp(new Anasazi::BasicEigenproblem<double,MV,OP>(A,ivec));
2338  eigProb->setNEV(1);
2339  eigProb->setHermitian(isHermitian);
2340 
2341  // set the problem up
2342  if(not eigProb->setProblem()) {
2343  // big time failure!
2344  return Teuchos::ScalarTraits<double>::nan();
2345  }
2346 
2347  // we want largert magnitude eigenvalue
2348  std::string which("SM"); // smallest magnitude
2349 
2350  // Create the parameter list for the eigensolver
2351  Teuchos::ParameterList MyPL;
2352  MyPL.set( "Verbosity", verbosity );
2353  MyPL.set( "Which", which );
2354  MyPL.set( "Block Size", startVectors );
2355  MyPL.set( "Num Blocks", numBlocks );
2356  MyPL.set( "Maximum Restarts", restart );
2357  MyPL.set( "Convergence Tolerance", tol );
2358 
2359  // build status test manager
2360  // RCP<Anasazi::StatusTestMaxIters<double,MV,OP> > statTest
2361  // = rcp(new Anasazi::StatusTestMaxIters<double,MV,OP>(10));
2362 
2363  // Create the Block Krylov Schur solver
2364  // This takes as inputs the eigenvalue problem and the solver parameters
2365  Anasazi::BlockKrylovSchurSolMgr<double,MV,OP> MyBlockKrylovSchur(eigProb, MyPL );
2366 
2367  // Solve the eigenvalue problem, and save the return code
2368  Anasazi::ReturnType solverreturn = MyBlockKrylovSchur.solve();
2369 
2370  if(solverreturn==Anasazi::Unconverged) {
2371  // cout << "Anasazi::BlockKrylovSchur::solve() did not converge! " << std::endl;
2372  return -std::abs(MyBlockKrylovSchur.getRitzValues().begin()->realpart);
2373  }
2374  else { // solverreturn==Anasazi::Converged
2375  // cout << "Anasazi::BlockKrylovSchur::solve() converged!" << endl;
2376  return std::abs(eigProb->getSolution().Evals.begin()->realpart);
2377  }
2378 }
2379 
2388 ModifiableLinearOp getDiagonalOp(const Teko::LinearOp & A,const DiagonalType & dt)
2389 {
2390  switch(dt) {
2391  case Diagonal:
2392  return getDiagonalOp(A);
2393  case Lumped:
2394  return getLumpedMatrix(A);
2395  case AbsRowSum:
2396  return getAbsRowSumMatrix(A);
2397  case NotDiag:
2398  default:
2399  TEUCHOS_TEST_FOR_EXCEPT(true);
2400  };
2401 
2402  return Teuchos::null;
2403 }
2404 
2413 ModifiableLinearOp getInvDiagonalOp(const Teko::LinearOp & A,const Teko::DiagonalType & dt)
2414 {
2415  switch(dt) {
2416  case Diagonal:
2417  return getInvDiagonalOp(A);
2418  case Lumped:
2419  return getInvLumpedMatrix(A);
2420  case AbsRowSum:
2421  return getAbsRowSumInvMatrix(A);
2422  case NotDiag:
2423  default:
2424  TEUCHOS_TEST_FOR_EXCEPT(true);
2425  };
2426 
2427  return Teuchos::null;
2428 }
2429 
2436 std::string getDiagonalName(const DiagonalType & dt)
2437 {
2438  switch(dt) {
2439  case Diagonal:
2440  return "Diagonal";
2441  case Lumped:
2442  return "Lumped";
2443  case AbsRowSum:
2444  return "AbsRowSum";
2445  case NotDiag:
2446  return "NotDiag";
2447  case BlkDiag:
2448  return "BlkDiag";
2449  };
2450 
2451  return "<error>";
2452 }
2453 
2462 DiagonalType getDiagonalType(std::string name)
2463 {
2464  if(name=="Diagonal")
2465  return Diagonal;
2466  if(name=="Lumped")
2467  return Lumped;
2468  if(name=="AbsRowSum")
2469  return AbsRowSum;
2470  if(name=="BlkDiag")
2471  return BlkDiag;
2472 
2473  return NotDiag;
2474 }
2475 
2476 LinearOp probe(Teuchos::RCP<const Epetra_CrsGraph> &G,const LinearOp & Op){
2477 #ifdef Teko_ENABLE_Isorropia
2478  Teuchos::ParameterList probeList;
2479  Prober prober(G,probeList,true);
2480  Teuchos::RCP<Epetra_CrsMatrix> Mat=rcp(new Epetra_CrsMatrix(Copy,*G));
2482  prober.probe(Mwrap,*Mat);
2483  return Thyra::epetraLinearOp(Mat);
2484 #else
2485  (void)G;
2486  (void)Op;
2487  TEUCHOS_TEST_FOR_EXCEPTION(true,std::runtime_error,"Probe requires Isorropia");
2488 #endif
2489 }
2490 
2491 double norm_1(const MultiVector & v,std::size_t col)
2492 {
2493  Teuchos::Array<double> n(v->domain()->dim());
2494  Thyra::norms_1<double>(*v,n);
2495 
2496  return n[col];
2497 }
2498 
2499 double norm_2(const MultiVector & v,std::size_t col)
2500 {
2501  Teuchos::Array<double> n(v->domain()->dim());
2502  Thyra::norms_2<double>(*v,n);
2503 
2504  return n[col];
2505 }
2506 
2507 void putScalar(const ModifiableLinearOp & op,double scalar)
2508 {
2509  try {
2510  // get Epetra_Operator
2511  RCP<Epetra_Operator> eOp = Thyra::get_Epetra_Operator(*op);
2512 
2513  // cast it to a CrsMatrix
2514  RCP<Epetra_CrsMatrix> eCrsOp = rcp_dynamic_cast<Epetra_CrsMatrix>(eOp,true);
2515 
2516  eCrsOp->PutScalar(scalar);
2517  }
2518  catch (std::exception & e) {
2519  RCP<Teuchos::FancyOStream> out = Teuchos::VerboseObjectBase::getDefaultOStream();
2520 
2521  *out << "Teko: putScalar requires an Epetra_CrsMatrix\n";
2522  *out << " Could not extract an Epetra_Operator from a \"" << op->description() << std::endl;
2523  *out << " OR\n";
2524  *out << " Could not cast an Epetra_Operator to a Epetra_CrsMatrix\n";
2525  *out << std::endl;
2526  *out << "*** THROWN EXCEPTION ***\n";
2527  *out << e.what() << std::endl;
2528  *out << "************************\n";
2529 
2530  throw e;
2531  }
2532 }
2533 
2534 void clipLower(MultiVector & v,double lowerBound)
2535 {
2536  using Teuchos::RCP;
2537  using Teuchos::rcp_dynamic_cast;
2538 
2539  // cast so entries are accessible
2540  // RCP<Thyra::SpmdMultiVectorBase<double> > spmdMVec
2541  // = rcp_dynamic_cast<Thyra::DefaultSpmdMultiVector<double> >(v);
2542 
2543  for(Thyra::Ordinal i=0;i<v->domain()->dim();i++) {
2544  RCP<Thyra::SpmdVectorBase<double> > spmdVec
2545  = rcp_dynamic_cast<Thyra::SpmdVectorBase<double> >(v->col(i),true);
2546 
2547  Teuchos::ArrayRCP<double> values;
2548  // spmdMVec->getNonconstLocalData(Teuchos::ptrFromRef(values),Teuchos::ptrFromRef(i));
2549  spmdVec->getNonconstLocalData(Teuchos::ptrFromRef(values));
2550  for(Teuchos::ArrayRCP<double>::size_type j=0;j<values.size();j++) {
2551  if(values[j]<lowerBound)
2552  values[j] = lowerBound;
2553  }
2554  }
2555 }
2556 
2557 void clipUpper(MultiVector & v,double upperBound)
2558 {
2559  using Teuchos::RCP;
2560  using Teuchos::rcp_dynamic_cast;
2561 
2562  // cast so entries are accessible
2563  // RCP<Thyra::SpmdMultiVectorBase<double> > spmdMVec
2564  // = rcp_dynamic_cast<Thyra::DefaultSpmdMultiVector<double> >(v);
2565  for(Thyra::Ordinal i=0;i<v->domain()->dim();i++) {
2566  RCP<Thyra::SpmdVectorBase<double> > spmdVec
2567  = rcp_dynamic_cast<Thyra::SpmdVectorBase<double> >(v->col(i),true);
2568 
2569  Teuchos::ArrayRCP<double> values;
2570  // spmdMVec->getNonconstLocalData(Teuchos::ptrFromRef(values),Teuchos::ptrFromRef(i));
2571  spmdVec->getNonconstLocalData(Teuchos::ptrFromRef(values));
2572  for(Teuchos::ArrayRCP<double>::size_type j=0;j<values.size();j++) {
2573  if(values[j]>upperBound)
2574  values[j] = upperBound;
2575  }
2576  }
2577 }
2578 
2579 void replaceValue(MultiVector & v,double currentValue,double newValue)
2580 {
2581  using Teuchos::RCP;
2582  using Teuchos::rcp_dynamic_cast;
2583 
2584  // cast so entries are accessible
2585  // RCP<Thyra::SpmdMultiVectorBase<double> > spmdMVec
2586  // = rcp_dynamic_cast<Thyra::SpmdMultiVectorBase<double> >(v,true);
2587  for(Thyra::Ordinal i=0;i<v->domain()->dim();i++) {
2588  RCP<Thyra::SpmdVectorBase<double> > spmdVec
2589  = rcp_dynamic_cast<Thyra::SpmdVectorBase<double> >(v->col(i),true);
2590 
2591  Teuchos::ArrayRCP<double> values;
2592  // spmdMVec->getNonconstLocalData(Teuchos::ptrFromRef(values),Teuchos::ptrFromRef(i));
2593  spmdVec->getNonconstLocalData(Teuchos::ptrFromRef(values));
2594  for(Teuchos::ArrayRCP<double>::size_type j=0;j<values.size();j++) {
2595  if(values[j]==currentValue)
2596  values[j] = newValue;
2597  }
2598  }
2599 }
2600 
2601 void columnAverages(const MultiVector & v,std::vector<double> & averages)
2602 {
2603  averages.resize(v->domain()->dim());
2604 
2605  // sum over each column
2606  Thyra::sums<double>(*v,averages);
2607 
2608  // build averages
2609  Thyra::Ordinal rows = v->range()->dim();
2610  for(std::size_t i=0;i<averages.size();i++)
2611  averages[i] = averages[i]/rows;
2612 }
2613 
2614 double average(const MultiVector & v)
2615 {
2616  Thyra::Ordinal rows = v->range()->dim();
2617  Thyra::Ordinal cols = v->domain()->dim();
2618 
2619  std::vector<double> averages;
2620  columnAverages(v,averages);
2621 
2622  double sum = 0.0;
2623  for(std::size_t i=0;i<averages.size();i++)
2624  sum += averages[i] * rows;
2625 
2626  return sum/(rows*cols);
2627 }
2628 
2629 bool isPhysicallyBlockedLinearOp(const LinearOp & op)
2630 {
2631  // See if the operator is a PBLO
2632  RCP<const Thyra::PhysicallyBlockedLinearOpBase<double> > pblo = rcp_dynamic_cast<const Thyra::PhysicallyBlockedLinearOpBase<double> >(op);
2633  if (!pblo.is_null())
2634  return true;
2635 
2636  // See if the operator is a wrapped PBLO
2637  ST scalar = 0.0;
2638  Thyra::EOpTransp transp = Thyra::NOTRANS;
2639  RCP<const Thyra::LinearOpBase<ST> > wrapped_op;
2640  Thyra::unwrap(op, &scalar, &transp, &wrapped_op);
2641  pblo = rcp_dynamic_cast<const Thyra::PhysicallyBlockedLinearOpBase<double> >(wrapped_op);
2642  if (!pblo.is_null())
2643  return true;
2644 
2645  return false;
2646 }
2647 
2648 RCP<const Thyra::PhysicallyBlockedLinearOpBase<double> > getPhysicallyBlockedLinearOp(const LinearOp & op, ST *scalar, bool *transp)
2649 {
2650  // If the operator is a TpetraLinearOp
2651  RCP<const Thyra::PhysicallyBlockedLinearOpBase<double> > pblo = rcp_dynamic_cast<const Thyra::PhysicallyBlockedLinearOpBase<double> >(op);
2652  if(!pblo.is_null()){
2653  *scalar = 1.0;
2654  *transp = false;
2655  return pblo;
2656  }
2657 
2658  // If the operator is a wrapped TpetraLinearOp
2659  RCP<const Thyra::LinearOpBase<ST> > wrapped_op;
2660  Thyra::EOpTransp eTransp = Thyra::NOTRANS;
2661  Thyra::unwrap(op, scalar, &eTransp, &wrapped_op);
2662  pblo = rcp_dynamic_cast<const Thyra::PhysicallyBlockedLinearOpBase<double> >(wrapped_op,true);
2663  if(!pblo.is_null()){
2664  *transp = true;
2665  if(eTransp == Thyra::NOTRANS)
2666  *transp = false;
2667  return pblo;
2668  }
2669 
2670  return Teuchos::null;
2671 }
2672 
2673 
2674 }
Specifies that a block diagonal approximation is to be used.
Specifies that just the diagonal is used.
int blockRowCount(const BlockedLinearOp &blo)
Get the row count in a block linear operator.
Specifies that row sum is used to form a diagonal.
void scale(const double alpha, MultiVector &x)
Scale a multivector by a constant.
Implements the Epetra_Operator interface with a Thyra LinearOperator. This enables the use of absrtac...
For user convenience, if Teko recieves this value, exceptions will be thrown.
DiagonalType
Type describing the type of diagonal to construct.
int blockColCount(const BlockedLinearOp &blo)
Get the column count in a block linear operator.
BlockedLinearOp createBlockedOp()
Build a new blocked linear operator.
Specifies that the diagonal entry is .