1 | #!/usr/bin/env python |
---|
2 | |
---|
3 | import sys |
---|
4 | |
---|
5 | import numpy as np |
---|
6 | |
---|
7 | from sasmodels.gpu import environment |
---|
8 | from compare import (MODELS, randomize_model, suppress_pd, eval_sasview, |
---|
9 | eval_opencl, eval_ctypes, make_data) |
---|
10 | |
---|
11 | def get_stats(target, value, index): |
---|
12 | resid = abs(value-target)[index] |
---|
13 | relerr = resid/target[index] |
---|
14 | srel = np.argsort(relerr) |
---|
15 | p90 = int(len(relerr)*0.90) |
---|
16 | p95 = int(len(relerr)*0.95) |
---|
17 | maxrel = np.max(relerr) |
---|
18 | rel95 = relerr[srel[p95]] |
---|
19 | maxabs = np.max(resid[srel[p95:]]) |
---|
20 | maxval = np.max(value[srel[p95:]]) |
---|
21 | return maxrel,rel95,maxabs,maxval |
---|
22 | |
---|
23 | def print_column_headers(pars, parts): |
---|
24 | stats = list('Max rel err|95% rel err|Max abs err above 90% rel|Max value above 90% rel'.split('|')) |
---|
25 | groups = [''] |
---|
26 | for p in parts: |
---|
27 | groups.append(p) |
---|
28 | groups.extend(['']*(len(stats)-1)) |
---|
29 | columns = ['Seed'] + stats*len(parts) + list(sorted(pars.keys())) |
---|
30 | print(','.join('"%s"'%c for c in groups)) |
---|
31 | print(','.join('"%s"'%c for c in columns)) |
---|
32 | |
---|
33 | def compare_instance(model, data, index, N=1, mono=True, cutoff=1e-5): |
---|
34 | name, pars = MODELS[model]() |
---|
35 | header = '\n"Model","%s","Count","%d"'%(name, N) |
---|
36 | if not mono: header += ',"Cutoff",%g'%(cutoff,) |
---|
37 | print(header) |
---|
38 | first = True |
---|
39 | for _ in range(N): |
---|
40 | pars, seed = randomize_model(name, pars) |
---|
41 | if mono: suppress_pd(pars) |
---|
42 | |
---|
43 | target, _ = eval_sasview(name, pars, data) |
---|
44 | |
---|
45 | env = environment() |
---|
46 | gpu_single_value,_ = eval_opencl(name, pars, data, dtype='single', cutoff=cutoff) |
---|
47 | gpu_single = get_stats(target, gpu_single_value, index) |
---|
48 | if env.has_double: |
---|
49 | gpu_double_value,_ = eval_opencl(name, pars, data, dtype='double', cutoff=cutoff) |
---|
50 | gpu_double = get_stats(target, gpu_double_value, index) |
---|
51 | else: |
---|
52 | gpu_double = [0]*len(gpu_single) |
---|
53 | cpu_double_value,_ = eval_ctypes(name, pars, data, dtype='double', cutoff=cutoff) |
---|
54 | cpu_double = get_stats(target, cpu_double_value, index) |
---|
55 | single_double = get_stats(cpu_double_value, gpu_single_value, index) |
---|
56 | |
---|
57 | values = (list(gpu_single) + list(gpu_double) + list(cpu_double) |
---|
58 | + list(single_double) + [v for _,v in sorted(pars.items())]) |
---|
59 | if gpu_single[0] > 5e-5: |
---|
60 | if first: |
---|
61 | print_column_headers(pars,'GPU single|GPU double|CPU double|single/double'.split('|')) |
---|
62 | first = False |
---|
63 | print(("%d,"%seed)+','.join("%g"%v for v in values)) |
---|
64 | |
---|
65 | def main(): |
---|
66 | try: |
---|
67 | model = sys.argv[1] |
---|
68 | assert (model in MODELS) or (model == "all") |
---|
69 | count = int(sys.argv[2]) |
---|
70 | is2D = sys.argv[3].startswith('2d') |
---|
71 | assert sys.argv[3][1] == 'd' |
---|
72 | Nq = int(sys.argv[3][2:]) |
---|
73 | mono = sys.argv[4] == 'mono' |
---|
74 | cutoff = float(sys.argv[4]) if not mono else 0 |
---|
75 | except: |
---|
76 | import traceback; traceback.print_exc() |
---|
77 | models = "\n ".join("%-7s: %s"%(k,v.__name__.replace('_',' ')) |
---|
78 | for k,v in sorted(MODELS.items())) |
---|
79 | print("""\ |
---|
80 | usage: compare_many.py MODEL COUNT (1dNQ|2dNQ) (CUTOFF|mono) |
---|
81 | |
---|
82 | MODEL is the model name of the model, which is one of: |
---|
83 | %s |
---|
84 | or "all" for all the models in alphabetical order. |
---|
85 | |
---|
86 | COUNT is the number of randomly generated parameter sets to try. A value |
---|
87 | of "10000" is a reasonable check for monodisperse models, or "100" for |
---|
88 | polydisperse models. For a quick check, use "100" and "5" respectively. |
---|
89 | |
---|
90 | NQ is the number of Q values to calculate. If it starts with "1d", then |
---|
91 | it is a 1-dimensional problem, with log spaced Q points from 1e-3 to 1.0. |
---|
92 | If it starts with "2d" then it is a 2-dimensional problem, with linearly |
---|
93 | spaced points Q points from -1.0 to 1.0 in each dimension. The usual |
---|
94 | values are "1d100" for 1-D and "2d32" for 2-D. |
---|
95 | |
---|
96 | CUTOFF is the cutoff value to use for the polydisperse distribution. Weights |
---|
97 | below the cutoff will be ignored. Use "mono" for monodisperse models. The |
---|
98 | choice of polydisperse parameters, and the number of points in the distribution |
---|
99 | is set in compare.py defaults for each model. |
---|
100 | """%(models,)) |
---|
101 | sys.exit(1) |
---|
102 | |
---|
103 | data, index = make_data(qmax=1.0, is2D=is2D, Nq=Nq) |
---|
104 | model_list = [model] if model != "all" else list(sorted(MODELS.keys())) |
---|
105 | for model in model_list: |
---|
106 | compare_instance(model, data, index, N=count, mono=mono, cutoff=cutoff) |
---|
107 | |
---|
108 | if __name__ == "__main__": |
---|
109 | main() |
---|