rndgenPL.f90 Source File


This file depends on

sourcefile~~rndgenpl.f90~~EfferentGraph sourcefile~rndgenpl.f90 rndgenPL.f90 sourcefile~rndgen.f90 rndgen.f90 sourcefile~rndgenpl.f90->sourcefile~rndgen.f90

Source Code

module rndgenPL_mod
   use rndgen_mod
   implicit none
   private

   integer, parameter :: dp = selected_real_kind(15) ! 8-byte reals
   integer, parameter :: i8 = selected_int_kind(8) ! 4-byte integers
   integer, parameter :: i16 = selected_int_kind(16) ! 8-byte integers
   real(kind=dp), parameter :: am = 4.656612873077392578d-10 ! multiplier 1/2^31

   !> Random number generator object for power-law distribution, adapted from Silvio C. Ferreira code.
   !> The power-law distribution is given by P(k) = k^(-gamma), where k is an integer between kmin and kmax.
   type, extends(rndgen) :: rndgenPL
      ! auxiliar variables
      real(kind=dp), private :: AA, expo, x0, xc

      ! parameters
      real(kind=dp) :: gamma
      integer(kind=i16) :: kmin, kmax

      ! auxiliar distribution
      real(kind=dp), private, allocatable :: prob(:)
   contains
      procedure :: rndPL => rndPL_rndgenPL ! generates a random number following the power-law distribution
      procedure :: initPL => initPL_rndgenPL ! initializes the power-law random number generator
   end type

   public :: rndgenPL

contains

   !> Initializes the power-law random number generator
   subroutine initPL_rndgenPL(this, kmin, kmax, gama, iseed)
      class(rndgenPL) :: this
      integer(kind=i16), intent(in) :: kmin, kmax
      real(kind=dp), intent(in) :: gama
      integer, intent(in), optional :: iseed

      if (present(iseed)) call this%init(iseed)

      this%kmin = kmin
      this%kmax = kmax
      this%gamma = gama

      if (allocated(this%prob)) deallocate (this%prob)
      allocate (this%prob(kmin:kmax))

      this%AA = 0d0
      block
         integer(kind=kind(kmax)) :: j

         do j = kmin, kmax
            this%AA = this%AA + (1.0_dp*j)**(-gama)
            this%prob(j) = (1.0_dp*j)**(-gama)
         end do

         this%AA = 1.0_dp/this%AA
         this%prob = this%AA*this%prob

      end block

      this%x0 = (1.0_dp*(kmin - 1))**(-gama + 1.0_dp)
      this%xc = (1.0_dp*kmax)**(-gama + 1.0_dp)
      this%expo = 1.0_dp/(1.0_dp - gama)

   end subroutine

   !> Generates a random number following the power-law distribution
   function rndPL_rndgenPL(this) result(rnd_number)
      class(rndgenPL) :: this
      real(kind=dp) :: z, x
      integer(kind=i16) :: j, rnd_number

      do
         z = this%rnd()
         x = (this%x0 - z*(this%x0 - this%xc))**this%expo
         j = ceiling(x)

         z = this%rnd()

         if (.not. z*this%AA/(x**this%gamma) >= this%prob(j)) exit

      end do

      rnd_number = j

   end function
end module