Reference documentation for deal.II version 9.4.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\}}\)
arkode.cc
Go to the documentation of this file.
1 // ---------------------------------------------------------------------
2 //
3 // Copyright (C) 2017 - 2022 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 
17 
18 #include <deal.II/base/config.h>
19 
21 
22 #ifdef DEAL_II_WITH_SUNDIALS
23 
25 # include <deal.II/base/utilities.h>
26 
30 # ifdef DEAL_II_WITH_TRILINOS
33 # endif
34 # ifdef DEAL_II_WITH_PETSC
37 # endif
38 
41 
42 # include <arkode/arkode_arkstep.h>
43 # include <sunlinsol/sunlinsol_spgmr.h>
44 # include <sunnonlinsol/sunnonlinsol_fixedpoint.h>
45 
46 # include <iostream>
47 
49 
50 namespace SUNDIALS
51 {
52  namespace
53  {
54  template <typename VectorType>
55  int
56  explicit_function_callback(realtype tt,
57  N_Vector yy,
58  N_Vector yp,
59  void * user_data)
60  {
61  Assert(user_data != nullptr, ExcInternalError());
62  ARKode<VectorType> &solver =
63  *static_cast<ARKode<VectorType> *>(user_data);
64 
65  auto *src_yy = internal::unwrap_nvector_const<VectorType>(yy);
66  auto *dst_yp = internal::unwrap_nvector<VectorType>(yp);
67 
68  return solver.explicit_function(tt, *src_yy, *dst_yp);
69  }
70 
71 
72 
73  template <typename VectorType>
74  int
75  implicit_function_callback(realtype tt,
76  N_Vector yy,
77  N_Vector yp,
78  void * user_data)
79  {
80  Assert(user_data != nullptr, ExcInternalError());
81  ARKode<VectorType> &solver =
82  *static_cast<ARKode<VectorType> *>(user_data);
83 
84  auto *src_yy = internal::unwrap_nvector_const<VectorType>(yy);
85  auto *dst_yp = internal::unwrap_nvector<VectorType>(yp);
86 
87  return solver.implicit_function(tt, *src_yy, *dst_yp);
88  }
89 
90 
91 
92  template <typename VectorType>
93  int
94  jacobian_times_vector_callback(N_Vector v,
95  N_Vector Jv,
96  realtype t,
97  N_Vector y,
98  N_Vector fy,
99  void * user_data,
100  N_Vector)
101  {
102  Assert(user_data != nullptr, ExcInternalError());
103  ARKode<VectorType> &solver =
104  *static_cast<ARKode<VectorType> *>(user_data);
105 
106  auto *src_v = internal::unwrap_nvector_const<VectorType>(v);
107  auto *src_y = internal::unwrap_nvector_const<VectorType>(y);
108  auto *src_fy = internal::unwrap_nvector_const<VectorType>(fy);
109 
110  auto *dst_Jv = internal::unwrap_nvector<VectorType>(Jv);
111 
112  return solver.jacobian_times_vector(*src_v, *dst_Jv, t, *src_y, *src_fy);
113  }
114 
115 
116 
117  template <typename VectorType>
118  int
119  jacobian_times_vector_setup_callback(realtype t,
120  N_Vector y,
121  N_Vector fy,
122  void * user_data)
123  {
124  Assert(user_data != nullptr, ExcInternalError());
125  ARKode<VectorType> &solver =
126  *static_cast<ARKode<VectorType> *>(user_data);
127 
128  auto *src_y = internal::unwrap_nvector_const<VectorType>(y);
129  auto *src_fy = internal::unwrap_nvector_const<VectorType>(fy);
130 
131  return solver.jacobian_times_setup(t, *src_y, *src_fy);
132  }
133 
134 
135 
136  template <typename VectorType>
137  int
138  solve_with_jacobian_callback(realtype t,
139  N_Vector y,
140  N_Vector fy,
141  N_Vector r,
142  N_Vector z,
143  realtype gamma,
144  realtype delta,
145  int lr,
146  void * user_data)
147  {
148  Assert(user_data != nullptr, ExcInternalError());
149  ARKode<VectorType> &solver =
150  *static_cast<ARKode<VectorType> *>(user_data);
151 
152  auto *src_y = internal::unwrap_nvector_const<VectorType>(y);
153  auto *src_fy = internal::unwrap_nvector_const<VectorType>(fy);
154  auto *src_r = internal::unwrap_nvector_const<VectorType>(r);
155 
156  auto *dst_z = internal::unwrap_nvector<VectorType>(z);
157 
158  return solver.jacobian_preconditioner_solve(
159  t, *src_y, *src_fy, *src_r, *dst_z, gamma, delta, lr);
160  }
161 
162 
163 
164  template <typename VectorType>
165  int
166  jacobian_solver_setup_callback(realtype t,
167  N_Vector y,
168  N_Vector fy,
169  booleantype jok,
170  booleantype *jcurPtr,
171  realtype gamma,
172  void * user_data)
173  {
174  Assert(user_data != nullptr, ExcInternalError());
175  ARKode<VectorType> &solver =
176  *static_cast<ARKode<VectorType> *>(user_data);
177 
178  auto *src_y = internal::unwrap_nvector_const<VectorType>(y);
179  auto *src_fy = internal::unwrap_nvector_const<VectorType>(fy);
180 
181  return solver.jacobian_preconditioner_setup(
182  t, *src_y, *src_fy, jok, *jcurPtr, gamma);
183  }
184 
185 
186 
187  template <typename VectorType>
188  int
189  mass_matrix_times_vector_callback(N_Vector v,
190  N_Vector Mv,
191  realtype t,
192  void * mtimes_data)
193  {
194  Assert(mtimes_data != nullptr, ExcInternalError());
195  ARKode<VectorType> &solver =
196  *static_cast<ARKode<VectorType> *>(mtimes_data);
197 
198  auto *src_v = internal::unwrap_nvector_const<VectorType>(v);
199  auto *dst_Mv = internal::unwrap_nvector<VectorType>(Mv);
200 
201  return solver.mass_times_vector(t, *src_v, *dst_Mv);
202  }
203 
204 
205 
206  template <typename VectorType>
207  int
208  mass_matrix_times_vector_setup_callback(realtype t, void *mtimes_data)
209  {
210  Assert(mtimes_data != nullptr, ExcInternalError());
211  ARKode<VectorType> &solver =
212  *static_cast<ARKode<VectorType> *>(mtimes_data);
213 
214  return solver.mass_times_setup(t);
215  }
216 
217 
218 
219  template <typename VectorType>
220  int
221  solve_with_mass_matrix_callback(realtype t,
222  N_Vector r,
223  N_Vector z,
224  realtype delta,
225  int lr,
226  void * user_data)
227  {
228  Assert(user_data != nullptr, ExcInternalError());
229  ARKode<VectorType> &solver =
230  *static_cast<ARKode<VectorType> *>(user_data);
231 
232  auto *src_r = internal::unwrap_nvector_const<VectorType>(r);
233  auto *dst_z = internal::unwrap_nvector<VectorType>(z);
234 
235  return solver.mass_preconditioner_solve(t, *src_r, *dst_z, delta, lr);
236  }
237 
238 
239 
240  template <typename VectorType>
241  int
242  mass_matrix_solver_setup_callback(realtype t, void *user_data)
243  {
244  Assert(user_data != nullptr, ExcInternalError());
245  ARKode<VectorType> &solver =
246  *static_cast<ARKode<VectorType> *>(user_data);
247 
248  return solver.mass_preconditioner_setup(t);
249  }
250  } // namespace
251 
252 
253  template <typename VectorType>
255  : ARKode(data, MPI_COMM_SELF)
256  {}
257 
258 
259  template <typename VectorType>
261  const MPI_Comm & mpi_comm)
262  : data(data)
263  , arkode_mem(nullptr)
264 # if DEAL_II_SUNDIALS_VERSION_GTE(6, 0, 0)
265  , arkode_ctx(nullptr)
266 # endif
267  , mpi_communicator(mpi_comm)
268  , last_end_time(data.initial_time)
269  {
271 
272 # if DEAL_II_SUNDIALS_VERSION_GTE(6, 0, 0)
273  // SUNDIALS will always duplicate communicators if we provide them. This
274  // can cause problems if SUNDIALS is configured with MPI and we pass along
275  // MPI_COMM_SELF in a serial application as MPI won't be
276  // initialized. Hence, work around that by just not providing a
277  // communicator in that case.
278  const int status =
279  SUNContext_Create(mpi_communicator == MPI_COMM_SELF ? nullptr :
281  &arkode_ctx);
282  (void)status;
283  AssertARKode(status);
284 # endif
285  }
286 
287 
288 
289  template <typename VectorType>
291  {
292  ARKStepFree(&arkode_mem);
293 
294 # if DEAL_II_SUNDIALS_VERSION_GTE(6, 0, 0)
295  const int status = SUNContext_Free(&arkode_ctx);
296  (void)status;
297  AssertARKode(status);
298 # endif
299  }
300 
301 
302 
303  template <typename VectorType>
304  unsigned int
305  ARKode<VectorType>::solve_ode(VectorType &solution)
306  {
307  DiscreteTime time(data.initial_time,
308  data.final_time,
309  data.initial_step_size);
310 
311  return do_evolve_time(solution, time, /* force_solver_restart = */ true);
312  }
313 
314 
315 
316  template <typename VectorType>
317  unsigned int
319  const double intermediate_time,
320  const bool reset_solver)
321  {
322  AssertThrow(
323  intermediate_time > last_end_time,
324  ::ExcMessage(
325  "The requested intermediate time is smaller than the last requested "
326  "intermediate time."));
327 
328  const bool do_reset = reset_solver || arkode_mem == nullptr;
329  DiscreteTime time(last_end_time, intermediate_time, data.initial_step_size);
330  return do_evolve_time(solution, time, do_reset);
331  }
332 
333 
334 
335  template <typename VectorType>
336  int
337  ARKode<VectorType>::do_evolve_time(VectorType & solution,
338  DiscreteTime &time,
339  const bool do_reset)
340  {
341  if (do_reset)
342  {
343  reset(time.get_current_time(), time.get_next_step_size(), solution);
344  if (output_step)
345  output_step(time.get_current_time(),
346  solution,
347  time.get_step_number());
348  }
349  else
350  {
351  // If we don't do a full reset then we still need to fix the end time.
352  // In SUNDIALS 6 and later, SUNDIALS will not do timesteps if the
353  // current time is past the set end point (i.e., ARKStepEvolve will
354  // return ARK_TSTOP_RETURN).
355  const int status = ARKStepSetStopTime(arkode_mem, time.get_end_time());
356  (void)status;
357  AssertARKode(status);
358  }
359 
360  auto solution_nvector = internal::make_nvector_view(solution
361 # if DEAL_II_SUNDIALS_VERSION_GTE(6, 0, 0)
362  ,
363  arkode_ctx
364 # endif
365  );
366 
367  while (!time.is_at_end())
368  {
369  time.set_desired_next_step_size(data.output_period);
370 
371  // Let ARKode advance time by one period:
372  double actual_next_time;
373  const auto status = ARKStepEvolve(arkode_mem,
374  time.get_next_time(),
375  solution_nvector,
376  &actual_next_time,
377  ARK_NORMAL);
378  (void)status;
379  AssertARKode(status);
380 
381  // Then reflect this time advancement in our own DiscreteTime object:
382  time.set_next_step_size(actual_next_time - time.get_current_time());
383  time.advance_time();
384 
385  // Finally check whether resets or output calls are desired at this
386  // time:
387  while (solver_should_restart(time.get_current_time(), solution))
388  reset(time.get_current_time(),
389  time.get_previous_step_size(),
390  solution);
391 
392  if (output_step)
393  output_step(time.get_current_time(),
394  solution,
395  time.get_step_number());
396  }
397  last_end_time = time.get_current_time();
398  return time.get_step_number();
399  }
400 
401 
402 
403  template <typename VectorType>
404  void
405  ARKode<VectorType>::reset(const double current_time,
406  const double current_time_step,
407  const VectorType &solution)
408  {
409  last_end_time = current_time;
410  int status;
411  (void)status;
412 
413 # if DEAL_II_SUNDIALS_VERSION_GTE(6, 0, 0)
414  status = SUNContext_Free(&arkode_ctx);
415  AssertARKode(status);
416  // Same comment applies as in class constructor:
417  status =
418  SUNContext_Create(mpi_communicator == MPI_COMM_SELF ? nullptr :
419  &mpi_communicator,
420  &arkode_ctx);
421  AssertARKode(status);
422 # endif
423 
424  if (arkode_mem)
425  {
426  ARKStepFree(&arkode_mem);
427  // Initialization is version-dependent: do that in a moment
428  }
429 
430  // just a view on the memory in solution, all write operations on yy by
431  // ARKODE will automatically be mirrored to solution
432  auto initial_condition_nvector = internal::make_nvector_view(solution
433 # if DEAL_II_SUNDIALS_VERSION_GTE(6, 0, 0)
434  ,
435  arkode_ctx
436 # endif
437  );
438 
439  Assert(explicit_function || implicit_function,
440  ExcFunctionNotProvided("explicit_function || implicit_function"));
441 
442  arkode_mem = ARKStepCreate(
443  explicit_function ? &explicit_function_callback<VectorType> : nullptr,
444  implicit_function ? &implicit_function_callback<VectorType> : nullptr,
445  current_time,
446  initial_condition_nvector
447 # if DEAL_II_SUNDIALS_VERSION_GTE(6, 0, 0)
448  ,
449  arkode_ctx
450 # endif
451  );
452  Assert(arkode_mem != nullptr, ExcInternalError());
453 
454  if (get_local_tolerances)
455  {
456  const auto abs_tols = internal::make_nvector_view(get_local_tolerances()
457 # if DEAL_II_SUNDIALS_VERSION_GTE(6, 0, 0)
458  ,
459  arkode_ctx
460 # endif
461  );
462  status =
463  ARKStepSVtolerances(arkode_mem, data.relative_tolerance, abs_tols);
464  AssertARKode(status);
465  }
466  else
467  {
468  status = ARKStepSStolerances(arkode_mem,
469  data.relative_tolerance,
470  data.absolute_tolerance);
471  AssertARKode(status);
472  }
473 
474  // for version 4.0.0 this call must be made before solver settings
475  status = ARKStepSetUserData(arkode_mem, this);
476  AssertARKode(status);
477 
478  setup_system_solver(solution);
479 
480  setup_mass_solver(solution);
481 
482  status = ARKStepSetInitStep(arkode_mem, current_time_step);
483  AssertARKode(status);
484 
485  status = ARKStepSetStopTime(arkode_mem, data.final_time);
486  AssertARKode(status);
487 
488  status = ARKStepSetOrder(arkode_mem, data.maximum_order);
489  AssertARKode(status);
490 
491  if (custom_setup)
492  custom_setup(arkode_mem);
493  }
494 
495 
496 
497  template <typename VectorType>
498  void
499  ARKode<VectorType>::setup_system_solver(const VectorType &solution)
500  {
501  // no point in setting up a solver when there is no linear system
502  if (!implicit_function)
503  return;
504 
505  int status;
506  (void)status;
507  // Initialize solver
508  // currently only iterative linear solvers are supported
509  if (jacobian_times_vector)
510  {
511  SUNLinearSolver sun_linear_solver;
512  if (solve_linearized_system)
513  {
514  linear_solver =
515  std::make_unique<internal::LinearSolverWrapper<VectorType>>(
516  solve_linearized_system
517 # if DEAL_II_SUNDIALS_VERSION_GTE(6, 0, 0)
518  ,
519  arkode_ctx
520 # endif
521  );
522  sun_linear_solver = *linear_solver;
523  }
524  else
525  {
526  // use default solver from SUNDIALS
527  // TODO give user options
528  auto y_template = internal::make_nvector_view(solution
529 # if DEAL_II_SUNDIALS_VERSION_GTE(6, 0, 0)
530  ,
531  arkode_ctx
532 # endif
533  );
534 # if DEAL_II_SUNDIALS_VERSION_LT(6, 0, 0)
535  sun_linear_solver =
536  SUNLinSol_SPGMR(y_template,
537  PREC_NONE,
538  0 /*krylov subvectors, 0 uses default*/);
539 # else
540  sun_linear_solver =
541  SUNLinSol_SPGMR(y_template,
542  PREC_NONE,
543  0 /*krylov subvectors, 0 uses default*/,
544  arkode_ctx);
545 # endif
546  }
547  status = ARKStepSetLinearSolver(arkode_mem, sun_linear_solver, nullptr);
548  AssertARKode(status);
549  status = ARKStepSetJacTimes(
550  arkode_mem,
551  jacobian_times_setup ?
552  jacobian_times_vector_setup_callback<VectorType> :
553  nullptr,
554  jacobian_times_vector_callback<VectorType>);
555  AssertARKode(status);
556  if (jacobian_preconditioner_solve)
557  {
558  status = ARKStepSetPreconditioner(
559  arkode_mem,
560  jacobian_preconditioner_setup ?
561  jacobian_solver_setup_callback<VectorType> :
562  nullptr,
563  solve_with_jacobian_callback<VectorType>);
564  AssertARKode(status);
565  }
566  if (data.implicit_function_is_linear)
567  {
568  status = ARKStepSetLinear(
569  arkode_mem, data.implicit_function_is_time_independent ? 0 : 1);
570  AssertARKode(status);
571  }
572  }
573  else
574  {
575  auto y_template = internal::make_nvector_view(solution
576 # if DEAL_II_SUNDIALS_VERSION_GTE(6, 0, 0)
577  ,
578  arkode_ctx
579 # endif
580  );
581 
582 # if DEAL_II_SUNDIALS_VERSION_LT(6, 0, 0)
583  SUNNonlinearSolver fixed_point_solver =
584  SUNNonlinSol_FixedPoint(y_template,
585  data.anderson_acceleration_subspace);
586 # else
587  SUNNonlinearSolver fixed_point_solver =
588  SUNNonlinSol_FixedPoint(y_template,
589  data.anderson_acceleration_subspace,
590  arkode_ctx);
591 # endif
592 
593  status = ARKStepSetNonlinearSolver(arkode_mem, fixed_point_solver);
594  AssertARKode(status);
595  }
596 
597  status =
598  ARKStepSetMaxNonlinIters(arkode_mem, data.maximum_non_linear_iterations);
599  AssertARKode(status);
600  }
601 
602 
603 
604  template <typename VectorType>
605  void
606  ARKode<VectorType>::setup_mass_solver(const VectorType &solution)
607  {
608  int status;
609  (void)status;
610 
611  if (mass_times_vector)
612  {
613  SUNLinearSolver sun_mass_linear_solver;
614  if (solve_mass)
615  {
616  mass_solver =
617  std::make_unique<internal::LinearSolverWrapper<VectorType>>(
618  solve_mass
619 # if DEAL_II_SUNDIALS_VERSION_GTE(6, 0, 0)
620  ,
621  arkode_ctx
622 # endif
623  );
624  sun_mass_linear_solver = *mass_solver;
625  }
626  else
627  {
628  auto y_template = internal::make_nvector_view(solution
629 # if DEAL_II_SUNDIALS_VERSION_GTE(6, 0, 0)
630  ,
631  arkode_ctx
632 # endif
633  );
634 # if DEAL_II_SUNDIALS_VERSION_LT(6, 0, 0)
635  sun_mass_linear_solver =
636  SUNLinSol_SPGMR(y_template,
637  PREC_NONE,
638  0 /*krylov subvectors, 0 uses default*/);
639 # else
640  sun_mass_linear_solver =
641  SUNLinSol_SPGMR(y_template,
642  PREC_NONE,
643  0 /*krylov subvectors, 0 uses default*/,
644  arkode_ctx);
645 # endif
646  }
647  booleantype mass_time_dependent =
648  data.mass_is_time_independent ? SUNFALSE : SUNTRUE;
649  status = ARKStepSetMassLinearSolver(arkode_mem,
650  sun_mass_linear_solver,
651  nullptr,
652  mass_time_dependent);
653  AssertARKode(status);
654  status = ARKStepSetMassTimes(
655  arkode_mem,
656  mass_times_setup ?
657  mass_matrix_times_vector_setup_callback<VectorType> :
658  nullptr,
659  mass_matrix_times_vector_callback<VectorType>,
660  this);
661  AssertARKode(status);
662 
663  if (mass_preconditioner_solve)
664  {
665  status = ARKStepSetMassPreconditioner(
666  arkode_mem,
667  mass_preconditioner_setup ?
668  mass_matrix_solver_setup_callback<VectorType> :
669  nullptr,
670  solve_with_mass_matrix_callback<VectorType>);
671  AssertARKode(status);
672  }
673  }
674  }
675 
676 
677 
678  template <typename VectorType>
679  void
681  {
682  reinit_vector = [](VectorType &) {
683  AssertThrow(false, ExcFunctionNotProvided("reinit_vector"));
684  };
685 
686  solver_should_restart = [](const double, VectorType &) -> bool {
687  return false;
688  };
689  }
690 
691 
692 
693  template <typename VectorType>
694  void *
696  {
697  return arkode_mem;
698  }
699 
700  template class ARKode<Vector<double>>;
701  template class ARKode<BlockVector<double>>;
702 
705 
706 # ifdef DEAL_II_WITH_MPI
707 
708 # ifdef DEAL_II_WITH_TRILINOS
711 
712 # endif // DEAL_II_WITH_TRILINOS
713 
714 # ifdef DEAL_II_WITH_PETSC
715 # ifndef PETSC_USE_COMPLEX
716  template class ARKode<PETScWrappers::MPI::Vector>;
718 # endif // PETSC_USE_COMPLEX
719 # endif // DEAL_II_WITH_PETSC
720 
721 # endif // DEAL_II_WITH_MPI
722 
723 } // namespace SUNDIALS
724 
726 
727 #endif
#define AssertARKode(code)
Definition: arkode.h:60
double get_next_step_size() const
void set_desired_next_step_size(const double time_step_size)
unsigned int get_step_number() const
bool is_at_end() const
double get_current_time() const
void set_next_step_size(const double time_step_size)
double get_next_time() const
double get_previous_step_size() const
void advance_time()
double get_end_time() const
void setup_mass_solver(const VectorType &solution)
Definition: arkode.cc:606
ARKode(const AdditionalData &data=AdditionalData())
Definition: arkode.cc:254
void * get_arkode_memory() const
Definition: arkode.cc:695
int do_evolve_time(VectorType &solution, ::DiscreteTime &time, const bool do_reset)
Definition: arkode.cc:337
MPI_Comm mpi_communicator
Definition: arkode.h:1071
void reset(const double t, const double h, const VectorType &y)
Definition: arkode.cc:405
SUNContext arkode_ctx
Definition: arkode.h:1064
void set_functions_to_trigger_an_assert()
Definition: arkode.cc:680
unsigned int solve_ode(VectorType &solution)
Definition: arkode.cc:305
void setup_system_solver(const VectorType &solution)
Definition: arkode.cc:499
unsigned int solve_ode_incrementally(VectorType &solution, const double intermediate_time, const bool reset_solver=false)
Definition: arkode.cc:318
#define DEAL_II_NAMESPACE_OPEN
Definition: config.h:442
#define DEAL_II_SUNDIALS_VERSION_GTE(major, minor, patch)
Definition: config.h:347
#define DEAL_II_NAMESPACE_CLOSE
Definition: config.h:443
static ::ExceptionBase & ExcInternalError()
#define Assert(cond, exc)
Definition: exceptions.h:1473
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
Definition: exceptions.h:1583
void implicit_function(Triangulation< dim, 3 > &tria, const Function< 3 > &implicit_function, const CGALWrappers::AdditionalData< dim > &data=CGALWrappers::AdditionalData< dim >{}, const Point< 3 > &interior_point=Point< 3 >(), const double &outer_ball_radius=1.0)
long double gamma(const unsigned int n)