Changes in sasmodels/model_test.py [1a6cd57:e09d1e0] in sasmodels


Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • sasmodels/model_test.py

    r1a6cd57 re09d1e0  
    9797        is_py = callable(model_info.Iq) 
    9898 
     99        # Some OpenCL drivers seem to be flaky, and are not producing the 
     100        # expected result.  Since we don't have known test values yet for 
     101        # all of our models, we are instead going to compare the results 
     102        # for the 'smoke test' (that is, evaluation at q=0.1 for the default 
     103        # parameters just to see that the model runs to completion) between 
     104        # the OpenCL and the DLL.  To do this, we define a 'stash' which is 
     105        # shared between OpenCL and DLL tests.  This is just a list.  If the 
     106        # list is empty (which it will be when DLL runs, if the DLL runs 
     107        # first), then the results are appended to the list.  If the list 
     108        # is not empty (which it will be when OpenCL runs second), the results 
     109        # are compared to the results stored in the first element of the list. 
     110        # This is a horrible stateful hack which only makes sense because the 
     111        # test suite is thrown away after being run once. 
     112        stash = [] 
     113 
    99114        if is_py:  # kernel implemented in python 
    100115            test_name = "Model: %s, Kernel: python"%model_name 
     
    103118                                 test_method_name, 
    104119                                 platform="dll",  # so that 
    105                                  dtype="double") 
     120                                 dtype="double", 
     121                                 stash=stash) 
    106122            suite.addTest(test) 
    107123        else:   # kernel implemented in C 
     124 
     125            # test using dll if desired 
     126            if 'dll' in loaders or not core.HAVE_OPENCL: 
     127                test_name = "Model: %s, Kernel: dll"%model_name 
     128                test_method_name = "test_%s_dll" % model_info.id 
     129                test = ModelTestCase(test_name, model_info, 
     130                                     test_method_name, 
     131                                     platform="dll", 
     132                                     dtype="double", 
     133                                     stash=stash) 
     134                suite.addTest(test) 
     135 
    108136            # test using opencl if desired and available 
    109137            if 'opencl' in loaders and core.HAVE_OPENCL: 
     
    116144                test = ModelTestCase(test_name, model_info, 
    117145                                     test_method_name, 
    118                                      platform="ocl", dtype=None) 
     146                                     platform="ocl", dtype=None, 
     147                                     stash=stash) 
    119148                #print("defining", test_name) 
    120                 suite.addTest(test) 
    121  
    122             # test using dll if desired 
    123             if 'dll' in loaders or not core.HAVE_OPENCL: 
    124                 test_name = "Model: %s, Kernel: dll"%model_name 
    125                 test_method_name = "test_%s_dll" % model_info.id 
    126                 test = ModelTestCase(test_name, model_info, 
    127                                      test_method_name, 
    128                                      platform="dll", 
    129                                      dtype="double") 
    130149                suite.addTest(test) 
    131150 
     
    144163        """ 
    145164        def __init__(self, test_name, model_info, test_method_name, 
    146                      platform, dtype): 
    147             # type: (str, ModelInfo, str, str, DType) -> None 
     165                     platform, dtype, stash): 
     166            # type: (str, ModelInfo, str, str, DType, List[Any]) -> None 
    148167            self.test_name = test_name 
    149168            self.info = model_info 
    150169            self.platform = platform 
    151170            self.dtype = dtype 
     171            self.stash = stash  # container for the results of the first run 
    152172 
    153173            setattr(self, test_method_name, self.run_all) 
     
    174194                ] 
    175195 
    176             tests = self.info.tests 
     196            tests = smoke_tests + self.info.tests 
    177197            try: 
    178198                model = build_model(self.info, dtype=self.dtype, 
    179199                                    platform=self.platform) 
    180                 for test in smoke_tests + tests: 
    181                     self.run_one(model, test) 
    182  
    183                 if not tests and self.platform == "dll": 
    184                     ## Uncomment the following to make forgetting the test 
    185                     ## values an error.  Only do so for the "dll" tests 
    186                     ## to reduce noise from both opencl and dll, and because 
    187                     ## python kernels use platform="dll". 
    188                     #raise Exception("No test cases provided") 
    189                     pass 
     200                results = [self.run_one(model, test) for test in tests] 
     201                if self.stash: 
     202                    for test, target, actual in zip(tests, self.stash[0], results): 
     203                        assert np.all(abs(target-actual)<2e-5*abs(actual)),\ 
     204                            "expected %s but got %s for %s"%(target, actual, test[0]) 
     205                else: 
     206                    self.stash.append(results) 
     207 
     208                # Check for missing tests.  Only do so for the "dll" tests 
     209                # to reduce noise from both opencl and dll, and because 
     210                # python kernels use platform="dll". 
     211                if self.platform == "dll": 
     212                    missing = [] 
     213                    ## Uncomment the following to require test cases 
     214                    #missing = self._find_missing_tests() 
     215                    if missing: 
     216                        raise ValueError("Missing tests for "+", ".join(missing)) 
    190217 
    191218            except: 
    192219                annotate_exception(self.test_name) 
    193220                raise 
     221 
     222        def _find_missing_tests(self): 
     223            # type: () -> None 
     224            """make sure there are 1D, 2D, ER and VR tests as appropriate""" 
     225            model_has_VR = callable(self.info.VR) 
     226            model_has_ER = callable(self.info.ER) 
     227            model_has_1D = True 
     228            model_has_2D = any(p.type == 'orientation' 
     229                               for p in self.info.parameters.kernel_parameters) 
     230 
     231            # Lists of tests that have a result that is not None 
     232            single = [test for test in self.info.tests 
     233                      if not isinstance(test[2], list) and test[2] is not None] 
     234            tests_has_VR = any(test[1] == 'VR' for test in single) 
     235            tests_has_ER = any(test[1] == 'ER' for test in single) 
     236            tests_has_1D_single = any(isinstance(test[1], float) for test in single) 
     237            tests_has_2D_single = any(isinstance(test[1], tuple) for test in single) 
     238 
     239            multiple = [test for test in self.info.tests 
     240                        if isinstance(test[2], list) 
     241                            and not all(result is None for result in test[2])] 
     242            tests_has_1D_multiple = any(isinstance(test[1][0], float) 
     243                                        for test in multiple) 
     244            tests_has_2D_multiple = any(isinstance(test[1][0], tuple) 
     245                                        for test in multiple) 
     246 
     247            missing = [] 
     248            if model_has_VR and not tests_has_VR: 
     249                missing.append("VR") 
     250            if model_has_ER and not tests_has_ER: 
     251                missing.append("ER") 
     252            if model_has_1D and not (tests_has_1D_single or tests_has_1D_multiple): 
     253                missing.append("1D") 
     254            if model_has_2D and not (tests_has_2D_single or tests_has_2D_multiple): 
     255                missing.append("2D") 
     256 
     257            return missing 
    194258 
    195259        def run_one(self, model, test): 
     
    207271 
    208272            if x[0] == 'ER': 
    209                 actual = [call_ER(model.info, pars)] 
     273                actual = np.array([call_ER(model.info, pars)]) 
    210274            elif x[0] == 'VR': 
    211                 actual = [call_VR(model.info, pars)] 
     275                actual = np.array([call_VR(model.info, pars)]) 
    212276            elif isinstance(x[0], tuple): 
    213277                qx, qy = zip(*x) 
     
    238302                                    'f(%s); expected:%s; actual:%s' 
    239303                                    % (xi, yi, actual_yi)) 
     304            return actual 
    240305 
    241306    return ModelTestCase 
Note: See TracChangeset for help on using the changeset viewer.