Skip to content

CI

CI #640

Workflow file for this run

# This is a basic workflow to help you get started with Actions
name: CI
# Controls when the workflow will run
on:
# Triggers the workflow on push or pull request events but only for the master branch
pull_request:
branches: [ main ]
schedule:
- cron: '30 3 * * 1,3,5' # Run on Monday, Wednesday, and Friday night at 3h30 UTC
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
env:
LOCAL_WEB_DIR: www/Rabbit/PRValidation
EOS_DIR: /eos/user/c/cmsmwbot
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
linting:
# The type of runner that the job will run on
runs-on: [self-hosted, linux, x64]
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v4
- name: run isort
run: |
isort . --check-only --diff --profile black --line-length 88
- name: run Flake8
run: >-
flake8 . --max-line-length 88
--select=F401,F402,F403,F404,F405,F406,F407,F601,F602,F621,F622,F631,F632,F633,F634,F701,F702,F704,F706,F707,F721,F722,F723,F821,F822,F823,F831,F901
- name: run Black
run: |
black --exclude '(^\.git|\.github)' --check .
- name: check Python Files
run: |
# Find all Python files and check their syntax in parallel
find . -name '*.py' | \
xargs -P 16 -I {} bash -c '
echo "Checking python file: {}"
python -m py_compile "{}" || \
{ echo "Invalid python syntax in {}"; exit 1; }
'
setenv:
runs-on: [self-hosted, linux, x64]
needs: linting
outputs:
RABBIT_OUTDIR: ${{steps.export.outputs.RABBIT_OUTDIR}}
WEB_DIR: ${{steps.export.outputs.WEB_DIR}}
PLOT_DIR: ${{steps.export.outputs.PLOT_DIR}}
PYTHONPATH: ${{steps.export.outputs.PYTHONPATH}}
PATH: ${{steps.export.outputs.PATH}}
steps:
- uses: actions/checkout@v4
- name: setup kerberos
run: |
kinit -kt ~/private/.keytab cmsmwbot@CERN.CH
klist -k -t -e ~/private/.keytab
klist
echo "xrdfs root://eosuser.cern.ch// ls $EOS_DIR"
xrdfs root://eosuser.cern.ch// ls $EOS_DIR
- name: setup unscheduled
if: github.event_name != 'schedule'
run: echo PLOT_DIR=PR$(echo $GITHUB_REF | awk 'BEGIN { FS = "/" } ; { print $3 }')/$(date +%Y_%m_%d) >> $GITHUB_ENV
- name: setup reference run
if: github.event_name == 'schedule'
run: |
echo PLOT_DIR=ReferenceRuns/$(date +%Y_%m_%d)_$(git rev-parse --short "$GITHUB_SHA") >> $GITHUB_ENV
- name: setup outdir
run: echo "RABBIT_OUTDIR=/tmp/${USER}/$(uuidgen)" >> $GITHUB_ENV
- name: setup python path
run: |
echo "PYTHONPATH=$GITHUB_WORKSPACE:$PYTHONPATH" >> $GITHUB_ENV
echo "PATH=$GITHUB_WORKSPACE/bin:$PATH" >> $GITHUB_ENV
- name: setup webdir
run: echo "WEB_DIR=$RABBIT_OUTDIR/$LOCAL_WEB_DIR" >> $GITHUB_ENV
- name: create plot dir
run: mkdir -p $WEB_DIR/$PLOT_DIR
- id: export
run: |
echo "RABBIT_OUTDIR=$RABBIT_OUTDIR" >> $GITHUB_OUTPUT
echo "WEB_DIR=$WEB_DIR" >> $GITHUB_OUTPUT
echo "PLOT_DIR=$PLOT_DIR" >> $GITHUB_OUTPUT
echo "PYTHONPATH=$PYTHONPATH" >> $GITHUB_OUTPUT
echo "PATH=$PATH" >> $GITHUB_OUTPUT
symmerizations:
runs-on: [self-hosted, linux, x64]
needs: setenv
steps:
- env:
RABBIT_OUTDIR: ${{ needs.setenv.outputs.RABBIT_OUTDIR }}
PYTHONPATH: ${{ needs.setenv.outputs.PYTHONPATH }}
PATH: ${{ needs.setenv.outputs.PATH }}
WEB_DIR: ${{ needs.setenv.outputs.WEB_DIR }}
PLOT_DIR: ${{ needs.setenv.outputs.PLOT_DIR }}
run: |
echo "RABBIT_OUTDIR=${RABBIT_OUTDIR}" >> $GITHUB_ENV
echo "PYTHONPATH=${PYTHONPATH}" >> $GITHUB_ENV
echo "PATH=${PATH}" >> $GITHUB_ENV
echo "WEB_DIR=${WEB_DIR}" >> $GITHUB_ENV
echo "PLOT_DIR=${PLOT_DIR}" >> $GITHUB_ENV
- uses: actions/checkout@v4
- name: symmetrizations
run: >-
python tests/symmetrizations.py -o $WEB_DIR/$PLOT_DIR/symmetrizations/ --titlePos 0
- name: symmetrizations with fluctations
run: >-
python tests/symmetrizations.py -o $WEB_DIR/$PLOT_DIR/symmetrizations/ --titlePos 0 --fluctuate
make-tensor:
runs-on: [self-hosted, linux, x64]
needs: setenv
steps:
- env:
RABBIT_OUTDIR: ${{ needs.setenv.outputs.RABBIT_OUTDIR }}
PYTHONPATH: ${{ needs.setenv.outputs.PYTHONPATH }}
PATH: ${{ needs.setenv.outputs.PATH }}
WEB_DIR: ${{ needs.setenv.outputs.WEB_DIR }}
PLOT_DIR: ${{ needs.setenv.outputs.PLOT_DIR }}
run: |
echo "RABBIT_OUTDIR=${RABBIT_OUTDIR}" >> $GITHUB_ENV
echo "PYTHONPATH=${PYTHONPATH}" >> $GITHUB_ENV
echo "PATH=${PATH}" >> $GITHUB_ENV
echo "WEB_DIR=${WEB_DIR}" >> $GITHUB_ENV
echo "PLOT_DIR=${PLOT_DIR}" >> $GITHUB_ENV
- uses: actions/checkout@v4
- name: make tensor
run: >-
python tests/make_tensor.py -o $RABBIT_OUTDIR/
- name: make bsm tensor
run: >-
python tests/make_tensor.py -o $RABBIT_OUTDIR/ --bsm --postfix bsm
- name: make symmetric tensor
run: >-
python tests/make_tensor.py -o $RABBIT_OUTDIR/ --symmetrizeAll --systematicType normal --postfix symmetric
- name: make linearized tensor
run: >-
python tests/make_tensor.py -o $RABBIT_OUTDIR/ --symmetrizeAl --systematicType normal --addSystToDataCovariance --skipMaskedChannels --postfix linearized
- name: make sparse tensor
run: >-
python tests/make_tensor.py -o $RABBIT_OUTDIR/ --sparse --postfix sparse
- name: make boost tensor
run: >-
python tests/make_tensor.py -o $RABBIT_OUTDIR/ --histType boost --postfix boost
- name: debug input
run: debug_inputdata.py $RABBIT_OUTDIR//test_tensor.hdf5
- name: plot input
run: >-
rabbit_plot_inputdata.py $RABBIT_OUTDIR/test_tensor.hdf5 -o $WEB_DIR/$PLOT_DIR
--varName slope_2_signal_ch1 --varLabel "Slope signal, 2 (ch1)" --varColor cyan
- name: plot symmetric input
run: >-
rabbit_plot_inputdata.py $RABBIT_OUTDIR/test_tensor_symmetric.hdf5 -o $WEB_DIR/$PLOT_DIR --postfix symmetric
--varName slope_2_signal_ch1SymAvg slope_2_signal_ch1SymDiff --varLabel "Slope signal, 2 (ch1) [Avg.]" "Slope signal, 2 (ch1) [Diff.]" --varColor cyan magenta
fitting:
runs-on: [self-hosted, linux, x64]
needs: [setenv, make-tensor]
steps:
- env:
RABBIT_OUTDIR: ${{ needs.setenv.outputs.RABBIT_OUTDIR }}
PYTHONPATH: ${{ needs.setenv.outputs.PYTHONPATH }}
PATH: ${{ needs.setenv.outputs.PATH }}
run: |
echo "RABBIT_OUTDIR=${RABBIT_OUTDIR}" >> $GITHUB_ENV
echo "PYTHONPATH=${PYTHONPATH}" >> $GITHUB_ENV
echo "PATH=${PATH}" >> $GITHUB_ENV
- uses: actions/checkout@v4
- name: nominal fit
run: >-
rabbit_fit.py $RABBIT_OUTDIR/test_tensor.hdf5 -o $RABBIT_OUTDIR/
-t 0 --unblind --doImpacts --globalImpacts
--saveHists --saveHistsPerProcess --computeHistErrors --computeHistErrorsPerProcess
--computeHistCov --computeHistImpacts --computeVariations
-m BaseMapping
-m Select ch0 'x:rebin(-5,-2,2,5)'
-m Project ch1 a
-m Project ch1 b
-m Project ch0_masked
-m Normalize ch0 x
-m Ratio ch0 ch0 sig sig,bkg
-m Ratio ch0 ch1 'None:None' 'b:slice(0,2),b:sum'
-m Ratio ch0 ch1 'x:slice(None,None,2),x:sum' 'a:sum,b:sum'
-m Normratio ch1 ch1 sig sig,bkg 'b:sum' 'b:2'
-m tests.param_mapping.Param 'slope_signal' 1 0
- name: nominal fit
run: >-
rabbit_fit.py $RABBIT_OUTDIR/test_tensor.hdf5 -o $RABBIT_OUTDIR/ --postfix composite
-t -1 0 --unblind '.*' --doImpacts --globalImpacts
--saveHists --saveHistsPerProcess --computeHistErrors --computeHistErrorsPerProcess
--computeHistCov --computeHistImpacts --computeVariations
--compositeMapping -m Project ch1 a -m Project ch1 b
- name: nominal fit blinded
run: >-
rabbit_fit.py $RABBIT_OUTDIR/test_tensor.hdf5 -o $RABBIT_OUTDIR/
-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
--saveHists --saveHistsPerProcess --computeHistErrors --computeHistErrorsPerProcess
-m Project ch1 a -m Project ch1 b
- name: pseudodata fit
run: >-
rabbit_fit.py $RABBIT_OUTDIR/test_tensor.hdf5 -o $RABBIT_OUTDIR/ --postfix pseudodata
-t 0 --pseudoData original --doImpacts --globalImpacts --unblind ^sig$
- name: covariance fit
run: >-
rabbit_fit.py $RABBIT_OUTDIR/test_tensor.hdf5 -o $RABBIT_OUTDIR/ --postfix covariance
-t 0 --unblind --covarianceFit --doImpacts --globalImpacts
--saveHists --saveHistsPerProcess --computeHistErrors --computeHistErrorsPerProcess
-m Project ch1 a -m Project ch1 b
- name: linearized solution
run: >-
rabbit_fit.py $RABBIT_OUTDIR/test_tensor_symmetric.hdf5 -o $RABBIT_OUTDIR/ --postfix linearized
-t 0 --chisqFit --doImpacts --globalImpacts --binByBinStatType normal-additive --allowNegativePOI
--saveHists --saveHistsPerProcess --computeHistErrors --computeHistErrorsPerProcess
--computeHistImpacts --computeHistCov -m Project ch1 a -m Project ch1 b
- name: chi2 fit with Barlow--Beeston full
run: >-
rabbit_fit.py $RABBIT_OUTDIR/test_tensor_symmetric.hdf5 -o $RABBIT_OUTDIR/ --postfix bb_full
-t 0 --globalImpacts --binByBinStatType normal-multiplicative --binByBinStatMode full
bsm:
runs-on: [self-hosted, linux, x64]
needs: [setenv, make-tensor]
steps:
- env:
RABBIT_OUTDIR: ${{ needs.setenv.outputs.RABBIT_OUTDIR }}
PYTHONPATH: ${{ needs.setenv.outputs.PYTHONPATH }}
PATH: ${{ needs.setenv.outputs.PATH }}
run: |
echo "RABBIT_OUTDIR=${RABBIT_OUTDIR}" >> $GITHUB_ENV
echo "PYTHONPATH=${PYTHONPATH}" >> $GITHUB_ENV
echo "PATH=${PATH}" >> $GITHUB_ENV
- uses: actions/checkout@v4
- name: bsm limits
run: >-
rabbit_limit.py $RABBIT_OUTDIR/test_tensor_bsm.hdf5 -o $RABBIT_OUTDIR/ --postfix bsm
-t 0 --unblind --expectSignal bsm1 0 --expectSignal bsm2 1 --allowNegativePOI --asymptoticLimits bsm1 --levels 0.05
- name: bsm limits on channel
run: >-
rabbit_limit.py $RABBIT_OUTDIR/test_tensor_bsm.hdf5 -o $RABBIT_OUTDIR/ --postfix bsm
-t 0 --unblind --poiModel Mixture bsm1 sig --expectSignal bsm1_sig_mixing 0 --asymptoticLimits bsm1_sig_mixing --levels 0.05 --allowNegativePOI
plotting:
runs-on: [self-hosted, linux, x64]
needs: [setenv, fitting]
steps:
- env:
RABBIT_OUTDIR: ${{ needs.setenv.outputs.RABBIT_OUTDIR }}
PYTHONPATH: ${{ needs.setenv.outputs.PYTHONPATH }}
PATH: ${{ needs.setenv.outputs.PATH }}
WEB_DIR: ${{ needs.setenv.outputs.WEB_DIR }}
PLOT_DIR: ${{ needs.setenv.outputs.PLOT_DIR }}
run: |
echo "RABBIT_OUTDIR=${RABBIT_OUTDIR}" >> $GITHUB_ENV
echo "PYTHONPATH=${PYTHONPATH}" >> $GITHUB_ENV
echo "PATH=${PATH}" >> $GITHUB_ENV
echo "WEB_DIR=${WEB_DIR}" >> $GITHUB_ENV
echo "PLOT_DIR=${PLOT_DIR}" >> $GITHUB_ENV
- uses: actions/checkout@v4
- name: print pulls & constraints blinded
run: rabbit_print_pulls_and_constraints.py $RABBIT_OUTDIR/fitresults_blinded.hdf5
- name: print pulls & constraints
run: rabbit_print_pulls_and_constraints.py $RABBIT_OUTDIR/fitresults.hdf5
- name: print impacts
run: rabbit_print_impacts.py $RABBIT_OUTDIR/fitresults.hdf5 -s
- name: print global impacts
run: rabbit_print_impacts.py $RABBIT_OUTDIR/fitresults.hdf5 -s --globalImpacts
- name: print global impacts of observable
run: rabbit_print_impacts.py $RABBIT_OUTDIR/fitresults.hdf5 --globalImpacts -m Project ch0_masked --ungroup --sort
- name: plot impacts
run: >-
rabbit_plot_pulls_and_impacts.py $RABBIT_OUTDIR/fitresults.hdf5 -o $WEB_DIR/$PLOT_DIR
--otherExtensions pdf png -n 50 --config tests/style_config.py -s absimpact --subtitle Preliminary --grouping max
- name: plot global impacts
run: >-
rabbit_plot_pulls_and_impacts.py $RABBIT_OUTDIR/fitresults.hdf5 -o $WEB_DIR/$PLOT_DIR
-r $RABBIT_OUTDIR/fitresults_pseudodata.hdf5 --refResult original --refName "Pseudo data" -s absimpact
--otherExtensions pdf png -n 50 --config tests/style_config.py --oneSidedImpacts --globalImpacts --diffPullAsym --showNumbers
--grouping max --subtitle Preliminary --postfix data_vs_pseudodata
- name: plot global impacts on observable
run: >-
rabbit_plot_pulls_and_impacts.py $RABBIT_OUTDIR/fitresults.hdf5 -o $WEB_DIR/$PLOT_DIR
-s absimpact -m Project ch0_masked
--otherExtensions pdf png -n 50 --config tests/style_config.py --oneSidedImpacts --globalImpacts --showNumbers
--grouping max --subtitle Preliminary --postfix ch0_masked
- name: plot prefit distributions
run: >-
rabbit_plot_hists.py $RABBIT_OUTDIR/fitresults.hdf5 -o $WEB_DIR/$PLOT_DIR
--extraTextLoc '0.05' '0.7' --legCols 1 -m BaseMapping -m Project ch1 a -m Project ch1 b --yscale '1.2'
--subtitle Preliminary --prefit --config tests/style_config.py
- name: plot postfit distributions
run: >-
rabbit_plot_hists.py $RABBIT_OUTDIR/fitresults.hdf5 -o $WEB_DIR/$PLOT_DIR
--extraTextLoc '0.05' '0.7' --legCols 1 -m BaseMapping -m Project ch1 a -m Project ch1 b -m Normalize ch0 x --yscale '1.2'
--subtitle Preliminary --varNames 'slope_signal' --varColors orange --config tests/style_config.py --rrange 0.8 1.2
- name: plot histogram uncertainties
run: >-
rabbit_plot_hists_uncertainties.py $RABBIT_OUTDIR/fitresults.hdf5 -o $WEB_DIR/$PLOT_DIR
--extraTextLoc '0.05' '0.7' --legCols 1 -m Project ch1 a -m Project ch1 b --yscale '1.2' --subtitle Preliminary --config tests/style_config.py
- name: plot postfit signal fraction
run: >-
rabbit_plot_hists.py $RABBIT_OUTDIR/fitresults.hdf5 -o $WEB_DIR/$PLOT_DIR
-m Ratio ch0 ch0 sig sig,bkg --yscale 1.2 --subtitle Preliminary --config tests/style_config.py --ylabel 'sig/(sig+bkg)' --postfix signalfraction
- name: plot postfit signal fraction uncertainties
run: >-
rabbit_plot_hists_uncertainties.py $RABBIT_OUTDIR/fitresults.hdf5 -o $WEB_DIR/$PLOT_DIR
-m Ratio ch0 ch0 sig sig,bkg --subtitle Preliminary --config tests/style_config.py --ylabel 'sig/(sig+bkg)' --postfix signalfraction
- name: plot postfit ratio
run: >-
rabbit_plot_hists.py $RABBIT_OUTDIR/fitresults.hdf5 -o $WEB_DIR/$PLOT_DIR
-m Ratio ch0 ch1 'None:None' 'b:slice(0,2)' --yscale 1.2 --subtitle Preliminary --config tests/style_config.py --ylabel 'ch0/ch1' --postfix ratio
- name: plot postfit ratio uncertainties
run: >-
rabbit_plot_hists_uncertainties.py $RABBIT_OUTDIR/fitresults.hdf5 -o $WEB_DIR/$PLOT_DIR
-m Ratio ch0 ch1 'None:None' 'b:slice(0,2)' --subtitle Preliminary --config tests/style_config.py --ylabel 'ch0/ch1' --postfix ratio
- name: plot histogram covariance matrices
run: >-
rabbit_plot_hists_cov.py $RABBIT_OUTDIR/fitresults.hdf5 -o $WEB_DIR/$PLOT_DIR
--subtitle Preliminary -m Project ch1 a -m Project ch1 b --subtitle Preliminary --config tests/style_config.py
likelihoodscans:
runs-on: [self-hosted, linux, x64]
needs: [setenv, make-tensor]
steps:
- env:
RABBIT_OUTDIR: ${{ needs.setenv.outputs.RABBIT_OUTDIR }}
PYTHONPATH: ${{ needs.setenv.outputs.PYTHONPATH }}
PATH: ${{ needs.setenv.outputs.PATH }}
WEB_DIR: ${{ needs.setenv.outputs.WEB_DIR }}
PLOT_DIR: ${{ needs.setenv.outputs.PLOT_DIR }}
run: |
echo "RABBIT_OUTDIR=${RABBIT_OUTDIR}" >> $GITHUB_ENV
echo "PYTHONPATH=${PYTHONPATH}" >> $GITHUB_ENV
echo "PATH=${PATH}" >> $GITHUB_ENV
echo "WEB_DIR=${WEB_DIR}" >> $GITHUB_ENV
echo "PLOT_DIR=${PLOT_DIR}" >> $GITHUB_ENV
- uses: actions/checkout@v4
- name: nominal fit with scans
run: >-
rabbit_fit.py $RABBIT_OUTDIR/test_tensor.hdf5 -o $RABBIT_OUTDIR/ --postfix scans
-t 0 --doImpacts
--scan sig slope_signal --contourScan sig slope_signal --contourLevels 1 2
--scan2D sig slope_signal
# --contourScan2D sig slope_signal
- name: plot 1D likelihood scan
run: >-
rabbit_plot_likelihood_scan.py $RABBIT_OUTDIR/fitresults_scans.hdf5 -o $WEB_DIR/$PLOT_DIR
--title Rabbit --subtitle Preliminary --params sig slope_signal --titlePos 0
- name: plot 2D likelihood scan
run: >-
rabbit_plot_likelihood_scan2D.py $RABBIT_OUTDIR/fitresults_scans.hdf5 -o $WEB_DIR/$PLOT_DIR
--title Rabbit --subtitle Preliminary --params sig slope_signal --titlePos 0 --legPos 'lower right'
copy-clean:
runs-on: [self-hosted, linux, x64]
needs: [setenv, symmerizations, bsm, plotting, likelihoodscans]
if: always()
steps:
- env:
RABBIT_OUTDIR: ${{ needs.setenv.outputs.RABBIT_OUTDIR }}
run: |
echo "RABBIT_OUTDIR=${RABBIT_OUTDIR}" >> $GITHUB_ENV
- name: copy clean plots
run: |
echo "xrdcp --parallel 4 -R -f $RABBIT_OUTDIR/$LOCAL_WEB_DIR/* root://eosuser.cern.ch//$EOS_DIR/$LOCAL_WEB_DIR"
xrdcp --parallel 4 -R -f $RABBIT_OUTDIR/$LOCAL_WEB_DIR/* root://eosuser.cern.ch//$EOS_DIR/$LOCAL_WEB_DIR
echo "Removing temp directory $RABBIT_OUTDIR/$LOCAL_WEB_DIR"
rm -r $RABBIT_OUTDIR/$LOCAL_WEB_DIR
- name: clean
run: |
echo "Removing temp directory $RABBIT_OUTDIR"
rm -r $RABBIT_OUTDIR