Compilation error most of the times

In most of the times i try to to run this code, it returns the error:

Program received signal SIGSEGV: Segmentation fault - invalid memory reference.

Backtrace for this error:
#0  0xffffffff
#1  0xffffffff
#2  0xffffffff
#3  0xffffffff
#4  0xffffffff
#5  0xffffffff
#6  0xffffffff
#7  0xffffffff
#8  0xffffffff
#9  0xffffffff
#10  0xffffffff
#11  0xffffffff
#12  0xffffffff
#13  0xffffffff
#14  0xffffffff

I’m still strugglin to learn the language but it’s (or it must be) a code for partciles collision using monte carlo method. I think the problem is the subroutine that change the velocities but i really have no idea. I know it is’nt the most efficient whey of writting this type of code and some of the code it’s temporary but the idea is pretty much it

program collision
    use rf_mod, only: rf
    implicit none
    
    integer                                  :: n_particles = 10, i, j, k=0, t, ts=1000
    real(8), parameter                       :: radius=0.06, dt=0.00008, c=1.0
    integer, dimension(:,:)    , allocatable :: id_pairs, id_pairs_collide
    real(8), dimension(:)      , allocatable :: ids, d_pairs
    real(8), dimension(:,:)    , allocatable :: r, v, v1, v2,v1new, v2new, r1, r2
    real(8), dimension(:,:,:), allocatable   :: rs, vs
    
    
    !GENARATING THE PARTICLES
    allocate(r(2,n_particles)) !position of the particles
    allocate(v(2,n_particles)) !vellocities of the particles
    allocate(ids(n_particles))
    
    allocate(rs(ts, 2, n_particles))
    allocate(vs(ts, 2, n_particles))
    rs = 0.0
    vs = 0.0
    
    ids = [(i, i=1, n_particles)]
    
    call random_number(r)
    !do i=1, 2 !randomly positioning each particle
        !do j=1, n_particles
            !r(i,j) = rf()
        !end do
    !end do
    
    open(40, file = 'pos.txt', status='unknown')        
        do j =1, n_particles
                if(r(1,j) > 0.5) then
                    write(40,1)r(:,j)!, 'red'
                    1 format(2f20.6)
                else
                    write(40,2)r(:,j)!, 'green'
                    2 format(2f20.6)
                end if
        end do
    close(40)
    !call system ('gnuplot -p grafico.plt')
    
    !initial vellocities
    !if the particle is in the left corner, v=100.
    !if it's in the right, v=-100
    v(2,:) = 0
    where(r(1,:) < 0.5)
        v(1,:) = 100.
    elsewhere
        v(1,:) = -100.
    end where
    
    !DISTANCE BETWEEN ALL THE PAIR OF PARTICLES
    
    !all pair of particles
    id_pairs = combination(ids)
    d_pairs = get_deltad_pairs(r)
    

    do t=1, ts
    
        do i=1, size(d_pairs)
            if((d_pairs(i) <2*radius) .eqv. .true.) then
                k = k+1
            end if
        enddo
       
        allocate(id_pairs_collide(2,k))
    
        j=1
        do i=1, size(d_pairs)
            if(d_pairs(i) < 2*radius) then 
                id_pairs_collide(:,j) =  id_pairs(:,i)
                j=j+1
            end if
        enddo

    !Now, we need to calculate the velocities of each particle, iterate, compare distances and change the vellocities
        v1 = v(:, id_pairs_collide(1,:)) !particle i
        v2 = v(:, id_pairs_collide(2,:)) !particle j
        r1 = r(:, id_pairs_collide(1,:))
        r2 = r(:, id_pairs_collide(2,:))
      
        call get_new_v(v1, v2, v1new, v2new) 
        v(:, id_pairs_collide(1,:)) = v1new
        v(:, id_pairs_collide(2,:)) = v2new
        
        
        where(r(1,:) > 1.0)
            v(1,:) = -abs(v(1,:))
        end where
        where(r(1,:) < 0.0)
            v(1,:) = abs(v(1,:))
        end where
        where(r(2,:) > 1.0)
            v(2,:) = -abs(v(2,:))
        end where
        where(r(2,:) < 0.0)
            v(2,:) = abs(v(2,:))
        end where
                
          
        r = r + v*dt
        rs(i,:,:) = r(:,:)
        vs(i,:,:) = v(:,:)


        deallocate(id_pairs_collide)
        deallocate(v1)
        deallocate(v2)
        deallocate(r1)
        deallocate(r2)
        !print *, r(:,1)

    enddo
    open(40, file = 'all_pos.txt', status='unknown')        
    do i = 1, ts
            write(40,*)rs(i,2,:)
    end do
    close(40)
    PRINT*, v1new
