From c31695861bad06214d21b612f238784534d9167d Mon Sep 17 00:00:00 2001 From: davidwalter2 Date: Sun, 25 Jan 2026 13:48:33 -0500 Subject: [PATCH 1/4] Add functionality to set parameter constraint minium --- bin/rabbit_fit.py | 7 +++++++ rabbit/fitter.py | 25 ++++++++++++++++++++----- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/bin/rabbit_fit.py b/bin/rabbit_fit.py index 58d7170..84f19c9 100755 --- a/bin/rabbit_fit.py +++ b/bin/rabbit_fit.py @@ -176,6 +176,13 @@ def make_parser(): action="store_true", help="compute impacts of frozen (non-profiled) systematics", ) + parser.add_argument( + "--setConstraintMinimum", + default=[], + nargs=2, + action="append", + help="Set the constraint minima of specified parameter to specified value", + ) return parser.parse_args() diff --git a/rabbit/fitter.py b/rabbit/fitter.py index faba62a..984020a 100644 --- a/rabbit/fitter.py +++ b/rabbit/fitter.py @@ -141,12 +141,27 @@ def __init__( self.parms = np.concatenate([self.poi_model.pois, self.indata.systs]) + # tf tensor containing default constraint minima + theta0default = np.zeros(self.indata.nsyst) + for parm, val in options.setConstraintMinimum: + idx = np.where(self.indata.systs.astype(str) == parm)[0] + if len(idx) != 1: + raise RuntimeError( + f"Expect to find exactly one match for {parm} to set constraint minimum, but found {len(len(idx))}" + ) + theta0default[idx[0]] = val + + self.theta0default = tf.convert_to_tensor( + theta0default, dtype=self.indata.dtype + ) + # tf variable containing all fit parameters - thetadefault = tf.zeros([self.indata.nsyst], dtype=self.indata.dtype) if self.poi_model.npoi > 0: - xdefault = tf.concat([self.poi_model.xpoidefault, thetadefault], axis=0) + xdefault = tf.concat( + [self.poi_model.xpoidefault, self.theta0default], axis=0 + ) else: - xdefault = thetadefault + xdefault = self.theta0default self.x = tf.Variable(xdefault, trainable=True, name="x") @@ -186,7 +201,7 @@ def __init__( # constraint minima for nuisance parameters self.theta0 = tf.Variable( - tf.zeros([self.indata.nsyst], dtype=self.indata.dtype), + self.theta0default, trainable=False, name="theta0", ) @@ -475,7 +490,7 @@ def set_beta0(self, values): self.logbeta0.assign(tf.math.log(beta0safe)) def theta0defaultassign(self): - self.theta0.assign(tf.zeros([self.indata.nsyst], dtype=self.theta0.dtype)) + self.theta0.assign(self.theta0default) def xdefaultassign(self): if self.poi_model.npoi == 0: From 6d4b8b7198f8830f646da3228b3e4ff481e0d619 Mon Sep 17 00:00:00 2001 From: davidwalter2 Date: Mon, 26 Jan 2026 13:54:12 -0500 Subject: [PATCH 2/4] Define option 'setConstraintMinimum' in common parser to make it available also for the limit script --- bin/rabbit_fit.py | 7 ------- rabbit/parsing.py | 7 +++++++ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/bin/rabbit_fit.py b/bin/rabbit_fit.py index 84f19c9..58d7170 100755 --- a/bin/rabbit_fit.py +++ b/bin/rabbit_fit.py @@ -176,13 +176,6 @@ def make_parser(): action="store_true", help="compute impacts of frozen (non-profiled) systematics", ) - parser.add_argument( - "--setConstraintMinimum", - default=[], - nargs=2, - action="append", - help="Set the constraint minima of specified parameter to specified value", - ) return parser.parse_args() diff --git a/rabbit/parsing.py b/rabbit/parsing.py index 24bf82c..c2dca87 100644 --- a/rabbit/parsing.py +++ b/rabbit/parsing.py @@ -93,6 +93,13 @@ def common_parser(): E.g. use '--unblind ^signal$' to unblind a parameter named signal or '--unblind' to unblind all. """, ) + parser.add_argument( + "--setConstraintMinimum", + default=[], + nargs=2, + action="append", + help="Set the constraint minima of specified parameter to specified value", + ) parser.add_argument( "--freezeParameters", type=str, From 9ca0fb27b520bce45e8ba50329726a477453b220 Mon Sep 17 00:00:00 2001 From: davidwalter2 Date: Mon, 26 Jan 2026 14:12:17 -0500 Subject: [PATCH 3/4] Add test for new functionality in CI --- .github/workflows/main.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c4fda92..c39c51b 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -226,7 +226,7 @@ jobs: - name: nominal fit run: >- rabbit_fit.py $RABBIT_OUTDIR/test_tensor.hdf5 -o $RABBIT_OUTDIR/ --postfix composite - -t 0 --unblind '.*' --doImpacts --globalImpacts + -t -1 0 --unblind '.*' --doImpacts --globalImpacts --saveHists --saveHistsPerProcess --computeHistErrors --computeHistErrorsPerProcess --computeHistCov --computeHistImpacts --computeVariations --compositeMapping -m Project ch1 a -m Project ch1 b @@ -234,12 +234,12 @@ jobs: - name: nominal fit blinded run: >- rabbit_fit.py $RABBIT_OUTDIR/test_tensor.hdf5 -o $RABBIT_OUTDIR/ - -t 0 --postfix blinded --doImpacts --globalImpacts + -t 0 --postfix blinded --setConstraintMinimum bkg_2_norm 0.5 --doImpacts --globalImpacts - name: sparse tensor fit run: >- rabbit_fit.py $RABBIT_OUTDIR/test_tensor_sparse.hdf5 -o $RABBIT_OUTDIR/ --postfix sparse - -t -0 --noBinByBinStat --doImpacts --globalImpacts --computeVariations + -t 0 --noBinByBinStat --doImpacts --globalImpacts --computeVariations --saveHists --saveHistsPerProcess --computeHistErrors --computeHistErrorsPerProcess -m Project ch1 a -m Project ch1 b From c99595b1eb95d21f8f06d3c7fcb2947d8d19610a Mon Sep 17 00:00:00 2001 From: davidwalter2 Date: Tue, 27 Jan 2026 10:32:15 -0500 Subject: [PATCH 4/4] Fix typo --- rabbit/fitter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rabbit/fitter.py b/rabbit/fitter.py index 984020a..22a5e11 100644 --- a/rabbit/fitter.py +++ b/rabbit/fitter.py @@ -147,7 +147,7 @@ def __init__( idx = np.where(self.indata.systs.astype(str) == parm)[0] if len(idx) != 1: raise RuntimeError( - f"Expect to find exactly one match for {parm} to set constraint minimum, but found {len(len(idx))}" + f"Expect to find exactly one match for {parm} to set constraint minimum, but found {len(idx)}" ) theta0default[idx[0]] = val