source: sasmodels/sasmodels/model_test.py @ d1fe925

gh-pages
Last change on this file since d1fe925 was d1fe925, checked in by ajj, 8 years ago

Creating gh_pages branch for docs

  • Property mode set to 100644
File size: 7.4 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, load_model, HAVE_OPENCL
52from .core import make_kernel, call_kernel, call_ER, call_VR
53from .exception import annotate_exception
54
55
56def make_suite(loaders, models):
57
58    ModelTestCase = _hide_model_case_from_nosetests()
59    suite = unittest.TestSuite()
60
61    if models[0] == 'all':
62        skip = models[1:]
63        models = list_models()
64    else:
65        skip = []
66    for model_name in models:
67        if model_name in skip: continue
68        model_definition = load_model_definition(model_name)
69
70        smoke_tests = [
71            [{},0.1,None],
72            [{},(0.1,0.1),None],
73            [{},'ER',None],
74            [{},'VR',None],
75            ]
76        tests = smoke_tests + getattr(model_definition, 'tests', [])
77
78        if tests: # in case there are no smoke tests...
79            #print '------'
80            #print 'found tests in', model_name
81            #print '------'
82
83            # if ispy then use the dll loader to call pykernel
84            # don't try to call cl kernel since it will not be
85            # available in some environmentes.
86            ispy = callable(getattr(model_definition,'Iq', None))
87
88            # test using opencl if desired
89            if not ispy and ('opencl' in loaders and HAVE_OPENCL):
90                test_name = "Model: %s, Kernel: OpenCL"%model_name
91                test_method = "test_%s_opencl" % model_name
92                test = ModelTestCase(test_name, model_definition,
93                                     tests, test_method,
94                                     platform="ocl", dtype='single')
95                #print "defining", test_name
96                suite.addTest(test)
97
98            # test using dll if desired
99            if ispy or 'dll' in loaders:
100                test_name = "Model: %s, Kernel: dll"%model_name
101                test_method = "test_%s_dll" % model_name
102                test = ModelTestCase(test_name, model_definition,
103                                     tests, test_method,
104                                     platform="dll", dtype="double")
105                suite.addTest(test)
106
107    return suite
108
109
110def _hide_model_case_from_nosetests():
111    class ModelTestCase(unittest.TestCase):
112        def __init__(self, test_name, definition, tests, test_method,
113                     platform, dtype):
114            self.test_name = test_name
115            self.definition = definition
116            self.tests = tests
117            self.platform = platform
118            self.dtype = dtype
119
120            setattr(self, test_method, self._runTest)
121            unittest.TestCase.__init__(self, test_method)
122
123        def _runTest(self):
124            try:
125                model = load_model(self.definition, dtype=self.dtype,
126                                   platform=self.platform)
127                for test in self.tests:
128                    self._run_one_test(model, test)
129
130            except Exception,exc:
131                annotate_exception(exc, self.test_name)
132                raise
133
134        def _run_one_test(self, model, test):
135            pars, x, y = test
136
137            if not isinstance(y, list):
138                y = [y]
139            if not isinstance(x, list):
140                x = [x]
141
142            self.assertEqual(len(y), len(x))
143
144            if x[0] == 'ER':
145                actual = [call_ER(model.info, pars)]
146            elif x[0] == 'VR':
147                actual = [call_VR(model.info, pars)]
148            elif isinstance(x[0], tuple):
149                Qx,Qy = zip(*x)
150                q_vectors = [np.array(Qx), np.array(Qy)]
151                kernel = make_kernel(model, q_vectors)
152                actual = call_kernel(kernel, pars)
153            else:
154                q_vectors = [np.array(x)]
155                kernel = make_kernel(model, q_vectors)
156                actual = call_kernel(kernel, pars)
157
158            self.assertGreater(len(actual), 0)
159            self.assertEqual(len(y), len(actual))
160
161            for xi, yi, actual_yi in zip(x, y, actual):
162                if yi is None:
163                    # smoke test --- make sure it runs and produces a value
164                    self.assertTrue(np.isfinite(actual_yi),
165                        'invalid f(%s): %s' % (xi, actual_yi))
166                else:
167                    err = abs(yi - actual_yi)
168                    nrm = abs(yi)
169                    self.assertLess(err * 10**5, nrm,
170                        'f(%s); expected:%s; actual:%s' % (xi, yi, actual_yi))
171
172    return ModelTestCase
173
174
175
176def main():
177    """
178    Run tests given is sys.argv.
179
180    Returns 0 if success or 1 if any tests fail.
181    """
182    import xmlrunner
183
184    models = sys.argv[1:]
185    if models and models[0] == 'opencl':
186        if not HAVE_OPENCL:
187            print >>sys.stderr, "opencl is not available"
188            return 1
189        loaders = ['opencl']
190        models = models[1:]
191    elif models and models[0] == 'dll':
192        # TODO: test if compiler is available?
193        loaders = ['dll']
194        models = models[1:]
195    elif models and models[0] == 'opencl_and_dll':
196        loaders = ['opencl', 'dll']
197        models = models[1:]
198    else:
199        loaders = ['opencl', 'dll']
200    if not models:
201        print >>sys.stderr, "usage: python -m sasmodels.model_test [opencl|dll|opencl_and_dll] model1 model2 ..."
202        print >>sys.stderr, "if model1 is 'all', then all except the remaining models will be tested"
203        return 1
204
205    #runner = unittest.TextTestRunner()
206    runner = xmlrunner.XMLTestRunner(output='logs')
207    result = runner.run(make_suite(loaders, models))
208    return 1 if result.failures or result.errors else 0
209
210
211def model_tests():
212    """
213    Test runner visible to nosetests.
214
215    Run "nosetests sasmodels" on the command line to invoke it.
216    """
217    tests = make_suite(['opencl','dll'],['all'])
218    for test_i in tests:
219        yield test_i._runTest
220
221
222if __name__ == "__main__":
223    sys.exit(main())
Note: See TracBrowser for help on using the repository browser.