Reference documentation for deal.II version 9.3.0
\(\newcommand{\dealvcentcolon}{\mathrel{\mathop{:}}}\) \(\newcommand{\dealcoloneq}{\dealvcentcolon\mathrel{\mkern-1.2mu}=}\) \(\newcommand{\jump}[1]{\left[\!\left[ #1 \right]\!\right]}\) \(\newcommand{\average}[1]{\left\{\!\left\{ #1 \right\}\!\right\}}\)
ida.cc
Go to the documentation of this file.
1 //-----------------------------------------------------------
2 //
3 // Copyright (C) 2015 - 2020 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 #include <deal.II/base/config.h>
16 
18 
19 #include <deal.II/sundials/ida.h>
20 
21 #ifdef DEAL_II_WITH_SUNDIALS
22 # include <deal.II/base/utilities.h>
23 
25 
28 # ifdef DEAL_II_WITH_TRILINOS
31 # endif
32 # ifdef DEAL_II_WITH_PETSC
35 # endif
36 
38 
39 # include <sundials/sundials_config.h>
40 # if DEAL_II_SUNDIALS_VERSION_LT(4, 0, 0)
41 # ifdef DEAL_II_SUNDIALS_WITH_IDAS
42 # include <idas/idas_impl.h>
43 # else
44 # include <ida/ida_impl.h>
45 # endif
46 # endif
47 # if DEAL_II_SUNDIALS_VERSION_LT(5, 0, 0)
49 # endif
50 # include <iomanip>
51 # include <iostream>
52 
54 
55 namespace SUNDIALS
56 {
57  using namespace internal;
58 
59  namespace
60  {
61  template <typename VectorType>
62  int
63  t_dae_residual(realtype tt,
64  N_Vector yy,
65  N_Vector yp,
66  N_Vector rr,
67  void * user_data)
68  {
69  IDA<VectorType> &solver = *static_cast<IDA<VectorType> *>(user_data);
70 
71  auto *src_yy = internal::unwrap_nvector_const<VectorType>(yy);
72  auto *src_yp = internal::unwrap_nvector_const<VectorType>(yp);
73  auto *residual = internal::unwrap_nvector<VectorType>(rr);
74 
75  int err = solver.residual(tt, *src_yy, *src_yp, *residual);
76 
77  return err;
78  }
79 
80 
81 
82 # if DEAL_II_SUNDIALS_VERSION_LT(4, 0, 0)
83  template <typename VectorType>
84  int
85  t_dae_lsetup(IDAMem IDA_mem,
86  N_Vector yy,
87  N_Vector yp,
88  N_Vector resp,
89  N_Vector tmp1,
90  N_Vector tmp2,
91  N_Vector tmp3)
92  {
93  (void)tmp1;
94  (void)tmp2;
95  (void)tmp3;
96  (void)resp;
97  IDA<VectorType> &solver =
98  *static_cast<IDA<VectorType> *>(IDA_mem->ida_user_data);
99 
100  auto *src_yy = internal::unwrap_nvector_const<VectorType>(yy);
101  auto *src_yp = internal::unwrap_nvector_const<VectorType>(yp);
102 
103  int err = solver.setup_jacobian(IDA_mem->ida_tn,
104  *src_yy,
105  *src_yp,
106  IDA_mem->ida_cj);
107 
108  return err;
109  }
110 
111 
112 
113  template <typename VectorType>
114  int
115  t_dae_solve(IDAMem IDA_mem,
116  N_Vector b,
117  N_Vector weight,
118  N_Vector yy,
119  N_Vector yp,
120  N_Vector resp)
121  {
122  (void)weight;
123  (void)yy;
124  (void)yp;
125  (void)resp;
126  IDA<VectorType> &solver =
127  *static_cast<IDA<VectorType> *>(IDA_mem->ida_user_data);
129 
130  typename VectorMemory<VectorType>::Pointer dst(mem);
131  solver.reinit_vector(*dst);
132 
133  auto *src = internal::unwrap_nvector<VectorType>(b);
134 
135  int err = solver.solve_jacobian_system(*src, *dst);
136  *src = *dst;
137 
138  return err;
139  }
140 
141 
142 
143 # else
144  template <typename VectorType>
145  int
146  t_dae_jacobian_setup(realtype tt,
147  realtype cj,
148  N_Vector yy,
149  N_Vector yp,
150  N_Vector /* residual */,
151  SUNMatrix /* ignored */,
152  void *user_data,
153  N_Vector /* tmp1 */,
154  N_Vector /* tmp2 */,
155  N_Vector /* tmp3 */)
156  {
157  Assert(user_data != nullptr, ExcInternalError());
158  IDA<VectorType> &solver = *static_cast<IDA<VectorType> *>(user_data);
159 
160  auto *src_yy = internal::unwrap_nvector_const<VectorType>(yy);
161  auto *src_yp = internal::unwrap_nvector_const<VectorType>(yp);
162 
163  int err = solver.setup_jacobian(tt, *src_yy, *src_yp, cj);
164 
165  return err;
166  }
167 
168 
169 
170  template <typename VectorType>
171  int
172  t_dae_solve_jacobian_system(SUNLinearSolver LS,
173  SUNMatrix /*ignored*/,
174  N_Vector x,
175  N_Vector b,
176  realtype tol)
177  {
178  IDA<VectorType> &solver = *static_cast<IDA<VectorType> *>(LS->content);
179 
180  auto *src_b = internal::unwrap_nvector_const<VectorType>(b);
181  auto *dst_x = internal::unwrap_nvector<VectorType>(x);
182  int err = 0;
183  if (solver.solve_with_jacobian)
184  err = solver.solve_with_jacobian(*src_b, *dst_x, tol);
185  else if (solver.solve_jacobian_system)
186  err = solver.solve_jacobian_system(*src_b, *dst_x);
187  else
188  // We have already checked this outside, so we should never get here.
189  Assert(false, ExcInternalError());
190 
191  return err;
192  }
193 # endif
194  } // namespace
195 
196 
197 
198  template <typename VectorType>
199  IDA<VectorType>::IDA(const AdditionalData &data, const MPI_Comm &mpi_comm)
200  : data(data)
201  , ida_mem(nullptr)
202  , communicator(is_serial_vector<VectorType>::value ?
203  MPI_COMM_SELF :
204  Utilities::MPI::duplicate_communicator(mpi_comm))
205  {
207  }
208 
209  template <typename VectorType>
211  {
212  if (ida_mem)
213  IDAFree(&ida_mem);
214 # ifdef DEAL_II_WITH_MPI
216  {
217  const int ierr = MPI_Comm_free(&communicator);
218  (void)ierr;
219  AssertNothrow(ierr == MPI_SUCCESS, ExcMPI(ierr));
220  }
221 # endif
222  }
223 
224 
225 
226  template <typename VectorType>
227  unsigned int
228  IDA<VectorType>::solve_dae(VectorType &solution, VectorType &solution_dot)
229  {
230  double t = data.initial_time;
231  double h = data.initial_step_size;
232  unsigned int step_number = 0;
233 
234  int status;
235  (void)status;
236 
237  reset(data.initial_time, data.initial_step_size, solution, solution_dot);
238 
239  // The solution is stored in
240  // solution. Here we take only a
241  // view of it.
242 
243  double next_time = data.initial_time;
244 
245  output_step(0, solution, solution_dot, 0);
246 
247  while (t < data.final_time)
248  {
249  next_time += data.output_period;
250 
251  auto yy = internal::make_nvector_view(solution);
252  auto yp = internal::make_nvector_view(solution_dot);
253 
254  status = IDASolve(ida_mem, next_time, &t, yy, yp, IDA_NORMAL);
255  AssertIDA(status);
256 
257  status = IDAGetLastStep(ida_mem, &h);
258  AssertIDA(status);
259 
260  while (solver_should_restart(t, solution, solution_dot))
261  reset(t, h, solution, solution_dot);
262 
263  step_number++;
264 
265  output_step(t, solution, solution_dot, step_number);
266  }
267 
268  return step_number;
269  }
270 
271 
272 
273  template <typename VectorType>
274  void
275  IDA<VectorType>::reset(const double current_time,
276  const double current_time_step,
277  VectorType & solution,
278  VectorType & solution_dot)
279  {
280  bool first_step = (current_time == data.initial_time);
281 
282  if (ida_mem)
283  IDAFree(&ida_mem);
284 
285  ida_mem = IDACreate();
286 
287  int status;
288  (void)status;
289 
290  auto yy = internal::make_nvector_view(solution);
291  auto yp = internal::make_nvector_view(solution_dot);
292 
293  status = IDAInit(ida_mem, t_dae_residual<VectorType>, current_time, yy, yp);
294  AssertIDA(status);
295  if (get_local_tolerances)
296  {
297  const auto abs_tols =
298  internal::make_nvector_view(get_local_tolerances());
299  status = IDASVtolerances(ida_mem, data.relative_tolerance, abs_tols);
300  AssertIDA(status);
301  }
302  else
303  {
304  status = IDASStolerances(ida_mem,
305  data.relative_tolerance,
306  data.absolute_tolerance);
307  AssertIDA(status);
308  }
309 
310  status = IDASetInitStep(ida_mem, current_time_step);
311  AssertIDA(status);
312 
313  status = IDASetUserData(ida_mem, this);
314  AssertIDA(status);
315 
316  if (data.ic_type == AdditionalData::use_y_diff ||
317  data.reset_type == AdditionalData::use_y_diff ||
318  data.ignore_algebraic_terms_for_errors)
319  {
320  VectorType diff_comp_vector(solution);
321  diff_comp_vector = 0.0;
322  auto dc = differential_components();
323  for (auto i = dc.begin(); i != dc.end(); ++i)
324  diff_comp_vector[*i] = 1.0;
325  diff_comp_vector.compress(VectorOperation::insert);
326 
327  const auto diff_id = internal::make_nvector_view(diff_comp_vector);
328  status = IDASetId(ida_mem, diff_id);
329  AssertIDA(status);
330  }
331 
332  status = IDASetSuppressAlg(ida_mem, data.ignore_algebraic_terms_for_errors);
333  AssertIDA(status);
334 
335  // status = IDASetMaxNumSteps(ida_mem, max_steps);
336  status = IDASetStopTime(ida_mem, data.final_time);
337  AssertIDA(status);
338 
339  status = IDASetMaxNonlinIters(ida_mem, data.maximum_non_linear_iterations);
340  AssertIDA(status);
341 
342  // Initialize solver
343 # if DEAL_II_SUNDIALS_VERSION_LT(4, 0, 0)
344  auto IDA_mem = static_cast<IDAMem>(ida_mem);
345 
346  IDA_mem->ida_lsetup = t_dae_lsetup<VectorType>;
347 
348  if (solve_jacobian_system)
349  IDA_mem->ida_lsolve = t_dae_solve<VectorType>;
350  else
351  AssertThrow(false, ExcFunctionNotProvided("solve_jacobian_system"));
352 # if DEAL_II_SUNDIALS_VERSION_LT(3, 0, 0)
353  IDA_mem->ida_setupNonNull = true;
354 # endif
355 # else
356  SUNMatrix J = nullptr;
357  SUNLinearSolver LS = nullptr;
358 
359  // and attach it to the SUNLinSol object. The functions that will get
360  // called do not actually receive the IDAMEM object, just the LS
361  // object, so we have to store a pointer to the current
362  // object in the LS object
363  LS = SUNLinSolNewEmpty();
364  LS->content = this;
365 
366  LS->ops->gettype = [](SUNLinearSolver /*ignored*/) -> SUNLinearSolver_Type {
367  return SUNLINEARSOLVER_MATRIX_ITERATIVE;
368  };
369 
370  LS->ops->free = [](SUNLinearSolver LS) -> int {
371  if (LS->content)
372  {
373  LS->content = nullptr;
374  }
375  if (LS->ops)
376  {
377  free(LS->ops);
378  LS->ops = nullptr;
379  }
380  free(LS);
381  LS = nullptr;
382  return 0;
383  };
384 
385  AssertThrow(solve_jacobian_system || solve_with_jacobian,
386  ExcFunctionNotProvided(
387  "solve_jacobian_system or solve_with_jacobian"));
388  LS->ops->solve = t_dae_solve_jacobian_system<VectorType>;
389 
390  // When we set an iterative solver IDA requires that resid is provided. From
391  // SUNDIALS docs If an iterative method computes the preconditioned initial
392  // residual and returns with a successful solve without performing any
393  // iterations (i.e., either the initial guess or the preconditioner is
394  // sufficiently accurate), then this optional routine may be called by the
395  // SUNDIALS package. This routine should return the N_Vector containing the
396  // preconditioned initial residual vector.
397  LS->ops->resid = [](SUNLinearSolver /*ignored*/) -> N_Vector {
398  return nullptr;
399  };
400  // When we set an iterative solver IDA requires that last number of
401  // iteration is provided. Since we can't know what kind of solver the user
402  // has provided we set 1. This is clearly suboptimal.
403  LS->ops->numiters = [](SUNLinearSolver /*ignored*/) -> int { return 1; };
404  // Even though we don't use it, IDA still wants us to set some
405  // kind of matrix object for the nonlinear solver. This is because
406  // if we don't set it, it won't call the functions that set up
407  // the matrix object (i.e., the argument to the 'IDASetJacFn'
408  // function below).
409  J = SUNMatNewEmpty();
410  J->content = this;
411 
412  J->ops->getid = [](SUNMatrix /*ignored*/) -> SUNMatrix_ID {
413  return SUNMATRIX_CUSTOM;
414  };
415 
416  J->ops->destroy = [](SUNMatrix A) {
417  if (A->content)
418  {
419  A->content = nullptr;
420  }
421  if (A->ops)
422  {
423  free(A->ops);
424  A->ops = nullptr;
425  }
426  free(A);
427  A = nullptr;
428  };
429 
430  // Now set the linear system and Jacobian objects in the solver:
431  status = IDASetLinearSolver(ida_mem, LS, J);
432  AssertIDA(status);
433 
434  status = IDASetLSNormFactor(ida_mem, data.ls_norm_factor);
435  AssertIDA(status);
436  // Finally tell IDA about
437  // it as well. The manual says that this must happen *after*
438  // calling IDASetLinearSolver
439  status = IDASetJacFn(ida_mem, &t_dae_jacobian_setup<VectorType>);
440  AssertIDA(status);
441 # endif
442  status = IDASetMaxOrd(ida_mem, data.maximum_order);
443  AssertIDA(status);
444 
446  if (first_step)
447  type = data.ic_type;
448  else
449  type = data.reset_type;
450 
451  status =
452  IDASetMaxNumItersIC(ida_mem, data.maximum_non_linear_iterations_ic);
453  AssertIDA(status);
454 
455  if (type == AdditionalData::use_y_dot)
456  {
457  // (re)initialization of the vectors
458  status =
459  IDACalcIC(ida_mem, IDA_Y_INIT, current_time + current_time_step);
460  AssertIDA(status);
461 
462  status = IDAGetConsistentIC(ida_mem, yy, yp);
463  AssertIDA(status);
464  }
465  else if (type == AdditionalData::use_y_diff)
466  {
467  status =
468  IDACalcIC(ida_mem, IDA_YA_YDP_INIT, current_time + current_time_step);
469  AssertIDA(status);
470 
471  status = IDAGetConsistentIC(ida_mem, yy, yp);
472  AssertIDA(status);
473  }
474  }
475 
476  template <typename VectorType>
477  void
479  {
480  reinit_vector = [](VectorType &) {
481  AssertThrow(false, ExcFunctionNotProvided("reinit_vector"));
482  };
483 
484  residual = [](const double,
485  const VectorType &,
486  const VectorType &,
487  VectorType &) -> int {
488  int ret = 0;
489  AssertThrow(false, ExcFunctionNotProvided("residual"));
490  return ret;
491  };
492 
493 
494  output_step = [](const double,
495  const VectorType &,
496  const VectorType &,
497  const unsigned int) { return; };
498 
499  solver_should_restart =
500  [](const double, VectorType &, VectorType &) -> bool { return false; };
501 
502  differential_components = [&]() -> IndexSet {
504  typename VectorMemory<VectorType>::Pointer v(mem);
505  reinit_vector(*v);
506  return v->locally_owned_elements();
507  };
508  }
509 
510  template class IDA<Vector<double>>;
511  template class IDA<BlockVector<double>>;
512 
513 # ifdef DEAL_II_WITH_MPI
514 
515 # ifdef DEAL_II_WITH_TRILINOS
516  template class IDA<TrilinosWrappers::MPI::Vector>;
518 # endif // DEAL_II_WITH_TRILINOS
519 
520 # ifdef DEAL_II_WITH_PETSC
521 # ifndef PETSC_USE_COMPLEX
522  template class IDA<PETScWrappers::MPI::Vector>;
524 # endif // PETSC_USE_COMPLEX
525 # endif // DEAL_II_WITH_PETSC
526 
527 # endif // DEAL_II_WITH_MPI
528 
529 } // namespace SUNDIALS
530 
532 
533 #endif // DEAL_II_WITH_SUNDIALS
unsigned int solve_dae(VectorType &solution, VectorType &solution_dot)
Definition: ida.cc:228
void set_functions_to_trigger_an_assert()
Definition: ida.cc:478
void reset(const double t, const double h, VectorType &y, VectorType &yp)
Definition: ida.cc:275
IDA(const AdditionalData &data=AdditionalData(), const MPI_Comm &mpi_comm=MPI_COMM_WORLD)
Definition: ida.cc:199
#define DEAL_II_NAMESPACE_OPEN
Definition: config.h:394
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:395
static ::ExceptionBase & ExcInternalError()
#define Assert(cond, exc)
Definition: exceptions.h:1465
#define AssertNothrow(cond, exc)
Definition: exceptions.h:1528
#define AssertThrow(cond, exc)
Definition: exceptions.h:1575
#define AssertIDA(code)
Definition: ida.h:60
static const char A
SymmetricTensor< 2, dim, Number > b(const Tensor< 2, dim, Number > &F)
SUNLinearSolver SUNLinSolNewEmpty()
void free(T *&pointer)
Definition: cuda.h:97
MPI_Comm duplicate_communicator(const MPI_Comm &mpi_communicator)
Definition: mpi.cc:160