[0bc0683] | 1 | """ |
---|
| 2 | Unit Tests for CorfuncCalculator class |
---|
| 3 | """ |
---|
[86ba9d6] | 4 | from __future__ import division, print_function |
---|
[0bc0683] | 5 | |
---|
[3a473ef] | 6 | import os.path |
---|
[0bc0683] | 7 | import unittest |
---|
| 8 | import time |
---|
[86ba9d6] | 9 | |
---|
[0bc0683] | 10 | import numpy as np |
---|
[86ba9d6] | 11 | |
---|
[0bc0683] | 12 | from sas.sascalc.corfunc.corfunc_calculator import CorfuncCalculator |
---|
| 13 | from sas.sascalc.dataloader.data_info import Data1D |
---|
[253eb6c6] | 14 | |
---|
[0bc0683] | 15 | |
---|
[3a473ef] | 16 | def find(filename): |
---|
| 17 | return os.path.join(os.path.dirname(__file__), filename) |
---|
| 18 | |
---|
| 19 | |
---|
[0bc0683] | 20 | class TestCalculator(unittest.TestCase): |
---|
| 21 | |
---|
| 22 | def setUp(self): |
---|
| 23 | self.data = load_data() |
---|
[1f21a43] | 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 |
---|
[0bc0683] | 33 | self.calculator = CorfuncCalculator(data=self.data, lowerq=0.013, |
---|
| 34 | upperq=(0.15, 0.24)) |
---|
[1f21a43] | 35 | self.calculator.background = 0.3 |
---|
[0bc0683] | 36 | self.extrapolation = None |
---|
[968d67e] | 37 | self.transformation = None |
---|
[3a473ef] | 38 | self.results = [np.loadtxt(find(filename+"_out.txt")).T[2] |
---|
[1f21a43] | 39 | for filename in ("gamma1", "gamma3", "idf")] |
---|
[0bc0683] | 40 | |
---|
| 41 | def extrapolate(self): |
---|
[be51cf6] | 42 | params, extrapolation, s2 = self.calculator.compute_extrapolation() |
---|
[acefa2b] | 43 | # Check the extrapolation parameters |
---|
[1f21a43] | 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) |
---|
[86ba9d6] | 47 | #self.assertAlmostEqual(params['sigma'], 1.70181e-10, places=15) |
---|
[0bc0683] | 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) |
---|
[3a473ef] | 76 | if (not self.calculator.transform_isrunning() and |
---|
| 77 | self.transformation is not None): |
---|
[0bc0683] | 78 | break |
---|
| 79 | |
---|
[3a473ef] | 80 | transform1, transform3, idf = self.transformation |
---|
[be51cf6] | 81 | self.assertIsNotNone(transform1) |
---|
| 82 | self.assertAlmostEqual(transform1.y[0], 1) |
---|
| 83 | self.assertAlmostEqual(transform1.y[-1], 0, 5) |
---|
[3a473ef] | 84 | |
---|
| 85 | def transform_callback(self, transforms): |
---|
[1f21a43] | 86 | self.transformation = transforms |
---|
[0bc0683] | 87 | |
---|
| 88 | def extract_params(self): |
---|
[1f21a43] | 89 | params = self.calculator.extract_parameters(self.transformation[0]) |
---|
[0bc0683] | 90 | self.assertIsNotNone(params) |
---|
| 91 | self.assertEqual(len(params), 6) |
---|
| 92 | self.assertLess(abs(params['max']-75), 2.5) # L_p ~= 75 |
---|
| 93 | |
---|
[1f21a43] | 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)) |
---|
[86ba9d6] | 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) |
---|
[1f21a43] | 105 | |
---|
[0bc0683] | 106 | # Ensure tests are ran in correct order; |
---|
| 107 | # Each test depends on the one before it |
---|
| 108 | def test_calculator(self): |
---|
[1f21a43] | 109 | steps = [self.extrapolate, self.transform, self.extract_params, self.check_transforms] |
---|
[0bc0683] | 110 | for test in steps: |
---|
| 111 | try: |
---|
| 112 | test() |
---|
| 113 | except Exception as e: |
---|
[be51cf6] | 114 | raise |
---|
[0bc0683] | 115 | self.fail("{} failed ({}: {})".format(test, type(e), e)) |
---|
| 116 | |
---|
| 117 | |
---|
| 118 | def load_data(filename="98929.txt"): |
---|
[3a473ef] | 119 | data = np.loadtxt(find(filename), dtype=np.float64) |
---|
[0bc0683] | 120 | q = data[:,0] |
---|
| 121 | iq = data[:,1] |
---|
| 122 | return Data1D(x=q, y=iq) |
---|
| 123 | |
---|
| 124 | if __name__ == '__main__': |
---|
| 125 | unittest.main() |
---|