contains

function get_deltad_pairs(r)
    !get the distance between all the particles
    !d_ij = sqrt(x_ij ^ 2 + y_ij ^ 2)
    real(8), allocatable :: get_deltad_pairs(:), r(:,:)
    
    get_deltad_pairs = sqrt(diff(combination(r(1,:)))**2 + diff(combination(r(2,:)))**2)

end function get_deltad_pairs

function combination(arg) result(comb)
    implicit none
    real(8), dimension(:,:), allocatable :: comb
    real(8), intent(in), dimension(:) :: arg
    integer :: M, N, counter, i, j

    N=size(arg)
    M=int(N*(N-1)/2)
    allocate(comb(2,M))
    counter=1
    do i=1,N
        do j=i+1,N
            comb(1,counter)=arg(i)
            comb(2,counter)=arg(j)
            counter = counter + 1
        enddo
    enddo
    
end function combination

function diff(v)
    implicit none
    real(8), intent(in), dimension(:,:) :: v
    real(8), allocatable:: diff(:), v1(:), v2(:)
    integer :: n 

    n = size(v)/2
    allocate(v1(n))
    allocate(v2(n))
    v1 = v(1,:)
    v2 = v(2,:)
    diff = abs(v1 - v2)
end function diff

subroutine get_new_v(v1, v2, v1n, v2n)
    
    implicit none
    real(8), dimension(:,:), intent(in)  :: v1, v2
    real(8), dimension(:,:), allocatable :: G, gr, grnew
    real(8), dimension(:,:), allocatable, intent(out) :: v1n, v2n
    real(8) :: cosx, sinx, e, RF1, RF2, PI=4.D0*DATAN(1.D0)
    integer :: i, j
    
    gr = v1 - v2       !relative velocities
    G  = (v1 + v2)/2.0 !relative velocities o the center of mass
    
    do i=1, 2
        do j=1, size(gr)/2
            call random_number(RF2)
            call random_number(RF1)
            cosx = 2.0*RF1 - 1.0
            sinx = sqrt(1 - cosx**2)
            e = 2*RF2*pi

            if(i==1) then
                
                grnew(i,j) = sqrt(sum(gr(i,:)**2))*cosx
                
            else 
                
                grnew(i,j) = sqrt(sum(gr(i,:)**2))*sinx*sin(e)
                
            endif
        enddo
    enddo

    v1n = G + 0.5*grnew
    v2n = G - 0.5*grnew
    return

end subroutine get_new_v 

end program

module rf_mod
    contains
    DOUBLE PRECISION FUNCTION RF()
        IMPLICIT DOUBLE PRECISION (A-H, O-Z)
        data IX1,IX2,IX3,IX4,IX5,IX6/1500419,1400159,1364,1528,1,3/
        RR1=1.0/FLOAT(IX1)
        RR2=1.0/FLOAT(IX2)
        IX5=MOD(IX5*IX3,IX1)
        IX6=MOD(IX6*IX4,IX2)
        RF=RR1*IX5+RR2*IX6
        IF(RF.GE.1.0)RF=RF-1.0
    END FUNCTION


end module
1 Like

In subroutine get_newv(), you are using the 2-D allocatable array grnew without allocating it!

Another thing to check: does your code satisfies the following rule?

If a vector subscript has two or more elements with the same value, an array section with that vector subscript shall not appear in a variable definition context

2 Likes

I see these problems in your code:

  • Some allocatable variables are not allocated
  • Mixed mode arithmetic
  • Mixed mode variable assignments
  • real(kind=4) instead of real(kind=8)
2 Likes

Using debugging compiler options can aid in debugging. On WSL2, compiling with
gfortran -g -fbacktrace collision.f90 and running

gives

Program received signal SIGSEGV: Segmentation fault - invalid memory reference.

Backtrace for this error:
#0  0x7fe1bdf1d700 in ???
#1  0x7fe1bdf1c8a5 in ???
#2  0x7fe1bdc0120f in ???
#3  0x55df3f479b98 in get_new_v
	at /mnt/c/fortran/test/collision.f90:207
#4  0x55df3f47ce6d in collision
	at /mnt/c/fortran/test/collision.f90:130
#5  0x55df3f47f0e9 in main
	at /mnt/c/fortran/test/collision.f90:18
