Reference documentation for deal.II version 9.1.0-pre
trilinos_precondition_ml.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 
21 # include <deal.II/lac/sparse_matrix.h>
22 # include <deal.II/lac/trilinos_index_access.h>
23 # include <deal.II/lac/trilinos_sparse_matrix.h>
24 # include <deal.II/lac/vector.h>
25 
26 # include <Epetra_MultiVector.h>
27 # include <Ifpack.h>
28 # include <Ifpack_Chebyshev.h>
29 # include <Teuchos_ParameterList.hpp>
30 # include <Teuchos_RCP.hpp>
31 # include <ml_MultiLevelPreconditioner.h>
32 # include <ml_include.h>
33 
34 DEAL_II_NAMESPACE_OPEN
35 
36 namespace TrilinosWrappers
37 {
38  /* -------------------------- PreconditionAMG -------------------------- */
39 
41  const bool elliptic,
42  const bool higher_order_elements,
43  const unsigned int n_cycles,
44  const bool w_cycle,
45  const double aggregation_threshold,
46  const std::vector<std::vector<bool>> &constant_modes,
47  const unsigned int smoother_sweeps,
48  const unsigned int smoother_overlap,
49  const bool output_details,
50  const char * smoother_type,
51  const char * coarse_type)
52  : elliptic(elliptic)
53  , higher_order_elements(higher_order_elements)
54  , n_cycles(n_cycles)
55  , w_cycle(w_cycle)
56  , aggregation_threshold(aggregation_threshold)
57  , constant_modes(constant_modes)
58  , smoother_sweeps(smoother_sweeps)
59  , smoother_overlap(smoother_overlap)
60  , output_details(output_details)
61  , smoother_type(smoother_type)
62  , coarse_type(coarse_type)
63  {}
64 
65 
67  {
68  preconditioner.reset();
69  trilinos_matrix.reset();
70  }
71 
72 
73 
74  void
76  const AdditionalData &additional_data)
77  {
78  initialize(matrix.trilinos_matrix(), additional_data);
79  }
80 
81 
82 
83  void
84  PreconditionAMG::initialize(const Epetra_RowMatrix &matrix,
85  const AdditionalData & additional_data)
86  {
87  // Build the AMG preconditioner.
88  Teuchos::ParameterList parameter_list;
89 
90  if (additional_data.elliptic == true)
91  {
92  ML_Epetra::SetDefaults("SA", parameter_list);
93 
94  // uncoupled mode can give a lot of warnings or even fail when there
95  // are too many entries per row and aggreggation gets complicated, but
96  // MIS does not work if too few elements are located on one
97  // processor. work around these warnings by choosing the different
98  // strategies in different situations: for low order, always use the
99  // standard choice uncoupled. if higher order, right now we also just
100  // use Uncoupled, but we should be aware that maybe MIS might be
101  // needed
102  if (additional_data.higher_order_elements)
103  parameter_list.set("aggregation: type", "Uncoupled");
104  }
105  else
106  {
107  ML_Epetra::SetDefaults("NSSA", parameter_list);
108  parameter_list.set("aggregation: type", "Uncoupled");
109  parameter_list.set("aggregation: block scaling", true);
110  }
111 
112  parameter_list.set("smoother: type", additional_data.smoother_type);
113  parameter_list.set("coarse: type", additional_data.coarse_type);
114 
115  // Force re-initialization of the random seed to make ML deterministic
116  // (only supported in trilinos >12.2):
117 # if DEAL_II_TRILINOS_VERSION_GTE(12, 4, 0)
118  parameter_list.set("initialize random seed", true);
119 # endif
120 
121  parameter_list.set("smoother: sweeps",
122  static_cast<int>(additional_data.smoother_sweeps));
123  parameter_list.set("cycle applications",
124  static_cast<int>(additional_data.n_cycles));
125  if (additional_data.w_cycle == true)
126  parameter_list.set("prec type", "MGW");
127  else
128  parameter_list.set("prec type", "MGV");
129 
130  parameter_list.set("smoother: Chebyshev alpha", 10.);
131  parameter_list.set("smoother: ifpack overlap",
132  static_cast<int>(additional_data.smoother_overlap));
133  parameter_list.set("aggregation: threshold",
134  additional_data.aggregation_threshold);
135  parameter_list.set("coarse: max size", 2000);
136 
137  if (additional_data.output_details)
138  parameter_list.set("ML output", 10);
139  else
140  parameter_list.set("ML output", 0);
141 
142  const Epetra_Map &domain_map = matrix.OperatorDomainMap();
143 
144  const size_type constant_modes_dimension =
145  additional_data.constant_modes.size();
146  Epetra_MultiVector distributed_constant_modes(
147  domain_map, constant_modes_dimension > 0 ? constant_modes_dimension : 1);
148  std::vector<double> dummy(constant_modes_dimension);
149 
150  if (constant_modes_dimension > 0)
151  {
152  const size_type global_size = TrilinosWrappers::n_global_rows(matrix);
153  (void)global_length; // work around compiler warning about unused
154  // function in release mode
155  Assert(global_size ==
156  static_cast<size_type>(
157  TrilinosWrappers::global_length(distributed_constant_modes)),
158  ExcDimensionMismatch(global_size,
160  distributed_constant_modes)));
161  const bool constant_modes_are_global =
162  additional_data.constant_modes[0].size() == global_size;
163  const size_type my_size = domain_map.NumMyElements();
164 
165  // Reshape null space as a contiguous vector of doubles so that
166  // Trilinos can read from it.
167  const size_type expected_mode_size =
168  constant_modes_are_global ? global_size : my_size;
169  for (size_type d = 0; d < constant_modes_dimension; ++d)
170  {
171  Assert(
172  additional_data.constant_modes[d].size() == expected_mode_size,
173  ExcDimensionMismatch(additional_data.constant_modes[d].size(),
174  expected_mode_size));
175  for (size_type row = 0; row < my_size; ++row)
176  {
177  const TrilinosWrappers::types::int_type mode_index =
178  constant_modes_are_global ?
179  TrilinosWrappers::global_index(domain_map, row) :
180  row;
181  distributed_constant_modes[d][row] =
182  additional_data.constant_modes[d][mode_index];
183  }
184  }
185  (void)expected_mode_size;
186 
187  parameter_list.set("null space: type", "pre-computed");
188  parameter_list.set("null space: dimension",
189  distributed_constant_modes.NumVectors());
190  if (my_size > 0)
191  parameter_list.set("null space: vectors",
192  distributed_constant_modes.Values());
193  // We need to set a valid pointer to data even if there is no data on
194  // the current processor. Therefore, pass a dummy in that case
195  else
196  parameter_list.set("null space: vectors", dummy.data());
197  }
198 
199  initialize(matrix, parameter_list);
200 
201  if (additional_data.output_details)
202  {
203  ML_Epetra::MultiLevelPreconditioner *multilevel_operator =
204  dynamic_cast<ML_Epetra::MultiLevelPreconditioner *>(
205  preconditioner.get());
206  Assert(multilevel_operator != nullptr,
207  ExcMessage("Preconditioner setup failed."));
208  multilevel_operator->PrintUnused(0);
209  }
210  }
211 
212 
213 
214  void
216  const Teuchos::ParameterList &ml_parameters)
217  {
218  initialize(matrix.trilinos_matrix(), ml_parameters);
219  }
220 
221 
222 
223  void
224  PreconditionAMG::initialize(const Epetra_RowMatrix & matrix,
225  const Teuchos::ParameterList &ml_parameters)
226  {
227  preconditioner.reset();
229  std::make_shared<ML_Epetra::MultiLevelPreconditioner>(matrix,
230  ml_parameters);
231  }
232 
233 
234 
235  template <typename number>
236  void
238  const ::SparseMatrix<number> &deal_ii_sparse_matrix,
239  const AdditionalData & additional_data,
240  const double drop_tolerance,
241  const ::SparsityPattern * use_this_sparsity)
242  {
243  preconditioner.reset();
244  const size_type n_rows = deal_ii_sparse_matrix.m();
245 
246  // Init Epetra Matrix using an
247  // equidistributed map; avoid
248  // storing the nonzero
249  // elements.
250  vector_distributor = std::make_shared<Epetra_Map>(
251  static_cast<TrilinosWrappers::types::int_type>(n_rows), 0, communicator);
252 
253  if (trilinos_matrix.get() == nullptr)
254  trilinos_matrix = std::make_shared<SparseMatrix>();
255 
258  deal_ii_sparse_matrix,
259  drop_tolerance,
260  true,
261  use_this_sparsity);
262 
263  initialize(*trilinos_matrix, additional_data);
264  }
265 
266 
267 
268  void
270  {
271  ML_Epetra::MultiLevelPreconditioner *multilevel_operator =
272  dynamic_cast<ML_Epetra::MultiLevelPreconditioner *>(preconditioner.get());
273  multilevel_operator->ReComputePreconditioner();
274  }
275 
276 
277 
278  void
280  {
282  trilinos_matrix.reset();
283  }
284 
285 
286 
289  {
290  unsigned int memory = sizeof(*this);
291 
292  // todo: find a way to read out ML's data
293  // sizes
294  if (trilinos_matrix.get() != nullptr)
295  memory += trilinos_matrix->memory_consumption();
296  return memory;
297  }
298 
299 
300 
301  // explicit instantiations
302  template void
303  PreconditionAMG::initialize(const ::SparseMatrix<double> &,
304  const AdditionalData &,
305  const double,
306  const ::SparsityPattern *);
307  template void
308  PreconditionAMG::initialize(const ::SparseMatrix<float> &,
309  const AdditionalData &,
310  const double,
311  const ::SparsityPattern *);
312 
313 
314 
315 } // namespace TrilinosWrappers
316 
317 DEAL_II_NAMESPACE_CLOSE
318 
319 #endif // DEAL_II_WITH_TRILINOS
AdditionalData(const bool elliptic=true, const bool higher_order_elements=false, 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")
const Epetra_CrsMatrix & trilinos_matrix() const
TrilinosWrappers::types::int_type global_length(const Epetra_MultiVector &vector)
std::shared_ptr< Epetra_Map > vector_distributor
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)
std::shared_ptr< SparseMatrix > trilinos_matrix
void initialize(const SparseMatrix &matrix, const AdditionalData &additional_data=AdditionalData())
TrilinosWrappers::types::int_type global_index(const Epetra_BlockMap &map, const ::types::global_dof_index i)
std::shared_ptr< Epetra_Operator > preconditioner