utilities.f90 Source File


Files dependent on this one

sourcefile~~utilities.f90~~AfferentGraph sourcefile~utilities.f90 utilities.f90 sourcefile~randomwalk.f90 randomwalk.f90 sourcefile~randomwalk.f90->sourcefile~utilities.f90 sourcefile~percolation.f90 percolation.f90 sourcefile~randomwalk.f90->sourcefile~percolation.f90 sourcefile~percolation.f90->sourcefile~utilities.f90

Contents

Source Code


Source Code

module utilities
    !! Useful procedures when doing percolation.
    implicit none
    integer, parameter :: dp = kind(1.0d0)
        !! Kind used for all **real** variables.
    contains
        function stringfromint(x)
            !! Make a string of "correct" length from a positive integer.
            character(len=:), allocatable :: stringfromint
                !! String containing the given integer, without spaces.
            integer, intent(in) :: x
                !! Positive integer to be converted.
            integer :: numdigits

            numdigits = int(log10(real(x))) + 1
            allocate(character(len=numdigits) :: stringfromint)
            write(unit=stringfromint, fmt="(i0)") x
        end function

        function linspace(a,b,N)
            !! Create an array of **N** linearly spaced *values* (not intervals)
            !! from **a** to **b**.
            !! Similar to [`numpy.linspace(a, b, N)`](https://docs.scipy.org/doc/numpy/reference/generated/numpy.linspace.html).
            integer, intent(in) :: N
                !! Number of values (not intervals).
            real(kind=dp), intent(in) :: a
                !! Lower endpoint.
            real(kind=dp), intent(in) :: b
                !! Upper endpoint.
            real(kind=dp), dimension(:), allocatable :: linspace
                !! Array of linearly spaced values.
            real(kind=dp) :: dx
            integer :: i

            dx = (b - a)/(N - 1)
            linspace = [ (a + i*dx, i=0, N-1) ]
        end function

        subroutine linfit(x, y, slope, const)
            !! Compute a linear fit for the given data, return
            !! the slope and the constant term.
            !! `dgels` from LAPACK solves the linear least squares problem.
            real(kind=dp), dimension(:), intent(in) :: x, y
                !! Values to be fitted.
            real(kind=dp), intent(inout) :: slope
                !! \\(a\\) in \\(y=ax+b\\).
            real(kind=dp), intent(inout) :: const
                !! \\(b\\) in \\(y=ax+b\\).

            real(kind=dp), dimension(:,:), allocatable :: A
            real(kind=dp), dimension(:), allocatable :: b, work
            integer :: lda, ldb, lwork, info, m

            m = size(x)
            allocate(A(m,2))
            allocate(b(m))
            allocate(work(1))

            A(:,1) = x(:)
            A(:,2) = 1
            b(:) = y(:)

            lda = m
            ldb = m

            lwork = -1
            call dgels("N",m,2,1,A,lda,b,ldb,work,lwork,info)
            lwork = int(work(1))
            deallocate(work)
            allocate(work(lwork))
            call dgels("N",m,2,1,A,lda,b,ldb,work,lwork,info)

            slope = b(1)
            const = b(2)

            if(info /= 0) then
                error stop "Problems with least squares"
            endif
        end subroutine

        function find_intersection(array1, array2, num_labels) result(intersect_label)
            !! Find the common element in two arrays, given a total of
            !! **num_labels** unique elements. Used by [[find_spanning_cluster]].
            integer, dimension(:), intent(in) :: array1, array2
                !! Array to analyse.
            integer, intent(in) :: num_labels
                !! The known number of unique non-zero elements.
            integer :: intersect_label
                !! The first non-zero common element.
            integer :: L, i
            logical, dimension(:), allocatable :: label_found

            L = size(array1)

            allocate(label_found(0:num_labels))
            !/intersectsnippetstart/!
            label_found(0:num_labels) = .false.

            do i=1,L
                label_found(array1(i)) = .true.
            end do

            do i=1,L
                if(array2(i) /= 0 .and. label_found(array2(i))) then
                    intersect_label = array2(i)
                    return
                end if
            end do
            !/intersectsnippetend/!

            intersect_label = -1
        end function

        subroutine find_random_point(matrix, i, j)
            !! Find a random position on **matrix** such that
            !! **matrix(i, j)** is `.true.`.

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

            integer, intent(out) :: i, j
                !! Returned random point on **matrix**.

            integer :: L
            real(kind=dp) :: x0_real, y0_real

            L = size(matrix, 1)

            ! Find random starting point.
            do
                call random_number(x0_real)
                call random_number(y0_real)

                x0_real = L*x0_real + 1
                y0_real = L*y0_real + 1

                i = int(x0_real)
                j = int(y0_real)

                if(matrix(i,j)) then
                    return
                end if
            end do
        end subroutine

        subroutine periodic_wraparound(x, L)
            integer, intent(inout) :: x
            integer, intent(in) :: L

            if(x == 0) then
                !write(*,*) "before:", x
                x = L
                !write(*,*) "after:", x
            else if(x == L+1) then
                !write(*,*) "before:", x
                x = 1
                !write(*,*) "after:", x
            end if
        end subroutine

        function mark_percolating_with_periodic(label_matrix, &
                                                percolating_label, &
                                                num_clusters) &
                                                result(matrix)
            !! Return a `logical` matrix where the `.true.` values are the sites
            !! belonging to the percolating cluster, when periodic boundary
            !! conditions are considered.

            integer, dimension(:,:), intent(in) :: label_matrix
                !! Labelled matrix from [[label]] or [[hoshen_kopelman]].
            integer, intent(in) :: percolating_label
                !! Known label of the percolating cluster.
            integer, intent(in) :: num_clusters
                !! The known number of clusters.
            logical, dimension(:,:), allocatable :: matrix
                !! Matrix where the `.true.` values are the sites belonging to
                !! the percolating cluster with periodic boundary conditions.

            integer :: L, i, j
            logical, dimension(:), allocatable :: connected_to_percolating

            L = size(label_matrix, 1)

            allocate(matrix(L,L))
            allocate(connected_to_percolating(0:num_clusters))

            connected_to_percolating(:) = .false.
            connected_to_percolating(percolating_label) = .true.

            do i = 1, L
                if(label_matrix(i,1) == percolating_label) then
                    connected_to_percolating(label_matrix(i, L)) = .true.
                end if

                if(label_matrix(i,L) == percolating_label) then
                    connected_to_percolating(label_matrix(i, 1)) = .true.
                end if

                if(label_matrix(1,i) == percolating_label) then
                    connected_to_percolating(label_matrix(L, i)) = .true.
                end if

                if(label_matrix(L, i) == percolating_label) then
                    connected_to_percolating(label_matrix(1, i)) = .true.
                end if
            end do

            connected_to_percolating(0) = .false.

            !$omp parallel do
            do j = 1, L
                do i = 1, L
                    matrix(i,j) = connected_to_percolating(label_matrix(i,j))
                end do
            end do
            !$omp end parallel do
        end function
end module