dcdfort
Modern Fortran library for analyzing DCD trajectories
Data Types | Functions/Subroutines
dcdfort_index Module Reference

Module that contains IndexFile type. More...

Data Types

type  indexfile
 IndexFile class. More...
 
type  ndxgroups
 ndxgroups class More...
 

Functions/Subroutines

subroutine indexfile_read (this, filename, N)
 Open, read in, and process the GROMACS-style index file, storing information in memory. More...
 
integer function indexfile_get (this, group_name, I)
 Gets the number of atoms in a group. More...
 

Detailed Description

Module that contains IndexFile type.

This module contains the IndexFile class which can be used to read in and process GROMACS-style index files. It should not be necessary to create an object from this class independently from a Trajectory object, since it is included in the Trajectory class.

Function/Subroutine Documentation

◆ indexfile_get()

integer function dcdfort_index::indexfile_get ( class(indexfile), intent(inout)  this,
character (len=*), intent(in)  group_name,
integer, intent(in), optional  I 
)
private

Gets the number of atoms in a group.

Parameters
[in,out]thisIndexFile class
[in]group_nameindex group title or name (in brackets in the index file)
[in]Ithe location in the group
Returns
If an atom is specified, integer returns the overall index for that atom; otherwise, returns number of atoms in group
226 
227  implicit none
228  integer :: indexfile_get
229  class(indexfile), intent(inout) :: this
230  character (len=*), intent(in) :: group_name
231  integer, intent(in), optional :: i
232  integer :: j
233 
234  do j = 1, size(this%group)
235 
236  if (trim(this%group(j)%title) .eq. trim(group_name)) then
237 
238  indexfile_get = merge(this%group(j)%LOC(i), this%group(j)%NUMATOMS, present(i))
239  return
240 
241  end if
242 
243  end do
244 
245  ! If user asked to get the number of atoms in an index group, and that index group is not
246  ! in the index file, just return 0. If the user specified an atom number, then throw an error,
247  ! since the overall index cannot be returned in that case
248  if (.not. present(i)) then
249  if (this%group_warning) then
250  write(error_unit, '(a)') prompt//"WARNING: No atoms found in index group '"//trim(group_name)//"'."
251  write(error_unit, '(a)') prompt//"This warning will not appear again for any other index groups."
252  this%group_warning = .false.
253  end if
254  indexfile_get = 0
255  else
256  indexfile_get = -1
257  write(error_unit, '(a)') prompt//"ERROR: "//trim(group_name)//" is not in index file. The groups available are:"
258  do j = 1, size(this%group)
259  write(error_unit,'(a10,a,i0,a)') this%group(j)%title, " (", this%group(j)%NUMATOMS, ")"
260  end do
261  stop 1
262  end if
263 

◆ indexfile_read()

subroutine dcdfort_index::indexfile_read ( class(indexfile), intent(inout)  this,
character (len=*), intent(in)  filename,
integer, intent(in), optional  N 
)

Open, read in, and process the GROMACS-style index file, storing information in memory.