Segmentation fault

The code was rearranged to put the module before the main program:

collision.f90
module rf_mod
    contains
    DOUBLE PRECISION FUNCTION RF()
        IMPLICIT DOUBLE PRECISION (A-H, O-Z)
        data IX1,IX2,IX3,IX4,IX5,IX6/1500419,1400159,1364,1528,1,3/
        RR1=1.0/FLOAT(IX1)
        RR2=1.0/FLOAT(IX2)
        IX5=MOD(IX5*IX3,IX1)
        IX6=MOD(IX6*IX4,IX2)
        RF=RR1*IX5+RR2*IX6
        IF(RF.GE.1.0)RF=RF-1.0
    END FUNCTION


end module

program collision
    use rf_mod, only: rf
    implicit none
    
    integer                                  :: n_particles = 10, i, j, k=0, t, ts=1000
    real(8), parameter                       :: radius=0.06, dt=0.00008, c=1.0
    integer, dimension(:,:)    , allocatable :: id_pairs, id_pairs_collide
    real(8), dimension(:)      , allocatable :: ids, d_pairs
    real(8), dimension(:,:)    , allocatable :: r, v, v1, v2,v1new, v2new, r1, r2
    real(8), dimension(:,:,:), allocatable   :: rs, vs
    
    
    !GENARATING THE PARTICLES
    allocate(r(2,n_particles)) !position of the particles
    allocate(v(2,n_particles)) !vellocities of the particles
    allocate(ids(n_particles))
    
    allocate(rs(ts, 2, n_particles))
    allocate(vs(ts, 2, n_particles))
    rs = 0.0
    vs = 0.0
    
    ids = [(i, i=1, n_particles)]
    
    call random_number(r)
    !do i=1, 2 !randomly positioning each particle
        !do j=1, n_particles
            !r(i,j) = rf()
        !end do
    !end do
    
    open(40, file = 'pos.txt', status='unknown')        
        do j =1, n_particles
                if(r(1,j) > 0.5) then
                    write(40,1)r(:,j)!, 'red'
                    1 format(2f20.6)
                else
                    write(40,2)r(:,j)!, 'green'
                    2 format(2f20.6)
                end if
        end do
    close(40)
    !call system ('gnuplot -p grafico.plt')
    
    !initial vellocities
    !if the particle is in the left corner, v=100.
    !if it's in the right, v=-100
    v(2,:) = 0
    where(r(1,:) < 0.5)
        v(1,:) = 100.
    elsewhere
        v(1,:) = -100.
    end where
    
    !DISTANCE BETWEEN ALL THE PAIR OF PARTICLES
    
    !all pair of particles
    id_pairs = combination(ids)
    d_pairs = get_deltad_pairs(r)
    

    do t=1, ts
    
        do i=1, size(d_pairs)
            if((d_pairs(i) <2*radius) .eqv. .true.) then
                k = k+1
            end if
        enddo
       
        allocate(id_pairs_collide(2,k))
    
        j=1
        do i=1, size(d_pairs)
            if(d_pairs(i) < 2*radius) then 
                id_pairs_collide(:,j) =  id_pairs(:,i)
                j=j+1
            end if
        enddo

    !Now, we need to calculate the velocities of each particle, iterate, compare distances and change the vellocities
        v1 = v(:, id_pairs_collide(1,:)) !particle i
        v2 = v(:, id_pairs_collide(2,:)) !particle j
        r1 = r(:, id_pairs_collide(1,:))
        r2 = r(:, id_pairs_collide(2,:))
      
        call get_new_v(v1, v2, v1new, v2new) 
        v(:, id_pairs_collide(1,:)) = v1new
        v(:, id_pairs_collide(2,:)) = v2new
        
        
        where(r(1,:) > 1.0)
            v(1,:) = -abs(v(1,:))
        end where
        where(r(1,:) < 0.0)
            v(1,:) = abs(v(1,:))
        end where
        where(r(2,:) > 1.0)
            v(2,:) = -abs(v(2,:))
        end where
        where(r(2,:) < 0.0)
            v(2,:) = abs(v(2,:))
        end where
                
          
        r = r + v*dt
        rs(i,:,:) = r(:,:)
        vs(i,:,:) = v(:,:)


        deallocate(id_pairs_collide)
        deallocate(v1)
        deallocate(v2)
        deallocate(r1)
        deallocate(r2)
        !print *, r(:,1)

    enddo
    open(40, file = 'all_pos.txt', status='unknown')        
    do i = 1, ts
            write(40,*)rs(i,2,:)
    end do
    close(40)
    PRINT*, v1new
