Reference documentation for deal.II version 9.4.1
\(\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\}}\)
Loading...
Searching...
No Matches
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
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
50namespace 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)
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 {
323 intermediate_time > last_end_time,
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
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
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(),
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
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
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()
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
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
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
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
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
#define Assert(cond, exc)
Definition: exceptions.h:1473
static ::ExceptionBase & ExcInternalError()
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
Definition: exceptions.h:1583