mergesort_module.f90
Go to the documentation of this file.
1 !> @file mergesort_class.f90
2 !!
3 !! The error file code for this file is ***W29***.
4 !! Contains the module \ref mergesort_module.
5 
6 !>
7 !! Module \ref mergesort_module for merging arrays of rates
8 !!
9 !! A mergesort is a recursive algorithm to sort arrays.
10 !! It works as illustrated in these two figures (Source: en.wikipedia)
11 !! <div class="row">
12 !! @image html https://upload.wikimedia.org/wikipedia/commons/e/e6/Merge_sort_algorithm_diagram.svg "Illustration of a mergesort" height=280
13 !! @image html https://upload.wikimedia.org/wikipedia/commons/c/c5/Merge_sort_animation2.gif "Illustration of a mergesort" height=280 </div>
14 !!
15 #include "macros.h"
18  implicit none
19 
20  integer, private :: debug_tabl !< File ID for debugging tabulated rate class
21 
22  !
23  ! Public and private fields and methods of the module
24  !
25  public:: &
28  private:: &
29  qsort
30 
31 contains
32 
33 
34 
35 
36 !>
37 !! Initialize the mergesort module and open files for debugging.
38 !!
39 !! The file _debug_tabln.dat_ is created in case of
40 !! verbose_level>2.
41 !!
42 !! @author Moritz Reichert
43 !!
44 !! \b Edited:
45 !! - 06.06.17
46 !! .
47 subroutine mergesort_init()
50  implicit none
51 
52  ! Debugging
53  if (verbose_level .gt. 2) then
54 
55  if (use_tabulated_rates) then
56  ! Open debug file and write a header for the tabulated rates
57  debug_tabl = open_outfile('debug_tabln.dat')
58  write(debug_tabl,'(A)') '# This file contains data to debug the subroutine rrate_qs_replace, contained in mergesort_module.f90'
59  end if
60  end if
61 
62 end subroutine mergesort_init
63 
64 
65 
66 !>
67 !! Merges two tables of neutrino rates (of type global_class::nurate_type).
68 !!
69 !! Parameter r is a flag with the following meaning:
70 !!
71 !! <table>
72 !! <caption id="multi_row">Explanation of the flag "r"</caption>
73 !! <tr><th> r mode <th> Behavior
74 !! <tr><td> 1 <td> Values of y replace corresponding values of x
75 !! <tr><td> 2 <td> Values of x replace corresponding values of y
76 !! <tr><td> other <td> Both values are stored one after the other\
77 !! </table>
78 !!
79 !! @remark At the moment, this function is only called with \f$ r=0 \f$
80 !! i.e., case "other".
81 !!
82 !! @see rrate_ms, network_init_module::network_init
83 !!
84 !! \b Edited:
85 !! - 11.01.14
86 !! .
87 subroutine nurate_ms(x,xs,y,ys,r)
88  use global_class, only: nurate_type, nurate
89 
90  implicit none
91 
92  integer, intent(in) :: xs !< Length of x
93  integer, intent(in) :: ys !< Length of y
94  type(nurate_type),dimension(xs),intent(in) :: x !< the first nurates table
95  type(nurate_type),dimension(ys),intent(in) :: y !< the second nurates table
96  integer, intent(in) :: r !< flag
97  !
98  type(nurate_type), dimension(:), allocatable :: tmp
99  integer :: x1,x2,y1,y2,n
100  integer :: ptx, pty, ptz
101  integer :: fin
102  integer :: ptb, pte
103  integer :: i
104  integer :: istat
105 
106  n = xs+ys
107  ptx = 1
108  pty = 1
109  ptz = 1
110  fin = 0
111 
112  allocate(tmp(n),stat=istat)
113  if (istat /= 0) call raise_exception('Allocation of "tmp" failed.',&
114  "nurate_ms",290001)
115 
116  do while (fin.eq.0)
117  x1 = x(ptx)%parts(1)
118  x2 = x(ptx)%parts(2)
119 
120  y1 = y(pty)%parts(1)
121  y2 = y(pty)%parts(2)
122 
123  select case(x1 - y1)
124  case(:-1)
125  tmp(ptz) = x(ptx)
126  ptx = ptx+1
127  ptz = ptz+1
128  case(1:)
129  tmp(ptz) = y(pty)
130  pty = pty+1
131  ptz = ptz+1
132  case(0)
133  select case(x2 - y2)
134  case(:-1)
135  tmp(ptz) = x(ptx)
136  ptx = ptx+1
137  ptz = ptz+1
138  case(1:)
139  tmp(ptz) = y(pty)
140  pty = pty+1
141  ptz = ptz+1
142  case(0)
143  select case(r)
144  case(1)
145  tmp(ptz) = y(pty)
146  pty = pty+1
147  ptx = ptx+1
148  ptz = ptz+1
149  case(2)
150  tmp(ptz) = x(ptx)
151  pty = pty+1
152  ptx = ptx+1
153  ptz = ptz+1
154  case default
155  tmp(ptz) = x(ptx)
156  ptx = ptx+1
157  ptz = ptz+1
158  tmp(ptz) = y(pty)
159  pty = pty+1
160  ptz = ptz+1
161  end select
162  end select
163  end select
164  if (ptx.gt.xs) fin = fin+1
165  if (pty.gt.ys) fin = fin+2
166  end do
167 
168  if (fin .eq. 1) then
169  ptb = pty
170  pte = ys
171  else if (fin.eq.2) then
172  ptb = ptx
173  pte = xs
174  else
175  ptz = ptz -1
176  if(allocated(nurate)) deallocate(nurate)
177  allocate(nurate(ptz))
178  nurate = tmp(1:ptz)
179  deallocate(tmp)
180  return
181  end if
182 
183  do i = ptb,pte
184  if (fin.eq.1) tmp(ptz) = y(i)
185  if (fin.eq.2) tmp(ptz) = x(i)
186  ptz = ptz+1
187  end do
188 
189  ptz = ptz -1
190  if(allocated(nurate)) deallocate(nurate)
191  allocate(nurate(ptz))
192  nurate = tmp(1:ptz)
193  deallocate(tmp)
194 
195  return
196 end subroutine nurate_ms
197 
198 
199 !>
200 !! Merges two tables of rates (of type global_class::reactionrate_type).
201 !!
202 !! Parameter r is a flag with the following meaning:
203 !!
204 !! <table>
205 !! <caption id="multi_row">Evolution mode switches</caption>
206 !! <tr><th> r mode <th> Behavior
207 !! <tr><td> 1 <td> Values of y replace corresponding values of x
208 !! <tr><td> 2 <td> Values of x replace corresponding values of y
209 !! <tr><td> other <td> Both values are stored one after the other\
210 !! </table>
211 !!
212 !! In case of theoretical weak rates that get merged, this function counts
213 !! the amount of rates that get replaced.
214 !!
215 !! @remark The function is used to merge the rate array with theoretical weak rates
216 !! (with r=1) and neutrino rates (r=0).
217 !!
218 !!
219 !! @see nurate_ms, network_init_module::network_init
220 !!
221 !! \b Edited:
222 !! - 17.02.14
223 !! - 27.01.21, MR - introduced "rate_out" instead of writing directly to rrate
224 !! - 04.08.22, MR - removed hardcoded " ffn" flag and replaced it with "rrs_twr"
225 !! .
226  subroutine rrate_ms(x,xs,y,ys,r,ptz,rate_out)
229  use global_class, only: rrate_weak_exp
231  implicit none
232 
233  integer, intent(in) :: xs !< Length of x
234  integer, intent(in) :: ys !< Length of y
235  type(reactionrate_type),dimension(xs),intent(in) :: x !< the first nurates table
236  type(reactionrate_type),dimension(ys),intent(in) :: y !< the second nurates table
237  integer, intent(in) :: r !< flag
238  integer, intent(out) :: ptz!< length of new (merged) array
239  type(reactionrate_type), dimension(:), &
240  allocatable,optional, intent(out) :: rate_out !< returns the merged
241  !< reactions in this array, if present
242  !
243  type(reactionrate_type), dimension(:), allocatable :: tmp
244  type(reactionrate_type), dimension(:), allocatable :: tmp2
245  integer :: x1,x2,y1,y2,n
246  integer :: ptx, pty
247  integer :: fin
248  integer :: ptb, pte
249  integer :: alloc_stat !< Allocation status flag
250  integer :: i
251  integer :: rp
252 
253  n = xs+ys
254  ptx = 1
255  pty = 1
256  ptz = 1
257  fin = 0
258  rp = 0
259 
260  allocate(tmp(n))
261 
262  !common_weak_rates = 0
263  !only_theo_weak_rates = 0
264  if (y(pty)%reac_src .eq. rrs_twr) then
265  if (.not. allocated(tmp2)) allocate(tmp2(ys))
266  end if
267 
268  do while (fin.eq.0)
269  x1 = x(ptx)%parts(1)
270  x2 = x(ptx)%parts(2)
271 
272  y1 = y(pty)%parts(1)
273  y2 = y(pty)%parts(2)
274 
275  select case(r)
276  case(1)
277  if(ptz.gt.1) then
278  if(rp.eq.1) then
279  if((x1.eq.tmp(ptz-1)%parts(1)).and.(x2.eq.tmp(ptz-1)%parts(2))) then
280  ptx=ptx+1
281  cycle
282  end if
283  end if
284  end if
285  case(2)
286  if(ptz.gt.1) then
287  if(rp.eq.1) then
288  if((y1.eq.tmp(ptz-1)%parts(1)).and.(y2.eq.tmp(ptz-1)%parts(2))) then
289  pty=pty+1
290  cycle
291  end if
292  end if
293  end if
294  end select
295  rp = 0
296  select case(x1 - y1)
297  case(:-1)
298  tmp(ptz) = x(ptx)
299  ptx = ptx+1
300  ptz = ptz+1
301  case(1:)
302  tmp(ptz) = y(pty)
303  if (y(pty)%reac_src .eq. rrs_twr) then
304  only_theo_weak_rates = only_theo_weak_rates + 1
305  end if
306  pty = pty+1
307  ptz = ptz+1
308  case(0)
309  select case(x2 - y2)
310  case(:-1)
311  tmp(ptz) = x(ptx)
312  ptx = ptx+1
313  ptz = ptz+1
314  case(1:)
315  tmp(ptz) = y(pty)
316  if (y(pty)%reac_src .eq. rrs_twr) then
317  only_theo_weak_rates = only_theo_weak_rates + 1
318  end if
319  pty = pty+1
320  ptz = ptz+1
321  case(0)
322  select case(r)
323  case(1)
324  tmp(ptz) = y(pty)
325  pty = pty+1
326  ptx = ptx+1
327  ptz = ptz+1
328  rp = 1
329  case(2)
330  tmp(ptz) = x(ptx)
331  pty = pty+1
332  ptx = ptx+1
333  ptz = ptz+1
334  rp = 1
335  case default
336  tmp(ptz) = x(ptx)
337  ptx = ptx+1
338  ptz = ptz+1
339  tmp(ptz) = y(pty)
340  pty = pty+1
341  ptz = ptz+1
342  end select
343  if (y(pty-1)%reac_src .eq. rrs_twr) then
344  common_weak_rates = common_weak_rates + 1
345  tmp2(common_weak_rates) = x(ptx-1)
346  end if
347  end select
348  end select
349  if (ptx.gt.xs) fin = fin+1
350  if (pty.gt.ys) fin = fin+2
351  end do
352 
353  if (fin .eq. 1) then
354  ptb = pty
355  pte = ys
356  else if (fin.eq.2) then
357  ptb = ptx
358  pte = xs
359  else
360  ptz = ptz -1
361  if (present(rate_out))then
362  if (allocated(rate_out)) deallocate(rate_out)
363  allocate(rate_out(ptz),stat=alloc_stat)
364  rate_out(1:ptz) = tmp(1:ptz)
365  else
366  rrate(1:ptz) = tmp(1:ptz)
367  end if
368  deallocate(tmp)
369  return
370  end if
371 
372  do i = ptb,pte
373  if (fin.eq.1) then
374  tmp(ptz) = y(i)
375  if (y(i)%reac_src .eq. rrs_twr) then
376  only_theo_weak_rates = only_theo_weak_rates + 1
377  end if
378  end if
379  if (fin.eq.2) tmp(ptz) = x(i)
380  ptz = ptz+1
381  end do
382 
383  ptz = ptz -1
384  if (present(rate_out)) then
385  if (allocated(rate_out)) deallocate(rate_out)
386  allocate(rate_out(ptz),stat=alloc_stat)
387  if ( alloc_stat /= 0) call raise_exception('Allocation of "rrate_array" failed.',&
388  "merge_neutrino_rates",290001)
389  rate_out(1:ptz) = tmp(1:ptz)
390  else
391  rrate(1:ptz) = tmp(1:ptz) !< store directly into rrate and hope for the best
392  end if
393 
394  deallocate(tmp)
395 
396  if (y(1)%reac_src .eq. rrs_twr) then
397  if (.not. allocated(rrate_weak_exp)) allocate(rrate_weak_exp(common_weak_rates))
398  rrate_weak_exp(1:common_weak_rates) = tmp2(1:common_weak_rates)
399  deallocate(tmp2)
400  end if
401 
402  return
403  end subroutine rrate_ms
404 
405 
406 
407 !> Wrapper around the quicksort subroutine
408 !!
409 !! This subroutine is able to replace rates that appear with
410 !! multiple entries in the REACLIB (e.g., because it has a resonance)
411 !! with a tabulated rate. In debug mode, the file debug_tabln.dat
412 !! is written to debug this subroutine.
413 !!
414 !! @see qsort
415 !!
416 !! @author D. Martin
417 !!
418 !! \b Edited:
419 !! - 15.04.15
420 !! - 07.06.17
421 !! - 04.08.22, MR: removed hardcoded "tabl" flag and replaced it with "rrs_tabl"
422 !! - 05.08.22, MR: fixed bug and gave a new array as output (out_array)
423 !! .
424  subroutine rrate_qs_replace(x,xs,y,ys,r,out_array,ptz)
426 
427  implicit none
428 
429  integer, intent(in) :: r,xs,ys !< replacement rule, lenghts of arrays
430  type(reactionrate_type), dimension(xs), intent(in) :: x !< array 1 (rrate)
431  type(reactionrate_type), dimension(ys), intent(in) :: y !< array 2 (tabl)
432  type(reactionrate_type), dimension(:),allocatable, intent(out) :: out_array !< new merged array
433  integer, intent(out) :: ptz !y final length of merged array
434  !
435  type(reactionrate_type), dimension(:), allocatable :: tmp
436  integer :: n, i, j, k
437  integer :: nrduplicates
438  logical :: duplicate
439  type(reactionrate_type) :: tmp_find_duplicates
440  integer :: count_duplicates
441  integer :: tabl_position
442  integer :: new_rate_length
443  character(5),dimension(6) :: part_names ! For debugging
444 
445  duplicate = .false.
446 
447 
448  ! prepare array to be sorted
449  n = xs+ys
450  allocate(tmp(n))
451  tmp(1:xs) = x
452  tmp(xs+1:n) = y
453 
454  new_rate_length = n
455 
456  ! sort array
457  call qsort(tmp,n)
458  ! remove duplicates and create array without duplicates, if r!=0
459 
460  j = 1
461  nrduplicates = 0
462  if(r .ne. 0) then
463  do i=1,n-1
464  ! Prepare loops to identify the number of the duplicates and the position of the tabulated rate
465  tmp_find_duplicates = tmp(i)
466  count_duplicates = 1
467  if (tmp_find_duplicates%reac_src .eq. rrs_tabl) then
468  tabl_position = i
469  else
470  tabl_position = 0
471  end if
472 
473  do k =i, new_rate_length-1
474  if (all(tmp_find_duplicates%parts .eq. tmp(k+1)%parts) .and. &
475  (tmp_find_duplicates%group .eq. tmp(k+1)%group)) then
476  ! Count the amount of duplicates
477  count_duplicates= count_duplicates + 1
478  ! Check the position of the tabulated rate
479  if (tmp(k+1)%reac_src .eq. rrs_tabl) then
480  tabl_position = k+1
481  end if
482  else
483  exit
484  end if
485  end do
486 
487 
488  ! If there was a tabulated rate included, replace the first rate with that one
489  if (tabl_position .ne. 0) then
490  ! Write debug file
491  if (verbose_level .gt. 2) then
492  ! Convert parts to corresponding names
493  do k=1, 6
494  if (tmp_find_duplicates%parts(k) .ne. 0) then
495  part_names(k) = net_names(tmp_find_duplicates%parts(k))
496  else
497  part_names(k) = ' '
498  end if
499  end do
500  ! Write an output
501  write(debug_tabl,"('Replacing rate ',6a,' found ',i10,' reactions in Reaclib')") part_names(:),count_duplicates-1
502  end if
503 
504  ! Replace the first rate with the tabulated one
505  tmp(i) = tmp(tabl_position)
506  do k=i,new_rate_length - count_duplicates
507  tmp(k+1)=tmp(k+count_duplicates)
508  end do
509  new_rate_length = (new_rate_length - count_duplicates) + 1
510  end if
511 
512  ! Exit condition
513  if (i .ge. new_rate_length) then
514  exit
515  end if
516  enddo
517 
518 
519  if (verbose_level .gt. 2) then
520  ! Write an output
521  write(debug_tabl,*)
522  write(debug_tabl,'(A,i10,A)') 'Merged in ', n-xs, ' rates.'
523  end if
524 
525  endif
526  if (verbose_level .gt. 2) print *, "duplicates: ", new_rate_length
527 
528  ptz = new_rate_length
529 
530  allocate(out_array(new_rate_length))
531  ! TODO throw exception
532  ! assign rates to rrate
533  out_array(1:new_rate_length) = tmp(1:new_rate_length)
534  deallocate(tmp)
535 
536  return
537  end subroutine rrate_qs_replace
538 
539 
540 
541 !> Modified quicksort algorithm
542 !!
543 !! A quicksort is a recursive sorting algorithm. An illustration of it is shown
544 !! in the following (Source en.wikipedia):
545 !! @image html https://upload.wikimedia.org/wikipedia/commons/6/6a/Sorting_quicksort_anim.gif "Illustration of the quicksort" width=300
546 !! In this gif, the red indicated number is the so called pivot-element.
547 !!
548 !! @see [Rosettacode](http://rosettacode.org/wiki/Sorting_algorithms/Quicksort#Fortran),
549 !! rateSortKey, rrate_qs_replace
550 !!
551 !! \b Edited:
552 !! - 15.04.15
553 !! - 25.4.19, M.R.
554 !! .
555  recursive subroutine qsort(A,nA)
557 
558  implicit none
559 
560  ! DUMMY ARGUMENTS
561  type (reactionrate_type), dimension(nA), intent(in out) :: a !< Reaction rate array
562  integer, intent(in) :: na !< Length of the investigated reaction rate array.
563  !! The recursion anchor of the routine is given
564  !! for nA \f$\le =1 \f$.
565 
566  ! LOCAL VARIABLES
567  character(31) :: ratesortkey
568  integer :: left, right
569  real :: random
570  character(31) :: pivot
571  type (reactionrate_type) :: temp
572  integer :: marker, randi, clock
573  integer :: n
574  integer,dimension(:) ,allocatable :: variable_put
575  integer :: istat
576 
577 
578  if (na > 1) then
579 
580  call system_clock(count=clock)
581 
582  ! Get the size in order to call put properly and system independent
583  call random_seed(size=n)
584  allocate(variable_put(n),stat=istat)
585  if (istat /= 0) call raise_exception('Allocation failed.',"QSort",290001)
586  variable_put(:) = clock
587 
588  call random_seed(put = variable_put)
589  call random_number(random)
590  randi = int(random*real(na-1))+1
591  pivot = ratesortkey(a(randi)%group, a(randi)%parts) ! random pivot (not best performance, but avoids worst-case)
592  left = 0
593  right = na + 1
594 
595  do while (left < right)
596  right = right - 1
597  do while (lgt(ratesortkey(a(right)%group, a(right)%parts), pivot))
598  right = right - 1
599  end do
600  left = left + 1
601  do while (llt(ratesortkey(a(left)%group, a(left)%parts), pivot))
602  left = left + 1
603  end do
604  if (left < right) then
605  temp = a(left)
606  a(left) = a(right)
607  a(right) = temp
608  end if
609  end do
610 
611  if (left == right) then
612  marker = left + 1
613  else
614  marker = left
615  end if
616 
617  call qsort(a(:marker-1),marker-1)
618  call qsort(a(marker:),na-marker+1)
619 
620  end if
621 
622  end subroutine qsort
623 
624 
625 
626 
627  !> Close files and finalize this module
628  !!
629  !! This subroutine closes the debug file "debug_tabln.dat"
630  !!
631  !! @author: Moritz Reichert
632  !!
633  !! \b Edited:
634  !! - 07.06.17
635  !! .
636  subroutine mergesort_finalize()
639  implicit none
640 
641  ! Debugging
642  if (verbose_level .gt. 2) then
643  if (use_tabulated_rates) then
644  ! Close the debug file again
645  call close_io_file(debug_tabl,'debug_tabln.dat')
646  end if
647  end if
648 
649  end subroutine mergesort_finalize
650 
651  !> Sorts chapter one of the rate array
652  !!
653  !! The sorting is based on the second nucleus in the rate array.
654  !!
655  !! ### Example
656  !! <pre>
657  !! Rate 1: cl34 (Z=17) -> s34 (Z=16)
658  !! Rate 2: cl36 (Z=17) -> ar36 (Z=18)
659  !! Rate 3: cl36 (Z=17) -> s36 (Z=16)
660  !! Rate 4: cl38 (Z=17) -> ar38 (Z=18)
661  !! </pre>
662  !! will switch the order of the rates to:
663  !! <pre>
664  !! Rate 1: cl34 (Z=17) -> s34 (Z=16)
665  !! Rate 3: cl36 (Z=17) -> s36 (Z=16)
666  !! Rate 2: cl36 (Z=17) -> ar36 (Z=18)
667  !! Rate 4: cl38 (Z=17) -> ar38 (Z=18)
668  !! </pre>
669  !! In case the sunet is ordered by proton number.
670  !!
671  !! @todo Expand and change this subroutine
672  !!
673  !! @warning This subroutine assumes a certain ordering of the
674  !! sunet!
675  subroutine rrate_sort(num,rate_array)
677 
678  implicit none
679 
680  integer,intent(in) :: num !< Number of rates in chapter 1
681  type(reactionrate_type),dimension(num),intent(inout) :: rate_array !< Rate array that will get sorted
682  type(reactionrate_type),dimension(1) :: temp !< Temporary reaction rate
683  integer :: i
684 
685  info_entry("rrate_sort")
686  i=1
687 
688  do i=1,num-1
689  if (rate_array(i+1)%group.ne.1)exit
690  if ((rate_array(i)%parts(1).eq.rate_array(i+1)%parts(1)) .and. &
691  (rate_array(i)%parts(2).gt.rate_array(i+1)%parts(2))) then
692  if (verbose_level .ge. 2) then
693  print '(a10,4i6)','switch ' ,rate_array(i)%parts(1:2), rate_array(i+1)%parts(1:2)
694  end if
695  temp(1) = rate_array(i+1)
696  rate_array(i+1) = rate_array(i)
697  rate_array(i) = temp(1)
698  end if
699  end do
700 
701  info_exit("rrate_sort")
702 
703  return
704  end subroutine rrate_sort
705 
706 
707 
708  !> Bubblesort of array.
709  !!
710  !! This subroutine performs a bubblesort of an array. See the following
711  !! illustration (from wikipedia):
712  !! @image html https://upload.wikimedia.org/wikipedia/commons/c/c8/Bubble-sort-example-300px.gif "Illustration of a bubblesort" width=300
713  !! The subroutine is able to run in 2 modes,
714  !! - mode 0 : Ascending order
715  !! - mode 1 : Descending order
716  !! .
717  !! Furthermore, a second array can be given which will return the indices of
718  !! the changes within the first array.
719  !!
720  !! @see reorder, tw_rate_module::readweak_logft
721  !!
722  !! @author M. Reichert
723  subroutine bubblesort(mode,length,arr1,arr2)
725  implicit none
726  real(r_kind),dimension(:),intent(inout) :: arr1 !< Array to get sorted
727  integer,dimension(:),intent(out),optional :: arr2 !< Indices of the sort
728  integer,intent(in) :: length !< Length of the arrays
729  integer,intent(in) :: mode !<0 descending; 1 ascending
730  ! Internal helper variables
731  logical :: unsorted
732  integer :: i
733  real(r_kind) :: h
734 
735  !Create indices in array2
736  if (present(arr2)) then
737  do i=1, length
738  arr2(i) = i
739  end do
740  end if
741 
742  unsorted = .true.
743 
744  do while(unsorted)
745  unsorted = .false.
746 
747  do i = 1 , length-1
748  if (mode .eq. 1) then
749  ! descending order
750  if (arr1(i)>arr1(i+1)) then
751  h = arr1(i)
752  arr1(i) = arr1(i+1)
753  arr1(i+1) = h
754  ! Also sort arr2 if present
755  if (present(arr2)) then
756  h = arr2(i)
757  arr2(i) = arr2(i+1)
758  arr2(i+1) = int(h)
759  end if
760  unsorted=.true.
761  end if
762  elseif (mode .eq. 0) then
763  ! ascending order
764  if (arr1(i)<arr1(i+1)) then
765  h = arr1(i)
766  arr1(i) = arr1(i+1)
767  arr1(i+1) = h
768  ! Also sort arr2 if present
769  if (present(arr2)) then
770  h = arr2(i)
771  arr2(i) = arr2(i+1)
772  arr2(i+1) = int(h)
773  end if
774  unsorted=.true.
775  end if
776  else
777  call raise_exception("Unknown sort mode "//int_to_str(mode),&
778  "bubblesort",290003)
779  end if
780  end do
781  end do
782 
783  end subroutine bubblesort
784 
785 
786 
787  !> Quicksort of array.
788  !!
789  !! This subroutine performs a quicksort of an array.
790  !! A quicksort is a recursive sorting algorithm. An illustration of it is shown
791  !! in the following (Source en.wikipedia):
792  !! @image html https://upload.wikimedia.org/wikipedia/commons/6/6a/Sorting_quicksort_anim.gif "Illustration of the quicksort" width=300
793  !! In this gif, the red indicated number is the so called pivot-element.
794  !! In contrast to \ref QSort, this subroutine is able to sort an array that is not a derived type and comes in form of
795  !! an array of doubles.
796  !! The subroutine is able to run in 2 modes,
797  !! - mode 0 : Ascending order
798  !! - mode 1 : Descending order
799  !! .
800  !! Furthermore, a second array can be given which will return the indices of
801  !! the changes within the first array.
802  !!
803  !! @see [Rosettacode](http://rosettacode.org/wiki/Sorting_algorithms/Quicksort#Fortran),
804  !!
805  !! @see reorder
806  !!
807  !! @author M. Reichert
808  !! @date 08.05.24
809  recursive subroutine quicksort(mode, length, arr1, arr2, is_recursion)
811  implicit none
812  real(r_kind), dimension(:), intent(inout) :: arr1 !< Array to get sorted
813  integer, dimension(:), intent(out), optional :: arr2 !< Indices of the sort
814  integer, intent(in) :: length !< Length of the arrays
815  integer, intent(in) :: mode !< 0 descending; 1 ascending
816  logical, intent(in), optional :: is_recursion !< Flag to indicate if the subroutine is called recursively
817  ! Internal helper variables
818  real(r_kind) :: pivot_value
819  integer :: pivot_index, i, j
820  logical :: recursive_call
821  real(r_kind) :: h
822 
823  !Create indices in array2
824  if (present(is_recursion)) then
825  recursive_call = is_recursion
826  else
827  recursive_call = .false.
828  end if
829 
830  if (.not. recursive_call) then
831  if (present(arr2)) then
832  arr2 = [(i, i=1,length)]
833  end if
834  end if
835 
836  ! Check for base case
837  if (length <= 1) return
838 
839  ! Choose pivot element
840  pivot_index = length / 2
841  pivot_value = arr1(pivot_index)
842 
843  ! Partition step
844  i = 1
845  j = length
846 
847  do while (i <= j)
848  if (mode == 1) then
849  do while (arr1(i) < pivot_value)
850  i = i + 1
851  end do
852  do while (arr1(j) > pivot_value)
853  j = j - 1
854  end do
855  else
856  do while (arr1(i) > pivot_value)
857  i = i + 1
858  end do
859  do while (arr1(j) < pivot_value)
860  j = j - 1
861  end do
862  end if
863 
864  if (i <= j) then
865  ! Swap elements
866  h = arr1(i)
867  arr1(i) = arr1(j)
868  arr1(j) = h
869 
870  if (present(arr2)) then
871  h = arr2(i)
872  arr2(i) = arr2(j)
873  arr2(j) = h
874  end if
875 
876  i = i + 1
877  j = j - 1
878  end if
879  end do
880 
881  ! Recursive calls
882  if (present(arr2)) then
883  call quicksort(mode, j, arr1, arr2, .true.)
884  call quicksort(mode, length - i + 1, arr1(i:), arr2(i:),.true.)
885  else
886  call quicksort(mode, j, arr1, is_recursion=.true.)
887  call quicksort(mode, length - i + 1, arr1(i:), is_recursion=.true.)
888  end if
889 
890 end subroutine quicksort
891 
892 
893 
894 
895  !> Takes an array and an array with indices to reorder the first array
896  !!
897  !! @see bubblesort, tw_rate_module::readweak_logft
898  !!
899  !! @author M. Reichert
900  subroutine reorder(arr1,arr2,length)
902  implicit none
903  real(r_kind),dimension(:),intent(inout) :: arr1 !< Array to reorder
904  integer,dimension(:),intent(in) :: arr2 !< Array containing the indices
905  integer,intent(in) :: length !< Length of the arrays
906 
907  real(r_kind),dimension(length) :: helper !< Helper variable
908  integer :: i
909 
910  do i=1,length
911  ! Check for weird things in index array
912  if ((arr2(i) .lt. 1) .or. (arr2(i) .gt. length)) then
913  call raise_exception("Inconsistent index array! Got index "//int_to_str(arr2(i)),&
914  "reorder",290004)
915  end if
916 
917  helper(i) = arr1(arr2(i))
918  end do
919 
920  arr1(:) = helper(:)
921  end subroutine reorder
922 
923 
924  !> Takes an array and an array with indices to reorder the first array
925  !!
926  !! Same as \ref reorder, but for integer arrays.
927  !!
928  !! @see bubblesort, tw_rate_module::readweak_logft
929  !!
930  !! @author M. Reichert
931  subroutine reorder_int(arr1,arr2,length)
933  implicit none
934  integer,dimension(:),intent(inout) :: arr1 !< Array to reorder
935  integer,dimension(:),intent(in) :: arr2 !< Array containing the indices
936  integer,intent(in) :: length !< Length of the arrays
937 
938  integer,dimension(length) :: helper !< Helper variable
939  integer :: i
940 
941  do i=1,length
942  ! Check for weird things in index array
943  if ((arr2(i) .lt. 1) .or. (arr2(i) .gt. length)) then
944  call raise_exception("Inconsistent index array! Got index "//int_to_str(arr2(i)),&
945  "reorder",290004)
946  end if
947 
948  helper(i) = arr1(arr2(i))
949  end do
950 
951  arr1(:) = helper(:)
952  end subroutine reorder_int
953 
954 
955 end module mergesort_module
956 
957 
958 
959 
960 
961 !>
962 !! Returns a key for sorting a rate array by concatenating isotope indices.
963 !!
964 !! Rule: order of elements depends on chapter. \n
965 !! The here produced string is compared for
966 !! being lexically greater or smaller in \ref qsort.
967 !!
968 !! @returns String with that determines the ordering of an isotope
969 !!
970 !! @see qsort
971 !!
972 !! \b Edited:
973 !! - 15.04.15
974 !! - 28.07.22, MR: Introduced new chapters
975 !! .
976 character(31) function ratesortkey(group,parts)
977  !
978  implicit none
979  integer :: group
980  integer,dimension(6) :: parts
981 
982  select case (group)
983  case (1:3,11)
984  write (ratesortkey, "(I1,6I5)") group, parts
985  case (4:7)
986  write (ratesortkey, "(I1,6I5)") group, parts(2), parts(1), parts(3:)
987  case (8:9)
988  write (ratesortkey, "(I1,6I5)") group, parts(3), parts(2), parts(1), parts(4:)
989  case (10)
990  write (ratesortkey, "(I1,6I5)") group, parts(4), parts(3), parts(2), parts(1), parts(5:)
991  end select
992 
993 end function ratesortkey
ratesortkey
character(31) function ratesortkey(group, parts)
Returns a key for sorting a rate array by concatenating isotope indices.
Definition: mergesort_module.f90:977
global_class::net_names
character *5, dimension(:), allocatable, public net_names
list of isotopes contained in the network
Definition: global_class.f90:95
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
global_class::common_weak_rates
integer common_weak_rates
Counter for rates that are included in Reaclib and theoretical weak rates.
Definition: global_class.f90:101
mergesort_module::mergesort_init
subroutine, public mergesort_init()
Initialize the mergesort module and open files for debugging.
Definition: mergesort_module.f90:48
error_msg_class
Error handling routines.
Definition: error_msg_class.f90:16
qsort
subroutine qsort(limit, last, maxerr, ermax, elist, iord, nrmax)
Definition: quadpack_module.f90:8072
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
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
mergesort_module::rrate_ms
subroutine, public rrate_ms(x, xs, y, ys, r, ptz, rate_out)
Merges two tables of rates (of type global_class::reactionrate_type).
Definition: mergesort_module.f90:227
global_class::rrate_weak_exp
type(reactionrate_type), dimension(:), allocatable, public rrate_weak_exp
array saving the exp. weak rates from reaclib that are replaced by theo weak rates
Definition: global_class.f90:66
global_class::nurate_type
data fields for neutrino rates given in Langanke&Kolbe 2001
Definition: global_class.f90:70
mergesort_module::reorder_int
subroutine, public reorder_int(arr1, arr2, length)
Takes an array and an array with indices to reorder the first array.
Definition: mergesort_module.f90:932
mergesort_module::mergesort_finalize
subroutine, public mergesort_finalize()
Close files and finalize this module.
Definition: mergesort_module.f90:637
mergesort_module::reorder
subroutine, public reorder(arr1, arr2, length)
Takes an array and an array with indices to reorder the first array.
Definition: mergesort_module.f90:901
parameter_class::use_tabulated_rates
logical use_tabulated_rates
switch for using tabulated rates (e.g. talysNGrates.dat)
Definition: parameter_class.f90:92
global_class::nurate
type(nurate_type), dimension(:), allocatable, public nurate
neutrino rates
Definition: global_class.f90:81
global_class::only_theo_weak_rates
integer only_theo_weak_rates
Counter for rates that are not included in Reaclib, but in theoretical weak rates.
Definition: global_class.f90:102
mergesort_module::rrate_sort
subroutine, public rrate_sort(num, rate_array)
Sorts chapter one of the rate array.
Definition: mergesort_module.f90:676
rrs_twr
#define rrs_twr
Definition: macros.h:52
file_handling_class
Provide some basic file-handling routines.
Definition: file_handling_class.f90:18
mergesort_module::debug_tabl
integer, private debug_tabl
File ID for debugging tabulated rate class.
Definition: mergesort_module.f90:20
r_kind
#define r_kind
Definition: macros.h:46
file_handling_class::open_outfile
integer function, public open_outfile(file_name)
Shorthand for opening a new file for writing (output file)
Definition: file_handling_class.f90:108
mergesort_module::rrate_qs_replace
subroutine, public rrate_qs_replace(x, xs, y, ys, r, out_array, ptz)
Wrapper around the quicksort subroutine.
Definition: mergesort_module.f90:425
global_class
Contains types and objects shared between multiple modules.
Definition: global_class.f90:19
mergesort_module::quicksort
recursive subroutine, public quicksort(mode, length, arr1, arr2, is_recursion)
Quicksort of array.
Definition: mergesort_module.f90:810
file_handling_class::close_io_file
subroutine, public close_io_file(unit_no, file_name)
Close an external file.
Definition: file_handling_class.f90:144
mergesort_module::bubblesort
subroutine, public bubblesort(mode, length, arr1, arr2)
Bubblesort of array.
Definition: mergesort_module.f90:724
mergesort_module
Module mergesort_module for merging arrays of rates.
Definition: mergesort_module.f90:16
rrs_tabl
#define rrs_tabl
Definition: macros.h:50
parameter_class
Contains all runtime parameters as well as phys and math constants.
Definition: parameter_class.f90:24
mergesort_module::nurate_ms
subroutine, public nurate_ms(x, xs, y, ys, r)
Merges two tables of neutrino rates (of type global_class::nurate_type).
Definition: mergesort_module.f90:88