MueLu  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MueLu_Amesos2Smoother_def.hpp
Go to the documentation of this file.
1 // @HEADER
2 //
3 // ***********************************************************************
4 //
5 // MueLu: A package for multigrid based preconditioning
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 //
43 // ***********************************************************************
44 //
45 // @HEADER
46 #ifndef MUELU_AMESOS2SMOOTHER_DEF_HPP
47 #define MUELU_AMESOS2SMOOTHER_DEF_HPP
48 
49 #include <algorithm>
50 
51 #include "MueLu_ConfigDefs.hpp"
52 #if defined (HAVE_MUELU_TPETRA) && defined(HAVE_MUELU_AMESOS2)
53 #include <Xpetra_Matrix.hpp>
54 
55 #include <Amesos2_config.h>
56 #include <Amesos2.hpp>
57 
59 #include "MueLu_Level.hpp"
60 #include "MueLu_Utilities.hpp"
61 #include "MueLu_Monitor.hpp"
62 
63 namespace MueLu {
64 
65  template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
67  : type_(type), useTransformation_(false) {
68  this->SetParameterList(paramList);
69 
70  if (!type_.empty()) {
71  // Transform string to "Abcde" notation
72  std::transform(type_.begin(), type_.end(), type_.begin(), ::tolower);
73  std::transform(type_.begin(), ++type_.begin(), type_.begin(), ::toupper);
74  }
75  if (type_ == "Superlu_dist")
76  type_ = "Superludist";
77 
78  // Try to come up with something availble
79  // Order corresponds to our preference
80  // TODO: It would be great is Amesos2 provides directly this kind of logic for us
81  if (type_ == "" || Amesos2::query(type_) == false) {
82  std::string oldtype = type_;
83 #if defined(HAVE_AMESOS2_SUPERLU)
84  type_ = "Superlu";
85 #elif defined(HAVE_AMESOS2_KLU2)
86  type_ = "Klu";
87 #elif defined(HAVE_AMESOS2_SUPERLUDIST)
88  type_ = "Superludist";
89 #elif defined(HAVE_AMESOS2_BASKER)
90  type_ = "Basker";
91 #else
92  throw Exceptions::RuntimeError("Amesos2 has been compiled without SuperLU_DIST, SuperLU, Klu, or Basker. By default, MueLu tries"
93  "to use one of these libraries. Amesos2 must be compiled with one of these solvers, "
94  "or a valid Amesos2 solver has to be specified explicitly.");
95 #endif
96  if (oldtype != "")
97  this->GetOStream(Warnings0) << "MueLu::Amesos2Smoother: \"" << oldtype << "\" is not available. Using \"" << type_ << "\" instead" << std::endl;
98  else
99  this->GetOStream(Runtime1) << "MueLu::Amesos2Smoother: using \"" << type_ << "\"" << std::endl;
100  }
101 
102  // Check the validity of the solver type parameter
103  TEUCHOS_TEST_FOR_EXCEPTION(Amesos2::query(type_) == false, Exceptions::RuntimeError, "The Amesos2 library reported that the solver '" << type_ << "' is not available. "
104  "Amesos2 has been compiled without the support of this solver, or the solver name is misspelled.");
105  }
106 
107  template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
109 
110  template <class Scalar, class LocalOrdinal, class GlobalOrdinal, class Node>
112  RCP<ParameterList> validParamList = rcp(new ParameterList());
113  validParamList->set< RCP<const FactoryBase> >("A", null, "Factory of the coarse matrix");
114  validParamList->set< RCP<const FactoryBase> >("Nullspace", null, "Factory of the nullspace");
115  validParamList->set<bool>("fix nullspace", false, "Remove zero eigenvalue by adding rank one correction.");
116  return validParamList;
117  }
118 
119  template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
121  ParameterList pL = this->GetParameterList();
122 
123  this->Input(currentLevel, "A");
124  if (pL.get<bool>("fix nullspace"))
125  this->Input(currentLevel, "Nullspace");
126  }
127 
128  template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
130  FactoryMonitor m(*this, "Setup Smoother", currentLevel);
131 
132  if (SmootherPrototype::IsSetup() == true)
133  this->GetOStream(Warnings0) << "MueLu::Amesos2Smoother::Setup(): Setup() has already been called" << std::endl;
134 
135  RCP<Matrix> A = Factory::Get< RCP<Matrix> >(currentLevel, "A");
136 
137  // Do a quick check if we need to modify the matrix
138  RCP<const Map> rowMap = A->getRowMap();
139  if (rowMap->getGlobalNumElements() != as<size_t>((rowMap->getMaxAllGlobalIndex() - rowMap->getMinAllGlobalIndex())+1)) {
140  // If our system is non-conventional, here is the place where we try to fix it
141  // One example is: if our maps contain a gap in them, for instance GIDs
142  // are [0,..., 100, 10000, ..., 10010], then Amesos2 breaks down.
143  //
144  // The approach we take is to construct a second system with maps
145  // replaced by their continuous versions.
146  //
147  // FIXME: for the moment, this functionality works for selected limited scenarios
148  this->GetOStream(Runtime1) << "MueLu::Amesos2Smoother::Setup(): using system transformation" << std::endl;
149 
150  TEUCHOS_TEST_FOR_EXCEPTION(rowMap->getComm()->getSize() > 1, Exceptions::RuntimeError,
151  "MueLu::Amesos2Smoother::Setup Fixing coarse matrix for Amesos2 for multiple processors has not been implemented yet.");
152  TEUCHOS_TEST_FOR_EXCEPTION(!rowMap->isSameAs(*A->getColMap()), Exceptions::RuntimeError,
153  "MueLu::Amesos2Smoother::Setup Fixing coarse matrix for Amesos2 when row map is different from column map has not been implemented yet.");
154 
155  RCP<CrsMatrixWrap> Acrs = rcp_dynamic_cast<CrsMatrixWrap>(A);
156  TEUCHOS_TEST_FOR_EXCEPTION(Acrs.is_null(), Exceptions::RuntimeError,
157  "MueLu::Amesos2Smoother::Setup Fixing coarse matrix for Amesos2 when matrix is not a Crs matrix has not been implemented yet.");
158 
159  useTransformation_ = true;
160 
161  ArrayRCP<const size_t> rowPointers;
162  ArrayRCP<const LO> colIndices;
163  ArrayRCP<const SC> values;
164  Acrs->getCrsMatrix()->getAllValues(rowPointers, colIndices, values);
165 
166  // Create new map
167  RCP<Map> map = MapFactory::Build(rowMap->lib(), rowMap->getGlobalNumElements(), 0, rowMap->getComm());
168  RCP<Matrix> newA = rcp(new CrsMatrixWrap(map, map, 0, Xpetra::StaticProfile));
169  RCP<CrsMatrix> newAcrs = rcp_dynamic_cast<CrsMatrixWrap>(newA)->getCrsMatrix();
170 
171  using Teuchos::arcp_const_cast;
172  newAcrs->setAllValues(arcp_const_cast<size_t>(rowPointers), arcp_const_cast<LO>(colIndices), arcp_const_cast<SC>(values));
173  newAcrs->expertStaticFillComplete(map, map);
174 
175  A.swap(newA);
176 
177  X_ = MultiVectorFactory::Build(map, 1);
178  B_ = MultiVectorFactory::Build(map, 1);
179  }
180 
181  RCP<Matrix> factorA;
182  Teuchos::ParameterList pL = this->GetParameterList();
183  if (pL.get<bool>("fix nullspace")) {
184  this->GetOStream(Runtime1) << "MueLu::Amesos2Smoother::Setup(): fixing nullspace" << std::endl;
185 
186  rowMap = A->getRowMap();
187  size_t M = rowMap->getGlobalNumElements();
188 
189  RCP<MultiVector> Nullspace = Factory::Get< RCP<MultiVector> >(currentLevel, "Nullspace");
190 
191  TEUCHOS_TEST_FOR_EXCEPTION(Nullspace->getNumVectors() > 1, Exceptions::RuntimeError,
192  "MueLu::Amesos2Smoother::Setup Fixing nullspace for coarse matrix for Amesos2 for nullspace of dim > 1 has not been implemented yet.");
193 
194  RCP<MultiVector> NullspaceImp;
195  RCP<const Map> colMap;
196  RCP<const Import> importer;
197  if (rowMap->getComm()->getSize() > 1) {
198  this->GetOStream(Warnings0) << "MueLu::Amesos2Smoother::Setup(): Applying nullspace fix on distributed matrix. Try rebalancing to single rank!" << std::endl;
199  ArrayRCP<GO> elements_RCP;
200  elements_RCP.resize(M);
201  ArrayView<GO> elements = elements_RCP();
202  for (size_t k = 0; k<M; k++)
203  elements[k] = Teuchos::as<GO>(k);
204  colMap = MapFactory::Build(rowMap->lib(),M*rowMap->getComm()->getSize(),elements,Teuchos::ScalarTraits<GO>::zero(),rowMap->getComm());
205  importer = ImportFactory::Build(rowMap,colMap);
206  NullspaceImp = MultiVectorFactory::Build(colMap, Nullspace->getNumVectors());
207  NullspaceImp->doImport(*Nullspace,*importer,Xpetra::INSERT);
208  } else {
209  NullspaceImp = Nullspace;
210  colMap = rowMap;
211  }
212 
213  ArrayRCP<const SC> nullspaceRCP, nullspaceImpRCP;
214  ArrayView<const SC> nullspace, nullspaceImp;
215  nullspaceRCP = Nullspace->getData(0);
216  nullspace = nullspaceRCP();
217  nullspaceImpRCP = NullspaceImp->getData(0);
218  nullspaceImp = nullspaceImpRCP();
219 
220  RCP<CrsMatrixWrap> Acrs = rcp_dynamic_cast<CrsMatrixWrap>(A);
221 
223  "MueLu::Amesos2Smoother::Setup Fixing nullspace for coarse matrix for Amesos2 when matrix is not a Crs matrix has not been implemented yet.");
224 
225  ArrayRCP<const size_t> rowPointers;
226  ArrayRCP<const LO> colIndices;
227  ArrayRCP<const SC> values;
228  Acrs->getCrsMatrix()->getAllValues(rowPointers, colIndices, values);
229 
230  ArrayRCP<size_t> newRowPointers_RCP;
231  ArrayRCP<LO> newColIndices_RCP;
232  ArrayRCP<SC> newValues_RCP;
233 
234  size_t N = rowMap->getNodeNumElements();
235  newRowPointers_RCP.resize(N+1);
236  newColIndices_RCP.resize(N*M);
237  newValues_RCP.resize(N*M);
238 
239  ArrayView<size_t> newRowPointers = newRowPointers_RCP();
240  ArrayView<LO> newColIndices = newColIndices_RCP();
241  ArrayView<SC> newValues = newValues_RCP();
242 
243  SC normalization = Nullspace->getVector(0)->norm2();
244  normalization = Teuchos::ScalarTraits<Scalar>::one()/(normalization*normalization);
245 
246  // form nullspace * nullspace^T
247  for (size_t i = 0; i < N; i++) {
248  newRowPointers[i] = i*M;
249  for (size_t j = 0; j < M; j++) {
250  newColIndices[i*M+j] = Teuchos::as<LO>(j);
251  newValues[i*M+j] = normalization * nullspace[i]*Teuchos::ScalarTraits<Scalar>::conjugate(nullspaceImp[j]);
252  }
253  }
254  newRowPointers[N] = N*M;
255 
256  // add A
257  for (size_t i = 0; i < N; i++) {
258  for (size_t jj = rowPointers[i]; jj < rowPointers[i+1]; jj++) {
259  LO j = colMap->getLocalElement(A->getColMap()->getGlobalElement(colIndices[jj]));
260  SC v = values[jj];
261  newValues[i*M+j] += v;
262  }
263  }
264 
265  RCP<Matrix> newA = rcp(new CrsMatrixWrap(rowMap, colMap, 0, Xpetra::StaticProfile));
266  RCP<CrsMatrix> newAcrs = rcp_dynamic_cast<CrsMatrixWrap>(newA)->getCrsMatrix();
267 
268  using Teuchos::arcp_const_cast;
269  newAcrs->setAllValues(arcp_const_cast<size_t>(newRowPointers_RCP), arcp_const_cast<LO>(newColIndices_RCP), arcp_const_cast<SC>(newValues_RCP));
270  newAcrs->expertStaticFillComplete(A->getDomainMap(), A->getRangeMap(),
271  importer, A->getCrsGraph()->getExporter());
272 
273  factorA = newA;
274  } else {
275  factorA = A;
276  }
277 
279 
280  prec_ = Amesos2::create<Tpetra_CrsMatrix,Tpetra_MultiVector>(type_, tA);
281  TEUCHOS_TEST_FOR_EXCEPTION(prec_ == Teuchos::null, Exceptions::RuntimeError, "Amesos2::create returns Teuchos::null");
282 
284  }
285 
286  template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
287  void Amesos2Smoother<Scalar, LocalOrdinal, GlobalOrdinal, Node>::Apply(MultiVector& X, const MultiVector& B, bool /* InitialGuessIsZero */) const {
288  TEUCHOS_TEST_FOR_EXCEPTION(SmootherPrototype::IsSetup() == false, Exceptions::RuntimeError, "MueLu::Amesos2Smoother::Apply(): Setup() has not been called");
289 
291  if (!useTransformation_) {
293  tB = Utilities::MV2NonConstTpetraMV2(const_cast<MultiVector&>(B));
294  } else {
295  // Copy data of the original vectors into the transformed ones
296  size_t numVectors = X.getNumVectors();
297  size_t length = X.getLocalLength();
298 
300  "MueLu::Amesos2Smoother::Apply: Fixing coarse matrix for Amesos2 for multivectors has not been implemented yet.");
301  ArrayRCP<const SC> Xdata = X. getData(0), Bdata = B. getData(0);
302  ArrayRCP<SC> X_data = X_->getDataNonConst(0), B_data = B_->getDataNonConst(0);
303 
304  for (size_t i = 0; i < length; i++) {
305  X_data[i] = Xdata[i];
306  B_data[i] = Bdata[i];
307  }
308 
311  }
312 
313  prec_->setX(tX);
314  prec_->setB(tB);
315 
316  prec_->solve();
317 
318  prec_->setX(Teuchos::null);
319  prec_->setB(Teuchos::null);
320 
321  if (useTransformation_) {
322  // Copy data from the transformed vectors into the original ones
323  size_t length = X.getLocalLength();
324 
325  ArrayRCP<SC> Xdata = X. getDataNonConst(0);
326  ArrayRCP<const SC> X_data = X_->getData(0);
327 
328  for (size_t i = 0; i < length; i++)
329  Xdata[i] = X_data[i];
330  }
331  }
332 
333  template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
336  Copy() const
337  {
338  return rcp (new Amesos2Smoother (*this));
339  }
340 
341  template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
343  std::ostringstream out;
344 
345  if (SmootherPrototype::IsSetup() == true) {
346  out << prec_->description();
347 
348  } else {
350  out << "{type = " << type_ << "}";
351  }
352  return out.str();
353  }
354 
355  template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
358 
359  if (verbLevel & Parameters0)
360  out0 << "Prec. type: " << type_ << std::endl;
361 
362  if (verbLevel & Parameters1) {
363  out0 << "Parameter list: " << std::endl;
364  Teuchos::OSTab tab2(out);
365  out << this->GetParameterList();
366  }
367 
368  if ((verbLevel & External) && prec_ != Teuchos::null) {
369  Teuchos::OSTab tab2(out);
370  out << *prec_ << std::endl;
371  }
372 
373  if (verbLevel & Debug)
374  out0 << "IsSetup: " << Teuchos::toString(SmootherPrototype::IsSetup()) << std::endl
375  << "-" << std::endl
376  << "RCP<prec_>: " << prec_ << std::endl;
377  }
378 
379  template <class Scalar,class LocalOrdinal, class GlobalOrdinal, class Node>
381  if(!prec_.is_null())
382  return prec_->getStatus().getNnzLU();
383  else
384  return 0.0;
385 
386  }
387 } // namespace MueLu
388 
389 #endif // HAVE_MUELU_TPETRA && HAVE_MUELU_AMESOS2
390 #endif // MUELU_AMESOS2SMOOTHER_DEF_HPP
Important warning messages (one line)
Teuchos::FancyOStream & GetOStream(MsgType type, int thisProcRankOnly=0) const
Get an output stream for outputting the input message type.
RCP< const ParameterList > GetValidParameterList() const
Return a const parameter list of valid parameters that setParameterList() will accept.
Print external lib objects.
T & get(const std::string &name, T def_value)
ParameterList & set(std::string const &name, T const &value, std::string const &docString="", RCP< const ParameterEntryValidator > const &validator=null)
std::string type_
amesos2-specific key phrase that denote smoother type
void Apply(MultiVector &X, const MultiVector &B, bool InitialGuessIsZero=false) const
Apply the direct solver. Solves the linear system AX=B using the constructed solver.
Timer to be used in factories. Similar to Monitor but with additional timers.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
void swap(RCP< T > &r_ptr)
Print additional debugging information.
LocalOrdinal LO
std::string tolower(const std::string &str)
Amesos2Smoother(const std::string &type="", const Teuchos::ParameterList &paramList=Teuchos::ParameterList())
Constructor Creates a MueLu interface to the direct solvers in the Amesos2 package. If you are using type==&quot;&quot;, then either SuperLU or KLU2 are used by default.
std::string description() const
Return a simple one-line description of this object.
void resize(const size_type n, const T &val=T())
static T conjugate(T a)
RCP< SmootherPrototype > Copy() const
virtual void SetParameterList(const Teuchos::ParameterList &paramList)
Set parameters from a parameter list and return with default values.
TEUCHOS_DEPRECATED RCP< T > rcp(T *p, Dealloc_T dealloc, bool owns_mem)
Class that holds all level-specific information.
Definition: MueLu_Level.hpp:99
Class that encapsulates Amesos2 direct solvers.
static RCP< Tpetra::CrsMatrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > Op2NonConstTpetraCrs(RCP< Xpetra::Matrix< Scalar, LocalOrdinal, GlobalOrdinal, Node > > Op)
static RCP< Tpetra::MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > > MV2NonConstTpetraMV2(Xpetra::MultiVector< Scalar, LocalOrdinal, GlobalOrdinal, Node > &vec)
bool IsSetup() const
Get the state of a smoother prototype.
void DeclareInput(Level &currentLevel) const
Input.
#define MUELU_DESCRIBE
Helper macro for implementing Describable::describe() for BaseClass objects.
Print class parameters.
virtual ~Amesos2Smoother()
Destructor.
void Setup(Level &currentLevel)
Set up the direct solver. This creates the underlying Amesos2 solver object according to the paramete...
Scalar SC
Print class parameters (more parameters, more verbose)
Exception throws to report errors in the internal logical of the program.
Description of what is happening (more verbose)
size_t getNodeSmootherComplexity() const
Get a rough estimate of cost per iteration.
void print(Teuchos::FancyOStream &out, const VerbLevel verbLevel=Default) const
Print the object with some verbosity level to an FancyOStream object.
virtual std::string description() const
Return a simple one-line description of this object.
std::string toString(const T &t)
bool is_null() const