Daniel502
Daniel502

Reputation: 15

Reading .xyz file into array(s)

I've currently created a code that can open a file from an in putted directory, then begin sorting that data into two different arrays, an integer and a character. The input file looks like this:

1817
Plot50.0.xyz
  C        0.70900        0.00000        0.00000
  C        0.00000        1.22802        0.00000
  C        2.12700        0.00000        0.00000
  C        2.83600        1.22802        0.00000
  C        4.96300        0.00000        0.00000
  C        4.25400        1.22802        0.00000
  C        6.38100        0.00000        0.00000
  C        7.09000        1.22802        0.00000
  C        9.21700        0.00000        0.00000
  C        8.50800 

datafile

Now I'm not sure if maybe I haven't allocated everything correctly when opening the file (format etc) but here is the code [working]:

program test01

character(len=40)    :: filename           !Storing the file name
character(len=20)    :: nam                !Collecting the file name within the file
integer(8)           :: N                  !Number of coordinates within the file
real(8), allocatable :: coa(:,:)           !Array containing xyz coordinates
character(len=6), allocatable :: atom(:,:) !Array containing the atomic make up
integer(8)           :: i,j,k              !Do loop parameters

    filename = '' 
    write (6,*) 'Enter file name' 
    read (5,*) filename 
    open (10, file=filename, status='OLD') 
    write (6,*) 'Sucessfully opened file:', filename 
    read(10,*) N

    allocate (coa(N,4))
    allocate (atom(N,1))
    read (10,*) nam
        print*, nam

        i = 0
        do while (i < N)
            read(10,*) atom(i,1), coa(i,2:4)
            i = i+1  
        end do

    print*, atom(0,1), atom(1,1), atom(4,1), atom(1818,1) !checking
    print*, coa(0,2), coa(1500,3)                         !checking   
    close (10) 

end program test01

So my main question lies with, are there any better ways to create the arrays (needs to be two as I believe characters and real cannot be mixed, and the coa array while be used for calculations later on) and specifically extract certain data from the file (more so to skip the row 2 of the file instead of inserting it into a character to remove it as it was causing all the issues when I was trying to create the arrays).

Upvotes: 1

Views: 2099

Answers (1)

High Performance Mark
High Performance Mark

Reputation: 78354

You write are there any better ways to create the arrays. Let's start with a correct way, which this isn't ...

i = 0
do while (i < N)
    read(10,*) atom(i,1), coa(i,2:4)
    i = i+1  
end do

That looks to be like a C loop (for (i=0; i<N; i++) ) written in Fortran and it makes the mistake of starting indexing into the arrays at row 0. Since the code makes no effort to start the array indexes at 0, and Fortran defaults to indexing from 1, the first execution of the read will read data into memory locations outside the extent of the arrays.

A correct and more Fortranic way would be

do i = 1, N
    read(10,*) atom(i,1), coa(i,2:4)
end do

I see that elsewhere you've printed values from row 0 of the arrays. You got 'lucky' that those outside-the-bounds accesses don't go to addresses outside the program's address space and lead to segmentation faults.

The program is broken, it's just that it's only a little broken and hasn't caused you any pain yet.

Upvotes: 2

Related Questions