So I've written a basic Vigenere Cypher in Fortran 90, however when I try to compile it, I am hammered with Unclassifiable Statement Errors due to my internal SUBROUTINES.
I have listed the variables used in each SUBROUTINE in '(' ')', but I am still getting back errors. I think it's a really simple fix, but I can't seem to find a solution to it.
Here is my code:
PROGRAM Assign_8
IMPLICIT NONE
CHARACTER*750 :: Input
CHARACTER*10 :: Key
CHARACTER*750 :: RepeatedKey
CHARACTER*750 :: Encrypted, Decrypted
LOGICAL :: Path
CHARACTER*10 :: Validation
INTEGER :: Reps, Encrypt, Decrypt, KeyInt, InputInt, MergeInt, UnmergeInt
WRITE(*,*) 'Do you wish to Encrypt or Decrypt a file?'
CALL Validation_Sub
SUBROUTINE Validation_Sub(Path, Validation)
IMPLICIT NONE
READ(*,*) Validation
SELECT CASE (Validation)
CASE ('Encrypt' , 'encrypt')
WRITE(*,*) 'You have selected to Encrypt a file.'
Path = .TRUE.
CASE ('Decrypt' , 'decrypt')
WRITE(*,*) 'You have selected to Decrypt a file.'
Path = .FALSE.
CASE DEFAULT
WRITE(*,*) 'Selection not valid please select to either Encrypt or Decrypt a file.'
IF (Path .EQV. .TRUE.) THEN
CALL Encrypt_Sub
ELSE IF (Path .EQV. .FALSE.) THEN
CALL Decrypt_Sub
END IF
END SELECT
END SUBROUTINE
SUBROUTINE Encrypt_Sub(Input, Key, RepeatedKey, Encrypt, InputInt, KeyInt, MergeInt, Encrypted)
IMPLICIT NONE
OPEN(1,FILE='plaintext.txt')
READ(1,'(A)') Input
WRITE(*,*) 'Please Enter a Key Phrase of 10 Characters (Including Spaces and Punctuation)'
READ(*,*) Key
RepeatedKey = REPEAT(Key(1:10),75)
DO Encrypt = 1, LEN_TRIM(Input)
InputInt = IACHAR(Input(Encrypt:Encrypt))
KeyInt = IACHAR(RepeatedKey(Encrypt:Encrypt))
MergeInt = InputInt + (KeyInt - 32)
IF (MergeInt > 126) THEN
MergeInt = MergeInt - 94
END IF
Encrypted(Encrypt:Encrypt) = ACHAR(MergeInt)
END DO
OPEN(2,FILE='EncryptionTest.txt')
WRITE(2,'(A)') Encrypted
CLOSE(2)
END SUBROUTINE
SUBROUTINE Decrypt_Sub(Encrypted, Key, RepeatedKey, Decrypt, MergeInt, KeyInt, UnmergeInt, Decrypted)
IMPLICIT NONE
OPEN(1,FILE='EncryptionTest.txt')
READ(1,'(A)') Encrypted
CLOSE(1)
WRITE(*,*) 'Please Enter Your Key Phrase'
READ(*,'(A)') Key
RepeatedKey = REPEAT(Key(1:10),75)
DO Decrypt = 1, 750, 1
MergeInt = IACHAR(Encrypted(Decrypt:Decrypt))
KeyInt = IACHAR(RepeatedKey(Decrypt:Decrypt))
UnmergeInt = MergeInt - (KeyInt - 32)
IF (UnmergeInt < 32) THEN
UnmergeInt = UnmergeInt + 94
END IF
Decrypted(Decrypt:Decrypt) = ACHAR(UnmergeInt)
END DO
OPEN(2,FILE='DecryptionTest.txt')
WRITE(2,'(A)') Decrypted
CLOSE(2)
END SUBROUTINE
END PROGRAM Assign_8
And the specific errors I am getting back are:
SUBROUTINE Validation_Sub(Path, Validation)
1
>Unclassifiable Statement at (1)
(Spacer)
IMPLICIT NONE
1
>Unexpected IMPLICIT NONE statement at (1)
I suspect the IMPLICIT NONE error is due to the SUBROUTINE not being defined properly.
END SUBROUTINE
1
>Expecting END Program statement at (1)
As before, I suspect this is because the SUBROUTINE has not been defined.
These errors repeat themselves for:
SUBROUTINE Encrypt_Sub
&
SUBROUTINE Decrypt_Sub
Any help would be greatly appreciated, if anyone does spot any immediate errors within my Vigenere Cypher code itself it would also be greatly appreciated if you could point them out if its no trouble.
You are missing CONTAINS before your subroutine.
In the future learn modules, but now use CONTAINS to make those subroutines properly internal to the main program.
So it should look like
PROGRAM Assign_8
...
CALL Validation_Sub
CONTAINS
SUBROUTINE Validation_Sub(Path, Validation)
END SUBROUTINE
...
END PROGRAM Assign_8
As well as "Contains" being missing from the top, there are several other little things.
Your select case should end after the default case, with the if (Path.. outside of it. The default case should also stop the programme.
You have also not closed one of your file units.
Here is code that I compiled with
$ gfortran -Og -std=f95 -Wall test.f90
PROGRAM Assign_8
IMPLICIT NONE
LOGICAL :: Path
CHARACTER(LEN=10) :: Validation
CHARACTER(LEN=750) :: Input
CHARACTER(LEN=10) :: Key
CHARACTER(LEN=750) :: RepeatedKey
CHARACTER(LEN=750) :: Encrypted, Decrypted
INTEGER :: Encrypt, Decrypt, KeyInt, InputInt, MergeInt, UnmergeInt
WRITE(*,*) 'Do you wish to Encrypt or Decrypt a file?'
CALL Validation_Sub
CONTAINS
SUBROUTINE Validation_Sub
IMPLICIT NONE
READ(*,*) Validation
SELECT CASE (Validation)
CASE ('Encrypt' , 'encrypt')
WRITE(*,*) 'You have selected to Encrypt a file.'
Path = .TRUE.
CASE ('Decrypt' , 'decrypt')
WRITE(*,*) 'You have selected to Decrypt a file.'
Path = .FALSE.
CASE DEFAULT
WRITE(*,*) 'Selection not valid please select to either Encrypt or Decrypt a file.'
stop
end SELECT
IF (Path .EQV. .TRUE.) THEN
CALL Encrypt_Sub
ELSE IF (Path .EQV. .FALSE.) THEN
CALL Decrypt_Sub
END IF
END SUBROUTINE Validation_Sub
SUBROUTINE Encrypt_Sub
IMPLICIT NONE
OPEN(1,FILE='plaintext.txt')
READ(1,'(A)') Input
close(1)
WRITE(*,*) 'Please Enter a Key Phrase of 10 Characters (Including Spaces and Punctuation)'
READ(*,*) Key
RepeatedKey = REPEAT(Key,75)
DO Encrypt = 1, LEN_TRIM(Input)
InputInt = IACHAR(Input(Encrypt:Encrypt))
KeyInt = IACHAR(RepeatedKey(Encrypt:Encrypt))
MergeInt = InputInt + (KeyInt - 32)
IF (MergeInt > 126) THEN
MergeInt = MergeInt - 94
END IF
Encrypted(Encrypt:Encrypt) = ACHAR(MergeInt)
END DO
OPEN(2,FILE='EncryptionTest.txt')
WRITE(2,'(A)') Encrypted
CLOSE(2)
END SUBROUTINE Encrypt_Sub
SUBROUTINE Decrypt_Sub
IMPLICIT NONE
OPEN(1,FILE='EncryptionTest.txt')
READ(1,'(A)') Encrypted
CLOSE(1)
WRITE(*,*) 'Please Enter Your Key Phrase'
READ(*,'(A)') Key
RepeatedKey = REPEAT(Key,75)
DO Decrypt = 1, 750, 1
MergeInt = IACHAR(Encrypted(Decrypt:Decrypt))
KeyInt = IACHAR(RepeatedKey(Decrypt:Decrypt))
UnmergeInt = MergeInt - (KeyInt - 32)
IF (UnmergeInt < 32) THEN
UnmergeInt = UnmergeInt + 94
END IF
Decrypted(Decrypt:Decrypt) = ACHAR(UnmergeInt)
END DO
OPEN(2,FILE='DecryptionTest.txt')
WRITE(2,'(A)') Decrypted
CLOSE(2)
END SUBROUTINE Decrypt_Sub
END PROGRAM Assign_8
Related
I use Fortran 90 via Force 2.0, with a 64bits pc under windows 10.
Everytime I compile and execute my code one of my column (the 't' one at the left) that I write in a .dat file changes even though I didn't change my code.
! module
module force_param
implicit none
integer,parameter :: dim=3
integer,parameter :: dim_l=dim-1
real*8,parameter :: rapmas=0.5, omega2=100, fsm2=1.E-4, x0_=0.1E0, x2_ =0.01E0
real*8,parameter :: omeg=10.d0, Aex=0.01E0
contains
subroutine force(x,v,f)
implicit none
real*8 :: x(dim), v(dim), f(dim_l)
f(1)=-omega2*(x(1)-x(3)) - omega2*rapmas*(x(1)-x(2))
f(2)=-omega2*(x(2)-x(1)) - fsm2*(v(1)-v(3))
end subroutine force
end module force_param
! algorithme de heun
subroutine heun(x,v,xn,vn,dt)
use force_param
IMPLICIT NONE
real*8::x( dim),v( dim),xn(dim),vn( dim),dt
real*8::f( dim_l), fn( dim_l)
call force(x,v,f)
xn(1: dim_l)=x( 1 : dim_l)+v( 1 : dim_l )*dt
vn(1:dim_l)=v(1: dim_l)+f( 1 : dim_l )*dt
call force(xn,vn,fn )
xn( 1 : dim_l)=x(1:dim_l)+((v(1:dim_l)+vn(1:dim_l))*.5d0*dt)
vn( 1 : dim_l)=v(1:dim_l)+((f(1:dim_l)+fn(1:dim_l))*.5d0*dt)
end subroutine heun
Thank you, I don't know how to access the debugging options though, I tried the button that says 'debugging' but it doesn't seem to do anything. I initialized all my variables too and nothing changed :
! PROGRAM PRINCIPAL
program vibrations
use force_param
implicit none
integer,parameter :: n=50
integer :: i
real*8 :: dt,pi
real*8:: x(dim),v(dim),xn(dim),vn(dim)
real*8 :: t,tn
pi=3.141592
dt=2*pi/(omeg*n)
x(1)=x0_
x(2)=x2_
x(3)=0
v(:)=0
xn(:)=0
vn(:)=0
t=0
tn=0
do i=0,n*1000
t=i*dt
x(3)=0
v(3)=0
tn=(i+n)*dt
xn(3)=0
vn(3)=0
call heun(x,v,xn,vn,dt)
open(11,file='oscill_libI.dat')
write(11,*)t,xn(1), xn(2)
x(:)=xn(:)
v(:)=vn(:)
enddo
end program vibrations
Here is the beginning of my dat file, sometimes the 't' column goes from 0 to 62, sometimes from 0 to 79 it's like randomized, but the 2 right columns stay the same :
0.0000000000000000 9.88551278186548116E-002 1.07106110228664085E-002
1.25663681030273432E-002 9.54368715187558225E-002 1.28277973235651557E-002
2.51327362060546865E-002 8.98431692414301264E-002 1.62639044499528901E-002
3.76991043090820280E-002 8.22344006522621740E-002 2.08756113538187266E-002
5.02654724121093729E-002 7.28284342737571672E-002 2.64687493992564297E-002
6.28318405151367110E-002 6.18938950672803800E-002 3.28048473194145346E-002
7.53982086181640559E-002 4.97418661274231927E-002 3.96091910096331989E-002
8.79645767211914009E-002 3.67162863528836467E-002 4.65801381808427575E-002
0.10053094482421875 2.31833471408859799E-002 5.33993871027770503E-002
0.11309731292724609 9.52022271687244688E-003 5.97428674724096373E-002
0.12566368103027342 -3.89651034653112948E-003 6.52919008503467374E-002
0.13823004913330078 -1.67023992139428389E-002 6.97442687804509659E-002
0.15079641723632811 -2.85562232108175044E-002 7.28248289506616686E-002
0.16336278533935547 -3.91503348001675106E-002 7.42953335021119959E-002
0.17592915344238280 -4.82199079113247164E-002 7.39631284187664967E-002
0.18849552154541016 -5.55508033296286119E-002 7.16884480472895630E-002
Here is two example of the end of my .dat file, generated from the same code :
62.643344993591306 -2.22234174408908088E-002 -6.79345709753481353E-002
62.655911361694336 7.81763163624332930E-004 -8.43500285728980836E-002
62.668477729797360 2.31009413326696972E-002 -9.94182790176534326E-002
62.681044097900390 4.40812444698733333E-002 -0.11254380214307025
62.693610466003413 6.31170757113199837E-002 -0.12318313084617104
62.706176834106444 7.96689081015940076E-002 -0.13086315388478151
62.718743202209467 9.32799461005491132E-002 -0.13519725211303918
62.731309570312497 0.10359012770409017 -0.13589874559045442
62.743875938415528 0.11034702522217735 -0.13279121399446445
62.756442306518551 0.11341330157177297 -0.12581535178107928
62.769008674621581 0.11277048866797904 -0.11503212942774470
62.781575042724604 0.10851897164177816 -0.10062214936426861
62.794141410827635 0.10087418344945331 -8.28812061224447061E-002
62.806707778930658 9.01591351206557229E-002 -6.22121809658964242E-002
76.566880851745609 -2.17677700529351897E-002 -1.05802168534466483E-002
76.579447219848632 -4.88389979588944381E-002 6.79397900452341150E-003
76.592013587951655 -7.46968241174833236E-002 2.32872848719374026E-002
76.604579956054678 -9.85925322542900023E-002 3.82250728574096491E-002
76.617146324157716 -0.11983644140594378 5.09885339005944488E-002
76.629712692260739 -0.13781930927178770 6.10355204755949760E-002
76.642279060363762 -0.15203121044591339 6.79188940734381658E-002
76.654845428466800 -0.16207729220063621 7.13017843304816629E-002
76.667411796569823 -0.16768990946606288 7.09692653728316025E-002
76.679978164672846 -0.16873675548102926 6.68360694761913066E-002
76.692544532775869 -0.16522473162941959 5.89500848494855997E-002
76.705110900878907 -0.15729943518448128 4.74915192035008926E-002
76.717677268981930 -0.14524028276312445 3.27677494663660557E-002
76.730243637084953 -0.12945142581913546 1.52040161357704148E-002
76.742810005187991 -0.11044874807218197 -4.66974609003714767E-003
76.755376373291014 -8.88433591287705327E-002 -2.62355258305883438E-002
! algorithme de heun
subroutine heun(x,v,xn,vn,dt)
use force_param
IMPLICIT NONE
real*8::x( dim),v( dim),xn(dim),vn( dim),dt
real*8::f( dim_l), fn( dim_l)
call force(x,v,f)
xn(1: dim_l)=x( 1 : dim_l)+v( 1 : dim_l )*dt
vn(1:dim_l)=v(1: dim_l)+f( 1 : dim_l )*dt
call force(xn,vn,fn )
xn( 1 : dim_l)=x(1:dim_l)+((v(1:dim_l)+vn(1:dim_l))*.5d0*dt)
vn( 1 : dim_l)=v(1:dim_l)+((f(1:dim_l)+fn(1:dim_l))*.5d0*dt)
end subroutine heun
! PROGRAM PRINCIPAL
program vibrations
use force_param
implicit none
integer,parameter :: n=50
integer :: i
real*8 :: dt,pi
real*8:: x(dim),v(dim),xn(dim),vn(dim),f( dim_l),fn( dim_l)
real*8 :: t,tn
pi=3.141592
dt=2*pi/(omeg*n)
x(1)=x0_
x(2)=x2_
x(3)=0
v(:)=0
xn(:)=0
vn(:)=0
t=0
tn=0
f(:) = 0
fn(:) = 0
do i=0,n*1000
t=i*dt
x(3)=0
v(3)=0
tn=(i+n)*dt
xn(3)=0
vn(3)=0
call heun(x,v,xn,vn,dt)
open(11,file='oscill_lib.dat')
write(11,'(f15.8,1x,f15.8,1x,f15.8)')t,xn(1), xn(2)
x(:)=xn(:)
v(:)=vn(:)
enddo
close(11)
end program vibrations
I misunderstood your issue: You have to close your file. Use close(11) before terminating your program. That way you make sure your output is saved fully.
And, as mentioned in the comments. You should open the file only once. Or close it and the open again for appending if necessary.
I have only limited experience with FORTRAN and I need to parse files with a structure similar to this:
H s 13.010000 0.019685
1.962000 0.137977
0.444600 0.478148
s 0.122000 1.000000
p 0.727000 1.000000
***
He s 38.360000 0.023809
5.770000 0.154891
1.240000 0.469987
s 0.297600 1.000000
p 1.275000 1.000000
***
I need to search for the label (e.g. He) and then read the corresponding blocks into an array.
I know I can parse file by specifying the format each line is supposed to have, but here there are different formats possible.
In Python I would just split each line by the white spaces and deal with it depending on the number of columns. But how to approach this in FORTRAN?
You can read each line as a character string and then process it. If, as it seems, the format is fixed (element symbol in first two characters, orbital letter in sixth character, etc.), the following program could serve you as inspiration:
program elms
implicit none
integer, parameter :: MAX_LEN = 40
character(len=MAX_LEN) :: line_el, line
integer :: u
integer :: is
integer :: nlin
character(len=2) :: element = 'He'
integer, parameter :: MAX_LINES = 20
real, dimension(MAX_LINES) :: e, f
open(newunit=u, file='elms.dat', status='old', action='read')
main_loop: do
! Read line
read(u, '(a)', iostat=is) line_el
if (eof_iostat(is)) exit main_loop
! Check first two characters of the line vs. chemical element.
if (line_el(1:2) .eq. element) then
! This is the beginning of an element block
nlin = 0
line = line_el
do
if (line .ne. '') then
! Line is not empty or only spaces.
nlin = nlin + 1
if (line(6:6) .ne. ' ') then
! Line contains an orbital letter - process it.
end if
! Read the real values in the rest of the line
read(line(7:),*) e(nlin), f(nlin)
end if
! Read next line
read(u, '(a)', iostat=is) line
if (eof_iostat(is)) exit main_loop
if (line(1:2) .ne. ' ') then
! Finished processing element block.
exit main_loop
end if
end do
end if
end do main_loop
! Close file
close(u)
contains
logical function eof_iostat(istat)
! Returns true if the end of file has been reached
use, intrinsic :: iso_fortran_env, only: IOSTAT_END
implicit none
integer, intent(in) :: istat
select case (istat)
case (0) ! No error
eof_iostat = .false.
case (IOSTAT_END) ! End of file reached
eof_iostat = .true.
case default ! Error
STOP
end select
end function eof_iostat
end program
You will probably need to make the program a subroutine, make element an intent(in) dummy argument, process the orbital symbols, etc.
Note that, if possible, it would be easier to just read all the data from the file in one go, and then search for the relevant data in the memory (e.g., having an array with the chemical symbols).
I'm trying to open 6 different files (at least) and then read the number of lines in each file, which should be about 20,000 lines each. I've read some posts on this forum about how to do that as I'm a newbie, and I've tried to implement it for my purposes.
I can do this individually without any problem, but when I try to read in all the files, I get an error message. I get either the "Killed: 9" error message or a malloc error:
malloc: *** mach_vm_map(size=63032829050880) failed (error code=3)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
What does this error mean regarding memory allocation? What am I doing wrong? How do I go about correcting this?
PROGRAM X
IMPLICIT NONE
INTEGER :: J,IO,NFILES,NLINES
CHARACTER (LEN=128) :: FILENAME
NFILES = 6
NLINES = 0
DO J = 0,NFILES-1
WRITE(FILENAME,'(A,I7.7,A)') 'data_',J*200,'.txt'
OPEN(1,FILE='FILENAME',FORM='FORMATTED')
DO
READ(1,*,IOSTAT=IO)
IF (IO/=0) EXIT
NLINES = NLINES + 1
END DO
WRITE(*,*) NLINES
CLOSE(1)
END DO
END PROGRAM X
I am using gfortran to compile.
UPDATE
I created 6 test files, data_0000000.txt, data_0000200.txt, ..., data_0001000.txt, each with less than 10 lines where there are less than 100 characters in each line. Unfortunately, I get the same error.
Obligatory disclaimer: If you just want to know the number of lines in a file, use wc -l <filename>. Don't reinvent the wheel if you don't have to.
I write this not necessarily because I think you didn't know that, but because someone else might come along, and think they need to write their own program to get the number of lines of files.
As for your question: I don't know why you get a malloc error. Maybe tell us which compiler and system you're using (including versions)? That said, there are three things that I noticed when reading your code:
You create a variable FILENAME, but then you don't use it. You're quoting it: FILE='FILENAME' which means that the open command looks for a file literally called FILENAME, not for a file with the name stored in the variable FILENAME. Remove the quotes:
OPEN(1, FILENAME=FILENAME, FORM='FORMATTED')
You use the unit number 1 -- that is dangerous. Different version of Fortran use specific unit numbers for specific uses. Use a handle far larger (at least 10, or more), or, even better, use the newunit descriptor in the open statement:
INTEGER :: u
OPEN(NEWUNIT=u, FILE=FILENAME, ACTION='READ', FORM='FORMATTED')
READ(u, *, IOSTAT=IO)
CLOSE(u)
You're not resetting the NLINES variable to 0 between files. The program will print a cumulative sum, not the number of lines for each file directly.
Adding to #chw21's response, if your sole purpose is to count the number of records (lines) in a file, here is a modular solution and a test program along with it (the counting is done inside subroutine getNumRecordInFile()):
module NumRecord_mod
implicit none
type :: Err_type
logical :: occurred = .false.
integer :: stat = -huge(0)
character(:), allocatable :: msg
end type Err_type
contains
! returns the number of lines in a file.
subroutine getNumRecordInFile(filePath,numRecord,Err)
implicit none
character(len=*), intent(in) :: filePath
integer, intent(out) :: numRecord
type(Err_type), intent(out) :: Err
character(len=8) :: record
integer :: fileUnit
logical :: fileExists, isOpen
integer :: iostat
character(*), parameter :: PROCEDURE_NAME = "#getNumRecordInFile()"
Err%occurred = .false.
Err%msg = ""
! Check if file exists
inquire( file=filePath, exist=fileExists, opened=isOpen, number=fileUnit, iostat=Err%stat )
if (Err%stat/=0) then
Err%occurred = .true.
Err%msg = PROCEDURE_NAME // ": Error occurred while inquiring the status of file='" // filePath // "'."
return
end if
if (.not.fileExists) then
Err%occurred = .true.
Err%msg = PROCEDURE_NAME // ": The input file='" // filePath // "' does not exist."
return
end if
if (isOpen) close(unit=fileUnit,iostat=Err%stat)
if (Err%stat>0) then
Err%occurred = .true.
Err%msg = PROCEDURE_NAME // ": Error occurred while attempting to close the open input file='" // filePath // "'."
return
end if
open(newunit=fileUnit,file=filePath,status="old",iostat=Err%stat)
if (Err%stat>0) then
Err%occurred = .true.
Err%msg = PROCEDURE_NAME // ": Error occurred while opening input file='" // filePath // "'."
return
end if
numRecord = 0
do
read(fileUnit,'(A)',iostat=iostat) record
if(iostat==0) then
numRecord = numRecord + 1
cycle
elseif(is_iostat_end(iostat)) then
exit
else
Err%occurred = .true.
Err%stat = iostat
Err%msg = PROCEDURE_NAME // ": Error occurred while reading input file='" // filePath // "'."
return
end if
end do
close(fileUnit,iostat=Err%stat)
if (Err%stat>0) then
Err%occurred = .true.
Err%msg = PROCEDURE_NAME // ": Error occurred while attempting to close the open input file='" // &
filePath // "' after counting the number of records in file."
return
end if
end subroutine getNumRecordInFile
end module NumRecord_mod
program test_numRecord
use NumRecord_mod
implicit none
type(Err_type) :: Err
integer :: numRecord
character(:), allocatable :: filePath
filePath = "main.f95"
call getNumRecordInFile(filePath=filePath,numRecord=numRecord,Err=Err)
if (Err%occurred) then
write(*,*) Err%msg
write(*,*) Err%stat
error stop
else
write(*,*) "Total number of records in file='" // filePath // "': ", numRecord
end if
end program test_numRecord
Now if you put this code in a file named "main.f95" and compile it under Fortran 2008 standard, then it should output the number of lines in your "main.f95" file, which should be something like the following:
$gfortran -std=f2008 *.f95 -o main
$main
Total number of records in file='main.f95': 98
For testing, you can simply copy paste the entire code in the online Fortran compiler here: https://www.tutorialspoint.com/compile_fortran_online.php
But keep in mind to change the compile option -std=f95 to -std=f2008 by going to Project -> Compile Options before executing the code.
Try this change (declaration and read line), there was no variable specified where the line contents shall go, here insert now dummy...
character(len=1000) :: dummy
...
READ(u, '(a)' , IOSTAT=IO) dummy
....
This is a small portion of the data I am trying to read:
01/06/2009,Tom Sanders,,264,220,73,260
01/08/2009,Adam Apple,158,,260,,208
01/13/2009,Lori Freeman,230,288,218,282,234
01/15/2009,Diane Greenberg,170,,250,321,197
01/20/2009,Adam Apple,257,,263,256,190
01/21/2009,Diane Greenberg,201,,160,195,142
01/27/2009,Tom Sanders,267,,143,140,206
01/29/2009,Tina Workman,153,,124,155,140
02/03/2009,Tina Workman,233,,115,,163
02/03/2009,Adam Apple,266,130,310,,310
the numbers between each comma are from a different location
Where two commas would represent missing data and a trailing comma would mean the fifth data point is missing
My goal is to organize the data into a table after calculating the average of each site and person, hence my two dim arrays
I want my output to look something like the following:
(obviously neater formatting but a table nonetheless)
Average Observed TDS (mg/l)
Name Site 1 Site 2 Site 3 Site 4 Site 5
------------------------------------------------------
Tom Sanders 251.0 172.5 251.7 160.0 229.0
Adam Apple 227.0 130.0 277.7 256.0 236.0
Lori Freeman 194.0 288.0 216.7 279.0 202.7
Diane Greenberg 185.5 190.0 205.0 258.0 169.5
Tina Workman 193.0 140.0 119.5 155.0 163.0
This is my program so far:
program name_finder
implicit none
integer, parameter :: wp = selected_real_kind(15)
real(wp) :: m, tds
real(wp), dimension(20,5) :: avg_site, site_sum
integer, dimension(20) :: nobs
integer, dimension(5) :: x
integer :: ierror, i, nemp, cp, non, ni, n
character(len=40), dimension(20) :: names
character(len=200) :: line, aname
character(len=20) :: output, filename
character(len=3), parameter :: a = "(A)"
do
write(*,*) "Enter file to open."
read(*,*) filename
open(unit=10,file = filename, status = "old", iostat = ierror)
if (ierror==0) exit
end do
write(*,*) "File, ",trim(filename)," has been opened."
non = 0
outer: do
read(10,a, iostat = ierror) line
if (ierror/=0) exit
cp = index(line(12:),",") + 11
aname = line(12:cp-1)
n=0
middle: do
read(line,'(Tcp,f4.2)') tds
write(*,*) "tds=", tds
n=n+1
if (n>10) exit
i = 1
inner: do
if (i > non) then
non = non +1
names(non) = trim(aname)
!ni = non
exit
end if
if (aname == names(i)) then
!ni = i
!cycle outer
exit inner
end if
i = i + 1
end do inner
end do middle
end do outer
write(*,*)
write(*,*) "Names:"
do i = 1,non
write(*,*) i, names(i)
end do
close(10)
close(20)
STOP
end program name_finder
TLDR; I am having trouble reading the data from the file shown at the top of each site after the names.
Suggestions? Thanks!
I hope the following is helpful. I have omitted any easily assumed declarations or any further data manipulation or writing to another file. The code is used just to read the data line by line.
character(150) :: word
read(fileunit, '(A)') word ! read the entire line
comma_ind = index(word,',') ! find the position of first comma
! Find the position of next comma
data_begin = index(word(comma_ind+1:),',')
! Save the name
thename = word(comma_ind+1:comma_ind+data_begin-1)
! Define next starting point
data_begin = comma_ind+data_begin
! Read the rest of the data
outer: do
if (word(data_begin+1:data_begin+1) == ',') then
! decide what to do when missing an entry
data_begin = data_begin + 1
cycle outer
else if (word(data_begin+1:data_begin+1) == ' ') then
! Missing last entry
exit outer
else
! Use it to find the length of current entry
st_ind = index(word(data_begin+1:),',')
if (st_ind == 0) then
! You reached the last entry, read it and exit
read(word(data_begin+1:), *) realData
exit outer
else
! Read current entry
read(word(data_begin+1: data_begin+st_ind-1),*) realData
end if
! Update starting point
data_begin = data_begin + st_ind
end if
end do outer
There could be a more elegant way to do it but I cannot think of any at the moment.
I want to read data from some files in Fortran, I can do that when the file names have a regular order. but now it's not regular, although all have same prefix for example : Fix001, Fix002, Fix023, Fix432, ...
I want the program get the prefix from the user and open all the files in a loop, read the data and write them in a single file.
any idea ?
Thanks.
PROGRAM Output
Implicit none
Integer ::n=5 !number of files
Integer ::nn=50 !number of rows in each file
Integer ::i,j
Real,Dimension(:),Allocatable::t,x,y,z
Character(len=12)::TD
Open(11,file='outputX.txt')
Allocate (t(1000),x(1000),y(1000),z(1000))
j=0
Do i=1,n
Write(TD,10)i
Write(*,*)TD
Open(1,file=TD)
Read(1,*)(t(j),x(j),j=1,nn)
Write(11,20)(x(j),j=1,nn)
j=j+1
Enddo
10 Format('100',i3.3,'')
20 Format(<nn>E25.8E3)
Deallocate(x,y,z,t)
END PROGRAM Output
If you do have an upper limit, you can try to open the file and test with the iostat parameter whether that was successful. If it wasn't, you skip the file.
This is an example that reads only the first integer variable from a file and appends it to the output file:
program read_files
implicit none
integer :: i, d
integer :: ioerr
character(len=len("FixXXX.txt")) :: fname
open(unit=30, file="Output.txt", action="write", iostat=ioerr)
if (ioerr /= 0) stop 1
do i = 0, 999
write(fname, '(A, I3.3, A)') "Fix", i, ".txt"
open(unit = 40, file=fname, status="old", action="read", iostat=ioerr)
if (ioerr /= 0) cycle
read(40, *) d
write(30, *) d
close(40)
end do
end program read_files