pardiso_class.f90
Go to the documentation of this file.
1 !> @file pardiso_class.f90
2 !!
3 !! The error file code for this file is ***W35***.
4 !!
5 !! @brief Module \ref pardiso_class with the sparse solver
6 !!
7 
8 !> Contains subroutines for sparse matrix assembly and
9 !! the solver core
10 !!
11 !! @note this module used to be split
12 !! into two: cscf and pardiso_class
13 !!
14 !! @author Christian Winteler
15 !! @date 27.10.2009
16 !!
17 !! \b Edited:
18 !! - 14.01.14, Oleg Korobkin
19 !! - 7.11.16, Oleg Korobkin
20 !! - 6.04.18, M. Jacobi
21 !! - 24.07.22, M. Reichert
22 !! .
23 #include "macros.h"
26  use global_class, only: net_size
27  implicit none
28 
29  ! Variables are used in the jacobian class and the flow_module
30  real(r_kind),dimension(:),allocatable, public :: vals !< contains non-zero matrix elements (of the Jacobian)
31  integer,dimension(:),allocatable , public :: rows !< rows(i) is the number of the row in the matrix that contains the i-th value in vals
32  integer,dimension(:),allocatable , public :: pt_b !< pt_b(j) gives the index into vals that contains the FIRST non-zero element of column j of the matrix
33  integer,dimension(:),allocatable , public :: pt_e !< pt_e(j)-pt_b(j) gives the index into vals that contains the LAST non-zero element of column j of the matrix
34  integer,dimension(:),allocatable , public :: dia !< dia(j) gives the index into vals that contains the (j,j) diagonal element of the matrix
35  integer,dimension(:,:),allocatable , public :: jind !< jind(i,j) contains the index of jacobian entry in vals
36 
37  !
38  ! Public and private fields and methods of the module.
39  !
40  public:: &
42  ! private:: &
43  ! nothing here
44 
45 contains
46 
47 
48 
49 !> Determines the position of jacobian entries in the cscf value array.
50 !!
51 !! This subroutine creates the basic sparse format of the jacobian. For this
52 !! it writes a dummy matrix with entries = 1 at places in the matrix
53 !! that are connected via nuclear reaction rates. Afterwards the matrix
54 !! is stored in compressed sparse column format (cscf) into the arrays
55 !! \ref vals, \ref rows, and \ref pt_b.
56 !! In cscf format, the matrix:
57 !! \f[
58 !! X= \left( \begin{array}{cccc}
59 !! 9 & 8 & 0 & 2\\
60 !! 0 & 0 & 0 & 5\\
61 !! 0 & 3 & 0 & 0\\
62 !! 5 & 0 & 4 & 9\end{array} \right).
63 !! \f]
64 !! will be stored like
65 !! \f[ \mathrm{vals} =[9,5,8,3,4,2,5,9] \f]
66 !! with vals storing the non-zero values of X,
67 !! \f[ \mathrm{rows} = [1,4,1,3,4,1,2,4] \f]
68 !! rows storing the position of a new row in vals, and
69 !! \f[ \mathrm{pt\_b} = [1,3,5,6,9] \f].
70 !! the position of the columns of the non-zero entries.
71 !!
72 !! @see [Winteler 2013](https://edoc.unibas.ch/29895/), section 2.4.2
73 !!
74 !! \b Edited:
75 !! - 11.01.14
76 !! - 28.07.22, MR: introduced new chapters
77 !! .
78 subroutine sparse
81  use parameter_class, only: fissflag
82  implicit none
83 
84  integer :: i,j,n !< loop variables
85  type(reactionrate_type) :: rr_tmp !< Temporary reaction rate variable
86  integer, dimension(net_size*net_size) :: ja_t
87  integer, dimension(:,:),allocatable :: cscf_tmp_fiss
88  integer, dimension(4,6) :: cscf_tmp
89  integer :: cnt
90 
91  info_entry("sparse")
92  n = net_size
93  allocate(pt_b(n+1))
94  allocate(pt_e(n))
95  allocate(dia(n))
96  allocate(jind(n,n))
97  jind = 0
98 
99 !---- Write dummy jacobian
100  do i = 1,n
101  jind(i,i) = 1
102  end do
103 
104  do i=1, nreac
105  rr_tmp = rrate(i)
106  select case (rr_tmp%group)
107  case(1:3,11)
108  if ((rr_tmp%reac_type.eq.rrt_sf).or.(rr_tmp%reac_type.eq.rrt_bf)) cycle ! fission
109  do j=1,5
110  if (rr_tmp%parts(j).eq.0) exit
111  jind(rr_tmp%parts(1),rr_tmp%parts(j)) = 1
112  end do
113  case(4:7)
114  if (rr_tmp%reac_type.eq.rrt_nf) cycle ! n-induced fission reaction
115  do j=1,6
116  if (rr_tmp%parts(j).eq.0) exit
117  jind(rr_tmp%parts(1),rr_tmp%parts(j)) = 1
118  jind(rr_tmp%parts(2),rr_tmp%parts(j)) = 1
119  end do
120  case(8:9)
121  do j=1,6
122  if (rr_tmp%parts(j).eq.0) exit
123  jind(rr_tmp%parts(1),rr_tmp%parts(j)) = 1
124  jind(rr_tmp%parts(2),rr_tmp%parts(j)) = 1
125  jind(rr_tmp%parts(3),rr_tmp%parts(j)) = 1
126  end do
127  case(10)
128  do j=1,6
129  if (rr_tmp%parts(j).eq.0) exit
130  jind(rr_tmp%parts(1),rr_tmp%parts(j)) = 1
131  jind(rr_tmp%parts(2),rr_tmp%parts(j)) = 1
132  jind(rr_tmp%parts(3),rr_tmp%parts(j)) = 1
133  jind(rr_tmp%parts(4),rr_tmp%parts(j)) = 1
134  end do
135  end select
136  end do
137 
138  if (fissflag.ne.0) then
139  do i=1,nfiss
140  do j=1,fissrate(i)%dimens
141  jind(fissrate(i)%fissnuc_index,fissrate(i)%fissparts(j)) = 1
142  if (fissrate(i)%reac_type.eq. rrt_nf) then ! neutron-induced fission
143  jind(ineu,fissrate(i)%fissparts(j)) = 1
144  end if
145  end do
146  end do
147  end if
148 
149 !---- convert dummy jacobian to compressed sparse column format and
150 !---- write the index in a for a combination (i,j) into the jacobian
151 !---- at the corresponding position
152  ja_t = 0
153  pt_b = -1
154  cnt = 0
155  do i=1,n
156  do j=1,n
157  if (jind(j,i).eq.0) cycle
158  cnt = cnt + 1
159  if (j.eq.i) dia(i)=cnt
160  jind(j,i) = cnt
161  ja_t(cnt) = j
162  if (pt_b(i).lt.0)pt_b(i)=cnt
163  end do
164  pt_e(i) = cnt + 1
165  end do
166  pt_b(n+1) = cnt + 1
167 
168  allocate(vals(cnt))
169  allocate(rows(cnt))
170  rows = ja_t(1:cnt)
171 
172 !---- write the index in the dummy jacobian into cscf_ind of the
173 !---- corresponding reactionrates
174  do i=1, nreac
175  rr_tmp = rrate(i)
176  cscf_tmp = 0
177  select case (rr_tmp%group)
178  case(1:3,11)
179  if ((rr_tmp%reac_type.eq.rrt_sf).or.(rr_tmp%reac_type.eq.rrt_bf)) cycle ! fission
180  do j=1,5
181  if (rr_tmp%parts(j).eq.0) exit
182  cscf_tmp(1,j)=jind(rr_tmp%parts(1),rr_tmp%parts(j))
183  end do
184  case(4:7)
185  if (rr_tmp%reac_type.eq.rrt_nf) cycle ! n-induced fission
186  do j=1,6
187  if (rr_tmp%parts(j).eq.0) exit
188  cscf_tmp(1,j)=jind(rr_tmp%parts(1),rr_tmp%parts(j))
189  cscf_tmp(2,j)=jind(rr_tmp%parts(2),rr_tmp%parts(j))
190  end do
191  case(8:9)
192  do j=1,6
193  if (rr_tmp%parts(j).eq.0) exit
194  cscf_tmp(1,j)=jind(rr_tmp%parts(1),rr_tmp%parts(j))
195  cscf_tmp(2,j)=jind(rr_tmp%parts(2),rr_tmp%parts(j))
196  cscf_tmp(3,j)=jind(rr_tmp%parts(3),rr_tmp%parts(j))
197  end do
198  case(10)
199  do j=1,6
200  if (rr_tmp%parts(j).eq.0) exit
201  cscf_tmp(1,j)=jind(rr_tmp%parts(1),rr_tmp%parts(j))
202  cscf_tmp(2,j)=jind(rr_tmp%parts(2),rr_tmp%parts(j))
203  cscf_tmp(3,j)=jind(rr_tmp%parts(3),rr_tmp%parts(j))
204  cscf_tmp(4,j)=jind(rr_tmp%parts(4),rr_tmp%parts(j))
205  end do
206  end select
207 
208  rrate(i)%cscf_ind = cscf_tmp
209  end do
210 
211  if (fissflag.ne.0) then
212  do i=1,nfiss
213  ! Size to correct dimensions, take care that it doesnt get allocated twice
214  if (allocated(cscf_tmp_fiss)) deallocate(cscf_tmp_fiss)
215  allocate(cscf_tmp_fiss(2,fissrate(i)%dimens))
216 
217  do j=1,fissrate(i)%dimens
218  if (fissrate(i)%reac_type .eq. rrt_nf) then
219  cscf_tmp_fiss(1,j) = jind(ineu,fissrate(i)%fissparts(j))
220  cscf_tmp_fiss(2,j) = jind(fissrate(i)%fissnuc_index,fissrate(i)%fissparts(j))
221  else
222  cscf_tmp_fiss(1,j) = jind(fissrate(i)%fissnuc_index,fissrate(i)%fissparts(j))
223  end if
224  end do
225  allocate(fissrate(i)%cscf_ind(2,fissrate(i)%dimens))
226  fissrate(i)%cscf_ind = cscf_tmp_fiss
227  end do
228  end if
229 
230  info_exit("sparse")
231 
232 end subroutine sparse
233 
234 
235 !>
236 !! The solver core
237 !!
238 !! This subroutine calls the sparse PARDISO solver
239 !! [intel pardiso](https://software.intel.com/en-us/node/470282) to
240 !! solve equations in the following form:
241 !! \f[ J\cdot \mathrm{res} = \mathrm{rhs} \f]
242 !! with res being the unknown. In addition, this subroutine
243 !! checks for zero entries in vals and adjusts the sparse
244 !! format accordingly.
245 !!
246 subroutine netsolve(rhs, res)
247  use parameter_class, only: solver
248  implicit none
249 
250  real(r_kind),dimension(net_size),intent(inout) :: rhs !< right-hand sides of the system
251  real(r_kind),dimension(net_size),intent(inout) :: res !< resulting abundances
252 
253 !!! definitions for sparse matrix solver pardiso
254  integer*8 ::pt(64)
255 !!! all other variables
256  integer :: i, j
257  integer :: maxfct, mnum, mtype, phase, nrhs, error, msglvl
258  integer :: iparm(64)
259  integer :: ia_par(net_size+1)
260  integer, dimension(:), allocatable :: ja_par
261  real(r_kind), dimension(:), allocatable :: a_par
262  real(r_kind) :: el(net_size)
263  integer :: idum(1)
264  real(r_kind) :: ddum(1)
265  integer :: cnt
266  integer :: nthreads
267  character*3 :: omp_env
268  integer :: nz_cnt
269 
270  data nrhs /1/, maxfct /1/, mnum /1/
271 
272  info_entry("netsolve")
273 
274  nz_cnt = count(vals.ne.0.d0)
275  allocate(ja_par(nz_cnt))
276  allocate(a_par(nz_cnt))
277  ! Check if entries are zero and adjust
278  ! sparse format
279  cnt = 0
280  ia_par = -1
281  do i=1,net_size
282  do j=pt_b(i),pt_e(i)-1
283  if(vals(j).eq.0.d0) cycle
284  cnt = cnt + 1
285  a_par(cnt) = vals(j)
286  ja_par(cnt) = rows(j)
287  if (ia_par(i).lt.0) ia_par(i) = cnt
288  end do
289  end do
290  ia_par(net_size+1) = cnt+1
291 
292  el = rhs
293 
294 ! setup pardiso control parameters and initialize the solvers
295 ! internal adress pointers. this is only necessary for the first
296 ! call of the pardiso solver.
297 !
298  mtype = 11 ! unsymmetric matrix
299  call pardisoinit(pt, mtype, iparm)
300 ! numbers of processors ( value of omp_num_threads )
301  call getenv('OMP_NUM_THREADS',omp_env)
302  ! Check if variable is set, set threads to 1 if not
303  if (len_trim(omp_env)==0)then
304  nthreads=1
305  else
306  read(omp_env,'(i3)')nthreads
307  endif
308 
309  iparm(3) = nthreads
310 ! iparm(4) = 61 ???
311 ! iparm(11) = 1 ???
312 ! iparm(13) = 1 ???
313  msglvl = 0 ! without statistical information
314  iparm(8) = 10 ! max numbers of iterative refinement steps
315  iparm(10) = 13
316  phase = 13 ! analysis, numerical factorization, solve, iterative refinement
317 
318  idum = 0
319  call pardiso (pt, maxfct, mnum, mtype, phase, net_size, a_par, ia_par, ja_par, &
320  idum, nrhs, iparm, msglvl, rhs, el, error)
321 
322 ! termination and release of memory
323  phase = -1 ! release internal memory
324  call pardiso (pt, maxfct, mnum, mtype, phase, net_size, ddum, idum, idum,&
325  idum, nrhs, iparm, msglvl, ddum, ddum, error)
326 
327 ! check solution for NaNs
328  do i=1, net_size
329  if (el(i).ne.el(i)) then
330  call raise_exception("el(i) is NaN","netsolve",350003)
331  endif
332  end do
333 
334 ! form output vectors
335  select case (solver)
336  case(0) ! implicit Euler solver
337  do i=1, net_size
338  if((i.gt.2).and.(el(i) .lt. 1.d-25)) el(i) = 0.d0
339  rhs(i) = el(i) - res(i)
340  res(i) = el(i)
341  end do
342  case(1) ! Gear solver
343  res(1:net_size) = el(1:net_size)
344  case default
345  call raise_exception("Solver flag ("//trim(adjustl(int_to_str(solver)))//") not known."//&
346  new_line("A")//'Choose either "1" or "2".',"netsolve",350004)
347  endselect
348 
349 ! end call pardiso
350  deallocate(a_par)
351  deallocate(ja_par)
352  info_exit("netsolve")
353  return
354 
355 end subroutine netsolve
356 
357 end module pardiso_class
pardiso_class::vals
real(r_kind), dimension(:), allocatable, public vals
contains non-zero matrix elements (of the Jacobian)
Definition: pardiso_class.f90:30
rrt_nf
#define rrt_nf
Definition: macros.h:78
global_class::reactionrate_type
reaction rate type
Definition: global_class.f90:44
global_class::rrate
type(reactionrate_type), dimension(:), allocatable, public rrate
array containing all reaction rates used in the network
Definition: global_class.f90:65
error_msg_class
Error handling routines.
Definition: error_msg_class.f90:16
fission_rate_module
Module to deal with fission reactions.
Definition: fission_rate_module.f90:16
error_msg_class::int_to_str
character(:) function, allocatable, public int_to_str(num)
Converts a given integer to a string.
Definition: error_msg_class.f90:224
pardiso_class::netsolve
subroutine, public netsolve(rhs, res)
The solver core.
Definition: pardiso_class.f90:247
pardiso_class::dia
integer, dimension(:), allocatable, public dia
dia(j) gives the index into vals that contains the (j,j) diagonal element of the matrix
Definition: pardiso_class.f90:34
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
fission_rate_module::nfiss
integer, public nfiss
Amount of fission rates.
Definition: fission_rate_module.f90:68
pardiso_class::pt_e
integer, dimension(:), allocatable, public pt_e
pt_e(j)-pt_b(j) gives the index into vals that contains the LAST non-zero element of column j of the ...
Definition: pardiso_class.f90:33
global_class::ineu
integer, public ineu
Definition: global_class.f90:94
pardiso_class::jind
integer, dimension(:,:), allocatable, public jind
jind(i,j) contains the index of jacobian entry in vals
Definition: pardiso_class.f90:35
parameter_class::fissflag
integer fissflag
defines type of fission fragment distribution used
Definition: parameter_class.f90:86
parameter_class::solver
integer solver
solver flag (0 - implicit Euler, 1 - Gear's method, ...), is integer as it is faster than comparing s...
Definition: parameter_class.f90:147
global_class::net_size
integer, public net_size
total number of isotopes (network size)
Definition: global_class.f90:93
fission_rate_module::fissrate
type(fissionrate_type), dimension(:), allocatable, public fissrate
Array storing fission reactions.
Definition: fission_rate_module.f90:39
error_msg_class::num_to_str
character(:) function, allocatable, public num_to_str(num)
Converts a given real to a string with format "(1pE10.2)".
Definition: error_msg_class.f90:205
pardiso_class
Contains subroutines for sparse matrix assembly and the solver core.
Definition: pardiso_class.f90:24
pardiso_class::rows
integer, dimension(:), allocatable, public rows
rows(i) is the number of the row in the matrix that contains the i-th value in vals
Definition: pardiso_class.f90:31
r_kind
#define r_kind
Definition: macros.h:46
pardiso_class::pt_b
integer, dimension(:), allocatable, public pt_b
pt_b(j) gives the index into vals that contains the FIRST non-zero element of column j of the matrix
Definition: pardiso_class.f90:32
global_class
Contains types and objects shared between multiple modules.
Definition: global_class.f90:19
global_class::nreac
integer, public nreac
total number of reactions
Definition: global_class.f90:98
rrt_bf
#define rrt_bf
Definition: macros.h:79
rrt_sf
#define rrt_sf
Definition: macros.h:80
pardiso_class::sparse
subroutine, public sparse
Determines the position of jacobian entries in the cscf value array.
Definition: pardiso_class.f90:79
parameter_class
Contains all runtime parameters as well as phys and math constants.
Definition: parameter_class.f90:24