Report Typos and Errors    
Semi-Lagrangian Library
Modular library for kinetic and gyrokinetic simulations of plasmas in fusion energy devices.
sll_m_penta_diagonal.F90
Go to the documentation of this file.
1 !**************************************************************
2 ! Copyright INRIA
3 ! Authors :
4 ! CALVI project team
5 !
6 ! This code SeLaLib (for Semi-Lagrangian-Library)
7 ! is a parallel library for simulating the plasma turbulence
8 ! in a tokamak.
9 !
10 ! This software is governed by the CeCILL-B license
11 ! under French law and abiding by the rules of distribution
12 ! of free software. You can use, modify and redistribute
13 ! the software under the terms of the CeCILL-B license as
14 ! circulated by CEA, CNRS and INRIA at the following URL
15 ! "http://www.cecill.info".
16 !**************************************************************
17 
23 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
24 #include "sll_memory.h"
25 #include "sll_working_precision.h"
26 
27  implicit none
28 
29  public :: &
30  sll_o_create, &
31  sll_o_delete, &
34 
35  private
36 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
37 
40  sll_int32 :: n
41  sll_real64, dimension(:), pointer :: e1
42  sll_real64, dimension(:), pointer :: e2
43  sll_real64, dimension(:), pointer :: y
44  sll_real64, dimension(:), pointer :: z
45  sll_real64, dimension(:), pointer :: w
46  sll_real64, dimension(:), pointer :: solution
48 
49  interface sll_o_create
50  module procedure new_penta_diagonal
51  end interface sll_o_create
52 
53  interface sll_o_solve
54  module procedure solve_penta_diagonal
55  end interface sll_o_solve
56 
57  interface sll_o_delete
58  module procedure delete_penta_diagonal
59  end interface sll_o_delete
60 
61 contains
62 
64  function new_penta_diagonal(n) result(plan)
65 
66  sll_int32 :: n, ierr
67  type(sll_t_penta_diagonal_solver), pointer :: plan
68 
69  if (n < 3) then
70  print *, 'Matrix size must be at least 3x3'
71  print *, 'Exiting...'
72  stop
73  end if
74 
75  ! Plan allocation
76  sll_allocate(plan, ierr)
77 
78  ! Plan components allocation
79  plan%n = n;
80  sll_allocate(plan%e1(n), ierr)
81  sll_allocate(plan%e2(n), ierr)
82  sll_allocate(plan%y(n), ierr)
83  sll_allocate(plan%z(n), ierr)
84  sll_allocate(plan%w(n), ierr)
85  sll_allocate(plan%solution(n), ierr)
86 
87  end function new_penta_diagonal
88 
90  subroutine solve_penta_diagonal(a, b, c, f, plan)
91 
92  sll_real64 :: a, b, c
93  sll_real64, dimension(:) :: f
94  type(sll_t_penta_diagonal_solver), pointer :: plan
95  sll_real64 :: s, t, p, l1, l2
96  sll_real64 :: d, d1, d2
97  sll_int32 :: n, i
98  sll_real64 :: sign_of_a = 0.0_f64
99 
100  if (abs(a) <= 2.0_f64*(abs(b) + abs(c))) then
101  print *, 'a, b, and c must be such that: |a| > 2(|b|+|c|)'
102  print *, a, b, c
103  print *, 'Exiting...'
104  stop
105  end if
106 
107  n = plan%n
108 
109  s = (a/2 + c)*(a/2 + c) - b*b
110  t = a*a/2 - b*b - 2*c*c
111 
112  if (a /= 0.0_f64) then
113  sign_of_a = a/abs(a)
114  end if
115 
116  p = (a - 2*c)/4 + sign_of_a*sqrt(sign_of_a*(a - 2*c)* &
117  sqrt(s) + t)/2.0_f64 + sign_of_a*sqrt(s)/2.0_f64
118  l1 = b/(p + c)
119  l2 = c/p
120 
121  do i = 1, n
122  plan%y(i) = f(i)/p
123  plan%e1(i) = 0.0_f64
124  plan%e2(i) = 0.0_f64
125  end do
126  plan%e1(1) = 1.0_f64
127  plan%e2(2) = 1.0_f64
128 
129  plan%y = solve_subsystem(l1, l2, plan%y, n)
130  plan%z = solve_subsystem(l1, l2, plan%e1, n)
131  plan%w = solve_subsystem(l1, l2, plan%e2, n)
132 
133  d = 1.0_f64 + l1*l2*(plan%z(2) + plan%w(1)) + l2*l2*(plan%z(1) + plan%w(2)) + &
134  l1*l1*plan%z(1) + l2**4*(plan%z(1)*plan%w(2) - plan%z(2)*plan%w(1))
135 
136  d1 = l2**4*(plan%y(1)*plan%w(2) - plan%y(2)*plan%w(1)) + &
137  (l1*l1 + l2*l2)*plan%y(1) + l1*l2*plan%y(2)
138 
139  d2 = l2**4*(plan%y(2)*plan%z(1) - plan%y(1)*plan%z(2)) + &
140  l1*l2*plan%y(1) + l2*l2*plan%y(2)
141 
142  do i = 1, n
143  plan%solution(i) = plan%y(i) - (d1*plan%z(i) + d2*plan%w(i))/d
144  end do
145 
146  end subroutine solve_penta_diagonal
147 
148  function solve_subsystem(l1, l2, b, n) result(x)
149 
150  sll_real64 :: l1, l2
151  sll_real64, dimension(:) :: b
152  sll_int32 :: n, i
153  sll_real64, dimension(n) :: x, y
154  sll_real64 :: tmp
155 
156  y(1) = b(1)
157  y(2) = b(2) - l1*y(1)
158 
159  do i = 3, n
160  tmp = b(i) - (l2*y(i - 2) + l1*y(i - 1))
161  if (abs(tmp) < 1e-30_f64) then
162  tmp = 0.0_f64
163  end if
164  y(i) = tmp
165  end do
166 
167  x(n) = y(n)
168  x(n - 1) = y(n - 1) - l1*y(n)
169  do i = n - 2, 1, -1
170  tmp = y(i) - (l1*x(i + 1) + l2*x(i + 2))
171  if (abs(tmp) < 1e-30_f64) then
172  tmp = 0.0_f64
173  end if
174  x(i) = tmp
175  end do
176 
177  end function solve_subsystem
178 
180  subroutine delete_penta_diagonal(plan)
181 
182  type(sll_t_penta_diagonal_solver), pointer :: plan
183  sll_int32 :: ierr
184 
185  ! Plan components deallocation
186  sll_deallocate_array(plan%e1, ierr)
187  sll_deallocate_array(plan%e2, ierr)
188  sll_deallocate_array(plan%y, ierr)
189  sll_deallocate_array(plan%z, ierr)
190  sll_deallocate_array(plan%w, ierr)
191  sll_deallocate_array(plan%solution, ierr)
192 
193  ! Plan deallocation
194  sll_deallocate_array(plan, ierr)
195 
196  end subroutine delete_penta_diagonal
197 
198 end module sll_m_penta_diagonal
199 
Toeplitz penta-diagonal system solver.
type(sll_t_penta_diagonal_solver) function, pointer new_penta_diagonal(n)
allocate the solveR
real(kind=f64) function, dimension(n) solve_subsystem(l1, l2, b, n)
subroutine solve_penta_diagonal(a, b, c, f, plan)
The solution will be set in plansolution.
subroutine delete_penta_diagonal(plan)
deallocat the solver
    Report Typos and Errors