Let us compile the following Fortran program:
program main
implicit none
integer::j
complex::y(2)
real::x(2)
x(1)=1.0
x(2)=2.0
do j=1,2
y(j)=FF(x(j))
enddo
write(6,*)
write(6,*) y,"by DO"
forall (integer::i=1:2)
y(i)=FF(x(i))
end forall
write(6,*)
write(6,*) y,"by FORALL"
do concurrent (integer::i=1:2)
y(i)=FF(x(i))
enddo
write(6,*)
write(6,*) y,"by DO CONCURRENT"
write(6,*)
contains
complex pure function FF(xx)
real,intent(in)::xx
FF=cmplx(xx)
end function
end program
by ifort (ver. 19.0.4.243) with no options.
Then, we get the result:
$ ./a.out
(1.000000,0.0000000E+00) (2.000000,0.0000000E+00) by DO
(1.000000,0.0000000E+00) (2.000000,0.0000000E+00) by FORALL
(2.000000,0.0000000E+00) (2.000000,0.0000000E+00) by DO CONCURRENT
The first and second results are as expected.
Why does not DO CONCURRENT gives the same result?
Related
I have to write a Fortran program for a homework assignment. When I compile it, I get this :
At line 36 of file projetfinal2.f90 (Unit 10 "PARAM.dat")
Traceback: not available, compile with -ftrace=frame or -ftrace=full
Fortran runtime error: Bad integer for item 1 in list input
I don't understand this error, can you help me fix this please?
''' this is the part of the program that uses the .dat file'''
SUBROUTINE initialisation(r,l_clear,f,it_max,densite)
TYPE(ROUTE),INTENT(INOUT) :: r
REAL,INTENT(OUT) :: f
INTEGER,INTENT(OUT):: it_max
LOGICAL,INTENT(OUT) :: l_clear
INTEGER::ios
OPEN(UNIT=10,FILE='PARAM.dat',FORM='formatted',ACTION='read',iostat=ios)
IF (ios/=0) STOP 'Erreur'
READ (UNIT=10,FMT=*) r%n_max
READ (UNIT=10,FMT=*) r%v_max
READ (UNIT=10,FMT=*) f
READ (UNIT=10,FMT=*) it_max
READ (UNIT=10,FMT=*) l_clear
CLOSE(UNIT=10)
END SUBROUTINE initialisation
'''this is the .dat file'''
60
3
1
0.3
30
.TRUE.
I create a fortran code to calculate the temperature of a cfd model. This code will be called on every iteration of a steady state simulation and calculate the temperature. On every calling of my code/iteration i want my fortran code also save the temperature field on a txt file and save. After calculating the temperature field and saving the values in TFIELD(100;1:6) the part with saving in txt file looks like:
OPEN(UNIT=35,FILE='W:\temperaturField.txt',
&FORM ='FORMATTED',STATUS='UNKNOWN',
&ACTION='READWRITE')
WRITE (35,FMT='5(F8.3,2X))') TFIELD(100,1:6)
With this code it only overwrites the first line of my txt file on every iteration. But i want to paste every TFIELD(100,1:6) array on a new line. How can i do this?
Add POSTITION='APPEND' to the OPEN:
OPEN(UNIT=35,FILE='W:\temperaturField.txt',
&FORM ='FORMATTED',STATUS='UNKNOWN',POSITION='APPEND',
&ACTION='READWRITE')
It seems like you are opening and closing the file for each iteration. This is a quick and dirty method if you need to debug, but it's slow.
If you want to do that, you might want to do what #Jack said: Include a POSITION='APPEND' to the OPEN statement to set the position to write the data to the end of the file. Also, you need to make sure that you close it every time.
A better (more efficient) method would be to keep the file open for the whole time. I'd do that with a module:
module temp_writer_module
implicit none
integer :: temp_writer_unit
logical :: is_opened = .FALSE.
private :: temp_writer_unit, is_opened
contains
subroutine temp_writer_open()
integer :: ios
character(len=100) :: iomsg
if (is_opened) then
print*, "Warning: Temperature file already openend"
return
end if
open(newunit=temp_writer_unit, file='W:\temperatureField', &
form='FORMATTED', status='UNKNOWN', action='WRITE', &
iostat=ios, iomsg=iomsg)
if (ios /= 0) then
print*, "Error opening temperature file:"
print*, trim(iomsg)
STOP
end if
is_opened = .TRUE.
end subroutine temp_writer_open
subroutine temp_writer_close()
if (.not. is_opened) return
close(temp_writer_unit)
is_opened = .FALSE.
end subroutine temp_writer_close
subroutine temp_writer(temps)
real, intent(in) :: temps(6)
integer :: ios
character(len=100) :: iomsg
if (.not. is_opened) call temp_writer_open()
write(temp_writer_unit, *, iostat=ios, iomsg=iomsg) temps
if (ios /= 0) then
print*, "Error writing to temperature file:"
print*, trim(iomsg)
end if
end subroutine temp_writer
end module temp_writer_module
Then you can use it in your program like this:
subroutine calc_temps(...)
use temp_writer_module
<variable declarations>
<calculations>
call temp_writer(tfield(100, 1:6))
end subroutine calc_temps
Just don't forget to call the temp_writer_close routine before your program ends.
Intuitively, I think to compare two value the speed should be logical>integer>real, So I made this test program:
program t
logical :: a=.true.
real :: b=1.021341
integer :: c=1
real(kind=16) :: start, finish,test
call cpu_time(start)
test=0.0
do while (test<1000000.)
if (a.eqv.a) then
test=test+0.01
endif
enddo
call cpu_time(finish)
print '("Time for compare logical= ",f6.3," seconds.")',finish-start
call cpu_time(start)
test=0.0
do while (test<1000000.)
if (b.eq.b) then
test=test+0.01
endif
enddo
call cpu_time(finish)
print '("Time for compare real= ",f6.3," seconds.")',finish-start
call cpu_time(start)
test=0.0
do while (test<1000000.)
if (c.eq.c) then
test=test+0.01
endif
enddo
call cpu_time(finish)
print '("Time for compare integer= ",f6.3," seconds.")',finish-start
end program
but the output is
Time for compare logical= 2.228 seconds.
Time for compare real= 2.200 seconds.
Time for compare integer= 2.200 seconds.
It seems they are no significant differences. Why I think the logical should be fastest. I use gfortran 5.4.0. My OS is ubuntu 16.04.
The code is here:
interface
subroutine csrcoo (nrow,job,nzmax,a,ja,ia,nnz,ao,ir,jc,ierr) bind(c,name="CSRCOO")
use iso_c_binding
implicit none
integer(c_int), value :: nrow,job,nzmax,nnz
real(c_double) :: a(*),ao(*)
integer(c_int) :: ir(*),jc(*),ja(*),ia(nrow+1),ierr
end subroutine csrcoo
end interface
subroutine csrcoo (nrow,job,nzmax,a,ja,ia,nnz,ao,ir,jc,ierr)
integer :: nrow,job,nzmax,nnz
real*8 :: a(*),ao(*)
integer :: ir(*),jc(*),ja(*),ia(nrow+1),ierr
integer :: i,k,k1,k2
ierr = 0
nnz = ia(nrow+1)-1
if (nnz > nzmax) then
ierr = 1
return
endif
goto (3,2,1) job
1 do 10 k=1,nnz
ao(k) = a(k)
10 END DO
2 do 11 k=1,nnz
jc(k) = ja(k)
11 END DO
3 do 13 i=nrow,1,-1
k1 = ia(i+1)-1
k2 = ia(i)
do 12 k=k1,k2,-1
ir(k) = i
12 END DO
13 END DO
return
end subroutine csrcoo
When I use the gfortran to compile this code like this: gfortran -O2 -c test.f90
It always shows this error:
test.f90:11:
subroutine csrcoo (nrow,job,nzmax,a,ja,ia,nnz,ao,ir,jc,ierr)
1
Error: Unclassifiable statement at (1)
test.f90:41.3:
end subroutine csrcoo
1
Error: Expecting END PROGRAM statement at (1)
Error: Unexpected end of file in 'test.f90'
Can anyone tell me what wrong with that code and give me some advice?
The problem is, that a standalone interface doesn't make any sense, because its name has to be accessible inside the part of the program, where you want to use it. Therefore, it has to be defined inside a module or a program.
I think, the error stems from the fact, that the program statement is not necessary and your interface, therefor, implicitely defines a program, which should be ended with an end statement, which is obviously missing.
You can solve your problem by wrapping your interface in a module and leaving the subroutine out of the module (otherwise, your subroutine would already have a module interface).
module [name]
[your interface]
end module
[your subroutine]
EDIT (Suggestion form #HighPerformanceMark): The better solution for the code you showed us would be to put the subroutine itself into the module and delete the interface. In this case, the interface for the subroutine is created automatically and you don't have to care for it.
module [name]
use iso_c_binding
implicit none
subroutine csrcoo (nrow,job,nzmax,a,ja,ia,nnz,ao,ir,jc,ierr) bind(c,name="CSRCOO")
[the content of your subroutine]
end subroutine
end module
I want to wrap the fortran write-statement in a custom subroutine or function which includes some additional debug-logic.
But I'm currently stuck with defining the prototype of the function/subroutine.
Is this possible? If yes, how?
The title of your question exhibits a misunderstanding, though the text suggests you know better. Nevertheless, for the record, write is a Fortran statement, it is neither a subroutine nor a function.
I think you have a number of options. One, which I have used occasionally, would be to write a function which returns a string. Perhaps
function error_message(error)
character(len=*), intent(in) :: error
character(len=:), allocatable :: error_message
error_message = 'ERROR: '//trim(error)
end function error_message
which you can then use like this
write(*,*) error_message('Oh s**t')
You could certainly write a subroutine or a function with side effects which include writing to an ouput channel, but if you adopt this approach you have to be careful to observe the rules for recursive i/o.
EDIT
after OP's comment.
If you want to switch off debug messages another option you have is to direct them to a null device or file, eg /dev/null on Linux or NUL on Windows. Something like
integer, parameter :: debug_channel = 99
logical, parameter :: debugging = .false.
...
if (debugging) then
open(debug_channel, file='NUL')
else
open(debug_channel, file='debuglog'
end if
and then
write(debug_channel,*) 'message'
a relatively simple way to accomplish most of what you want is to simply put the if inline in front of every write that is subject to debug control:
if(debug)write(..,..)..
where debug is a global logical value, or even:
if(debugf(level))write(..,..)..
where the logical function debugf determines whether to write based on some argument.
In addition to the other answers, you may be able to avoid using if (debug) write... with derived type IO.
I say "may", as it is quite silly unless you already have a suitable structure, and compiler support is currently rare.
However, as an example, compiled with ifort 14.0.1:
module errormod
type error_t
character(len=:), allocatable :: message
contains
procedure write_error
generic :: write(formatted) => write_error
end type error_t
logical debug_verbose
contains
subroutine write_error(err, unit, iotype, v_list, iostat, iomsg)
class(error_t), intent(in) :: err
integer, intent(in) :: unit
character(len=*), intent(in) :: iotype
integer, intent(in), dimension(:) :: v_list
integer, intent(out) :: iostat
character(len=*), intent(inout) :: iomsg
if (debug_verbose) then
write(unit, '("Error: ", A)', iostat=iostat, iomsg=iomsg) err%message
else
write(unit, '()', advance='no')
end if
end subroutine write_error
end module errormod
program test
use errormod
implicit none
type(error_t) error
debug_verbose = .TRUE.
error%message = "This error will be reported."
write(*, '(dt)') error
debug_verbose = .FALSE.
error%message = "This error will not be reported."
write(*, '(dt)') error
debug_verbose = .TRUE.
error%message = "This final error will also be reported."
write(*, '(dt)') error
end program test
The first and third messages will appear, but not the second.