All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Xpetra_MatrixMatrix.hpp
Go to the documentation of this file.
1 // @HEADER
2 //
3 // ***********************************************************************
4 //
5 // Xpetra: A linear algebra interface package
6 // Copyright 2012 Sandia Corporation
7 //
8 // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
9 // the U.S. Government retains certain rights in this software.
10 //
11 // Redistribution and use in source and binary forms, with or without
12 // modification, are permitted provided that the following conditions are
13 // met:
14 //
15 // 1. Redistributions of source code must retain the above copyright
16 // notice, this list of conditions and the following disclaimer.
17 //
18 // 2. Redistributions in binary form must reproduce the above copyright
19 // notice, this list of conditions and the following disclaimer in the
20 // documentation and/or other materials provided with the distribution.
21 //
22 // 3. Neither the name of the Corporation nor the names of the
23 // contributors may be used to endorse or promote products derived from
24 // this software without specific prior written permission.
25 //
26 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
27 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
30 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
31 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
32 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
33 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
34 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
35 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
36 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 //
38 // Questions? Contact
39 // Jonathan Hu (jhu@sandia.gov)
40 // Andrey Prokopenko (aprokop@sandia.gov)
41 // Ray Tuminaro (rstumin@sandia.gov)
42 // Tobias Wiesner (tawiesn@sandia.gov)
43 //
44 // ***********************************************************************
45 //
46 // @HEADER
47 
48 #ifndef PACKAGES_XPETRA_SUP_UTILS_XPETRA_MATRIXMATRIX_HPP_
49 #define PACKAGES_XPETRA_SUP_UTILS_XPETRA_MATRIXMATRIX_HPP_
50 
51 #include "Xpetra_ConfigDefs.hpp"
52 
54 #include "Xpetra_CrsMatrixWrap.hpp"
55 #include "Xpetra_MapExtractor.hpp"
56 #include "Xpetra_Map.hpp"
57 #include "Xpetra_MatrixFactory.hpp"
58 #include "Xpetra_Matrix.hpp"
60 #include "Xpetra_StridedMap.hpp"
61 
62 #ifdef HAVE_XPETRA_EPETRA
64 #endif
65 
66 #ifdef HAVE_XPETRA_EPETRAEXT
67 #include <EpetraExt_MatrixMatrix.h>
68 #include <EpetraExt_RowMatrixOut.h>
69 #include <Epetra_RowMatrixTransposer.h>
70 #endif // HAVE_XPETRA_EPETRAEXT
71 
72 #ifdef HAVE_XPETRA_TPETRA
73 #include <TpetraExt_MatrixMatrix.hpp>
74 #include <MatrixMarket_Tpetra.hpp>
75 #include <Xpetra_TpetraCrsMatrix.hpp>
76 #include <Xpetra_TpetraMultiVector.hpp>
77 #include <Xpetra_TpetraVector.hpp>
78 #endif // HAVE_XPETRA_TPETRA
79 
80 namespace Xpetra {
81 
88  template <class Scalar,
89  class LocalOrdinal = int,
90  class GlobalOrdinal = LocalOrdinal,
92  class Helpers {
93 #include "Xpetra_UseShortNames.hpp"
94 
95  public:
96 
97 #ifdef HAVE_XPETRA_EPETRA
99  // Get the underlying Epetra Mtx
100  RCP<const CrsMatrixWrap> crsOp = Teuchos::rcp_dynamic_cast<const CrsMatrixWrap>(Op);
102  "Cast from Xpetra::Matrix to Xpetra::CrsMatrixWrap failed");
103 
104  RCP<const CrsMatrix> tmp_CrsMtx = crsOp->getCrsMatrix();
105  const RCP<const EpetraCrsMatrixT<GO,NO> > &tmp_ECrsMtx = Teuchos::rcp_dynamic_cast<const EpetraCrsMatrixT<GO,NO> >(tmp_CrsMtx);
106  TEUCHOS_TEST_FOR_EXCEPTION(tmp_ECrsMtx == Teuchos::null, Exceptions::BadCast,
107  "Cast from Xpetra::CrsMatrix to Xpetra::EpetraCrsMatrix failed");
108 
109  return tmp_ECrsMtx->getEpetra_CrsMatrix();
110  }
111 
114  // Get the underlying Epetra Mtx
115  RCP<const CrsMatrixWrap> crsOp = Teuchos::rcp_dynamic_cast<const CrsMatrixWrap>(Op);
116  TEUCHOS_TEST_FOR_EXCEPTION(crsOp == Teuchos::null, Exceptions::BadCast,
117  "Cast from Xpetra::Matrix to Xpetra::CrsMatrixWrap failed");
118 
119  RCP<const CrsMatrix> tmp_CrsMtx = crsOp->getCrsMatrix();
120  const RCP<const EpetraCrsMatrixT<GO,NO> > &tmp_ECrsMtx = Teuchos::rcp_dynamic_cast<const EpetraCrsMatrixT<GO,NO> >(tmp_CrsMtx);
121  TEUCHOS_TEST_FOR_EXCEPTION(tmp_ECrsMtx == Teuchos::null, Exceptions::BadCast, "Cast from Xpetra::CrsMatrix to Xpetra::EpetraCrsMatrix failed");
122 
123  return tmp_ECrsMtx->getEpetra_CrsMatrixNonConst();
124  }
125 
126  static const Epetra_CrsMatrix& Op2EpetraCrs(const Matrix& Op) {
127  // Get the underlying Epetra Mtx
128  try {
129  const CrsMatrixWrap& crsOp = dynamic_cast<const CrsMatrixWrap&>(Op);
130  RCP<const CrsMatrix> tmp_CrsMtx = crsOp.getCrsMatrix();
131  const RCP<const EpetraCrsMatrixT<GO,NO> > &tmp_ECrsMtx = Teuchos::rcp_dynamic_cast<const EpetraCrsMatrixT<GO,NO> >(tmp_CrsMtx);
132  TEUCHOS_TEST_FOR_EXCEPTION(tmp_ECrsMtx == Teuchos::null, Xpetra::Exceptions::BadCast,
133  "Cast from Xpetra::CrsMatrix to Xpetra::EpetraCrsMatrix failed");
134 
135  return *tmp_ECrsMtx->getEpetra_CrsMatrix();
136 
137  } catch(...) {
138  throw(Xpetra::Exceptions::BadCast("Cast from Xpetra::Matrix to Xpetra::CrsMatrixWrap failed"));
139  }
140  }
141 
144  // Get the underlying Epetra Mtx
145  try {
146  const CrsMatrixWrap& crsOp = dynamic_cast<const CrsMatrixWrap&>(Op);
147  RCP<const CrsMatrix> tmp_CrsMtx = crsOp.getCrsMatrix();
148  const RCP<const EpetraCrsMatrixT<GO,NO> > &tmp_ECrsMtx = Teuchos::rcp_dynamic_cast<const EpetraCrsMatrixT<GO,NO> >(tmp_CrsMtx);
149  TEUCHOS_TEST_FOR_EXCEPTION(tmp_ECrsMtx == Teuchos::null, Xpetra::Exceptions::BadCast, "Cast from Xpetra::CrsMatrix to Xpetra::EpetraCrsMatrix failed");
150 
151  return *Teuchos::rcp_const_cast<Epetra_CrsMatrix>(tmp_ECrsMtx->getEpetra_CrsMatrix());
152 
153  } catch(...) {
154  throw(Xpetra::Exceptions::BadCast("Cast from Xpetra::Matrix to Xpetra::CrsMatrixWrap failed"));
155  }
156  }
157 #endif // HAVE_XPETRA_EPETRA
158 
159 #ifdef HAVE_XPETRA_TPETRA
161  // Get the underlying Tpetra Mtx
162  RCP<const CrsMatrixWrap> crsOp = Teuchos::rcp_dynamic_cast<const CrsMatrixWrap>(Op);
163  TEUCHOS_TEST_FOR_EXCEPTION(crsOp == Teuchos::null, Xpetra::Exceptions::BadCast, "Cast from Xpetra::Matrix to Xpetra::CrsMatrixWrap failed");
164 
165  RCP<const CrsMatrix> tmp_CrsMtx = crsOp->getCrsMatrix();
166  const RCP<const Xpetra::TpetraCrsMatrix<SC,LO,GO,NO> > &tmp_ECrsMtx = Teuchos::rcp_dynamic_cast<const Xpetra::TpetraCrsMatrix<SC,LO,GO,NO> >(tmp_CrsMtx);
167  TEUCHOS_TEST_FOR_EXCEPTION(tmp_ECrsMtx == Teuchos::null, Xpetra::Exceptions::BadCast, "Cast from Xpetra::CrsMatrix to Xpetra::TpetraCrsMatrix failed");
168 
169  return tmp_ECrsMtx->getTpetra_CrsMatrix();
170  }
171 
173  // Get the underlying Tpetra Mtx
174  RCP<const CrsMatrixWrap> crsOp = Teuchos::rcp_dynamic_cast<const CrsMatrixWrap>(Op);
175  TEUCHOS_TEST_FOR_EXCEPTION(crsOp == Teuchos::null, Xpetra::Exceptions::BadCast, "Cast from Xpetra::Matrix to Xpetra::CrsMatrixWrap failed");
176  RCP<const CrsMatrix> tmp_CrsMtx = crsOp->getCrsMatrix();
177  const RCP<const Xpetra::TpetraCrsMatrix<SC,LO,GO,NO> > &tmp_ECrsMtx = Teuchos::rcp_dynamic_cast<const Xpetra::TpetraCrsMatrix<SC,LO,GO,NO> >(tmp_CrsMtx);
178  TEUCHOS_TEST_FOR_EXCEPTION(tmp_ECrsMtx == Teuchos::null, Xpetra::Exceptions::BadCast, "Cast from Xpetra::CrsMatrix to Xpetra::TpetraCrsMatrix failed");
179 
180  return tmp_ECrsMtx->getTpetra_CrsMatrixNonConst();
181  }
182 
183  static const Tpetra::CrsMatrix<SC,LO,GO,NO> & Op2TpetraCrs(const Matrix& Op) {
184  // Get the underlying Tpetra Mtx
185  try{
186  const CrsMatrixWrap& crsOp = dynamic_cast<const CrsMatrixWrap&>(Op);
187  RCP<const CrsMatrix> tmp_CrsMtx = crsOp.getCrsMatrix();
188  const RCP<const Xpetra::TpetraCrsMatrix<SC,LO,GO,NO> > &tmp_TCrsMtx = Teuchos::rcp_dynamic_cast<const Xpetra::TpetraCrsMatrix<SC,LO,GO,NO> >(tmp_CrsMtx);
189  TEUCHOS_TEST_FOR_EXCEPTION(tmp_TCrsMtx == Teuchos::null, Xpetra::Exceptions::BadCast, "Cast from Xpetra::CrsMatrix to Xpetra::TpetraCrsMatrix failed");
190 
191  return *tmp_TCrsMtx->getTpetra_CrsMatrix();
192 
193  } catch (...) {
194  throw(Xpetra::Exceptions::BadCast("Cast from Xpetra::Matrix to Xpetra::CrsMatrixWrap failed"));
195  }
196  }
197 
198  static Tpetra::CrsMatrix<SC,LO,GO,NO> & Op2NonConstTpetraCrs(const Matrix& Op) {
199  // Get the underlying Tpetra Mtx
200  try{
201  const CrsMatrixWrap& crsOp = dynamic_cast<const CrsMatrixWrap& >(Op);
202  RCP<const CrsMatrix> tmp_CrsMtx = crsOp.getCrsMatrix();
203  const RCP<const Xpetra::TpetraCrsMatrix<SC,LO,GO,NO> > &tmp_TCrsMtx = Teuchos::rcp_dynamic_cast<const Xpetra::TpetraCrsMatrix<SC,LO,GO,NO> >(tmp_CrsMtx);
204  TEUCHOS_TEST_FOR_EXCEPTION(tmp_TCrsMtx == Teuchos::null, Xpetra::Exceptions::BadCast, "Cast from Xpetra::CrsMatrix to Xpetra::TpetraCrsMatrix failed");
205 
206  return *Teuchos::rcp_const_cast<Tpetra::CrsMatrix<Scalar, LocalOrdinal, GlobalOrdinal, Node> >(tmp_TCrsMtx->getTpetra_CrsMatrix());
207 
208  } catch (...) {
209  throw(Xpetra::Exceptions::BadCast("Cast from Xpetra::Matrix to Xpetra::CrsMatrixWrap failed"));
210  }
211  }
212 #endif // HAVE_XPETRA_TPETRA
213 
214  };
215 
216  template <class Scalar,
217  class LocalOrdinal /*= int*/,
218  class GlobalOrdinal /*= LocalOrdinal*/,
219  class Node /*= KokkosClassic::DefaultNode::DefaultNodeType*/>
220  class MatrixMatrix {
221 #undef XPETRA_MATRIXMATRIX_SHORT
222 #include "Xpetra_UseShortNames.hpp"
223 
224  public:
225 
250  static void Multiply(const Matrix& A, bool transposeA,
251  const Matrix& B, bool transposeB,
252  Matrix& C,
253  bool call_FillComplete_on_result = true,
254  bool doOptimizeStorage = true,
255  const std::string & label = std::string(),
256  const RCP<ParameterList>& params = null) {
257 
258  TEUCHOS_TEST_FOR_EXCEPTION(transposeA == false && C.getRowMap()->isSameAs(*A.getRowMap()) == false,
259  Exceptions::RuntimeError, "XpetraExt::MatrixMatrix::Multiply: row map of C is not same as row map of A");
260  TEUCHOS_TEST_FOR_EXCEPTION(transposeA == true && C.getRowMap()->isSameAs(*A.getDomainMap()) == false,
261  Exceptions::RuntimeError, "XpetraExt::MatrixMatrix::Multiply: row map of C is not same as domain map of A");
262 
263  TEUCHOS_TEST_FOR_EXCEPTION(!A.isFillComplete(), Exceptions::RuntimeError, "A is not fill-completed");
264  TEUCHOS_TEST_FOR_EXCEPTION(!B.isFillComplete(), Exceptions::RuntimeError, "B is not fill-completed");
265 
266  bool haveMultiplyDoFillComplete = call_FillComplete_on_result && doOptimizeStorage;
267 
268  if (C.getRowMap()->lib() == Xpetra::UseEpetra) {
269 #if defined(HAVE_XPETRA_EPETRA) && defined(HAVE_XPETRA_EPETRAEXT)
270  throw(Xpetra::Exceptions::RuntimeError("Xpetra::MatrixMatrix::Multiply only available for GO=int or GO=long long with EpetraNode (Serial or OpenMP depending on configuration)"));
271 #else
272  throw(Xpetra::Exceptions::RuntimeError("Xpetra::MatrixMatrix::Multiply requires EpetraExt to be compiled."));
273 
274 #endif
275  } else if (C.getRowMap()->lib() == Xpetra::UseTpetra) {
276 #ifdef HAVE_XPETRA_TPETRA
277  const Tpetra::CrsMatrix<SC,LO,GO,NO> & tpA = Xpetra::Helpers<SC,LO,GO,NO>::Op2TpetraCrs(A);
278  const Tpetra::CrsMatrix<SC,LO,GO,NO> & tpB = Xpetra::Helpers<SC,LO,GO,NO>::Op2TpetraCrs(B);
279  Tpetra::CrsMatrix<SC,LO,GO,NO> & tpC = Xpetra::Helpers<SC,LO,GO,NO>::Op2NonConstTpetraCrs(C);
280 
281  // 18Feb2013 JJH I'm reenabling the code that allows the matrix matrix multiply to do the fillComplete.
282  // Previously, Tpetra's matrix matrix multiply did not support fillComplete.
283  Tpetra::MatrixMatrix::Multiply(tpA, transposeA, tpB, transposeB, tpC, haveMultiplyDoFillComplete, label, params);
284 #else
285  throw(Xpetra::Exceptions::RuntimeError("Xpetra must be compiled with Tpetra."));
286 #endif
287  }
288 
289  if (call_FillComplete_on_result && !haveMultiplyDoFillComplete) {
291  fillParams->set("Optimize Storage", doOptimizeStorage);
292  C.fillComplete((transposeB) ? B.getRangeMap() : B.getDomainMap(),
293  (transposeA) ? A.getDomainMap() : A.getRangeMap(),
294  fillParams);
295  }
296 
297  // transfer striding information
298  RCP<Matrix> rcpA = Teuchos::rcp_const_cast<Matrix>(Teuchos::rcpFromRef(A));
299  RCP<Matrix> rcpB = Teuchos::rcp_const_cast<Matrix>(Teuchos::rcpFromRef(B));
300  C.CreateView("stridedMaps", rcpA, transposeA, rcpB, transposeB); // TODO use references instead of RCPs
301  } // end Multiply
302 
325  static RCP<Matrix> Multiply(const Matrix& A, bool transposeA, const Matrix& B, bool transposeB, RCP<Matrix> C_in,
327  bool doFillComplete = true,
328  bool doOptimizeStorage = true,
329  const std::string & label = std::string(),
330  const RCP<ParameterList>& params = null) {
331 
332  TEUCHOS_TEST_FOR_EXCEPTION(!A.isFillComplete(), Exceptions::RuntimeError, "A is not fill-completed");
333  TEUCHOS_TEST_FOR_EXCEPTION(!B.isFillComplete(), Exceptions::RuntimeError, "B is not fill-completed");
334 
335  // Default case: Xpetra Multiply
336  RCP<Matrix> C = C_in;
337 
338  if (C == Teuchos::null) {
339  double nnzPerRow = Teuchos::as<double>(0);
340 
341 #if 0
342  if (A.getDomainMap()->lib() == Xpetra::UseTpetra) {
343  // For now, follow what ML and Epetra do.
344  GO numRowsA = A.getGlobalNumRows();
345  GO numRowsB = B.getGlobalNumRows();
346  nnzPerRow = sqrt(Teuchos::as<double>(A.getGlobalNumEntries())/numRowsA) +
347  sqrt(Teuchos::as<double>(B.getGlobalNumEntries())/numRowsB) - 1;
348  nnzPerRow *= nnzPerRow;
349  double totalNnz = nnzPerRow * A.getGlobalNumRows() * 0.75 + 100;
350  double minNnz = Teuchos::as<double>(1.2 * A.getGlobalNumEntries());
351  if (totalNnz < minNnz)
352  totalNnz = minNnz;
353  nnzPerRow = totalNnz / A.getGlobalNumRows();
354 
355  fos << "Matrix product nnz per row estimate = " << Teuchos::as<LO>(nnzPerRow) << std::endl;
356  }
357 #endif
358  if (transposeA) C = MatrixFactory::Build(A.getDomainMap(), Teuchos::as<LO>(nnzPerRow));
359  else C = MatrixFactory::Build(A.getRowMap(), Teuchos::as<LO>(nnzPerRow));
360 
361  } else {
362  C->resumeFill(); // why this is not done inside of Tpetra MxM?
363  fos << "Reuse C pattern" << std::endl;
364  }
365 
366  Multiply(A, transposeA, B, transposeB, *C, doFillComplete, doOptimizeStorage, label, params); // call Multiply routine from above
367 
368  return C;
369  }
370 
381  static RCP<Matrix> Multiply(const Matrix& A, bool transposeA, const Matrix& B, bool transposeB, Teuchos::FancyOStream &fos,
382  bool callFillCompleteOnResult = true, bool doOptimizeStorage = true, const std::string& label = std::string(),
383  const RCP<ParameterList>& params = null) {
384  return Multiply(A, transposeA, B, transposeB, Teuchos::null, fos, callFillCompleteOnResult, doOptimizeStorage, label, params);
385  }
386 
387 #ifdef HAVE_XPETRA_EPETRAEXT
388  // Michael Gee's MLMultiply
390  const Epetra_CrsMatrix& epB,
391  Teuchos::FancyOStream& fos) {
392  throw(Xpetra::Exceptions::RuntimeError("MLTwoMatrixMultiply only available for GO=int or GO=long long with EpetraNode (Serial or OpenMP depending on configuration)"));
393  TEUCHOS_UNREACHABLE_RETURN(Teuchos::null);
394  }
395 #endif //ifdef HAVE_XPETRA_EPETRAEXT
396 
408  const BlockedCrsMatrix& B, bool transposeB,
410  bool doFillComplete = true,
411  bool doOptimizeStorage = true) {
412  TEUCHOS_TEST_FOR_EXCEPTION(transposeA || transposeB, Exceptions::RuntimeError,
413  "TwoMatrixMultiply for BlockedCrsMatrix not implemented for transposeA==true or transposeB==true");
414 
415  // Preconditions
416  TEUCHOS_TEST_FOR_EXCEPTION(!A.isFillComplete(), Exceptions::RuntimeError, "A is not fill-completed");
417  TEUCHOS_TEST_FOR_EXCEPTION(!B.isFillComplete(), Exceptions::RuntimeError, "B is not fill-completed");
418 
419  RCP<const MapExtractor> rgmapextractor = A.getRangeMapExtractor();
420  RCP<const MapExtractor> domapextractor = B.getDomainMapExtractor();
421 
422  RCP<BlockedCrsMatrix> C = rcp(new BlockedCrsMatrix(rgmapextractor, domapextractor, 33 /* TODO fix me */));
423 
424  for (size_t i = 0; i < A.Rows(); ++i) { // loop over all block rows of A
425  for (size_t j = 0; j < B.Cols(); ++j) { // loop over all block columns of B
426  RCP<Matrix> Cij;
427 
428  for (size_t l = 0; l < B.Rows(); ++l) { // loop for calculating entry C_{ij}
429  RCP<Matrix> crmat1 = A.getMatrix(i,l);
430  RCP<Matrix> crmat2 = B.getMatrix(l,j);
431 
432  if (crmat1.is_null() || crmat2.is_null())
433  continue;
434 
435  RCP<CrsMatrixWrap> crop1 = Teuchos::rcp_dynamic_cast<CrsMatrixWrap>(crmat1);
436  RCP<CrsMatrixWrap> crop2 = Teuchos::rcp_dynamic_cast<CrsMatrixWrap>(crmat2);
438  "A and B must be either both (compatible) BlockedCrsMatrix objects or both CrsMatrixWrap objects.");
439 
440  // Forcibly compute the global constants if we don't have them (only works for real CrsMatrices, not nested blocks)
441  if (!crop1.is_null())
442  Teuchos::rcp_const_cast<CrsGraph>(crmat1->getCrsGraph())->computeGlobalConstants();
443  if (!crop2.is_null())
444  Teuchos::rcp_const_cast<CrsGraph>(crmat2->getCrsGraph())->computeGlobalConstants();
445 
446  TEUCHOS_TEST_FOR_EXCEPTION(!crmat1->haveGlobalConstants(), Exceptions::RuntimeError,
447  "crmat1 does not have global constants");
448  TEUCHOS_TEST_FOR_EXCEPTION(!crmat2->haveGlobalConstants(), Exceptions::RuntimeError,
449  "crmat2 does not have global constants");
450 
451  if (crmat1->getGlobalNumEntries() == 0 || crmat2->getGlobalNumEntries() == 0)
452  continue;
453 
454  // temporary matrix containing result of local block multiplication
455  RCP<Matrix> temp = Teuchos::null;
456 
457  if(crop1 != Teuchos::null && crop2 != Teuchos::null)
458  temp = Multiply (*crop1, false, *crop2, false, fos);
459  else {
460  RCP<BlockedCrsMatrix> bop1 = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(crmat1);
461  RCP<BlockedCrsMatrix> bop2 = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(crmat2);
462  TEUCHOS_TEST_FOR_EXCEPTION(bop1.is_null()==true, Xpetra::Exceptions::BadCast, "A is not a BlockedCrsMatrix. (TwoMatrixMultiplyBlock)");
463  TEUCHOS_TEST_FOR_EXCEPTION(bop2.is_null()==true, Xpetra::Exceptions::BadCast, "B is not a BlockedCrsMatrix. (TwoMatrixMultiplyBlock)");
464  TEUCHOS_TEST_FOR_EXCEPTION(bop1->Cols()!=bop2->Rows(), Xpetra::Exceptions::RuntimeError, "A has " << bop1->Cols() << " columns and B has " << bop2->Rows() << " rows. Matrices are not compatible! (TwoMatrixMultiplyBlock)");
465  TEUCHOS_TEST_FOR_EXCEPTION(bop1->getDomainMap()->isSameAs(*(bop2->getRangeMap()))==false, Xpetra::Exceptions::RuntimeError, "Domain map of A is not the same as range map of B. Matrices are not compatible! (TwoMatrixMultiplyBlock)");
466 
467  // recursive multiplication call
468  temp = TwoMatrixMultiplyBlock(*bop1, transposeA, *bop2, transposeB, fos, doFillComplete, doOptimizeStorage);
469 
470  RCP<BlockedCrsMatrix> btemp = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(temp);
471  TEUCHOS_TEST_FOR_EXCEPTION(btemp->Rows()!=bop1->Rows(), Xpetra::Exceptions::RuntimeError, "Number of block rows of local blocked operator is " << btemp->Rows() << " but should be " << bop1->Rows() << ". (TwoMatrixMultiplyBlock)");
472  TEUCHOS_TEST_FOR_EXCEPTION(btemp->Cols()!=bop2->Cols(), Xpetra::Exceptions::RuntimeError, "Number of block cols of local blocked operator is " << btemp->Cols() << " but should be " << bop2->Cols() << ". (TwoMatrixMultiplyBlock)");
473  TEUCHOS_TEST_FOR_EXCEPTION(btemp->getRangeMapExtractor()->getFullMap()->isSameAs(*(bop1->getRangeMapExtractor()->getFullMap())) == false, Xpetra::Exceptions::RuntimeError, "Range map of local blocked operator should be same as first operator. (TwoMatrixMultiplyBlock)");
474  TEUCHOS_TEST_FOR_EXCEPTION(btemp->getDomainMapExtractor()->getFullMap()->isSameAs(*(bop2->getDomainMapExtractor()->getFullMap())) == false, Xpetra::Exceptions::RuntimeError, "Domain map of local blocked operator should be same as second operator. (TwoMatrixMultiplyBlock)");
475  TEUCHOS_TEST_FOR_EXCEPTION(btemp->getRangeMapExtractor()->getThyraMode() != bop1->getRangeMapExtractor()->getThyraMode(), Xpetra::Exceptions::RuntimeError, "Thyra mode of local range map extractor incompatible with range map extractor of A (TwoMatrixMultiplyBlock)");
476  TEUCHOS_TEST_FOR_EXCEPTION(btemp->getDomainMapExtractor()->getThyraMode() != bop2->getDomainMapExtractor()->getThyraMode(), Xpetra::Exceptions::RuntimeError, "Thyra mode of local domain map extractor incompatible with domain map extractor of B (TwoMatrixMultiplyBlock)");
477  }
478 
479  TEUCHOS_TEST_FOR_EXCEPTION(temp->isFillComplete() == false, Xpetra::Exceptions::RuntimeError, "Local block is not filled. (TwoMatrixMultiplyBlock)");
480 
481  RCP<Matrix> addRes = null;
482  if (Cij.is_null ())
483  Cij = temp;
484  else {
485  MatrixMatrix::TwoMatrixAdd (*temp, false, 1.0, *Cij, false, 1.0, addRes, fos);
486  Cij = addRes;
487  }
488  }
489 
490  if (!Cij.is_null()) {
491  if (Cij->isFillComplete())
492  Cij->resumeFill();
493  Cij->fillComplete(B.getDomainMap(j), A.getRangeMap(i));
494  C->setMatrix(i, j, Cij);
495  } else {
496  C->setMatrix(i, j, Teuchos::null);
497  }
498  }
499  }
500 
501  if (doFillComplete)
502  C->fillComplete(); // call default fillComplete for BlockCrsMatrixWrap objects
503 
504  return C;
505  } // TwoMatrixMultiplyBlock
506 
519  static void TwoMatrixAdd(const Matrix& A, bool transposeA, SC alpha, Matrix& B, SC beta) {
520  if (!(A.getRowMap()->isSameAs(*(B.getRowMap()))))
521  throw Exceptions::Incompatible("TwoMatrixAdd: matrix row maps are not the same.");
522 
523  if (A.getRowMap()->lib() == Xpetra::UseEpetra) {
524  throw Exceptions::RuntimeError("TwoMatrixAdd for Epetra matrices needs <double,int,int> for Scalar, LocalOrdinal and GlobalOrdinal.");
525  } else if (A.getRowMap()->lib() == Xpetra::UseTpetra) {
526 #ifdef HAVE_XPETRA_TPETRA
527  const Tpetra::CrsMatrix<SC,LO,GO,NO>& tpA = Xpetra::Helpers<SC,LO,GO,NO>::Op2TpetraCrs(A);
528  Tpetra::CrsMatrix<SC,LO,GO,NO>& tpB = Xpetra::Helpers<SC,LO,GO,NO>::Op2NonConstTpetraCrs(B);
529 
530  Tpetra::MatrixMatrix::Add(tpA, transposeA, alpha, tpB, beta);
531 #else
532  throw Exceptions::RuntimeError("Xpetra must be compiled with Tpetra.");
533 #endif
534  }
535  } //MatrixMatrix::TwoMatrixAdd()
536 
537 
550  static void TwoMatrixAdd(const Matrix& A, bool transposeA, const SC& alpha,
551  const Matrix& B, bool transposeB, const SC& beta,
552  RCP<Matrix>& C, Teuchos::FancyOStream &fos, bool AHasFixedNnzPerRow = false) {
553 
554  RCP<const Matrix> rcpA = Teuchos::rcpFromRef(A);
555  RCP<const Matrix> rcpB = Teuchos::rcpFromRef(B);
556  RCP<const BlockedCrsMatrix> rcpBopA = Teuchos::rcp_dynamic_cast<const BlockedCrsMatrix>(rcpA);
557  RCP<const BlockedCrsMatrix> rcpBopB = Teuchos::rcp_dynamic_cast<const BlockedCrsMatrix>(rcpB);
558 
559  // We have to distinguish 4 cases:
560  // both matrices are CrsMatrixWrap based, only one of them is CrsMatrixWrap based, or none.
561 
562  // Both matrices are CrsMatrixWrap
563  if(rcpBopA == Teuchos::null && rcpBopB == Teuchos::null) {
564 
565  if (!(A.getRowMap()->isSameAs(*(B.getRowMap()))))
566  throw Exceptions::Incompatible("TwoMatrixAdd: matrix row maps are not the same.");
567 
568 
569  if (C == Teuchos::null) {
570  size_t maxNzInA = 0;
571  size_t maxNzInB = 0;
572  size_t numLocalRows = 0;
573  if (A.isFillComplete() && B.isFillComplete()) {
574  maxNzInA = A.getNodeMaxNumRowEntries();
575  maxNzInB = B.getNodeMaxNumRowEntries();
576  numLocalRows = A.getNodeNumRows();
577  }
578  if (maxNzInA == 1 || maxNzInB == 1 || AHasFixedNnzPerRow) {
579  // first check if either A or B has at most 1 nonzero per row
580  // the case of both having at most 1 nz per row is handled by the ``else''
581  Teuchos::ArrayRCP<size_t> exactNnzPerRow(numLocalRows);
582 
583  if ((maxNzInA == 1 && maxNzInB > 1) || AHasFixedNnzPerRow) {
584  for (size_t i = 0; i < numLocalRows; ++i)
585  exactNnzPerRow[i] = B.getNumEntriesInLocalRow(Teuchos::as<LO>(i)) + maxNzInA;
586 
587  } else {
588  for (size_t i = 0; i < numLocalRows; ++i)
589  exactNnzPerRow[i] = A.getNumEntriesInLocalRow(Teuchos::as<LO>(i)) + maxNzInB;
590  }
591 
592  fos << "MatrixMatrix::TwoMatrixAdd : special case detected (one matrix has a fixed nnz per row)"
593  << ", using static profiling" << std::endl;
594  C = rcp(new CrsMatrixWrap(A.getRowMap(), exactNnzPerRow, Xpetra::StaticProfile));
595  } else {
596  // general case
597  double nnzPerRowInA = Teuchos::as<double>(A.getNodeNumEntries()) / A.getNodeNumRows();
598  double nnzPerRowInB = Teuchos::as<double>(B.getNodeNumEntries()) / B.getNodeNumRows();
599  LO nnzToAllocate = Teuchos::as<LO>( (nnzPerRowInA + nnzPerRowInB) * 1.5) + Teuchos::as<LO>(1);
600 
601  LO maxPossible = A.getNodeMaxNumRowEntries() + B.getNodeMaxNumRowEntries();
602  //Use static profiling (more efficient) if the estimate is at least as big as the max
603  //possible nnz's in any single row of the result.
604  Xpetra::ProfileType pft = (maxPossible) > nnzToAllocate ? Xpetra::DynamicProfile : Xpetra::StaticProfile;
605 
606  fos << "nnzPerRowInA = " << nnzPerRowInA << ", nnzPerRowInB = " << nnzPerRowInB << std::endl;
607  fos << "MatrixMatrix::TwoMatrixAdd : space allocated per row = " << nnzToAllocate
608  << ", max possible nnz per row in sum = " << maxPossible
609  << ", using " << (pft == Xpetra::DynamicProfile ? "dynamic" : "static" ) << " profiling"
610  << std::endl;
611  C = rcp(new CrsMatrixWrap(A.getRowMap(), nnzToAllocate, pft));
612  }
613  if (transposeB)
614  fos << "MatrixMatrix::TwoMatrixAdd : ** WARNING ** estimate could be badly wrong because second summand is transposed" << std::endl;
615  }
616 
617  if (C->getRowMap()->lib() == Xpetra::UseEpetra) {
618  throw Exceptions::RuntimeError("MatrixMatrix::Add for Epetra only available with Scalar = double, LO = GO = int.");
619  } else if (C->getRowMap()->lib() == Xpetra::UseTpetra) {
620  #ifdef HAVE_XPETRA_TPETRA
621  const Tpetra::CrsMatrix<SC,LO,GO,NO>& tpA = Xpetra::Helpers<SC,LO,GO,NO>::Op2TpetraCrs(A);
622  const Tpetra::CrsMatrix<SC,LO,GO,NO>& tpB = Xpetra::Helpers<SC,LO,GO,NO>::Op2TpetraCrs(B);
624 
625  Tpetra::MatrixMatrix::Add(tpA, transposeA, alpha, tpB, transposeB, beta, tpC);
626  #else
627  throw Exceptions::RuntimeError("Xpetra must be compile with Tpetra.");
628  #endif
629  }
631  if (A.IsView("stridedMaps")) C->CreateView("stridedMaps", rcpFromRef(A));
632  if (B.IsView("stridedMaps")) C->CreateView("stridedMaps", rcpFromRef(B));
634  }
635  // the first matrix is of type CrsMatrixWrap, the second is a blocked operator
636  else if(rcpBopA == Teuchos::null && rcpBopB != Teuchos::null) {
637  RCP<const MapExtractor> rgmapextractor = rcpBopB->getRangeMapExtractor();
638  RCP<const MapExtractor> domapextractor = rcpBopB->getDomainMapExtractor();
639 
640  C = rcp(new BlockedCrsMatrix(rgmapextractor, domapextractor, 33 /* TODO fix me */));
641  RCP<BlockedCrsMatrix> bC = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(C);
642 
643  size_t i = 0;
644  for (size_t j = 0; j < rcpBopB->Cols(); ++j) { // loop over all block columns of B
645  RCP<Matrix> Cij = Teuchos::null;
646  if(rcpA != Teuchos::null &&
647  rcpBopB->getMatrix(i,j)!=Teuchos::null) {
648  // recursive call
649  TwoMatrixAdd(*rcpA, transposeA, alpha,
650  *(rcpBopB->getMatrix(i,j)), transposeB, beta,
651  Cij, fos, AHasFixedNnzPerRow);
652  } else if (rcpA == Teuchos::null &&
653  rcpBopB->getMatrix(i,j)!=Teuchos::null) {
654  Cij = rcpBopB->getMatrix(i,j);
655  } else if (rcpA != Teuchos::null &&
656  rcpBopB->getMatrix(i,j)==Teuchos::null) {
657  Cij = Teuchos::rcp_const_cast<Matrix>(rcpA);
658  } else {
659  Cij = Teuchos::null;
660  }
661 
662  if (!Cij.is_null()) {
663  if (Cij->isFillComplete())
664  Cij->resumeFill();
665  Cij->fillComplete();
666  bC->setMatrix(i, j, Cij);
667  } else {
668  bC->setMatrix(i, j, Teuchos::null);
669  }
670  } // loop over columns j
671  }
672  // the second matrix is of type CrsMatrixWrap, the first is a blocked operator
673  else if(rcpBopA != Teuchos::null && rcpBopB == Teuchos::null) {
674  RCP<const MapExtractor> rgmapextractor = rcpBopA->getRangeMapExtractor();
675  RCP<const MapExtractor> domapextractor = rcpBopA->getDomainMapExtractor();
676 
677  C = rcp(new BlockedCrsMatrix(rgmapextractor, domapextractor, 33 /* TODO fix me */));
678  RCP<BlockedCrsMatrix> bC = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(C);
679  size_t j = 0;
680  for (size_t i = 0; i < rcpBopA->Rows(); ++i) { // loop over all block rows of A
681  RCP<Matrix> Cij = Teuchos::null;
682  if(rcpBopA->getMatrix(i,j)!=Teuchos::null &&
683  rcpB!=Teuchos::null) {
684  // recursive call
685  TwoMatrixAdd(*(rcpBopA->getMatrix(i,j)), transposeA, alpha,
686  *rcpB, transposeB, beta,
687  Cij, fos, AHasFixedNnzPerRow);
688  } else if (rcpBopA->getMatrix(i,j) == Teuchos::null &&
689  rcpB!=Teuchos::null) {
690  Cij = Teuchos::rcp_const_cast<Matrix>(rcpB);
691  } else if (rcpBopA->getMatrix(i,j) != Teuchos::null &&
692  rcpB==Teuchos::null) {
693  Cij = rcpBopA->getMatrix(i,j);
694  } else {
695  Cij = Teuchos::null;
696  }
697 
698  if (!Cij.is_null()) {
699  if (Cij->isFillComplete())
700  Cij->resumeFill();
701  Cij->fillComplete();
702  bC->setMatrix(i, j, Cij);
703  } else {
704  bC->setMatrix(i, j, Teuchos::null);
705  }
706  } // loop over rows i
707  }
708  else {
709  // This is the version for blocked matrices
710 
711  // check the compatibility of the blocked operators
712  TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA.is_null()==true, Xpetra::Exceptions::BadCast, "A is not a BlockedCrsMatrix. (TwoMatrixAdd)");
713  TEUCHOS_TEST_FOR_EXCEPTION(rcpBopB.is_null()==true, Xpetra::Exceptions::BadCast, "B is not a BlockedCrsMatrix. (TwoMatrixAdd)");
714  TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA->Rows()!=rcpBopB->Rows(), Xpetra::Exceptions::RuntimeError, "A has " << rcpBopA->Rows() << " rows and B has " << rcpBopA->Rows() << " rows. Matrices are not compatible! (TwoMatrixAdd)");
715  TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA->Rows()!=rcpBopB->Rows(), Xpetra::Exceptions::RuntimeError, "A has " << rcpBopA->Cols() << " cols and B has " << rcpBopA->Cols() << " cols. Matrices are not compatible! (TwoMatrixAdd)");
716  TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA->getRangeMap()->isSameAs(*(rcpBopB->getRangeMap()))==false, Xpetra::Exceptions::RuntimeError, "Range map of A is not the same as range map of B. Matrices are not compatible! (TwoMatrixAdd)");
717  TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA->getDomainMap()->isSameAs(*(rcpBopB->getDomainMap()))==false, Xpetra::Exceptions::RuntimeError, "Domain map of A is not the same as domain map of B. Matrices are not compatible! (TwoMatrixAdd)");
718  TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA->getRangeMapExtractor()->getThyraMode() != rcpBopB->getRangeMapExtractor()->getThyraMode(), Xpetra::Exceptions::RuntimeError, "Different Thyra/Xpetra style gids in RangeMapExtractor of A and B. Matrices are not compatible! (TwoMatrixAdd)");
719  TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA->getDomainMapExtractor()->getThyraMode() != rcpBopB->getDomainMapExtractor()->getThyraMode(), Xpetra::Exceptions::RuntimeError, "Different Thyra/Xpetra style gids in DomainMapExtractor of A and B. Matrices are not compatible! (TwoMatrixAdd)");
720 
721  RCP<const MapExtractor> rgmapextractor = rcpBopA->getRangeMapExtractor();
722  RCP<const MapExtractor> domapextractor = rcpBopB->getDomainMapExtractor();
723 
724  C = rcp(new BlockedCrsMatrix(rgmapextractor, domapextractor, 33 /* TODO fix me */));
725  RCP<BlockedCrsMatrix> bC = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(C);
726  for (size_t i = 0; i < rcpBopA->Rows(); ++i) { // loop over all block rows of A
727  for (size_t j = 0; j < rcpBopB->Cols(); ++j) { // loop over all block columns of B
728 
729  RCP<Matrix> Cij = Teuchos::null;
730  if(rcpBopA->getMatrix(i,j)!=Teuchos::null &&
731  rcpBopB->getMatrix(i,j)!=Teuchos::null) {
732  // recursive call
733  TwoMatrixAdd(*(rcpBopA->getMatrix(i,j)), transposeA, alpha,
734  *(rcpBopB->getMatrix(i,j)), transposeB, beta,
735  Cij, fos, AHasFixedNnzPerRow);
736  } else if (rcpBopA->getMatrix(i,j) == Teuchos::null &&
737  rcpBopB->getMatrix(i,j)!=Teuchos::null) {
738  Cij = rcpBopB->getMatrix(i,j);
739  } else if (rcpBopA->getMatrix(i,j) != Teuchos::null &&
740  rcpBopB->getMatrix(i,j)==Teuchos::null) {
741  Cij = rcpBopA->getMatrix(i,j);
742  } else {
743  Cij = Teuchos::null;
744  }
745 
746  if (!Cij.is_null()) {
747  if (Cij->isFillComplete())
748  Cij->resumeFill();
749  Cij->fillComplete();
750  bC->setMatrix(i, j, Cij);
751  } else {
752  bC->setMatrix(i, j, Teuchos::null);
753  }
754  } // loop over columns j
755  } // loop over rows i
756 
757  } // end blocked recursive algorithm
758  } //MatrixMatrix::TwoMatrixAdd()
759 
760 
761  }; // class MatrixMatrix
762 
763 
764 #ifdef HAVE_XPETRA_EPETRA
765  // specialization MatrixMatrix for SC=double, LO=GO=int
766  template<>
767  class MatrixMatrix<double,int,int,EpetraNode> {
768  typedef double Scalar;
769  typedef int LocalOrdinal;
770  typedef int GlobalOrdinal;
771  typedef EpetraNode Node;
772 #include "Xpetra_UseShortNames.hpp"
773 
774  public:
775 
800  static void Multiply(const Matrix& A, bool transposeA,
801  const Matrix& B, bool transposeB,
802  Matrix& C,
803  bool call_FillComplete_on_result = true,
804  bool doOptimizeStorage = true,
805  const std::string & label = std::string(),
806  const RCP<ParameterList>& params = null) {
807  TEUCHOS_TEST_FOR_EXCEPTION(transposeA == false && C.getRowMap()->isSameAs(*A.getRowMap()) == false,
808  Xpetra::Exceptions::RuntimeError, "XpetraExt::MatrixMatrix::Multiply: row map of C is not same as row map of A");
809  TEUCHOS_TEST_FOR_EXCEPTION(transposeA == true && C.getRowMap()->isSameAs(*A.getDomainMap()) == false,
810  Xpetra::Exceptions::RuntimeError, "XpetraExt::MatrixMatrix::Multiply: row map of C is not same as domain map of A");
811 
814 
815  bool haveMultiplyDoFillComplete = call_FillComplete_on_result && doOptimizeStorage;
816 
817  if (C.getRowMap()->lib() == Xpetra::UseEpetra) {
818 #if defined(HAVE_XPETRA_EPETRA) && defined(HAVE_XPETRA_EPETRAEXT)
822 
823  int i = EpetraExt::MatrixMatrix::Multiply(epA, transposeA, epB, transposeB, epC, haveMultiplyDoFillComplete);
824  if (haveMultiplyDoFillComplete) {
825  // Due to Epetra wrapper intricacies, we need to explicitly call
826  // fillComplete on Xpetra matrix here. Specifically, EpetraCrsMatrix
827  // only keeps an internal variable to check whether we are in resumed
828  // state or not, but never touches the underlying Epetra object. As
829  // such, we need to explicitly update the state of Xpetra matrix to
830  // that of Epetra one afterwords
831  C.fillComplete();
832  }
833 
834  if (i != 0) {
835  std::ostringstream buf;
836  buf << i;
837  std::string msg = "EpetraExt::MatrixMatrix::Multiply return value of " + buf.str();
838  throw(Exceptions::RuntimeError(msg));
839  }
840 
841 #else
842  throw(Xpetra::Exceptions::RuntimeError("Xpetra::MatrixMatrix::Multiply requires EpetraExt to be compiled."));
843 #endif
844  } else if (C.getRowMap()->lib() == Xpetra::UseTpetra) {
845 #ifdef HAVE_XPETRA_TPETRA
846 # if ((defined(EPETRA_HAVE_OMP) && (!defined(HAVE_TPETRA_INST_OPENMP) || !defined(HAVE_TPETRA_INST_INT_INT))) || \
847  (!defined(EPETRA_HAVE_OMP) && (!defined(HAVE_TPETRA_INST_SERIAL) || !defined(HAVE_TPETRA_INST_INT_INT))))
848  throw(Xpetra::Exceptions::RuntimeError("Xpetra must be compiled with Tpetra <double,int,int> ETI enabled."));
849 # else
850  const Tpetra::CrsMatrix<SC,LO,GO,NO> & tpA = Xpetra::Helpers<SC,LO,GO,NO>::Op2TpetraCrs(A);
851  const Tpetra::CrsMatrix<SC,LO,GO,NO> & tpB = Xpetra::Helpers<SC,LO,GO,NO>::Op2TpetraCrs(B);
852  Tpetra::CrsMatrix<SC,LO,GO,NO> & tpC = Xpetra::Helpers<SC,LO,GO,NO>::Op2NonConstTpetraCrs(C);
853 
854  // 18Feb2013 JJH I'm reenabling the code that allows the matrix matrix multiply to do the fillComplete.
855  // Previously, Tpetra's matrix matrix multiply did not support fillComplete.
856  Tpetra::MatrixMatrix::Multiply(tpA, transposeA, tpB, transposeB, tpC, haveMultiplyDoFillComplete, label, params);
857 # endif
858 #else
859  throw(Xpetra::Exceptions::RuntimeError("Xpetra must be compiled with Tpetra."));
860 #endif
861  }
862 
863  if (call_FillComplete_on_result && !haveMultiplyDoFillComplete) {
865  fillParams->set("Optimize Storage",doOptimizeStorage);
866  C.fillComplete((transposeB) ? B.getRangeMap() : B.getDomainMap(),
867  (transposeA) ? A.getDomainMap() : A.getRangeMap(),
868  fillParams);
869  }
870 
871  // transfer striding information
872  RCP<Matrix> rcpA = Teuchos::rcp_const_cast<Matrix>(Teuchos::rcpFromRef(A));
873  RCP<Matrix> rcpB = Teuchos::rcp_const_cast<Matrix>(Teuchos::rcpFromRef(B));
874  C.CreateView("stridedMaps", rcpA, transposeA, rcpB, transposeB); // TODO use references instead of RCPs
875  } // end Multiply
876 
899  static RCP<Matrix> Multiply(const Matrix& A, bool transposeA,
900  const Matrix& B, bool transposeB,
901  RCP<Matrix> C_in,
903  bool doFillComplete = true,
904  bool doOptimizeStorage = true,
905  const std::string & label = std::string(),
906  const RCP<ParameterList>& params = null) {
907 
908  TEUCHOS_TEST_FOR_EXCEPTION(!A.isFillComplete(), Exceptions::RuntimeError, "A is not fill-completed");
909  TEUCHOS_TEST_FOR_EXCEPTION(!B.isFillComplete(), Exceptions::RuntimeError, "B is not fill-completed");
910 
911  // Optimization using ML Multiply when available and requested
912  // This feature is currently not supported. We would have to introduce the HAVE_XPETRA_ML_MMM flag
913 #if defined(HAVE_XPETRA_EPETRA) && defined(HAVE_XPETRA_EPETRAEXT) && defined(HAVE_XPETRA_ML_MMM)
914  if (B.getDomainMap()->lib() == Xpetra::UseEpetra && !transposeA && !transposeB) {
917  RCP<Epetra_CrsMatrix> epC = MLTwoMatrixMultiply(*epA, *epB, fos);
918 
919  RCP<Matrix> C = Convert_Epetra_CrsMatrix_ToXpetra_CrsMatrixWrap<SC,LO,GO,NO> (epC);
920  if (doFillComplete) {
922  fillParams->set("Optimize Storage", doOptimizeStorage);
923  C->fillComplete(B.getDomainMap(), A.getRangeMap(), fillParams);
924  }
925 
926  // Fill strided maps information
927  // This is necessary since the ML matrix matrix multiplication routine has no handling for this
928  // TODO: move this call to MLMultiply...
929  C->CreateView("stridedMaps", rcpFromRef(A), transposeA, rcpFromRef(B), transposeB);
930 
931  return C;
932  }
933 #endif // EPETRA + EPETRAEXT + ML
934 
935  // Default case: Xpetra Multiply
936  RCP<Matrix> C = C_in;
937 
938  if (C == Teuchos::null) {
939  double nnzPerRow = Teuchos::as<double>(0);
940 
941 #if 0
942  if (A.getDomainMap()->lib() == Xpetra::UseTpetra) {
943  // For now, follow what ML and Epetra do.
944  GO numRowsA = A.getGlobalNumRows();
945  GO numRowsB = B.getGlobalNumRows();
946  nnzPerRow = sqrt(Teuchos::as<double>(A.getGlobalNumEntries())/numRowsA) +
947  sqrt(Teuchos::as<double>(B.getGlobalNumEntries())/numRowsB) - 1;
948  nnzPerRow *= nnzPerRow;
949  double totalNnz = nnzPerRow * A.getGlobalNumRows() * 0.75 + 100;
950  double minNnz = Teuchos::as<double>(1.2 * A.getGlobalNumEntries());
951  if (totalNnz < minNnz)
952  totalNnz = minNnz;
953  nnzPerRow = totalNnz / A.getGlobalNumRows();
954 
955  fos << "Matrix product nnz per row estimate = " << Teuchos::as<LO>(nnzPerRow) << std::endl;
956  }
957 #endif
958 
959  if (transposeA) C = MatrixFactory::Build(A.getDomainMap(), Teuchos::as<LO>(nnzPerRow));
960  else C = MatrixFactory::Build(A.getRowMap(), Teuchos::as<LO>(nnzPerRow));
961 
962  } else {
963  C->resumeFill(); // why this is not done inside of Tpetra MxM?
964  fos << "Reuse C pattern" << std::endl;
965  }
966 
967  Multiply(A, transposeA, B, transposeB, *C, doFillComplete, doOptimizeStorage, label, params); // call Multiply routine from above
968 
969  return C;
970  }
971 
982  static RCP<Matrix> Multiply(const Matrix& A, bool transposeA,
983  const Matrix& B, bool transposeB,
985  bool callFillCompleteOnResult = true,
986  bool doOptimizeStorage = true,
987  const std::string & label = std::string(),
988  const RCP<ParameterList>& params = null) {
989  return Multiply(A, transposeA, B, transposeB, Teuchos::null, fos, callFillCompleteOnResult, doOptimizeStorage, label, params);
990  }
991 
992 #if defined(HAVE_XPETRA_EPETRA) && defined(HAVE_XPETRA_EPETRAEXT)
993  // Michael Gee's MLMultiply
995  const Epetra_CrsMatrix& epB,
996  Teuchos::FancyOStream& fos) {
997 #if defined(HAVE_XPETRA_ML_MMM) // Note: this is currently not supported
998  ML_Comm* comm;
999  ML_Comm_Create(&comm);
1000  fos << "****** USING ML's MATRIX MATRIX MULTIPLY ******" << std::endl;
1001 #ifdef HAVE_MPI
1002  // ML_Comm uses MPI_COMM_WORLD, so try to use the same communicator as epA.
1003  const Epetra_MpiComm * Mcomm = dynamic_cast<const Epetra_MpiComm*>(&(epA.Comm()));
1004  if (Mcomm)
1005  ML_Comm_Set_UsrComm(comm,Mcomm->GetMpiComm());
1006 # endif
1007  //in order to use ML, there must be no indices missing from the matrix column maps.
1008  EpetraExt::CrsMatrix_SolverMap Atransform;
1009  EpetraExt::CrsMatrix_SolverMap Btransform;
1010  const Epetra_CrsMatrix& A = Atransform(const_cast<Epetra_CrsMatrix&>(epA));
1011  const Epetra_CrsMatrix& B = Btransform(const_cast<Epetra_CrsMatrix&>(epB));
1012 
1013  if (!A.Filled()) throw Exceptions::RuntimeError("A has to be FillCompleted");
1014  if (!B.Filled()) throw Exceptions::RuntimeError("B has to be FillCompleted");
1015 
1016  // create ML operators from EpetraCrsMatrix
1017  ML_Operator* ml_As = ML_Operator_Create(comm);
1018  ML_Operator* ml_Bs = ML_Operator_Create(comm);
1019  ML_Operator_WrapEpetraCrsMatrix(const_cast<Epetra_CrsMatrix*>(&A),ml_As); // Should we test if the lightweight wrapper is actually used or if WrapEpetraCrsMatrix fall backs to the heavy one?
1020  ML_Operator_WrapEpetraCrsMatrix(const_cast<Epetra_CrsMatrix*>(&B),ml_Bs);
1021  ML_Operator* ml_AtimesB = ML_Operator_Create(comm);
1022  {
1023  Teuchos::TimeMonitor tm(*Teuchos::TimeMonitor::getNewTimer("ML_2matmult kernel"));
1024  ML_2matmult(ml_As,ml_Bs,ml_AtimesB,ML_CSR_MATRIX); // do NOT use ML_EpetraCRS_MATRIX!!!
1025  }
1026  ML_Operator_Destroy(&ml_As);
1027  ML_Operator_Destroy(&ml_Bs);
1028 
1029  // For ml_AtimesB we have to reconstruct the column map in global indexing,
1030  // The following is going down to the salt-mines of ML ...
1031  // note: we use integers, since ML only works for Epetra...
1032  int N_local = ml_AtimesB->invec_leng;
1033  ML_CommInfoOP* getrow_comm = ml_AtimesB->getrow->pre_comm;
1034  if (!getrow_comm) throw(Exceptions::RuntimeError("ML_Operator does not have a CommInfo"));
1035  ML_Comm* comm_AB = ml_AtimesB->comm; // get comm object
1036  if (N_local != B.DomainMap().NumMyElements())
1037  throw(Exceptions::RuntimeError("Mismatch in local row dimension between ML and Epetra"));
1038  int N_rcvd = 0;
1039  int N_send = 0;
1040  int flag = 0;
1041  for (int i = 0; i < getrow_comm->N_neighbors; i++) {
1042  N_rcvd += (getrow_comm->neighbors)[i].N_rcv;
1043  N_send += (getrow_comm->neighbors)[i].N_send;
1044  if ( ((getrow_comm->neighbors)[i].N_rcv != 0) &&
1045  ((getrow_comm->neighbors)[i].rcv_list != NULL) ) flag = 1;
1046  }
1047  // For some unknown reason, ML likes to have stuff one larger than
1048  // neccessary...
1049  std::vector<double> dtemp(N_local + N_rcvd + 1); // "double" vector for comm function
1050  std::vector<int> cmap (N_local + N_rcvd + 1); // vector for gids
1051  for (int i = 0; i < N_local; ++i) {
1052  cmap[i] = B.DomainMap().GID(i);
1053  dtemp[i] = (double) cmap[i];
1054  }
1055  ML_cheap_exchange_bdry(&dtemp[0],getrow_comm,N_local,N_send,comm_AB); // do communication
1056  if (flag) { // process received data
1057  int count = N_local;
1058  const int neighbors = getrow_comm->N_neighbors;
1059  for (int i = 0; i < neighbors; i++) {
1060  const int nrcv = getrow_comm->neighbors[i].N_rcv;
1061  for (int j = 0; j < nrcv; j++)
1062  cmap[getrow_comm->neighbors[i].rcv_list[j]] = (int) dtemp[count++];
1063  }
1064  } else {
1065  for (int i = 0; i < N_local+N_rcvd; ++i)
1066  cmap[i] = (int)dtemp[i];
1067  }
1068  dtemp.clear(); // free double array
1069 
1070  // we can now determine a matching column map for the result
1071  Epetra_Map gcmap(-1, N_local+N_rcvd, &cmap[0], B.ColMap().IndexBase(), A.Comm());
1072 
1073  int allocated = 0;
1074  int rowlength;
1075  double* val = NULL;
1076  int* bindx = NULL;
1077 
1078  const int myrowlength = A.RowMap().NumMyElements();
1079  const Epetra_Map& rowmap = A.RowMap();
1080 
1081  // Determine the maximum bandwith for the result matrix.
1082  // replaces the old, very(!) memory-consuming guess:
1083  // int guessnpr = A.MaxNumEntries()*B.MaxNumEntries();
1084  int educatedguess = 0;
1085  for (int i = 0; i < myrowlength; ++i) {
1086  // get local row
1087  ML_get_matrix_row(ml_AtimesB, 1, &i, &allocated, &bindx, &val, &rowlength, 0);
1088  if (rowlength>educatedguess)
1089  educatedguess = rowlength;
1090  }
1091 
1092  // allocate our result matrix and fill it
1093  RCP<Epetra_CrsMatrix> result = rcp(new Epetra_CrsMatrix(::Copy, A.RangeMap(), gcmap, educatedguess, false));
1094 
1095  std::vector<int> gcid(educatedguess);
1096  for (int i = 0; i < myrowlength; ++i) {
1097  const int grid = rowmap.GID(i);
1098  // get local row
1099  ML_get_matrix_row(ml_AtimesB, 1, &i, &allocated, &bindx, &val, &rowlength, 0);
1100  if (!rowlength) continue;
1101  if ((int)gcid.size() < rowlength) gcid.resize(rowlength);
1102  for (int j = 0; j < rowlength; ++j) {
1103  gcid[j] = gcmap.GID(bindx[j]);
1104  if (gcid[j] < 0)
1105  throw Exceptions::RuntimeError("Error: cannot find gcid!");
1106  }
1107  int err = result->InsertGlobalValues(grid, rowlength, val, &gcid[0]);
1108  if (err != 0 && err != 1) {
1109  std::ostringstream errStr;
1110  errStr << "Epetra_CrsMatrix::InsertGlobalValues returned err=" << err;
1111  throw Exceptions::RuntimeError(errStr.str());
1112  }
1113  }
1114  // free memory
1115  if (bindx) ML_free(bindx);
1116  if (val) ML_free(val);
1117  ML_Operator_Destroy(&ml_AtimesB);
1118  ML_Comm_Destroy(&comm);
1119 
1120  return result;
1121 #else // no MUELU_ML
1122  (void)epA;
1123  (void)epB;
1124  (void)fos;
1126  "No ML multiplication available. This feature is currently not supported by Xpetra.");
1127  TEUCHOS_UNREACHABLE_RETURN(Teuchos::null);
1128 #endif
1129  }
1130 #endif //ifdef HAVE_XPETRA_EPETRAEXT
1131 
1143  const BlockedCrsMatrix& B, bool transposeB,
1144  Teuchos::FancyOStream& fos,
1145  bool doFillComplete = true,
1146  bool doOptimizeStorage = true) {
1147  TEUCHOS_TEST_FOR_EXCEPTION(transposeA || transposeB, Exceptions::RuntimeError,
1148  "TwoMatrixMultiply for BlockedCrsMatrix not implemented for transposeA==true or transposeB==true");
1149 
1150  // Preconditions
1151  TEUCHOS_TEST_FOR_EXCEPTION(!A.isFillComplete(), Exceptions::RuntimeError, "A is not fill-completed");
1152  TEUCHOS_TEST_FOR_EXCEPTION(!B.isFillComplete(), Exceptions::RuntimeError, "B is not fill-completed");
1153 
1154  RCP<const MapExtractor> rgmapextractor = A.getRangeMapExtractor();
1155  RCP<const MapExtractor> domapextractor = B.getDomainMapExtractor();
1156 
1157  RCP<BlockedCrsMatrix> C = rcp(new BlockedCrsMatrix(rgmapextractor, domapextractor, 33 /* TODO fix me */));
1158 
1159  for (size_t i = 0; i < A.Rows(); ++i) { // loop over all block rows of A
1160  for (size_t j = 0; j < B.Cols(); ++j) { // loop over all block columns of B
1161  RCP<Matrix> Cij;
1162 
1163  for (size_t l = 0; l < B.Rows(); ++l) { // loop for calculating entry C_{ij}
1164  RCP<Matrix> crmat1 = A.getMatrix(i,l);
1165  RCP<Matrix> crmat2 = B.getMatrix(l,j);
1166 
1167  if (crmat1.is_null() || crmat2.is_null())
1168  continue;
1169 
1170  RCP<CrsMatrixWrap> crop1 = Teuchos::rcp_dynamic_cast<CrsMatrixWrap>(crmat1);
1171  RCP<CrsMatrixWrap> crop2 = Teuchos::rcp_dynamic_cast<CrsMatrixWrap>(crmat2);
1173  "A and B must be either both (compatible) BlockedCrsMatrix objects or both CrsMatrixWrap objects.");
1174 
1175  // Forcibly compute the global constants if we don't have them (only works for real CrsMatrices, not nested blocks)
1176  if (!crop1.is_null())
1177  Teuchos::rcp_const_cast<CrsGraph>(crmat1->getCrsGraph())->computeGlobalConstants();
1178  if (!crop2.is_null())
1179  Teuchos::rcp_const_cast<CrsGraph>(crmat2->getCrsGraph())->computeGlobalConstants();
1180 
1181  TEUCHOS_TEST_FOR_EXCEPTION(!crmat1->haveGlobalConstants(), Exceptions::RuntimeError,
1182  "crmat1 does not have global constants");
1183  TEUCHOS_TEST_FOR_EXCEPTION(!crmat2->haveGlobalConstants(), Exceptions::RuntimeError,
1184  "crmat2 does not have global constants");
1185 
1186  if (crmat1->getGlobalNumEntries() == 0 || crmat2->getGlobalNumEntries() == 0)
1187  continue;
1188 
1189 
1190  // temporary matrix containing result of local block multiplication
1191  RCP<Matrix> temp = Teuchos::null;
1192 
1193  if(crop1 != Teuchos::null && crop2 != Teuchos::null)
1194  temp = Multiply (*crop1, false, *crop2, false, fos);
1195  else {
1196  RCP<BlockedCrsMatrix> bop1 = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(crmat1);
1197  RCP<BlockedCrsMatrix> bop2 = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(crmat2);
1198  TEUCHOS_TEST_FOR_EXCEPTION(bop1.is_null()==true, Xpetra::Exceptions::BadCast, "A is not a BlockedCrsMatrix. (TwoMatrixMultiplyBlock)");
1199  TEUCHOS_TEST_FOR_EXCEPTION(bop2.is_null()==true, Xpetra::Exceptions::BadCast, "B is not a BlockedCrsMatrix. (TwoMatrixMultiplyBlock)");
1200  TEUCHOS_TEST_FOR_EXCEPTION(bop1->Cols()!=bop2->Rows(), Xpetra::Exceptions::RuntimeError, "A has " << bop1->Cols() << " columns and B has " << bop2->Rows() << " rows. Matrices are not compatible! (TwoMatrixMultiplyBlock)");
1201  TEUCHOS_TEST_FOR_EXCEPTION(bop1->getDomainMap()->isSameAs(*(bop2->getRangeMap()))==false, Xpetra::Exceptions::RuntimeError, "Domain map of A is not the same as range map of B. Matrices are not compatible! (TwoMatrixMultiplyBlock)");
1202 
1203  // recursive multiplication call
1204  temp = TwoMatrixMultiplyBlock(*bop1, transposeA, *bop2, transposeB, fos, doFillComplete, doOptimizeStorage);
1205 
1206  RCP<BlockedCrsMatrix> btemp = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(temp);
1207  TEUCHOS_TEST_FOR_EXCEPTION(btemp->Rows()!=bop1->Rows(), Xpetra::Exceptions::RuntimeError, "Number of block rows of local blocked operator is " << btemp->Rows() << " but should be " << bop1->Rows() << ". (TwoMatrixMultiplyBlock)");
1208  TEUCHOS_TEST_FOR_EXCEPTION(btemp->Cols()!=bop2->Cols(), Xpetra::Exceptions::RuntimeError, "Number of block cols of local blocked operator is " << btemp->Cols() << " but should be " << bop2->Cols() << ". (TwoMatrixMultiplyBlock)");
1209  TEUCHOS_TEST_FOR_EXCEPTION(btemp->getRangeMapExtractor()->getFullMap()->isSameAs(*(bop1->getRangeMapExtractor()->getFullMap())) == false, Xpetra::Exceptions::RuntimeError, "Range map of local blocked operator should be same as first operator. (TwoMatrixMultiplyBlock)");
1210  TEUCHOS_TEST_FOR_EXCEPTION(btemp->getDomainMapExtractor()->getFullMap()->isSameAs(*(bop2->getDomainMapExtractor()->getFullMap())) == false, Xpetra::Exceptions::RuntimeError, "Domain map of local blocked operator should be same as second operator. (TwoMatrixMultiplyBlock)");
1211  TEUCHOS_TEST_FOR_EXCEPTION(btemp->getRangeMapExtractor()->getThyraMode() != bop1->getRangeMapExtractor()->getThyraMode(), Xpetra::Exceptions::RuntimeError, "Thyra mode of local range map extractor incompatible with range map extractor of A (TwoMatrixMultiplyBlock)");
1212  TEUCHOS_TEST_FOR_EXCEPTION(btemp->getDomainMapExtractor()->getThyraMode() != bop2->getDomainMapExtractor()->getThyraMode(), Xpetra::Exceptions::RuntimeError, "Thyra mode of local domain map extractor incompatible with domain map extractor of B (TwoMatrixMultiplyBlock)");
1213  }
1214 
1215  TEUCHOS_TEST_FOR_EXCEPTION(temp->isFillComplete() == false, Xpetra::Exceptions::RuntimeError, "Local block is not filled. (TwoMatrixMultiplyBlock)");
1216 
1217  RCP<Matrix> addRes = null;
1218  if (Cij.is_null ())
1219  Cij = temp;
1220  else {
1221  MatrixMatrix::TwoMatrixAdd (*temp, false, 1.0, *Cij, false, 1.0, addRes, fos);
1222  Cij = addRes;
1223  }
1224  }
1225 
1226  if (!Cij.is_null()) {
1227  if (Cij->isFillComplete())
1228  Cij->resumeFill();
1229  Cij->fillComplete(B.getDomainMap(j), A.getRangeMap(i));
1230  C->setMatrix(i, j, Cij);
1231  } else {
1232  C->setMatrix(i, j, Teuchos::null);
1233  }
1234  }
1235  }
1236 
1237  if (doFillComplete)
1238  C->fillComplete(); // call default fillComplete for BlockCrsMatrixWrap objects
1239 
1240  return C;
1241  } // TwoMatrixMultiplyBlock
1242 
1255  static void TwoMatrixAdd(const Matrix& A, bool transposeA, SC alpha, Matrix& B, SC beta) {
1257  "TwoMatrixAdd: matrix row maps are not the same.");
1258 
1259  if (A.getRowMap()->lib() == Xpetra::UseEpetra) {
1260 #if defined(HAVE_XPETRA_EPETRA) && defined(HAVE_XPETRA_EPETRAEXT)
1263 
1264  //FIXME is there a bug if beta=0?
1265  int rv = EpetraExt::MatrixMatrix::Add(epA, transposeA, alpha, epB, beta);
1266 
1267  if (rv != 0)
1268  throw Exceptions::RuntimeError("EpetraExt::MatrixMatrix::Add return value " + Teuchos::toString(rv));
1269  std::ostringstream buf;
1270 #else
1271  throw Exceptions::RuntimeError("Xpetra must be compiled with EpetraExt.");
1272 #endif
1273  } else if (A.getRowMap()->lib() == Xpetra::UseTpetra) {
1274 #ifdef HAVE_XPETRA_TPETRA
1275 # if ((defined(EPETRA_HAVE_OMP) && (!defined(HAVE_TPETRA_INST_OPENMP) || !defined(HAVE_TPETRA_INST_INT_INT))) || \
1276  (!defined(EPETRA_HAVE_OMP) && (!defined(HAVE_TPETRA_INST_SERIAL) || !defined(HAVE_TPETRA_INST_INT_INT))))
1277  throw(Xpetra::Exceptions::RuntimeError("Xpetra must be compiled with Tpetra GO=int enabled."));
1278 # else
1279  const Tpetra::CrsMatrix<SC,LO,GO,NO>& tpA = Xpetra::Helpers<SC,LO,GO,NO>::Op2TpetraCrs(A);
1280  Tpetra::CrsMatrix<SC,LO,GO,NO>& tpB = Xpetra::Helpers<SC,LO,GO,NO>::Op2NonConstTpetraCrs(B);
1281 
1282  Tpetra::MatrixMatrix::Add(tpA, transposeA, alpha, tpB, beta);
1283 # endif
1284 #else
1285  throw Exceptions::RuntimeError("Xpetra must be compiled with Tpetra.");
1286 #endif
1287  }
1288  } //MatrixMatrix::TwoMatrixAdd()
1289 
1290 
1303  static void TwoMatrixAdd(const Matrix& A, bool transposeA, const SC& alpha,
1304  const Matrix& B, bool transposeB, const SC& beta,
1305  RCP<Matrix>& C, Teuchos::FancyOStream &fos, bool AHasFixedNnzPerRow = false) {
1306  RCP<const Matrix> rcpA = Teuchos::rcpFromRef(A);
1307  RCP<const Matrix> rcpB = Teuchos::rcpFromRef(B);
1308  RCP<const BlockedCrsMatrix> rcpBopA = Teuchos::rcp_dynamic_cast<const BlockedCrsMatrix>(rcpA);
1309  RCP<const BlockedCrsMatrix> rcpBopB = Teuchos::rcp_dynamic_cast<const BlockedCrsMatrix>(rcpB);
1310 
1311  if(rcpBopA == Teuchos::null && rcpBopB == Teuchos::null) {
1312 
1313 
1314  if (!(A.getRowMap()->isSameAs(*(B.getRowMap()))))
1315  throw Exceptions::Incompatible("TwoMatrixAdd: matrix row maps are not the same.");
1316 
1317  if (C == Teuchos::null) {
1318  size_t maxNzInA = 0;
1319  size_t maxNzInB = 0;
1320  size_t numLocalRows = 0;
1321  if (A.isFillComplete() && B.isFillComplete()) {
1322 
1323  maxNzInA = A.getNodeMaxNumRowEntries();
1324  maxNzInB = B.getNodeMaxNumRowEntries();
1325  numLocalRows = A.getNodeNumRows();
1326  }
1327 
1328  if (maxNzInA == 1 || maxNzInB == 1 || AHasFixedNnzPerRow) {
1329  // first check if either A or B has at most 1 nonzero per row
1330  // the case of both having at most 1 nz per row is handled by the ``else''
1331  Teuchos::ArrayRCP<size_t> exactNnzPerRow(numLocalRows);
1332 
1333  if ((maxNzInA == 1 && maxNzInB > 1) || AHasFixedNnzPerRow) {
1334  for (size_t i = 0; i < numLocalRows; ++i)
1335  exactNnzPerRow[i] = B.getNumEntriesInLocalRow(Teuchos::as<LO>(i)) + maxNzInA;
1336 
1337  } else {
1338  for (size_t i = 0; i < numLocalRows; ++i)
1339  exactNnzPerRow[i] = A.getNumEntriesInLocalRow(Teuchos::as<LO>(i)) + maxNzInB;
1340  }
1341 
1342  fos << "MatrixMatrix::TwoMatrixAdd : special case detected (one matrix has a fixed nnz per row)"
1343  << ", using static profiling" << std::endl;
1345 
1346  } else {
1347  // general case
1348  double nnzPerRowInA = Teuchos::as<double>(A.getNodeNumEntries()) / A.getNodeNumRows();
1349  double nnzPerRowInB = Teuchos::as<double>(B.getNodeNumEntries()) / B.getNodeNumRows();
1350  LO nnzToAllocate = Teuchos::as<LO>( (nnzPerRowInA + nnzPerRowInB) * 1.5) + Teuchos::as<LO>(1);
1351 
1352  LO maxPossible = A.getNodeMaxNumRowEntries() + B.getNodeMaxNumRowEntries();
1353  //Use static profiling (more efficient) if the estimate is at least as big as the max
1354  //possible nnz's in any single row of the result.
1355  Xpetra::ProfileType pft = (maxPossible) > nnzToAllocate ? Xpetra::DynamicProfile : Xpetra::StaticProfile;
1356 
1357  fos << "nnzPerRowInA = " << nnzPerRowInA << ", nnzPerRowInB = " << nnzPerRowInB << std::endl;
1358  fos << "MatrixMatrix::TwoMatrixAdd : space allocated per row = " << nnzToAllocate
1359  << ", max possible nnz per row in sum = " << maxPossible
1360  << ", using " << (pft == Xpetra::DynamicProfile ? "dynamic" : "static" ) << " profiling"
1361  << std::endl;
1362  C = rcp(new Xpetra::CrsMatrixWrap<SC,LO,GO,NO>(A.getRowMap(), nnzToAllocate, pft));
1363  }
1364  if (transposeB)
1365  fos << "MatrixMatrix::TwoMatrixAdd : ** WARNING ** estimate could be badly wrong because second summand is transposed" << std::endl;
1366  }
1367 
1368  if (C->getRowMap()->lib() == Xpetra::UseEpetra) {
1369  #if defined(HAVE_XPETRA_EPETRA) && defined(HAVE_XPETRA_EPETRAEXT)
1373  Epetra_CrsMatrix* ref2epC = &*epC; //to avoid a compiler error...
1374 
1375  //FIXME is there a bug if beta=0?
1376  int rv = EpetraExt::MatrixMatrix::Add(epA, transposeA, alpha, epB, transposeB, beta, ref2epC);
1377 
1378  if (rv != 0)
1379  throw Exceptions::RuntimeError("EpetraExt::MatrixMatrix::Add return value of " + Teuchos::toString(rv));
1380  #else
1381  throw Exceptions::RuntimeError("MueLu must be compile with EpetraExt.");
1382  #endif
1383  } else if (C->getRowMap()->lib() == Xpetra::UseTpetra) {
1384  #ifdef HAVE_XPETRA_TPETRA
1385  # if ((defined(EPETRA_HAVE_OMP) && (!defined(HAVE_TPETRA_INST_OPENMP) || !defined(HAVE_TPETRA_INST_INT_INT))) || \
1386  (!defined(EPETRA_HAVE_OMP) && (!defined(HAVE_TPETRA_INST_SERIAL) || !defined(HAVE_TPETRA_INST_INT_INT))))
1387  throw(Xpetra::Exceptions::RuntimeError("Xpetra must be compiled with Tpetra GO=int enabled."));
1388  # else
1389  const Tpetra::CrsMatrix<SC,LO,GO,NO>& tpA = Xpetra::Helpers<SC,LO,GO,NO>::Op2TpetraCrs(A);
1390  const Tpetra::CrsMatrix<SC,LO,GO,NO>& tpB = Xpetra::Helpers<SC,LO,GO,NO>::Op2TpetraCrs(B);
1392 
1393  Tpetra::MatrixMatrix::Add(tpA, transposeA, alpha, tpB, transposeB, beta, tpC);
1394  # endif
1395  #else
1396  throw Exceptions::RuntimeError("Xpetra must be compile with Tpetra.");
1397  #endif
1398  }
1399 
1401  if (A.IsView("stridedMaps")) C->CreateView("stridedMaps", rcpFromRef(A));
1402  if (B.IsView("stridedMaps")) C->CreateView("stridedMaps", rcpFromRef(B));
1404  }
1405  // the first matrix is of type CrsMatrixWrap, the second is a blocked operator
1406  else if(rcpBopA == Teuchos::null && rcpBopB != Teuchos::null) {
1407  RCP<const MapExtractor> rgmapextractor = rcpBopB->getRangeMapExtractor();
1408  RCP<const MapExtractor> domapextractor = rcpBopB->getDomainMapExtractor();
1409 
1410  C = rcp(new BlockedCrsMatrix(rgmapextractor, domapextractor, 33 /* TODO fix me */));
1411  RCP<BlockedCrsMatrix> bC = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(C);
1412 
1413  size_t i = 0;
1414  for (size_t j = 0; j < rcpBopB->Cols(); ++j) { // loop over all block columns of B
1415  RCP<Matrix> Cij = Teuchos::null;
1416  if(rcpA != Teuchos::null &&
1417  rcpBopB->getMatrix(i,j)!=Teuchos::null) {
1418  // recursive call
1419  TwoMatrixAdd(*rcpA, transposeA, alpha,
1420  *(rcpBopB->getMatrix(i,j)), transposeB, beta,
1421  Cij, fos, AHasFixedNnzPerRow);
1422  } else if (rcpA == Teuchos::null &&
1423  rcpBopB->getMatrix(i,j)!=Teuchos::null) {
1424  Cij = rcpBopB->getMatrix(i,j);
1425  } else if (rcpA != Teuchos::null &&
1426  rcpBopB->getMatrix(i,j)==Teuchos::null) {
1427  Cij = Teuchos::rcp_const_cast<Matrix>(rcpA);
1428  } else {
1429  Cij = Teuchos::null;
1430  }
1431 
1432  if (!Cij.is_null()) {
1433  if (Cij->isFillComplete())
1434  Cij->resumeFill();
1435  Cij->fillComplete();
1436  bC->setMatrix(i, j, Cij);
1437  } else {
1438  bC->setMatrix(i, j, Teuchos::null);
1439  }
1440  } // loop over columns j
1441  }
1442  // the second matrix is of type CrsMatrixWrap, the first is a blocked operator
1443  else if(rcpBopA != Teuchos::null && rcpBopB == Teuchos::null) {
1444  RCP<const MapExtractor> rgmapextractor = rcpBopA->getRangeMapExtractor();
1445  RCP<const MapExtractor> domapextractor = rcpBopA->getDomainMapExtractor();
1446 
1447  C = rcp(new BlockedCrsMatrix(rgmapextractor, domapextractor, 33 /* TODO fix me */));
1448  RCP<BlockedCrsMatrix> bC = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(C);
1449 
1450  size_t j = 0;
1451  for (size_t i = 0; i < rcpBopA->Rows(); ++i) { // loop over all block rows of A
1452  RCP<Matrix> Cij = Teuchos::null;
1453  if(rcpBopA->getMatrix(i,j)!=Teuchos::null &&
1454  rcpB!=Teuchos::null) {
1455  // recursive call
1456  TwoMatrixAdd(*(rcpBopA->getMatrix(i,j)), transposeA, alpha,
1457  *rcpB, transposeB, beta,
1458  Cij, fos, AHasFixedNnzPerRow);
1459  } else if (rcpBopA->getMatrix(i,j) == Teuchos::null &&
1460  rcpB!=Teuchos::null) {
1461  Cij = Teuchos::rcp_const_cast<Matrix>(rcpB);
1462  } else if (rcpBopA->getMatrix(i,j) != Teuchos::null &&
1463  rcpB==Teuchos::null) {
1464  Cij = rcpBopA->getMatrix(i,j);
1465  } else {
1466  Cij = Teuchos::null;
1467  }
1468 
1469  if (!Cij.is_null()) {
1470  if (Cij->isFillComplete())
1471  Cij->resumeFill();
1472  Cij->fillComplete();
1473  bC->setMatrix(i, j, Cij);
1474  } else {
1475  bC->setMatrix(i, j, Teuchos::null);
1476  }
1477  } // loop over rows i
1478  }
1479  else {
1480  // This is the version for blocked matrices
1481 
1482  // check the compatibility of the blocked operators
1483  TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA.is_null()==true, Xpetra::Exceptions::BadCast, "A is not a BlockedCrsMatrix. (TwoMatrixAdd)");
1484  TEUCHOS_TEST_FOR_EXCEPTION(rcpBopB.is_null()==true, Xpetra::Exceptions::BadCast, "B is not a BlockedCrsMatrix. (TwoMatrixAdd)");
1485  TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA->Rows()!=rcpBopB->Rows(), Xpetra::Exceptions::RuntimeError, "A has " << rcpBopA->Rows() << " rows and B has " << rcpBopA->Rows() << " rows. Matrices are not compatible! (TwoMatrixAdd)");
1486  TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA->Rows()!=rcpBopB->Rows(), Xpetra::Exceptions::RuntimeError, "A has " << rcpBopA->Cols() << " cols and B has " << rcpBopA->Cols() << " cols. Matrices are not compatible! (TwoMatrixAdd)");
1487  TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA->getRangeMap()->isSameAs(*(rcpBopB->getRangeMap()))==false, Xpetra::Exceptions::RuntimeError, "Range map of A is not the same as range map of B. Matrices are not compatible! (TwoMatrixAdd)");
1488  TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA->getDomainMap()->isSameAs(*(rcpBopB->getDomainMap()))==false, Xpetra::Exceptions::RuntimeError, "Domain map of A is not the same as domain map of B. Matrices are not compatible! (TwoMatrixAdd)");
1489  TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA->getRangeMapExtractor()->getThyraMode() != rcpBopB->getRangeMapExtractor()->getThyraMode(), Xpetra::Exceptions::RuntimeError, "Different Thyra/Xpetra style gids in RangeMapExtractor of A and B. Matrices are not compatible! (TwoMatrixAdd)");
1490  TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA->getDomainMapExtractor()->getThyraMode() != rcpBopB->getDomainMapExtractor()->getThyraMode(), Xpetra::Exceptions::RuntimeError, "Different Thyra/Xpetra style gids in DomainMapExtractor of A and B. Matrices are not compatible! (TwoMatrixAdd)");
1491 
1492  RCP<const MapExtractor> rgmapextractor = rcpBopA->getRangeMapExtractor();
1493  RCP<const MapExtractor> domapextractor = rcpBopB->getDomainMapExtractor();
1494 
1495  C = rcp(new BlockedCrsMatrix(rgmapextractor, domapextractor, 33 /* TODO fix me */));
1496  RCP<BlockedCrsMatrix> bC = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(C);
1497 
1498  for (size_t i = 0; i < rcpBopA->Rows(); ++i) { // loop over all block rows of A
1499  for (size_t j = 0; j < rcpBopB->Cols(); ++j) { // loop over all block columns of B
1500 
1501  RCP<Matrix> Cij = Teuchos::null;
1502  if(rcpBopA->getMatrix(i,j)!=Teuchos::null &&
1503  rcpBopB->getMatrix(i,j)!=Teuchos::null) {
1504  // recursive call
1505 
1506  TwoMatrixAdd(*(rcpBopA->getMatrix(i,j)), transposeA, alpha,
1507  *(rcpBopB->getMatrix(i,j)), transposeB, beta,
1508  Cij, fos, AHasFixedNnzPerRow);
1509  } else if (rcpBopA->getMatrix(i,j) == Teuchos::null &&
1510  rcpBopB->getMatrix(i,j)!=Teuchos::null) {
1511  Cij = rcpBopB->getMatrix(i,j);
1512  } else if (rcpBopA->getMatrix(i,j) != Teuchos::null &&
1513  rcpBopB->getMatrix(i,j)==Teuchos::null) {
1514  Cij = rcpBopA->getMatrix(i,j);
1515  } else {
1516  Cij = Teuchos::null;
1517  }
1518 
1519  if (!Cij.is_null()) {
1520  if (Cij->isFillComplete())
1521  Cij->resumeFill();
1522  //Cij->fillComplete(rcpBopA->getDomainMap(j), rcpBopA->getRangeMap(i));
1523  Cij->fillComplete();
1524  bC->setMatrix(i, j, Cij);
1525  } else {
1526  bC->setMatrix(i, j, Teuchos::null);
1527  }
1528  } // loop over columns j
1529  } // loop over rows i
1530 
1531  } // end blocked recursive algorithm
1532  } //MatrixMatrix::TwoMatrixAdd()
1533  }; // end specialization on SC=double, GO=int and NO=EpetraNode
1534 
1535  // specialization MatrixMatrix for SC=double, GO=long long and NO=EptraNode
1536  template<>
1537  class MatrixMatrix<double,int,long long,EpetraNode> {
1538  typedef double Scalar;
1539  typedef int LocalOrdinal;
1540  typedef long long GlobalOrdinal;
1541  typedef EpetraNode Node;
1542 #include "Xpetra_UseShortNames.hpp"
1543 
1544  public:
1545 
1570  static void Multiply(const Matrix& A, bool transposeA,
1571  const Matrix& B, bool transposeB,
1572  Matrix& C,
1573  bool call_FillComplete_on_result = true,
1574  bool doOptimizeStorage = true,
1575  const std::string & label = std::string(),
1576  const RCP<ParameterList>& params = null) {
1577  TEUCHOS_TEST_FOR_EXCEPTION(transposeA == false && C.getRowMap()->isSameAs(*A.getRowMap()) == false,
1578  Xpetra::Exceptions::RuntimeError, "XpetraExt::MatrixMatrix::Multiply: row map of C is not same as row map of A");
1579  TEUCHOS_TEST_FOR_EXCEPTION(transposeA == true && C.getRowMap()->isSameAs(*A.getDomainMap()) == false,
1580  Xpetra::Exceptions::RuntimeError, "XpetraExt::MatrixMatrix::Multiply: row map of C is not same as domain map of A");
1581 
1582 
1585 
1586  bool haveMultiplyDoFillComplete = call_FillComplete_on_result && doOptimizeStorage;
1587 
1588  if (C.getRowMap()->lib() == Xpetra::UseEpetra) {
1589 #if defined(HAVE_XPETRA_EPETRA) && defined(HAVE_XPETRA_EPETRAEXT)
1593 
1594  int i = EpetraExt::MatrixMatrix::Multiply(epA, transposeA, epB, transposeB, epC, haveMultiplyDoFillComplete);
1595  if (haveMultiplyDoFillComplete) {
1596  // Due to Epetra wrapper intricacies, we need to explicitly call
1597  // fillComplete on Xpetra matrix here. Specifically, EpetraCrsMatrix
1598  // only keeps an internal variable to check whether we are in resumed
1599  // state or not, but never touches the underlying Epetra object. As
1600  // such, we need to explicitly update the state of Xpetra matrix to
1601  // that of Epetra one afterwords
1602  C.fillComplete();
1603  }
1604 
1605  if (i != 0) {
1606  std::ostringstream buf;
1607  buf << i;
1608  std::string msg = "EpetraExt::MatrixMatrix::Multiply return value of " + buf.str();
1609  throw(Exceptions::RuntimeError(msg));
1610  }
1611 
1612 #else
1613  throw(Xpetra::Exceptions::RuntimeError("Xpetra::MatrixMatrix::Multiply requires EpetraExt to be compiled."));
1614 #endif
1615  } else if (C.getRowMap()->lib() == Xpetra::UseTpetra) {
1616 #ifdef HAVE_XPETRA_TPETRA
1617 # if ((defined(EPETRA_HAVE_OMP) && (!defined(HAVE_TPETRA_INST_OPENMP) || !defined(HAVE_TPETRA_INST_INT_LONG_LONG))) || \
1618  (!defined(EPETRA_HAVE_OMP) && (!defined(HAVE_TPETRA_INST_SERIAL) || !defined(HAVE_TPETRA_INST_INT_LONG_LONG))))
1619  throw(Xpetra::Exceptions::RuntimeError("Xpetra must be compiled with Tpetra <double,int,long long, EpetraNode> ETI enabled."));
1620 # else
1621  const Tpetra::CrsMatrix<SC,LO,GO,NO> & tpA = Xpetra::Helpers<SC,LO,GO,NO>::Op2TpetraCrs(A);
1622  const Tpetra::CrsMatrix<SC,LO,GO,NO> & tpB = Xpetra::Helpers<SC,LO,GO,NO>::Op2TpetraCrs(B);
1623  Tpetra::CrsMatrix<SC,LO,GO,NO> & tpC = Xpetra::Helpers<SC,LO,GO,NO>::Op2NonConstTpetraCrs(C);
1624 
1625  //18Feb2013 JJH I'm reenabling the code that allows the matrix matrix multiply to do the fillComplete.
1626  //Previously, Tpetra's matrix matrix multiply did not support fillComplete.
1627  Tpetra::MatrixMatrix::Multiply(tpA, transposeA, tpB, transposeB, tpC, haveMultiplyDoFillComplete, label, params);
1628 # endif
1629 #else
1630  throw(Xpetra::Exceptions::RuntimeError("Xpetra must be compiled with Tpetra."));
1631 #endif
1632  }
1633 
1634  if(call_FillComplete_on_result && !haveMultiplyDoFillComplete) {
1636  fillParams->set("Optimize Storage",doOptimizeStorage);
1637  C.fillComplete((transposeB) ? B.getRangeMap() : B.getDomainMap(),
1638  (transposeA) ? A.getDomainMap() : A.getRangeMap(),
1639  fillParams);
1640  }
1641 
1642  // transfer striding information
1643  RCP<Matrix> rcpA = Teuchos::rcp_const_cast<Matrix>(Teuchos::rcpFromRef(A));
1644  RCP<Matrix> rcpB = Teuchos::rcp_const_cast<Matrix>(Teuchos::rcpFromRef(B));
1645  C.CreateView("stridedMaps", rcpA, transposeA, rcpB, transposeB); // TODO use references instead of RCPs
1646  } // end Multiply
1647 
1670  static RCP<Matrix> Multiply(const Matrix& A, bool transposeA,
1671  const Matrix& B, bool transposeB,
1672  RCP<Matrix> C_in,
1673  Teuchos::FancyOStream& fos,
1674  bool doFillComplete = true,
1675  bool doOptimizeStorage = true,
1676  const std::string & label = std::string(),
1677  const RCP<ParameterList>& params = null) {
1678 
1679  TEUCHOS_TEST_FOR_EXCEPTION(!A.isFillComplete(), Exceptions::RuntimeError, "A is not fill-completed");
1680  TEUCHOS_TEST_FOR_EXCEPTION(!B.isFillComplete(), Exceptions::RuntimeError, "B is not fill-completed");
1681 
1682  // Default case: Xpetra Multiply
1683  RCP<Matrix> C = C_in;
1684 
1685  if (C == Teuchos::null) {
1686  double nnzPerRow = Teuchos::as<double>(0);
1687 
1688 #if 0
1689  if (A.getDomainMap()->lib() == Xpetra::UseTpetra) {
1690  // For now, follow what ML and Epetra do.
1691  GO numRowsA = A.getGlobalNumRows();
1692  GO numRowsB = B.getGlobalNumRows();
1693  nnzPerRow = sqrt(Teuchos::as<double>(A.getGlobalNumEntries())/numRowsA) +
1694  sqrt(Teuchos::as<double>(B.getGlobalNumEntries())/numRowsB) - 1;
1695  nnzPerRow *= nnzPerRow;
1696  double totalNnz = nnzPerRow * A.getGlobalNumRows() * 0.75 + 100;
1697  double minNnz = Teuchos::as<double>(1.2 * A.getGlobalNumEntries());
1698  if (totalNnz < minNnz)
1699  totalNnz = minNnz;
1700  nnzPerRow = totalNnz / A.getGlobalNumRows();
1701 
1702  fos << "Matrix product nnz per row estimate = " << Teuchos::as<LO>(nnzPerRow) << std::endl;
1703  }
1704 #endif
1705  if (transposeA) C = MatrixFactory::Build(A.getDomainMap(), Teuchos::as<LO>(nnzPerRow));
1706  else C = MatrixFactory::Build(A.getRowMap(), Teuchos::as<LO>(nnzPerRow));
1707 
1708  } else {
1709  C->resumeFill(); // why this is not done inside of Tpetra MxM?
1710  fos << "Reuse C pattern" << std::endl;
1711  }
1712 
1713  Multiply(A, transposeA, B, transposeB, *C, doFillComplete, doOptimizeStorage, label, params); // call Multiply routine from above
1714 
1715  return C;
1716  }
1717 
1728  static RCP<Matrix> Multiply(const Matrix& A, bool transposeA,
1729  const Matrix& B, bool transposeB,
1730  Teuchos::FancyOStream &fos,
1731  bool callFillCompleteOnResult = true,
1732  bool doOptimizeStorage = true,
1733  const std::string & label = std::string(),
1734  const RCP<ParameterList>& params = null) {
1735  return Multiply(A, transposeA, B, transposeB, Teuchos::null, fos, callFillCompleteOnResult, doOptimizeStorage, label, params);
1736  }
1737 
1738 #if defined(HAVE_XPETRA_EPETRA) && defined(HAVE_XPETRA_EPETRAEXT)
1739  // Michael Gee's MLMultiply
1741  const Epetra_CrsMatrix& /* epB */,
1742  Teuchos::FancyOStream& /* fos */) {
1744  "No ML multiplication available. This feature is currently not supported by Xpetra.");
1745  TEUCHOS_UNREACHABLE_RETURN(Teuchos::null);
1746  }
1747 #endif //ifdef HAVE_XPETRA_EPETRAEXT
1748 
1760  const BlockedCrsMatrix& B, bool transposeB,
1761  Teuchos::FancyOStream& fos,
1762  bool doFillComplete = true,
1763  bool doOptimizeStorage = true) {
1764  TEUCHOS_TEST_FOR_EXCEPTION(transposeA || transposeB, Exceptions::RuntimeError,
1765  "TwoMatrixMultiply for BlockedCrsMatrix not implemented for transposeA==true or transposeB==true");
1766 
1767  // Preconditions
1768  TEUCHOS_TEST_FOR_EXCEPTION(!A.isFillComplete(), Exceptions::RuntimeError, "A is not fill-completed");
1769  TEUCHOS_TEST_FOR_EXCEPTION(!B.isFillComplete(), Exceptions::RuntimeError, "B is not fill-completed");
1770 
1771  RCP<const MapExtractor> rgmapextractor = A.getRangeMapExtractor();
1772  RCP<const MapExtractor> domapextractor = B.getDomainMapExtractor();
1773 
1774  RCP<BlockedCrsMatrix> C = rcp(new BlockedCrsMatrix(rgmapextractor, domapextractor, 33 /* TODO fix me */));
1775 
1776  for (size_t i = 0; i < A.Rows(); ++i) { // loop over all block rows of A
1777  for (size_t j = 0; j < B.Cols(); ++j) { // loop over all block columns of B
1778  RCP<Matrix> Cij;
1779 
1780  for (size_t l = 0; l < B.Rows(); ++l) { // loop for calculating entry C_{ij}
1781  RCP<Matrix> crmat1 = A.getMatrix(i,l);
1782  RCP<Matrix> crmat2 = B.getMatrix(l,j);
1783 
1784  if (crmat1.is_null() || crmat2.is_null())
1785  continue;
1786 
1787  RCP<CrsMatrixWrap> crop1 = Teuchos::rcp_dynamic_cast<CrsMatrixWrap>(crmat1);
1788  RCP<CrsMatrixWrap> crop2 = Teuchos::rcp_dynamic_cast<CrsMatrixWrap>(crmat2);
1790  "A and B must be either both (compatible) BlockedCrsMatrix objects or both CrsMatrixWrap objects.");
1791 
1792  // Forcibly compute the global constants if we don't have them (only works for real CrsMatrices, not nested blocks)
1793  if (!crop1.is_null())
1794  Teuchos::rcp_const_cast<CrsGraph>(crmat1->getCrsGraph())->computeGlobalConstants();
1795  if (!crop2.is_null())
1796  Teuchos::rcp_const_cast<CrsGraph>(crmat2->getCrsGraph())->computeGlobalConstants();
1797 
1798  TEUCHOS_TEST_FOR_EXCEPTION(!crmat1->haveGlobalConstants(), Exceptions::RuntimeError,
1799  "crmat1 does not have global constants");
1800  TEUCHOS_TEST_FOR_EXCEPTION(!crmat2->haveGlobalConstants(), Exceptions::RuntimeError,
1801  "crmat2 does not have global constants");
1802 
1803  if (crmat1->getGlobalNumEntries() == 0 || crmat2->getGlobalNumEntries() == 0)
1804  continue;
1805 
1806  // temporary matrix containing result of local block multiplication
1807  RCP<Matrix> temp = Teuchos::null;
1808 
1809  if(crop1 != Teuchos::null && crop2 != Teuchos::null)
1810  temp = Multiply (*crop1, false, *crop2, false, fos);
1811  else {
1812  RCP<BlockedCrsMatrix> bop1 = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(crmat1);
1813  RCP<BlockedCrsMatrix> bop2 = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(crmat2);
1814  TEUCHOS_TEST_FOR_EXCEPTION(bop1.is_null()==true, Xpetra::Exceptions::BadCast, "A is not a BlockedCrsMatrix. (TwoMatrixMultiplyBlock)");
1815  TEUCHOS_TEST_FOR_EXCEPTION(bop2.is_null()==true, Xpetra::Exceptions::BadCast, "B is not a BlockedCrsMatrix. (TwoMatrixMultiplyBlock)");
1816  TEUCHOS_TEST_FOR_EXCEPTION(bop1->Cols()!=bop2->Rows(), Xpetra::Exceptions::RuntimeError, "A has " << bop1->Cols() << " columns and B has " << bop2->Rows() << " rows. Matrices are not compatible! (TwoMatrixMultiplyBlock)");
1817  TEUCHOS_TEST_FOR_EXCEPTION(bop1->getDomainMap()->isSameAs(*(bop2->getRangeMap()))==false, Xpetra::Exceptions::RuntimeError, "Domain map of A is not the same as range map of B. Matrices are not compatible! (TwoMatrixMultiplyBlock)");
1818 
1819  // recursive multiplication call
1820  temp = TwoMatrixMultiplyBlock(*bop1, transposeA, *bop2, transposeB, fos, doFillComplete, doOptimizeStorage);
1821 
1822  RCP<BlockedCrsMatrix> btemp = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(temp);
1823  TEUCHOS_TEST_FOR_EXCEPTION(btemp->Rows()!=bop1->Rows(), Xpetra::Exceptions::RuntimeError, "Number of block rows of local blocked operator is " << btemp->Rows() << " but should be " << bop1->Rows() << ". (TwoMatrixMultiplyBlock)");
1824  TEUCHOS_TEST_FOR_EXCEPTION(btemp->Cols()!=bop2->Cols(), Xpetra::Exceptions::RuntimeError, "Number of block cols of local blocked operator is " << btemp->Cols() << " but should be " << bop2->Cols() << ". (TwoMatrixMultiplyBlock)");
1825  TEUCHOS_TEST_FOR_EXCEPTION(btemp->getRangeMapExtractor()->getFullMap()->isSameAs(*(bop1->getRangeMapExtractor()->getFullMap())) == false, Xpetra::Exceptions::RuntimeError, "Range map of local blocked operator should be same as first operator. (TwoMatrixMultiplyBlock)");
1826  TEUCHOS_TEST_FOR_EXCEPTION(btemp->getDomainMapExtractor()->getFullMap()->isSameAs(*(bop2->getDomainMapExtractor()->getFullMap())) == false, Xpetra::Exceptions::RuntimeError, "Domain map of local blocked operator should be same as second operator. (TwoMatrixMultiplyBlock)");
1827  TEUCHOS_TEST_FOR_EXCEPTION(btemp->getRangeMapExtractor()->getThyraMode() != bop1->getRangeMapExtractor()->getThyraMode(), Xpetra::Exceptions::RuntimeError, "Thyra mode of local range map extractor incompatible with range map extractor of A (TwoMatrixMultiplyBlock)");
1828  TEUCHOS_TEST_FOR_EXCEPTION(btemp->getDomainMapExtractor()->getThyraMode() != bop2->getDomainMapExtractor()->getThyraMode(), Xpetra::Exceptions::RuntimeError, "Thyra mode of local domain map extractor incompatible with domain map extractor of B (TwoMatrixMultiplyBlock)");
1829  }
1830 
1831  TEUCHOS_TEST_FOR_EXCEPTION(temp->isFillComplete() == false, Xpetra::Exceptions::RuntimeError, "Local block is not filled. (TwoMatrixMultiplyBlock)");
1832 
1833  RCP<Matrix> addRes = null;
1834  if (Cij.is_null ())
1835  Cij = temp;
1836  else {
1837  MatrixMatrix::TwoMatrixAdd (*temp, false, 1.0, *Cij, false, 1.0, addRes, fos);
1838  Cij = addRes;
1839  }
1840  }
1841 
1842  if (!Cij.is_null()) {
1843  if (Cij->isFillComplete())
1844  Cij->resumeFill();
1845  Cij->fillComplete(B.getDomainMap(j), A.getRangeMap(i));
1846  C->setMatrix(i, j, Cij);
1847  } else {
1848  C->setMatrix(i, j, Teuchos::null);
1849  }
1850  }
1851  }
1852 
1853  if (doFillComplete)
1854  C->fillComplete(); // call default fillComplete for BlockCrsMatrixWrap objects
1855 
1856  return C;
1857  } // TwoMatrixMultiplyBlock
1858 
1871  static void TwoMatrixAdd(const Matrix& A, bool transposeA, SC alpha, Matrix& B, SC beta) {
1873  "TwoMatrixAdd: matrix row maps are not the same.");
1874 
1875  if (A.getRowMap()->lib() == Xpetra::UseEpetra) {
1876 #if defined(HAVE_XPETRA_EPETRA) && defined(HAVE_XPETRA_EPETRAEXT)
1879 
1880  //FIXME is there a bug if beta=0?
1881  int rv = EpetraExt::MatrixMatrix::Add(epA, transposeA, alpha, epB, beta);
1882 
1883  if (rv != 0)
1884  throw Exceptions::RuntimeError("EpetraExt::MatrixMatrix::Add return value " + Teuchos::toString(rv));
1885  std::ostringstream buf;
1886 #else
1887  throw Exceptions::RuntimeError("Xpetra must be compiled with EpetraExt.");
1888 #endif
1889  } else if (A.getRowMap()->lib() == Xpetra::UseTpetra) {
1890 #ifdef HAVE_XPETRA_TPETRA
1891 # if ((defined(EPETRA_HAVE_OMP) && (!defined(HAVE_TPETRA_INST_OPENMP) || !defined(HAVE_TPETRA_INST_INT_LONG_LONG))) || \
1892  (!defined(EPETRA_HAVE_OMP) && (!defined(HAVE_TPETRA_INST_SERIAL) || !defined(HAVE_TPETRA_INST_INT_LONG_LONG))))
1893  throw(Xpetra::Exceptions::RuntimeError("Xpetra must be compiled with Tpetra GO=long long enabled."));
1894 # else
1895  const Tpetra::CrsMatrix<SC,LO,GO,NO>& tpA = Xpetra::Helpers<SC,LO,GO,NO>::Op2TpetraCrs(A);
1896  Tpetra::CrsMatrix<SC,LO,GO,NO>& tpB = Xpetra::Helpers<SC,LO,GO,NO>::Op2NonConstTpetraCrs(B);
1897 
1898  Tpetra::MatrixMatrix::Add(tpA, transposeA, alpha, tpB, beta);
1899 # endif
1900 #else
1901  throw Exceptions::RuntimeError("Xpetra must be compiled with Tpetra.");
1902 #endif
1903  }
1904  } //MatrixMatrix::TwoMatrixAdd()
1905 
1906 
1919  static void TwoMatrixAdd(const Matrix& A, bool transposeA, const SC& alpha,
1920  const Matrix& B, bool transposeB, const SC& beta,
1921  RCP<Matrix>& C, Teuchos::FancyOStream &fos, bool AHasFixedNnzPerRow = false) {
1922  RCP<const Matrix> rcpA = Teuchos::rcpFromRef(A);
1923  RCP<const Matrix> rcpB = Teuchos::rcpFromRef(B);
1924  RCP<const BlockedCrsMatrix> rcpBopA = Teuchos::rcp_dynamic_cast<const BlockedCrsMatrix>(rcpA);
1925  RCP<const BlockedCrsMatrix> rcpBopB = Teuchos::rcp_dynamic_cast<const BlockedCrsMatrix>(rcpB);
1926 
1927  if(rcpBopA == Teuchos::null && rcpBopB == Teuchos::null) {
1929  "TwoMatrixAdd: matrix row maps are not the same.");
1930 
1931  if (C == Teuchos::null) {
1932  size_t maxNzInA = 0;
1933  size_t maxNzInB = 0;
1934  size_t numLocalRows = 0;
1935  if (A.isFillComplete() && B.isFillComplete()) {
1936  maxNzInA = A.getNodeMaxNumRowEntries();
1937  maxNzInB = B.getNodeMaxNumRowEntries();
1938  numLocalRows = A.getNodeNumRows();
1939  }
1940 
1941  if (maxNzInA == 1 || maxNzInB == 1 || AHasFixedNnzPerRow) {
1942  // first check if either A or B has at most 1 nonzero per row
1943  // the case of both having at most 1 nz per row is handled by the ``else''
1944  Teuchos::ArrayRCP<size_t> exactNnzPerRow(numLocalRows);
1945 
1946  if ((maxNzInA == 1 && maxNzInB > 1) || AHasFixedNnzPerRow) {
1947  for (size_t i = 0; i < numLocalRows; ++i)
1948  exactNnzPerRow[i] = B.getNumEntriesInLocalRow(Teuchos::as<LO>(i)) + maxNzInA;
1949 
1950  } else {
1951  for (size_t i = 0; i < numLocalRows; ++i)
1952  exactNnzPerRow[i] = A.getNumEntriesInLocalRow(Teuchos::as<LO>(i)) + maxNzInB;
1953  }
1954 
1955  fos << "MatrixMatrix::TwoMatrixAdd : special case detected (one matrix has a fixed nnz per row)"
1956  << ", using static profiling" << std::endl;
1958 
1959  } else {
1960  // general case
1961  double nnzPerRowInA = Teuchos::as<double>(A.getNodeNumEntries()) / A.getNodeNumRows();
1962  double nnzPerRowInB = Teuchos::as<double>(B.getNodeNumEntries()) / B.getNodeNumRows();
1963  LO nnzToAllocate = Teuchos::as<LO>( (nnzPerRowInA + nnzPerRowInB) * 1.5) + Teuchos::as<LO>(1);
1964 
1965  LO maxPossible = A.getNodeMaxNumRowEntries() + B.getNodeMaxNumRowEntries();
1966  //Use static profiling (more efficient) if the estimate is at least as big as the max
1967  //possible nnz's in any single row of the result.
1968  Xpetra::ProfileType pft = (maxPossible) > nnzToAllocate ? Xpetra::DynamicProfile : Xpetra::StaticProfile;
1969 
1970  fos << "nnzPerRowInA = " << nnzPerRowInA << ", nnzPerRowInB = " << nnzPerRowInB << std::endl;
1971  fos << "MatrixMatrix::TwoMatrixAdd : space allocated per row = " << nnzToAllocate
1972  << ", max possible nnz per row in sum = " << maxPossible
1973  << ", using " << (pft == Xpetra::DynamicProfile ? "dynamic" : "static" ) << " profiling"
1974  << std::endl;
1975  C = rcp(new Xpetra::CrsMatrixWrap<SC,LO,GO,NO>(A.getRowMap(), nnzToAllocate, pft));
1976  }
1977  if (transposeB)
1978  fos << "MatrixMatrix::TwoMatrixAdd : ** WARNING ** estimate could be badly wrong because second summand is transposed" << std::endl;
1979  }
1980 
1981  if (C->getRowMap()->lib() == Xpetra::UseEpetra) {
1982  #if defined(HAVE_XPETRA_EPETRA) && defined(HAVE_XPETRA_EPETRAEXT)
1986  Epetra_CrsMatrix* ref2epC = &*epC; //to avoid a compiler error...
1987 
1988  //FIXME is there a bug if beta=0?
1989  int rv = EpetraExt::MatrixMatrix::Add(epA, transposeA, alpha, epB, transposeB, beta, ref2epC);
1990 
1991  if (rv != 0)
1992  throw Exceptions::RuntimeError("EpetraExt::MatrixMatrix::Add return value of " + Teuchos::toString(rv));
1993  #else
1994  throw Exceptions::RuntimeError("MueLu must be compile with EpetraExt.");
1995  #endif
1996  } else if (C->getRowMap()->lib() == Xpetra::UseTpetra) {
1997  #ifdef HAVE_XPETRA_TPETRA
1998  # if ((defined(EPETRA_HAVE_OMP) && (!defined(HAVE_TPETRA_INST_OPENMP) || !defined(HAVE_TPETRA_INST_INT_LONG_LONG))) || \
1999  (!defined(EPETRA_HAVE_OMP) && (!defined(HAVE_TPETRA_INST_SERIAL) || !defined(HAVE_TPETRA_INST_INT_LONG_LONG))))
2000  throw(Xpetra::Exceptions::RuntimeError("Xpetra must be compiled with Tpetra GO=long long enabled."));
2001  # else
2002  const Tpetra::CrsMatrix<SC,LO,GO,NO>& tpA = Xpetra::Helpers<SC,LO,GO,NO>::Op2TpetraCrs(A);
2003  const Tpetra::CrsMatrix<SC,LO,GO,NO>& tpB = Xpetra::Helpers<SC,LO,GO,NO>::Op2TpetraCrs(B);
2005 
2006  Tpetra::MatrixMatrix::Add(tpA, transposeA, alpha, tpB, transposeB, beta, tpC);
2007  # endif
2008  #else
2009  throw Exceptions::RuntimeError("Xpetra must be compile with Tpetra.");
2010  #endif
2011  }
2012 
2014  if (A.IsView("stridedMaps")) C->CreateView("stridedMaps", rcpFromRef(A));
2015  if (B.IsView("stridedMaps")) C->CreateView("stridedMaps", rcpFromRef(B));
2017  }
2018  // the first matrix is of type CrsMatrixWrap, the second is a blocked operator
2019  else if(rcpBopA == Teuchos::null && rcpBopB != Teuchos::null) {
2020  RCP<const MapExtractor> rgmapextractor = rcpBopB->getRangeMapExtractor();
2021  RCP<const MapExtractor> domapextractor = rcpBopB->getDomainMapExtractor();
2022 
2023  C = rcp(new BlockedCrsMatrix(rgmapextractor, domapextractor, 33 /* TODO fix me */));
2024  RCP<BlockedCrsMatrix> bC = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(C);
2025 
2026  size_t i = 0;
2027  for (size_t j = 0; j < rcpBopB->Cols(); ++j) { // loop over all block columns of B
2028  RCP<Matrix> Cij = Teuchos::null;
2029  if(rcpA != Teuchos::null &&
2030  rcpBopB->getMatrix(i,j)!=Teuchos::null) {
2031  // recursive call
2032  TwoMatrixAdd(*rcpA, transposeA, alpha,
2033  *(rcpBopB->getMatrix(i,j)), transposeB, beta,
2034  Cij, fos, AHasFixedNnzPerRow);
2035  } else if (rcpA == Teuchos::null &&
2036  rcpBopB->getMatrix(i,j)!=Teuchos::null) {
2037  Cij = rcpBopB->getMatrix(i,j);
2038  } else if (rcpA != Teuchos::null &&
2039  rcpBopB->getMatrix(i,j)==Teuchos::null) {
2040  Cij = Teuchos::rcp_const_cast<Matrix>(rcpA);
2041  } else {
2042  Cij = Teuchos::null;
2043  }
2044 
2045  if (!Cij.is_null()) {
2046  if (Cij->isFillComplete())
2047  Cij->resumeFill();
2048  Cij->fillComplete();
2049  bC->setMatrix(i, j, Cij);
2050  } else {
2051  bC->setMatrix(i, j, Teuchos::null);
2052  }
2053  } // loop over columns j
2054  }
2055  // the second matrix is of type CrsMatrixWrap, the first is a blocked operator
2056  else if(rcpBopA != Teuchos::null && rcpBopB == Teuchos::null) {
2057  RCP<const MapExtractor> rgmapextractor = rcpBopA->getRangeMapExtractor();
2058  RCP<const MapExtractor> domapextractor = rcpBopA->getDomainMapExtractor();
2059 
2060  C = rcp(new BlockedCrsMatrix(rgmapextractor, domapextractor, 33 /* TODO fix me */));
2061  RCP<BlockedCrsMatrix> bC = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(C);
2062 
2063  size_t j = 0;
2064  for (size_t i = 0; i < rcpBopA->Rows(); ++i) { // loop over all block rows of A
2065  RCP<Matrix> Cij = Teuchos::null;
2066  if(rcpBopA->getMatrix(i,j)!=Teuchos::null &&
2067  rcpB!=Teuchos::null) {
2068  // recursive call
2069  TwoMatrixAdd(*(rcpBopA->getMatrix(i,j)), transposeA, alpha,
2070  *rcpB, transposeB, beta,
2071  Cij, fos, AHasFixedNnzPerRow);
2072  } else if (rcpBopA->getMatrix(i,j) == Teuchos::null &&
2073  rcpB!=Teuchos::null) {
2074  Cij = Teuchos::rcp_const_cast<Matrix>(rcpB);
2075  } else if (rcpBopA->getMatrix(i,j) != Teuchos::null &&
2076  rcpB==Teuchos::null) {
2077  Cij = rcpBopA->getMatrix(i,j);
2078  } else {
2079  Cij = Teuchos::null;
2080  }
2081 
2082  if (!Cij.is_null()) {
2083  if (Cij->isFillComplete())
2084  Cij->resumeFill();
2085  Cij->fillComplete();
2086  bC->setMatrix(i, j, Cij);
2087  } else {
2088  bC->setMatrix(i, j, Teuchos::null);
2089  }
2090  } // loop over rows i
2091  }
2092  else {
2093  // This is the version for blocked matrices
2094 
2095  // check the compatibility of the blocked operators
2096  TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA.is_null()==true, Xpetra::Exceptions::BadCast, "A is not a BlockedCrsMatrix. (TwoMatrixAdd)");
2097  TEUCHOS_TEST_FOR_EXCEPTION(rcpBopB.is_null()==true, Xpetra::Exceptions::BadCast, "B is not a BlockedCrsMatrix. (TwoMatrixAdd)");
2098  TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA->Rows()!=rcpBopB->Rows(), Xpetra::Exceptions::RuntimeError, "A has " << rcpBopA->Rows() << " rows and B has " << rcpBopA->Rows() << " rows. Matrices are not compatible! (TwoMatrixAdd)");
2099  TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA->Rows()!=rcpBopB->Rows(), Xpetra::Exceptions::RuntimeError, "A has " << rcpBopA->Cols() << " cols and B has " << rcpBopA->Cols() << " cols. Matrices are not compatible! (TwoMatrixAdd)");
2100  TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA->getRangeMap()->isSameAs(*(rcpBopB->getRangeMap()))==false, Xpetra::Exceptions::RuntimeError, "Range map of A is not the same as range map of B. Matrices are not compatible! (TwoMatrixAdd)");
2101  TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA->getDomainMap()->isSameAs(*(rcpBopB->getDomainMap()))==false, Xpetra::Exceptions::RuntimeError, "Domain map of A is not the same as domain map of B. Matrices are not compatible! (TwoMatrixAdd)");
2102  TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA->getRangeMapExtractor()->getThyraMode() != rcpBopB->getRangeMapExtractor()->getThyraMode(), Xpetra::Exceptions::RuntimeError, "Different Thyra/Xpetra style gids in RangeMapExtractor of A and B. Matrices are not compatible! (TwoMatrixAdd)");
2103  TEUCHOS_TEST_FOR_EXCEPTION(rcpBopA->getDomainMapExtractor()->getThyraMode() != rcpBopB->getDomainMapExtractor()->getThyraMode(), Xpetra::Exceptions::RuntimeError, "Different Thyra/Xpetra style gids in DomainMapExtractor of A and B. Matrices are not compatible! (TwoMatrixAdd)");
2104 
2105  RCP<const MapExtractor> rgmapextractor = rcpBopA->getRangeMapExtractor();
2106  RCP<const MapExtractor> domapextractor = rcpBopB->getDomainMapExtractor();
2107 
2108  C = rcp(new BlockedCrsMatrix(rgmapextractor, domapextractor, 33 /* TODO fix me */));
2109  RCP<BlockedCrsMatrix> bC = Teuchos::rcp_dynamic_cast<BlockedCrsMatrix>(C);
2110 
2111  for (size_t i = 0; i < rcpBopA->Rows(); ++i) { // loop over all block rows of A
2112  for (size_t j = 0; j < rcpBopB->Cols(); ++j) { // loop over all block columns of B
2113 
2114  RCP<Matrix> Cij = Teuchos::null;
2115  if(rcpBopA->getMatrix(i,j)!=Teuchos::null &&
2116  rcpBopB->getMatrix(i,j)!=Teuchos::null) {
2117  // recursive call
2118 
2119  TwoMatrixAdd(*(rcpBopA->getMatrix(i,j)), transposeA, alpha,
2120  *(rcpBopB->getMatrix(i,j)), transposeB, beta,
2121  Cij, fos, AHasFixedNnzPerRow);
2122  } else if (rcpBopA->getMatrix(i,j) == Teuchos::null &&
2123  rcpBopB->getMatrix(i,j)!=Teuchos::null) {
2124  Cij = rcpBopB->getMatrix(i,j);
2125  } else if (rcpBopA->getMatrix(i,j) != Teuchos::null &&
2126  rcpBopB->getMatrix(i,j)==Teuchos::null) {
2127  Cij = rcpBopA->getMatrix(i,j);
2128  } else {
2129  Cij = Teuchos::null;
2130  }
2131 
2132  if (!Cij.is_null()) {
2133  if (Cij->isFillComplete())
2134  Cij->resumeFill();
2135  //Cij->fillComplete(rcpBopA->getDomainMap(j), rcpBopA->getRangeMap(i));
2136  Cij->fillComplete();
2137  bC->setMatrix(i, j, Cij);
2138  } else {
2139  bC->setMatrix(i, j, Teuchos::null);
2140  }
2141  } // loop over columns j
2142  } // loop over rows i
2143 
2144  } // end blocked recursive algorithm
2145  } //MatrixMatrix::TwoMatrixAdd()
2146  }; // end specialization on GO=long long and NO=EpetraNode
2147 
2148 #endif // HAVE_XPETRA_EPETRA
2149 
2150 } // end namespace Xpetra
2151 
2152 #define XPETRA_MATRIXMATRIX_SHORT
2153 
2154 #endif /* PACKAGES_XPETRA_SUP_UTILS_XPETRA_MATRIXMATRIX_HPP_ */
virtual size_t getNodeMaxNumRowEntries() const =0
Returns the maximum number of entries across all rows/columns on this node.
virtual size_t getNodeNumRows() const =0
Returns the number of matrix rows owned on the calling node.
const Epetra_Map & RangeMap() const
static void TwoMatrixAdd(const Matrix &A, bool transposeA, const SC &alpha, const Matrix &B, bool transposeB, const SC &beta, RCP< Matrix > &C, Teuchos::FancyOStream &fos, bool AHasFixedNnzPerRow=false)
Helper function to calculate C = alpha*A + beta*B.
virtual size_t getNodeNumEntries() const =0
Returns the local number of entries in this matrix.
static void TwoMatrixAdd(const Matrix &A, bool transposeA, const SC &alpha, const Matrix &B, bool transposeB, const SC &beta, RCP< Matrix > &C, Teuchos::FancyOStream &fos, bool AHasFixedNnzPerRow=false)
Helper function to calculate C = alpha*A + beta*B.
MPI_Comm GetMpiComm() const
RCP< CrsMatrix > getCrsMatrix() const
virtual global_size_t getGlobalNumRows() const =0
Returns the number of global rows in this matrix.
static RCP< Matrix > Multiply(const Matrix &A, bool transposeA, const Matrix &B, bool transposeB, RCP< Matrix > C_in, Teuchos::FancyOStream &fos, bool doFillComplete=true, bool doOptimizeStorage=true, const std::string &label=std::string(), const RCP< ParameterList > &params=null)
Helper function to do matrix-matrix multiply.
bool isFillComplete() const
Returns true if fillComplete() has been called and the matrix is in compute mode. ...
GlobalOrdinal GO
ParameterList & set(std::string const &name, T const &value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
RCP< const Map > getRangeMap() const
Returns the Map associated with the range of this operator.
static Epetra_CrsMatrix & Op2NonConstEpetraCrs(const Matrix &Op)
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Xpetra utility class containing transformation routines between Xpetra::Matrix and Epetra/Tpetra obje...
Exception throws to report errors in the internal logical of the program.
LocalOrdinal LO
static RCP< BlockedCrsMatrix > TwoMatrixMultiplyBlock(const BlockedCrsMatrix &A, bool transposeA, const BlockedCrsMatrix &B, bool transposeB, Teuchos::FancyOStream &fos, bool doFillComplete=true, bool doOptimizeStorage=true)
Helper function to do matrix-matrix multiply &quot;in-place&quot;.
const Epetra_Map & ColMap() const
static const Epetra_CrsMatrix & Op2EpetraCrs(const Matrix &Op)
int IndexBase() const
static RCP< Time > getNewTimer(const std::string &name)
Exception indicating invalid cast attempted.
const Epetra_Map & RowMap() const
int NumMyElements() const
virtual void fillComplete(const RCP< const Map > &domainMap, const RCP< const Map > &rangeMap, const RCP< ParameterList > &params=null)=0
Signal that data entry is complete, specifying domain and range maps.
static void TwoMatrixAdd(const Matrix &A, bool transposeA, const SC &alpha, const Matrix &B, bool transposeB, const SC &beta, RCP< Matrix > &C, Teuchos::FancyOStream &fos, bool AHasFixedNnzPerRow=false)
Helper function to calculate C = alpha*A + beta*B.
static RCP< Epetra_CrsMatrix > MLTwoMatrixMultiply(const Epetra_CrsMatrix &, const Epetra_CrsMatrix &, Teuchos::FancyOStream &)
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
static RCP< Matrix > Multiply(const Matrix &A, bool transposeA, const Matrix &B, bool transposeB, Teuchos::FancyOStream &fos, bool callFillCompleteOnResult=true, bool doOptimizeStorage=true, const std::string &label=std::string(), const RCP< ParameterList > &params=null)
Helper function to do matrix-matrix multiply.
bool IsView(const viewLabel_t viewLabel) const
Teuchos::RCP< Matrix > getMatrix(size_t r, size_t c) const
return block (r,c)
int GID(int LID) const
virtual bool isFillComplete() const =0
Returns true if fillComplete() has been called and the matrix is in compute mode. ...
virtual size_t Cols() const
number of column blocks
void CreateView(viewLabel_t viewLabel, const RCP< const Map > &rowMap, const RCP< const Map > &colMap)
static void Multiply(const Matrix &A, bool transposeA, const Matrix &B, bool transposeB, Matrix &C, bool call_FillComplete_on_result=true, bool doOptimizeStorage=true, const std::string &label=std::string(), const RCP< ParameterList > &params=null)
static RCP< Matrix > Multiply(const Matrix &A, bool transposeA, const Matrix &B, bool transposeB, RCP< Matrix > C_in, Teuchos::FancyOStream &fos, bool doFillComplete=true, bool doOptimizeStorage=true, const std::string &label=std::string(), const RCP< ParameterList > &params=null)
Helper function to do matrix-matrix multiply.
static Tpetra::CrsMatrix< SC, LO, GO, NO > & Op2NonConstTpetraCrs(const Matrix &Op)
static RCP< Matrix > Multiply(const Matrix &A, bool transposeA, const Matrix &B, bool transposeB, RCP< Matrix > C_in, Teuchos::FancyOStream &fos, bool doFillComplete=true, bool doOptimizeStorage=true, const std::string &label=std::string(), const RCP< ParameterList > &params=null)
Helper function to do matrix-matrix multiply.
virtual size_t getNumEntriesInLocalRow(LocalOrdinal localRow) const =0
Returns the current number of entries on this node in the specified local row.
static void Multiply(const Matrix &A, bool transposeA, const Matrix &B, bool transposeB, Matrix &C, bool call_FillComplete_on_result=true, bool doOptimizeStorage=true, const std::string &label=std::string(), const RCP< ParameterList > &params=null)
static RCP< BlockedCrsMatrix > TwoMatrixMultiplyBlock(const BlockedCrsMatrix &A, bool transposeA, const BlockedCrsMatrix &B, bool transposeB, Teuchos::FancyOStream &fos, bool doFillComplete=true, bool doOptimizeStorage=true)
Helper function to do matrix-matrix multiply &quot;in-place&quot;.
static void TwoMatrixAdd(const Matrix &A, bool transposeA, SC alpha, Matrix &B, SC beta)
Helper function to calculate B = alpha*A + beta*B.
virtual int InsertGlobalValues(int GlobalRow, int NumEntries, const double *Values, const int *Indices)
static RCP< const Epetra_CrsMatrix > Op2EpetraCrs(RCP< Matrix > Op)
RCP< const MapExtractor > getDomainMapExtractor() const
Returns map extractor for domain map.
#define TEUCHOS_UNREACHABLE_RETURN(dummyReturnVal)
static void Multiply(const Matrix &A, bool transposeA, const Matrix &B, bool transposeB, Matrix &C, bool call_FillComplete_on_result=true, bool doOptimizeStorage=true, const std::string &label=std::string(), const RCP< ParameterList > &params=null)
bool Filled() const
static RCP< Epetra_CrsMatrix > Op2NonConstEpetraCrs(RCP< Matrix > Op)
const Epetra_Map & DomainMap() const
Exception throws to report incompatible objects (like maps).
RCP< const Map > getDomainMap() const
Returns the Map associated with the domain of this operator.
static void TwoMatrixAdd(const Matrix &A, bool transposeA, SC alpha, Matrix &B, SC beta)
Helper function to calculate B = alpha*A + beta*B.
virtual global_size_t getGlobalNumEntries() const =0
Returns the global number of entries in this matrix.
Concrete implementation of Xpetra::Matrix.
virtual Teuchos::RCP< const Map > getRangeMap() const =0
The Map associated with the range of this operator, which must be compatible with Y...
virtual size_t Rows() const
number of row blocks
static RCP< Epetra_CrsMatrix > MLTwoMatrixMultiply(const Epetra_CrsMatrix &epA, const Epetra_CrsMatrix &epB, Teuchos::FancyOStream &fos)
static RCP< Matrix > Build(const RCP< const Map > &rowMap, size_t maxNumEntriesPerRow, Xpetra::ProfileType pftype=Xpetra::DynamicProfile)
Constructor specifying the number of non-zeros for all rows.
static RCP< BlockedCrsMatrix > TwoMatrixMultiplyBlock(const BlockedCrsMatrix &A, bool transposeA, const BlockedCrsMatrix &B, bool transposeB, Teuchos::FancyOStream &fos, bool doFillComplete=true, bool doOptimizeStorage=true)
Helper function to do matrix-matrix multiply &quot;in-place&quot;.
virtual const RCP< const Map > & getRowMap() const
Returns the Map that describes the row distribution in this matrix.
static RCP< Tpetra::CrsMatrix< SC, LO, GO, NO > > Op2NonConstTpetraCrs(RCP< Matrix > Op)
static RCP< Matrix > Multiply(const Matrix &A, bool transposeA, const Matrix &B, bool transposeB, Teuchos::FancyOStream &fos, bool callFillCompleteOnResult=true, bool doOptimizeStorage=true, const std::string &label=std::string(), const RCP< ParameterList > &params=null)
Helper function to do matrix-matrix multiply.
const Epetra_Comm & Comm() const
static RCP< Epetra_CrsMatrix > MLTwoMatrixMultiply(const Epetra_CrsMatrix &epA, const Epetra_CrsMatrix &epB, Teuchos::FancyOStream &fos)
static void TwoMatrixAdd(const Matrix &A, bool transposeA, SC alpha, Matrix &B, SC beta)
Helper function to calculate B = alpha*A + beta*B.
static const Tpetra::CrsMatrix< SC, LO, GO, NO > & Op2TpetraCrs(const Matrix &Op)
virtual Teuchos::RCP< const Map > getDomainMap() const =0
The Map associated with the domain of this operator, which must be compatible with X...
Xpetra-specific matrix class.
static RCP< const Tpetra::CrsMatrix< SC, LO, GO, NO > > Op2TpetraCrs(RCP< Matrix > Op)
std::string toString(const T &t)
static RCP< Matrix > Multiply(const Matrix &A, bool transposeA, const Matrix &B, bool transposeB, Teuchos::FancyOStream &fos, bool callFillCompleteOnResult=true, bool doOptimizeStorage=true, const std::string &label=std::string(), const RCP< ParameterList > &params=null)
Helper function to do matrix-matrix multiply.
RCP< const MapExtractor > getRangeMapExtractor() const
Returns map extractor class for range map.
bool is_null() const