This question already has answers here:
Fortran pass an array to function
(1 answer)
How to pass allocatable arrays to subroutines in Fortran
(3 answers)
Closed 4 years ago.
I'm taking a course in atomistic simulation, and the language is Fortran.
I'm writing a program that simulates the movement of atoms in a box.
I have got a main and numerous subroutines. The main program code is the following:
program Spheres
implicit none
integer :: nspheres
double precision :: rvolume
integer :: ncollisions
double precision :: sigma
double precision, allocatable :: pos(:,:)
integer :: k,j
write(*,*) '1st subroutine read_input:'
call read_input(nspheres,rvolume,ncollisions)
write(*,*) ' '
allocate(pos(1:3,1:nspheres))
write(*,*) '2nd subroutine validate_input:'
call validate_input(nspheres,rvolume)
write(*,*) ' '
write(*,*) '3rd subroutine compute_diameter:'
call compute_diameter(nspheres,rvolume,sigma)
write(*,*) ' '
do k = 1, 3
do j = 1, nspheres
pos(k,j) = k
end do
end do
write(*,*) '4th subroutine assign_positions:'
call assign_positions(pos)
write(*,*) ' '
end program Spheres
I've created a 2-D array, which I allocate according to an integer that's inputted by the user (integer named nspheres).
After receiving nspheres from another subroutine, I'm allocating for the array.
Afterwards, the array is sent to another subroutine which decides the locations of the given amount of atoms (subroutine's name is assign_positions).
The 'assign_positions' subroutine code is the following, with the relevant part of code:
subroutine assign_positions(pos)
double precision, dimension(:,:), intent(inout), allocatable :: pos
integer :: nspheres
...
write(*,*), size(pos,2)
nspheres = size(pos,2)
...
do k = 1, 3
do j = 1, nspheres
write(*,*), pos(k,j)
end do
end do
end subroutine assign_positions
The thing is my lecturer wants the subroutine "assign-positions" to calculate the nspheres from the size of the sent array, and not sending both the array and the nspheres integer.
Inside the subroutine I've created another array, in order to receive the sent array and another integer named nspheres (along with other variables..).
Outside that subroutine (namely, before it) size(pos,2) gives back nspheres, because the array was created for the nspheres, BUT inside that subroutine, size(pos,2) give back a huge number, 1862125071.
I'm working on a virtual ubuntu environment, with gfortran compiler.
In order the test my code, I've entered some values to the array inside the main, and printed them, inside the main and then inside that suboutine.
The program compiled, and upon going to that subroutine the next error appears:
Program received signal SIGBUS: Access to an undefined portion of a memory object.
Backtrace for this error:
#0 0x7FEF314C0E08
#1 0x7FEF314BFF90
#2 0x7FEF30E074AF
#3 0x7FEF3159863F
#4 0x7FEF3159B154
#5 0x7FEF3159BD3E
#6 0x400EC5 in assign_positions_
#7 0x40192D in MAIN__ at Spheres.f90:?
Bus error (core dumped)
Related
This question already has answers here:
Preserve bounds in allocation in intrinsic assignment
(2 answers)
Preserve the bounds of a function array result
(1 answer)
Fortran doesn't keep lower/upper array bounds after copy to another allocatable array
(2 answers)
Closed 2 years ago.
As per object, I'm struggling understanding the logic behind functions returning allocatable arrays. I like this construct because its clarity compared to subroutines, and because pure functions in fortran are an excellent way to write clean, functional programming code.
Assume I have to write a simple function, returning an array of indices, with arbitrary bounds, such as in this program:
program test_allocatable_functionReturn
implicit none
integer, allocatable :: fun(:),sub(:),noa(:)
integer, parameter :: low = -4
integer, parameter :: hi = 3
call testsub(sub,low,hi)
fun = testfun(low,hi)
noa = testfun_noalloc(low,hi)
print '(4(a,i3),a)', 'testsub: lbound=',lbound(sub),'(expected = ',low,'), ubound=',ubound(sub),'(expected = ',hi,')'
print '(4(a,i3),a)', 'testfun: lbound=',lbound(fun),'(expected = ',low,'), ubound=',ubound(fun),'(expected = ',hi,')'
print '(4(a,i3),a)', 'no alloc: lbound=',lbound(noa),'(expected = ',low,'), ubound=',ubound(noa),'(expected = ',hi,')'
contains
pure function testfun_noalloc(low,hi) result(array)
integer, intent(in) :: low,hi
integer :: array(low:hi)
integer :: i
forall(i=low:hi) array(i) = i
end function testfun_noalloc
pure function testfun(low,hi) result(array)
integer, allocatable :: array(:)
integer, intent(in) :: low,hi
integer :: i
allocate(array(low:hi))
forall(i=low:hi) array(i) = i
end function testfun
pure subroutine testsub(array,low,hi)
integer, intent(out), allocatable :: array(:)
integer, intent(in) :: low,hi
integer :: i
allocate(array(low:hi))
forall(i=low:hi) array(i) = i
end subroutine testsub
end program
I have implemented it in three ways:
a function returning an allocatable array (testfun)
a subroutine (testsub)
a function returning a static array (testfun_noalloc)
The subroutine operates on the return array, and allocates it properly. In the example, an array sized (-4:3) should be returned. The function, in either implementation, returns an (1:hi-low+1) -sized array:
testsub: lbound= -4(expected = -4), ubound= 3(expected = 3)
testfun: lbound= 1(expected = -4), ubound= 8(expected = 3)
no alloc: lbound= 1(expected = -4), ubound= 8(expected = 3)
Why is that happening? I get the fact that fortran may reallocate the array when assigning the function return value to my LHS array, but even so, why isn't it allocated with the proper bounds? I understand such may happen when passing the static array to an allocatable with f2003-style reallocation of the lhs, but with an allocatable array as input, I was expecting the bounds information to be conserved. Am I missing something here? BTW, this example was compiled with gfortran 9.2.0.
Thanks,
Federico
Fortran question: I successfully made an array of pointers, which point to elements in an array of objects
Compiler is gcc/5.4.0
NOTE:
Using gcc/6.4.0 this problem is solved.
options are:
>>gfortran -fdefault-real-8 -o H -fbacktrace -g -fcheck=all pointersToObjects.f90
>>./H
here is a picture of my problem
I based my array of pointers on the answer to Arrays of pointers
I successfully create the array, and if I call any particular element in it, it gives the correct result. However, if I try to loop through the array of pointers, I get a segmentation fault once it reaches values that point to the second object.
This is strange because if I explicitly call for the value stored in the array of pointers from object 2 or 3 etc, it outputs the correct value. It only fails if I try to loop through all values.
here is the code:
program pointers
type objects
real, allocatable :: array(:)
character(10) :: misc1=""
end type objects
type ptr
real, pointer :: p
end type ptr
class(objects), allocatable, target :: objectArray(:)
integer :: i, j, elem
type(ptr), allocatable :: pointy(:)
allocate(objectArray(3))
do i = 1,3
allocate(objectArray(i)%array(i+1)) ! arbitrary array length in each object,
enddo
allocate(pointy(9)) ! this is 2 + 3 + 4, dimeneions of each objectArray%array
elem = 0 ! dummy counter variable
do i = 1,3
do j = 1,size(objectArray(i)%array)
elem = elem + 1
! give dummy values to objectArray, then point to them with pointy
objectArray(i)%array(j) = rand()
pointy(elem)%p => objectArray(i)%array(j)
print*,i,j, 'obj: ', objectArray(i)%array(j), 'pointer: ', pointy(elem)%p
enddo
enddo
print*, 'size: ', size(pointy), elem, pointy(9)%p
print*, '========================='
do i = 1,size(pointy)
print*, i, pointy(i)%p
enddo
end program pointers
and here is the output:
Francescalus gave the answer in the comments. But to give closing:
Using gcc/6.4.0 rather than gcc/5.4.0 fixes the problem.
This question already has answers here:
keeping array limits in fortran during subroutine call
(3 answers)
Closed 5 years ago.
I am trying to pass the allocatable array to the subroutine. When I am using the serial version as mentioned in How to pass allocatable arrays to subroutines in Fortran it is working fine. Below is my serial version of code.
module test
contains
subroutine func(a,sqa,n)
implicit none
integer, intent(in) :: n
integer, intent(in), dimension(:,:) :: a
integer, intent(out), dimension(:,:):: sqa
!local variables
integer :: i,j
do i= 1,n
do j = 1,2
sqa(i,j) = a(i,j)*a(i,j)
print *, 'i',i, 'j', j,'sqa(i,j)',sqa(i,j)
end do
end do
end subroutine func
end module test
program main
use test
implicit none
integer :: n,i,j
integer, dimension(:,:), allocatable :: a, sqa
print *, 'enter no of rows'
read *, n
allocate(a(1:n,2))
allocate(sqa(1:n,2))
do i = 1,n
do j = 1, 2
a(i,j) = i +j
print *, 'i =',i,'j =',j, a(i,j)
end do
end do
call func(a, sqa,n)
deallocate(a,sqa)
end program main
When I start to implement using MPI, my parallel version of code is
module test
contains
subroutine func(a,sqa,istart,iend)
implicit none
integer, intent(in) :: istart, iend
integer, intent(in), dimension(:,:) :: a
integer, intent(out),dimension(:,:) :: sqa
!local variables
integer :: i,j
do i= istart, iend
do j = 1,2
sqa(i,j) = a(i,j)*a(i,j)
print *, 'i',i, 'j', j,'sqa(i,j)',sqa(i,j)
end do
end do
end subroutine func
end module test
program main
use test
use mpi
implicit none
integer :: istart, iend, ierr,nproc, procnum, n,&
points_per_thread, i,j
integer, dimension(:,:), allocatable :: a, sqa
integer,dimension(mpi_status_size) :: status
call mpi_init(ierr)
call mpi_comm_size(mpi_comm_world, nproc, ierr)
call mpi_comm_rank(mpi_comm_world,procnum, ierr)
if(procnum == 0)then
print *, 'enter no of rows'
read *, n
end if
call mpi_bcast(n,1,mpi_integer,0,mpi_comm_world, ierr)
points_per_thread = (n + nproc - 1)/nproc
istart = procnum*points_per_thread + 1
iend = min((procnum + 1)*points_per_thread,n)
print *, 'istart ', istart, 'iend', iend, 'procnum', procnum
call mpi_barrier(mpi_comm_world, ierr)
allocate(a(istart:iend,2))
allocate(sqa(istart:iend,2))
do i = istart,iend
do j = 1, 2
a(i,j) = i +j
print *, 'i =',i,'j =',j, a(i,j)
end do
end do
call mpi_barrier(mpi_comm_world, ierr)
call func(a(istart:iend,:), sqa(istart:iend,:),istart,iend)
deallocate(a,sqa)
call mpi_finalize(ierr)
end program main
The above code gives the segmentation fault error. I don't understand the reason for this.
Next, when in my subroutine func I change the declaration of arrays a and sqa to
integer,intent(in):: a(istart:iend,2)
integer, intent(out)::sqa(istart:iend,2)
Now it works fine. I request to kindly help me understand the reason for the error.
Assumed shape dummy arrays make available the extension of the actual arguments inside the function but not their bounds. If the actual bounds are needed inside the function, explicit-shape dummy arrays must be used.
I have a simple problem in a rather simple code, but I really dont get to find the error after some hours. Here a minimised version of the code, where the problem occurs:
SUBROUTINE Partial_KlassRKV(x,y,f,f_xMarge,f_yMarge)
USE DGL_Functions
IMPLICIT NONE
REAL :: x(:),y(:),f(:,:,:),f_xMarge(:,:),f_yMarge(:,:)
INTEGER :: i,j,k
REAL :: partial_fx(6,6)
DO k=1,size(f,3)
partial_fx=PartialCalc(x,y,f(:,:,k),f_xMarge,f_yMarge)
WRITE(*,*) 'Nach PartialCalc x'
STOP
END DO
...
MODULE DGL_Functions
CONTAINS
FUNCTION PartialCalc(x,y,f,f_xMarge,f_yMarge)
IMPLICIT NONE
REAL :: x(:),y(:),f(:,:),f_xMarge(:,:),f_yMarge(:,:)
REAL :: PartialCalc(6,6)
INTEGER :: i,j
DO i=1,size(PartialCalc,1)
DO j=1,size(PartialCalc,2)
PartialCalc(i,j)=i+j
END DO
END DO
WRITE(*,*) 'PartialCalc ',PartialCalc
END FUNCTION PartialCalc
It returns the last WRITE-statement in FUNCION PartialCalc but not the WRITE after
partial_fx=PartialCalc(x,y,f(:,:,k),f_xMarge,f_yMarge)
in the SUBROUTINE. At that line there is "Array subscript out of bounds". I dont understand this. Both arrays (partial_fx and PartialCalc) are declared with dim (6,6) and a value is assigned to each PartialCalc(i,j)...?
Greets intasys
PS:I am using Plato f95 with Checkmate 32.
Maybe try a different compiler. gfortran and ifort normally identify the array and even the index value that is the problem. Here is a example that I quickly wrote:
module mysubs
contains
subroutine subxy (x,y)
real, dimension (5) :: x, y
x = 4.0
y = 5.0
end subroutine subxy
end module mysubs
program test_bounds
use mysubs
real :: x(4), y(5)
call subxy (x, y)
write (*, *) x, y
end program test_bounds
gfortran, with the right compiler options, finds this at compile time, with useful specificity:
call subxy (x, y)
1
Warning: Actual argument contains too few elements for dummy argument 'x' (4/5) at (1)
Is it possible in a modern Fortran compiler such as Intel Fortran to determine array strides at runtime? For example, I may want to perform a Fast Fourier Transform (FFT) on an array section:
program main
complex(8),allocatable::array(:,:)
allocate(array(17, 17))
array = 1.0d0
call fft(array(1:16,1:16))
contains
subroutine fft(a)
use mkl_dfti
implicit none
complex(8),intent(inout)::a(:,:)
type(dfti_descriptor),pointer::desc
integer::stat
stat = DftiCreateDescriptor(desc, DFTI_DOUBLE, DFTI_COMPLEX, 2, shape(a) )
stat = DftiCommitDescriptor(desc)
stat = DftiComputeForward(desc, a(:,1))
stat = DftiFreeDescriptor(desc)
end subroutine
end program
However, the MKL Dfti* routines need to be explicitly told the array strides.
Looking through reference manuals I have not found any intrinsic functions which return stride information.
A couple of interesting resources are here and here which discuss whether array sections are copied and how Intel Fortran handles arrays internally.
I would rather not restrict myself to the way that Intel currently uses its array descriptors.
How can I figure out the stride information? Note that in general I would want the fft routine (or any similar routine) to not require any additional information about the array to be passed in.
EDIT:
I have verified that an array temporary is not created in this scenario, here is a simpler piece of code which I have checked on Intel(R) Visual Fortran Compiler XE 14.0.2.176 [Intel(R) 64], with optimizations disabled and heap arrays set to 0.
program main
implicit none
real(8),allocatable::a(:,:)
pause
allocate(a(8192,8192))
pause
call random_number(a)
pause
call foo(a(:4096,:4096))
pause
contains
subroutine foo(a)
implicit none
real(8)::a(:,:)
open(unit=16, file='a_sum.txt')
write(16, *) sum(a)
close(16)
end subroutine
end program
Monitoring the memory usage, it is clear that an array temporary is never created.
EDIT 2:
module m_foo
implicit none
contains
subroutine foo(a)
implicit none
real(8),contiguous::a(:,:)
integer::i, j
open(unit=16, file='a_sum.txt')
write(16, *) sum(a)
close(16)
call nointerface(a)
end subroutine
end module
subroutine nointerface(a)
implicit none
real(8)::a(*)
end subroutine
program main
use m_foo
implicit none
integer,parameter::N = 8192
real(8),allocatable::a(:,:)
integer::i, j
real(8)::count
pause
allocate(a(N, N))
pause
call random_number(a)
pause
call foo(a(:N/2,:N/2))
pause
end program
EDIT 3:
The example illustrates what I'm trying to achieve. There is a 16x16 contiguous array, but I only want to transform the upper 4x4 array. The first call simply passes in the array section, but it doesn't return a single one in the upper left corner of the array. The second call sets the appropriate stride and a subsequently contains the correct upper 4x4 array. The stride of the upper 4x4 array with respect to the full 16x16 array is not one.
program main
implicit none
complex(8),allocatable::a(:,:)
allocate(a(16,16))
a = 0.0d0
a(1:4,1:4) = 1.0d0
call fft(a(1:4,1:4))
write(*,*) a(1:4,1:4)
pause
a = 0.0d0
a(1:4,1:4) = 1.0d0
call fft_stride(a(1:4,1:4), 1, 16)
write(*,*) a(1:4,1:4)
pause
contains
subroutine fft(a) !{{{
use mkl_dfti
implicit none
complex(8),intent(inout)::a(:,:)
type(dfti_descriptor),pointer::desc
integer::stat
stat = DftiCreateDescriptor(desc, DFTI_DOUBLE, DFTI_COMPLEX, 2, shape(a) )
stat = DftiCommitDescriptor(desc)
stat = DftiComputeForward(desc, a(:,1))
stat = DftiFreeDescriptor(desc)
end subroutine !}}}
subroutine fft_stride(a, s1, s2) !{{{
use mkl_dfti
implicit none
complex(8),intent(inout)::a(:,:)
integer::s1, s2
type(dfti_descriptor),pointer::desc
integer::stat
integer::strides(3)
strides = [0, s1, s2]
stat = DftiCreateDescriptor(desc, DFTI_DOUBLE, DFTI_COMPLEX, 2, shape(a) )
stat = DftiSetValue(desc, DFTI_INPUT_STRIDES, strides)
stat = DftiCommitDescriptor(desc)
stat = DftiComputeForward(desc, a(:,1))
stat = DftiFreeDescriptor(desc)
end subroutine !}}}
end program
I'm guessing you get confused because you worked around the explicit interface of the MKL function DftiComputeForward by giving it a(:,1). This is contiguous and doesn't need an array temporary. It's wrong, however, the low-level routine will get the whole array and that's why you see that it works if you specify strides. Since the DftiComputeForward exects an array complex(kind), intent inout :: a(*), you can work by passing it through an external subroutine.
program ...
call fft(4,4,a(1:4,1:4))
end program
subroutine fft(m,n,a) !{{{
use mkl_dfti
implicit none
complex(8),intent(inout)::a(*)
integer :: m, n
type(dfti_descriptor),pointer::desc
integer::stat
stat = DftiCreateDescriptor(desc, DFTI_DOUBLE, DFTI_COMPLEX, 2, (/m,n/) )
stat = DftiCommitDescriptor(desc)
stat = DftiComputeForward(desc, a)
stat = DftiFreeDescriptor(desc)
end subroutine !}}}
This will create an array temporary though when going into the subroutine. A more efficient solution is then indeed strides:
program ...
call fft_strided(4,4,a,16)
end program
subroutine fft_strided(m,n,a,lda) !{{{
use mkl_dfti
implicit none
complex(8),intent(inout)::a(*)
integer :: m, n, lda
type(dfti_descriptor),pointer::desc
integer::stat
integer::strides(3)
strides = [0, 1, lda]
stat = DftiCreateDescriptor(desc, DFTI_DOUBLE, DFTI_COMPLEX, 2, (/m,n/) )
stat = DftiSetValue(desc, DFTI_INPUT_STRIDES, strides)
stat = DftiCommitDescriptor(desc)
stat = DftiComputeForward(desc, a)
stat = DftiFreeDescriptor(desc)
end subroutine !}}}
Tho routine DftiComputeForward accepts an assumed size array. If you pass something complicated and non-contiguous, a copy will have to be made at passing. The compiler can check at run-time if the copy is actually necessary or not. In any case for you the stride is always 1, because that will be the stride the MKL routine will see.
In your case you pass A(:,something), this is a contiguous section, provided A is contiguous. If A is not contiguous a copy will have to be made. Stride is always 1.
Some of the answers here do not understand the different between fortran strides and memory strides (though they are related).
To answer your question for future readers beyond the specific case you have here - there does not appear to be away to find an array stride solely in fortran, but it can be done via C using inter-operability features in newer compilers.
You can do this in C:
#include "stdio.h"
size_t c_compute_stride(int * x, int * y)
{
size_t px = (size_t) x;
size_t py = (size_t) y;
size_t d = py-px;
return d;
}
and then call this function from fortran on the first two elements of an array, e.g.:
program main
use iso_c_binding
implicit none
interface
function c_compute_stride(x, y) bind(C, name="c_compute_stride")
use iso_c_binding
integer :: x, y
integer(c_size_t) :: c_compute_stride
end function
end interface
integer, dimension(10) :: a
integer, dimension(10,10) :: b
write(*,*) find_stride(a)
write(*,*) find_stride(b(:,1))
write(*,*) find_stride(b(1,:))
contains
function find_stride(x)
integer, dimension(:) :: x
integer(c_size_t) :: find_stride
find_stride = c_compute_stride(x(1), x(2))
end function
end program
This will print out:
4
4
40
In short: assumed-shape arrays always have stride 1.
A bit longer: When you pass a section of an array to a subroutine which takes an assumed-shape array, as you have here, then the subroutine doesn't know anything about the original size of the array. If you look at the upper- and lower-bounds of the dummy argument in the subroutine, you'll see they will always be the size of the array section and 1.
integer, dimension(10:20) :: array
integer :: i
array = [ (i, i=10,20) ]
call foo(array(10:20:2))
subroutine foo(a)
integer, dimension(:) :: a
integer :: i
print*, lbound(a), ubound(a)
do i=lbound(a,1), ubound(a,2)
print*, a(i)
end do
end subroutine foo
This gives the output:
1 6
10 12 14 16 18 20
So, even when your array indices start at 10, when you pass it (or a section of it), the subroutine thinks the indices start at 1. Similarly, it thinks the stride is 1. You can give a lower bound to the dummy argument:
integer, dimension(10:) :: a
which will make lbound(a) 10 and ubound(a) 15. But it's not possible to give an assumed-shape array a stride.