# Fortran90-How to allocate an array dimension

• Fortran

## Main Question or Discussion Point

Hi,
I have a problem with a code I'm working with. I'm a student in physics and I'm writing a code in Fortran 90 that should calculate the Polonium's half-life time.
I have no data to work with so I generated them with the library random number and here is the problem, I have a 300 lines code with something like 5 subroutine but one of them is the one that is generating the data with which I'll work with and it is the one creating several segmentation faults.
What I'd like to do, and I hope someone of you could help me, is to define an allocatable array, in which generate n times random numbers of which just r will satisfied some given conditions. So the fact is that i'm trying to allocate the array dimension after having create some of his component.
Being more specific I'll write just the piece of code that generate those number because it is the same as the subroutine and is much shorter than the whole code.

Fortran:
program polly

implicit none

REAL::dx,l,p,q,z,m
INTEGER::i,n,r
REAL,DIMENSION(:),allocatable::x,y

n=100

dx=0.05

l=3.0

p=10.0
q=10.0

r=0

!allocate (x(n),y(n))

do i=1,n

call random_number(x)

call random_number(y)

m=y(i)*q
z=x(i)*p

if ((exp(-l*(z+dx))) <= log(m) .AND. log(m) <= (exp(-l*(z-dx)))) then

write(unit=1,fmt=*), x,y

r=r+1

else

x=0
y=0

END IF

print*,"r",r,"x",x,"y",y

end program polly
So here the value of r after the do cycle should be the times which the condition is satisfied so it is the dimension I wish x and y had.
I tried multiple times and multiple ways, even setting the dimension as n and giving the value 0 to all the n-r "holes" in the array. Then in the whole program I have those other subroutine that are based on the same x and y that are intent in, which are the two arrays that I calculate in the subroutine above. Moreover these subroutines calculate several mean value that need to be divided by the real number of component and not the whole n. Furthermore, I don't know where the accepted point will be in the array so that it is not sufficient to just allocate the vectors but I need also a procedures to select only the acceptable points ignoring all the others.
I don't know if I made it clear to you or not, I tried. I hope you can help.
Thanks anyway.

Related Programming and Computer Science News on Phys.org
Mark44
Mentor
Hi,
I have a problem with a code I'm working with. I'm a student in physics and I'm writing a code in Fortran 90 that should calculate the Polonium's half-life time.
I have no data to work with so I generated them with the library random number and here is the problem, I have a 300 lines code with something like 5 subroutine but one of them is the one that is generating the data with which I'll work with and it is the one creating several segmentation faults.
What I'd like to do, and I hope someone of you could help me, is to define an allocatable array, in which generate n times random numbers of which just r will satisfied some given conditions. So the fact is that i'm trying to allocate the array dimension after having create some of his component.
Being more specific I'll write just the piece of code that generate those number because it is the same as the subroutine and is much shorter than the whole code.

Fortran:
program polly

implicit none

REAL::dx,l,p,q,z,m
INTEGER::i,n,r
REAL,DIMENSION(:),allocatable::x,y

n=100

dx=0.05

l=3.0

p=10.0
q=10.0

r=0

!allocate (x(n),y(n))

do i=1,n

call random_number(x)

call random_number(y)

m=y(i)*q
z=x(i)*p

if ((exp(-l*(z+dx))) <= log(m) .AND. log(m) <= (exp(-l*(z-dx)))) then

write(unit=1,fmt=*), x,y

r=r+1

else

x=0
y=0

END IF

print*,"r",r,"x",x,"y",y

end program polly
So here the value of r after the do cycle should be the times which the condition is satisfied so it is the dimension I wish x and y had.
I tried multiple times and multiple ways, even setting the dimension as n and giving the value 0 to all the n-r "holes" in the array. Then in the whole program I have those other subroutine that are based on the same x and y that are intent in, which are the two arrays that I calculate in the subroutine above. Moreover these subroutines calculate several mean value that need to be divided by the real number of component and not the whole n. Furthermore, I don't know where the accepted point will be in the array so that it is not sufficient to just allocate the vectors but I need also a procedures to select only the acceptable points ignoring all the others.
I don't know if I made it clear to you or not, I tried. I hope you can help.
Thanks anyway.
You can't do this:
Code:
!allocate (x(n),y(n))
You need a separate allcocate statement for each array, as in this example.
Code:
allocate (x(n))
allocate (y(n))
Also, your calls to random_number() don't look right. I think they should be like so, I believe (based on the fact that you have them inside a do loop):
Code:
do i=1,n
call random_number(x(i))
call random_number(y(i))

m=y(i)*q
z=x(i)*p

if ((exp(-l*(z+dx))) <= log(m) .AND. log(m) <= (exp(-l*(z-dx)))) then

write(unit=1,fmt=*), x(i), y(i)
In addition, you are missing the end do for your do loop. There might be other errors...

