Last commit for src/random.f90: 5874abaa643d4472a2aa9d1c5dbe454dadbd8d1f

Initial commit of the AENET code.

Bruno Mundim [2017-01-02 17:48:39]
Initial commit of the AENET code.
!-----------------------------------------------------------------------
!       random.f90 - everything related to pseudo random numbers
!-----------------------------------------------------------------------
!+ This file is part of the AENET package.
!+
!+ Copyright (C) 2012-2016 Nongnuch Artrith and Alexander Urban
!+
!+ This program is free software: you can redistribute it and/or modify
!+ it under the terms of the GNU General Public License as published by
!+ the Free Software Foundation, either version 3 of the License, or
!+ (at your option) any later version.
!+
!+ This program is distributed in the hope that it will be useful, but
!+ WITHOUT ANY WARRANTY; without even the implied warranty of
!+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
!+ General Public License for more details.
!+
!+ You should have received a copy of the GNU General Public License
!+ along with this program.  If not, see <http://www.gnu.org/licenses/>.
!-----------------------------------------------------------------------
! This module is a simple interface to the default Fortran pseudo-RNG.
! There is no guarantee that the (compiler provided) RNG is 'good', so
! do not use this module for anything critical (such as MC simulations)
! unless you are certain that your compiler provides a reliable RNG.
!-----------------------------------------------------------------------
! 2013-07-03 Alexander Urban (AU), Nongnuch Artrith (NA)
!-----------------------------------------------------------------------

module random

  implicit none
  private
  save

  public :: random_init,       &
            random_reinit,     &
            random_final,      &
            random_integer,    &
            random_gauss,      &
            random_save_state, &
            random_load_state


  double precision,        parameter, private :: PI = 3.141592653589793d0
  integer,                 parameter, private :: DEFAULT_UNIT = 67

  !--------------------------------------------------------------------!

  integer, dimension(:), allocatable, private :: iSeed

  double precision,                   private :: gauss_sigma = 1.0d0
  double precision,                   private :: gauss_x0    = 0.0d0
  integer,                            private :: gauss_N     = 20

  logical,                            private :: isInit = .false.

contains

  subroutine random_init()

    implicit none

    integer :: i, n
    integer :: clock

    if (isInit) return

    i = 0
    call random_seed(size=n)
    allocate(iSeed(n))
    call system_clock(count=clock)
    iSeed = clock + 37 * (/ (i - 1, i = 1, n) /)
    call random_seed(put=iSeed)

    isInit = .true.

  end subroutine random_init

  !--------------------------------------------------------------------!

  subroutine random_reinit()

    implicit none

    call random_final()
    call random_init()

  end subroutine random_reinit

  !--------------------------------------------------------------------!

  subroutine random_final()

    implicit none

    if (.not. isInit) return

    deallocate(iSeed)
    isInit = .false.

  end subroutine random_final

  !--------------------------------------------------------------------!
  !                     save/load state of the RNG                     !
  !--------------------------------------------------------------------!

  subroutine random_save_state(file, unit)

    implicit none

    character(len=*), optional, intent(in) :: file
    integer,          optional, intent(in) :: unit

    integer                            :: u
    integer                            :: n
    integer, dimension(:), allocatable :: curr_seed

    if (.not. (present(file) .or. present(unit))) then
       write(0,*) "Warning: neither file, nor unit given in 'save_state()'."
       return
    end if

    if (present(unit)) then
       u = unit
    else
       u = DEFAULT_UNIT
    end if

    if (present(file)) then
       open(u, file=trim(file), status='replace', action='write', &
               form='unformatted')
    end if

    call random_seed(size=n)
    allocate(curr_seed(n))
    call random_seed(get=curr_seed)
    write(u) n
    write(u) curr_seed
    deallocate(curr_seed)

    if (present(file)) close(u)

  end subroutine random_save_state

  !--------------------------------------------------------------------!

  subroutine random_load_state(file, unit)

    implicit none

    character(len=*), optional, intent(in) :: file
    integer,          optional, intent(in) :: unit

    integer                            :: u
    integer                            :: n1, n2
    integer, dimension(:), allocatable :: curr_seed

    if (.not. (present(file) .or. present(unit))) then
       write(0,*) "Warning: neither file, nor unit given in 'load_state()'."
       return
    end if

    if (present(unit)) then
       u = unit
    else
       u = DEFAULT_UNIT
    end if

    if (present(file)) then
       open(u, file=trim(file), status='old', action='read', &
               form='unformatted')
    end if

    read(u) n1
    allocate(curr_seed(n1))
    read(u) curr_seed
    call random_seed(size=n2)
    if (n1 /= n2) then
       write(0,*) "Warning: unable to restart RNG state (incompatible seed)."
    else
       call random_seed(put=curr_seed)
    end if
    deallocate(curr_seed)

    if (present(file)) close(u)

  end subroutine random_load_state

  !--------------------------------------------------------------------!
  !            random integer irand with 1 <= irand <= imax            !
  !--------------------------------------------------------------------!

  function random_integer(imax) result(irand)

    implicit none

    integer, intent(in) :: imax
    integer             :: irand

    double precision :: r

    call random_number(r)
    irand = ceiling(r*dble(imax))
    ! in case (r == 0)
    if (irand == 0) irand = imax

  end function random_integer

  !--------------------------------------------------------------------!
  !                        normal distribution                         !
  !    (simple implementation based on the central limit theoreme)     !
  !--------------------------------------------------------------------!

  function random_gauss(sigma, x0, N) result(r)

    implicit none

    double precision, optional, intent(in) :: sigma
    double precision, optional, intent(in) :: x0
    integer,          optional, intent(in) :: N
    double precision                       :: r

    double precision :: x
    integer          :: i

    if (present(sigma)) gauss_sigma = sigma
    if (present(x0))    gauss_x0    = x0
    if (present(N))     gauss_N     = N

    r = 0.0d0
    do i = 1, gauss_N
       call random_number(x)
       r = r + x
    end do

    r = r - 0.5d0*dble(gauss_N)
    r = r*sqrt(12.0d0/dble(gauss_N))

    ! apply requested mean and variance
    r = gauss_x0 + gauss_sigma*r

  end function random_gauss



end module random
ViewGit