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 diff --git a/rabbit/fitter.py b/rabbit/fitter.py index faba62a..22a5e11 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(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: 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,