Report Typos and Errors    
Semi-Lagrangian Library
Modular library for kinetic and gyrokinetic simulations of plasmas in fusion energy devices.
sll_m_spline_matrix_banded.F90
Go to the documentation of this file.
1 
5 
7 
8 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
9 #include "sll_assert.h"
10 #include "sll_errors.h"
11 
12  use sll_m_working_precision, only: f64
13 
14  use sll_m_spline_matrix_base, only: &
16 
17  use iso_fortran_env, only: output_unit
18 
19  implicit none
20 
22 
23  private
24 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
25 
27  integer, parameter :: wp = f64
28 
29  !-----------------------------------------------------------------------------
31  !-----------------------------------------------------------------------------
33 
34  integer :: n
35  integer :: kl
36  integer :: ku
37  integer, allocatable :: ipiv(:)
38  real(wp), allocatable :: q(:, :)
39 
40  contains
41 
42  procedure :: init => s_spline_matrix_banded__init
43  procedure :: set_element => s_spline_matrix_banded__set_element
44  procedure :: factorize => s_spline_matrix_banded__factorize
45  procedure :: solve_inplace => s_spline_matrix_banded__solve_inplace
46  procedure :: write => s_spline_matrix_banded__write
47  procedure :: free => s_spline_matrix_banded__free
48 
50 
51  !-----------------------------------------------------------------------------
52  ! Interfaces to LAPACK subroutines (www.netlib.org/lapack)
53  !-----------------------------------------------------------------------------
54  interface
55 
56  ! LU factorization of a real M-by-N band matrix A using partial pivoting
57  ! with row interchanges
58  subroutine dgbtrf(m, n, kl, ku, ab, ldab, ipiv, info)
59  integer, intent(in) :: m ! no. of rows
60  integer, intent(in) :: n ! no. of columns
61  integer, intent(in) :: kl ! no. of subdiagonals
62  integer, intent(in) :: ku ! no. of superdiagonals
63  double precision, intent(inout) :: ab(ldab, n) ! matrix A in band storage
64  integer, intent(in) :: ldab ! leading dimension of A
65  integer, intent(out) :: ipiv(min(m, n))! pivot indices
66  integer, intent(out) :: info ! 0 if successful
67  end subroutine dgbtrf
68 
69  ! Solution of the linear system A*X=B or A^T*X=B with a general band
70  ! matrix A using the LU factorization computed by DGBTRF
71  subroutine dgbtrs(trans, n, kl, ku, nrhs, ab, ldab, ipiv, b, ldb, info)
72  character(len=1), intent(in) :: trans ! form of system of eqns.
73  integer, intent(in) :: n ! order of matrix A
74  integer, intent(in) :: kl ! no. of subdiagonals
75  integer, intent(in) :: ku ! no. of superdiagonals
76  integer, intent(in) :: nrhs ! no. of right hand sides
77  double precision, intent(in) :: ab(ldab, n) ! LU factors (A=P*L*U)
78  integer, intent(in) :: ldab ! leading dimension of A
79  integer, intent(in) :: ipiv(n) ! pivot indices
80  double precision, intent(inout) :: b(ldb, nrhs) ! B on entry, X on exit
81  integer, intent(in) :: ldb ! leading dimension of B
82  integer, intent(out) :: info ! 0 if successful
83  end subroutine dgbtrs
84 
85  end interface
86 
87 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
88 contains
89 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
90 
91  !-----------------------------------------------------------------------------
92  subroutine s_spline_matrix_banded__init(self, n, kl, ku)
93  class(sll_t_spline_matrix_banded), intent(out) :: self
94  integer, intent(in) :: n
95  integer, intent(in) :: kl
96  integer, intent(in) :: ku
97 
98  sll_assert(n > 0)
99  sll_assert(kl >= 0)
100  sll_assert(ku >= 0)
101  sll_assert(kl < n)
102  sll_assert(ku < n)
103 
104  self%n = n
105  self%kl = kl
106  self%ku = ku
107 
108  ! Given the linear system A*x=b, we assume that A is a square (n by n)
109  ! with ku super-diagonals and kl sub-diagonals.
110  ! All non-zero elements of A are stored in the rectangular matrix q, using
111  ! the format required by DGBTRF (LAPACK): diagonals of A are rows of q.
112  ! q has 2*kl rows for the subdiagonals, 1 row for the diagonal, and ku rows
113  ! for the superdiagonals. (The kl additional rows are needed for pivoting.)
114  ! The term A(i,j) of the full matrix is stored in q(i-j+2*kl+1,j).
115 
116  allocate (self%ipiv(n))
117  allocate (self%q(2*kl + ku + 1, n))
118  self%q(:, :) = 0.0_wp
119 
120  end subroutine s_spline_matrix_banded__init
121 
122  !-----------------------------------------------------------------------------
123  subroutine s_spline_matrix_banded__set_element(self, i, j, a_ij)
124  class(sll_t_spline_matrix_banded), intent(inout) :: self
125  integer, intent(in) :: i
126  integer, intent(in) :: j
127  real(wp), intent(in) :: a_ij
128 
129  sll_assert(max(1, j - self%ku) <= i)
130  sll_assert(i <= min(self%n, j + self%kl))
131 
132  self%q(self%kl + self%ku + 1 + i - j, j) = a_ij
133 
135 
136  !-----------------------------------------------------------------------------
138  class(sll_t_spline_matrix_banded), intent(inout) :: self
139 
140  integer :: info
141 
142  character(len=*), parameter :: &
143  this_sub_name = "sll_t_spline_matrix_banded % factorize"
144  character(len=256) :: err_msg
145 
146  ! Perform LU decomposition of matrix q with Lapack
147  call dgbtrf(self%n, self%n, self%kl, self%ku, self%q, 2*self%kl + self%ku + 1, &
148  self%ipiv, info)
149 
150  if (info < 0) then
151  write (err_msg, '(i0,a)') abs(info), "-th argument had an illegal value"
152  sll_error(this_sub_name, err_msg)
153  else if (info > 0) then
154  write (err_msg, "('U(',i0,',',i0,')',a)") info, info, &
155  " is exactly zero. The factorization has been completed, but the factor" &
156  //" U is exactly singular, and division by zero will occur if it is used to" &
157  //" solve a system of equations."
158  sll_error(this_sub_name, err_msg)
159  end if
160 
161  end subroutine s_spline_matrix_banded__factorize
162 
163  !-----------------------------------------------------------------------------
165  class(sll_t_spline_matrix_banded), intent(in) :: self
166  real(wp), intent(inout) :: bx(:)
167 
168  integer :: info
169 
170  character(len=*), parameter :: &
171  this_sub_name = "sll_t_spline_matrix_banded % solve_inplace"
172  character(len=256) :: err_msg
173 
174  sll_assert(size(bx) == self%n)
175 
176  call dgbtrs('N', self%n, self%kl, self%ku, 1, self%q, 2*self%kl + self%ku + 1, &
177  self%ipiv, bx, self%n, info)
178 
179  if (info < 0) then
180  write (err_msg, '(i0,a)') abs(info), "-th argument had an illegal value"
181  sll_error(this_sub_name, err_msg)
182  end if
183 
185 
186  !-----------------------------------------------------------------------------
187  subroutine s_spline_matrix_banded__write(self, unit, fmt)
188  class(sll_t_spline_matrix_banded), intent(in) :: self
189  integer, optional, intent(in) :: unit
190  character(len=*), optional, intent(in) :: fmt
191 
192  integer :: i, j
193  integer :: unit_loc
194  character(len=32) :: fmt_loc
195 
196  if (present(unit)) then
197  unit_loc = unit
198  else
199  unit_loc = output_unit
200  end if
201 
202  if (present(fmt)) then
203  fmt_loc = fmt
204  else
205  fmt_loc = 'es9.1'
206  end if
207 
208  write (fmt_loc, '(a)') "("//trim(fmt_loc)//")"
209 
210  do i = 1, self%n
211  do j = 1, self%n
212  if (max(1, j - self%ku) <= i .and. i <= min(self%n, j + self%kl)) then
213  write (unit_loc, fmt_loc, advance='no') self%q(self%kl + self%ku + 1 + i - j, j)
214  else
215  write (unit_loc, fmt_loc, advance='no') 0.0_wp
216  end if
217  end do
218  write (unit_loc, *)
219  end do
220 
221  end subroutine s_spline_matrix_banded__write
222 
223  !-----------------------------------------------------------------------------
225  class(sll_t_spline_matrix_banded), intent(inout) :: self
226 
227  self%n = -1
228  self%kl = -1
229  self%ku = -1
230  if (allocated(self%ipiv)) deallocate (self%ipiv)
231  if (allocated(self%q)) deallocate (self%q)
232 
233  end subroutine s_spline_matrix_banded__free
234 
Derived type for banded matrices.
integer, parameter wp
Working precision.
subroutine s_spline_matrix_banded__init(self, n, kl, ku)
subroutine s_spline_matrix_banded__write(self, unit, fmt)
subroutine s_spline_matrix_banded__solve_inplace(self, bx)
subroutine s_spline_matrix_banded__set_element(self, i, j, a_ij)
Abstract class for small matrix library with basic operations: set matrix element,...
Module to select the kind parameter.
integer, parameter, public f64
f64 is the kind type for 64-bit reals (double precision)
    Report Typos and Errors