Skip to content

Commit acc2994

Browse files
authored
Merge pull request #690 from scipp/peak-fit-robust-polynomial
Peak fitting: Do not drop params with value=0
2 parents fe6253b + d4ac90a commit acc2994

2 files changed

Lines changed: 27 additions & 2 deletions

File tree

src/scippneutron/peaks/model.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,9 +311,14 @@ def _call(self, x: sc.Variable, params: dict[str, sc.Variable]) -> sc.Variable:
311311

312312
def _guess(self, x: sc.Variable, y: sc.Variable) -> dict[str, sc.Variable]:
313313
poly = np.polynomial.Polynomial.fit(x.values, y.values, deg=self.degree)
314+
# `fit` returns a polynomial with domain=[x.min, x.max], convert to [-1, 1]
315+
# because all models are defined for peaks centered around 0.
316+
coef = poly.convert().coef
317+
# Pad with 0's because `convert` drops those to simplify the polynomial
318+
# but the model requires an exact number of params.
319+
coef = np.pad(coef, (0, len(self._param_names) - len(coef)))
314320
return {
315-
f'a{i}': sc.scalar(c, unit=y.unit / x.unit**i)
316-
for i, c in enumerate(poly.convert().coef)
321+
f'a{i}': sc.scalar(c, unit=y.unit / x.unit**i) for i, c in enumerate(coef)
317322
}
318323

319324

tests/peaks/model_test.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,26 @@ def test_polynomial_degree_2_guess_params():
209209
sc.testing.assert_allclose(params['a2'], a2, atol=sc.scalar(0.1, unit='K/m^2'))
210210

211211

212+
def test_polynomial_degree_2_guess_params_degenerate():
213+
x = sc.linspace('xx', 0.8, 4.3, 10, unit='s')
214+
y = sc.zeros(sizes=x.sizes, unit='cm')
215+
data = sc.DataArray(y, coords={'xx': x})
216+
217+
m = model.PolynomialModel(degree=2, prefix='')
218+
params = m.guess(data)
219+
# Test that no params have been optimized away:
220+
assert params.keys() == {'a0', 'a1', 'a2'}
221+
sc.testing.assert_allclose(
222+
params['a0'], sc.scalar(0.0, unit='cm'), atol=sc.scalar(0.1, unit='cm')
223+
)
224+
sc.testing.assert_allclose(
225+
params['a1'], sc.scalar(0.0, unit='cm/s'), atol=sc.scalar(0.1, unit='cm/s')
226+
)
227+
sc.testing.assert_allclose(
228+
params['a2'], sc.scalar(0.0, unit='cm/s^2'), atol=sc.scalar(0.1, unit='cm/s^2')
229+
)
230+
231+
212232
def test_gaussian_guess_params_linspace():
213233
amplitude = sc.scalar(2.8, unit='kg')
214234
loc = sc.scalar(0.4, unit='m')

0 commit comments

Comments
 (0)