I'm new to Fortran programming and I'm trying to understand the call between subroutines. So I wrote a simple program to test it
Here is my code
program dummy
real, allocatable, dimension(:) :: zz,yy
call test2(zz,yy)
print *, zz, yy
contains
subroutine test1(ar1,ar2,arsum)
real, dimension(:) :: ar1,ar2
real, allocatable, dimension(:) :: arsum
allocate(arsum(size(ar1)+size(ar2)))
arsum(1:size(ar1)) = ar1
arsum(size(ar1)+1:size(ar1)+size(ar2)) = ar2
end subroutine test1
subroutine test2(sg1,sg2)
real, dimension(3) :: g1,g3
real, dimension(4) :: g2,g4
real, allocatable,dimension(:) :: sg1,sg2,dum
g1 = 1.0
g2 = 2.0
g3 = 3.0
g4 = 4.0
call test1(g1,g3,dum)
sg1 = 2*dum
call test1(g2,g4,dum)
sg2 = 3*dum
end subroutine test2
end program dummy
However this throws me the following error
forrtl: severe (151): allocatable array is already allocated
Image PC Routine Line Source
dummy.exe 0000000000409B1C Unknown Unknown Unknown
dummy.exe 0000000000402E70 MAIN__ 26 dummy.f90
dummy.exe 0000000000402A2E Unknown Unknown Unknown
libc-2.23.so 00002B3E716C7830 __libc_start_main Unknown Unknown
dummy.exe 0000000000402929 Unknown Unknown Unknown
The test1 subroutine simply concatenates any two given arrays. Test2 subroutine defines the arrays to be concatenated and does some algebra on the output and stores them in new arrays. The program dummy simply prints the new arrays.
What is it that I'm doing wrong here?
Let's look at the flow of the program here. There's some terminology involved here, but what is used can hopefully be explored through other documentation.
The main program calls the subroutine test2 with a couple of arguments. For the problem here, those arguments are of no interest. Instead, look at the local (to the subroutine) variable dum.
dum is an allocatable array. It starts life at execution of test2 as not allocated. It's first an (actual) argument to the call of test1 and later as an (actual) argument to another call of test1. So, what goes wrong?
Intent of the arguments is crucial here. Really crucial. One should read up on intents elsewhere before continuing with this answer.
So, we're now familiar with argument intents.
On entering the subroutine test1 the dummy argument arsum has the same allocation status as the actual argument dum. During test1's execution there is an allocate statement.
An allocate statement may only attempt to allocate a thing not already allocated. This is fine on the first call: on entry dum/arsum is not allocated. During execution of the subroutine arsum is allocated, and this affects the allocation status of test2's dum.
On the second call to test1 arsum is now allocated because the actual argument dum is allocated. The allocate statement fails, with the error message given, because of this.
That's the problem; how to fix? We need to ensure arsum is not allocated. There are two obvious ways:
test the allocation status of arsum and respond accordingly (perhaps with a deallocate);
deallocate dum between calls of test1.
But there is a possibly more appropriate way. Note that dum is useful only as returning to test2 the value of some operation. Think back to intents: this is what intent(out) signifies.
If we rewrite the subroutine test1 as
subroutine test1(ar1,ar2,arsum)
real, dimension(:) :: ar1,ar2
real, allocatable, dimension(:), intent(out) :: arsum
allocate(arsum(size(ar1)+size(ar2)))
arsum(1:size(ar1)) = ar1
arsum(size(ar1)+1:size(ar1)+size(ar2)) = ar2
end subroutine test1
then, because of the intent(out), attribute arsum/dum is automatically deallocated if it is allocated on entry.
Finally (and not shown), one could even consider using a function to return arsum or even use automatic arrays rather than allocatable ones. Or, even Fortran 2003 automatic allocation and an array constructor:
subroutine test1(ar1,ar2,arsum)
real, dimension(:) :: ar1,ar2
real, allocatable, dimension(:) :: arsum ! Or with `intent(out)`
arsum = [ar1,ar2]
end subroutine test1
Related
UPDATE: My modified code looks like this:
program run_module_test
use module_test
implicit none
TYPE(newXYZ), allocatable, intent(inout) :: xyzArray(:)
call update(xyzArray)
write(6,*)'xyzArray',xyzArray
end program run_module_test
module module_test
implicit none
TYPE :: newXYZ
real(4) :: x, u
real(4) :: y, v
real(4) :: z, w
real(4),dimension(3) :: uvw
END TYPE
integer(4) :: shape = 3
contains
subroutine update(xyzArray)
integer(4) :: i
TYPE(newXYZ), allocatable, intent(inout) :: xyzArray(:)
allocate( xyzArray(shape) )
do i = 1, shape
xyzArray(i)%x = 0
xyzArray(i)%y = 0
xyzArray(i)%z = 0
xyzArray(i)%u = 0
xyzArray(i)%v = 0
xyzArray(i)%w = 0
xyzArray(i)%uvw = (/0,0,0/)
end do
return
end subroutine update
end module module_test
When they are compiled, they generate a similar error:
TYPE(newXYZ), allocatable, intent(inout) :: xyzArray(:)
1
Error: ALLOCATABLE attribute conflicts with DUMMY attribute at (1)
When I eliminate the argument in update() subroutine, I receive a contradictory error:
TYPE(newXYZ), allocatable, intent(inout) :: xyzArray(:)
1
Error: Symbol at (1) is not a DUMMY variable
Have I eliminated the sources of error pointed out in the helpful suggestions? Could this be a compiler related error (using mpi90)?
~~~First Edit~~~
I have a subroutine whose input argument is an array of user defined type XYZ. I wish to deallocate xyzArray and allocate/modify it to a different size in the body of the subroutine. I attempted the method suggested by changing array dimensions in fortran, but when I do the following:
subroutine update(xyzArray, ...)
...
TYPE (XYZ), allocatable :: xyzArray(:)
I receive an error message:
Error: ALLOCATABLE attribute conflicts with DUMMY attribute at (1)
When I try:
subroutine update(xyzArray, ...)
...
deallocate( xyzArray(myshape) )
allocate( xyzArray(newshape) )
I receive error messages:
Error: Expression in DEALLOCATE statement at (1) must be ALLOCATABLE or a POINTER
Error: Expression in ALLOCATE statement at (1) must be ALLOCATABLE or a POINTER
What do I need to do to change the size of the array in the subroutine?
To do this:
The dummy argument must be allocatable. Allocatable dummy arguments require a compiler that implements the relevant part of the Fortran 2003 standard (or a Fortran 95 compiler that implements the so called "allocatable" TR).
An explicit interface to the procedure is required (the procedure must be a module procedure, an internal procedure or have an interface block in the calling scope).
The dummy argument must not be intent(in). If you are not using the allocation status or other aspects of the value of the dummy argument at all in the subroutine then intent(out) may be appropriate (if allocated beforehand the dummy argument will be automatically deallocated when the procedure is called), otherwise intent(inout) or no intent.
(Your second block of example code has a syntax error with the deallocate statement - you should simply specify the xyzArray variable, leave off the (myshape) shape specification))
For example, in a module:
subroutine update(xyzArray)
type(xyz), allocatable, intent(inout) :: xyzArray(:)
...
if (allocated(xyzArray)) deallocate(xyzArray)
allocate(xyzArray(newshape))
...
If you are sure, you want to deallocate the array in your subroutine, you can declare the dummy argument being intent(out), so that it is deallocated automatically when the subroutine is entered:
module whatever
implicit none
type :: xyz
:
end type xyz
contains
subroutine update(xyzArray)
type(xyz), allocatable, intent(out) :: xyzArray(:)
:
allocate(xyzArray(someshape))
:
end subroutine update
end module whatever
As already noted by IanH, the process must have an explicit interface (e.g. being enclosed in a module) and in the caller program you must declare the actual argument allocatable:
program test
use whatever
implicit none
type(xyz), allocatable :: array(:)
:
call update(array)
:
end program test
Let me just preface this by saying that I am very new to Fortran but familiar with Python. My research project however requires me to use some pre-written Fortran code, which at this moment wont compile on my pc. I am trying to understand why.
The actual code I am trying to compile is very long and probably not very illuminating, but I think I have managed to come up with a minimal example of where I think the issue is. Let's say I have a very simple module and subroutine as follows,
module arraycheck
implicit none
real*8, allocatable, dimension(:) :: x
contains
subroutine fillx
real*8, allocatable, dimension(:) :: x
allocate(x(5))
x(1) = 1
x(2) = 2
x(3) = 3
x(4) = 4
x(5) = 5
print*, x
end subroutine fillx
end module arraycheck
which I expect to simply create an array x, which when the subroutine fillx is called fills the array with the integers 1 to 5. My actual source contains something conceptually similar to this. Now I also have a main program as follows,
program main
use arraycheck
print*, x
call fillx
print*,x
end
My idea here would be that on the first print statement the variable x is still unallocated, so print returns nothing, and then on the second print statement x has been filled, so it should return the filled array.
However on both print statements nothing is returned. Now in my original source code something similar happens, which causes runtime to throw an error that an unallocated array was passed somewhere as an actual argument, which should have been allocated. It seems like the exact same thing happens as in my small example here.
So my question is, is the behaviour that I observe in my example here expected? And if it is, how can I alter the code to make it work in the way that I would want it to? If I know this I might better understand why the actual source doesn't work.
Just in case it is relevant, I am using gfortran on ubuntu.
Thanks!
You have too different xs. They do not have anything in common. One a module array and one array local to the subroutine. When you allocate the local array in the subroutine, it does not do anything to the other array in the module.
Also, you cannot print array that is not allocated. That is not standard conforming (undefined behaviour). Anything can happen. You should definitely enable all compiler checks when diagnosing problems. The compiler should complain about your code with those checks.
Remove the local array declaration and avoid referencing unallocated variables. Module procedures have access to module variables through host association.
module arraycheck
implicit none
real*8, allocatable, dimension(:) :: x
contains
subroutine fillx
allocate(x(5))
x(1) = 1
x(2) = 2
x(3) = 3
x(4) = 4
x(5) = 5
print*, x
end subroutine fillx
end module arraycheck
program main
use arraycheck
call fillx
print*,x
end
Also, real*8 is not standard Fortran, it is a non-standard extension. Fortran 90 and later uses the kind system instead.
Here are some other things which might be helpful - shown in UPPERCASE.
module arraycheck
USE ISO_C_BINDING, ONLY : C_Int32_t, C_DOUBLE
implicit none
PRIVATE
real(KIND=C_DOUBLE), allocatable, dimension(:), PUBLIC :: x
PUBLIC Creation_X, Destruction_X, FillX
contains
subroutine Creation_X(n)
USE ISO_C_BINDING, ONLY : C_Int32_t
IMPLICIT NONE
INTEGER(KIND=C_Int32_t), INTENT(IN) :: n
allocate(x(n))
RETURN
end subroutine Creation_X
subroutine Destruction_X
USE ISO_C_BINDING, ONLY : C_Int32_t
IMPLICIT NONE
IF(ALLOCATED(X)) DEALLOCATE(X)
RETURN
end subroutine Destruction_X
subroutine fillx
USE ISO_C_BINDING, ONLY : C_Int32_t
IMPLICIT NONE
INTEGER(KIND=C_Int32_t) :: N
DO I= 1, SIZE(x)
x(I) = I
ENDDO
RETURN
end subroutine fillx
end module arraycheck
program main
use arraycheck
CALL Creation_X(5)
call fillx
print*,x
CALL Destruction_X
end
I'm learning the basics of Fortran. I created a simple subroutine initializing a matrix:
program test
integer, parameter :: n = 1024
real :: a(n, n)
call init(a)
write (*, *) a(1, 1)
end program
subroutine init(a)
real :: a(n, n)
a(:, :) = 3.0
end subroutine
Then the output is 0.0 instead of expected 3.0. Apart from that, valgrind says that:
==7006== Conditional jump or move depends on uninitialised value(s)
==7006== at 0x400754: init_ (in /home/marcin/proj/mimuw/fortran/test)
==7006== by 0x4007A4: MAIN__ (in /home/marcin/proj/mimuw/fortran/test)
==7006== by 0x40083B: main (in /home/marcin/proj/mimuw/fortran/test)
Why? The n parameter is correctly recognized by the compiler and should be a global one.
I compiled the program with gfortran 6.3.1
n is not a global variable, it is a local variable of the main program.
The subroutine is a completely independent compilation unit from the main program and they do not share any information.
A subroutine can "see" other variables of the parent module, if it is a module procedure, or variables of a parent (host) procedure or program if it is an internal procedure.
Be sure to read about the structure of Fortran programs and use modules as much as possible. Prefer modules over internal procedures. You will see how to put the subroutine into a module or how to make it internal to the main program in the link.
I did not mention common blocks, just don't use them, they are obsolete. And rember to use implicit none in every compilation unit.
Assuming that you want it everywhere, then one uses a COMMON block in the f77 era, and a MODULE now.
I CAPITALISED most of the changes. And if there is no error gives a few ways to consider understanding N in the SUBROUTINE, and an ELEMENTAL FUNCTION would likely be worthwhile to try here too.
MODULE MyMODULE
integer, parameter :: n = 1024
END MODULE MyMODULE
!%%%%%%%%%%
program test
USE MyModule
IMPLICIT NONE
! done up in ˆmoduleˆ...! integer, parameter :: n = 1024
REAL, DIMENSION(n,n) :: A
CALL Alternative_Init(A, 3.3)
WRITE (*,*) a(1, 1)
CALL Alternative2_Init(A, n, 1.23)
WRITE (*,*) a(1, 1)
call init(a)
write (*, *) a(1, 1)
END PROGRAM TEST
!%%%%%%%%%%
subroutine init(a)
USE MyModule
IMPLICIT NONE
real :: a(n, n)
a(:, :) = 3.0
RETURN
END SUBROUTINE init
!%%%%%%%%%%
SUBROUTINE Alternative_Init(a, Val4A)
USE MyModule
IMPLICIT NONE
REAL, DIMENSION(:,:) , INTENT(INOUT) :: a
REAL , INTENT(IN ) :: Val4A
a(:, :) = Val4A
! or just... A = Val4A ! which does them all too.
RETURN
END SUBROUTINE Alternative_Init
!%%%%%%%%%%
SUBROUTINE Alternative2_Init(a, n, Val4A)
!!!! USE MyModule
IMPLICIT NONE
INTEGER , INTENT(IN ) :: n
REAL, DIMENSION(n,n) , INTENT( OUT) :: a
REAL , INTENT(IN ) :: Val4A
A = Val4A
RETURN
END SUBROUTINE Alternative2_Init
I'm new to Fortran (more experienced in C), and am trying to allocate memory for a matrix of values using the allocate command. The code is:
module SMS
contains
subroutine readSMS(elem)
real, dimension(:,:), allocatable :: elem
allocate( elem(3792, 3) ) ! this will be a variable later on, for now I've
! hard-coded the number of elements in my test case
end subroutine
end module
When running, the code always crashes on the allocate line, with the error: Program exception - access violation. This program, however, works fine if elem is a local variable as opposed to one passed in to the subroutine. In C, I would use something like:
double **elem;
readSMS(&elem); //pass in a pointer to elem so that memory can be allocated
Is there a similar method in Fortran that I can use to allocate memory in a subroutine?
Here is the call to the function:
program main
use SMS
implicit none
include 'mpif.h'
! Variables
integer ierr,num_procs,my_id
integer num_elem,num_regions
real, dimension(:,:), allocatable :: elem
real, dimension(:,:), allocatable :: regions
! Body of main
call MPI_INIT(ierr)
call MPI_COMM_RANK(MPI_COMM_WORLD,my_id,ierr)
call MPI_COMM_SIZE(MPI_COMM_WORLD,num_procs,ierr)
call readSMS(elem)
deallocate(elem)
call MPI_FINALIZE(ierr)
end program main
At the moment, this is the entirety of the program (as you can see, I'm just getting started).
#francescalus I think the subroutine readSMS is in the module, so the explicit interface is not the problem. #wolfPack88 look at the link provided by #Jonathan and you will be able to figure out the solution.
update:
module SMS
contains
subroutine readSMS(elem)
real, dimension(:,:), allocatable :: elem
allocate( elem(10, 3) )
elem=10
end subroutine
end module
program main
use SMS
implicit none
real, dimension(:,:), allocatable :: elem
call readSMS(elem)
print *, elem
deallocate(elem)
end program main
This code works in ifort without any issue...
I seem to have hit a wall while coding these past few days. from what i can gather, it is possible to make arrays of arrays in fortran ala Fortran array of variable size arrays
type par
.... !data
integer :: location
end type par
type locations
....! data
type (par), allocatable, dimension(:) :: pars
end type locations
type (par), allocatable, dimension(:) :: all_pars
type (locations), allocatable, dimension(:) :: all_loc
.... !read numpars, numlocs from file etc
allocate(all_pars(numpars))
allocate(all_locs(numlocs))
!initialize all_pars
do n = 1:numpars
....
all_pars(n)%location = some_location
enddo
!get particles in each location
do n = 1:numlocs
allocate(all_locs(n)%pars(count(all_pars(:)%location .ne. n)))
all_locs(n)%pars = pack(all_pars, (all_pars(:)%location .ne. n)) !ERROR: An assignment of different structure types is invalid.
enddo
the compiler does not complain with my equivalent lines of code for the stack overflow example above, but it indeed does have an issue when i attempt to use that array to store the result of a pack function call. i suspect that it may be the case that the allocate function is not behaving as expected, but since the code does not compile, i cannot debug it....
the squirrely idea for pack usage comes from http://flibs.sourceforge.net/fortran_aspects.html , about halfway down the page.
I am running on a linux system, with ifort 12.1.3.293
any help is much appreciated
This may be an extended comment rather than an answer ...
to get it to compile I modified your posted code to;
program main
implicit none
integer :: numpars, numlocs, n
type par
!data
integer :: location
end type par
type locations
! data
type (par), allocatable, dimension(:) :: pars
end type locations
type (par), allocatable, dimension(:) :: all_pars
type (locations), allocatable, dimension(:) :: all_locs
!read numpars, numlocs from file etc
numpars = 10
numlocs = 4
allocate(all_pars(numpars))
allocate(all_locs(numlocs))
!initialize all_pars
all_pars(1:numpars:4)%location = 1
all_pars(2:numpars:4)%location = 2
all_pars(3:numpars:4)%location = 3
all_pars(4:numpars:4)%location = 4
!get particles in each location
do n = 1,numlocs
! allocate(all_locs(n)%pars(count(all_pars(:)%location .ne. n)))
all_locs(n)%pars = pack(all_pars, (all_pars(:)%location .ne. n))
enddo
end program
and it compiles without a hitch on my Mac with Intel Fortran 13.something. Of course, since you've only posted a syntactically-slightly-incorrect part of your code I can't be sure that this tells you very much.
Since you don't show that your code uses implicit none your error might be down to the difference between all_loc and all_locs or some other similar issue.
Note, in passing, that with Fortran allocatable arrays you don't need to allocate all_locs(n)%pars prior to setting its value with the call to pack, the compiler will take care of that for you. This, though, is not the source of your error.