UCL Burger shop’s burger, 9 quid for 3 patties not bad. This week felt like a mix of theory revision, code archaeology, and finally getting my own Rivet routine to actually run. Less “big discovery”, more slowly making the setup honest.

Tuesday 21st October — Why was ZZ so big?
We started with a quick theory chat in the Tuesday meeting.
The Higgs doublet has four degrees of freedom. After electroweak symmetry breaking:
- three of them become the longitudinal polarisation states of W+, W− and Z,
- the last one is the physical Higgs boson.
So the Higgs sector is really where all the longitudinal W/Z behaviour is hiding, and HEL has to get this right. That is important for boosted HZ, which is exactly what I am looking at.
We also tidied up some language:
- “Single particle inclusive” – something like the total ZZ (4 lepton) cross section at high pT, inclusive in anything else.
- “Two particle exclusive” – only pp -> ZH, not adding in extra ZZ or HH contributions.
This turned out to be directly related to an old puzzle: the huge ZZ cross section I saw in Herwig over the summer.
Morning job: cross-check cross sections between MadGraph and Herwig.
- MadGraph was only generating pp -> Z0H.
- Herwig’s HEL constructor was being far too enthusiastic: it was producing ZH, ZZ, HH, etc, all at once.
- On top of that, Herwig includes all Higgs-sector couplings to W and Z, although W production itself was switched off in the config I use.
So when I thought I was looking at “ZZ only” in Herwig, I was actually summing over several processes. Once I told Herwig to be Exclusive and keep only ZH (using HPConstructor:Processes Exclusive), the cross section came down and lined up nicely with MadGraph, around 0.56 pb when all coefficients are zero.
Mystery solved: nothing exotic, just a configuration issue.
HEL sanity check — does it really become the SM?
Another important check this week was the obvious one: if I set all HEL Wilson coefficients to zero, do I recover the Standard Model?
I generated SM and HEL samples in both MadGraph and Herwig at 13 TeV and 85 TeV. With all coefficients set to zero:
- MadGraph’s HEL cross sections matched its pure SM setup.
- Herwig’s HEL numbers matched MadGraph within statistical uncertainties, once I restricted to ZH only.
So at least in terms of total cross sections, HEL behaves exactly as it should: “HEL with ci = 0 is just the SM”. That gives me a solid baseline before I start scanning non-zero coefficients.
Rivet routine – turning ZH into something measurable
The other big piece of Week 4 was getting my Rivet analysis into shape.
The process I am targeting is:
- q q-bar -> HZ
- Z -> neutrinos (invisible, gives missing transverse energy)
- H -> b b-bar (two b quarks merged into one “fat jet” when highly boosted)
At a very high Higgs pT, the two b’s end up inside a single large-radius jet. The neutrinos are invisible, so experimentally the signature is:
- one big b-tagged jet,
- plus large missing transverse energy (MET).
The logic inside analyze(const Event& event) is roughly:
- Check MET
Only keep events where the missing transverse energy is above a threshold. This picks out highly boosted, relatively clean events. - Build fat jets
Cluster jets with a large radius (around 1.0 rather than the usual 0.4). Take the leading fat jet – the one with the highest pT – and treat its pT as the Higgs pT, since the Higgs recoils against the Z. - Basic jet cuts
Apply standard pT and eta cuts to the leading fat jet. - MET vs jet pT balance
Check that MET and the jet pT are roughly similar, within a loose ratio (around 0.8–1.2). If they balance, it is consistent with a boosted H and a Z recoiling against each other. - b-tagging
Use Rivet’s bTagged / bTags machinery to check if the fat jet actually contains b-hadrons. For example,pre_mmdt_bTags = leading_fj.bTags()lets me inspect the b content. - Jet grooming with MMDT
Run the Modified Mass Drop Tagger (MMDT) on the fat jet. This:- throws away soft junk and pile-up (important for FCC-hh where pile-up is around 200),
- confirms the jet really has two hard subjets (the two b’s),
- uses parameters like z_cut to enforce some symmetry between the two subjets.
- Higgs mass window
Finally, require the jet mass after grooming to fall between about 115 and 140 GeV. If it passes, it is a Higgs candidate.
Events that survive all of this are counted, and I fill a few histograms: jet pT, MET, jet mass, and a simple pass/fail counter to measure the tagging efficiency.
Rivet vs Contur – who is in charge?
Originally, the plan was to let Contur do everything: use contur-batch to generate Herwig jobs and then just drop my new Rivet routine into the right place.
In practice, it was painful:
- Contur’s config.dat kept overwriting my carefully edited herwig.in.
- Herwig runs started from Contur could not see the new analysis at all.
- Even after reading the Contur Rivet README (helpful, but slightly depressing), Herwig still complained about not finding the routine.
The solution in the end was simple:
- Use Contur once to create a baseline herwig.in and directory layout.
- Write my own herwig.in by hand and run Herwig directly, without Contur getting in the way.
- After each fresh login, export: export RIVET_ANALYSIS_PATH=$RIVET_ANALYSIS_PATH:/unix/cedar/michaelzhang/ucl-masters-projects/FCC/FCC_2526/ZH
- Check herwig.log to make sure my analysis is actually loaded and appears in the cut-flow summary.
It now works reliably. Sometimes the “infrastructure” tools are more useful as templates than as things you actually use every day.
Week 4 in one line
HEL behaves like the SM when it should, Herwig is finally generating only the process I care about, and my first Rivet routine is alive and producing numbers. Not the most glamorous week, but a necessary one.

