randomwalk.f90 Source File


This file depends on

sourcefile~~randomwalk.f90~~EfferentGraph sourcefile~randomwalk.f90 randomwalk.f90 sourcefile~utilities.f90 utilities.f90 sourcefile~randomwalk.f90->sourcefile~utilities.f90 sourcefile~percolation.f90 percolation.f90 sourcefile~randomwalk.f90->sourcefile~percolation.f90 sourcefile~percolation.f90->sourcefile~utilities.f90 sourcefile~hk.f90 hk.f90 sourcefile~percolation.f90->sourcefile~hk.f90

Contents

Source Code


Source Code

module randomwalk
    use utilities
    use percolation
    implicit none
    private :: find_random_point
    contains

        function one_random_walker(matrix, num_steps) result(displacement)
            !! Let one random walker do **num_steps** jumps on the `.true.`
            !! values of **matrix**. The initial position is randomly selected.

            logical, dimension(:,:), intent(in) :: matrix
                !! Matrix whose `.true.` values are allowed positions for the
                !! random walker.

            integer :: num_steps
                !! Number of steps for the random walker to take.

            real(kind=dp), dimension(:,:), allocatable :: displacement
                !! Array of displacements, which has dimension
                !! 2 \\(\times\\) (**num_steps** + 1),
                !! and should logically have `dimension(2,0:num_steps)`, such that
                !! the i'th column contains the displacement after i steps.
                !! Averaged over all systems and all walkers.

            integer :: x0, y0, x, y, x_new, y_new, dx, dy, L, i, direction
            real(kind=dp) :: real_direction

            ! North - East - South - West
            integer, dimension(4) :: dxs = [0, 1, 0, -1]
            integer, dimension(4) :: dys = [1, 0, -1, 0]

            L = size(matrix, 1)
            allocate(displacement(2,0:num_steps))

            displacement(:,:) = 0

            call find_random_point(matrix, x0, y0)

            x = x0
            y = y0

            do i = 1, num_steps
                call random_number(real_direction)
                direction = int(4*real_direction + 1)

                dx = dxs(direction)
                dy = dys(direction)

                x_new = x + dx
                y_new = y + dy

                call periodic_wraparound(x_new, L)
                call periodic_wraparound(y_new, L)

                if(matrix(x_new, y_new)) then
                    x = x_new
                    y = y_new
                    displacement(:,i) = displacement(:,i-1) + [dx, dy]
                else
                    displacement(:,i) = displacement(:,i-1)
                end if

            end do
        end function

        function random_walkers(p, L, num_systems, num_walkers, num_steps) result(displacement)
            !! Start **num_walkers** on the percolating cluster of each of **num_systems**
            !! systems, and return the averaged displacement.

            real(kind=dp), intent(in) :: p
                !! The probability for each site to allow transport.
            integer, intent(in) ::  L
                !! The system size.
            integer, intent(in) ::  num_systems
                !! The number of systems over which to average.
            integer, intent(in) ::  num_walkers
                !! The number of random walkers for each system over which to average.
            integer, intent(in) ::  num_steps
                !! The number of steps which the random walkers take.

            real(kind=dp), dimension(:), allocatable :: displacement
                !! Array of squared displacements, which has dimension
                !! (**num_steps** + 1),
                !! and should logically have `dimension(0:num_steps)`, such that
                !! the i'th element contains the displacement after i steps.
                !! Averaged over all systems and all walkers.


            logical, dimension(:,:), allocatable :: binary_matrix, spanning_cluster
            integer, dimension(:,:), allocatable :: label_matrix
            real(kind=dp), dimension(:,:), allocatable :: tmp_displacement

            integer :: i, num_spanning_clusters, num_clusters, spanning_cluster_label

            allocate(displacement(0:num_steps))
            displacement(:) = 0

            num_spanning_clusters = 0
            do while(num_spanning_clusters < num_systems)
                binary_matrix = create_binary_matrix(p, L)
                call label(binary_matrix, label_matrix, num_clusters)
                spanning_cluster_label = find_spanning_cluster(label_matrix, num_clusters)

                if(spanning_cluster_label < 1) then
                    cycle
                end if
                num_spanning_clusters = num_spanning_clusters + 1

                spanning_cluster = mark_percolating_with_periodic( &
                                        label_matrix, spanning_cluster_label, &
                                        num_clusters)


                !$omp parallel do private(tmp_displacement) reduction(+:displacement)
                do i = 1, num_walkers
                    tmp_displacement = one_random_walker(spanning_cluster, num_steps)
                    displacement(:) = displacement(:) + sum(tmp_displacement(:,:)**2,dim=1)
                end do
                !$omp end parallel do
            end do
            displacement(:) = displacement(:)/(num_walkers*num_systems)

        end function

        function probability_distribution(p, L, num_steps, num_walkers, num_systems, num_hists) &
                 result(result_hist)
            !! Start **num_walkers** on the percolating cluster of each of **num_systems**
            !! systems, and compute **num_hists** histograms of the distribution
            !! of particles.

            real(kind=dp), intent(in) :: p
                !! The probability for each site to allow transport.
            integer, intent(in) ::  L
                !! The system size.
            integer, intent(in) ::  num_systems
                !! The number of systems over which to average.
            integer, intent(in) ::  num_walkers
                !! The number of random walkers for each system over which to average.
            integer, intent(in) ::  num_steps
                !! The number of steps which the random walkers take.
            integer, intent(in) :: num_hists
                !! The number of histograms to be returned.

            real(kind=dp), dimension(:,:), allocatable :: result_hist
                !! Array of histograms. The first row contains the centres of the
                !! bins, while the remaining **num_hists+1** rows each contain
                !! one histogram.


            logical, dimension(:,:), allocatable :: binary_matrix, spanning_cluster
            integer, dimension(:,:), allocatable :: label_matrix
            integer, dimension(:), allocatable :: hist_indices
            integer :: hist_dist, i, j, maxdist, x_index, y_index
            real(kind=dp), dimension(:,:), allocatable :: tmp_displacement, tmp_hist
            integer, dimension(:,:,:), allocatable :: displacement, absdisplacement



            integer :: num_spanning_clusters, num_clusters, spanning_cluster_label

            allocate(displacement(2,0:num_hists,num_walkers*num_systems))
            hist_dist = num_steps/num_hists
            allocate(hist_indices(0:num_hists))
            hist_indices(:) = [(hist_dist*i, i=0, num_hists)]

            num_spanning_clusters = 0
            do while(num_spanning_clusters < num_systems)
                binary_matrix = create_binary_matrix(p, L)
                call label(binary_matrix, label_matrix, num_clusters)
                spanning_cluster_label = find_spanning_cluster(label_matrix, num_clusters)

                if(spanning_cluster_label < 1) then
                    cycle
                end if
                num_spanning_clusters = num_spanning_clusters + 1

                spanning_cluster = mark_percolating_with_periodic( &
                                        label_matrix, spanning_cluster_label, &
                                        num_clusters)


                !$omp parallel do private(tmp_displacement)
                do i = 1, num_walkers
                    tmp_displacement = one_random_walker(spanning_cluster, num_steps)
                    do j = 0, num_hists
                        associate(hist_index => hist_indices(j), &
                                  indx => (num_spanning_clusters-1)*num_walkers+i)
                            displacement(:,j,indx) = tmp_displacement(:,hist_index+1)
                        end associate
                    end do
                end do
                !$omp end parallel do
            end do

            allocate(absdisplacement(2,0:num_hists,num_walkers*num_systems))

            !$omp parallel workshare
            absdisplacement(:,:,:) = abs(displacement(:,:,:))
            maxdist = maxval(absdisplacement)
            !$omp end parallel workshare

            allocate(result_hist(-1:num_hists,-maxdist:maxdist))
            result_hist(-1,:) = [(i, i = -maxdist, maxdist)]
            result_hist(0:,:) = 0

            !$omp parallel do private(x_index, y_index) reduction(+:result_hist)
            do i = 0, num_hists
                do j = 1, num_systems*num_walkers
                    associate(x => displacement(1,i,j), &
                              y => displacement(2,i,j))
                        result_hist(i,x) = result_hist(i,x) + 1
                        result_hist(i,y) = result_hist(i,y) + 1
                    end associate
                end do
            end do
            !$omp end parallel do

            result_hist(0:,:) = result_hist(0:,:)/(2.0d0*num_systems*num_walkers)

        end function
end module randomwalk