Parameters
[in,out]thisIndexFile class
[in]filenamename of GROMACS-style index file
[in]Nnumber of atoms in the entire system; used as a check
66 
67  implicit none
68  class(indexfile), intent(inout) :: this
69  character (len=*), intent(in) :: filename
70  character (len=2048) :: line, ncols_string, fmt_string
71  integer :: index_file_unit, io_status, ngrps, i, j, ncols
72  integer, allocatable :: indices_tmp(:), title_loc(:), num_array(:)
73  logical :: ex
74  integer, intent(in), optional :: n
75 
76  write(error_unit,'(a)') prompt//"Reading in "//trim(filename)//"."
77 
78  ! Does the file exist?
79  inquire(file=trim(filename), exist=ex)
80  if (ex .eqv. .false.) call error_stop_program(trim(filename)//" does not exist.")
81 
82  ! Is in index file?
83  open(newunit=index_file_unit, file=trim(filename), status="old")
84  read(index_file_unit, '(a)', iostat=io_status) line
85  if (index(line, "[") .eq. 0) call error_stop_program(trim(filename)//" is not a valid index file.")
86 
87  ! How many groups are in it?
88  rewind index_file_unit
89  io_status = 0
90  ngrps = 0
91  do while (io_status .eq. 0)
92  read(index_file_unit, '(a)', iostat=io_status) line
93  if (io_status .ne. 0) goto 100
94  if (index(line, "[") .ne. 0) ngrps = ngrps + 1
95  end do
96 
97 100 continue
98 
99  if (allocated(this%group)) deallocate(this%group)
100  allocate(this%group(ngrps), title_loc(ngrps+1)) ! Add one to include end of file
101 
102  ! Now find the title locations and save their names
103  rewind index_file_unit
104  i = 1
105  j = 1
106  io_status = 0
107  do while (io_status .eq. 0)
108 
109  read(index_file_unit, '(a)', iostat=io_status) line
110  if (io_status .ne. 0) goto 200
111  if (index(line, "[") .ne. 0) then
112  this%group(i)%title = trim(line(index(line, "[")+2:index(line, "]")-2))
113  title_loc(i) = j
114  i = i + 1
115  end if
116  j = j + 1
117 
118  end do
119 
120 200 continue
121 
122  if (this%group(1)%title .ne. "System") call error_stop_program("Index file does not have 'System' group as first group.")
123 
124  ! Index files can have a varying number of columns. This attempts to
125  ! detect the correct number by reading in the second line of the file,
126  ! which should be a list of indices for the "System" group.
127  ncols = 100
128  allocate(num_array(ncols))
129  io_status = 5000
130  do while (io_status .ne. 0)
131  ncols = ncols - 1
132  write(ncols_string, '(i0)') ncols
133  write(fmt_string, '(a)') '('//trim(ncols_string)//'i0)'
134  rewind index_file_unit
135  read(index_file_unit, '(a)', iostat=io_status) line
136  read(index_file_unit, '(a)', iostat=io_status) line
137  read(line, *, iostat=io_status) num_array(1:ncols)
138  end do
139 
140  title_loc(i) = j ! End of file location
141 
142  ! Now finally get all of the indices for each group
143  ! Allocate for total number of atoms in system, since that is the maximum
144  allocate(indices_tmp(n))
145  do i = 1, ngrps
146 
147  ! Initial guess only how many items are in the group
148  ! Add 1, bc loop subtracts 1 at the beginning
149  this%group(i)%NUMATOMS = (title_loc(i+1)-title_loc(i)-1)*ncols + 1
150 
151  if (n < this%group(i)%NUMATOMS) this%group(i)%NUMATOMS = n + 1
152  io_status = 5000
153 
154  do while (io_status .ne. 0)
155 
156  ! Our guess was too large if we made it back here, go to the beginning and reduce our guess by 1, try again
157  rewind index_file_unit
158  this%group(i)%NUMATOMS = this%group(i)%NUMATOMS - 1
159  if (this%group(i)%NUMATOMS .le. 0) then
160  this%group(i)%NUMATOMS = 0
161  goto 300
162  end if
163 
164  ! Read all the way to the group
165  do j = 1, title_loc(i); read(index_file_unit, '(a)', iostat=io_status) line; end do
166 
167  ! Attempt to read into array
168  read(index_file_unit, *, iostat=io_status) indices_tmp(1:this%group(i)%NUMATOMS)
169 
170  end do
171 
172  ! Specifying array bounds for array to be allocated is not required for F2008 but is required for F2003
173  allocate(this%group(i)%LOC(1:this%group(i)%NUMATOMS), source=indices_tmp(1:this%group(i)%NUMATOMS))
174 
175 300 cycle
176 
177  end do
178  deallocate(indices_tmp)
179 
180  do i = 1, ngrps-1
181  do j = i+1, ngrps
182  if (i .ne. j) then
183  if (this%group(i)%title .eq. this%group(j)%title) then
184  write(error_unit,*)
185  write(error_unit,'(a, a, a)') prompt//"WARNING: Index group ", this%group(i)%title, &
186  " was specified more than once in index file."
187  write(error_unit,*)
188  end if
189  end if
190  end do
191  end do
192 
193  ! Error checking to see if index file goes with the trajectory file
194 
195  ! If the number of atoms is not the same in the System group (first group) and dcd file
196  if (this%group(1)%numatoms .ne. n .or. this%group(1)%loc(this%group(1)%numatoms) .ne. n) then
197  call error_stop_program("Index file does not match dcd file.")
198  end if
199 
200  if (present(n)) then
201  do i = 1, ngrps
202 
203  ! If number of atoms in index group is larger than number of atoms in dcd file
204  if (this%group(i)%numatoms .gt. n) call error_stop_program("Index file does not match dcd file.")
205 
206  ! If a location number is greater than number of atoms in dcd file
207  do j = 1, this%group(i)%numatoms
208  if (this%group(i)%loc(j) .gt. n) call error_stop_program("Index file does not match dcd file.")
209  end do
210 
211  end do
212  end if
213 
214  close(index_file_unit)
215 
216  write(error_unit,'(a,i0,a)') prompt//"Read in ", ngrps, " index groups."
217