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 diff = use_data1 - use_data2
178 allocate(norm1(1, 1))
179 allocate(abs_err(1, 1))
182 norm1(1, 1) = sum(abs(use_data1))
183 abs_err(1, 1) = sum(abs(diff))
185 norm1(1, 1) = sqrt(sum(use_data1**2))
186 abs_err(1, 1) = sqrt(sum(diff**2))
188 norm1(1, 1) = maxval(abs(use_data1))
189 abs_err(1, 1) = maxval(abs(diff))
194 allocate(norm1(
size(diff, 1), 1))
195 allocate(abs_err(
size(diff, 1), 1))
198 norm1(:, 1) = sum(abs(use_data1), 2)
199 abs_err(:, 1) = sum(abs(diff), 2)
201 norm1(:, 1) = sqrt(sum(use_data1**2, 2))
202 abs_err(:, 1) = sqrt(sum(diff**2, 2))
204 norm1(:, 1) = maxval(abs(use_data1), 2)
205 abs_err(:, 1) = maxval(abs(diff), 2)
210 allocate(norm1(1,
size(diff, 2)))
211 allocate(abs_err(1,
size(diff, 2)))
214 norm1(1, :) = sum(abs(use_data1), 1)
215 abs_err(1, :) = sum(abs(diff), 1)
217 norm1(1, :) = sqrt(sum(use_data1**2, 1))
218 abs_err(1, :) = sqrt(sum(diff**2, 1))
220 norm1(1, :) = maxval(abs(use_data1), 1)
221 abs_err(1, :) = maxval(abs(diff), 1)
226 allocate(norm1(
size(diff, 1),
size(diff, 2)))
227 allocate(abs_err(
size(diff, 1),
size(diff, 2)))
228 norm1(:, :) = abs(use_data1)
229 abs_err(:, :) = abs(diff)
234 if (.not.
allocated(norm1))
then
238 allocate(rel_err(
size(abs_err, 1),
size(abs_err, 2)))
240 rel_err = abs_err / norm1
245 if ((abs_tol <= 0d0) .and. (rel_tol <= 0d0))
then
247 elseif (((abs_tol <= 0d0) .or. all(abs_err < abs_tol)) &
248 .and. ((rel_tol <= 0d0) .or. all(rel_err < rel_tol)))
then
249 write(*,
'(a)')
'files match within the given relative tolerance'
251 write(*,
'(a)')
'files differ'
264 write(*,
'(a)')
'Usage: numeric_diff [options] <reference_file> <test_file>'
266 write(*,
'(a)')
'options are:'
267 write(*,
'(a)')
' -h, --help Print this help message.'
268 write(*,
'(a)')
' -t, --abs-tol <N> Absolute error tolerance.'
269 write(*,
'(a)')
' -T, --rel-tol <N> Relative error tolerance.'
270 write(*,
'(a)')
' -r, --min-row <N> Minimum row number of data to use.'
271 write(*,
'(a)')
' -R, --max-row <N> Maximum row number of data to use.'
272 write(*,
'(a)')
' -c, --min-col <N> Minimum column number of data to ' &
274 write(*,
'(a)')
' -C, --max-col <N> Maximum column number of data to ' &
276 write(*,
'(a)')
' -b, --by <S> Compute error by <S>. <S> is one ' &
277 //
'of "array", "row",'
278 write(*,
'(a)')
' "col", or "elem". Default: "array".'
279 write(*,
'(a)')
' -n, --norm <S> Compute error with norm <S>. <S> ' &
280 //
'is one of "one",'
281 write(*,
'(a)')
' "two", or "sup". Default: "two".'
283 write(*,
'(a)')
'Examples:'
284 write(*,
'(a)')
' numeric_diff --rel-tol 1e-3 ref_data.txt test_data.txt'
285 write(*,
'(a)')
' numeric_diff --by col --rel-tol 1e-6 --min-col 2 ' &
286 //
'ref_data.txt test_data.txt'
296 real(kind=
dp) :: abs_err(:,:)
298 real(kind=
dp) :: rel_err(:,:)
300 integer :: i_row, i_col
301 character(len=3) :: advance
303 call assert(434301862, (
size(abs_err, 1) ==
size(rel_err, 1)) &
304 .and. (
size(abs_err, 2) ==
size(rel_err, 2)))
306 if ((
size(abs_err, 1) == 1) .and. (
size(abs_err, 2) <= 5))
then
312 write(*,
'(a)', advance=advance)
'absolute error: '
313 do i_row = 1,
size(abs_err, 1)
314 do i_col = 1,
size(abs_err, 2)
315 write(*,
'(e12.3)', advance=
'no') abs_err(i_row, i_col)
319 write(*,
'(a)', advance=advance)
'relative error: '
320 do i_row = 1,
size(abs_err, 1)
321 do i_col = 1,
size(abs_err, 2)
322 write(*,
'(e12.3)', advance=
'no') rel_err(i_row, i_col)
327 if ((
size(abs_err, 1) > 1) .or. (
size(abs_err, 2) > 1))
then
328 write(*,
'(a,e12.3)')
'maximum absolute error: ', maxval(abs_err)
329 write(*,
'(a,e12.3)')
'maximum relative error: ', maxval(rel_err)