I'm learning Fortran with the book Fortran 90 for scientists and engineers by Brian Hahn. In chapter 9 about arrays, pages 131/132, he gives the following code as an example of dynamic arrays
Program Chap_9_Allocatable_Array
Implicit none
! Variables
Real, dimension(:), Allocatable :: X, OldX
Real A
Integer IO, N, i
! Body of Chap_9_Allocatable_Array
Allocate( X(0) ) !Size zero to sart with?
N = 0
Open(1, File = 'Data.txt')
Do
Read(1, *, IOStat = IO) A
If (IO < 0) Exit
N = N + 1
Allocate( OldX( Size(X) ) )
OldX = X !Entire array can be assigned
Deallocate( X )
Allocate( X(N) )
X = OldX
X(N) = A
Deallocate( OldX )
End do
Print *, (X(i), i = 1, N)
End program Chap_9_Allocatable_Array
I have implemented this program in Visual Studio Community 2019 with the Intel Visual Fortran Compiler. The purpose of this program as he explains is
The following program extract shows how to use allocatable arrays, as these beasts are called, to read an unknown amount of data, which unfortunately must be supplied one item per line because of the way READ works.
I found an interesting error. The file data.txt consists of 100 random numbers, 1 per row. When I try to run it, it just seems to stall for a couple of seconds and then the console simply prints the
Press any key to continue.
prompt, without an error message. I have inserted some debug prints and determined that the program runs the do cycle between 3 to 8 times before stopping. I have not been able to determine the reason. If I then change the data.txt file to only be 3 numbers long, the program runs as intended. With the debug prints, I have pinned the error to being the
Deallocate( X )
line. If I debug the program in Visual Studio I just get the following message:
Chap_9_Allocatable_Array.exe has triggered a breakpoint.
There have been a few minor errors in the book. Just in this example, the author seems to have forgotten to declare i, which caused a compile error. However, as I'm only beggining to understand arrays, I don't know what else to try. Any ideas?
Related
I am trying to call a subroutine in a loop. This subroutine has a local coarray. Following is the code that I am using:
! Test local coarray in procedure called in a loop.
!
program main
use, intrinsic :: iso_fortran_env, only : input_unit, output_unit, error_unit
implicit none
! Variable declaration.
integer :: me, ti
integer :: GHOST_WIDTH, TSTART, TSTEPS
sync all
! Initialize.
GHOST_WIDTH = 1
TSTART = 0
TSTEPS = 100000
me = this_image()
! Iterate.
do ti = TSTART + 1, TSTART + TSTEPS
call Aldeal( GHOST_WIDTH )
if ( me == 1 ) write( output_unit, * ) ti
end do
if ( me == 1 ) write( output_unit, * ) "All done!"
contains
subroutine Aldeal( width )
integer, intent(in) :: width
integer, allocatable, codimension[:] :: shell1_Co, shell2_Co, shell3_Co
allocate( shell1_Co[*], shell2_Co[*], shell3_Co[*] )
deallocate( shell1_Co, shell2_Co, shell3_Co )
return
end subroutine Aldeal
end program main
Right now the subroutine is not doing anything other than allocating the local coarray and deallocating it. But even while doing this, the program is throwing me the following error after some iterations:
forrtl: severe (174): SIGSEGV, segmentation fault occurred
In coarray image 1
Image PC Routine Line Source
coarray_main 0000000000406063 Unknown Unknown Unknown
libpthread-2.17.s 00007F21D8B845F0 Unknown Unknown Unknown
libicaf.so 00007F21D90970D5 for_rtl_ICAF_CO_D Unknown Unknown
coarray_main 0000000000405054 main_IP_aldeal_ 37 coarray_main.f90
coarray_main 0000000000404AEC MAIN__ 23 coarray_main.f90
coarray_main 0000000000404A22 Unknown Unknown Unknown
libc-2.17.so 00007F21D85C5505 __libc_start_main Unknown Unknown
coarray_main 0000000000404929 Unknown Unknown Unknown
Abort(0) on node 0 (rank 0 in comm 496): application called MPI_Abort(comm=0x84000003, 0) - process 0
And the same error is repeated for other images as well.
Line 23 is call Aldeal( GHOST_WIDTH ) inside the do loop of the main program. And line 37 corresponds to deallocate( shell1_Co, shell2_Co, shell3_Co ) statement in the subroutine.
Additionally, if I remove the deallocate statement from the subroutine, it throws the same error but the line number in the error statement this time are 23 and 39. Line 39 corresponds to the end subroutine Aldeal statement.
I am not able to understand what exactly I am doing wrong. Please help.
P.S. I am using Centos 7 with Intel(R) Parallel Studio XE 2019 Update 4 for Linux.
Observations:
If I modify the code to have a derived-type with an allocatable component and use that to create the coarray in the subroutine, the code runs a little longer but eventually aborts with an error. Following is the modification:
module mod_coarray_error
implicit none
type :: int_t
integer, allocatable, dimension(:) :: var
end type int_t
contains
subroutine Aldeal_type( width )
integer, intent(in) :: width
type(int_t), allocatable, codimension[:] :: int_t_Co
allocate( int_t_Co[*] )
allocate( int_t_Co%var(width) )
sync all
! deallocate( int_t_Co%var )
deallocate( int_t_Co )
return
end subroutine Aldeal_type
end module mod_coarray_error
program main
use, intrinsic :: iso_fortran_env, only : input_unit, output_unit, error_unit
use :: mod_coarray_error
implicit none
! Variable declaration.
integer :: me, ti
integer :: GHOST_WIDTH, TSTART, TSTEPS, SAVET
sync all
! Initialize.
GHOST_WIDTH = 3
TSTART = 0
TSTEPS = 100000
SAVET = 1000
me = this_image()
! Iterate.
do ti = TSTART + 1, TSTART + TSTEPS
sync all
call Aldeal_type( GHOST_WIDTH )
if ( mod( ti, SAVET ) == 0 ) then
if ( me == 1 ) write( output_unit, * ) ti
end if
end do
sync all
if ( me == 1 ) write( output_unit, * ) "All done!"
end program main
Additionally, this code runs fine till the end when compiled in Windows.
Now if I add the compiler option heap-arrays 0, the code seems to run till the end even in Linux.
I tried to increase the number of loops, ie, TSTEPS in the code to 1e7. Even then, it runs successfully till the end. But I observe the following effects:
Code gets slower as loop count increases, ie, it takes more time to run from ti = 1e6 to ti = 2e6 than the time it takes to run from ti = 1 to ti = 1e6.
Memory used by the program keeps on increasing, ie, each image which consumes 2GB at start of the program run, consumes 3.5GB at ti = 2e6, 4.7GB at ti = 4e6, and 6GB at ti = 6e6.
Memory used by the program is relatively less when run in Windows, but it still keeps on increasing as the loop count increases. Eg each image which consumes 100MB at start, consumes 1.5GB at ti = 2e6, 2.5GB at ti = 4e6, and 3.5GB at ti = 6e6.
Using the compiler option /heap-arrays0 in Windows has no effect either on the run (as it was already successfully running without it) or on the amount of memory consumed while running.
The original code posted in the question still throws an error even when compiled using the above compiler option. It does not seem to run in Windows too.
Ultimately, I am still confused as to what is happening.
P.S. I posted the question in Intel forum but have not received any response yet.
I am using a computational fluid dynamics software that is compiled with gfortran version 4.8.5 on Ubuntu 16.04 LTS. The software can be compiled with either single precision or double precision and the -O3 optimization option. As I do not have the necessary computational resources to run the CFD software on double precision I am compiling it with single precision and the following options
ffpe-trap=invalid,zero,overflow
I am getting a SIGFPE error on a line of code that contains the asin function-
INTEGER, PARAMETER :: sp = SELECTED_REAL_KIND( 6, 37) !< single precision
INTEGER, PARAMETER :: wp = sp
REAL(KIND=wp) zsm(:,:)
ela(i,j) = ASIN(zsm(ip,jp))
In other words the inverse sin function and this code is part of a doubly nested FOR loop with jp and ip as the indices. Currently the software staff is unable to help me for various other reasons and so I am trying to debug this on my own. The SIGFPE error is only being observed in the single precision compilation not double precision compilation.
I have inserted the following print statements in my code prior to the line of code that is failing i.e. the asin function call. Would this help me with unraveling the problem that I am facing ? This piece of code is executed for every time step and it is occurring after a series of time steps. Alternatively what other steps can I do to help me fix this problem ? Would adding "precision" to the compiler flag help ?
if (zsm(ip,jp) >= 1.0 .or. zsm(ip,jp) <= -1.0) then
print *,zsm(ip,jp),ip,jp
end if
EDIT
I took a look at this answer Unexpected behavior of asin in R and I am wondering whether I could do something similar in fortran i.e. by using the max function. If it goes below -1 or greater than 1 then round it off in the proper manner. How can I do it with gfortran using the max function ?
On my desktop the following program executes with no problems(i.e. it has the ability to handle signed zeros properly) and so I am guessing the SIGFPE error occurs with either the argument greater than 1 or less than -1.
program testa
real a,x
x = -0.0000
a = asin(x)
print *,a
end program testa
We have min and max functions in Fortran, so I think we can use the same method as in the linked page, i.e., asin( max(-1.0,min(1.0,x) ). I have tried the following test with gfortran-4.8 & 7.1:
program main
implicit none
integer, parameter :: sp = selected_real_kind( 6, 37 )
integer, parameter :: wp = sp
! integer, parameter :: wp = kind( 0.0 )
! integer, parameter :: wp = kind( 0.0d0 )
real(wp) :: x, a
print *, "Input x"
read(*,*) x
print *, "x =", x
print *, "equal to 1 ? :", x == 1.0_wp
print *, asin( x )
print *, asin( max( -1.0_wp, min( 1.0_wp, x ) ) )
end
which gives with wp = sp (or wp = kind(0.0) on my computer)
$ ./a.out
Input x
1.00000001
x = 1.00000000
equal to 1 ? : T
1.57079625 (<- 1.5707964 for gfortran-4.8)
1.57079625
$ ./a.out
Input x
1.0000001
x = 1.00000012
equal to 1 ? : F
NaN
1.57079625
and with wp = kind(0.0d0)
$ ./a.out
Input x
1.0000000000000001
x = 1.0000000000000000
equal to 1 ? : T
1.5707963267948966
1.5707963267948966
$ ./a.out
Input x
1.000000000000001
x = 1.0000000000000011
equal to 1 ? : F
NaN
1.5707963267948966
If it is necessary to modify a lot of asin(x) and the program relies on a C or Fortran preprocessor, it may be convenient to define some macro like
#define clamp(x) max(-1.0_wp,min(1.0_wp,x))
and use it as asin( clamp(x) ). If we want to remove such a modification, we can simply change the definition of clamp() as #define clamp(x) (x). Another approach may be to define some asin2(x) function that limits x to [-1,1] and replace the built-in asin by asin2 (either as a macro or a Fortran function).
There are several threads with similar titles of mine, but I do not believe they are the same. One was very similar fortran pass allocated array to main procedure, but the answer required Fortran 2008. I am after a Fortran 90/95 solution.
Another very good, and quite similar thread is Dynamic array allocation in fortran90. However in this method while they allocate in the subroutine, they don't ever appear to deallocate, which seems odd. My method looks on the surface at least to be the same, yet when I print the array in the main program, only blank spaces are printed. When I print in the subroutine itself, the array prints to screen the correct values, and the correct number of values.
In the following a MAIN program calls a subroutine. This subroutine reads data into an allocatable array, and passes the array back to the main program. I do this by using small subroutines each designed to look for specific terms in the input file. All of these subroutines are in one module file. So there are three files: Main.f90, input_read.f90 and filename.inp.
It seems then that I do not know how to pass an array that is allocatable in program Main.f90 as well as in the called subroutine where it is actually allocated, sized, and then deallocated before being passed to program Main. This perhaps sounds confusing, so here is the code for all three programs. I apologize for the poor formatting when I pasted it. I tried to separate all the rows.
main.f90:
Program main
use input_read ! the module with the subroutines used for reading filename.inp
implicit none
REAL, Allocatable :: epsilstar(:)
INTEGER :: natoms
call Obtain_LJ_Epsilon(epsilstar, natoms)
print*, 'LJ Epsilon : ', epsilstar
END Program main
Next is the module with a subroutine (I removed all but the necessary one for space), input_read.f90:
module input_read
contains
!===============================================================
!===============================================================
Subroutine Obtain_LJ_Epsilon(epsilstar,natoms)
! Reads epsilon and sigma parameters for Lennard-Jones Force-Field and also
! counts the number of types of atoms in the system
!===============================================================
!===============================================================
INTEGER :: error,line_number,natoms_eps,i
CHARACTER(120) :: string, next_line, next_next_line,dummy_char
CHARACTER(8) :: dummy_na,dummy_eps
INTEGER,intent(out) :: natoms
LOGICAL :: Proceed
real, intent(out), allocatable :: epsilstar(:)
error = 0
line_number = 0
Proceed = .true.
open(10,file='filename.inp',status='old')
!=============================================
! Find key word LJ_Epsilon
!=============================================
DO
line_number = line_number + 1
Read(10,'(A120)',iostat=error) string
IF (error .NE. 0) THEN
print*, "Error, stopping read input due to an error reading line"
exit
END IF
IF (string(1:12) == '$ LJ_epsilon') THEN
line_number = line_number + 1
exit
ELSE IF (string(1:3) == 'END' .or. line_number > 2000) THEN
print*, "Hit end of file before reading '$ LJ_epsilon' "
Proceed = .false.
exit
ENDIF
ENDDO
!========================================================
! Key word found, now determine number of parameters
! needing to be read
!========================================================
natoms_eps = -1
dummy_eps = 'iii'
do while ((dummy_eps(1:1) .ne. '$') .and. (dummy_eps(1:1) .ne. ' '))
natoms_eps = natoms_eps + 1
read(10,*) dummy_eps
enddo !we now know the number of atoms in the system (# of parameters)
close(10)
Allocate(epsilstar(natoms_eps))
epsilstar = 0.0
!============================================================
! Number of parameters found, now read their values
!============================================================
if(Proceed) then
open(11,file='filename.inp',status='old')
do i = 1,line_number-1
read(11,*) ! note it is not recording anything for this do loop
enddo
do i = 1,natoms_eps
read(11,*) dummy_char
read(dummy_char,*) epsilstar(i) ! convert string read in to real, and store in epsilstar
enddo
close(11)
PRINT*, 'LJ_epsilon: ', epsilstar ! printing to make sure it worked
endif
deallocate(epsilstar)
END Subroutine Obtain_LJ_Epsilon
end module input_read
And finally the input file: filename.inp
# Run_Type
NVT
# Run_Name
Test_Name
# Pressure
1.0
# Temperature
298.15
# Number_Species
# LJ_epsilon
117.1
117.1
117.1
# LJ_sigma
3.251
3.251
3.251
END
And again, I can't figure out how to pass the allocated epsilstar array to the main program. I have tried passing an unallocated array to the subroutine from the main.f90, allocating it inside, passing it back, and deallocating it in the main.f90, but that did not work. I have tried it as the code currently is... the code works (i.e. is bug free) but it does not pass epsilstar from the subroutine where it correctly finds it and creates an array.
It turns out that the mistake I made was in deallocating the array in the subroutine before passing it to the main program. By NOT deallocating, the array was sent back fine. Also, I do not deallocate in the main program either.
I am currently writing a code to simulate particle collisions. I am trying to open as much files as there are particles (N) and then put the data for positions and velocities in each of these files for each step of the time integration (using Euler's method, but that is not relevant). For that, I tried using a do loop so it will open all the files I need - then I put all the data in them with a different do loop later - and then close them all.
I first tried just doing a do loop to open the files - but it gave errors of the type "file already open in another unit", so I did the following:
module parameters
implicit none
character :: posvel
integer :: i, j, N
real :: tmax
real, parameter :: tmin=0.0, pi=3.14159265, k=500.0*10E3, dt=10.0E-5, dx=10.0E-3, g=9.806, ro=1.5*10E3
real, dimension(:), allocatable :: xold, xnew, vold, vnew, m, F, r
end module parameters
PROGRAM Collision
use parameters
implicit none
write(*,*) 'Enter total number of particles (integer number):'
read(*,*) N
allocate(xold(N))
allocate(vold(N))
allocate(xnew(N))
allocate(vnew(N))
allocate(m(N))
allocate(F(N))
allocate(r(N))
xold(1) = 0.0
vold(1) = 0.0
m(1) = 6.283*10E-9
r(1) = 10E-4
xold(2) = 5.0
vold(2) = 0.0
m(2) = 6.283*10E-9
r(2) = 10E-4
write(*,*) 'Type total time elapsed for the simulation(real number):'
read(*,*) tmax
do i = 1, N
write(posvel,"(a,i3.3,a)") "posveldata",i,".txt"
open(unit=i,file=posvel, status="unknown")
end do
do i = 1, N
close(unit=i)
end do
END PROGRAM Collision
The last ten lines are the ones that regard to my problem.
That worked in codeblocks - it opened just the number of files I needed, but I'm actually using gfortran and it gives me and "end of record" error in the write statement.
How can I make it to execute properly and give me the N different files that I need?
P.S.: It is not a problem of compilation, but after I execute the program.
Your character string in the parameter module has only 1 character length, so it cannot contain the full file name. So please use a longer string, for example
character(100) :: posvel
Then you can open each file as
do i = 1, N
write(posvel,"(a,i0,a)") "posveldata",i,".txt"
open(unit=i,file=trim(posvel), status="unknown")
end do
Here, I have used the format i0 to automatically determine a proper width for integer, and trim() for removing unnecessary blanks in the file name (though they may not be necessary). The write statement can also be written more compactly as
write(posvel,"('posveldata',i0,'.txt')") i
by embedding character literals into the format specification.
The error message "End of record" comes from the above issue. This can be confirmed by the following code
character c
write(c,"(a)") "1"
print *, "c = ", c
write(c,"(a)") "23" !! line 8 in test.f90
print *, "c = ", c
for which gfortran gives
c = 1
At line 8 of file test.f90
Fortran runtime error: End of record
This means that while c is used as an internal file, this "file" does not have enough space to accommodate two characters (here "23"). For comparison, ifort14 gives
c = 1
forrtl: severe (66): output statement overflows record, unit -5, file Internal Formatted Write
while Oracle Fortran12 gives
c = 1
****** FORTRAN RUN-TIME SYSTEM ******
Error 1010: record too long
Location: the WRITE statement at line 8 of "test.f90"
Aborted
(It is interesting that Oracle Fortran reports the record to be "too long", which may refer to the input string.)
Hi everyone and happy new year !
I'm trying to use the fftw library in a simple fortran 90 code (yes, an old fortran...).
This is a very simple code computing the FFT of vector in=1,2,..., N. I'm surprise by the fact that, for N<20, it works. For N >= 20, it does not work anymore. I guess I missed something important but can't figure out what... And was wondering if you could help me...
I compile my code with this command
ifort test.f90 -o test -lfftw3f
And the code is the following
program test
implicit none
include "fftw3.f"
integer, parameter :: fp =4
integer*8 :: N
double complex, allocatable, dimension (:) :: in, out, aux
integer*8 :: plan
integer*8 :: i, errflag
N=10
allocate(in(N), stat=errflag)
allocate(out(N), stat=errflag)
do i=1,N
in(i) = i
end do
call sfftw_plan_dft_1d(plan, N, in, out, -1, 0)
do i=1,N
print *, in(i)
end do
print *, "================================================"
do i=1,N
print *, out(i)
end do
call sfftw_execute_dft(plan, in, out)
call sfftw_destroy_plan(plan)
deallocate(in, out)
end program test
Surpringly (for me), the vector "in" is modified after the line
call sfftw_plan_dft_1d(plan, N, in, out, -1, 0)
Indeed, the vector is "cut in half" as soon as N>20, in the sense that:
in(i) = 0 if i < N/2
in(i) = i otherwise
However, with N =10 for example, the result seems to be good (same as the one obtained with scilab fft function).
I'm kind of lost and not totally familiar with fortran. Did I missed something important ?
Thank you so much in advance !
edit : whoups, bad copy/paste in the code...
Looking around for what your flags meant, I found this here
http://www.fftw.org/fftw3_doc/Planner-Flags.html#Planner-Flags
Important: the planner overwrites the input array during planning unless a saved plan (see Wisdom) is available for that problem, so you should initialize your input data after creating the plan. The only exceptions to this are the FFTW_ESTIMATE and FFTW_WISDOM_ONLY flags, as mentioned below.
Maybe try
call sfftw_plan_dft_1d(plan, N, in, out, -1, 0)
do i=1,N
in(i) = i
end do
Or I may be misreading something completely out of contect, but I guess it's worth a try :)