1 | #!/bin/env python |
---|
2 | |
---|
3 | """ |
---|
4 | Program to verify that the output of Dave Burbidge's FORTRAN programs |
---|
5 | (list_quakes.f90 and get_multimux.f90) are the same as from the python |
---|
6 | replacement programs. |
---|
7 | |
---|
8 | This program will *not* run under Windows! |
---|
9 | """ |
---|
10 | |
---|
11 | import sys |
---|
12 | if sys.platform == 'win32': |
---|
13 | print 'Sorry, this program cannot run under Windows' |
---|
14 | sys.exit(10) |
---|
15 | import os |
---|
16 | import os.path |
---|
17 | import glob |
---|
18 | import re |
---|
19 | import EventSelection as es |
---|
20 | |
---|
21 | # Regions we are going to check in |
---|
22 | RegionNames = ['Australia', 'Indian', 'SW_Pacific'] |
---|
23 | |
---|
24 | # where the data files live (Unix/Linux) |
---|
25 | BaseDirectory = '/nas/gemd/georisk_models/tsunami/models/PTHA' |
---|
26 | |
---|
27 | # where the FORTRAN programs live and full program pathnames |
---|
28 | FTNDir = '/nas/gemd/georisk_models/tsunami/models/template/event_selection' |
---|
29 | FTN_list_quakes = os.path.join(FTNDir, 'list_quakes_solaris') |
---|
30 | FTN_get_multimux = os.path.join(FTNDir, 'get_multimux_solaris') |
---|
31 | |
---|
32 | # 'T' files directory |
---|
33 | TFilesDir = 'Tfiles' |
---|
34 | |
---|
35 | # 'multimux' directory |
---|
36 | MultimuxDir = 'multimux' |
---|
37 | |
---|
38 | # invall filename |
---|
39 | InvallFilename = 'i_invall' |
---|
40 | |
---|
41 | # file containing FORTRAN list_quakes input data |
---|
42 | FTN_list_quakes_inputfile = 'lq_input' |
---|
43 | |
---|
44 | # min and max wave heights used, along with step value |
---|
45 | MinWaveHeight = 0.3 |
---|
46 | MaxWaveHeight = 1.6 |
---|
47 | StepWaveHeight = 0.2 |
---|
48 | |
---|
49 | # accuracy to decide of two numbers are equal |
---|
50 | Epsilon = 0.0001 |
---|
51 | |
---|
52 | # regular expression pattern to split a line on multiple spaces |
---|
53 | SpacesPattern = re.compile(' +') |
---|
54 | |
---|
55 | |
---|
56 | ## |
---|
57 | # @brief Compare the list_quake output files, FORTRAN and python. |
---|
58 | # @param gn The guage number. |
---|
59 | # @param min_wh The minimum wave height. |
---|
60 | # @param max_wh The maximum wave height. |
---|
61 | # @note Writes to stdout if there is a difference. |
---|
62 | def list_quake_compare(gn, min_wh, max_wh): |
---|
63 | # first, check for outut files identical |
---|
64 | faultxy_OK = (os.system('diff fault.xy.py fault.xy >/dev/null 2>&1') == 0) |
---|
65 | quake_prob_OK = (os.system('diff quake_prob.txt.py quake_prob.txt >/dev/null 2>&1') == 0) |
---|
66 | if faultxy_OK and quake_prob_OK: |
---|
67 | return |
---|
68 | |
---|
69 | # set error message |
---|
70 | error = None |
---|
71 | |
---|
72 | # now check for logical equality |
---|
73 | if not faultxy_OK: |
---|
74 | # if no output from FORTRAN list_quakes, python must be 1 line exactly (header) |
---|
75 | if not os.path.exists('fault.xy'): |
---|
76 | fd = open('fault.xy.py', 'r') |
---|
77 | lines = fd.readlines() |
---|
78 | fd.close() |
---|
79 | if len(lines) != 1: |
---|
80 | error = error + ', ' + 'fault.xy' |
---|
81 | else: |
---|
82 | # same number of lines? |
---|
83 | fd = open('fault.xy.py', 'r') |
---|
84 | py_lines = fd.readlines() |
---|
85 | fd.close() |
---|
86 | fd = open('fault.xy', 'r') |
---|
87 | ftn_lines = fd.readlines() |
---|
88 | fd.close() |
---|
89 | if len(py_lines) != len(ftn_lines): |
---|
90 | error = 'fault.xy' |
---|
91 | else: |
---|
92 | # check logical difference - should never be different |
---|
93 | raise RuntimeError, "Can't get here!?" |
---|
94 | |
---|
95 | if not quake_prob_OK: |
---|
96 | # if no output from FORTRAN list_quakes, python must be 1 line exactly (header) |
---|
97 | if not os.path.exists('quake_prob.txt'): |
---|
98 | fd = open('quake_prob.txt.py', 'r') |
---|
99 | lines = fd.readlines() |
---|
100 | fd.close() |
---|
101 | if len(lines) != 1: |
---|
102 | error = error + ', ' + 'quake_prob.txt (1)' |
---|
103 | else: |
---|
104 | # same number of lines? |
---|
105 | fd = open('quake_prob.txt.py', 'r') |
---|
106 | py_lines = fd.readlines() |
---|
107 | fd.close() |
---|
108 | fd = open('quake_prob.txt', 'r') |
---|
109 | ftn_lines = fd.readlines() |
---|
110 | fd.close() |
---|
111 | if len(py_lines) != len(ftn_lines): |
---|
112 | if error: |
---|
113 | error += ', quake_prob.txt (2)' |
---|
114 | else: |
---|
115 | error = 'quake_prob.txt (2)' |
---|
116 | else: |
---|
117 | # files are textually different, check for logical difference |
---|
118 | py_data = read_qp_data(py_lines) |
---|
119 | ftn_data = read_qp_data(ftn_lines) |
---|
120 | if not cmp_qp_data(py_data, ftn_data, Epsilon): |
---|
121 | if error: |
---|
122 | error += ', quake_prob.txt (3)' |
---|
123 | else: |
---|
124 | error = 'quake_prob.txt (3)' |
---|
125 | |
---|
126 | if error: |
---|
127 | print 'Gauge=%d, min=%.1f, max=%.1f, file differ: %s' % (gn, min_wh, max_wh, error) |
---|
128 | |
---|
129 | def read_qp_data(lines): |
---|
130 | data = [lines[0]] |
---|
131 | for l in lines[1:]: |
---|
132 | (_, v1, v2, v3, v4) = re.split(SpacesPattern, l) |
---|
133 | data.append((int(v1), float(v2), float(v3), float(v4))) |
---|
134 | return data |
---|
135 | |
---|
136 | |
---|
137 | def cmp_qp_data(d1, d2, eps): |
---|
138 | # now check each numeric tuple - (%d, %f, %f, %f) |
---|
139 | # headers should be identical |
---|
140 | z = zip(d1[1:], d2[1:]) |
---|
141 | for (t1, t2) in z: |
---|
142 | (d1, f11, f12, f13) = t1 |
---|
143 | (d2, f21, f22, f23) = t2 |
---|
144 | if (d1 != d2) or (f11 != f21) or (f12 != f22) or (f13 != f23): |
---|
145 | print 'd1=%d, f11=%f, F12=%f, f13=%f' % (d1, f11, f12, f13) |
---|
146 | print 'd2=%d, f21=%f, F22=%f, f23=%f' % (d2, f21, f22, f23) |
---|
147 | sys.exit(0) |
---|
148 | return True |
---|
149 | |
---|
150 | |
---|
151 | def main(): |
---|
152 | for r in RegionNames: |
---|
153 | r_dir = os.path.join(BaseDirectory, r) |
---|
154 | if not os.path.exists(r_dir): |
---|
155 | print "Sorry, region '%s' doesn't exist" % r |
---|
156 | continue |
---|
157 | # link to i_invall file |
---|
158 | invall_file = os.path.join(r_dir, MultimuxDir, InvallFilename) |
---|
159 | os.system('rm -f %s' % InvallFilename) |
---|
160 | os.system('ln -s %s %s' % (invall_file, InvallFilename)) |
---|
161 | |
---|
162 | # get tide gauge numbers, if none, goto next region |
---|
163 | tf_dir = os.path.join(r_dir, TFilesDir) |
---|
164 | tf_dir_mask = os.path.join(tf_dir, 'T-[0-9]*') |
---|
165 | tgn_files = [os.path.basename(x) for x in glob.glob(tf_dir_mask)] |
---|
166 | if not tgn_files: |
---|
167 | print "No T files for region '%s'" % r_dir |
---|
168 | continue |
---|
169 | |
---|
170 | # now cycle through all T files |
---|
171 | for t in tgn_files: |
---|
172 | t_file = os.path.join(tf_dir, t) |
---|
173 | # link to T file |
---|
174 | os.system('rm -f %s' % t) |
---|
175 | os.system('ln -s %s %s' % (t_file, t)) |
---|
176 | |
---|
177 | gn = int(t[2:]) |
---|
178 | min_wh = MinWaveHeight |
---|
179 | while min_wh <= MaxWaveHeight: |
---|
180 | max_wh = min_wh |
---|
181 | while max_wh <= MaxWaveHeight: |
---|
182 | # run the python list_quakes |
---|
183 | es.list_quakes(gn, min_wh, max_wh, invall_file, t_file, 'fault.xy.py', 'quake_prob.txt.py') |
---|
184 | # run the FORTRAN list_quakes |
---|
185 | fin = open(FTN_list_quakes_inputfile, 'w') |
---|
186 | fin.write('%d\n' % gn) |
---|
187 | fin.write('%.1f\n' % min_wh) |
---|
188 | fin.write('%.1f\n' % max_wh) |
---|
189 | fin.close() |
---|
190 | # print '%s < %s >/dev/null' % (FTN_list_quakes, FTN_list_quakes_inputfile) |
---|
191 | os.system('rm -f fault.xy quake_prob.txt') |
---|
192 | os.system('%s < %s >/dev/null' % (FTN_list_quakes, FTN_list_quakes_inputfile)) |
---|
193 | # compare list_quakes output |
---|
194 | print '%s %d, %.1f, %.1f' % (r, gn, min_wh, max_wh) |
---|
195 | list_quake_compare(gn, min_wh, max_wh) |
---|
196 | max_wh += StepWaveHeight |
---|
197 | min_wh += StepWaveHeight |
---|
198 | os.system('rm -f %s' % t) |
---|
199 | |
---|
200 | if __name__ == '__main__': |
---|
201 | sys.exit(main()) |
---|