# coding: utf-8 # /*########################################################################## # Copyright (C) 2016 European Synchrotron Radiation Facility # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. # # ############################################################################*/ import copy import unittest import numpy import random from silx.math.fit import bgtheories from silx.math.fit.functions import sum_gauss class TestBgTheories(unittest.TestCase): """ """ def setUp(self): self.x = numpy.arange(100) self.y = 10 + 0.05 * self.x + sum_gauss(self.x, 10., 45., 15.) # add a very narrow high amplitude peak to test strip and snip self.y += sum_gauss(self.x, 100., 75., 2.) self.narrow_peak_index = list(self.x).index(75) random.seed() def tearDown(self): pass def testTheoriesAttrs(self): for theory_name in bgtheories.THEORY: self.assertIsInstance(theory_name, str) self.assertTrue(hasattr(bgtheories.THEORY[theory_name], "function")) self.assertTrue(hasattr(bgtheories.THEORY[theory_name].function, "__call__")) # Ensure legacy functions are not renamed accidentally self.assertTrue( {"No Background", "Constant", "Linear", "Strip", "Snip"}.issubset( set(bgtheories.THEORY))) def testNoBg(self): nobgfun = bgtheories.THEORY["No Background"].function self.assertTrue(numpy.array_equal(nobgfun(self.x, self.y), numpy.zeros_like(self.x))) # default estimate self.assertEqual(bgtheories.THEORY["No Background"].estimate(self.x, self.y), ([], [])) def testConstant(self): consfun = bgtheories.THEORY["Constant"].function c = random.random() * 100 self.assertTrue(numpy.array_equal(consfun(self.x, self.y, c), c * numpy.ones_like(self.x))) # default estimate esti_par, cons = bgtheories.THEORY["Constant"].estimate(self.x, self.y) self.assertEqual(cons, [[0, 0, 0]]) self.assertAlmostEqual(esti_par, min(self.y)) def testLinear(self): linfun = bgtheories.THEORY["Linear"].function a = random.random() * 100 b = random.random() * 100 self.assertTrue(numpy.array_equal(linfun(self.x, self.y, a, b), a + b * self.x)) # default estimate esti_par, cons = bgtheories.THEORY["Linear"].estimate(self.x, self.y) self.assertEqual(cons, [[0, 0, 0], [0, 0, 0]]) self.assertAlmostEqual(esti_par[0], 10, places=3) self.assertAlmostEqual(esti_par[1], 0.05, places=3) def testStrip(self): stripfun = bgtheories.THEORY["Strip"].function anchors = sorted(random.sample(list(self.x), 4)) anchors_indices = [list(self.x).index(a) for a in anchors] # we really want to strip away the narrow peak anchors_indices_copy = copy.deepcopy(anchors_indices) for idx in anchors_indices_copy: if abs(idx - self.narrow_peak_index) < 5: anchors_indices.remove(idx) anchors.remove(self.x[idx]) width = 2 niter = 1000 bgtheories.THEORY["Strip"].configure(AnchorsList=anchors, AnchorsFlag=True) bg = stripfun(self.x, self.y, width, niter) # assert peak amplitude has been decreased self.assertLess(bg[self.narrow_peak_index], self.y[self.narrow_peak_index]) # default estimate for i in anchors_indices: self.assertEqual(bg[i], self.y[i]) # estimated parameters are equal to the default ones in the config dict bgtheories.THEORY["Strip"].configure(StripWidth=7, StripIterations=8) esti_par, cons = bgtheories.THEORY["Strip"].estimate(self.x, self.y) self.assertTrue(numpy.array_equal(cons, [[3, 0, 0], [3, 0, 0]])) self.assertEqual(esti_par, [7, 8]) def testSnip(self): snipfun = bgtheories.THEORY["Snip"].function anchors = sorted(random.sample(list(self.x), 4)) anchors_indices = [list(self.x).index(a) for a in anchors] # we want to strip away the narrow peak, so remove nearby anchors anchors_indices_copy = copy.deepcopy(anchors_indices) for idx in anchors_indices_copy: if abs(idx - self.narrow_peak_index) < 5: anchors_indices.remove(idx) anchors.remove(self.x[idx]) width = 16 bgtheories.THEORY["Snip"].configure(AnchorsList=anchors, AnchorsFlag=True) bg = snipfun(self.x, self.y, width) # assert peak amplitude has been decreased self.assertLess(bg[self.narrow_peak_index], self.y[self.narrow_peak_index], "Snip didn't decrease the peak amplitude.") # anchored data must remain fixed for i in anchors_indices: self.assertEqual(bg[i], self.y[i]) # estimated parameters are equal to the default ones in the config dict bgtheories.THEORY["Snip"].configure(SnipWidth=7) esti_par, cons = bgtheories.THEORY["Snip"].estimate(self.x, self.y) self.assertTrue(numpy.array_equal(cons, [[3, 0, 0]])) self.assertEqual(esti_par, [7])