PartMC  2.6.1
numeric_average.F90
Go to the documentation of this file.
1 ! Copyright (C) 2009, 2011 Matthew West
2 ! Licensed under the GNU General Public License version 2 or (at your
3 ! option) any later version. See the file COPYING for details.
4 
5 !> \file
6 !> The numeric_average program.
7 
8 !> Compute the mean of a sequence of files containing numerical arrays,
9 !> all of the same size.
11 
12  integer, parameter :: dp = kind(0.d0)
13  integer, parameter :: max_input_files = 10000
14  integer, parameter :: out_unit = 40
15  integer, parameter :: in_unit_start = 41
16 
17  character(len=1000) :: filename
18  integer :: ios
19  character(len=1000) :: word1, word2
20  logical :: eol1, eol2, eof1, eof2
21  real(kind=dp) :: total
22  integer :: row, col, i_file, n_file
23  integer :: in_units(max_input_files)
24 
25  ! process commandline arguments
26  if (command_argument_count() < 2) then
27  write(6,*) 'Usage: numeric_average <out_filename>' &
28  // ' <in_filename_1> ... <in_filename_N>'
29  stop 2
30  endif
31  n_file = command_argument_count() - 1
32  if (n_file > max_input_files) then
33  write(0,*) 'ERROR: Too many input files'
34  stop 1
35  end if
36  call get_command_argument(1, filename)
37  write(*,*) "averaging output: ", trim(filename)
38  open(unit=out_unit, file=filename, iostat=ios)
39  if (ios /= 0) then
40  write(0,'(a,a,a,i4)') 'ERROR: unable to open file ', &
41  trim(filename), ' for writing: ', ios
42  stop 1
43  end if
44  do i_file = 1,n_file
45  call get_command_argument(i_file + 1, filename)
46  in_units(i_file) = in_unit_start + i_file - 1
47  write(*,*) "averaging input: ", trim(filename)
48  open(unit=in_units(i_file), status='old', file=filename, iostat=ios)
49  if (ios /= 0) then
50  write(0,'(a,a,a,i4)') 'ERROR: unable to open file ', &
51  trim(filename), ' for reading: ', ios
52  stop 2
53  end if
54  end do
55 
56  ! read data and compute average
57  eof1 = .false.
58  row = 1
59  col = 1
60  do while (.not. eof1)
61  total = 0d0
62  call read_word_raw(in_units(1), word1, eol1, eof1)
63  if (len(word1) > 0) then
64  total = string_to_real(word1)
65  end if
66  do i_file = 2,n_file
67  call read_word_raw(in_units(i_file), word2, eol2, eof2)
68  if (((len(word1) > 0) .and. (len(word2) == 0)) &
69  .or. ((len(word1) > 0) .and. (len(word2) == 0)) &
70  .or. (eol1 .and. (.not. eol2)) &
71  .or. ((.not. eol1) .and. eol2) &
72  .or. (eof1 .and. (.not. eof2)) &
73  .or. ((.not. eof1) .and. eof2)) then
74  write(*,'(a,i8,i8,i8)') 'different shape at row/col/file:', &
75  row, col, i_file
76  stop 1
77  end if
78  if (len(word1) > 0) then
79  total = total + string_to_real(word2)
80  end if
81  end do
82  if (len(word1) > 0) then
83  if (eol1) then
84  row = row + 1
85  col = 1
86  else
87  col = col + 1
88  end if
89  if (.not. eof1) then
90  write(out_unit,'(e30.15e3)', advance='no') &
91  (total / real(n_file, kind=dp))
92  if (eol1) write(out_unit, '(a)') ''
93  end if
94  end if
95  end do
96 
97  close(out_unit)
98  do i_file = 1,n_file
99  close(in_units(i_file))
100  end do
101 
102 contains
103 
104 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
105 
106  !> Convert a string to a real.
107  real(kind=dp) function string_to_real(string)
108 
109  !> String to convert.
110  character(len=*), intent(in) :: string
111 
112  real(kind=dp) :: val
113  integer :: ios
114 
115  read(string, '(e40.0)', iostat=ios) val
116  if (ios /= 0) then
117  write(0,'(a,a,a,i3)') 'Error converting ', trim(string), &
118  ' to real: IOSTAT = ', ios
119  stop 2
120  end if
121  string_to_real = val
122 
123  end function string_to_real
124 
125 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
126 
127  !> Expand all tabs in a line into single spaces (one tab makes one
128  !> space).
129  subroutine inout_tabs_to_spaces(line)
130 
131  !> Complete input line.
132  character(len=*), intent(inout) :: line
133 
134  integer i
135 
136  do i = 1,len(line)
137  if (ichar(line(i:i)) == 9) then
138  line(i:i) = ' '
139  end if
140  end do
141 
142  end subroutine inout_tabs_to_spaces
143 
144 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
145 
146  !> Read a single character from a file, signaling if we have hit EOL
147  !> or EOF. If EOL or EOF are true then the character value should be
148  !> ignored. A file containing a single line with a single character
149  !> on it will first return the character with EOL and EOF both
150  !> false, then will return with EOL true but EOF false, and finally
151  !> will return with EOL false and EOF true.
152  subroutine read_char_raw(unit, char, eol, eof)
153 
154  !> Unit number to read from.
155  integer, intent(in) :: unit
156  !> Character read.
157  character, intent(out) :: char
158  !> True if at EOL (end of line).
159  logical, intent(out) :: eol
160  !> True if at EOF (end of file).
161  logical, intent(out) :: eof
162 
163  integer :: ios, n_read
164  character(len=1) :: read_char
165 
166  eol = .false.
167  eof = .false.
168  char = " " ! shut up uninitialized variable warnings
169  read_char = "" ! needed for pgf95 for reading blank lines
170  read(unit=unit, fmt='(a)', advance='no', end=100, eor=110, &
171  iostat=ios) read_char
172  if (ios /= 0) then
173  write(0,*) 'ERROR: reading file: IOSTAT = ', ios
174  stop 2
175  end if
176  ! only reach here if we didn't hit end-of-record (end-of-line) in
177  ! the above read
178  char = read_char
179  goto 120
180 
181 100 eof = .true. ! goto here if end-of-file was encountered immediately
182  goto 120
183 
184 110 eol = .true. ! goto here if end-of-record, meaning end-of-line
185 
186 120 return
187 
188  end subroutine read_char_raw
189 
190 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
191 
192  !> Read a white-space delimited word from a file, signaling if we
193  !> have EOL or EOF. If EOL or EOF are true then the word will still
194  !> be meaningful data. If there was no data to be read then
195  !> len(word) will be 0.
196  subroutine read_word_raw(unit, word, eol, eof)
197 
198  !> Unit number to read from.
199  integer, intent(in) :: unit
200  !> Word read.
201  character(len=*), intent(out) :: word
202  !> True if at EOL (end of line).
203  logical, intent(out) :: eol
204  !> True if at EOF (end of file).
205  logical, intent(out) :: eof
206 
207  integer :: i
208  character :: char
209 
210  word = ""
211 
212  ! skip over spaces
213  call read_char_raw(unit, char, eol, eof)
214  do while (((ichar(char) == 9) .or. (ichar(char) == 32)) &
215  .and. (.not. eol) .and. (.not. eof))
216  call read_char_raw(unit, char, eol, eof)
217  end do
218  if (eol .or. eof) return
219 
220  ! char is now the first word character
221  i = 1
222  word(i:i) = char
223  call read_char_raw(unit, char, eol, eof)
224  do while ((ichar(char) /= 9) .and. (ichar(char) /= 32) &
225  .and. (.not. eol) .and. (.not. eof))
226  i = i + 1
227  word(i:i) = char
228  call read_char_raw(unit, char, eol, eof)
229  end do
230 
231  end subroutine read_word_raw
232 
233 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
234 
235 end program numeric_average
read_char_raw
subroutine read_char_raw(unit, char, eol, eof)
Read a single character from a file, signaling if we have hit EOL or EOF. If EOL or EOF are true then...
Definition: numeric_average.F90:153
inout_tabs_to_spaces
subroutine inout_tabs_to_spaces(line)
Expand all tabs in a line into single spaces (one tab makes one space).
Definition: numeric_average.F90:130
pmc_constants::dp
integer, parameter dp
Kind of a double precision real number.
Definition: constants.F90:12
numeric_average
program numeric_average
Compute the mean of a sequence of files containing numerical arrays, all of the same size.
Definition: numeric_average.F90:10
string_to_real
real(kind=dp) function string_to_real(string)
Convert a string to a real.
Definition: numeric_average.F90:108
read_word_raw
subroutine read_word_raw(unit, word, eol, eof)
Read a white-space delimited word from a file, signaling if we have EOL or EOF. If EOL or EOF are tru...
Definition: numeric_average.F90:197