Related
GCC version 4.6
The Problem: To find a way to feed in parameters to the executable, say a.out, from the command line - more specifically feed in an array of double precision numbers.
Attempt: Using the READ(*,*) command, which is older in the standard:
Program test.f -
PROGRAM MAIN
REAL(8) :: A,B
READ(*,*) A,B
PRINT*, A+B, COMMAND_ARGUMENT_COUNT()
END PROGRAM MAIN
The execution -
$ gfortran test.f
$ ./a.out 3.D0 1.D0
This did not work. On a bit of soul-searching, found that
$./a.out
3.d0,1.d0
4.0000000000000000 0
does work, but the second line is an input prompt, and the objective of getting this done in one-line is not achieved. Also the COMMAND_ARGUMENT_COUNT() shows that the numbers fed into the input prompt don't really count as 'command line arguments', unlike PERL.
If you want to get the arguments fed to your program on the command line, use the (since Fortran 2003) standard intrinsic subroutine GET_COMMAND_ARGUMENT. Something like this might work
PROGRAM MAIN
REAL(8) :: A,B
integer :: num_args, ix
character(len=12), dimension(:), allocatable :: args
num_args = command_argument_count()
allocate(args(num_args)) ! I've omitted checking the return status of the allocation
do ix = 1, num_args
call get_command_argument(ix,args(ix))
! now parse the argument as you wish
end do
PRINT*, A+B, COMMAND_ARGUMENT_COUNT()
END PROGRAM MAIN
Note:
The second argument to the subroutine get_command_argument is a character variable which you'll have to parse to turn into a real (or whatever). Note also that I've allowed only 12 characters in each element of the args array, you may want to fiddle around with that.
As you've already figured out read isn't used for reading command line arguments in Fortran programs.
Since you want to read an array of real numbers, you might be better off using the approach you've already figured out, that is reading them from the terminal after the program has started, it's up to you.
The easiest way is to use a library. There is FLAP or f90getopt available. Both are open source and licensed under free licenses.
The latter is written by Mark Gates and me, just one module and can be learned in minutes but contains all what is needed to parse GNU- and POSIX-like command-line options. The first is more sophisticated and can be used even in closed-source projects. Check them out.
Furthermore libraries at https://fortranwiki.org/fortran/show/Command-line+arguments
What READ (*,*) does is that it reads from the standard input. For example, the characters entered using the keyboard.
As the question shows COMMAND_ARGUMENT_COUNT() can be used to get the number of the command line arguments.
The accepted answer by High Performance Mark show how to retrieve the individual command line arguments separated by blanks as individual character strings using GET_COMMAND_ARGUMENT(). One can also get the whole command line using GET_COMMAND(). One then has to somehow parse that character-based information into the data in your program.
I very simple cases you just need the program requires, for example, two numbers, so you read one number from arg 1 and another form arg 2. That is simple. Or you can read a triplet of numbers from a single argument if they are comma-separated like 1,2,3 using a simple read(arg,*) nums(1:3).
For general complicated command line parsing one uses libraries such as those mentioned in the answer by Hani. You have set them up so that the library knows the expected syntax of the command line arguments and the data it should fill with the values.
There is a middle ground, that is still relatively simple, but one already have multiple arguments, that correspond to Fortran variables in the program, that may or may not be present. In that case one can use the namelist for the syntax and for the parsing.
Here is an example, the man point is the namelist /cmd/ name, point, flag:
implicit none
real :: point(3)
logical :: flag
character(256) :: name
character(1024) :: command_line
call read_command_line
call parse_command_line
print *, point
print *, "'",trim(name),"'"
print *, flag
contains
subroutine read_command_line
integer :: exenamelength
integer :: io, io2
command_line = ""
call get_command(command = command_line,status = io)
if (io==0) then
call get_command_argument(0,length = exenamelength,status = io2)
if (io2==0) then
command_line = "&cmd "//adjustl(trim(command_line(exenamelength+1:)))//" /"
else
command_line = "&cmd "//adjustl(trim(command_line))//" /"
end if
else
write(*,*) io,"Error getting command line."
end if
end subroutine
subroutine parse_command_line
character(256) :: msg
namelist /cmd/ name, point, flag
integer :: io
if (len_trim(command_line)>0) then
msg = ''
read(command_line,nml = cmd,iostat = io,iomsg = msg)
if (io/=0) then
error stop "Error parsing the command line or cmd.conf " // msg
end if
end if
end subroutine
end
Usage in bash:
> ./command flag=T name=\"data.txt\" point=1.0,2.0,3.0
1.00000000 2.00000000 3.00000000
'data.txt'
T
or
> ./command flag=T name='"data.txt"' point=1.0,2.0,3.0
1.00000000 2.00000000 3.00000000
'data.txt'
T
Escaping the quotes for the string is unfortunately necessary, because bash eats the first quotes.
I have created a code that reads in a data file and print out the 20 lines of it. I want to develop this by making the code read all the lines within the data file, and only printing out certain lines that comply with an if statement. There are 4 values per data row, and I want it to look at the 3rd value and see if this changes, and if it does then to print that row of values. Can anyone help?
program datafile
implicit none
real*8 um,nm,pN,s
integer*8 au
integer*8 i
real, dimension(1:4)
real, dimension(4) :: file
WRITE(*,*)"test"
OPEN(UNIT=1, FILE="file.dat",STATUS="old",ACTION="read")
WRITE(*,*)"file opened"
do i=1,20
read(1,*) file
write(*,*)file
enddo
close(unit=1)
end program datafile
~
rogram readfromfile
implicit none
integer :: N, i
integer, dimension(130,2) :: cs
OPEN (UNIT=20,FILE='readtry.txt',STATUS='OLD',FORM='UNFORMATTED',)
do i=1,130
read (*,*) cs(i,1), cs(i,2)
enddo
do i=1,130
print *, cs(i,1), cs(i,2)
enddo
I am a beginner in programming, I just want read data from a file which has two columns and approximately 130 lines. I have tried to write down this code but its not working can someone please help?
The following error appears
gfortran -Wall -c "Rwarray.f95" (in directory: D:\Fortrandir\2Darrays)
Rwarray.f95:7:67:
OPEN (UNIT=20,FILE='readtry.txt',STATUS='OLD',FORM='UNFORMATTED',)
1
Error: Syntax error in OPEN statement at (1)
Compilation failed.
you have a compile time error, not a problem reading. But here's the gist of it:
It complains about a syntax error. Your statement is like this:
open(xxx, xxx, xxx, xxx,)
In order for it to compile, you need to remove the last comma. But I don't think that will give you what you want.
When you open the file, you declare it to be unformatted. Unformatted basically means that it contains the values in some form of binary. What's more, unformatted is not guaranteed to work between computers. So unless this file was written on your system, by a Fortran Program, with the FORM="UNFORMATTED" parameter, I don't think you'll get what you want.
I suspect that your input file looks something like this:
1 3
2 10
31 4711
That would be FORMATTED, not UNFORMATTED.
Then you use read(*, *). But the first * in there refers to "standard input", if you want to read from the file, you want to use the read(20, *), as 20 is the unit on which you opened the input file.
For the write statement, the * is correct, assuming that you want to write to "standard output" -- i.e. the screen.
What I'd further recommend is to use the error handling routines. Add these two variables to your declaration block:
integer :: ios
character(len=100) :: iomsg
And then use them whenever you open, read, or write:
open(unit=xx, file=xxx, status=xxx, action=xxx, form=xxx, io_stat=ios, iomsg=iomsg)
call check(ios, iomsg, "OPEN")
read(20, *, io_stat=ios, iomsg=iomsg) cs(1, i), cs(2, i)
call check(ios, iomsg, "READ")
You'd have to include the check subroutine, of course:
program readfromfile
implicit none
<declaraction block>
<execution block>
contains
subroutine check(ios, iomsg, action)
integer, intent(in) :: ios
character(len=*), intent(in) :: iomsg
character(len=*), intent(in), optional :: action
if (ios == 0) return ! No error occured, return
print*, "Error found. Error code:", ios
print*, "Message: ", trim(iomsg)
if (present(action)) print*, "Action was: ", trim(action)
stop 1
end subroutine check
end program readfromfile
GCC version 4.6
The Problem: To find a way to feed in parameters to the executable, say a.out, from the command line - more specifically feed in an array of double precision numbers.
Attempt: Using the READ(*,*) command, which is older in the standard:
Program test.f -
PROGRAM MAIN
REAL(8) :: A,B
READ(*,*) A,B
PRINT*, A+B, COMMAND_ARGUMENT_COUNT()
END PROGRAM MAIN
The execution -
$ gfortran test.f
$ ./a.out 3.D0 1.D0
This did not work. On a bit of soul-searching, found that
$./a.out
3.d0,1.d0
4.0000000000000000 0
does work, but the second line is an input prompt, and the objective of getting this done in one-line is not achieved. Also the COMMAND_ARGUMENT_COUNT() shows that the numbers fed into the input prompt don't really count as 'command line arguments', unlike PERL.
If you want to get the arguments fed to your program on the command line, use the (since Fortran 2003) standard intrinsic subroutine GET_COMMAND_ARGUMENT. Something like this might work
PROGRAM MAIN
REAL(8) :: A,B
integer :: num_args, ix
character(len=12), dimension(:), allocatable :: args
num_args = command_argument_count()
allocate(args(num_args)) ! I've omitted checking the return status of the allocation
do ix = 1, num_args
call get_command_argument(ix,args(ix))
! now parse the argument as you wish
end do
PRINT*, A+B, COMMAND_ARGUMENT_COUNT()
END PROGRAM MAIN
Note:
The second argument to the subroutine get_command_argument is a character variable which you'll have to parse to turn into a real (or whatever). Note also that I've allowed only 12 characters in each element of the args array, you may want to fiddle around with that.
As you've already figured out read isn't used for reading command line arguments in Fortran programs.
Since you want to read an array of real numbers, you might be better off using the approach you've already figured out, that is reading them from the terminal after the program has started, it's up to you.
The easiest way is to use a library. There is FLAP or f90getopt available. Both are open source and licensed under free licenses.
The latter is written by Mark Gates and me, just one module and can be learned in minutes but contains all what is needed to parse GNU- and POSIX-like command-line options. The first is more sophisticated and can be used even in closed-source projects. Check them out.
Furthermore libraries at https://fortranwiki.org/fortran/show/Command-line+arguments
What READ (*,*) does is that it reads from the standard input. For example, the characters entered using the keyboard.
As the question shows COMMAND_ARGUMENT_COUNT() can be used to get the number of the command line arguments.
The accepted answer by High Performance Mark show how to retrieve the individual command line arguments separated by blanks as individual character strings using GET_COMMAND_ARGUMENT(). One can also get the whole command line using GET_COMMAND(). One then has to somehow parse that character-based information into the data in your program.
I very simple cases you just need the program requires, for example, two numbers, so you read one number from arg 1 and another form arg 2. That is simple. Or you can read a triplet of numbers from a single argument if they are comma-separated like 1,2,3 using a simple read(arg,*) nums(1:3).
For general complicated command line parsing one uses libraries such as those mentioned in the answer by Hani. You have set them up so that the library knows the expected syntax of the command line arguments and the data it should fill with the values.
There is a middle ground, that is still relatively simple, but one already have multiple arguments, that correspond to Fortran variables in the program, that may or may not be present. In that case one can use the namelist for the syntax and for the parsing.
Here is an example, the man point is the namelist /cmd/ name, point, flag:
implicit none
real :: point(3)
logical :: flag
character(256) :: name
character(1024) :: command_line
call read_command_line
call parse_command_line
print *, point
print *, "'",trim(name),"'"
print *, flag
contains
subroutine read_command_line
integer :: exenamelength
integer :: io, io2
command_line = ""
call get_command(command = command_line,status = io)
if (io==0) then
call get_command_argument(0,length = exenamelength,status = io2)
if (io2==0) then
command_line = "&cmd "//adjustl(trim(command_line(exenamelength+1:)))//" /"
else
command_line = "&cmd "//adjustl(trim(command_line))//" /"
end if
else
write(*,*) io,"Error getting command line."
end if
end subroutine
subroutine parse_command_line
character(256) :: msg
namelist /cmd/ name, point, flag
integer :: io
if (len_trim(command_line)>0) then
msg = ''
read(command_line,nml = cmd,iostat = io,iomsg = msg)
if (io/=0) then
error stop "Error parsing the command line or cmd.conf " // msg
end if
end if
end subroutine
end
Usage in bash:
> ./command flag=T name=\"data.txt\" point=1.0,2.0,3.0
1.00000000 2.00000000 3.00000000
'data.txt'
T
or
> ./command flag=T name='"data.txt"' point=1.0,2.0,3.0
1.00000000 2.00000000 3.00000000
'data.txt'
T
Escaping the quotes for the string is unfortunately necessary, because bash eats the first quotes.
I have a dataset of parameter values for 30 species, and I want to run a script that conducts a simulation for each species. The parameter values are currently stored in a .txt file, where each row is a different species, and each column is a different parameter value. What I'd like to do is set up a do-loop that reads in the relevant row of parameter values for each species, runs the simulation script, and writes a .txt file of the output for each species. Unfortunately, I'm new to fortran and having a lot of trouble understanding how to read in consecutive rows from a .txt file in each step of a do loop. I tried making a simplified script to test whether the read step was working:
PROGRAM DRIVER
IMPLICIT NONE
INTEGER :: mm ! I forgot this line in the first version of this question
and edited to add it in
CHARACTER(7) :: species !! the first column is the species name
REAL*8 :: leaf_variable ! The next 3 columns are variable values
REAL*8 :: stem_variable !
REAL*8 :: root_variable !
OPEN (12, file = "species_parameters.txt") ! open the .txt file
DO mm = 1,30 ! set up the do loop
READ (12,*) species, leaf_variable, stem_variable, root_variable
! Read in the species-specific parameter values
WRITE (*,*) species, leaf_variable, stem_variable, root_variable
! Print the values on the screen just to show the do loop runs
ENDDO
END PROGRAM DRIVER
But when I go to compile, I get the error:
At line XX of file XX (unit = 12, file = 'species_parameters.txt')
Fortran runtime error: End of file
What am I misunderstanding about opening and reading in this file?
Thanks very much for any help.
EDIT: I think I've narrowed down my problem. My understanding is that read() takes in one row in a .txt file at a time, so that in this example:
read(7, *) species, leaf_variable, stem_variable, root_variable
read(7, *) species, leaf_variable, stem_variable, root_variable
The variables should equal the values in the second row of the .txt file. Instead, no matter how many times I put in the read() function, the variable values equal the first row. And, even though there are only 4 columns, I can define as many variables as I want with a read() function:
read(7, *) species, leaf_variable, stem_variable, root_variable,
fake_variable1, fake_variable2, fake_variable3, fake_variable4
where the fake_variable values equal the values in the second row of the .txt file. Am I confused about what read() does, or is there something I need to do to keep my script from reading my entire .txt file as one line?
EDIT #2: The do loop reads line by line correctly now that I've saved my .txt file with Unix encoding using TextWrangler. The original file was saved as a .txt file with Excel. This seems to have solved it, but if anyone has suggestions for a better way to specify the input file format, I'd appreciate it. The first few lines of the input file look like this:
species1,1.2,6.54,10.9
species2,1.42,3.5,8.23
species3,0.85,2.41,4.9
A run time error is when you have an executable, execute it, and it crashes. A compile time error is when the compiler fails to produce an executable.
This code shouldn't compile, because you have IMPLICIT NONE, but haven't declared the integer mm.
What I'd recommend is to get more information:
program driver
use iso_fortran_env
implicit none
character(len=7) :: species
real(kind=real64) :: leaf_variable, stem_variable, root_variable
integer :: u, ioerr
character(len=120) :: iomsg
open(newunit=u, file='species_parameters.txt', action='read', status='old', iostat=ioerr, iomsg=iomsg)
if (ioerr /= 0) then
print *, "Error opening file"
print *, trim(iomsg)
stop 1
end if
do
read(u, *, iostat=ioerr, iomsg=iomsg) species, leaf_variable, stem_variable, root_variable
if (ioerr /= 0) exit ! exits the loop
write(*, *) species, leaf_variable, stem_variable, root_variable
end do
print *, trim(iomsg)
close(u)
end program driver
This will always print the "read past end of file" error, but this is just to check how to program reads anyway.
This should compile, and when you run it, it should give you some information on what is going wrong.