39 integer,
parameter :: by_array = 1
40 integer,
parameter :: by_row = 2
41 integer,
parameter :: by_col = 3
42 integer,
parameter :: by_elem = 4
44 integer,
parameter :: norm_one = 1
45 integer,
parameter :: norm_two = 2
46 integer,
parameter :: norm_sup = 3
48 character(len=PMC_MAX_FILENAME_LEN) :: filename1, filename2
49 integer :: by, norm, min_row, max_row, min_col, max_col, n_row, n_col
50 real(kind=dp) :: abs_tol, rel_tol
51 real(kind=dp),
allocatable,
target,
dimension(:,:) :: data1, data2
52 real(kind=dp),
allocatable,
dimension(:,:) :: diff, norm1, abs_err, rel_err
53 real(kind=dp),
pointer,
dimension(:,:) :: use_data1, use_data2
58 opts(1) =
option_s(
"help", .false.,
'h')
59 opts(2) =
option_s(
"abs-tol", .true.,
't')
60 opts(3) =
option_s(
"rel-tol", .true.,
'T')
61 opts(4) =
option_s(
"min-row", .true.,
'r')
62 opts(5) =
option_s(
"max-row", .true.,
'R')
63 opts(6) =
option_s(
"min-col", .true.,
'c')
64 opts(7) =
option_s(
"max-col", .true.,
'C')
65 opts(8) =
option_s(
"by", .true.,
'b')
66 opts(9) =
option_s(
"norm", .true.,
'n')
78 select case(
getopt(
"ht:T:r:R:c:C:pP", opts))
107 call
die_msg(526174645,
"unknown --by argument: " // trim(optarg))
118 call
die_msg(568020730,
"unknown --norm argument: " // trim(optarg))
121 call
die_msg(141541134,
'unknown option')
123 call
die_msg(816884701,
'unhandled option: ' // trim(optopt))
127 if (optind /= command_argument_count() - 1)
then
130 'expected exactly two non-option prefix arguments')
133 call get_command_argument(optind, filename1)
134 call get_command_argument(optind + 1, filename2)
141 if (min_row <= 0)
then
144 if (max_row <= 0)
then
145 call
assert_msg(266216891,
size(data1, 1) ==
size(data2, 1), &
146 "number of rows differs between input files")
147 max_row =
size(data1, 1)
149 call
assert_msg(136425118, max_row <=
size(data1, 1), &
150 "max-row exceeds the number of rows in " // trim(filename1))
151 call
assert_msg(279083405, max_row <=
size(data2, 1), &
152 "max-row exceeds the number of rows in " // trim(filename2))
155 if (min_col <= 0)
then
158 if (max_col <= 0)
then
159 call
assert_msg(148743161,
size(data1, 2) ==
size(data2, 2), &
160 "number of columns differs between input files")
161 max_col =
size(data1, 2)
163 call
assert_msg(884008689, max_col <=
size(data1, 2), &
164 "max-col exceeds the number of columns in " // trim(filename1))
165 call
assert_msg(553561214, max_col <=
size(data2, 2), &
166 "max-col exceeds the number of columns in " // trim(filename2))
169 use_data1 => data1(min_row:max_row, min_col:max_col)
170 use_data2 => data2(min_row:max_row, min_col:max_col)
172 n_row = max_row - min_row + 1
173 n_col = max_col - min_col + 1
174 allocate(diff(n_row, n_col))
175 diff = use_data1 - use_data2
179 allocate(norm1(1, 1))
180 allocate(abs_err(1, 1))
183 norm1(1, 1) = sum(abs(use_data1))
184 abs_err(1, 1) = sum(abs(diff))
186 norm1(1, 1) = sqrt(sum(use_data1**2))
187 abs_err(1, 1) = sqrt(sum(diff**2))
189 norm1(1, 1) = maxval(abs(use_data1))
190 abs_err(1, 1) = maxval(abs(diff))
195 allocate(norm1(
size(diff, 1), 1))
196 allocate(abs_err(
size(diff, 1), 1))
199 norm1(:, 1) = sum(abs(use_data1), 2)
200 abs_err(:, 1) = sum(abs(diff), 2)
202 norm1(:, 1) = sqrt(sum(use_data1**2, 2))
203 abs_err(:, 1) = sqrt(sum(diff**2, 2))
205 norm1(:, 1) = maxval(abs(use_data1), 2)
206 abs_err(:, 1) = maxval(abs(diff), 2)
211 allocate(norm1(1,
size(diff, 2)))
212 allocate(abs_err(1,
size(diff, 2)))
215 norm1(1, :) = sum(abs(use_data1), 1)
216 abs_err(1, :) = sum(abs(diff), 1)
218 norm1(1, :) = sqrt(sum(use_data1**2, 1))
219 abs_err(1, :) = sqrt(sum(diff**2, 1))
221 norm1(1, :) = maxval(abs(use_data1), 1)
222 abs_err(1, :) = maxval(abs(diff), 1)
227 allocate(norm1(
size(diff, 1),
size(diff, 2)))
228 allocate(abs_err(
size(diff, 1),
size(diff, 2)))
229 norm1(:, :) = abs(use_data1)
230 abs_err(:, :) = abs(diff)
235 allocate(rel_err(
size(abs_err, 1),
size(abs_err, 2)))
237 rel_err = abs_err / norm1
242 if ((abs_tol <= 0d0) .and. (rel_tol <= 0d0))
then
244 elseif (((abs_tol <= 0d0) .or. all(abs_err < abs_tol)) &
245 .and. ((rel_tol <= 0d0) .or. all(rel_err < rel_tol)))
then
246 write(*,
'(a)')
'files match within the given relative tolerance'
248 write(*,
'(a)')
'files differ'
268 write(*,
'(a)')
'Usage: numeric_diff [options] <reference_file> <test_file>'
270 write(*,
'(a)')
'options are:'
271 write(*,
'(a)')
' -h, --help Print this help message.'
272 write(*,
'(a)')
' -t, --abs-tol <N> Absolute error tolerance.'
273 write(*,
'(a)')
' -T, --rel-tol <N> Relative error tolerance.'
274 write(*,
'(a)')
' -r, --min-row <N> Minimum row number of data to use.'
275 write(*,
'(a)')
' -R, --max-row <N> Maximum row number of data to use.'
276 write(*,
'(a)')
' -c, --min-col <N> Minimum column number of data to ' &
278 write(*,
'(a)')
' -C, --max-col <N> Maximum column number of data to ' &
280 write(*,
'(a)')
' -b, --by <S> Compute error by <S>. <S> is one ' &
281 //
'of "array", "row",'
282 write(*,
'(a)')
' "col", or "elem". Default: "array".'
283 write(*,
'(a)')
' -n, --norm <S> Compute error with norm <S>. <S> ' &
284 //
'is one of "one",'
285 write(*,
'(a)')
' "two", or "sup". Default: "two".'
287 write(*,
'(a)')
'Examples:'
288 write(*,
'(a)')
' numeric_diff --rel-tol 1e-3 ref_data.txt test_data.txt'
289 write(*,
'(a)')
' numeric_diff --by col --rel-tol 1e-6 --min-col 2 ' &
290 //
'ref_data.txt test_data.txt'
300 real(kind=dp) :: abs_err(:,:)
302 real(kind=dp) :: rel_err(:,:)
304 integer :: i_row, i_col
305 character(len=3) :: advance
307 call
assert(434301862, (
size(abs_err, 1) ==
size(rel_err, 1)) &
308 .and. (
size(abs_err, 2) ==
size(rel_err, 2)))
310 if ((
size(abs_err, 1) == 1) .and. (
size(abs_err, 2) <= 5))
then
316 write(*,
'(a)', advance=advance)
'absolute error: '
317 do i_row = 1,
size(abs_err, 1)
318 do i_col = 1,
size(abs_err, 2)
319 write(*,
'(e12.3)', advance=
'no') abs_err(i_row, i_col)
323 write(*,
'(a)', advance=advance)
'relative error: '
324 do i_row = 1,
size(abs_err, 1)
325 do i_col = 1,
size(abs_err, 2)
326 write(*,
'(e12.3)', advance=
'no') rel_err(i_row, i_col)
331 if ((
size(abs_err, 1) > 1) .or. (
size(abs_err, 2) > 1))
then
332 write(*,
'(a,e12.3)')
'maximum absolute error: ', maxval(abs_err)
333 write(*,
'(a,e12.3)')
'maximum relative error: ', maxval(rel_err)
subroutine die_msg(code, error_msg)
Error immediately.
character function getopt(optstring, longopts)
subroutine print_errors(abs_err, rel_err)
subroutine assert_msg(code, condition_ok, error_msg)
Errors unless condition_ok is true.
subroutine pmc_mpi_finalize()
Shut down MPI.
subroutine pmc_mpi_init()
Initialize MPI.
integer function string_to_integer(string)
Convert a string to an integer.
Common utility subroutines.
Wrapper functions for MPI.
program numeric_diff
Compare two files containing numerical arrays and check whether they are the same as each other...
subroutine die(code)
Error immediately.
subroutine loadtxt(filename, data)
Load a real array from a text file.
subroutine assert(code, condition_ok)
Errors unless condition_ok is true.
real(kind=dp) function string_to_real(string)
Convert a string to a real.