source: sasmodels/sasmodels/model_test.py @ 3c56da87

core_shell_microgelscostrafo411magnetic_modelrelease_v0.94release_v0.95ticket-1257-vesicle-productticket_1156ticket_1265_superballticket_822_more_unit_tests
Last change on this file since 3c56da87 was 3c56da87, checked in by Paul Kienzle <pkienzle@…>, 9 years ago

lint cleanup

  • Property mode set to 100644
File size: 7.6 KB
Line 
1# -*- coding: utf-8 -*-
2"""
3Run model unit tests.
4
5Usage::
6
7    python -m sasmodels.model_test [opencl|dll|opencl_and_dll] model1 model2 ...
8
9    if model1 is 'all', then all except the remaining models will be tested
10
11Each model is tested using the default parameters at q=0.1, (qx,qy)=(0.1,0.1),
12and the ER and VR are computed.  The return values at these points are not
13considered.  The test is only to verify that the models run to completion,
14and do not produce inf or NaN.
15
16Tests are defined with the *tests* attribute in the model.py file.  *tests*
17is a list of individual tests to run, where each test consists of the
18parameter values for the test, the q-values and the expected results.  For
19the effective radius test, the q-value should be 'ER'.  For the VR test,
20the q-value should be 'VR'.  For 1-D tests, either specify the q value or
21a list of q-values, and the corresponding I(q) value, or list of I(q) values.
22
23That is::
24
25    tests = [
26        [ {parameters}, q, I(q)],
27        [ {parameters}, [q], [I(q)] ],
28        [ {parameters}, [q1, q2, ...], [I(q1), I(q2), ...]],
29
30        [ {parameters}, (qx, qy), I(qx, Iqy)],
31        [ {parameters}, [(qx1, qy1), (qx2, qy2), ...],
32                        [I(qx1,qy1), I(qx2,qy2), ...]],
33
34        [ {parameters}, 'ER', ER(pars) ],
35        [ {parameters}, 'VR', VR(pars) ],
36        ...
37    ]
38
39Parameters are *key:value* pairs, where key is one of the parameters of the
40model and value is the value to use for the test.  Any parameters not given
41in the parameter list will take on the default parameter value.
42
43Precision defaults to 5 digits (relative).
44"""
45
46import sys
47import unittest
48
49import numpy as np
50
51from .core import list_models, load_model_definition
52from .core import load_model_cl, load_model_dll
53from .core import make_kernel, call_kernel, call_ER, call_VR
54
55def annotate_exception(exc, msg):
56    """
57    Add an annotation to the current exception, which can then be forwarded
58    to the caller using a bare "raise" statement to reraise the annotated
59    exception.
60    Example::
61        >>> D = {}
62        >>> try:
63        ...    print D['hello']
64        ... except Exception,exc:
65        ...    annotate_exception(exc, "while accessing 'D'")
66        ...    raise
67        Traceback (most recent call last):
68            ...
69        KeyError: "hello while accessing 'D'"
70    """
71    args = exc.args
72    if not args:
73        exc.args = (msg,)
74    else:
75        try:
76            arg0 = " ".join((args[0],msg))
77            exc.args = tuple([arg0] + list(args[1:]))
78        except:
79            exc.args = (" ".join((str(exc),msg)),)
80
81def make_suite(loaders, models):
82
83    ModelTestCase = _hide_model_case_from_nosetests()
84    suite = unittest.TestSuite()
85
86    if models[0] == 'all':
87        skip = models[1:]
88        models = list_models()
89    else:
90        skip = []
91    for model_name in models:
92        if model_name in skip: continue
93        model_definition = load_model_definition(model_name)
94
95        smoke_tests = [
96            [{},0.1,None],
97            [{},(0.1,0.1),None],
98            [{},'ER',None],
99            [{},'VR',None],
100            ]
101        tests = smoke_tests + getattr(model_definition, 'tests', [])
102
103        if tests: # in case there are no smoke tests...
104            #print '------'
105            #print 'found tests in', model_name
106            #print '------'
107
108            # if ispy then use the dll loader to call pykernel
109            # don't try to call cl kernel since it will not be
110            # available in some environmentes.
111            ispy = callable(getattr(model_definition,'Iq', None))
112
113            # test using opencl if desired
114            if not ispy and ('opencl' in loaders and load_model_cl):
115                test_name = "Model: %s, Kernel: OpenCL"%model_name
116                test = ModelTestCase(test_name, model_definition,
117                                     load_model_cl, tests)
118                #print "defining", test_name
119                suite.addTest(test)
120
121            # test using dll if desired
122            if ispy or ('dll' in loaders and load_model_dll):
123                test_name = "Model: %s, Kernel: dll"%model_name
124                test = ModelTestCase(test_name, model_definition,
125                                     load_model_dll, tests)
126                #print "defining", test_name
127                suite.addTest(test)
128
129    return suite
130
131def _hide_model_case_from_nosetests():
132    class ModelTestCase(unittest.TestCase):
133        def __init__(self, test_name, definition, loader, tests):
134            unittest.TestCase.__init__(self)
135
136            self.test_name = test_name
137            self.definition = definition
138            self.loader = loader
139            self.tests = tests
140
141        def runTest(self):
142            try:
143                model = self.loader(self.definition)
144                for test in self.tests:
145                    self._run_one_test(model, test)
146
147            except Exception,exc:
148                annotate_exception(exc, self.test_name)
149                raise
150
151        def _run_one_test(self, model, test):
152            pars, x, y = test
153
154            if not isinstance(y, list):
155                y = [y]
156            if not isinstance(x, list):
157                x = [x]
158
159            self.assertEqual(len(y), len(x))
160
161            if x[0] == 'ER':
162                actual = [call_ER(model.info, pars)]
163            elif x[0] == 'VR':
164                actual = [call_VR(model.info, pars)]
165            elif isinstance(x[0], tuple):
166                Qx,Qy = zip(*x)
167                q_vectors = [np.array(Qx), np.array(Qy)]
168                kernel = make_kernel(model, q_vectors)
169                actual = call_kernel(kernel, pars)
170            else:
171                q_vectors = [np.array(x)]
172                kernel = make_kernel(model, q_vectors)
173                actual = call_kernel(kernel, pars)
174
175            self.assertGreater(len(actual), 0)
176            self.assertEqual(len(y), len(actual))
177
178            for xi, yi, actual_yi in zip(x, y, actual):
179                if yi is None:
180                    # smoke test --- make sure it runs and produces a value
181                    self.assertTrue(np.isfinite(actual_yi),
182                        'invalid f(%s): %s' % (xi, actual_yi))
183                else:
184                    err = abs(yi - actual_yi)
185                    nrm = abs(yi)
186                    self.assertLess(err * 10**5, nrm,
187                        'f(%s); expected:%s; actual:%s' % (xi, yi, actual_yi))
188
189    return ModelTestCase
190
191
192# let nosetests sniff out the tests
193def model_tests():
194    tests = make_suite(['opencl','dll'],['all'])
195    for test_i in tests:
196        yield test_i.runTest
197
198def main():
199    models = sys.argv[1:]
200    if models and models[0] == 'opencl':
201        if load_model_cl is None:
202            print >>sys.stderr, "opencl is not available"
203            return 1
204        loaders = ['opencl']
205        models = models[1:]
206    elif models and models[0] == 'dll':
207        # TODO: test if compiler is available?
208        loaders = ['dll']
209        models = models[1:]
210    elif models and models[0] == 'opencl_and_dll':
211        if load_model_cl is None:
212            print >>sys.stderr, "opencl is not available"
213            return 1
214        loaders = ['opencl', 'dll']
215        models = models[1:]
216    else:
217        loaders = ['opencl', 'dll']
218    if not models:
219        print >>sys.stderr, "usage: python -m sasmodels.model_test [opencl|dll|opencl_and_dll] model1 model2 ..."
220        print >>sys.stderr, "if model1 is 'all', then all except the remaining models will be tested"
221        return 1
222
223    #run_tests(loaders, models)
224    runner = unittest.TextTestRunner()
225    result = runner.run(make_suite(loaders, models))
226    return 1 if result.failures or result.errors else 0
227
228if __name__ == "__main__":
229    sys.exit(main())
Note: See TracBrowser for help on using the repository browser.