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