source: sasview/test/corfunc/test/utest_corfunc.py @ de43192

magnetic_scattrelease-4.2.2ticket-1009ticket-1094-headlessticket-1242-2d-resolutionticket-1243ticket-1249unittest-saveload
Last change on this file since de43192 was 6ef75fa6, checked in by Stuart Prescott <stuart@…>, 6 years ago

Fix race condition in test

transform_isrunning() returns False both before the calculation has started
and also after the calculation has finished. The test of the transformation
was only considering the latter case and so was regularly failing on the
reproducible-builds.org test infrastructure.

  • Property mode set to 100644
File size: 4.7 KB
Line 
1"""
2Unit Tests for CorfuncCalculator class
3"""
4from __future__ import division, print_function
5
6import os.path
7import unittest
8import time
9
10import numpy as np
11
12from sas.sascalc.corfunc.corfunc_calculator import CorfuncCalculator
13from sas.sascalc.dataloader.data_info import Data1D
14
15
16def find(filename):
17    return os.path.join(os.path.dirname(__file__), filename)
18
19
20class TestCalculator(unittest.TestCase):
21
22    def setUp(self):
23        self.data = load_data()
24        # Note: to generate target values from the GUI:
25        # * load the data from test/corfunc/test/98929.txt
26        # * set qrange to (0, 0.013), (0.15, 0.24)
27        # * select fourier transform type
28        # * click Calculate Bg
29        # * click Extrapolate
30        # * click Compute Parameters
31        # * copy the Guinier and Porod values to the extrapolate function
32        # * for each graph, grab the data from DataInfo and store it in _out.txt
33        self.calculator = CorfuncCalculator(data=self.data, lowerq=0.013,
34            upperq=(0.15, 0.24))
35        self.calculator.background = 0.3
36        self.extrapolation = None
37        self.transformation = None
38        self.results = [np.loadtxt(find(filename+"_out.txt")).T[2]
39                        for filename in ("gamma1", "gamma3", "idf")]
40
41    def extrapolate(self):
42        params, extrapolation, s2 = self.calculator.compute_extrapolation()
43        # Check the extrapolation parameters
44        self.assertAlmostEqual(params['A'], 4.18970, places=5)
45        self.assertAlmostEqual(params['B'], -25469.9, places=1)
46        self.assertAlmostEqual(params['K'], 4.44660e-5, places=10)
47        #self.assertAlmostEqual(params['sigma'], 1.70181e-10, places=15)
48
49        # Ensure the extraplation tends to the background value
50        self.assertAlmostEqual(extrapolation.y[-1], self.calculator.background)
51
52        # Test extrapolation for q values between 0.02 and 0.24
53        mask = np.logical_and(self.data.x > 0.02, self.data.x < 0.24)
54        qs = self.data.x[mask]
55        iqs = self.data.y[mask]
56
57        for q, iq in zip(qs, iqs):
58            # Find the q value in the extraplation nearest to the value in
59            # the data
60            q_extrap = min(extrapolation.x, key=lambda x:abs(x-q))
61            # Find the index of this value in the extrapolation
62            index = list(extrapolation.x).index(q_extrap)
63            # Find it's corresponding intensity value
64            iq_extrap = extrapolation.y[index]
65            # Check the extrapolation agrees to the data at this point to 1 d.p
66            self.assertAlmostEqual(iq_extrap, iq, 1)
67
68        self.extrapolation = extrapolation
69
70    def transform(self):
71        self.calculator.compute_transform(self.extrapolation, 'fourier',
72            completefn=self.transform_callback)
73        # Transform is performed asynchronously; give it time to run
74        while True:
75            time.sleep(0.001)
76            if (not self.calculator.transform_isrunning() and
77                self.transformation is not None):
78                break
79
80        transform1, transform3, idf = self.transformation
81        self.assertIsNotNone(transform1)
82        self.assertAlmostEqual(transform1.y[0], 1)
83        self.assertAlmostEqual(transform1.y[-1], 0, 5)
84
85    def transform_callback(self, transforms):
86        self.transformation = transforms
87
88    def extract_params(self):
89        params = self.calculator.extract_parameters(self.transformation[0])
90        self.assertIsNotNone(params)
91        self.assertEqual(len(params), 6)
92        self.assertLess(abs(params['max']-75), 2.5) # L_p ~= 75
93
94    def check_transforms(self):
95        gamma1, gamma3, idf = self.transformation
96        gamma1_out, gamma3_out, idf_out = self.results
97        def compare(a, b):
98            return max(abs((a-b)/b))
99        #print("gamma1 diff", compare(gamma1.y[gamma1.x<=200.], gamma1_out))
100        #print("gamma3 diff", compare(gamma3.y[gamma3.x<=200.], gamma3_out))
101        #print("idf diff", compare(idf.y[idf.x<=200.], idf_out))
102        #self.assertLess(compare(gamma1.y[gamma1.x<=200.], gamma1_out), 1e-10)
103        #self.assertLess(compare(gamma3.y[gamma3.x<=200.], gamma3_out), 1e-10)
104        #self.assertLess(compare(idf.y[idf.x<=200.], idf_out), 1e-10)
105
106    # Ensure tests are ran in correct order;
107    # Each test depends on the one before it
108    def test_calculator(self):
109        steps = [self.extrapolate, self.transform, self.extract_params, self.check_transforms]
110        for test in steps:
111            try:
112                test()
113            except Exception as e:
114                raise
115                self.fail("{} failed ({}: {})".format(test, type(e), e))
116
117
118def load_data(filename="98929.txt"):
119    data = np.loadtxt(find(filename), dtype=np.float64)
120    q = data[:,0]
121    iq = data[:,1]
122    return Data1D(x=q, y=iq)
123
124if __name__ == '__main__':
125    unittest.main()
Note: See TracBrowser for help on using the repository browser.