Home > Archive > Fortran > July 2006 > writing output listing onto screen (or not) and onto file
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
writing output listing onto screen (or not) and onto file
|
|
| Bernard Bru 2006-07-17, 3:59 am |
| Is it possible to simplify my code by putting only one
WRITE statement when I want to write output results onto screen
(or not) and onto a file :
I put :
CHARACTER*1 SEL
OPEN( 8,FILE='sosout')
WRITE(6,*) ' Sorties en ligne (o | n ou > )?'
READ (5,'(A)') SEL
IF(SEL.NE.'o') OPEN(6,FILE='NO')
WRITE(6,200) A, B, C
WRITE(8,200) A, B, C
200 FORMAT(' A B C=', 3F12.4)
............;
Thanks for your help!
Bernard Bru
| |
| Tim Prince 2006-07-17, 7:59 am |
| Bernard Bru wrote:
> Is it possible to simplify my code by putting only one
> WRITE statement when I want to write output results onto screen
> (or not) and onto a file :
>
Are you asking about facilities provided by most systems for redirecting
output sent to '*' (or, on many systems, unit 6 without an OPEN)?
For example, the tee program, or redirection using '>' on the command line?
| |
|
| Tim Prince wrote:
> Bernard Bru wrote:
>
> Are you asking about facilities provided by most systems for redirecting
> output sent to '*' (or, on many systems, unit 6 without an OPEN)?
> For example, the tee program, or redirection using '>' on the command line?
Sorry, perhaps I'm not so clear:
Some time I want to have at the same time output on screen (Unit 6 or *)
and onto a file (OPEN(8,FILE= 'sosout')
An an other time I want only output on file (here unit 8) (for me it is
easier to visualize the output using vim editor) So I put in this case
OPEN(6,FILE= 'NO') because I dont need it
It seems to me heavy to put in the code 2 WRITE's for each output!!!
WRITE(6,....................
WRITE(8, the same as above
Bernard Bru
| |
|
| bru wrote:
> Some time I want to have at the same time output on screen (Unit 6 or *)
> and onto a file (OPEN(8,FILE= 'sosout')
> An an other time I want only output on file (here unit 8) (for me it is
> easier to visualize the output using vim editor) So I put in this case
> OPEN(6,FILE= 'NO') because I dont need it
What about this:
integer, parameter :: USR_UNIT(2) = [6, 8]
integer i
logical StdOutput, FileOutput
real a, b, c
a = 1.; b = 2.; c = 3.
write(*, '("Std output? [T/F]: ")', ADVANCE = 'NO')
read(*, *) StdOutput
write(*, '("File? [T/F]: ")', ADVANCE = 'NO')
read(*, *) FileOutput
if (FileOutput) Open(unit = USR_UNIT(2), file = 'userfile.txt')
do i = 1, 2
if (i == 1 .AND. (.NOT.StdOutput)) cycle
if (i == 2 .AND. (.NOT.FileOutput)) cycle
write(USR_UNIT(i), "(' A B C=', 3F12.4)") a, b, c
enddo
| |
|
| jwm wrote:
> bru wrote:
>
>
>
>
>
> What about this:
>
> integer, parameter :: USR_UNIT(2) = [6, 8]
> integer i
> logical StdOutput, FileOutput
> real a, b, c
>
> a = 1.; b = 2.; c = 3.
>
> write(*, '("Std output? [T/F]: ")', ADVANCE = 'NO')
> read(*, *) StdOutput
>
> write(*, '("File? [T/F]: ")', ADVANCE = 'NO')
> read(*, *) FileOutput
>
> if (FileOutput) Open(unit = USR_UNIT(2), file = 'userfile.txt')
>
> do i = 1, 2
> if (i == 1 .AND. (.NOT.StdOutput)) cycle
> if (i == 2 .AND. (.NOT.FileOutput)) cycle
> write(USR_UNIT(i), "(' A B C=', 3F12.4)") a, b, c
> enddo
>
I tried to compile your code: it works with g95, ifort and pgf90 but not
with f90 of Sun; error messages are:
integer, parameter :: USR_UNIT(2) = [6, 8]
^
"io.f90", Line = 2, Column = 40: ERROR: Unexpected syntax: "operand" was
expected but found "[".
^
"io.f90", Line = 2, Column = 44: ERROR: Unexpected syntax: "object-name"
was expected but found "8".
f90: COMPILE TIME 0.090000 SECONDS
f90: MAXIMUM FIELD LENGTH 4282502 DECIMAL WORDS
f90: 22 SOURCE LINES
f90: 2 ERRORS, 0 WARNINGS, 0 OTHER MESSAGES, 0 ANSI
nor with f95 of NAG :
Error: io.f90, line 2: Illegal character '['
Error: io.f90, line 2: syntax error
***Invalid item in type declaration
Error: io.f90, line 2: Illegal character ']'
[f95 terminated - errors found by pass 1]
I'm not a specialist of Fortran 90!!
Your solution seems to me to heavy because I have hundred of writes in
my code!!
Thanks a lot for your ansver
Bernard Bru
| |
|
|
bru wrote:
>
> I tried to compile your code: it works with g95, ifort and pgf90 but not
> with f90 of Sun; error messages are:
>
>
> integer, parameter :: USR_UNIT(2) = [6, 8]
> ^
> "io.f90", Line = 2, Column = 40: ERROR: Unexpected syntax: "operand" was
> expected but found "[".
> ^
> "io.f90", Line = 2, Column = 44: ERROR: Unexpected syntax: "object-name"
> was expected but found "8".
Yes, It's a f2003 feature, sorry about that. Try using:
integer, parameter :: USR_UNIT(2) = (/ 6, 8 /)
| |
|
| Tim Prince wrote:
> Bernard Bru wrote:
>
> Are you asking about facilities provided by most systems for redirecting
> output sent to '*' (or, on many systems, unit 6 without an OPEN)?
> For example, the tee program, or redirection using '>' on the command line?
Your solution is good for me in the case I want to have results only on
a file.
In the other case I want to have results at the same time on the screen
and on a file!!
Thanks for your ansver
Bernard Bru
| |
| Richard Maine 2006-07-17, 7:00 pm |
| On Mon, 17 Jul 2006 08:15:09 -0700, bru wrote
(in article <e9g9ht$662$1@ccpntc8.in2p3.fr> ):
> Some time I want to have at the same time output on screen (Unit 6 or *)
> and onto a file (OPEN(8,FILE= 'sosout')
....
> ^
> "io.f90", Line = 2, Column = 40: ERROR: Unexpected syntax: "operand" was
> expected but found "[".
That's just because of the use of the [] for array constructors. That
is an f2003 feature adopted as an extension by some f95 compilers, but
you can't portably count on it in f95. But that is peripheral to the
question.
> Your solution seems to me to heavy because I have hundred of writes in
> my code!!
Yes. I'd agree that this is a bit much for most applications. It
requires too much structuring of the code around this particular I/O
requirement.
If you want output to go to *EITHER* the terminal or a file, that is
relatively simple. There is a minor system-dependent piece needed to
get a unit number that is connected to standard output (f2003 finally
has a standard way to do this). Then you can select between that unit
or a unit connected to some other file. I do that kind of thing
regularly.
But if you want the output to go to both places, there isn't a "nice"
way to do that within Fortran. It requires that two WRITE statements be
executed. Something like the trick that jwm illustrated can be used to
make one statement that is executed twice, but still, the fundamental
issue is that there have to be two writes, whether written as two
separate statements, or as a single statement executed twice.
There are often ways outside of Fortran to do this. See the Unix "tee"
command (although sometimes it has "issues" with buffering, which can
cause awkwardness for interactive use.)
--
Richard Maine | Good judgment comes from
experience;
email: my first.last at org.domain| experience comes from bad judgment.
org: nasa, domain: gov | -- Mark Twain
| |
|
| jwm wrote:
> bru wrote:
>
>
>
>
>
> What about this:
>
> integer, parameter :: USR_UNIT(2) = [6, 8]
> integer i
> logical StdOutput, FileOutput
> real a, b, c
>
> a = 1.; b = 2.; c = 3.
>
> write(*, '("Std output? [T/F]: ")', ADVANCE = 'NO')
> read(*, *) StdOutput
>
> write(*, '("File? [T/F]: ")', ADVANCE = 'NO')
> read(*, *) FileOutput
>
> if (FileOutput) Open(unit = USR_UNIT(2), file = 'userfile.txt')
>
> do i = 1, 2
> if (i == 1 .AND. (.NOT.StdOutput)) cycle
> if (i == 2 .AND. (.NOT.FileOutput)) cycle
> write(USR_UNIT(i), "(' A B C=', 3F12.4)") a, b, c
> enddo
>
In my case your code is a little bit simpler with a test only on
StdOutput :
integer, parameter :: USR_UNIT(2) = (/6, 8/)
integer i
logical StdOutput
real a, b, c
a = 1.; b = 2.; c = 3.
write(*, '("Std output? [T/F]: ")', ADVANCE = 'NO')
read(*, *) StdOutput
Open(unit = USR_UNIT(2), file = 'userfile.txt')
do i = 1, 2
if (i == 1 .AND. (.NOT.StdOutput)) cycle
write(USR_UNIT(i), "(' A B C=', 3F12.4)") a, b, c
enddo
end
| |
| Ken Fairfield 2006-07-17, 7:00 pm |
| On 7/17/2006 8:15 AM, bru wrote:
[...snip example of selecting output units...]
> Your solution seems to me to heavy because I have hundred of writes in
> my code!!
In priniciple, you could generalize jwm's example to any number of
units/files, but isolate the multiple WRITE's to a subroutine you've
written, e.g., MY_WRITE, and then replace all the WRITE's with
MY_WRITE's in your code. Unfortunately in practice, that may be
quite difficult because of needing to pass a variable number of
arguments to MY_WRITE. Only if the number of different combinations
of format, argument number and argument types is fairly small would
this be feasible (presumably be using a generic feature to overload
the finite number of different versions...).
-Ken
--
I don't speak for Intel, Intel doesn't speak for me...
Ken Fairfield
D1C Automation VMS System Support
who: kenneth dot h dot fairfield
where: intel dot com
| |
| e p chandler 2006-07-17, 7:00 pm |
|
Ken Fairfield wrote:
> On 7/17/2006 8:15 AM, bru wrote:
> [...snip example of selecting output units...]
>
> In priniciple, you could generalize jwm's example to any number of
> units/files, but isolate the multiple WRITE's to a subroutine you've
> written, e.g., MY_WRITE, and then replace all the WRITE's with
> MY_WRITE's in your code. Unfortunately in practice, that may be
> quite difficult because of needing to pass a variable number of
> arguments to MY_WRITE. Only if the number of different combinations
> of format, argument number and argument types is fairly small would
> this be feasible (presumably be using a generic feature to overload
> the finite number of different versions...).
How about using an internal WRITE first, then sending the resulting
string to a subroutine along with a flag value which selects where
output goes?
implicit none
character(len=256) :: s
integer :: i,j
open(7,file='out.txt')
i=10
j=20
write(s,*)i,j
call prt_sub(s,1)
i=i+10
j=j+20
write(s,*)i,j
call prt_sub(s,2)
i=i+10
j=j+20
write(s,*)i,j
call prt_sub(s,3)
end
subroutine prt_sub(s,f)
implicit none
character(*) :: s
integer :: f
select case(f)
case(1)
write(*,*)trim(s)
case(2)
write(7,*)trim(s)
case(3)
write(*,*)trim(s)
write(7,*)trim(s)
end select
end
-- elliot
| |
|
| bru wrote:
> Tim Prince wrote:
>
> Your solution is good for me in the case I want to have results only on
> a file.
>
> In the other case I want to have results at the same time on the screen
> and on a file!!
>
> Thanks for your ansver
>
> Bernard Bru
Hi, Bernard.
Here is a module I wrote several years ago that I believe does what you
wish. You first write your output line to a character variable (or
array), then call either log_message, log_screen, or log_abort, with
the variable (or array) as the argument. log_message writes to the log
file only. log_screen writes to both the log file and the user's
standard output stream, and log_abort writes to both the log file and
the standard error stream, then aborts program execution.
--Peter
MODULE logfile_mod
! This module contains variables and routines related
! to the log file.
! P. Simon
! Revised: 9 April 2003
! Revised: 27 June 2003, to use FPP/CPP directives supporting
! multiple platforms.
! NOTE: THIS FILE MUST BE COMPILED USING THE FPP
! OR CPP PREPROCESSOR!
CHARACTER(len=132) :: logfile = 'arrayopt.log'
INTEGER, PARAMETER :: log_unit = 9 ! Unit number used
! ! for log messages.
INTERFACE log_message
MODULE PROCEDURE log_message_one
MODULE PROCEDURE log_message_mult
END INTERFACE
INTERFACE log_screen
MODULE PROCEDURE log_screen_one
MODULE PROCEDURE log_screen_mult
END INTERFACE
INTERFACE log_abort
MODULE PROCEDURE log_abort_one
MODULE PROCEDURE log_abort_mult
END INTERFACE
PRIVATE :: log_message_one
PRIVATE :: log_message_mult
PRIVATE :: log_screen_one
PRIVATE :: log_screen_mult
PRIVATE :: log_abort_one
PRIVATE :: log_abort_mult
CONTAINS
SUBROUTINE log_message_one(msg,flushit)
! If necessary, open the log file, append a message to the end.
! Flush the buffer if flushit is present.
#ifdef _CVF
USE dfport, ONLY: flush ! Needed for Compaq Visual Fortran
#endif
IMPLICIT NONE
CHARACTER(len=*), INTENT(IN) :: msg
INTEGER, INTENT(IN), OPTIONAL :: flushit
LOGICAL :: op
INQUIRE(unit=log_unit, opened=op)
IF (.NOT. op) THEN
OPEN(log_unit, file = logfile, status = 'unknown')
END IF
WRITE(log_unit,'(a)') TRIM(msg)
IF (PRESENT(flushit)) CALL flush(log_unit) ! Flush output buffer.
RETURN
END SUBROUTINE log_message_one
SUBROUTINE log_message_mult(msg,flushit)
! If necessary, open the log file, append a message to the end.
#ifdef _CVF
USE dfport, ONLY: flush ! Needed for Compaq Visual Fortran
#endif
IMPLICIT NONE
CHARACTER(len=*), INTENT(IN) :: msg(:)
INTEGER, INTENT(IN), optional :: flushit
LOGICAL :: op
INTEGER :: i
INQUIRE(unit=log_unit, opened=op)
IF (.NOT. op) THEN
OPEN(log_unit, file = logfile, status = 'unknown')
END IF
DO i = 1, SIZE(msg)
WRITE(log_unit,'(a)') TRIM(msg(i))
END DO
IF (PRESENT(flushit)) CALL flush(log_unit) ! Flush output buffer.
RETURN
END SUBROUTINE log_message_mult
SUBROUTINE log_screen_one(msg,flushit)
! If necessary, open the log file, append message to the end.
! Flush the buffer if flushit is present. Send message to the
! screen, also.
#ifdef _CVF
USE dfport, ONLY: flush ! Needed for Compaq Visual Fortran
#endif
IMPLICIT NONE
CHARACTER(len=*), INTENT(IN) :: msg
INTEGER, INTENT(IN), OPTIONAL :: flushit
LOGICAL :: op
INQUIRE(unit=log_unit, opened=op)
IF (.NOT. op) THEN
OPEN(log_unit, file = logfile, status = 'unknown')
END IF
WRITE(log_unit,'(a)') TRIM(msg)
WRITE(*,'(a)') TRIM(msg)
IF (PRESENT(flushit)) CALL flush(log_unit) ! Flush output buffer.
RETURN
END SUBROUTINE log_screen_one
SUBROUTINE log_screen_mult(msg,flushit)
! If necessary, open the log file, append a multiline
! message to the end. Send message to users screen, also.
#ifdef _CVF
USE dfport, ONLY: flush ! Needed for Compaq Visual Fortran
#endif
IMPLICIT NONE
CHARACTER(len=*), INTENT(IN) :: msg(:)
INTEGER, INTENT(IN), optional :: flushit
LOGICAL :: op
INTEGER :: i
INQUIRE(unit=log_unit, opened=op)
IF (.NOT. op) THEN
OPEN(log_unit, file = logfile, status = 'unknown')
END IF
DO i = 1, SIZE(msg)
WRITE(log_unit,'(a)') TRIM(msg(i))
WRITE(*,'(a)') TRIM(msg(i))
END DO
IF (PRESENT(flushit)) CALL flush(log_unit) ! Flush output buffer.
RETURN
END SUBROUTINE log_screen_mult
SUBROUTINE log_abort_one(msg)
! If necessary, open the log file, append message to the end,
! abort program execution, after closing the log file.
#ifdef _CVF
USE dfport, ONLY: abort ! Needed for Compaq Visual Fortran
#endif
IMPLICIT NONE
CHARACTER(len=*), INTENT(IN) :: msg
LOGICAL :: op
integer :: iunit
INQUIRE(unit=log_unit, opened=op)
IF (.NOT. op) THEN
OPEN(log_unit, file = logfile, status = 'unknown')
END IF
DO iunit = 0, log_unit, log_unit-iunit
WRITE(iunit,'(a)') ' '
WRITE(iunit,'(a)') ' '
WRITE(iunit,'(a)') '************* ABORTING EXECUTION
*************'
WRITE(iunit,'(a)') TRIM(msg)
WRITE(iunit,'(a)') '************* ABORTING EXECUTION
*************'
END DO
CLOSE(log_unit) ! Finish
CALL abort()
END SUBROUTINE log_abort_one
SUBROUTINE log_abort_mult(msg)
! If necessary, open the log file, append a multiline
! message to the end, then abort program execution,
! after closing the log file.
#ifdef _CVF
USE dfport, ONLY: abort ! Needed for Compaq Visual Fortran
#endif
IMPLICIT NONE
CHARACTER(len=*), INTENT(IN) :: msg(:)
LOGICAL :: op
INTEGER :: i, iunit
INQUIRE(unit=log_unit, opened=op)
IF (.NOT. op) THEN
OPEN(log_unit, file = logfile, status = 'unknown')
END IF
DO iunit = 0, log_unit, log_unit-iunit
WRITE(iunit,'(a)') ' '
WRITE(iunit,'(a)') ' '
WRITE(iunit,'(a)') '************* ABORTING EXECUTION
*************'
DO i = 1, SIZE(msg)
WRITE(iunit,'(a)') TRIM(msg(i))
END DO
WRITE(iunit,'(a)') '************* ABORTING EXECUTION
*************'
END DO
CLOSE(log_unit) ! Finish
CALL abort()
END SUBROUTINE log_abort_mult
END MODULE logfile_mod
| |
|
| Just define an interger*4 variable IOUNIT and set it to 0 for screen
output, or 2 (say) for printer or anything from 6 up (wiser) for a disk
device file..
The only problem is that screen i/o historically required a leading
space or other "carriage control" character as a prefix in the format
statement to avoid odd things happening, especially in earlier
compilers.
..
So you can work around the problem this way (one of many) by adding a
space only on screen i/o before any i/o to file IOUNIT..
IF (iounit.eq.0) THEN
write (0,701)
701 format(1X,\)
ENDIF
Terence Wright
| |
| Richard Maine 2006-07-17, 9:59 pm |
| On Mon, 17 Jul 2006 18:19:50 -0700, Terry wrote
(in article <1153185590.206914.127980@h48g2000cwc.googlegroups.com> ):
> Just define an interger*4 variable IOUNIT
Default integer is better. There is no benefit to specifying the nonstandard
*4 here. That adds system dependence with no balancing benefit. Sometimes
there are good reasons for system dependence, but it is completely
superfluous here.
and set it to 0 for screen
> output, or 2 (say) for printer or anything from 6 up (wiser) for a disk
> device file..
Those numbers are compiler-dependent. In particular, the 0 is not
particularly universal. By far the most common number is that unit 6 is often
standard output.
Other aspects of the OP's question are addressed in other followups.
--
Richard Maine | Good judgement comes from experience;
email: last name at domain . net | experience comes from bad judgement.
domain: summertriangle | -- Mark Twain
| |
| Paul Van Delst 2006-07-18, 7:01 pm |
| bru wrote:
> Tim Prince wrote:
>
>
>
> Your solution is good for me in the case I want to have results only on
> a file.
>
> In the other case I want to have results at the same time on the screen
> and on a file!!
Given that you have a bunch of these writes in your code already, a solution that uses
your O/S might be quicker. E.g. in *nix, for output to a file only, you do the usual redirect,
myprog > log_file
For output to a file and stdout you can use the "tee" utility,
myprog | tee log_file
Your previous posts indicate you're running on linux and/or unix systems so this is a
quick fix - with zero modification of your source code.
If you want duplicated output in the source code itself, then it really should be done
properly -- similar to what a previous poster, Peter, suggested. I've done similar and it
works great but it really needs to be built in from the start (IMO).
cheers,
paulv
--
Paul van Delst Ride lots.
CIMSS @ NOAA/NCEP/EMC Eddy Merckx
Ph: (301)763-8000 x7748
Fax:(301)763-8545
| |
| Bernard Bru 2006-07-20, 8:00 am |
| Bernard Bru wrote:
> Is it possible to simplify my code by putting only one
> WRITE statement when I want to write output results onto screen
> (or not) and onto a file :
>
> I put :
>
> CHARACTER*1 SEL
>
>
> OPEN( 8,FILE='sosout')
>
> WRITE(6,*) ' Sorties en ligne (o | n ou > )?'
> READ (5,'(A)') SEL
> IF(SEL.NE.'o') OPEN(6,FILE='NO')
>
> WRITE(6,200) A, B, C
> WRITE(8,200) A, B, C
> 200 FORMAT(' A B C=', 3F12.4)
> ............;
>
> Thanks for your help!
>
> Bernard Bru
Finally I did the following :
CHARACTER*1 SEL
LE= 7
LS= 8
OPEN(LS, FILE= 'sosout')
WRITE(6,*) ' Sorties en ligne (o | n ou > )?'
READ (5,'(A)') SEL
IF(SEL.NE.'o') OPEN(LE, STATUS= 'SCRATCH')
IF(SEL.EQ.'o') LE= 6
WRITE(LE,200) A, B, C
WRITE(LS,200) A, B, C
200 FORMAT(' A B C=', 3F12.4)
............;
and so on for other WRITES ........
Remark : it is not allowed by pgf90 to have such OPEN :
OPEN(6,STATUS= 'SCRATCH')
so I put LE= 7 (different from 6)
| |
| Dylan Sung 2006-07-30, 7:01 pm |
|
"Bernard Bru" <bru@in2p3.fr> wrote in message
news:e9nmc5$22q$1@ccpntc8.in2p3.fr...
> Bernard Bru wrote:
>
> Finally I did the following :
>
> CHARACTER*1 SEL
>
> LE= 7
> LS= 8
>
> OPEN(LS, FILE= 'sosout')
>
> WRITE(6,*) ' Sorties en ligne (o | n ou > )?'
> READ (5,'(A)') SEL
>
> IF(SEL.NE.'o') OPEN(LE, STATUS= 'SCRATCH')
> IF(SEL.EQ.'o') LE= 6
>
> WRITE(LE,200) A, B, C
> WRITE(LS,200) A, B, C
> 200 FORMAT(' A B C=', 3F12.4)
> ............;
> and so on for other WRITES ........
>
> Remark : it is not allowed by pgf90 to have such OPEN :
>
> OPEN(6,STATUS= 'SCRATCH')
>
> so I put LE= 7 (different from 6)
Use
C234567
print 200, A, B, C
usually send the lot to the screen, at least it does for me.
Dyl.
|
|
|
|
|