Reference documentation for deal.II version 9.1.0-pre
trilinos_precondition_muelu.cc
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2008 - 2018 by the deal.II authors
4 //
5 // This file is part of the deal.II library.
6 //
7 // The deal.II library is free software; you can use it, redistribute
8 // it, and/or modify it under the terms of the GNU Lesser General
9 // Public License as published by the Free Software Foundation; either
10 // version 2.1 of the License, or (at your option) any later version.
11 // The full text of the license can be found in the file LICENSE.md at
12 // the top level directory of deal.II.
13 //
14 // ---------------------------------------------------------------------
15 
16 #include <deal.II/lac/trilinos_index_access.h>
17 #include <deal.II/lac/trilinos_precondition.h>
18 
19 #ifdef DEAL_II_WITH_TRILINOS
20 # if DEAL_II_TRILINOS_VERSION_GTE(11, 14, 0)
21 
22 # include <deal.II/lac/sparse_matrix.h>
23 # include <deal.II/lac/trilinos_index_access.h>
24 # include <deal.II/lac/trilinos_sparse_matrix.h>
25 # include <deal.II/lac/vector.h>
26 
27 # include <Epetra_MultiVector.h>
28 # include <MueLu.hpp>
29 # include <MueLu_EpetraOperator.hpp>
30 # include <MueLu_MLParameterListInterpreter.hpp>
31 # include <Teuchos_ParameterList.hpp>
32 # include <Teuchos_RCP.hpp>
33 # include <ml_MultiLevelPreconditioner.h>
34 # include <ml_include.h>
35 
36 DEAL_II_NAMESPACE_OPEN
37 
38 namespace TrilinosWrappers
39 {
41  const bool elliptic,
42  const unsigned int n_cycles,
43  const bool w_cycle,
44  const double aggregation_threshold,
45  const std::vector<std::vector<bool>> &constant_modes,
46  const unsigned int smoother_sweeps,
47  const unsigned int smoother_overlap,
48  const bool output_details,
49  const char * smoother_type,
50  const char * coarse_type)
51  : elliptic(elliptic)
52  , n_cycles(n_cycles)
53  , w_cycle(w_cycle)
54  , aggregation_threshold(aggregation_threshold)
55  , constant_modes(constant_modes)
56  , smoother_sweeps(smoother_sweeps)
57  , smoother_overlap(smoother_overlap)
58  , output_details(output_details)
59  , smoother_type(smoother_type)
60  , coarse_type(coarse_type)
61  {}
62 
63 
64 
66  {
67 # ifdef DEAL_II_WITH_64BIT_INDICES
68  AssertThrow(false,
69  ExcMessage(
70  "PreconditionAMGMueLu does not support 64bit-indices!"));
71 # endif
72  }
73 
74 
75 
77  {
78  preconditioner.reset();
79  trilinos_matrix.reset();
80  }
81 
82 
83 
84  void
86  const AdditionalData &additional_data)
87  {
88  initialize(matrix.trilinos_matrix(), additional_data);
89  }
90 
91 
92 
93  void
94  PreconditionAMGMueLu::initialize(const Epetra_CrsMatrix &matrix,
95  const AdditionalData & additional_data)
96  {
97  // Build the AMG preconditioner.
98  Teuchos::ParameterList parameter_list;
99 
100  if (additional_data.elliptic == true)
101  ML_Epetra::SetDefaults("SA", parameter_list);
102  else
103  {
104  ML_Epetra::SetDefaults("NSSA", parameter_list);
105  parameter_list.set("aggregation: block scaling", true);
106  }
107  // MIS does not exist anymore, only choice are uncoupled and coupled. When
108  // using uncoupled, aggregates cannot span multiple processes. When using
109  // coupled aggregates can span multiple processes.
110  parameter_list.set("aggregation: type", "Uncoupled");
111 
112  parameter_list.set("smoother: type", additional_data.smoother_type);
113  parameter_list.set("coarse: type", additional_data.coarse_type);
114 
115  parameter_list.set("smoother: sweeps",
116  static_cast<int>(additional_data.smoother_sweeps));
117  parameter_list.set("cycle applications",
118  static_cast<int>(additional_data.n_cycles));
119  if (additional_data.w_cycle == true)
120  parameter_list.set("prec type", "MGW");
121  else
122  parameter_list.set("prec type", "MGV");
123 
124  parameter_list.set("smoother: Chebyshev alpha", 10.);
125  parameter_list.set("smoother: ifpack overlap",
126  static_cast<int>(additional_data.smoother_overlap));
127  parameter_list.set("aggregation: threshold",
128  additional_data.aggregation_threshold);
129  parameter_list.set("coarse: max size", 2000);
130 
131  if (additional_data.output_details)
132  parameter_list.set("ML output", 10);
133  else
134  parameter_list.set("ML output", 0);
135 
136  const Epetra_Map &domain_map = matrix.OperatorDomainMap();
137 
138  const size_type constant_modes_dimension =
139  additional_data.constant_modes.size();
140  Epetra_MultiVector distributed_constant_modes(
141  domain_map, constant_modes_dimension > 0 ? constant_modes_dimension : 1);
142  std::vector<double> dummy(constant_modes_dimension);
143 
144  if (constant_modes_dimension > 0)
145  {
146  const size_type n_rows = TrilinosWrappers::n_global_rows(matrix);
147  const bool constant_modes_are_global =
148  additional_data.constant_modes[0].size() == n_rows;
149  const size_type n_relevant_rows =
150  constant_modes_are_global ? n_rows :
151  additional_data.constant_modes[0].size();
152  const size_type my_size = domain_map.NumMyElements();
153  if (constant_modes_are_global == false)
154  Assert(n_relevant_rows == my_size,
155  ExcDimensionMismatch(n_relevant_rows, my_size));
156  Assert(n_rows == static_cast<size_type>(TrilinosWrappers::global_length(
157  distributed_constant_modes)),
158  ExcDimensionMismatch(n_rows,
160  distributed_constant_modes)));
161 
162  (void)n_relevant_rows;
163  (void)global_length;
164 
165  // Reshape null space as a contiguous vector of doubles so that
166  // Trilinos can read from it.
167  for (size_type d = 0; d < constant_modes_dimension; ++d)
168  for (size_type row = 0; row < my_size; ++row)
169  {
170  TrilinosWrappers::types::int_type global_row_id =
171  constant_modes_are_global ?
172  TrilinosWrappers::global_index(domain_map, row) :
173  row;
174  distributed_constant_modes[d][row] =
175  additional_data.constant_modes[d][global_row_id];
176  }
177 
178  parameter_list.set("null space: type", "pre-computed");
179  parameter_list.set("null space: dimension",
180  distributed_constant_modes.NumVectors());
181  if (my_size > 0)
182  parameter_list.set("null space: vectors",
183  distributed_constant_modes.Values());
184  // We need to set a valid pointer to data even if there is no data on
185  // the current processor. Therefore, pass a dummy in that case
186  else
187  parameter_list.set("null space: vectors", dummy.data());
188  }
189 
190  initialize(matrix, parameter_list);
191  }
192 
193 
194 
195  void
197  Teuchos::ParameterList &muelu_parameters)
198  {
199  initialize(matrix.trilinos_matrix(), muelu_parameters);
200  }
201 
202 
203 
204  void
205  PreconditionAMGMueLu::initialize(const Epetra_CrsMatrix &matrix,
206  Teuchos::ParameterList &muelu_parameters)
207  {
208  // We cannot use MueLu::CreateEpetraOperator directly because, we cannot
209  // transfer ownership of MueLu::EpetraOperator from Teuchos::RCP to
210  // std::shared_ptr.
211 
212  // For now, just use serial node, i.e. no multithreaing or GPU.
213  using node = KokkosClassic::DefaultNode::DefaultNodeType;
214  preconditioner.reset();
215 
216  // Cast matrix into a MueLu::Matrix. The constness needs to be cast away.
217  // MueLu uses Teuchos::RCP which are Trilinos version of std::shared_ptr.
218  Teuchos::RCP<Epetra_CrsMatrix> rcp_matrix =
219  Teuchos::rcpFromRef(*(const_cast<Epetra_CrsMatrix *>(&matrix)));
220  Teuchos::RCP<Xpetra::CrsMatrix<double, int, int, node>> muelu_crs_matrix =
221  Teuchos::rcp(new Xpetra::EpetraCrsMatrix(rcp_matrix));
222  Teuchos::RCP<Xpetra::Matrix<double, int, int, node>> muelu_matrix =
223  Teuchos::rcp(
224  new Xpetra::CrsMatrixWrap<double, int, int, node>(muelu_crs_matrix));
225 
226  // Create the multigrid hierarchy using ML parameters.
227  Teuchos::RCP<MueLu::HierarchyManager<double, int, int, node>>
228  hierarchy_factory;
229  hierarchy_factory = Teuchos::rcp(
230  new MueLu::MLParameterListInterpreter<double, int, int, node>(
231  muelu_parameters));
232  Teuchos::RCP<MueLu::Hierarchy<double, int, int, node>> hierarchy =
233  hierarchy_factory->CreateHierarchy();
234  hierarchy->GetLevel(0)->Set("A", muelu_matrix);
235  hierarchy_factory->SetupHierarchy(*hierarchy);
236 
237  // MueLu::EpetraOperator is just a wrapper around a "standard"
238  // Epetra_Operator.
239  preconditioner = std::make_shared<MueLu::EpetraOperator>(hierarchy);
240  }
241 
242 
243 
244  template <typename number>
245  void
247  const ::SparseMatrix<number> &deal_ii_sparse_matrix,
248  const AdditionalData & additional_data,
249  const double drop_tolerance,
250  const ::SparsityPattern * use_this_sparsity)
251  {
252  preconditioner.reset();
253  const size_type n_rows = deal_ii_sparse_matrix.m();
254 
255  // Init Epetra Matrix using an
256  // equidistributed map; avoid
257  // storing the nonzero
258  // elements.
259  vector_distributor = std::make_shared<Epetra_Map>(
260  static_cast<TrilinosWrappers::types::int_type>(n_rows), 0, communicator);
261 
262  if (trilinos_matrix.get() == nullptr)
263  trilinos_matrix = std::make_shared<SparseMatrix>();
264 
267  deal_ii_sparse_matrix,
268  drop_tolerance,
269  true,
270  use_this_sparsity);
271 
272  initialize(*trilinos_matrix, additional_data);
273  }
274 
275 
276 
277  void
279  {
281  trilinos_matrix.reset();
282  }
283 
284 
285 
288  {
289  unsigned int memory = sizeof(*this);
290 
291  // todo: find a way to read out ML's data
292  // sizes
293  if (trilinos_matrix.get() != nullptr)
294  memory += trilinos_matrix->memory_consumption();
295  return memory;
296  }
297 
298 
299 
300  // explicit instantiations
301  template void
302  PreconditionAMGMueLu::initialize(const ::SparseMatrix<double> &,
303  const AdditionalData &,
304  const double,
305  const ::SparsityPattern *);
306  template void
307  PreconditionAMGMueLu::initialize(const ::SparseMatrix<float> &,
308  const AdditionalData &,
309  const double,
310  const ::SparsityPattern *);
311 
312 } // namespace TrilinosWrappers
313 
314 DEAL_II_NAMESPACE_CLOSE
315 
316 # endif // DEAL_II_TRILINOS_VERSION_GTE(11,14,0)
317 #endif // DEAL_II_WITH_TRILINOS
void initialize(const SparseMatrix &matrix, const AdditionalData &additional_data=AdditionalData())
const Epetra_CrsMatrix & trilinos_matrix() const
TrilinosWrappers::types::int_type global_length(const Epetra_MultiVector &vector)
std::shared_ptr< Epetra_Map > vector_distributor
#define AssertThrow(cond, exc)
Definition: exceptions.h:1329
static::ExceptionBase & ExcMessage(std::string arg1)
TrilinosWrappers::types::int_type n_global_rows(const Epetra_CrsGraph &graph)
#define Assert(cond, exc)
Definition: exceptions.h:1227
static::ExceptionBase & ExcDimensionMismatch(std::size_t arg1, std::size_t arg2)
AdditionalData(const bool elliptic=true, const unsigned int n_cycles=1, const bool w_cyle=false, const double aggregation_threshold=1e-4, const std::vector< std::vector< bool >> &constant_modes=std::vector< std::vector< bool >>(0), const unsigned int smoother_sweeps=2, const unsigned int smoother_overlap=0, const bool output_details=false, const char *smoother_type="Chebyshev", const char *coarse_type="Amesos-KLU")
std::shared_ptr< SparseMatrix > trilinos_matrix
TrilinosWrappers::types::int_type global_index(const Epetra_BlockMap &map, const ::types::global_dof_index i)
std::shared_ptr< Epetra_Operator > preconditioner