-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathcprnc.F90
312 lines (275 loc) · 11.7 KB
/
cprnc.F90
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
program piocprnc
use netcdf
use filestruct
use compare_vars_mod
#ifdef NAGFOR
use f90_unix
#endif
implicit none
include "version.inc"
integer :: nargs, n
character(len=1024) :: arg = '' ! cmd-line argument
character(len=1024) :: fname(2) = ' ' ! input filenames
integer :: nchars
integer :: numcases=1
integer :: ierr
! integer, external :: iargc
type(file_t) :: file(2)
type(dim_t) :: dimoptions(12)
integer :: dimoptioncnt
integer :: nvars, ndiffs, nfilldiffs
! The following variables count the number of fields found on one file but not the
! other, only considering (a) fields with an unlimited (time) dimension, and (b) fields
! without an unlimited (time) dimension on a file that doesn't have an unlimited
! dimension.
integer :: num_not_found_on_file1, num_not_found_on_file2
! The following variables count the number of fields found on one file but not the
! other, only considering fields without an unlimited (time) dimension on a file that
! has an unlimited dimension.
integer :: num_not_found_on_file1_timeconst, num_not_found_on_file2_timeconst
integer :: num_sizes_differ
integer :: num_types_differ
integer :: num_not_analyzed
!
! Parse arg list
!
nargs = command_argument_count ()
dimoptioncnt=0
ignoretime=.false.
n = 1
do while (n <= nargs)
arg = ' '
call getarg (n, arg)
n = n + 1
select case (arg)
case ('-V')
print *,"cprnc version:", version
stop
case ('-v')
verbose = .true.
case ('-d')
call getarg(n, arg)
n=n+1
dimoptioncnt=dimoptioncnt+1
call parsearg(arg, dimoptions(dimoptioncnt)%name, dimoptions(dimoptioncnt)%start, dimoptions(dimoptioncnt)%kount)
case ('-m')
ignoretime=.true.
case default
if (fname(1) == ' ') then
fname(1) = arg(1:len_trim(arg))
nchars = len_trim (fname(1))
write (6,*) 'file 1=',fname(1)(1:nchars)
else if (fname(2)==' ') then
fname(2) = arg(1:len_trim(arg))
nchars = len_trim (fname(2))
write (6,*) 'file 2=',fname(2)(1:nchars)
numcases = 2
else
call usage_exit (' ')
end if
end select
end do
!
! Must have at least 1 file input
!
if (fname(1) == ' ') then
call usage_exit ('You must enter at least 1 input file')
end if
!
! Read the files and initialize file_t
!
do n=1, numcases
ierr = nf90_open(fname(n),NF90_NOWRITE, file(n)%fh)
if(ierr /= NF90_NOERR) then
stop 'Failed to open file '
endif
if(dimoptioncnt>0) then
call init_file_struct( file(n), dimoptions(1:dimoptioncnt) )
else
call init_file_struct( file(n))
end if
end do
if(numcases==2) then
call compare_metadata(file(1), file(2))
call compare_dimensions( file(1)%dim, file(2)%dim)
num_not_found_on_file1 = 0
num_not_found_on_file2 = 0
num_not_found_on_file1_timeconst = 0
num_not_found_on_file2_timeconst = 0
call match_vars( file(1), file(2), &
num_not_found_on_file1 = num_not_found_on_file1, &
num_not_found_on_file2 = num_not_found_on_file2, &
num_not_found_on_file1_timeconst = num_not_found_on_file1_timeconst, &
num_not_found_on_file2_timeconst = num_not_found_on_file2_timeconst)
end if
call compare_vars(numcases, file, nvars, ndiffs, nfilldiffs, &
num_sizes_differ, num_not_analyzed, num_types_differ)
!
! Summarize results
!
write(6,806)
write(6,*) ' '
write(6,700) 'SUMMARY of cprnc:'
if(numcases==1) then
write(6,700) ' A total number of ',nvars,' fields in file 1 were analyzed (non-compare mode)'
write(6,700) ' A total number of ',num_not_analyzed, &
' fields in file 1 could not be analyzed'
else
write(6,700) ' A total number of ',nvars,' fields were compared'
write(6,700) ' of which ',ndiffs,' had non-zero differences'
write(6,700) ' and ',nfilldiffs,' had differences in fill patterns'
write(6,700) ' and ',num_sizes_differ,' had different dimension sizes'
write(6,700) ' and ',num_types_differ,' had different data types'
write(6,700) ' A total number of ',num_sizes_differ + num_not_analyzed, &
' fields could not be analyzed'
call print_fields_not_found( &
filenum = 1, &
file_has_unlimited_dim = file(1)%has_unlimited_dim(), &
num_not_found = num_not_found_on_file2, &
num_not_found_timeconst = num_not_found_on_file2_timeconst)
call print_fields_not_found( &
filenum = 2, &
file_has_unlimited_dim = file(2)%has_unlimited_dim(), &
num_not_found = num_not_found_on_file1, &
num_not_found_timeconst = num_not_found_on_file1_timeconst)
if (nvars == 0 .or. ndiffs > 0 .or. nfilldiffs > 0 .or. &
num_sizes_differ > 0 .or. num_not_analyzed >= nvars .or. &
num_types_differ > 0) then
write(6,700) ' diff_test: the two files seem to be DIFFERENT '
else if (num_not_found_on_file1 > 0 .or. num_not_found_on_file2 > 0) then
! Note that we deliberately allow num_not_found_on_file1_timeconst or
! num_not_found_on_file2_timeconst to be > 0: those do NOT result in a
! "DIFFER" result.
!
! Ideally, we'd count those fields here, too. Doing so would catch more
! differences and would simplify the cprnc code. But this sometimes leads to
! problems when comparing restart vs. baseline files
! (https://github.com/ESMCI/cime/issues/3007). We could add a flag that you
! specify to not count these fields, but there are backwards compatibility
! issues with doing so. Eventually it could be good to count these absent
! fields as a DIFFER result by default, adding a flag that you can specify to
! not count them, then have cime specify this flag when doing the in-test
! comparison (so absent time-constant fields would result in a DIFFER result
! for cime's baseline comparisons and for interactive use of cprnc).
write(6,'(a)') ' diff_test: the two files DIFFER only in their field lists'
else
write(6,700) ' diff_test: the two files seem to be IDENTICAL '
if (num_not_found_on_file1_timeconst > 0 .or. &
num_not_found_on_file2_timeconst > 0) then
write(6,'(a)') ' (But note that there were differences in field lists just for time-constant fields.)'
end if
end if
end if
write(6,*) ' '
700 format(a,i6,a)
806 format(132('*'))
contains
subroutine usage_exit (arg)
implicit none
character(len=*), intent(in) :: arg
if (arg /= ' ') write (6,*) arg
write(6,*)'Usage: cprnc [-m] [-v] [-d dimname:start[:count]] file1 [file2]'
write(6,*)'-v: Verbose output'
write(6,*)'-m: Ignore time variable and just match contents (default is to match the values in variable time.)'
write(6,*)'-d dimname:start[:count]: Print variable values for the specified dimension index start and count. If not present,'
write(6,*)' count will default to 1. If count is < 0 then count will be set to dimsize-start'
write(6,*)' '
stop 999
end subroutine usage_exit
subroutine parsearg (arg, dimname, v1, v2)
!-------------------------------------------------------------------------------------------
! Purpose: Parse cmd line args about printing.
!
! Method: Input is expected in the form: dimname:number1[:number2] where dimname is expected to
! be the name of a dimension in the input file(s), number1 is the starting position in that
! dimension to be evaluated and number2 is the number of values to read in the dimension
! if number2 is missing all remaining values are read.
!
!-------------------------------------------------------------------------------------------
implicit none
character(len=*), intent(in) :: arg ! cmd line arg expected of the form 'num1:num2' or 'num1'
character(len=*), intent(out) :: dimname
integer, intent(out) :: v1 ! e.g. num1 from above example
integer, intent(out) :: v2 ! e.g. num2 from above example
integer :: i, j ! indices through arg
integer :: ierr ! io error status
!
! First get a dimension name
!
dimname = ' '
i = scan(arg,':')
dimname(1:i-1)=arg(1:i-1)
i=i+1
!
! now try to get an integer number for everything up to ":"
!
j=i
do while (j < len(arg) .and. arg(j:j) >= '0' .and. arg(j:j) <= '9' .and. arg(j:j) /= ':')
j = j + 1
end do
read (arg(i:j-1), '(i5)') v1
!
! Next, if ":" comes after the number, look for the next number
!
i=j
if (arg(i:i) == ':') then
j = i + 1
do while (j < len(arg) .and. scan(arg(j:j),"-0123456789")>0)
j = j + 1
end do
read (arg(i+1:j-1), '(i5)', iostat=ierr) v2
!
! On unexpected input set v2 = -1, e.g. "-d lon:2:blah" will mean get all lons > 1
!
if (ierr /= 0) then
v2 = -1
end if
else
!
! ":" not present. Interpret for example '-d lon:2' to mean '-d lon:2:1'
!
v2 = 1
end if
if(verbose) print *,__FILE__,__LINE__,trim(dimname),v1,v2
return
end subroutine parsearg
subroutine print_fields_not_found(filenum, file_has_unlimited_dim, &
num_not_found, num_not_found_timeconst)
! Prints information about the number of fields in filenum not found on the other file
integer, intent(in) :: filenum ! file number for which we're printing this information
logical, intent(in) :: file_has_unlimited_dim ! whether this file has an unlimited dimension
! Number of fields in filenum but not on the other file, only considering (a) fields
! with an unlimited (time) dimension, and (b) fields without an unlimited (time)
! dimension on a file that doesn't have an unlimited dimension
integer, intent(in) :: num_not_found
! Number of fields in filenum but not on the other file, only considering fields
! without an unlimited (time) dimension on a file that has an unlimited dimension
integer, intent(in) :: num_not_found_timeconst
integer :: other_filenum
if (filenum == 1) then
other_filenum = 2
else if (filenum == 2) then
other_filenum = 1
else
stop 'Unexpected value for filenum'
end if
if (file_has_unlimited_dim) then
write(6,'(a,i6,a,i1,a,i1,a)') &
' A total number of ', num_not_found, &
' time-varying fields on file ', filenum, &
' were not found on file ', other_filenum, '.'
write(6,'(a,i6,a,i1,a,i1,a)') &
' A total number of ', num_not_found_timeconst, &
' time-constant fields on file ', filenum, &
' were not found on file ', other_filenum, '.'
else
write(6,'(a,i6,a,i1,a,i1,a)') &
' A total number of ', num_not_found, &
' fields on file ', filenum, &
' were not found on file ', other_filenum, '.'
if (num_not_found_timeconst > 0) then
stop 'Programming error: file has no unlimited dimension, but num_not_found_timeconst > 0'
end if
end if
end subroutine print_fields_not_found
end program piocprnc