gear_module.f90
Go to the documentation of this file.
1 !> @file gear_module.f90
2 !!
3 !! The error file code for this file is ***W22***.
4 !! @brief Contains the module \ref gear_module
5 !!
6 
7 !>
8 !! @brief \ref gear_module contains adaptive high-order Gear solver
9 !!
10 !! The solver is described by, e.g.,
11 !! [Byrne & Hindmarsh (1975), ACM TOMS 1(1), p.71](https://www.sciencedirect.com/science/article/pii/0021999187900015).
12 !! The basic idea is to estimate the most efficient way between a larger timestep,
13 !! but a higher order (and therefore computationally more expensive) or a
14 !! smaller timestep and a lower order solution.
15 !! The Gear solver therefore calculates the timestep based on an error estimation
16 !! originating from the solution using different orders.
17 !!
18 !! @author Dirk Martin
19 !! @date 01.08.17
20 !!
21 !! @see
22 !! [Byrne & Hindmarsh 1975](https://www.sciencedirect.com/science/article/pii/0021999187900015),
23 !! [Longland et al. 2014](https://ui.adsabs.harvard.edu/abs/2014A%26A...563A..67L/abstract),
24 !! [Martin, D. 2017](https://tuprints.ulb.tu-darmstadt.de/6301/)
25 !!
26 !! \b Edited:
27 !! - OK 16.08.17: privatised local fields and methods
28 !! - MR 18.04.19: fixed gear for termination criterion 0
29 !! - MR 15.01.21: fixed gear for all termination criterions in timestep_module
30 !! - MR 22.01.21: Extented comments
31 !! - MR 17.07.22: Fixed a bug related to switching the orders. This bug was only visible
32 !! with the compiler flag check_bounds which lead to slightly different results
33 !! - MR 17.02.23: Introduced "revert_timestep" to revert the timestep if the solution did not converge
34 !! .
35 #include "macros.h"
36 
38 
39  use global_class, only: net_size
43  implicit none
44 
45  integer,parameter :: histsize = 13 !< length of history in tau, e, ...
46  integer,parameter :: qmax = 5 !< maximum order of q
47 
48  real(r_kind),dimension(6,6) :: amat = &
49  reshape( (/ 1.0d0, 1.0d0, 1.0d0, 1.0d0, 1.0d0, 1.0d0, &
50  0.0d0, 1.0d0, 2.0d0, 3.0d0, 4.0d0, 5.0d0, &
51  0.0d0, 0.0d0, 1.0d0, 3.0d0, 6.0d0,10.0d0, &
52  0.0d0, 0.0d0, 0.0d0, 1.0d0, 4.0d0,10.0d0, &
53  0.0d0, 0.0d0, 0.0d0, 0.0d0, 1.0d0, 5.0d0, &
54  0.0d0, 0.0d0, 0.0d0, 0.0d0, 0.0d0, 1.0d0 /), (/6, 6/) ) !< Helper Matrix
55  !< This Matrix is defined by:
56  !< \f[
57  !< A_{ij}=\begin{cases}0 & \text{if } i<j\\\begin{pmatrix}i\\j\end{pmatrix}
58  !< = \frac{i!}{j!(i-j)!} & \text{if } i\ge j\end{cases} \qquad \text{with } i,j \in [0,1,...,q]
59  !< \f]
60  !< The Taylor-series of \f$\vec{y}_n\f$ truncated at order q, can be calculated as
61  !< the product of the Nordsieck vector (\ref z).
62 
63  integer :: ifac
64  integer, dimension(qmax+1) :: helperarr = (/ (ifac, ifac=1,qmax+1) /)
65  integer, dimension(qmax+1) :: factorial
66 
67  !!! Newton-Raphson options
68  integer :: gear_nr_count = 0 !< counter for NR steps
69 
70  !!! iteration variables
71  integer :: q, n, nq
72  real(r_kind) :: ti, h
73 
74  !!! initial iteration values
75  integer :: q_ini = 1 !< start with order 1
76  integer :: n_ini = 1 !< iteration step
77  integer :: nq_ini = 1 !< iteration step at current order
78 
79  !!! initialize vectors
80  real(r_kind),dimension(histsize) :: tau !< hlist inverted
81  real(r_kind),dimension(:,:),allocatable :: z !< Nordsieck vector
82  !< It is defined as
83  !< \f[
84  !< \vec{z}_n = \left[\vec{y}_n,h\dot{\vec{y}}_n,\frac{h^2 \ddot{\vec{y}}_n}{2!}
85  !< ,...,\frac{h^q \vec{y}_n^{(q)}}{q!} \right]
86  !< \f]
87 
88  real(r_kind),dimension(:,:),allocatable :: znew !< Predictor step
89  real(r_kind),dimension(histsize) :: xi
90  real(r_kind),dimension(:),allocatable :: en
91  real(r_kind),dimension(:,:),allocatable :: e !list of en
92  real(r_kind),dimension(histsize) :: l, el
93  real(r_kind),dimension(:),allocatable :: errq,errqm1,errqp1
94 
95  integer :: alloc_stat
96  real(r_kind) :: hq, hqp1, hqm1
97 
98  !
99  ! Public and private fields and methods of the module
100  !
101  public:: &
104  public:: &
110 
111 
112  private:: &
116  private:: &
118 
119 contains
120 
121 !>
122 !! Initialize iteration variables
123 !!
124 !! Here, all necessary allocations are done. And
125 !! the initial abundance is written into the abundance
126 !! history array (\ref z(1,:)).
127 !!
128 !! @author D. Martin
129 !! @date 01.08.17
130 subroutine init_gear_solver(Y,t_init,h_init)
131  implicit none
132 
133  real(r_kind), dimension(net_size), intent(in) :: y
134  real(r_kind), intent(in) :: t_init
135  real(r_kind), intent(in) :: h_init
136 
137  ! initialize factorial function
138  do ifac=1,qmax+1
139  factorial(ifac) = product(helperarr(1:ifac))
140  enddo
141 
142  ! allocate arrays involving net_size
143  if (.not. allocated(z)) then
144  allocate(z(histsize,net_size),stat=alloc_stat)
145  if ( alloc_stat /= 0) call raise_exception('allocating z failed','init_gear_solver',220001)
146  allocate(znew(histsize,net_size),stat=alloc_stat)
147  if ( alloc_stat /= 0) call raise_exception('allocating znew failed','init_gear_solver',220001)
148  allocate(en(net_size),stat=alloc_stat)
149  if ( alloc_stat /= 0) call raise_exception('allocating en failed','init_gear_solver',220001)
150  allocate(e(histsize,net_size),stat=alloc_stat)
151  if ( alloc_stat /= 0) call raise_exception('allocating e failed','init_gear_solver',220001)
152  allocate(errq(net_size),stat=alloc_stat)
153  if ( alloc_stat /= 0) call raise_exception('allocating errq failed','init_gear_solver',220001)
154  allocate(errqm1(net_size),stat=alloc_stat)
155  if ( alloc_stat /= 0) call raise_exception('allocating errqm1 failed','init_gear_solver',220001)
156  allocate(errqp1(net_size),stat=alloc_stat)
157  if ( alloc_stat /= 0) call raise_exception('allocating errqp1 failed','init_gear_solver',220001)
158  end if
159 
160  q = q_ini ! start with order 1
161  ti = t_init ! initial time
162  h = h_init ! initial step size
163  n = n_ini ! iteration step
164  nq = nq_ini ! iteration step at current order
165 
166  z(1:histsize,1:net_size) = 0.0
167  z(1,1:net_size) = y(1:net_size)
168 
169 
170 end subroutine init_gear_solver
171 
172 
173 !>
174 !! Initialize dYdt component of the Nordsieck vector.
175 !!
176 !! Stores h * dYdt in the Nordsieck vector \ref z(2,:).
177 !!
178 !! @author D. Martin
179 !! @date 01.08.17
180 subroutine init_dydt(dYdt)
181  implicit none
182 
183  real(r_kind), dimension(net_size), intent(in) :: dydt
184 
185  z(2,1:net_size) = h*dydt
186 
187 end subroutine init_dydt
188 
189 
190 !>
191 !! The current time
192 !!
193 !! @author D. Martin
194 !! @date 01.08.17
195 function get_time()
196  implicit none
197 
198  real(r_kind) :: get_time
199 
200  get_time = ti
201 end function get_time
202 
203 
204 !>
205 !! The current timestep
206 !!
207 !! @author D. Martin
208 !! @date 01.08.17
209 function get_timestep()
210  implicit none
211 
212  real(r_kind) :: get_timestep
213 
214  get_timestep = h
215 end function get_timestep
216 
217 
218 !>
219 !! Set the current timestep
220 !!
221 !! @warning When changing the timestep
222 !! of Gear, the Nordsieck vector (\ref z) has
223 !! to be rescaled because it depends on the timestep.
224 !! The timestep of gear should therefore only changed
225 !! by this routine!
226 !!
227 !! @see timestep_module::restrict_timestep,
228 !! network_init_module::switch_evolution_mode.
229 !!
230 !! @author D. Martin
231 !! @date 01.08.17
232 subroutine set_timestep(timestep)
233  implicit none
234 
235  real(r_kind), intent(in) :: timestep
236 
237  integer :: j
238 
239 
240  ! rescale Nordsieck vector
241  do j=2,q+1
242  z(j,1:net_size) = z(j,1:net_size)*((timestep/h)**(j-1.d0))
243  enddo
244 
245  h = timestep
246 
247  ! Check the order afterwards again
248  nq = q
249 end subroutine set_timestep
250 
251 
252 !> Revert a timestep
253 !!
254 !! This routine reverts the timestep of Gear
255 !! to the previous timestep.
256 !! It is used in case the result did not converge
257 !!
258 !! @see timestep_module::advance_gear
259 !!
260 !! @author M. Reichert
261 subroutine revert_timestep(timestep)
262  implicit none
263  real(r_kind), intent(in) :: timestep
264 
265  ti = ti - h
266 
267  call set_timestep(timestep)
268  tau = eoshift(tau, 1)
269 
270 end subroutine revert_timestep
271 
272 
273 !>
274 !! The current l_1 (in Fortran: l(2))
275 !!
276 !! @see set_l
277 !!
278 !! @author D. Martin
279 !! @date 01.08.17
280 function get_l1()
281  implicit none
282 
283  real(r_kind) :: get_l1
284 
285  get_l1 = l(2)
286 end function get_l1
287 
288 
289 !>
290 !! Gives a copy of the solution at the current time
291 !!
292 !! The solution abundance is stored at \ref z(1,:).
293 !!
294 !! @author D. Martin
295 !! @date 01.08.17
296 function get_solution()
297  implicit none
298 
299  real(r_kind), dimension(net_size) :: get_solution
300 
301  get_solution = z(1,1:net_size)
302 end function get_solution
303 
304 
305 !>
306 !! Determines the predicted y_next
307 !!
308 !! The predicted abundance is stored in \ref z_new(1,:)
309 !!
310 !!
311 !! @author D. Martin
312 !! @date 01.08.17
313 function get_predictor_y()
314  implicit none
315 
316  real(r_kind), dimension(net_size) :: get_predictor_y
317 
319 
320 end function get_predictor_y
321 
322 
323 !>
324 !! Determines the predicted dydt_next
325 !!
326 !! This returns the predicted dydt from the predictor step
327 !! from \ref z_new.
328 !!
329 !! @author D. Martin
330 !! @date 01.08.17
332  implicit none
333 
334  real(r_kind), dimension(net_size) :: get_predictor_dydt
335 
337 end function get_predictor_dydt
338 
339 
340 !>
341 !! Determines the solution at a given point in time for [ti-h, ti]
342 !!
343 !! @author D. Martin
344 !! @date 01.08.17
345 subroutine get_solution_at(time_inter, Y_inter)
346  implicit none
347 
348  real(r_kind), intent(in) :: time_inter
349  real(r_kind), dimension(net_size), intent(out) :: y_inter
350 
351  integer :: j
352 
353  y_inter(1:net_size) = 0.0d0
354  if ((time_inter.gt.ti-tau(1)) .and. (time_inter.le.ti)) then
355  do j=1,q+1
356  y_inter = y_inter + (((time_inter - ti)/tau(1))**(j-1.0d0))*z(j,1:net_size)
357  enddo
358  endif
359 
360  return
361 
362 end subroutine get_solution_at
363 
364 
365 !>
366 !! Shifts tau vector and controls the current time
367 !!
368 !! @author D. Martin
369 !! @date 01.08.17
370 subroutine shift_tau
371  implicit none
372 
373  tau = eoshift(tau, -1)
374  tau(1) = h
375 
376  ti = ti + h
377 
378 end subroutine shift_tau
379 
380 
381 !>
382 !! Nordsieck vector-matrix product
383 !!
384 !! This calculates:
385 !! \f[
386 !! \vec{z}_{n+1}^{(0)} = \mathbf{A} \cdot \vec{z}_n
387 !! \f]
388 !! and stores the result in \ref z_new.
389 !!
390 !! @author D. Martin
391 !! @date 01.08.17
393  implicit none
394 
395  integer :: qp1
396 
397  integer :: i,j
398  znew = 0.0d0
399 
400  qp1 = q+1
401 
402  do i=1,qp1
403  do j=1,qp1
404  znew(i,1:net_size) = znew(i,1:net_size)+amat(j,i)*z(j,1:net_size)
405  enddo
406  enddo
407 end subroutine nordsieck_product
408 
409 
410 !>
411 !! Function to calculate xi (needed for getting l in the corrector step)
412 !!
413 !! xi is defined as:
414 !! \f[
415 !! \xi _i = \frac{t_{n+1} - t_{n+1-i}}{h}
416 !! \f]
417 !!
418 !! @author D. Martin
419 !! @date 01.08.17
420 subroutine set_xi
421  implicit none
422 
423  integer :: j
424 
425  xi(1:histsize) = 0.0d0
426  do j=1,q
427  xi(j) = xi(j)+sum(tau(1:j))
428  xi(j) = xi(j)/h
429  enddo
430 
431 end subroutine set_xi
432 
433 
434 !>
435 !! Function to calculate \f$ \ell \f$ (needed for the corrector step)
436 !! \f[
437 !! \begin{align}
438 !! \ell _0 (q) &=1, \nonumber \\
439 !! \quad \ell_1(q)&=\sum \limits _{i=1}^{q} \left( \xi _i ^{-1} \right), \nonumber\\
440 !! \quad \ell_j (q) &= \ell_j(q-1)+\ell_{j-1}(q-1)/\xi _q, \nonumber\\
441 !! \quad \ell _q (q) &= \left( \prod \limits_{i=1}^{q}\xi _i \right) ^{-1}. \nonumber
442 !! \end{align}
443 !! \f]
444 !!
445 !! @author D. Martin
446 !! @date 01.08.17
447 subroutine set_l
448  implicit none
449 
450  integer :: j,iback
451 
452  l = 0.0d0
453  l(1) = 1.0d0
454  l(2) = 1.0d0/xi(1) ! CAREFUL: this is l_1 in the formulas
455  do j=2,q
456  l(j+1) = l(j)/xi(j)
457  do iback=j,2,-1
458  l(iback) = l(iback) + l(iback-1)/xi(j)
459  enddo !iback
460  enddo !j
461 
462 end subroutine set_l
463 
464 
465 !>
466 !! Updates the solution (corrector step)
467 !!
468 !! This routine calculates
469 !! \f[ \vec{z}_{n+1}=\vec{z}_{n+1}^{(0)}+\vec{e}_{n+1}\vec{\ell} \f]
470 !!
471 !! @see set_l, timestep_module::advance_gear
472 !!
473 !! @author D. Martin
474 !! @date 01.08.17
475 subroutine set_new_result(ydiff)
476  implicit none
477 
478  real(r_kind),dimension(net_size),intent(in) :: ydiff
479 
480  integer :: j
481 
482  en = ydiff
483 
484  ! shift en list
485  e = eoshift(e, -1)
486  e(1,1:net_size) = en
487 
488  ! z -> znew
489  z = 0.0d0
490  do j=1,q+1
491  z(j,1:net_size) = znew(j,1:net_size) + en*l(j)
492  enddo
493 
494 end subroutine set_new_result
495 
496 
497 !>
498 !! Stepsize and order control to pepare the next step
499 !!
500 !! @author D. Martin
501 !! @date 01.08.17
503  implicit none
504 
505  integer :: j
506 
507  if(q>1 .and. nq==q) then
508  call geterrors
509 
510 
511  call shiftorder
512 
513  ! rescale Nordsieck vector, if necessary
514  do j=2,q+1
515  z(j,1:net_size) = z(j,1:net_size)*((h/tau(1))**(j-1.d0))
516  enddo
517 
518  nq = 0
519 
520  else if(q==1) then
521  !!! first increase of the order
522  q = q+1
523  z(q+1,1:net_size) = 0.0d0
524  nq = 0
525  endif
526 
527  nq = nq+1
528  n = n+1
529 end subroutine prepare_next_step
530 
531 
532 !>
533 !! Calculate errors (helper functions below)
534 !!
535 !! Calculates the errors (E, E(q+1), and E(q-1)) by calling the
536 !! respective subroutines \ref errorq, \ref errorqm1, \ref errorqp1.
537 !! Also estimates the resulting timestep from each order.
538 !!
539 !! @author D. Martin
540 !! @date 01.08.17
541 !!
542 !! \b Edited:
543 !! - M. Reichert, 15.07.22: Set time step of qp1 to zero if already in maximum order.
544 !! .
545 subroutine geterrors
546  implicit none
547 
548  call errorq
549  call errorqm1
550  call errorqp1 ! only calculate for q<qmax
551 
552  errq(1:net_size) = errq(1:net_size)/max(dabs(z(1,1:net_size)),gear_escale)
553  errqm1(1:net_size) = errqm1(1:net_size)/max(dabs(z(1,1:net_size)),gear_escale)
554  errqp1(1:net_size) = errqp1(1:net_size)/max(dabs(z(1,1:net_size)),gear_escale)
555 
556  if(maxval(errq) < 1.d-100) then
558  else
559  hq = gear_cfactor*h*((gear_eps/maxval(errq))**(1.0d0/(q+1.0d0)))
560  endif
561  if(maxval(errqm1) < 1.d-100) then
563  else
564  hqm1 = gear_cfactor*h*((gear_eps/maxval(errqm1))**(1.0d0/q))
565  endif
566 
567  ! Take care that one does not increase the order for the maximum order
568  if (q .ne. qmax) then
569  if(maxval(errqp1) < 1.d-100) then
571  else
572  hqp1 = gear_cfactor*h*((gear_eps/maxval(errqp1))**(1.0d0/(q+2.0d0))) ! see above
573  endif
574  else
575  hqp1 = 0
576  end if
577 ! print *, hq
578 ! print *, hqm1
579 ! print *, hqp1
580 
581 end subroutine geterrors
582 
583 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
584 !!! Error functions
585 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
586 !>
587 !! Calculate the errors for the current order
588 !!
589 !! The error is defined as:
590 !! \f[
591 !! \vec{E}_{n+1}(q) = -\frac{1}{\ell _1}\left[ 1+ \prod _{i=2}^{q}\left(
592 !! \frac{t_{n+1}-t_{n+1-i}}{t_{n}-t_{n+1-i}} \right) \right] ^{-1} \vec{e}_{n+1}
593 !! \f]
594 !!
595 !! @author D. Martin
596 !! @date 01.08.17
597 subroutine errorq
598  implicit none
599 
600  integer :: i
601  real(r_kind) :: tdiff1, tdiff2, tprod
602 
603  !errq = 999999.0d0
604  !if(q<2) return
605 
606  tprod = 1.0d0
607  do i=2,q
608  tdiff1 = 0.0d0
609  tdiff2 = 0.0d0
610  tdiff1 = tdiff1 + sum(tau(1:i)) !(t[n]-t[n-i])
611  tdiff2 = tdiff1 - tau(1) !(t[n-1]-t[n-i])
612  tprod = tprod*tdiff1/tdiff2 !tprod = tprod*(t[n]-t[n-i])/(t[n-1]-t[n-i])
613  enddo
614 
615  errq(1:net_size) = dabs(-(1.0d0/l(2))*(en(1:net_size)/(1.0d0+tprod)))
616 
617  return
618 end subroutine errorq
619 
620 
621 !>
622 !! Calculate the errors for the order (q-1)
623 !!
624 !! The error is defined as:
625 !! \f[
626 !! \vec{E}_{n+1}(q-1) = - \frac{\prod \limits _{i=1}^{q-1} \xi _i }
627 !! {\ell _1 (q-1)} \frac{h^q \vec{y}_{n+1}^{(q)}}{q!}
628 !! \f]
629 !!
630 !! @author D. Martin
631 !! @date 01.08.17
632 subroutine errorqm1
633  implicit none
634 
635  integer :: qm1
636  real(r_kind) :: xiprod
637 
638  qm1 = q-1
639 
640  errqm1 = 999999.0d0
641  if(qm1<1) return
642 
643  xiprod = 1.0d0
644  xiprod = xiprod*product(xi(1:qm1)) !xiprod = xiprod*xi[i]
645  xiprod = xiprod/(l(2)*qm1)
646 
647  errqm1(1:net_size) = dabs(-xiprod*z(q+1,1:net_size)) !abs(-xiprod*zq[k])
648 
649  return
650 end subroutine errorqm1
651 
652 
653 !>
654 !! Calculate the errors for the order (q+1)
655 !!
656 !! The error is defined as:
657 !! \f[
658 !! \vec{E}_{n+1}(q+1) = \frac{-\xi_{q+1}(\vec{e}_{n+1}-Q_{n+1}\vec{e}_n) }
659 !! {(q+2)\ell _1 (q+1)\left[1+ \prod \limits_{i=2}^{q} \frac{t_{n+1}-t_{n+1-i}}
660 !! {t_n-t_{n+1-i}} \right] }
661 !! \f]
662 !!
663 !! @author D. Martin
664 !! @date 01.08.17
665 subroutine errorqp1
666  implicit none
667 
668  integer :: qp1
669 
670  integer :: i
671  real(r_kind) :: xiqp1,tdiff1,tdiff2,helpprod,qval
672 
673  qp1 = q+1
674 
675  xiqp1 = 0.0d0
676  xiqp1 = xiqp1 + sum(tau(1:qp1))
677  xiqp1 = xiqp1/tau(1)
678 
679  helpprod = 1.0d0
680  do i=2,q
681  tdiff1 = 0.0d0
682  tdiff2 = 0.0d0
683  tdiff1 = tdiff1 + sum(tau(1:i)) !(t[n]-t[n-i])
684  tdiff2 = tdiff1 - tau(1) !(t[n-1]-t[n-i])
685  helpprod = helpprod*tdiff1/tdiff2
686  enddo
687  helpprod = helpprod + 1.0d0
688 
689  call qfun(helpprod,qval)
690 
691  errqp1(1:net_size) = dabs(-xiqp1*(en(1:net_size)-qval*e(2,1:net_size))/((qp1+1)*l(2)*qp1*helpprod))
692 
693  return
694 end subroutine errorqp1
695 
696 
697 !> Calculate Helper function Q
698 !!
699 !! Q is defined as:
700 !! \f[
701 !! Q_{n+1} =\frac{C_{n+1}}{C_n}\left( \frac{h_{n+1}}{h_n}\right)^{q+1} \\
702 !! \f]
703 !!
704 !! @author D. Martin
705 !! @date 01.08.17
706 subroutine qfun(helpprod,qval)
707  implicit none
708  real(r_kind),intent(in) :: helpprod
709  real(r_kind),intent(out) :: qval
710 
711  integer :: qp1
712 
713  integer :: i
714  real(r_kind) :: helpprod2, tdiff1, tdiff2, cfac1, cfac2, helpfac
715 
716  qp1 = q+1
717 
718  !!! 2nd helpprod for n-1
719  helpprod2 = 1.0d0
720  do i=2,q
721  tdiff1 = 0.0d0
722  tdiff2 = 0.0d0
723  tdiff1 = tdiff1 + sum(tau(2:i+1)) !(t[n-1]-t[n-1-i] = t[n-1]-t[n-(i+1)])
724  tdiff2 = tdiff1 - tau(2) !(t[n-2]-t[n-1-i] = t[n-2]-t[n-(i+1))
725  helpprod2 = helpprod2*tdiff1/tdiff2
726  enddo
727  helpprod2 = helpprod2 + 1.0d0
728 
729  call cfun(qp1,xi(1:histsize),helpprod,cfac1)
730  call cfun(qp1,xi(1:histsize),helpprod2,cfac2)
731  helpfac = cfac1/cfac2
732  qval = helpfac*((tau(1)/tau(2))**qp1)
733 
734  return
735 end subroutine qfun
736 
737 !> Calculate helper function C
738 !!
739 !! The function is defined as:
740 !! \f[
741 !! C_{n+1} = \frac{\prod \limits _{i=1}^{q} \xi _{i}}{(q+1)!}\left[1+ \prod
742 !! \limits _{i=2}^{q} \frac{t_{n+1} - t_{n+1-i}}{t_n -t_{n+1-i}} \right].
743 !! \f]
744 !!
745 !! @author D. Martin
746 !! @date 01.08.17
747 subroutine cfun(qp1,xi_in,helpprod,cval)
748  implicit none
749 
750  integer,intent(in) :: qp1
751  real(r_kind),dimension(histsize),intent(in) :: xi_in
752  real(r_kind),intent(in) :: helpprod
753  real(r_kind),intent(out) :: cval
754 
755  !integer :: j
756  real(r_kind) :: facqp1,xiprod
757 
758  ! simple factorial calculation: (q+1)!
759  facqp1 = factorial(qp1)
760  !facqp1 = 1.0d0
761  !do j=2,qp1
762  ! facqp1 = facqp1*real(j)
763  !enddo
764 
765  xiprod = 1.0d0
766  xiprod = xiprod*product(xi_in(1:q))
767  cval = xiprod*helpprod/facqp1
768 
769  return
770 end subroutine cfun
771 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
772 
773 
774 !>
775 !! Adjusts the order, if possible and necessary.
776 !! This is done every qth step, or earlier in case the time
777 !! step was modified.
778 !!
779 !!
780 !! @author D. Martin
781 !! @date 01.08.17
782 subroutine shiftorder
783  implicit none
784 
785  integer :: j, iback
786  real(r_kind) :: h_old
787 
788  ! Store the old timestep
789  h_old = h
790 
791  if(hqm1 .ge. hq .and. hqm1 .ge. hqp1) then
792 
793  el = 0.0d0
794  el(3) = 1.0d0
795  do j=3,q
796  el(j+1) = 1.0d0
797  do iback=j,3,-1
798  el(iback) = el(iback)*xi(j-2) + el(iback-1)
799  enddo
800  enddo
801 
802  ! subtract from Nordsieck vector for j=2,3,...,q-1
803  do j=3,q
804  z(j,1:net_size) = z(j,1:net_size) - z(q+1,1:net_size)*el(j)
805  enddo
806  q = q-1
807  h = hqm1
808  ! print *, "The order has decreased!",q,h
809  else if(hqp1>hq .and. q<qmax) then
810  q = q+1
811  ! set (q+2)-th entry [=(q+1)-th order] of z to 0.0
812  z(q+1,1:net_size) = 0.0d0
813  h = hqp1
814  ! print *, "The order has been increased!",q,h
815  else
816  h = hq
817  ! print *, "The order stayed the same!",q,h
818  endif
819 
820  ! Restrict timestep to the maximum allowed increase
821  h = min(h, h_old*gear_timestep_max)
822 
823  !gear_cFactor = get_cFactor(q)
824 
825 end subroutine shiftorder
826 
827 !>
828 !! Function to set the conservative timestep factor depending on the current
829 !! order q.
830 !!
831 !! @note This function is not used!
832 !!
833 !! @author D. Martin
834 !! @date 01.08.17
835 function get_cfactor(q_val)
836  implicit none
837 
838  integer, intent(in) :: q_val
839  real(r_kind) :: get_cfactor
840 
841  get_cfactor = 0.075d0*(q_val-1) + 0.1d0
842  return
843 
844  if(q_val==5) then
845  get_cfactor = 0.30d0
846  elseif(q_val==4) then
847  get_cfactor = 0.25d0
848  elseif(q_val==3) then
849  get_cfactor = 0.20d0
850  elseif(q_val==2) then
851  get_cfactor = 0.15d0
852  else
853  get_cfactor = 0.10d0
854  endif
855 
856 end function get_cfactor
857 
858 end module gear_module
gear_module::en
real(r_kind), dimension(:), allocatable, private en
Definition: gear_module.f90:90
gear_module::errorqm1
subroutine, private errorqm1
Calculate the errors for the order (q-1)
Definition: gear_module.f90:633
gear_module::get_predictor_dydt
real(r_kind) function, dimension(net_size), public get_predictor_dydt()
Determines the predicted dydt_next.
Definition: gear_module.f90:332
gear_module::get_time
real(r_kind) function, public get_time()
The current time.
Definition: gear_module.f90:196
gear_module::znew
real(r_kind), dimension(:,:), allocatable, private znew
Predictor step.
Definition: gear_module.f90:88
gear_module::l
real(r_kind), dimension(histsize), private l
Definition: gear_module.f90:92
gear_module::init_gear_solver
subroutine, public init_gear_solver(Y, t_init, h_init)
Initialize iteration variables.
Definition: gear_module.f90:131
parameter_class::gear_eps
real(r_kind) gear_eps
Abundance accuracy for gear solver.
Definition: parameter_class.f90:136
parameter_class::gear_nr_maxcount
integer gear_nr_maxcount
Maximum newton-raphson iterations for gear solver.
Definition: parameter_class.f90:141
gear_module::errq
real(r_kind), dimension(:), allocatable, private errq
Definition: gear_module.f90:93
gear_module::get_solution_at
subroutine, public get_solution_at(time_inter, Y_inter)
Determines the solution at a given point in time for [ti-h, ti].
Definition: gear_module.f90:346
parameter_class::gear_nr_eps
real(r_kind) gear_nr_eps
Convergence criterion for the newton-raphson of the gear solver.
Definition: parameter_class.f90:139
gear_module::get_timestep
real(r_kind) function, public get_timestep()
The current timestep.
Definition: gear_module.f90:210
error_msg_class
Error handling routines.
Definition: error_msg_class.f90:16
gear_module::set_xi
subroutine, public set_xi
Function to calculate xi (needed for getting l in the corrector step)
Definition: gear_module.f90:421
parameter_class::gear_escale
real(r_kind) gear_escale
Normalization cutoff for gear solver, similar to timestep_Ymin for Euler.
Definition: parameter_class.f90:137
gear_module::helperarr
integer, dimension(qmax+1), private helperarr
Definition: gear_module.f90:64
gear_module::q_ini
integer, private q_ini
start with order 1
Definition: gear_module.f90:75
gear_module::gear_nr_count
integer, public gear_nr_count
counter for NR steps
Definition: gear_module.f90:68
gear_module::factorial
integer, dimension(qmax+1), private factorial
Definition: gear_module.f90:65
parameter_class::gear_cfactor
real(r_kind) gear_cfactor
Conservative timestep factor for gear solver [0.1, ... , 0.4].
Definition: parameter_class.f90:138
error_msg_class::raise_exception
subroutine, public raise_exception(msg, sub, error_code)
Raise a exception with a given error message.
Definition: error_msg_class.f90:245
gear_module::e
real(r_kind), dimension(:,:), allocatable, private e
Definition: gear_module.f90:91
gear_module::el
real(r_kind), dimension(histsize), private el
Definition: gear_module.f90:92
gear_module::get_solution
real(r_kind) function, dimension(net_size), public get_solution()
Gives a copy of the solution at the current time.
Definition: gear_module.f90:297
gear_module::set_new_result
subroutine, public set_new_result(ydiff)
Updates the solution (corrector step)
Definition: gear_module.f90:476
gear_module::errqm1
real(r_kind), dimension(:), allocatable, private errqm1
Definition: gear_module.f90:93
gear_module::errorq
subroutine errorq
Calculate the errors for the current order.
Definition: gear_module.f90:598
gear_module::set_timestep
subroutine, public set_timestep(timestep)
Set the current timestep.
Definition: gear_module.f90:233
gear_module::hqm1
real(r_kind), private hqm1
Definition: gear_module.f90:96
gear_module::shiftorder
subroutine, private shiftorder
Adjusts the order, if possible and necessary. This is done every qth step, or earlier in case the tim...
Definition: gear_module.f90:783
gear_module::get_l1
real(r_kind) function, public get_l1()
The current l_1 (in Fortran: l(2))
Definition: gear_module.f90:281
gear_module::n
integer, private n
Definition: gear_module.f90:71
global_class::net_size
integer, public net_size
total number of isotopes (network size)
Definition: global_class.f90:93
gear_module::get_predictor_y
real(r_kind) function, dimension(net_size), public get_predictor_y()
Determines the predicted y_next.
Definition: gear_module.f90:314
gear_module::alloc_stat
integer, private alloc_stat
Definition: gear_module.f90:95
r_kind
#define r_kind
Definition: macros.h:46
gear_module::hq
real(r_kind), private hq
Definition: gear_module.f90:96
gear_module::cfun
subroutine cfun(qp1, xi_in, helpprod, cval)
Calculate helper function C.
Definition: gear_module.f90:748
gear_module::set_l
subroutine, public set_l
Function to calculate (needed for the corrector step)
Definition: gear_module.f90:448
gear_module::errorqp1
subroutine, private errorqp1
Calculate the errors for the order (q+1)
Definition: gear_module.f90:666
gear_module::qmax
integer, parameter, private qmax
maximum order of q
Definition: gear_module.f90:46
gear_module::tau
real(r_kind), dimension(histsize), private tau
hlist inverted
Definition: gear_module.f90:80
gear_module::prepare_next_step
subroutine, public prepare_next_step
Stepsize and order control to pepare the next step.
Definition: gear_module.f90:503
parameter_class::gear_timestep_max
real(r_kind) gear_timestep_max
For gear solver.
Definition: parameter_class.f90:140
gear_module::hqp1
real(r_kind), private hqp1
Definition: gear_module.f90:96
gear_module::ti
real(r_kind), private ti
Definition: gear_module.f90:72
gear_module::qfun
subroutine, private qfun(helpprod, qval)
Calculate Helper function Q.
Definition: gear_module.f90:707
global_class
Contains types and objects shared between multiple modules.
Definition: global_class.f90:19
gear_module::xi
real(r_kind), dimension(histsize), private xi
Definition: gear_module.f90:89
gear_module::geterrors
subroutine, private geterrors
Calculate errors (helper functions below)
Definition: gear_module.f90:546
gear_module::get_cfactor
real(r_kind) function, private get_cfactor(q_val)
Function to set the conservative timestep factor depending on the current order q.
Definition: gear_module.f90:836
gear_module::nq
integer, private nq
Definition: gear_module.f90:71
gear_module::errqp1
real(r_kind), dimension(:), allocatable, private errqp1
Definition: gear_module.f90:93
gear_module::nordsieck_product
subroutine, public nordsieck_product
Nordsieck vector-matrix product.
Definition: gear_module.f90:393
gear_module::amat
real(r_kind), dimension(6, 6), private amat
Helper Matrix.
Definition: gear_module.f90:48
gear_module::ifac
integer, private ifac
Definition: gear_module.f90:63
gear_module::nq_ini
integer, private nq_ini
iteration step at current order
Definition: gear_module.f90:77
gear_module::z
real(r_kind), dimension(:,:), allocatable, private z
Nordsieck vector It is defined as.
Definition: gear_module.f90:81
gear_module::revert_timestep
subroutine, public revert_timestep(timestep)
Revert a timestep.
Definition: gear_module.f90:262
gear_module::shift_tau
subroutine, public shift_tau
Shifts tau vector and controls the current time.
Definition: gear_module.f90:371
gear_module
gear_module contains adaptive high-order Gear solver
Definition: gear_module.f90:37
gear_module::histsize
integer, parameter, private histsize
length of history in tau, e, ...
Definition: gear_module.f90:45
gear_module::init_dydt
subroutine, public init_dydt(dYdt)
Initialize dYdt component of the Nordsieck vector.
Definition: gear_module.f90:181
gear_module::n_ini
integer, private n_ini
iteration step
Definition: gear_module.f90:76
parameter_class
Contains all runtime parameters as well as phys and math constants.
Definition: parameter_class.f90:24
gear_module::q
integer, private q
Definition: gear_module.f90:71
gear_module::h
real(r_kind), private h
Definition: gear_module.f90:72