FORTRAN:Algortihmic Problem

Hi guys

I am faced with this problem that I couldn't figure out yet, if you can point me to some direction that'll be of great help. So here's what I want to do.

I have let's say 10000 files which contains same number of Z coordinates in each file. I have to find the distance of those coordinates from a metal atom whose coordinate is constant, create an interval array (like 0.1,0.2...) then check how many atoms lie between 0.1 & 0.2, 0.2 & 0.3...Then I have to find the probability, just dividing by number of total atoms for each interval. At last I have to add those probabilities of each interval from all 10000 files and average those. I will try to make my self easier with example.

Let's say this is for my file 1.

coord                   metal     distance       interval   count  probability
0.096261585           0.05    0.046261585        0.1          0    0
0.114563334                   0.064563334        0.2          1    0.1
0.254013643                   0.204013643        0.3          0    0
0.453783515                   0.403783515        0.4          2    0.2
0.476391884                   0.426391884        0.5          0    0
0.659473448                   0.609473448        0.6          1    0.1
0.996886047                   0.946886047        0.7          0    0
1.033127279                   0.983127279        0.8          0    0
1.039735987                   0.989735987        0.9          3    0.3
1.137350541                   1.087350541          1          1    0.1
                                                 1.1          0    0

And this is of file 2.

coord                   metal     distance       interval   count  probability
0.141027861          0.05    0.091027861         0.1           2   0.2
0.183516896                  0.133516896         0.2           0    0
0.19548963                   0.14548963          0.3           1    0.1
0.373389271                  0.323389271         0.4           1    0.1
0.465507357                  0.415507357         0.5           0    0
0.722662302                  0.672662302         0.6           1    0.1
0.94961043                   0.89961043          0.7           0    0
1.107833235                  1.057833235         0.8           1    0.1
1.112145171                  1.062145171         0.9           0    0
1.272401645                  1.222401645           1           2    0.2
                                                 1.1           0    0
                                                 1.2           1    0.1
                                                 1.3           0    0

At the end I would get average probability at each interval.

Avg.Probability
0.1
0.05
0.05
0.15
0
0.1
0
0.05
0.15
0.15
0
0.05
0
0
0.1

So what I did was a loop over files that will read coordinates, calculate distances. But how do I count or get probabilities for the intervals? I tried creating mask and using a loop for counting before file loop starts but honestly I have no clue how should I progress. Cause has to go through all the distances to check how many atoms lie in that interval. I thought of giving this post last night but I slept over it but still have nothing. I also tried creating a mask but I'm pretty sure I'm doing it wrong.
I'm showing the audacity to post my terrible code here, if you have sometime to look over it.

program zdistribution        
implicit none

!Initializing inpputs
integer, parameter:: dp = selected_real_kind(15, 307)
real,parameter::waterlength=10.0
real(dp)::boxs,topl
integer::waterno
integer::ierror,stat_err
real(dp),allocatable::coord(:)
character(len=20)::filename

!Initializing outputs
integer::i,j
integer::int_size=waterlength/0.1
integer::array_int
integer::nlines
real(dp),allocatable::distance(:)
real(dp),allocatable::interval(:)
real(dp),allocatable::countw(:)
logical,allocatable::mask(:)
real(dp),allocatable::probability(:)

!prompt for boxsize, top layer metal and water layer length
write(*,*)"Enter the box size with at least one decimal place:"
read(*,*) boxs
write(*,*)"Enter the top layer metal surface coordinate with at least one decimal place:"
read(*,*) topl
write(*,*)"Enter the Total number of water in the box :"
read(*,*) waterno



!Counting lines in a file to allocate arrays
nlines=0

    OPEN(unit=10,file='OwZ-1.xyz',status='old',action='read',&
         iostat=ierror)
        do    ! count loop
           read(10,*,iostat=ierror)
            if (ierror /= 0) exit
            nlines=nlines+1
        end do !end count loop
    CLOSE(unit=10)


!allocating input arrays
allocate (coord(nlines))
allocate (distance(nlines))

!allocating output arrays
allocate (interval(int_size))
allocate (countw(int_size))
allocate (mask(int_size))
allocate (probability(int_size))