Aner
You can't do this:
Code:
!allocate (x(n),y(n))
You need a separate allcocate statement for each array, as in this example.
Code:
allocate (x(n))
allocate (y(n))
Also, your calls to random_number() don't look right. I think they should be like so, I believe (based on the fact that you have them inside a do loop):
Code:
do i=1,n
call random_number(x(i))
call random_number(y(i))

m=y(i)*q
z=x(i)*p

if ((exp(-l*(z+dx))) <= log(m) .AND. log(m) <= (exp(-l*(z-dx)))) then

write(unit=1,fmt=*), x(i), y(i)
In addition, you are missing the end do for your do loop. There might be other errors...
Thanks a lot, the end do is missing in the code I pasted because I deleted some comments that were written in Italian and were not useful for the problem. Anyway I modified the other things you said and it ends up calculating the array but the problem is that in order to have some interesting point I need to run the do cycle at least 1000 times and it gives me r=4 and it wrote me the 4 components for x and y (with the command print* in the do cycles), but at the end of the programs, the other print command should write the whole vectors and it just give me two vectors, x and y with n zero inside.
if I find something I'll write again.

Mark44
Mentor
but at the end of the programs, the other print command should write the whole vectors and it just give me two vectors, x and y with n zero inside.
I'm not sure what you're saying here. Possibly what you're seeing is due to this code:
Code:
else
x=0
y=0
END IF
Since that code is in your do loop, it should probably look like this:
Code:
else
x(i) = 0
y(i) = 0
end if
I believe that your intent is to set just specific elements of your arrays to zero, not all of the elements.

Aner
I'm not sure what you're saying here. Possibly what you're seeing is due to this code:
Code:
else
x=0
y=0
END IF
Since that code is in your do loop, it should probably look like this:
Code:
else
x(i) = 0
y(i) = 0
end if
I believe that your intent is to set just specific elements of your arrays to zero, not all of the elements.
Thank you so much, those were pretty dummy errors but you helped me find the way to make it works!I've even found out how to solve the initial problem of the array, I've left the dimension n and create an if cycle in order to avoid the 0 components.
Thank you very much!

Actually, it is possible to allocate more than one array in a single call...for as long as the statement is not commented out ;-)

Also, it is possible populate an entire array with a single call to random_number...this function is smart enough to do that...this means that you would need to make those calls BEFORE entering the do loop.

In all, you need to approach this a bit differently so that at the end you do get as many random numbers as desired... basically, you allocate you arrays to the desire length..then, instead of a do loop with finite range, you use a while loop to get a couple of random numbers (no directly array entries but two other auxiliary variables), you test those number if they meet the condition you assign them to the arrays and increase your counter, if the counter reaches a given value, you exit the while loop; otherwise, you repeat the loop.

Aner
Actually, it is possible to allocate more than one array in a single call...for as long as the statement is not commented out ;-)

Also, it is possible populate an entire array with a single call to random_number...this function is smart enough to do that...this means that you would need to make those calls BEFORE entering the do loop.

In all, you need to approach this a bit differently so that at the end you do get as many random numbers as desired... basically, you allocate you arrays to the desire length..then, instead of a do loop with finite range, you use a while loop to get a couple of random numbers (no directly array entries but two other auxiliary variables), you test those number if they meet the condition you assign them to the arrays and increase your counter, if the counter reaches a given value, you exit the while loop; otherwise, you repeat the loop.
Thank you so much, that's a really interesting thing to know, I forgot about the while loop, but surely it would have helped a lot (maybe my now 400 plus lines codes would be shorter). I'll surely try that!

Fortran:
program polly
implicit none
integer::n,r
real::dx,l,p,q,z,m,a,b
real,dimension(:),allocatable::x,y
dx = 0.05 ; l = 3.0 ; p = 10.0 ; q = 10.0
n = 100
allocate (x(n),y(n))

r = 0
do
call random_number(a) ; z = a*p
call random_number(b) ; m = b*q
if ( (exp(-l*(z+dx))) <= log(m) .AND. log(m) <= (exp(-l*(z-dx)))) then
r = r + 1
x(r) = a
y(r) = b
if (r == n) exit
end if
end do
write(*,'(i3, 2x, f5.2, 2x, f5.2)') (r, x(r), y(r), r = 1, n)
end program polly

Aner
Fortran:
program polly
implicit none
integer::n,r
real::dx,l,p,q,z,m,a,b
real,dimension(:),allocatable::x,y
dx = 0.05 ; l = 3.0 ; p = 10.0 ; q = 10.0
n = 100
allocate (x(n),y(n))

r = 0
do
call random_number(a) ; z = a*p
call random_number(b) ; m = b*q
if ( (exp(-l*(z+dx))) <= log(m) .AND. log(m) <= (exp(-l*(z-dx)))) then
r = r + 1
x(r) = a
y(r) = b
if (r == n) exit
end if
end do
write(*,'(i3, 2x, f5.2, 2x, f5.2)') (r, x(r), y(r), r = 1, n)
end program polly

It's fantastic! Thank you so much! It made my program better and even the result are more precise!I ended up deleting something like 100 lines with your help! Now my program is working perfectly and without all the if cycles that were necessary before! A really big thanks to you!