""" This software was developed by the University of Tennessee as part of the Distributed Data Analysis of Neutron Scattering Experiments (DANSE) project funded by the US National Science Foundation. See the license text in license.txt copyright 2010, University of Tennessee """ import os.path import unittest import math import numpy as np from sas.sascalc.dataloader.loader import Loader from sas.sascalc.dataloader.data_info import Data1D from sas.sascalc.invariant import invariant def find(filename): return os.path.join(os.path.dirname(__file__), filename) class TestLinearFit(unittest.TestCase): """ Test Line fit """ def setUp(self): x = np.asarray([1.,2.,3.,4.,5.,6.,7.,8.,9.]) y = np.asarray([1.,2.,3.,4.,5.,6.,7.,8.,9.]) dy = y/10.0 self.data = Data1D(x=x,y=y,dy=dy) def test_fit_linear_data(self): """ Simple linear fit """ # Create invariant object. Background and scale left as defaults. fit = invariant.Extrapolator(data=self.data) #a,b = fit.fit() p, dp = fit.fit() # Test results self.assertAlmostEquals(p[0], 1.0, 5) self.assertAlmostEquals(p[1], 0.0, 5) def test_fit_linear_data_with_noise(self): """ Simple linear fit with noise """ import random, math for i in range(len(self.data.y)): self.data.y[i] = self.data.y[i]+.1*(random.random()-0.5) # Create invariant object. Background and scale left as defaults. fit = invariant.Extrapolator(data=self.data) p, dp = fit.fit() # Test results self.assertTrue(math.fabs(p[0]-1.0)<0.05) self.assertTrue(math.fabs(p[1])<0.1) def test_fit_with_fixed_parameter(self): """ Linear fit for y=ax+b where a is fixed. """ # Create invariant object. Background and scale left as defaults. fit = invariant.Extrapolator(data=self.data) p, dp = fit.fit(power=-1.0) # Test results self.assertAlmostEquals(p[0], 1.0, 5) self.assertAlmostEquals(p[1], 0.0, 5) def test_fit_linear_data_with_noise_and_fixed_par(self): """ Simple linear fit with noise """ import random, math for i in range(len(self.data.y)): self.data.y[i] = self.data.y[i]+.1*(random.random()-0.5) # Create invariant object. Background and scale left as defaults. fit = invariant.Extrapolator(data=self.data) p, dp = fit.fit(power=-1.0) # Test results self.assertTrue(math.fabs(p[0]-1.0)<0.05) self.assertTrue(math.fabs(p[1])<0.1) class TestInvariantCalculator(unittest.TestCase): """ Test main functionality of the Invariant calculator """ def setUp(self): data = Loader().load(find("latex_smeared_slit.xml")) self.data = data[0] self.data.dxl = None def test_initial_data_processing(self): """ Test whether the background and scale are handled properly when creating an InvariantCalculator object """ length = len(self.data.x) self.assertEqual(length, len(self.data.y)) inv = invariant.InvariantCalculator(self.data) self.assertEqual(length, len(inv._data.x)) self.assertEqual(inv._data.x[0], self.data.x[0]) # Now the same thing with a background value bck = 0.1 inv = invariant.InvariantCalculator(self.data, background=bck) self.assertEqual(inv._background, bck) self.assertEqual(length, len(inv._data.x)) self.assertEqual(inv._data.y[0]+bck, self.data.y[0]) # Now the same thing with a scale value scale = 0.1 inv = invariant.InvariantCalculator(self.data, scale=scale) self.assertEqual(inv._scale, scale) self.assertEqual(length, len(inv._data.x)) self.assertAlmostEqual(inv._data.y[0]/scale, self.data.y[0],7) def test_incompatible_data_class(self): """ Check that only classes that inherit from Data1D are allowed as data. """ class Incompatible(): pass self.assertRaises(ValueError, invariant.InvariantCalculator, Incompatible()) def test_error_treatment(self): x = np.asarray(np.asarray([0,1,2,3])) y = np.asarray(np.asarray([1,1,1,1])) # These are all the values of the dy array that would cause # us to set all dy values to 1.0 at __init__ time. dy_list = [ [], None, [0,0,0,0] ] for dy in dy_list: data = Data1D(x=x, y=y, dy=dy) inv = invariant.InvariantCalculator(data) self.assertEqual(len(inv._data.x), len(inv._data.dy)) self.assertEqual(len(inv._data.dy), 4) for i in range(4): self.assertEqual(inv._data.dy[i],1) def test_qstar_low_q_guinier(self): """ Test low-q extrapolation with a Guinier """ inv = invariant.InvariantCalculator(self.data) # Basic sanity check _qstar = inv.get_qstar() qstar, dqstar = inv.get_qstar_with_error() self.assertEqual(qstar, _qstar) # Low-Q Extrapolation # Check that the returned invariant is what we expect given # the result we got without extrapolation inv.set_extrapolation('low', npts=10, function='guinier') qs_extr, dqs_extr = inv.get_qstar_with_error('low') delta_qs_extr, delta_dqs_extr = inv.get_qstar_low() self.assertEqual(qs_extr, _qstar+delta_qs_extr) self.assertEqual(dqs_extr, math.sqrt(dqstar*dqstar + delta_dqs_extr*delta_dqs_extr)) # We don't expect the extrapolated invariant to be very far from the # result without extrapolation. Let's test for a result within 10%. self.assertTrue(math.fabs(qs_extr-qstar)/qstar<0.1) # Check that the two results are consistent within errors # Note that the error on the extrapolated value takes into account # a systematic error for the fact that we may not know the shape of I(q) at low Q. self.assertTrue(math.fabs(qs_extr-qstar)