Search code examples
fortranpointsfile-read

Call a subroutine for a list of points instead of a single point


I have a certain piece of code in fortran. The code takes 'pq' as an input from the user and is a single point. Instead of doing this I want to read a set of points 'pq' from a file points.txt and run it for those number of points instead of just one single user input. Is it possible? The code is as follows:

program prop

      use module

      implicit none

      character(len=80)    :: ErrorMsg
      character(2)          :: xy
      real(8)               :: Conc(20) = 0.d0
      character(len=20)     :: fn, fl
      real(8)               :: Mmolar, Tcritical, Pcritical, Tmininimum, Tmaximum, x, y

call Init_module()

     write(*,*) 'Insert the gas name:'
     read(*,*) fn
     write(*,*) 'Insert the gas library:'
     read(*,*) fl


     write(*,*) 'Insert the copule pq:'
     read(*,*) pq
     write(*,*) 'Insert the value of ', pq(1:1)
     read(*,*) x
     write(*,*)  'Insert the value of ', pq(2:2)
     read(*,*) y

write(*,*) 'Pres      = ', Pres( pq, x, y, ErrorMsg)
     write(*,*) 'Temp   = ', Temperature( pq, x, y, ErrorMsg)

call ReleaseObjects()

end program prop

Instead of reading pq as a single point x,y from the user in the above code, I want to read a set of points from file.txt, for example 50 points and then run subroutines Pres and Temperature. Each line of the file contains one point x,y and x and y in each line are separated by a few space characters. The first few lines of file.txt are:

Ts
500
0.04781564   159.81587875
0.20396084   165.46398084
0.08159885   166.81382894
0.03879184   164.17497877
0.12585959   165.37000305
0.09895530   165.95997769
0.10389518   170.74235496

It must be noted that the length and the sign of the floating numbers can vary. The file.txt is originally written through python with the formatting for x, y being '%-12.8f %-12.8f\n'%. I have the following code to try and read the file but am not able to read from the 3rd line onwards:

real, allocatable     :: x(:),y(:)
        integer :: np

        open(12,file=trim('file.txt'),status='old',    &
             access='sequential', form='formatted', action='read' )

            read(12,*)pq
            write(*,*)'pq:', pq

            read(12,*)np
            write(*,*)'number of points:',np

            allocate (x(np))
            allocate (y(np))
            do i=1,np           
            read(12,*)x(i),y(i)
            write(*,*)x(i),y(i)
            enddo

Solution

  • Instead of using the READ statement with the asterisk (*) as the first argument asking for an user input, use a file identifier. You need to OPEN your file containing the set of points, assuming it is ASCII :

    OPEN(UNIT=10,FILE=file.txt,ACTION='read',STATUS='old')
    

    I think the arguments of this command are quite explanatory. Then assuming your file contains multiple lines with x and y values, you can read each line of your file by doing :

    READ(10,*) x,y
    

    If you have multiple points to read, just use a DO if you know the number of points to read, a DO WHILE otherwise. To take your example with 50 points, something like this should work :

    OPEN(UNIT=10,FILE=file.txt,ACTION='read',STATUS='old') ! Open file
    DO i=1,50
        READ(10,*) x,y
        write(*,*) 'Pres      = ', Pres( pq, x, y, ErrorMsg)
        write(*,*) 'Temp   = ', Temperature( pq, x, y, ErrorMsg)
    END DO
    CLOSE(10) ! Close file
    

    EDIT

    Your suggestion is almost correct. You forgot to declare pq as a character(len=2). You should not have been able to pass line 1 because of that. As I said, there is a space separator that is naturally treated by a asterisk as a format. Anyway, if you want to exactly match the format, use the same with which you wrote your data. Reading your format Python, I assume you wrote two floats with a space separator, and indeed if you count the number of character of your digits :

    0.04781564   159.81587875
    ^^^^^^^^^^^^|^^^^^^^^^^^^
    1         12|1          12
                |
              space
    

    which gives the following format in Fortran :

    read(12,'(f12.8,1X,f12.8)') x(i),y(i)
    

    X means a space separator in Fortran formats.

    Then you can write you data onscreen with the same format to check :

    write(*,'(f12.8,1X,f12.8)') x(i),y(i)
    

    It gives :

    pq:Ts 
    number of points:         500
    0.04781564 159.81587219
    0.20396084 165.46397400
    0.08159885 166.81382751
    0.03879184 164.17497253
    0.12585959 165.37001038
    0.09895530 165.95997620
    0.10389518 170.74235535
    

    You may have noticed that you lost precision on the last digits. It is because you have declared a simple real (4 bytes). Switch your real to 8 bytes with real(kind=8) or real*8 according to your compiler (be aware, not the right way to do it, not portable but sufficient in your case)

    Do not forget to close your file when you are done dealing with it :

    close(12)