Skipping input lines with #, # and & - fortran

I have a data file where some of the lines start with #, # and &. The file also contains the numerical data column. I want only the numerical data column.
So how to write a Fortran program to get fresh data avoiding the line starting with special characters?
I tried with the code provided in the post. But it is reading only first line of the numerical data not the remaining the lines.
# target g0.s1
# type xysize
0.05966 -70.06945 0.07000
0.08949 -70.06946 0.07000
0.11932 -70.06946 0.07000
0.14915 -70.06946 0.07000
0.17898 -70.06946 0.07000
# autoscale onread none
# target g0.s2 `
the code
implicit none
integer, parameter :: iu = 10
real :: x
integer :: ierr
open (unit=iu,file="data.txt",action="read")
do
read (iu,*,iostat=ierr) x
if (ierr == 0) exit
end do
print*,"x =",x
end program xread_data

If the line can contained something else than a number, you cannot read it directly as a number, that simply must fail.
So first you should read the line as a character string.
Then you can look at the first character in that line string and if it is a comment, skip the line. If not, try to read the numbers them from the string as from an internal file.
character(1024) :: line
open...
do
read(iu, '(a)', iostat=ierr) line
if (ierr/=0) exit
if (line(1:1)=='#' .or. line(1:1)=='#' .or. line(1:1)=='&') cycle
read(line, iostat...) x1, x2, x3
end do
close...

Related

How do I print a Fortran string with quotes around it?

Suppose I have a Fortran program like the following:
character*30 changed_string1
changed_string1="hello"
write(*,"(A)")changed_string1(1:3)
end
I would like to print the string with quotes so that I can exactly see leading and trailing spaces. How to do this?
There is no edit descriptor for characters which outputs them along with delimiters. A character variable does not have "automatic" delimiters like those which appear in a literal character constant (although may have them as content).
Which means you have to explicitly print any chosen delimiter yourself, adding them to the format or concatenating as in Vladimir F's answer.
Similarly, you can also add the delimiters to the output list (with
corresponding format change):
write (*,'(3A)') '"', string, '"'
You can even write a function which returns a "delimited string" and use the
result in the output list:
implicit none
character(50) :: string="hello"
print '(A)', delimit(string,'"')
contains
pure function delimit(str, delim) result(delimited)
character(*), intent(in) :: str, delim
character(len(str)+2*len(delim)) delimited
delimited = delim//str//delim
end function delimit
end program
The function result above could even be deferred length (character(:), allocatable :: delimited) to avoid the explicit statement of result length.
As yamajun reminds us in a comment, a connection for formatted output has a delimiter mode, which does allow quotes and apostrophes to be added automatically to the output for list-directed and namelist output (only). For example, we can control the delimiter mode for a particular data transfer statement:
write(*, *, delim='quote') string
write(*, *, delim='apostrophe') string
or for the connection as a whole:
open(unit=output_unit, delim='quote') ! output_unit from module iso_fortan_env
Don't forget that list-directed output will add that leading blank to your output, and if you have quotes or apostrophes in your character output item you will not see exactly the same representation (this could even be what you want):
use, intrinsic :: iso_fortran_env, only : output_unit
open(output_unit, delim='apostrophe')
print*, "Don't be surprised by this output"
end
Fortran 2018 doesn't allow arbitrary delimiter choice in this way, but this could still be suitable for some uses.
You can print quotes around your string. That will enable see the leading and trailing spaces.
write(*,"('''',A,'''')") changed_string1
or with the same effect
write(*,"(3A)") "'",changed_string1,"'"
(also mentioned by francescalus) that print a ' character before and afgter your string,
or you can concatenate your string with these characters and print the result
write(*,"(A)") "'"//changed_string1//"'"

How to read large amount of data from files and store them in variable?

