deal2lkit: A ToolKit library for Deal.II
ida_interface.cc
Go to the documentation of this file.
1 //-----------------------------------------------------------
2 //
3 // Copyright (C) 2015 by the deal2lkit authors
4 //
5 // This file is part of the deal2lkit library.
6 //
7 // The deal2lkit 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 at
12 // the top level of the deal2lkit distribution.
13 //
14 //-----------------------------------------------------------
15 
16 
18 #include <deal2lkit/utilities.h>
19 
20 #ifdef D2K_WITH_SUNDIALS
21 
22 #include <deal.II/base/utilities.h>
24 #ifdef DEAL_II_WITH_TRILINOS
28 #endif
29 #ifdef DEAL_II_WITH_PETSC
33 #endif
34 #include <deal.II/base/utilities.h>
35 
36 #include <iostream>
37 #include <iomanip>
38 #include <ida/ida_impl.h>
39 
40 
41 using namespace dealii;
42 
43 
44 D2K_NAMESPACE_OPEN
45 
46 namespace
47 {
48 
49 
50  template<typename VEC>
51  int t_dae_residual(realtype tt, N_Vector yy, N_Vector yp,
52  N_Vector rr, void *user_data)
53  {
54  IDAInterface<VEC> &solver = *static_cast<IDAInterface<VEC> *>(user_data);
55 
56  shared_ptr<VEC> src_yy = solver.create_new_vector();
57  shared_ptr<VEC> src_yp = solver.create_new_vector();
58  shared_ptr<VEC> residual = solver.create_new_vector();
59 
60  copy(*src_yy, yy);
61  copy(*src_yp, yp);
62 
63  int err = solver.residual(tt, *src_yy, *src_yp, *residual);
64 
65  copy(rr, *residual);
66 
67  return err;
68  }
69 
70 
71 
72  template<typename VEC>
73  int t_dae_lsetup(IDAMem IDA_mem,
74  N_Vector yy,
75  N_Vector yp,
76  N_Vector resp,
77  N_Vector tmp1,
78  N_Vector tmp2,
79  N_Vector tmp3)
80  {
81  (void) tmp1;
82  (void) tmp2;
83  (void) tmp3;
84  (void) resp;
85  IDAInterface<VEC> &solver = *static_cast<IDAInterface<VEC> *>(IDA_mem->ida_user_data);
86 
87  shared_ptr<VEC> src_yy = solver.create_new_vector();
88  shared_ptr<VEC> src_yp = solver.create_new_vector();
89 
90  copy(*src_yy, yy);
91  copy(*src_yp, yp);
92 
93  int err = solver.setup_jacobian(IDA_mem->ida_tn,
94  *src_yy,
95  *src_yp,
96  IDA_mem->ida_cj);
97  return err;
98  }
99 
100 
101  template<typename VEC>
102  int t_dae_solve(IDAMem IDA_mem,
103  N_Vector b,
104  N_Vector weight,
105  N_Vector yy,
106  N_Vector yp,
107  N_Vector resp)
108  {
109  (void) weight;
110  (void) yy;
111  (void) yp;
112  (void) resp;
113  IDAInterface<VEC> &solver = *static_cast<IDAInterface<VEC> *>(IDA_mem->ida_user_data);
114 
115  shared_ptr<VEC> dst = solver.create_new_vector();
116  shared_ptr<VEC> src = solver.create_new_vector();
117 
118  copy(*src, b);
119 
120  int err = solver.solve_jacobian_system(*src,
121  *dst);
122  copy(b, *dst);
123  return err;
124  }
125 
126 }
127 
128 #ifdef DEAL_II_WITH_MPI
129 template <typename VEC>
130 IDAInterface<VEC>::IDAInterface(const std::string name,
131  const MPI_Comm mpi_comm) :
132  ParameterAcceptor(name),
133  ida_mem(nullptr),
134  communicator(Utilities::MPI::duplicate_communicator(mpi_comm)),
135  pcout(std::cout, Utilities::MPI::this_mpi_process(mpi_comm)==0)
136 {
137  set_functions_to_trigger_an_assert();
138 }
139 #else
140 template <typename VEC>
141 IDAInterface<VEC>::IDAInterface(const std::string name) :
142  ParameterAcceptor(name),
143  ida_mem(nullptr),
144  pcout(std::cout)
145 {
147 }
148 #endif
149 
150 template <typename VEC>
152 {
153  if (ida_mem)
154  IDAFree(&ida_mem);
155 }
156 
157 template <typename VEC>
159 {
161  "Initial step size", "1e-4", Patterns::Double());
162 
164  "Min step size", "5e-5", Patterns::Double());
165 
166  add_parameter(prm, &abs_tol,
167  "Absolute error tolerance", "1e-4", Patterns::Double());
168 
169  add_parameter(prm, &rel_tol,
170  "Relative error tolerance", "1e-3", Patterns::Double());
171 
173  "Initial time", "0", Patterns::Double());
174 
176  "Final time", "1", Patterns::Double());
177 
179  "Seconds between each output", "1e-1", Patterns::Double());
180 
181 
182  add_parameter(prm, &max_order,
183  "Maximum order of BDF", "5", Patterns::Integer());
184 
185 
187  "Maximum number of nonlinear iterations", "10", Patterns::Integer());
188 
189 
191  "Ignore algebraic terms for error computations", "false",
192  Patterns::Bool(),
193  "Indicate whether or not to suppress algebraic variables "
194  "in the local error test.");
195 
196  add_parameter(prm, &ic_type,
197  "Initial condition type", "use_y_diff",
198  Patterns::Selection("none|use_y_diff|use_y_dot"),
199  "This is one of the following thress options for the "
200  "initial condition calculation. \n"
201  " none: do not try to make initial conditions consistent. \n"
202  " use_y_diff: compute the algebraic components of y and differential\n"
203  " components of y_dot, given the differential components of y. \n"
204  " This option requires that the user specifies differential and \n"
205  " algebraic components in the function get_differential_components.\n"
206  " use_y_dot: compute all components of y, given y_dot.");
207 
209  "Initial condition type after restart", "use_y_dot",
210  Patterns::Selection("none|use_y_diff|use_y_dot"),
211  "This is one of the following thress options for the "
212  "initial condition calculation. \n"
213  " none: do not try to make initial conditions consistent. \n"
214  " use_y_diff: compute the algebraic components of y and differential\n"
215  " components of y_dot, given the differential components of y. \n"
216  " This option requires that the user specifies differential and \n"
217  " algebraic components in the function get_differential_components.\n"
218  " use_y_dot: compute all components of y, given y_dot.");
219 
220  add_parameter(prm, &ic_alpha,
221  "Initial condition Newton parameter", "0.33", Patterns::Double());
222 
223 
225  "Initial condition Newton max iterations", "5", Patterns::Integer());
226 
228  "Use local tolerances", "false", Patterns::Bool());
229 
230  add_parameter(prm, &verbose,
231  "Show output of time steps", "true", Patterns::Bool());
232 }
233 
234 
235 template <typename VEC>
236 unsigned int IDAInterface<VEC>::solve_dae(VEC &solution,
237  VEC &solution_dot)
238 {
239 
240  system_size = solution.size();
241 
242  double t = initial_time;
243  double h = initial_step_size;
244  unsigned int step_number = 0;
245 
246  int status;
247 
248  // The solution is stored in
249  // solution. Here we take only a
250  // view of it.
251 
252 #ifdef DEAL_II_WITH_MPI
253  IndexSet is = solution.locally_owned_elements();
255 
256  yy = N_VNew_Parallel(communicator,
258  system_size);
259 
260  yp = N_VNew_Parallel(communicator,
262  system_size);
263 
264  diff_id = N_VNew_Parallel(communicator,
266  system_size);
267 
268  abs_tolls = N_VNew_Parallel(communicator,
270  system_size);
271 
272 #else
273  yy = N_VNew_Serial(system_size);
274  yp = N_VNew_Serial(system_size);
275  diff_id = N_VNew_Serial(system_size);
276  abs_tolls = N_VNew_Serial(system_size);
277 #endif
278 
280  solution,
281  solution_dot,
283  true);
284 
285  double next_time = initial_time;
286 
287  output_step( 0, solution, solution_dot, 0);
288 
289  while (t<final_time)
290  {
291 
292  next_time += outputs_period;
293  if (verbose)
294  {
295  pcout << " "//"\r"
296  << std::setw(5) << t << " ----> "
297  << std::setw(5) << next_time
298  << std::endl;
299  }
300  status = IDASolve(ida_mem, next_time, &t, yy, yp, IDA_NORMAL);
301 
302  status = IDAGetLastStep(ida_mem, &h);
303  AssertThrow(status == 0, ExcMessage("Error in IDA Solver"));
304 
305  copy(solution, yy);
306  copy(solution_dot, yp);
307 
308  // Check the solution
309  bool reset = solver_should_restart(t,
310  solution,
311  solution_dot);
312 
313 
314  while (reset)
315  {
316  // double frac = 0;
317  int k = 0;
318  IDAGetLastOrder(ida_mem, &k);
319  // frac = std::pow((double)k,2.);
320  reset_dae(t, solution, solution_dot,
321  h/2.0, false);
322  reset = solver_should_restart(t,
323  solution,
324  solution_dot);
325  }
326 
327  step_number++;
328 
329  output_step(t, solution, solution_dot, step_number);
330 
331 
332 
333  }
334 
335  pcout << std::endl;
336  // Free the vectors which are no longer used.
337 #ifdef DEAL_II_WITH_MPI
338  N_VDestroy_Parallel(yy);
339  N_VDestroy_Parallel(yp);
340  N_VDestroy_Parallel(abs_tolls);
341  N_VDestroy_Parallel(diff_id);
342 #else
343  N_VDestroy_Serial(yy);
344  N_VDestroy_Serial(yp);
345  N_VDestroy_Serial(abs_tolls);
346  N_VDestroy_Serial(diff_id);
347 #endif
348 
349  return step_number;
350 }
351 
352 template <typename VEC>
353 void IDAInterface<VEC>::reset_dae(double current_time,
354  VEC &solution,
355  VEC &solution_dot,
356  double current_time_step,
357  bool first_step)
358 {
359  if (ida_mem)
360  IDAFree(&ida_mem);
361 
362  ida_mem = IDACreate();
363 
364 
365  // Free the vectors which are no longer used.
366  if (yy)
367  {
368 #ifdef DEAL_II_WITH_MPI
369  N_VDestroy_Parallel(yy);
370  N_VDestroy_Parallel(yp);
371  N_VDestroy_Parallel(abs_tolls);
372  N_VDestroy_Parallel(diff_id);
373 #else
374  N_VDestroy_Serial(yy);
375  N_VDestroy_Serial(yp);
376  N_VDestroy_Serial(abs_tolls);
377  N_VDestroy_Serial(diff_id);
378 #endif
379  }
380 
381  int status;
382  system_size = solution.size();
383 #ifdef DEAL_II_WITH_MPI
384  IndexSet is = solution.locally_owned_elements();
386 
387  yy = N_VNew_Parallel(communicator,
389  system_size);
390 
391  yp = N_VNew_Parallel(communicator,
393  system_size);
394 
395  diff_id = N_VNew_Parallel(communicator,
397  system_size);
398 
399  abs_tolls = N_VNew_Parallel(communicator,
401  system_size);
402 
403 #else
404  yy = N_VNew_Serial(system_size);
405  yp = N_VNew_Serial(system_size);
406  diff_id = N_VNew_Serial(system_size);
407  abs_tolls = N_VNew_Serial(system_size);
408 #endif
409 
410  copy(yy, solution);
411  copy(yp, solution_dot);
413 
414  status = IDAInit(ida_mem, t_dae_residual<VEC>, current_time, yy, yp);
415 
417  {
418 // VEC tolerances = get_local_tolerances();
419 // VEC abs_tolerances(tolerances);
420 // abs_tolerances /= tolerances.linfty_norm();
421 // abs_tolerances *= abs_tol;
423  status += IDASVtolerances(ida_mem, rel_tol, abs_tolls);
424  }
425  else
426  {
427  status += IDASStolerances(ida_mem, rel_tol, abs_tol);
428  }
429 
430  status += IDASetInitStep(ida_mem, current_time_step);
431  status += IDASetUserData(ida_mem, (void *) this);
432 
433  status += IDASetId(ida_mem, diff_id);
434  status += IDASetSuppressAlg(ida_mem, ignore_algebraic_terms_for_errors);
435 
436 // status += IDASetMaxNumSteps(ida_mem, max_steps);
437  status += IDASetStopTime(ida_mem, final_time);
438 
439  status += IDASetMaxNonlinIters(ida_mem, max_non_linear_iterations);
440 
441  // Initialize solver
442  IDAMem IDA_mem;
443  IDA_mem = (IDAMem) ida_mem;
444 
445  IDA_mem->ida_lsetup = t_dae_lsetup<VEC>;
446  IDA_mem->ida_lsolve = t_dae_solve<VEC>;
447  IDA_mem->ida_setupNonNull = true;
448 
449 
450  status += IDASetMaxOrd(ida_mem, max_order);
451 
452  AssertThrow(status == 0, ExcMessage("Error initializing IDA."));
453 
454  std::string type;
455  if (first_step)
456  type = ic_type;
457  else
458  type = reset_type;
459 
460  if (verbose)
461  {
462  pcout << "computing consistent initial conditions with the option "
463  << type
464  << " please be patient."
465  << std::endl;
466  }
467 
468  if (type == "use_y_dot")
469  {
470  // (re)initialization of the vectors
471  IDACalcIC(ida_mem, IDA_Y_INIT, current_time+current_time_step);
472  IDAGetConsistentIC(ida_mem, yy, yp);
473 
474  copy(solution, yy);
475  copy(solution_dot, yp);
476  }
477  else if (type == "use_y_diff")
478  {
479  IDACalcIC(ida_mem, IDA_YA_YDP_INIT, current_time+current_time_step);
480  IDAGetConsistentIC(ida_mem, yy, yp);
481 
482  copy(solution, yy);
483  copy(solution_dot, yp);
484  }
485 
486  if (verbose)
487  {
488  pcout << "compute initial conditions: done."
489  << std::endl;
490  }
491 }
492 
493 template<typename VEC>
495 {
496  initial_time = t;
497 }
498 
499 template<typename VEC>
501 {
502 
503  create_new_vector = []() ->shared_ptr<VEC>
504  {
505  shared_ptr<VEC> p;
507  return p;
508  };
509 
510  residual = [](const double,
511  const VEC &,
512  const VEC &,
513  VEC &) ->int
514  {
515  int ret=0;
517  return ret;
518  };
519 
520  setup_jacobian = [](const double,
521  const VEC &,
522  const VEC &,
523  const double) ->int
524  {
525  int ret=0;
527  return ret;
528  };
529 
530  solve_jacobian_system = [](const VEC &,
531  VEC &) ->int
532  {
533  int ret=0;
535  return ret;
536  };
537 
538  output_step = [](const double,
539  const VEC &,
540  const VEC &,
541  const unsigned int)
542  {
544  };
545 
546  solver_should_restart = [](const double,
547  VEC &,
548  VEC &) ->bool
549  {
550  bool ret=false;
552  return ret;
553  };
554 
555  differential_components = []() ->VEC &
556  {
557  shared_ptr<VEC> y;
559  return *y;
560  };
561 
562  get_local_tolerances = []() ->VEC &
563  {
564  shared_ptr<VEC> y;
566  return *y;
567  };
568 }
569 
570 
571 
572 D2K_NAMESPACE_CLOSE
573 
574 template class deal2lkit::IDAInterface<BlockVector<double> >;
575 
576 #ifdef DEAL_II_WITH_MPI
577 
578 #ifdef DEAL_II_WITH_TRILINOS
579 template class deal2lkit::IDAInterface<TrilinosWrappers::MPI::Vector>;
580 template class deal2lkit::IDAInterface<TrilinosWrappers::MPI::BlockVector>;
581 #endif
582 
583 #ifdef DEAL_II_WITH_PETSC
584 template class deal2lkit::IDAInterface<PETScWrappers::MPI::Vector>;
585 template class deal2lkit::IDAInterface<PETScWrappers::MPI::BlockVector>;
586 #endif
587 
588 #endif
589 
590 
591 #endif
bool verbose
Show the progress of time steps.
Interface to SUNDIALS IDA library.
static::ExceptionBase & ExcPureFunctionCalled()
std::function< bool(const double t, VEC &sol, VEC &sol_dot)> solver_should_restart
Evaluate wether the mesh should be refined or not.
unsigned int local_system_size
N_Vector diff_id
Ida differential components vector.
A parameter acceptor base class.
unsigned int solve_dae(VEC &solution, VEC &solution_dot)
Evolve.
static ParameterHandler prm
Static parameter.
~IDAInterface()
House cleaning.
std::string reset_type
Type of conditions to be used after a solver restart.
void copy(BlockVector< double > &dst, const N_Vector &src)
Definition: utilities.cc:258
size_type n_elements() const
void set_initial_time(const double &t)
Set initial time equal to t disregarding what is written in the parameter file.
STL namespace.
#define AssertThrow(cond, exc)
double rel_tol
Relative error tolerance for adaptive time stepping.
double ic_alpha
Alpha to use in Newton method for IC calculation.
void reset_dae(const double t, VEC &y, VEC &yp, double h, bool first_step)
Clear internal memory, and start with clean objects.
unsigned int max_order
Maximum order of BDF.
double min_step_size
Minimum step size.
std::function< VEC &()> get_local_tolerances
Return a vector whose components are the weights used by IDA to compute the vector norm...
static::ExceptionBase & ExcMessage(std::string arg1)
double final_time
Final time.
double initial_step_size
Initial step size.
Epetra_Comm * duplicate_communicator(const Epetra_Comm &communicator)
ConditionalOStream pcout
Output stream.
std::function< void(const double t, const VEC &sol, const VEC &sol_dot, const unsigned int step_number)> output_step
Store solutions to file.
virtual void declare_parameters(ParameterHandler &prm)
Declare parameters for this class to function properly.
std::string type(const T &t)
Return a human readable name of the type passed as argument.
Definition: utilities.h:461
unsigned int max_non_linear_iterations
Maximum number of iterations for Newton method during time advancement.
std::function< VEC &()> differential_components
Return a vector whose component are 1 if the corresponding dof is differential, 0 if algebraic...
bool use_local_tolerances
Use local tolerances when computing absolute tolerance.
std::string ic_type
Type of initial conditions.
std::function< int(const double t, const VEC &y, const VEC &y_dot, VEC &res)> residual
Compute residual.
double abs_tol
Absolute error tolerance for adaptive time stepping.
bool ignore_algebraic_terms_for_errors
Ignore algebraic terms for errors.
std::function< int(const VEC &rhs, VEC &dst)> solve_jacobian_system
Solve linear system.
std::function< int(const double t, const VEC &y, const VEC &y_dot, const double alpha)> setup_jacobian
Compute Jacobian.
IDAInterface(const std::string name="", const MPI_Comm mpi_comm=MPI_COMM_WORLD)
Constructor for the IDAInterface class.
void * ida_mem
Ida memory object.
void set_functions_to_trigger_an_assert()
This function is executed at construction time to set the std::function above to trigger an assert if...
unsigned ic_max_iter
Maximum number of iterations for Newton method in IC calculation.
unsigned int this_mpi_process(const MPI_Comm &mpi_communicator)
unsigned int system_size
double outputs_period
Seconds between each output.
MPI_Comm communicator
double initial_time
Initial time for the ode.
void add_parameter(ParameterHandler &prm, T *parameter, const std::string &entry, const std::string &default_value, const Patterns::PatternBase &pattern=Patterns::Anything(), const std::string &documentation=std::string())
Add a parameter the given parameter list.
N_Vector abs_tolls
Ida absolute tolerances vector.
std::function< shared_ptr< VEC >)> create_new_vector
Return a shared_ptr<VEC>.