Report Typos and Errors    
Semi-Lagrangian Library
Modular library for kinetic and gyrokinetic simulations of plasmas in fusion energy devices.
sll_m_utilities.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 
21 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
22 #include "sll_errors.h"
23 #include "sll_working_precision.h"
24 
25  implicit none
26 
27  public :: &
33  sll_f_is_even, &
37  sll_o_display, &
42 
43  private
44 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
45 ! intrinsic :: selected_int_kind ! this line gives an error, why?
46 
47  ! Tentative implementation of a standard-compliant way to get the
48  ! memory footprint of a variable. This is our yardstick...
49  !
50  ! selected_int_kind(r) returns the default integer scalar that is the kind
51  ! type parameter value for an integer data type able to represent all
52  ! integer values n in the range -10^(-r) < n < 10^r, where r is a scalar
53  ! integer. If more than one is available, a kind with least decimal exponent
54  ! range is chosen (and least kind value if several have least decimal
55  ! exponent range). If no corresponding kind is availalble, the result is -1.
56  ! (Metcalf & Reid. F90/95 2nd ed. p. 176).
57  !
58  ! We are, maybe dangerously, relying on the common practice of many compilers
59  ! of using the kind values to indicate the number of bytes of storage
60  ! occupied by a value. But this is not mandated by the standard. For
61  ! instance a compiler that only has available 4-byte integers may still
62  ! support kind values of 1, 2 and 4 to 'ease portability' from other
63  ! platforms. The size of k1 will become our basic 'yardstick' to measure
64  ! the size of a memory footprint of a variable. When we ask for the size
65  ! of 'var', the answer will be given in terms of how many 'yardsticks'
66  ! are needed to represent 'var'. The implications of this assumption
67  ! need to be checked further.
68 
70  integer, parameter :: sll_p_byte_size = selected_int_kind(0)
71 
73  interface sll_o_display
74  module procedure sll_s_display_matrix_2d_integer
75  module procedure display_matrix_2d_real
76  module procedure display_vector_integer
77  module procedure display_vector_real
78  end interface sll_o_display
79 
81  logical :: flag = .true.
82 
84  interface sll_o_factorial
85  module procedure factorial_int32, factorial_int64
86  end interface sll_o_factorial
87 
88 contains
89 
92  sll_int64, intent(in) :: n
93  logical :: sll_f_is_power_of_two
94 
95  intrinsic :: not, iand
96 
97  if ((n > 0) .and. (0 .eq. (iand(n, (n - 1))))) then
98  sll_f_is_power_of_two = .true.
99  else
100  sll_f_is_power_of_two = .false.
101  end if
102  end function sll_f_is_power_of_two
103 
105  function sll_f_is_even(n)
106  sll_int32, intent(in) :: n
107  logical :: sll_f_is_even
108 
109  intrinsic :: modulo
110 
111  if (modulo(n, 2) .eq. 0) then
112  sll_f_is_even = .true.
113  else
114  sll_f_is_even = .false.
115  end if
116  end function sll_f_is_even
117 
121  function factorial_int32(n) result(fac)
122  sll_int32, intent(in) :: n
123  sll_int64 :: fac
124 
125  sll_int64 :: acc
126  sll_int64 :: i
127 
128  if (n < 0) then
129  print *, 'ERROR, factorial_int32(): n < 0 or n > 20, if latter, ', &
130  'function will overflow a 64-bit integer. n = ', n
131  end if
132 
133  acc = 1
134  if (n >= 1) then
135  do i = int(n, kind=i64), 1, -1
136  acc = acc*i
137  end do
138  end if
139  ! case n == 0 is already taken care of. No protection for negative input.
140  fac = acc
141  end function factorial_int32
142 
146  function factorial_int64(n) result(fac)
147  sll_int64, intent(in) :: n
148  sll_int64 :: fac
149 
150  sll_int64 :: acc
151  sll_int64 :: i
152 
153  if ((n < 0) .or. (n > 20)) then
154  print *, 'ERROR, factorial_int64(): either a negative n was passed: ', &
155  'or n > 20, which will overflow a 64-bit integer. n = ', n
156  end if
157 
158  acc = 1
159  if (n >= 1) then
160  do i = n, 1, -1
161  acc = acc*i
162  end do
163  end if
164  ! case n == 0 is already taken care of.
165  fac = acc
166  end function factorial_int64
167 
169  subroutine sll_s_int2string(istep, cstep)
170  integer, intent(in) :: istep
171  character(len=*), intent(out) :: cstep
172 
173  integer :: l
174  character(len=8) :: str_fmt
175 
176  l = len(cstep)
177 
178  if (istep >= 0 .and. istep < 10**l) then
179  str_fmt = "(I0"//char(l + 48)//"."//char(l + 48)//")"
180  write (cstep, str_fmt) istep
181  else
182  sll_warning('sll_s_int2string', 'index is negative or too big')
183  print *, 'index =', istep, ' cstep length = ', l
184  cstep = 'xxxx'
185  end if
186 
187  end subroutine sll_s_int2string
188 
190  subroutine sll_s_new_file_id(file_id, error)
191  sll_int32, intent(out) :: file_id
192  sll_int32, intent(out) :: error
193 
194  logical :: lopen
195 
196  error = 1
197 
198  do 100 file_id = 20, 99
199 
200  inquire (unit=file_id, opened=lopen)
201  if (lopen) then
202  cycle
203  else
204  open (file_id, status='SCRATCH', err=100)
205  close (file_id, status='DELETE', err=100)
206  error = 0
207  exit
208  end if
209 
210 100 continue
211 
212  !SLL_ASSERT(error == 0)
213 
214  end subroutine sll_s_new_file_id
215 
217  subroutine display_vector_real(array, real_format)
218  sll_real64, dimension(:), intent(in) :: array
219  character(len=*), intent(in) :: real_format
220 
221  character(len=20) :: display_format
222  sll_int32 :: n, i
223 
224  n = size(array, 1)
225 
226  write (display_format, "('(''|''',i4,a,''' |'')')") n, real_format
227 
228  write (*, *)
229  write (*, display_format) (array(i), i=1, n)
230  write (*, *)
231 
232  end subroutine display_vector_real
233 
235  subroutine display_vector_integer(array, integer_format)
236  sll_int32, dimension(:), intent(in) :: array
237  character(len=*), intent(in) :: integer_format
238 
239  character(len=20) :: display_format
240  sll_int32 :: n, i
241 
242  n = size(array)
243 
244  write (display_format, "('(''|''',i4,a,''' |'')')") n, integer_format
245 
246  write (*, *)
247  write (*, display_format) (array(i), i=1, n)
248  write (*, *)
249 
250  end subroutine display_vector_integer
251 
253  subroutine display_matrix_2d_real(array, real_format)
254  sll_real64, dimension(:, :), intent(in) :: array
255  character(len=*), intent(in) :: real_format
256 
257  character(len=20) :: display_format
258  sll_int32 :: n1, n2, i, j
259 
260  n1 = size(array, 1)
261  n2 = size(array, 2)
262 
263  write (display_format, "('(''|''',i4,a,''' |'')')") n2, real_format
264 
265  write (*, *)
266  do i = 1, n1
267  write (*, display_format) (array(i, j), j=1, n2)
268  end do
269  write (*, *)
270 
271  end subroutine display_matrix_2d_real
272 
274  subroutine sll_s_display_matrix_2d_integer(array, integer_format)
275  sll_int32, dimension(:, :), intent(in) :: array
276  character(len=*), intent(in) :: integer_format
277 
278  character(len=20) :: display_format
279  sll_int32 :: n1, n2, i, j
280 
281  n1 = size(array, 1)
282  n2 = size(array, 2)
283 
284  write (display_format, "('(''|''',i4,a,''' |'')')") n2, integer_format
285 
286  write (*, *)
287  do i = 1, n1
288  write (*, display_format) (array(i, j), j=1, n2)
289  end do
290  write (*, *)
291 
292  end subroutine sll_s_display_matrix_2d_integer
293 
296  subroutine initialize_file(data_file_id, thf_file_id)
297  sll_int32, intent(out) :: data_file_id
298  sll_int32, intent(out) :: thf_file_id
299 
300  character(len=*), parameter :: this_sub_name = "initialize_file"
301  character(len=72) :: filename
302  integer :: IO_stat
303  sll_int32 :: error
304 
305  call get_command_argument(1, filename)
306 
307  call sll_s_new_file_id(data_file_id, error)
308  open (data_file_id, file=trim(filename), iostat=io_stat)
309  if (io_stat /= 0) sll_error(this_sub_name, "Miss argument file.nml")
310 
311  call sll_s_new_file_id(thf_file_id, error)
312  open (thf_file_id, file="thf.dat", iostat=io_stat, position='append')
313  if (io_stat /= 0) sll_error(this_sub_name, "Cannot open file thf.dat")
314 
315  rewind(thf_file_id)
316  close (thf_file_id)
317 
318  end subroutine initialize_file
319 
321  subroutine time_history(file_id, desc, fformat, array)
322  sll_int32, intent(in) :: file_id
323  character(3), intent(in) :: desc
324  character(14), intent(in) :: fformat
325  sll_real64, dimension(:), intent(in) :: array
326 
327  if (desc(1:3) == "thf") then
328  open (file_id, file="thf.dat", position='append')
329  if (flag) then
330  rewind(file_id)
331  flag = .false.
332  end if
333  write (file_id, fformat) array
334  close (file_id)
335  else
336  write (*, *) desc, " not recognized"
337  end if
338 
339  end subroutine time_history
340 
341 !------------------------------------------------------------------------
349 !------------------------------------------------------------------------
350  subroutine sll_s_mpe_decomp1d(n, numprocs, myid, s, e)
351  sll_int32, intent(in) :: n
352  sll_int32, intent(in) :: numprocs
353  sll_int32, intent(in) :: myid
354  sll_int32, intent(out) :: s
355  sll_int32, intent(out) :: e
356 
357  sll_int32 :: nlocal
358  sll_int32 :: deficit
359 
360  nlocal = n/numprocs
361  s = myid*nlocal + 1
362  deficit = mod(n, numprocs)
363  s = s + min(myid, deficit)
364  if (myid < deficit) then
365  nlocal = nlocal + 1
366  end if
367  e = s + nlocal - 1
368  if (e > n .or. myid == numprocs - 1) e = n
369 
370  end subroutine sll_s_mpe_decomp1d
371 
379  subroutine sll_s_pfenvelope(S, &
380  t, &
381  tflat, &
382  tL, &
383  tR, &
384  twL, &
385  twR, &
386  t0, &
387  turn_drive_off)
388 
389  sll_real64, intent(out) :: s
390  sll_real64, intent(in) :: t
391  sll_real64, intent(in) :: tflat
392  sll_real64, intent(in) :: tl
393  sll_real64, intent(in) :: tr
394  sll_real64, intent(in) :: twl
395  sll_real64, intent(in) :: twr
396  sll_real64, intent(in) :: t0
397  logical, intent(in) :: turn_drive_off
398 
399  sll_real64 :: epsilon
400 
401  ! The envelope function is defined such that it is zero at t0,
402  ! rises to 1 smoothly, stay constant for tflat, and returns
403  ! smoothly to zero.
404  if (turn_drive_off) then
405  epsilon = 0.5_f64*(tanh((t0 - tl)/twl) - tanh((t0 - tr)/twr))
406  s = 0.5_f64*(tanh((t - tl)/twl) - tanh((t - tr)/twr)) - epsilon
407  s = s/(1 - epsilon)
408  else
409  epsilon = 0.5_f64*(tanh((t0 - tl)/twl) + 1.0_f64)
410  s = 0.5_f64*(tanh((t - tl)/twl) + 1.0_f64) - epsilon
411  s = s/(1.0_f64 - epsilon)
412  end if
413  if (s < 0) then
414  s = 0.0_f64
415  end if
416  s = s + 0.0_f64*tflat ! for use of unused
417  return
418 
419  end subroutine sll_s_pfenvelope
420 
435  subroutine sll_s_compute_bloc(bloc_coord, bloc_index, N)
436 
437  sll_real64, intent(inout) :: bloc_coord(2)
438  sll_int32, intent(inout) :: bloc_index(3)
439  sll_int32, intent(in) :: n
440 
441  sll_real64 :: a, b
442  sll_int32 :: i1, i2, n_coarse, n_local, n_fine
443 
444  a = bloc_coord(1)
445  b = bloc_coord(2)
446 
447  !case of uniform mesh with refined zone
448  !we have a coarse mesh with N_coarse
449  !N=i1+N_local*(i2-i1)+N_coarse-i2
450  !N_fine=N_local*(i2-i1)
451  !x(i1)=i1/N_coarse x(i1+N_fine)=i2/N_coarse
452 
453  if ((bloc_index(1) == 1) .and. (bloc_index(3) == 1)) then
454 
455  n_local = bloc_index(2)
456  n_coarse = floor(real(n, f64)/(1._f64 + (b - a)*(real(n_local, f64) - 1._f64)))
457  if (n_local /= 1) then
458  i2 = (n - n_coarse)/(n_local - 1)
459  else
460  i2 = floor((b - a)*real(n_coarse, f64))
461  end if
462  n_coarse = n - i2*(n_local - 1)
463  i1 = floor(a*real(n_coarse, f64))
464  i2 = i2 + i1
465  bloc_index(1) = i1
466  n_fine = n_local*(i2 - i1)
467  bloc_index(2) = n_fine
468  bloc_index(3) = n - i1 - n_fine
469  bloc_coord(1) = real(i1, f64)/real(n_coarse, f64)
470  bloc_coord(2) = real(i2, f64)/real(n_coarse, f64)
471 
472  print *, '#uniform fine mesh would be:', n_coarse*n_local
473  print *, '#N_coarse=', n_coarse
474  print *, '#saving:', real(n, f64)/real(n_coarse*n_local, f64)
475  print *, '#new x(i1),x(i1+N_fine)=', bloc_coord(1), bloc_coord(2)
476  print *, '#error for x(i1),x(i1+N_fine)=', bloc_coord(1) - a, bloc_coord(2) - b
477  print *, '#i1,i1+N_fine,N_fine,N=', i1, i1 + n_fine, n_fine, n
478 
479  else
480 
481  print *, 'case in sll_s_compute_bloc not implemented yet'
482 
483  end if
484 
485  end subroutine sll_s_compute_bloc
486 
496  subroutine sll_s_compute_mesh_from_bloc(bloc_coord, bloc_index, node_positions)
497 
498  sll_real64, intent(in) :: bloc_coord(2)
499  sll_int32, intent(in) :: bloc_index(3)
500  sll_real64, dimension(:), intent(out) :: node_positions
501 
502  sll_int32 :: i, i1, i2, n
503  sll_real64 :: dx
504 
505  n = bloc_index(1) + bloc_index(2) + bloc_index(3)
506  i1 = bloc_index(1)
507  i2 = i1 + bloc_index(2)
508  node_positions(1:n + 1) = -1._f64
509  node_positions(1) = 0._f64
510  node_positions(i1 + 1) = bloc_coord(1)
511  node_positions(i2 + 1) = bloc_coord(2)
512  node_positions(n + 1) = 1._f64
513 
514  !piecewise linear mapping (maybe enhanced like in complete mesh)
515  if (bloc_index(1) .ne. 0) then
516  dx = bloc_coord(1)/real(bloc_index(1), f64)
517  do i = 2, bloc_index(1)
518  node_positions(i) = (real(i, f64) - 1._f64)*dx
519  end do
520  end if
521  if (bloc_index(2) .ne. 0) then
522  dx = (bloc_coord(2) - bloc_coord(1))/real(bloc_index(2), f64)
523  do i = 2, bloc_index(2)
524  node_positions(i + i1) = bloc_coord(1) + (real(i, f64) - 1._f64)*dx
525  end do
526  end if
527  if (bloc_index(3) .ne. 0) then
528  dx = (1._f64 - bloc_coord(2))/real(bloc_index(3), f64)
529  do i = 2, bloc_index(3)
530  node_positions(i + i2) = bloc_coord(2) + (real(i, f64) - 1._f64)*dx
531  end do
532  end if
533  end subroutine sll_s_compute_mesh_from_bloc
534 
537  logical function sll_f_query_environment(env_variable, default_value)
538 
539  character(len=*), intent(in) :: env_variable
540  logical, intent(in) :: default_value
541 
542  character(len=255) :: env_str
543 
544  sll_f_query_environment = default_value
545 
546  call get_environment_variable(env_variable, value=env_str)
547 
548  if (len_trim(env_str) > 0) then
549  select case (trim(env_str))
550  case ("1", "ON", "TRUE", "on", "true")
551  sll_f_query_environment = .true.
552  case ("0", "OFF", "FALSE", "off", "false")
553  sll_f_query_environment = .false.
554  end select
555  end if
556 
557  end function sll_f_query_environment
558 
559  !-----------------------------------------------------------------------------
567  !-----------------------------------------------------------------------------
568  pure subroutine sll_s_new_array_linspace(array, vmin, vmax, endpoint, step)
569 
570  integer, parameter :: wp = f64
571 
572  real(wp), intent(out) :: array(:)
573  real(wp), intent(in) :: vmin
574  real(wp), intent(in) :: vmax
575  logical, intent(in), optional :: endpoint
576  real(wp), intent(out), optional :: step
577 
578  integer :: i
579  integer :: np
580  integer :: nc
581  real(wp) :: a
582  real(wp) :: b
583 
584  ! Read number of points from given array
585  np = size(array)
586 
587  ! Calculate number of intervals in domain (cells) based on 'endpoint' flag
588  ! By default, we assume that endpoint = .true.
589  if (present(endpoint)) then
590  nc = merge(np - 1, np, endpoint)
591  else
592  nc = np - 1
593  end if
594 
595  ! Set first value to vmin in all cases
596  array(1) = vmin
597 
598  ! Calculate internal array values using linear blending of vmin and vmax,
599  ! in order to minimize round-off
600  a = vmin/real(nc, wp)
601  b = vmax/real(nc, wp)
602  do i = 2, nc
603  array(i) = a*real(nc + 1 - i, f64) + b*real(i - 1, f64)
604  end do
605 
606  ! If endpoint=.true., set last value to vmax
607  if (np == nc + 1) array(np) = vmax
608 
609  ! If required, return step size
610  if (present(step)) then
611  step = b - a
612  end if
613 
614  end subroutine sll_s_new_array_linspace
615  !-----------------------------------------------------------------------------
616 
617  end module sll_m_utilities
Functions to display on screen matrix or vector.
Some common numerical utilities.
subroutine display_vector_real(array, real_format)
Display a vector to screen.
integer(kind=i64) function factorial_int32(n)
It would have been nice to declare the next functions as 'pure' functions, but it is safer to be able...
subroutine display_vector_integer(array, integer_format)
Display a vector to screen.
subroutine, public sll_s_mpe_decomp1d(n, numprocs, myid, s, e)
From the MPE library.
subroutine, public sll_s_int2string(istep, cstep)
Convert an integer < 9999 to a 4 characters string.
subroutine initialize_file(data_file_id, thf_file_id)
Subroutine to open data file for slv2d and create the thf.dat file to write results.
pure subroutine, public sll_s_new_array_linspace(array, vmin, vmax, endpoint, step)
Equivalent to numpy.linspace @contact Yaman Güçlü, IPP Garching.
logical function, public sll_f_is_even(n)
Check if an integer is even.
subroutine time_history(file_id, desc, fformat, array)
Routine from slv2d to write diagnostics.
subroutine, public sll_s_compute_mesh_from_bloc(bloc_coord, bloc_index, node_positions)
logical function, public sll_f_is_power_of_two(n)
Check if an integer is equal to.
subroutine, public sll_s_display_matrix_2d_integer(array, integer_format)
Display matrix to screen.
subroutine, public sll_s_compute_bloc(bloc_coord, bloc_index, N)
integer(kind=i64) function factorial_int64(n)
It would have been nice to declare the next functions as 'pure' functions, but it is safer to be able...
subroutine display_matrix_2d_real(array, real_format)
Display matrix to screen.
subroutine, public sll_s_pfenvelope(S, t, tflat, tL, tR, twL, twR, t0, turn_drive_off)
S: the wave form at a given point in time. This wave form is not scaled (its maximum value is 1)....
integer, parameter, public sll_p_byte_size
kind of integers
subroutine, public sll_s_new_file_id(file_id, error)
Get a file unit number free before creating a file.
logical function, public sll_f_query_environment(env_variable, default_value)
Query an environment variable for the values on,off,1,0,true,false and return the result as a logical...
    Report Typos and Errors