do j=1,int_size
  
      do i=1,2    ! file loop
      write(filename,100)i
      100 format('OwZ-',I1,'.xyz')
      write(*,*)"This is for OwZ-",i,".xyz"
      OPEN(unit=10,file=filename,status='old',action='read',&
              iostat=ierror)
         do
                if (ierror /= 0) exit
                read(10,*,iostat=ierror) coord(nlines)
                write(*,*) "This is the coord: ",coord(nlines)
                  
                if (coord(nlines) < topl) then
                distance(nlines)=coord(nlines)+(boxs-topl)
                else
                distance(nlines)=coord(nlines)-topl
                end if
                write(*,*)"This is the distance from top layer metal",&
                ": ",distance(nlines) 
                 mask=((distance(nlines))>(interval(j)) .and. (distance(nlines))<(interval(j+1)))
                countw(j)=count(mask)
                probability(j)=countw(j)/waterno
         end do          
     end do !file loop                 
    CLOSE(10)
end do ! j loop


end program zdistribution

This code shows run time error after showing distance for the 1st coord of the 1st file. Obviously cause I have no idea what I'm doing. Also I've 10000's of files to read. So if in the loop over files I put I4 instead of I1 it can't read files which are numbered as 1,2 or 10,100,1000. It can only read 10000. And if I put I1, it can only read up to 9. Also I don't know how to average those probabilities at the end. In essence I'm in a big mess. If you guys could just point me to a direction, that will be of great help.

Thanks a lot!!

What be the verbatim msg of your run time error? I don't know what happens if you open a unit twice without closing it, but this is what you do in the file loop.

1 Like

Hi Rudic

Thank you so much for answering! I almost solved my problem but stuck in one single step. I have to read 10000 files which are named as

OwZ-1.xyz, OwZ-10.xyz, OwZ-10000.xyz

like this.
The problem is when I read files like this-

 do i=1,9    ! file loop
          write(filename,100)i
          100 format('OwZ-',I1,'.xyz')

it can read only upto 9 files. To read from to 10 to 99 I have to make that I2! I tried adding 0's on the left like

OwZ-00001.xyz,OwZ-00002.xyz

but then when I say

do i=1,9    ! file loop
          write(filename,100)i
          100 format('OwZ-',I5.5,'.xyz')

it can't read those files!!

How do I read all files from 1 to 10000?

Thanks! Really appreciate it!

Saleheen

My FORTRAN days are long gone. So this is a wild guess: How about write (TMP, *) i and then concatenate 'OwZ-', TMP, '.xyz' into filename?

1 Like

Thanks RudiC. But It seems like the concatenation operator only works for character strings, doesn't work with character and integer. I tried this way too.

       do i=1,9    ! file loop
      write(filename,*)'OwZ-',i,'.xyz'

Shows run time error!Seems like this damn thing vowed not to work.
Thanks a lot man!

Hi.

Using the short code:

     program one

       character(len=20)::filename
       integer i

       do i=1,10000 ! file loop
         ! write(*,*)'OwZ-',i,'.xyz'
         write(*,9) i
       end do

9      format('OwZ-',I0,'.xyz')
     end

compiling with gfortran one.f90 and running ./a.out | specimen 5:5:5
produces:

Edges: 5:5:5 of 10000 lines in file "-"
OwZ-1.xyz
OwZ-2.xyz
OwZ-3.xyz
OwZ-4.xyz
OwZ-5.xyz
   ---
OwZ-4999.xyz
OwZ-5000.xyz
OwZ-5001.xyz
OwZ-5002.xyz
OwZ-5003.xyz
   ---
OwZ-9996.xyz
OwZ-9997.xyz
OwZ-9998.xyz
OwZ-9999.xyz
OwZ-10000.xyz

( The specimen code is a local code for looking at beginning:middle:end of a file. )

Is that what you were trying to do? ... cheers, drl

1 Like

Thanks a lot drl! I actually had no time at that moment so I just converted all the files to 5 digits, like 1 to 10001 and 10000 to 20000. Your solution is the one I was looking for. I'll try it sometime.