I have a file which has values of pressure at every element. I require the element number (ELNO) and pressure (PLOAD) and pass through a subroutine. I am not able to read them separately from the file.
The data would read like given below starting with S175..
I want to be able to read this file, say A0001.txt, and read the lines one-by-one. When reading the lines I want to store the number after the first dot, for eg 1007, 1008 etc into a variable ELNO and the number after the last comma in a variable PLOAD in a loop. This is because I will require each value of ELNO and check a condition with the IF loop.
My problem is reading the file and storing in a variable like ELNO(i) something like that. The name S175 is constant.
I think I understand the logic. I have to store each like as a string and start iterating from the 6th position in the string till it finds the first "," and store that in ELNO(i). But I am new to FORTRAN and not able to get it. I have been trying for the past week learning FORTRAN to do this. But, not able to do this problem.
I tried a code like this below but its not reading line by line since I did not put it under a loop I guess.
S175.1007,P,0.221948
S175.1008,P,0.221943
S175.1009,P,0.221929
S175.1010,P,0.222287
S175.1018,P,0.222438
S175.1019,P,0.222425
.....
.....
.....
.....
.....
S175.13000,P,-1990
S175.13001,P,-1980
S175.13002,P,-2009
PROGRAM BARGE
implicit none
CHARACTER X*80
OPEN(UNIT=60, FILE="A0001.txt", ACCESS='SEQUENTIAL', ACTION='READ')
READ(UNIT=60, FMT='(A)', END=10)X
10 OPEN(UNIT=61, FILE="2.txt", ACTION="write")
WRITE (UNIT=61,FMT='(A)')X
END PROGRAM BARGE
Thank you everyone. I have completed it myself. There might be an easier and faster method but this works fine. Let me know if there is a more efficient method. I could learn. :)
PROGRAM BARGE
implicit none
CHARACTER PRES*80
INTEGER :: SUCCESS
INTEGER :: K, L, M, ELNO ! K is for the element number,L is word P and M is for pressure value
REAL :: PLOAD
OPEN(UNIT=60, FILE="1.txt", ACCESS='SEQUENTIAL', ACTION='READ')
DO
READ(UNIT=60, FMT='(A)', IOSTAT=SUCCESS)PRES
IF (SUCCESS.NE.0) EXIT
K=6
DO WHILE (PRES(K:K) .NE. ',')
K=K+1
END DO
READ(PRES(6:K-1), *) ELNO
PRINT *, ELNO ! ELEMENT NUMBER
L=K+1
DO WHILE (PRES(L:L) .NE. ',')
L=L+1
END DO
M=L+1
DO WHILE (PRES(M:M) .NE. ' ')
M=M+1
END DO
READ(PRES(L+1:M-1), *) PLOAD ! PRESSURE ON THE ELEMENT
PRINT *, PLOAD
OPEN(UNIT=61, FILE="2.txt", ACTION="write")
WRITE (UNIT=61,FMT='(A)')PRES
END DO
READ (*,*) PRES
END PROGRAM BARGE
It would be easy to use Fortran's list-directed input to read the data items from a line such as S175.1019,P,0.222425. The following snippet can replace the do loop in OP's own answer:
DO
READ(UNIT=60, FMT='(A)', IOSTAT=SUCCESS) PRES
IF (SUCCESS.NE.0) EXIT
READ(PRES(6:),*) ELNO, P, PLOAD
WRITE(*,*) ELNO, PLOAD
END DO
For this to work you have to include a declaration such as
CHARACTER(LEN=1) :: P
to catch the letter P in each line of the input file. The important line is this one
READ(PRES(6:),*) ELNO, P, PLOAD
which uses the edit descriptor * which tells the compiler / run-time to figure out how to read values for the three variables (one integer, one character, one real) from the 6th and following characters in the line PRES.
Fortunately, with a nice clean input file such as the one shown the compiler has no trouble reading the values, all the scanning for occurrences of , is unnecessary. If, for another application, you ever need to search a line for occurrences of a character use the intrinsic function index.

Is it possible to limit recursive reading in one line?

Further question from my last post: What is this error in fortran and how to stop the program when it occurs?
In my last post, I want to figure out how to identify the reading error when there is not enough elements in the input file which can be solved by using an iostat in the read statement.
My new code is:
program main
implicit none
integer ioerr, switch_1(3), switch_2, i, readerr
open(100, FILE='./input_error.gr', ACTION='READ', IOSTAT=ioerr)
if (ioerr == 0) then
read(100, *, iostat=readerr) (switch_1(i), i=1,3)
if(readerr .ne. 0) then
write(*,*) 'switch 1 wrong'
stop
end if
write(*,*) 'Switch_1 is: ', switch_1
read(100,*,iostat=readerr) switch_2
if(readerr .ne. 0) then
write(*,*) 'switch 2 wrong'
stop
end if
write(*,*) 'Switch_2 is: ', switch_2
else
write(*,*) 'File not read'
end if
end program main
my input file looks like this:
1,2,3
1
My new question is when there is less than three elements in the first line, the program will automatically read elements in the next line for Switch_1 and Switch_2 will have nothing to read and as the program is coded, it will return "Switch 2 wrong".
For example, when the input is like this:
1,3
2
However, what is really wrong is switch_1. Since there is not enough elements for switch_1, it goes to the next line the fill the last position of the array. This is not what I want. What I want is limit the reading in one line so the program will not read another line automatically, and in this case the program can stop at switch_1 and give me 'Switch 1 wrong. Is it possible?
I typically solve this problem by reading the line into a string first, and then attempting to read numbers from the string. For example,
character(len=200) :: str ! Long enough to hold a whole line
integer :: i(3), ier, fid
fid = 100
open(fid, FILE='./input_error.gr', ACTION='READ')
! -- Read a *single* line, and put it all into str
read(fid,'(a)') str
! -- Read str into integer array i
read(str,*,iostat=ier) i(1:3)
! -- Check if the line actually contained 3 integers
if (ier /= 0) then
write(*,*) 'Unsuccessful read'
endif
The read statement is therefore only able to use the current line because that is all str contains.
I figure out that if I add a comment at the end of each line, since character a is different data type, it will not be read as integer numbers. The advantage is when there is not enough elements for each switches, the program will read the comment first instead of reading the next line and give the right error message.
For example, make the input like:
1,2,3 ! Switch 1
4 ! Switch 2
with this structure, even if there is not enough input elements for switch 1, it is not reading 4 as the third element, instead, it is reading the comment, "! Switch 1" which will definitely return an error for Switch 1. This is exactly what I want and this works fine with number reading procedures. However, if the data type of switch_1 is character in the beginning, what will happen? It will not stop at numbers.

