Skip to content

Commit

Permalink
Merge pull request #208 from lsst/tickets/DM-40127
Browse files Browse the repository at this point in the history
DM-40127: Add check to ensure spline fit isn't run in unsuitable configuration.
  • Loading branch information
erykoff committed Jul 24, 2023
2 parents 570aff8 + 5d24682 commit f902d2f
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 8 deletions.
17 changes: 17 additions & 0 deletions python/lsst/cp/pipe/linearity.py
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,13 @@ class LinearitySolveConfig(pipeBase.PipelineTaskConfig,
default=None,
optional=True,
)
splineGroupingMinPoints = pexConfig.Field(
dtype=int,
doc="Minimum number of linearity points to allow grouping together points "
"for Spline mode with splineGroupingColumn. This configuration is here "
"to prevent misuse of the Spline code to avoid over-fitting.",
default=100,
)
splineFitMinIter = pexConfig.Field(
dtype=int,
doc="Minimum number of iterations for spline fit.",
Expand Down Expand Up @@ -346,6 +353,16 @@ def run(self, inputPtc, dummy, camera, inputDims,
ampName, detector.getName())
continue

# Check for too few points.
if self.config.linearityType == "Spline" \
and self.config.splineGroupingColumn is not None \
and len(inputPtc.inputExpIdPairs[ampName]) < self.config.splineGroupingMinPoints:
raise RuntimeError(
"The input PTC has too few points to reliably run with PD grouping. "
"The recommended course of action is to set splineGroupingColumn to None. "
"If you really know what you are doing, you may reduce "
"config.splineGroupingMinPoints.")

if (len(inputPtc.expIdMask[ampName]) == 0) or self.config.ignorePtcMask:
self.log.warning("Mask not found for %s in detector %s in fit. Using all points.",
ampName, detector.getName())
Expand Down
2 changes: 1 addition & 1 deletion python/lsst/cp/pipe/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -840,7 +840,7 @@ def __init__(self, nodes, grouping_values, pd, mu, mask=None, log=None):
self._w[~mask] = 0.0

# Values to regularize spline fit.
self._x_regularize = np.linspace(self._mu[self.mask].min(), self._mu[self.mask].max(), 100)
self._x_regularize = np.linspace(0.0, self._mu[self.mask].max(), 100)

def estimate_p0(self):
"""Estimate initial fit parameters.
Expand Down
23 changes: 16 additions & 7 deletions tests/test_linearity.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ def test_linearity_polynomial_aducuts(self):
"""Test linearity with polynomial and ADU cuts."""
self._check_linearity("Polynomial", min_adu=10000.0, max_adu=90000.0)

def _check_linearity_spline(self, do_pd_offsets=False):
def _check_linearity_spline(self, do_pd_offsets=False, n_points=200):
"""Check linearity with a spline solution.
Parameters
Expand All @@ -238,7 +238,7 @@ def _check_linearity_spline(self, do_pd_offsets=False):
np.random.seed(12345)

# Create a test dataset representative of real data.
pd_values = np.linspace(1e-8, 2e-5, 200)
pd_values = np.linspace(1e-8, 2e-5, n_points)
time_values = pd_values * 1000000.
linear_ratio = 5e9
mu_linear = linear_ratio * pd_values
Expand All @@ -265,18 +265,22 @@ def _check_linearity_spline(self, do_pd_offsets=False):
mu_values += np.random.normal(scale=mu_values, size=len(mu_values)) / 10000.

# Add some outlier values.
outlier_indices = np.arange(5) + 170
if n_points >= 200:
outlier_indices = np.arange(5) + 170
else:
outlier_indices = []
mu_values[outlier_indices] += 200.0

# Add some small offsets to the pd_values if requested.
pd_values_offset = pd_values.copy()
ccobcurr = None
if do_pd_offsets:
ccobcurr = np.zeros(pd_values.size)
group0 = np.arange(50)
group1 = np.arange(50) + 50
group2 = np.arange(50) + 100
group3 = np.arange(50) + 150
n_points_group = n_points//4
group0 = np.arange(n_points_group)
group1 = np.arange(n_points_group) + n_points_group
group2 = np.arange(n_points_group) + 2*n_points_group
group3 = np.arange(n_points_group) + 3*n_points_group
ccobcurr[group0] = 0.01
ccobcurr[group1] = 0.02
ccobcurr[group2] = 0.03
Expand Down Expand Up @@ -307,6 +311,7 @@ def _check_linearity_spline(self, do_pd_offsets=False):
config.minLinearAdu = 0.0
config.maxLinearAdu = np.nanmax(mu_values) + 1.0
config.splineKnots = n_nodes
config.splineGroupingMinPoints = 101

if do_pd_offsets:
config.splineGroupingColumn = "CCOBCURR"
Expand Down Expand Up @@ -397,6 +402,10 @@ def test_linearity_spline(self):
def test_linearity_spline_offsets(self):
self._check_linearity_spline(do_pd_offsets=True)

def test_linearity_spline_offsets_too_few_points(self):
with self.assertRaisesRegex(RuntimeError, "too few points"):
self._check_linearity_spline(do_pd_offsets=True, n_points=100)


class TestMemory(lsst.utils.tests.MemoryTestCase):
pass
Expand Down

0 comments on commit f902d2f

Please sign in to comment.