read multiple netcdf files in fortran using openmp - fortran

I have two netcdf files - ocean_rst_01.nc and ocean_rst_02.nc - which I wish to read in parallel using openmp in Fortran. The code I am using is the following
implicit none
....
....
!$OMP THREADPRIVATE(ncid,varid)
write ( *, '(a,i8)' ) &
' The number of processors available = ', omp_get_num_procs ( )
write ( *, '(a,i8)' ) &
' The number of threads available = ', omp_get_max_threads ( )
filen = "ocean_rst_0x"
!$OMP PARALLEL DO PRIVATE(j,filename,varname,buf)
do i = 1, nbv
j = OMP_GET_THREAD_NUM()
print*,"i=",i, "j = ",j! OMP_GET_THREAD_NUM()
if (i<10) write(num,"(a11,i1)") filen,i
if (i>=10) write(num,"(a10,i2)") filen,i
filename(i)=trim(num)//".nc"
write(6,*) "Reading file = ",trim(filename(i))," by ", j
varname="CHLA"
call check( NF90_OPEN(trim(filename(i)),NF90_NOWRITE,ncid) )
call check( NF90_INQ_VARID(ncid,trim(varname),varid) )
start = (/1, 1, 1/)
count = (/nlon, nlat, nlev/)
call check( NF90_GET_VAR(ncid,varid,buf,start=start, &
count = count) )
call check( NF90_CLOSE(ncid))
call check( NF90_OPEN(trim(filename(i)),NF90_NOWRITE,ncid) )
call check( NF90_INQ_VARID(ncid,"zeta",varid) )
start_1 = (/1, 1/)
count_1 = (/nlon, nlat/)
call check( NF90_GET_VAR(ncid,varid,buf2d,start=start_1, &
count = count_1) )
call check( NF90_CLOSE(ncid))
var(:,:,:,i) = buf(:,:,:)
var2d(:,:,i) = buf2d(:,:)
write(6,*) "var = ",var(132,231,39,i), "read by thread = ",j
write(6,*) "zeta = ",var2d(132,231,i), "read by thread = ",j
enddo
!$OMP END PARALLEL DO
end
I am compiling the code in a CRAY machine using ftn and netcdf4 libraries.
I am getting random outputs. Sometimes I get the right output. Sometimes the output of var2d and/or var is same for both the threads. And if I declare buf2d as private, I get a segmentation fault (core dumped) error. And Sometimes I get the followong error
a.out: posixio.c:442: px_rel: Assertion `pxp->bf_offset <= offset && offset < pxp->bf_offset + (off_t) pxp->bf_extent' failed.
Aborted (core dumped)
The above algorithm works fine if I read multiple ascii files. What is the right way to read multiple netcdf files in fortran 90 using openmp ?

Unfortunately netcdf is not thread-safe currently, see for instance
https://www.unidata.ucar.edu/support/help/MailArchives/netcdf/msg13578.html
though people do seem to be thinking about making it so, for instance
https://www.unidata.ucar.edu/blogs/developer/entry/implementing-thread-safe-access-to
Thus what you want to do is unlikely to work, and if it does it may not work reliably, as the actions of one thread will "interfere" with those of another.

Related

Fortran: Reading and printing 2D array from text file

I am trying to read a 3x3 array and print it out but I am getting an end of line error:
The text file contains the following array:
1 2 3
4 5 6
7 8 9
Here is my code:
program myfile
implicit none
! Declare Variables
integer i,j
!real, dimension(1:3,1:3) :: A
integer, parameter :: M = 3, N =3
real, dimension(1:M,1:N) :: A
! Open and read data
open(unit=10, file = 'test_file_cols.txt', status = 'old')
do i =1,M
do j =1,N
read(unit=10,FMT=*) A(i,j)
print *,A(i,j)
end do
end do
end program myfile
The error I am getting is below:
1.000000
4.000000
7.000000
forrtl: severe (24): end-of-file during read, unit 10, file C:\Users\M42141\Documents\mean_flow_file\test_file_cols.txt
As discussed briefly in the comments by default all I/O in Fortran is record based. This is true for both formatted and unformatted files. What happens is the file is viewed as a set of records - and you can think of a record as a line in the file. Now these lines may be very, very long, especially in an unformatted files, but the default Fortran I/O methodology still views it as a set of lines.
Now the important thing is that by default every time you perform an I/O statement (read, write, print) the last thing it does is move from the record it is on to the next record - a write statement will write an end of record marker. This is why you automatically get a newline after a write statement, but it also means that for a read statement any remaining data in the record (on the line) will get skipped over. This is what is happening to you. The first read reads record 1, and so you get 1.0, and then moves to record 2. Your program then reads record 2 and so you get 4.0, and it automatically moves to record 3. this is then read (9.0) and the file pointer moves onto record 4. You then try to read this, but there isn't a record 4, so you get an end of file error.
Record structure is a bit strange when you first encounter it, but when you get used to it it is very powerful and convenient - I'll show an example below, and another one might be that you could leave a comment at the end of each line saying what it does, the end of the read statement will mean you move to the next record, so skipping the comment and needing to take no special action in you code to deal with such a case.
Anyway how to solve your case. Three possible ways
Read a whole record at a time - the comment suggests an implied do loop but I think in this case an array section is much easier and more intuitive
You can simply read the whole array in one go. This works because when a read statement finishes a record and finds it still "needs" more data it will carry onto the next record and keep reading. But note the end of line comment idea won't work here - can you work out why?
Non-Advancing I/O. I don't recommend this at all in this case, but for completeness this allows you to perform a read or write without moving onto the next record
There may be others, you could probably use so called stream I/O but personally I prefer record based whenever possible, I find it more convenient and powerful. Anyway here is a program illustrating the 3 methods. Note I have also changed your input file, getting the original to work with non-advancing I/O is a pain, but not the other 2 - another reason not to use it here.
ian#eris:~/work/stack$ cat readit.f90
Program readit
Implicit None
Real, Dimension( 1:3, 1:3 ) :: a
Integer :: i, j
! one line per read
Write( *, * ) 'Line at a time'
Open( 10, file = 'in' )
Do i = 1, 3
Read ( 10, * ) a( i, : )
Write( *, * ) a( i, : )
End Do
Close( 10 )
! All in one go
Write( *, * ) 'All in one go'
Open( 10, file = 'in' )
Read ( 10, * ) a
Write( *, * ) a
Close( 10 )
! Non advancing I/O
Write( *, * ) 'Non-advancing'
Open( 10, file = 'in' )
Do i = 1, 3
Do j = 1, 3
! Non advancing I/O requires a 'proper' format
Read ( 10, '( f3.1, 1x )', Advance = 'No' ) a( i, j )
Write( *, '( f3.1, 1x )', Advance = 'No' ) a( i, j )
End Do
! Move to next records (lines)
Read ( 10, * )
Write( *, * )
End Do
Close( 10 )
End Program readit
ian#eris:~/work/stack$ gfortran-8 -Wall -Wextra -pedantic -std=f2008 -fcheck=all -O readit.f90
ian#eris:~/work/stack$ cat in
1.0 2.0 3.00
4.0 5.0 6.00
7.0 8.0 9.00
ian#eris:~/work/stack$ ./a.out
Line at a time
1.00000000 2.00000000 3.00000000
4.00000000 5.00000000 6.00000000
7.00000000 8.00000000 9.00000000
All in one go
1.00000000 2.00000000 3.00000000 4.00000000 5.00000000 6.00000000 7.00000000 8.00000000 9.00000000
Non-advancing
1.0 2.0 3.0
4.0 5.0 6.0
7.0 8.0 9.0

Fortran not writing to screen while file is open

Context: I have the intention to put a certain Fortran subroutine to some tests to see what is wrong with it. It's a numerical simulation and the results are not matching with theory. I use the write statement to do some simple debugging.
The problem: While a file is open in my main routine, I can't seem to write anything to the screen (so I can't check which stuff are being incorrectly passed to a certain chain of subroutines and etc.). It writes all fine when I do it before opening the file, but not inside it (after opening and after closing it).
Here is the code I'm referring to:
WRITE(*,*) 'BLA !<---------------------------------------
WRITE(*,*) 'BLA BLA' !<---------------------------------------
do p=1,N !open files
write(posvel, "(a,i0,a)") "1Dposveldatacomelasticaxy1", p, ".dat"
OPEN(unit=p, file=trim(posvel), status="unknown")
end do
WRITE(*,*) 'bla' !<---------------------------------------
t = tmin
cont = 0
do while ((t + dt) < (tmax))
t = t+dt
cont = cont+1
do i = 1, N
forcax(i) = 0.0d0
forcay(i) = flagy(i)*gravidade(m(i))
do j = 1, N
call coefficients(m(i), m(j), gama_n, k_n)
Fx_elastica(j,i) = 0.0d0
Fy_elastica(j,i) = 0.0d0
Fx_viscosa(j,i) = 0.0d0
Fy_viscosa(j,i) = 0.0d0
WRITE(*,*) 'inside j loop' !<---------------------------------------
if (i .NE. j) then
if ( (abs(sqrt(((xold(i)-xold(j))**2)+(yold(i)-yold(j))**2))).LE. (a(i)+a(j)) ) then
WRITE(*,*) 'inside collision' !<---------------------------------------
call forca_elastica(k_n, a(i), a(j), xold(i), xold(j), yold(i), yold(j), Fx_elastica(j,i),&
Fy_elastica(j,i))
if (Fx_elastica(j,i) .GT. 0.0d0) then
Fx_elastica(i,j) = -Fx_elastica(j,i)
WRITE(*,*) 'elastic x is being passed' !<---------------------------------------
end if
if (Fy_elastica(j,i) .GT. 0.0d0) then
Fy_elastica(i,j) = -Fy_elastica(j,i)
WRITE(*,*) 'elastic y is being passed' !<---------------------------------------
end if
forcax(i) = forcax(i) + flagex(i)*Fx_elastica(j,i)
forcay(i) = forcay(i) + flagey(i)*Fy_elastica(j,i)
end do
call integracao_Euler_xy (xold(i),xnew(i),vxold(i),vxnew(i),forcax(i),yold(i),ynew(i),vyold(i),vynew(i),forcay(i),m(i))
if (mod (cont,5000).eq. 0) then
WRITE(p, *) int(cont/5000), t, xold(i), yold(i), forcax(i), forcay(i) !<---------------------------------------
end if
end do
end do
do p = 1,N !close files
close(unit=p)
end do
Just look at the WRITE statements. The first two appear on the screen alright. After OPENing the files, though... It doesn't. The WRITE statements that depend on conditions are the ones I want to see, but Fortran is not even writing the ones that don't depend on those conditions. Also, take a look at the last WRITE statement - it writes to the file with no problems.
Any ideas on how to fix/contour this problem?
I'm using Fortran 90.
You should not use small numbers for unit numbers. You are looping from 1 with a step of 1. You are almost guaranteed to hit the pre-connected units for standard output and standard input. See also Standard input and output units in Fortran 90?
Loop from some larger number, say from 100, or use newunit= and store the unit numbers in some array.
Also note that p has value N+1 at WRITE(p, *) ....

data entrance error Fortran

I'm learning how to programming with fortran90 and i need receive data from a txt file by the command prompt (something like that:
program.exe"<"data.txt).
at the Input txt file I'll always have a single line with at least 6 numbers till infinity.
if the data was wrote line by line it runs fine but as single line I'm receiving the error: "traceback:not available,compile with - ftrace=frame or - ftrace=full fortran runtime error:end file"
*note: i'm using Force fortran 2.0
here is example of data:
0 1 0.001 5 3 1 0 -9 3
edit: just clarifying: the code is working fine itself except for the read statement, which is a simple "read*,". I want know how To read a entire line from a txt once the entrance will be made by the promt command with stream direction.
( you can see more about that here: https://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/redirection.mspx?mfr=true).
there is no need to read the code, i've posted it just for knowledge.
I'm sorry about the whole inconvenience.
here is the code so far:
program bissecao
implicit none
integer::cont,int,e,k,intc,t1,t2,t3
doubleprecision::ii,is,pre,prec,erro,somaa,somab,xn
doubleprecision,dimension(:),allocatable::co
t1=0
t2=0
t3=0
! print*,"insira um limite inf da funcao"
read*,ii
!print*,"insira o limite superior da func"
read*,is
! print*,"insira a precisÆo admissivel"
read*,pre
if (erro<=0) then !elimina criterio de parada negativo ou zero
Print*,"erro"
go to 100
end if
!print*,"insira a qtd iteracoes admissiveis"
read*,int
!print*,"insira o grau da f(x)"
read*,e
if (e<=0) then ! elimina expoente negativo
e=(e**2)**(0.5)
end if
allocate(co(e+1))
!print*, "insira os coeficientes na ordem:&
! &c1x^n+...+(cn-1)x^1+cnx^0"
read(*,*)(co(k),k=e+1,1,-1)
somab=2*pre
intc=0
do while (intc<int.and.(somab**2)**0.5>pre.and.((is-ii)**2)**0.5>pre)
somab=0
somaa=0
xn =(ii+is)/2
do k=1,e+1,1
if (ii /=0) then
somaa=ii**(k-1)*co(k)+somaa
else
somaa=co(1)
end if
! print*,"somaa",k,"=",somaa
end do
do k=1,(e+1),1
if (xn/=0) then
somab=xn**(k-1)*co(k)+somab
else
somab=co(1)
end if
!print*,"somab",k,"=",somab
end do
if ((somaa*somab)<0) then
is=xn
else if((somaa*somab)>0)then
ii=xn
else if ((somaa*somab)==0) then
xn=(ii+is)/2
go to 100
end if
intc =intc+1
prec=is-ii
if ((((is-ii)**2)**.5)< pre) then
t3=1
end if
if (((somab**2)**.5)< pre) then
t2=1.
end if
if (intc>=int) then
t1=1
end if
end do
somab=0
xn=(ii+is)/2
do k=1,(e+1),1
if (xn/=0) then
somab=xn**(k-1)*co(k)+somab
else
somab=co(1)
end if
end do
100 write(*,'(A,F20.15,A,F20.15,A,A,F20.15,A,F20.15,A,I2)'),"I:[",ii,",",is,"]","raiz:",xn,"Fraiz:",somab,"Iteracoes:",intc
end program !----------------------------------------------------------------------------
In your program, you are using the "list-directed input" (i.e., read *, or read(*,*))
read *, ii
read *, is
read *, pre
read *, int
read *, e
read *, ( co( k ), k = e+1, 1, -1 )
which means that the program goes to the next line of the data file after each read statement (by neglecting any remaining data in the same line). So, the program works if the data file (say "multi.dat") consists of separate lines (as suggested by OP):
0
1
0.001
5
3
1 0 -9 3
But now you are trying to read an input file containing only a single line (say "single.dat")
0 1 0.001 5 3 1 0 -9 3
In this case, we need to read all the values with a single read statement (if list-directed input is to be used).
A subtle point here is that the range of array co depends on e, which also needs to be read by the same read statement. A workaround might be to just pre-allocate co with a sufficiently large number of elements (say 100) and read the data in a single line, e.g.,
integer :: k
allocate( co( 100 ) )
read *, ii, is, pre, int, e, ( co( k ), k = e+1, 1, -1 )
For completeness, here is a test program where you can choose method = 1 or 2 to read "multi.dat" or "single.dat".
program main
implicit none
integer :: int, e, k, method
double precision :: ii, is, pre
double precision, allocatable :: co(:)
allocate( co( 1000 ) )
method = 1 !! 1:multi-line-data, 2:single-line-data
if ( method == 1 ) then
call system( "cat multi.dat" )
read*, ii
read*, is
read*, pre
read*, int
read*, e
read*, ( co( k ), k = e+1, 1, -1 )
else
call system( "cat single.dat" )
read*, ii, is, pre, int, e, ( co( k ), k = e+1, 1, -1 )
endif
print *, "Input data obtained:"
print *, "ii = ", ii
print *, "is = ", is
print *, "pre = ", pre
print *, "int = ", int
print *, "e = ", e
do k = 1, e+1
print *, "co(", k, ") = ", co( k )
enddo
end program
You can pass the input file from standard input as
./a.out < multi.dat (for method=1)
./a.out < single.dat (for method=2)
Please note that "multi.dat" can also be read directly by using "<".

Fortran Error - attempt to call a routine with argument number three as a real(kind =1) when procedure was required

I have a fortran project linked to various subroutines, which are called from the main program. Variables are passed using modules. I can compile the code without any error. When I run the code, during the subroutine call i get an error "attempt to call a routine with argument number three as a real(kind =1) when procedure was required. I am not sure where i am going wrong. Can someone point out the error? Your help is very much appreciated. The error appears when the subroutine 'ncalc' is called inside the loop
program partbal
use const
use times
use density
use parameters
use rateconst
use ploss
implicit none
integer :: i
real :: nclp_init, ncl2p_init, ncln_init, ne_init
real :: ncl_init, ncl2_init, Te_init, neTe_init
open (10,file='in.dat')
read (10,*)
read (10,*) pressure
read (10,*)
read (10,*) P, pfreq, duty
read (10,*)
read (10,*) nclp_init, ncl2p_init, ncln_init, Te_init, Ti
pi = 3.14159265
R = 0.043
L = 0.1778
Al = 2*pi*R*R
Ar = 2*pi*R*L
V = pi*R*R*L
S = 0.066
e = 1.6e-19
me = 9.1e-31
mCl = 35.5/(6.023e26)
mCl2 = 2*mCl
k = 1.3806e-23
vi = (3*Ti*e/(53.25/6.023e26))**0.5
ncl2_init = pressure*0.1333/(1.3806e-23*298)/2
ncl_init = ncl2_init
ne_init = nclp_init + ncl2p_init - ncln_init
tot_time = 1/(pfreq*1000)
off_time = duty*tot_time
npoints = 10000
dt = tot_time/npoints
neTe_init = ne_init*Te_init
t_step = 0
call kcalc(Te_init)
call param(nclp_init, ncl2p_init, ncln_init, ne_init, ncl_init,ncl2_init, Te_init, Ti)
do i = 1, npoints, 1
t_step = i*dt + t_step
if (t_step > 0 .and. t_step <= 500) then
Pabs = 500
else if (t_step > 500) then
Pabs = 0
end if
if (i <= 1) then
call ncalc(ne_init, ncl_init, ncl2_init, nclp_init, ncln_init, ncl2p_init)
call powerloss(ne_init, ncl_init, ncl2_init, Pabs, neTe_init)
Te = neTe/ne
call kcalc(Te)
call param(nclp, ncl2p, ncln, ne, ncl, ncl2, Te, Ti)
else
call ncalc(ne, ncl, ncl2, nclp, ncln, ncl2p)
call powerloss(ne, ncl, ncl2, Pabs, neTe)
Te = neTe/ne
call kcalc(Te)
call param(nclp, ncl2p, ncln, ne, ncl, ncl2, Te, Ti)
end if
!open( 70, file = 'density.txt' )
!open( 80, file = 'Te.txt')
!do i = 1, 1001, 1
! np(i) = ncl2p(i) + nclp(i)
!write (70, *) ncl(i), ncl2(i), ncl2p(i), nclp(i), np(i), ncln(i), ne(i)
!close(70)
!write (80, *) Te(i), phi(i)
!close(80)
!end do
end do
end program partbal
subroutine ncalc(n_e, n_cl, n_cl2, n_clp, n_cln, n_cl2p)
use parameters
use const
use density
use rateconst
use times
implicit none
real :: n_e, n_cl, n_cl2, n_clp, n_cln, n_cl2p
nclp = (((kCliz*n_e*n_cl)+((kpair+kdisiz)*n_e*n_cl2)-(5e-14*n_clp*n_cln)-(S*n_clp/V)-((hlclp*Al+hrclp*Ar)*n_clp*ubclp))*dt)+n_clp
ncl2p = (((kCl2iz*n_e*n_cl2)-(5e-14*n_cl2p*n_cln) - (((hlcl2p*Al + hrcl2p*Ar)*n_cl2p*ubcl2p)/V)-(S*n_cl2p/V))*dt)+n_cl2p
ncln = ((((katt+kpair)*n_e*n_cl2)-(5e-14*n_clp*n_cln)-(5e-14*n_cl2p*n_cln)-(kdet*n_e*n_cln)-(S*n_cln/V)-(taun*(Al+Ar)/V))*dt)+n_cln
ne = ncl2p+nclp-ncln
ncl = ((((2*kdis+katt+kdisiz)*n_e*n_cl2)-(kCliz*n_e*n_cl)+(5e-14*n_cl2p *n_cln)+(2*5e-14*n_clp*n_cln)+ (kdet*n_e*n_cln) - (300*n_cl) + ((hlclp*Al + hrclp*Ar)*n_clp*ubclp/V)-(S*n_cl/V))*dt)+n_cl
ncl2 = ((n_cl2(1) + (5e-14*n_cl2p*n_cln) - ((kCl2iz+kdis+katt+kpair+kdisiz)*n_e*n_cl2) + (0.5*300*n_cl) + ((hlcl2p*Al + hrcl2p*Ar)*n_cl2p*ubcl2p/V)-(S*n_cl2/V))*dt)+n_cl2
return
end subroutine ncalc
In the line in subroutine ncalc immediately before the return statement, you have a reference to n_cl2(1) very early in the right hand side of the assignment statement. n_cl2 has not been declared as an array, therefore the compiler assumes that it must be a reference to a function that takes a single default integer argument. Because n_cl2 is a dummy argument, the it then expects you to provide a function for the corresponding actual argument when the routine is called.
(How your compiler manages to compile the preceding references to n_cl2 is a bit of a mystery - I suspect this error violates the syntax rules and hence you should see some sort of compile time diagnostic.)
Given you are using modules, it seems odd that you have not placed the ncalc routine in a module. If you did so, the error would probably become a compile time error rather than a runtime.

How to get FORTRAN 77 to read input?

I am using some old fortran code for a biology project I am doing. I am posting the relevant snippets here. Here is a subroutine called "READCN". Earllier in the program MAXN was set to 108.
OPEN ( UNIT = CNUNIT, FILE = CNFILE,
: STATUS = 'OLD', FORM = 'UNFORMATTED' )
READ ( CNUNIT ) N, BOX
IF ( N .GT. MAXN ) STOP ' N TOO LARGE '
READ ( CNUNIT ) ( RX(I), I = 1, N ), ( RY(I), I = 1, N )
CLOSE ( UNIT = CNUNIT )
RETURN
END
I am inputting a file called "data.dat" to the program. Here is the file:
10, 4
0.8147, 0.1576
0.9058, 0.9706
0.1270, 0.9572
0.9134, 0.4854
0.6324, 0.8003
0.0975, 0.1419
0.2785, 0.4218
0.5469, 0.9157
0.9575, 0.7922
0.9649, 0.9595
Nevertheless, I always get the message "N TOO LARGE". Any advice? Thanks!
Don't open as unformatted, it will read your file as if it were binary data. Open as formatted instead, and use "*" format. Also, don't read in one line, as you would not read your data in the expected order.
program bob
implicit none
integer cnunit, n, maxn, box, i
parameter(maxn=108, cnunit=10)
real rx(maxn), ry(maxn)
open(unit=cnunit, file='bob.txt', status='old', form='formatted')
read(cnunit, *) n, box
print *, 'n=', n, 'box=', box
if(n .gt. maxn) stop 'n too large'
do i=1, n
read(cnunit, *) rx(i), ry(i)
print *, rx(i), ry(i)
end do
close(unit=cnunit)
end
Alternately, if you can't change the code, then change your input file to fit the needs of your program. The input file you give simply won't work: you need binary data, in the format expected by your compiler (there is the usual, non portable "record size"), and data must be given column-wise, not row-wise.