How do I write a newline character in a character variable in Fortran?

I want to store newline character in my character buffer variable buff. So far my code goes like this:
program TYPE_CHECK
c newline storage in buffer
character(100), dimension(10) :: buff
integer, dimension(10) :: x
integer :: i
do i=1,10
x(i) = i
enddo
do j=1,10
write(buff(j), 1) x(j), x(j)
1 format(' This is line ', I3, /,
* ' This is newline ', I3)
enddo
do j=1,10
write(*, "(A100)") buff(j)
enddo
end program TYPE_CHECK
This gives the following error:
At line 13 of file myfoo6.F
Fortran runtime error: End of file
You can use the NEW_LINE intrinsic function to query the character used to represent newline in formatted stream output. This character typically does what you want when you send it to the console. It is probably easiest to write it out using a separate character data descriptor in your format specification.
Using a slash edit descriptor is actually a request to progress to the next record. For an internal file (writing to a character variable), this is the next array element. In your example code you are passing a scalar as the character variable (so just one record), hence an end of file condition occurs.

Fortran Character Input at Undefined Length

program Test
implicit none
character (LEN=100) :: input
character (LEN=100) :: output
print *,"Please input your message: "
read *, input
For every character, I encrypt it in Ceaser's Cipher
Calculations
print *,"This is the output: "
write (*,"(2a)") "Message = ", out
end program Test
This doesn't work entirely.
For every character in the input, I convert it using the modulo(iachar()) functions. It works up until the print, I followed the debugging, the encryption is fine.
But the issue with the output lies in LEN=100. The do loop will go through 100 times converting nonexistent characters into garbage, breaking the program at output with UNDEFINED TYPE.
So if I input "test", it will encrypt CBNC*GARBAGE-TO-100* and not output. If I define length as 4, and do it, it works. but I want to be able to do it without defining a length. Any way around this?
The read statement should pad input out to the full length of the variable (100 characters) with blanks, rather than adding "garbage". The LEN_TRIM intrinsic function will give the significant length of the variable's value - i.e. the length excluding trailing blanks. You may need to remember this significant length of the input string for when you print the output string.
(Note the rules on list directed input (indicated by the * in the read statement) can be a little surprising - a format of "(A)" may be more robust, depending on the behaviour your want.)
In terms of avoiding fixed length strings in the context of reading input - Fortran 2003 introduces deferred length character, which greatly helps here. Otherwise see Reading a character string of unknown length for Fortran 95 possibilities. One complication is that you are reading from the console, so the backspace statement may not work. The work around to that follows a similar approach to that linked, but necessitates piecewise building the input string into an allocatable array of character at the same time as the input record length is being determined. Sequence association is then used to convert that array into a scalar of the right length. Comment or ask again if you want more details.
The following code reads a user input string of unspecified length. Be aware that it requires a compiler that supports deferred-length character strings: character(len = :). Deferred-length character strings were introduced in Fortran 2003.
program test
use iso_fortran_env, only : IOSTAT_EOR
implicit none
integer :: io_number
character(len = 1) :: buffer
character(len = :), allocatable :: input, output
input = ""
print *, "Please input your message."
do
read(unit = *, fmt = '(a)', advance = "no", iostat = io_number) buffer
select case (io_number)
case(0)
input = input // buffer
case(IOSTAT_EOR)
exit
end select
end do
allocate(character(len=(len(input))) :: output)
! Now use "input" and "output" with the ciphering subroutine/function.
end program test
Explanation
The idea is to read in a single character at a time while looking for the end-of-record (eor) condition. The eor condition is caused by the user pressing the "return" key. The "iostat" option can be used to look for eor. The value returned by "iostat" is equal to the integer constant "IOSTAT_EOR" located in the the module "iso_fortran_env":
use iso_fortran_env, only : IOSTAT_EOR
We declare a deferred-length character string to grab user input of an unknown length:
character(len = :), allocatable :: input
In the "read" statement, "advance = 'no'" allows a few characters to be read in at a time. The size of "buffer" determines the number of characters to be read in (1 in our case).
read(unit = *, fmt = '(a)', advance = "no", iostat = io_number) buffer
If "iostat" returns a "0", then there were no errors and no eor. In this case the "buffer" character should be added to the "input" string. Ultimately this step allocates a "new" input that has the size of the "old" input + the buffer character. The newly allocated input contains the characters from the old input + the buffer character.
select case (io_number)
case(0)
input = input // buffer
If "iostat" returns an eor value, then exit the do loop.
case(IOSTAT_EOR)
exit
The standard Fortran string is fixed length, padded on the right with blanks. If your input string will never have trailing blanks the solution is easy: use the Fortran intrinsic function len_trim to find the nonblank length of the string and process only those characters. Another approach is to use a new feature, allocatable string ... this provides variable length strings. If disallowing blanks at the end of the string is acceptable, you will probably find using len_trim easier.