contains

function get_deltad_pairs(r)
    !get the distance between all the particles
    !d_ij = sqrt(x_ij ^ 2 + y_ij ^ 2)
    real(8), allocatable :: get_deltad_pairs(:), r(:,:)
    
    get_deltad_pairs = sqrt(diff(combination(r(1,:)))**2 + diff(combination(r(2,:)))**2)

end function get_deltad_pairs

function combination(arg) result(comb)
    implicit none
    real(8), dimension(:,:), allocatable :: comb
    real(8), intent(in), dimension(:) :: arg
    integer :: M, N, counter, i, j

    N=size(arg)
    M=int(N*(N-1)/2)
    allocate(comb(2,M))
    counter=1
    do i=1,N
        do j=i+1,N
            comb(1,counter)=arg(i)
            comb(2,counter)=arg(j)
            counter = counter + 1
        enddo
    enddo
    
end function combination

function diff(v)
    implicit none
    real(8), intent(in), dimension(:,:) :: v
    real(8), allocatable:: diff(:), v1(:), v2(:)
    integer :: n 

    n = size(v)/2
    allocate(v1(n))
    allocate(v2(n))
    v1 = v(1,:)
    v2 = v(2,:)
    diff = abs(v1 - v2)
end function diff

subroutine get_new_v(v1, v2, v1n, v2n)
    
    implicit none
    real(8), dimension(:,:), intent(in)  :: v1, v2
    real(8), dimension(:,:), allocatable :: G, gr, grnew
    real(8), dimension(:,:), allocatable, intent(out) :: v1n, v2n
    real(8) :: cosx, sinx, e, RF1, RF2, PI=4.D0*DATAN(1.D0)
    integer :: i, j
    
    gr = v1 - v2       !relative velocities
    G  = (v1 + v2)/2.0 !relative velocities o the center of mass
    
    do i=1, 2
        do j=1, size(gr)/2
            call random_number(RF2)
            call random_number(RF1)
            cosx = 2.0*RF1 - 1.0
            sinx = sqrt(1 - cosx**2)
            e = 2*RF2*pi

            if(i==1) then
                
                grnew(i,j) = sqrt(sum(gr(i,:)**2))*cosx
                
            else 
                
                grnew(i,j) = sqrt(sum(gr(i,:)**2))*sinx*sin(e)
                
            endif
        enddo
    enddo

    v1n = G + 0.5*grnew
    v2n = G - 0.5*grnew
    return

end subroutine get_new_v 

end program

Line 207 is
grnew(i,j) = sqrt(sum(gr(i,:)**2))*cosx
consistent with what @mecej4 wrote. Other gfortran debugging options were discussed at Stack Overflow.

Btw your question is about a run-time error, not a compilation error.

2 Likes

If you are using gfortran, compile your code with the following options: -g -O0 -Wall -Werror -fmax-errors=1 -fcheck=all. This set typically catches errors such as accessing an array with an out-of-bounds index.

2 Likes

about line 207, i don’t think i understood what’s wrong

1 Like

Thanks, but could you point me on how to fix those problems?

1 Like

Jorvz, looks like you missed this:

You need to allocate the allocatable arrays before using them. It looks like you did not explicitly allocate gr, G, or grnew. gr got allocated through the automatically allocated on assignment feature on the line which reads gr=v1-v2. Similar with G. grnew array is being used without being allocated.

1 Like
  • You need to allocate all allocatable variables, like gr, G, grnew, …

  • I would like to suggest you to use a module for kinds as follows:

!==============================================================================
MODULE MOD_KINDS

   INTEGER, PARAMETER :: REL8 = 8

END MODULE MOD_KINDS
!==============================================================================

Now to declare and define a variable using module MOD_KINDS you can use:
real(REL8) instead of real(8),
rs = 0.0_REL8 instead of rs = 0.0,
0.5_REL8 instead of 0.5
and 2.0_REL8*radius instead of 2*radius. Find all the same problems and fix them.

  • To convert x to real(kind=8), you can use REAL(x,KIND=REL8).

  • ids is real(kind=8): ids = REAL([(i, i=1, n_particles)], KIND=REL8)

  • Check n = size(v)/2 and M = int(N*(N-1)/2). Are they correct?

  • I think there are more problems but you can find them yourself, also debug each function and subroutine with a test program first, then use them in your program, and finally debug your main program. (as @beliavsky mentioned use -g -fbacktrace flags.)