diff --git a/software-basics/README.md b/1-first-steps/README.md similarity index 100% rename from software-basics/README.md rename to 1-first-steps/README.md diff --git a/software-basics/asking-questions.md b/1-first-steps/asking-questions.md similarity index 100% rename from software-basics/asking-questions.md rename to 1-first-steps/asking-questions.md diff --git a/software-basics/bookkeeping.md b/1-first-steps/bookkeeping.md similarity index 100% rename from software-basics/bookkeeping.md rename to 1-first-steps/bookkeeping.md diff --git a/software-basics/exploring-fcc-files.md b/1-first-steps/exploring-fcc-files.md similarity index 100% rename from software-basics/exploring-fcc-files.md rename to 1-first-steps/exploring-fcc-files.md diff --git a/software-basics/fccsw.md b/1-first-steps/fccsw.md similarity index 100% rename from software-basics/fccsw.md rename to 1-first-steps/fccsw.md diff --git a/software-basics/introduction-to-course.md b/1-first-steps/introduction-to-course.md similarity index 100% rename from software-basics/introduction-to-course.md rename to 1-first-steps/introduction-to-course.md diff --git a/software-basics/prerequisites.md b/1-first-steps/prerequisites.md similarity index 100% rename from software-basics/prerequisites.md rename to 1-first-steps/prerequisites.md diff --git a/software-basics/swan.md b/1-first-steps/swan.md similarity index 100% rename from software-basics/swan.md rename to 1-first-steps/swan.md diff --git a/software-basics/swan.png b/1-first-steps/swan.png similarity index 100% rename from software-basics/swan.png rename to 1-first-steps/swan.png diff --git a/software-basics/tips-tricks.md b/1-first-steps/tips-tricks.md similarity index 100% rename from software-basics/tips-tricks.md rename to 1-first-steps/tips-tricks.md diff --git a/fast-sim-and-analysis/FccFastSimGeneration.md b/2-gen-and-fastsim/2-1-event-generation/README.md similarity index 99% rename from fast-sim-and-analysis/FccFastSimGeneration.md rename to 2-gen-and-fastsim/2-1-event-generation/README.md index 02df3f5f1..aee12cd26 100644 --- a/fast-sim-and-analysis/FccFastSimGeneration.md +++ b/2-gen-and-fastsim/2-1-event-generation/README.md @@ -1,4 +1,4 @@ -# FCC: Getting started with event generation +# Getting Started with Event Generation > > Original author: Gerardo Ganis @@ -1193,7 +1193,7 @@ Now we are ready to go. #### Creating histograms with FCCAnalyses At this purpose we will use the recently introduced `build_graph` attribute. The example is availble at -[histmaker_ttmm.py](https://fccsw.web.cern.ch/tutorials/apr2023/tutorial1/histmaker_ttmm.py). +[histmaker_ttmm.py](./histmaker_ttmm.py). ##### Dissection of `histmaker_ttmm.py` @@ -1282,7 +1282,7 @@ The `build_graph` is part of the `fccanalyses run`: ```bash fccanalysis run histmaker_ttmm.py ``` -This should produce `ROTO` files with the histograms in `./outputs`: +This should produce `ROOT` files with the histograms in `./outputs`: ```bash ls -lt outputs/ ``` @@ -1302,9 +1302,9 @@ fccanalysis plots plots_ttmm.py ``` with results available under `plots`. -Example of a result are: [positive muon momentum](images/p_mup.png), -[positive muon cosine theta](images/costheta_mup.png), -[acollinearity of muons](images/acolmu.png). +Example of a result are: [positive muon momentum](p_mup.png), +[positive muon cosine theta](costheta_mup.png), +[acollinearity of muons](acolmu.png). #### Possible conclusion of the exercise diff --git a/fast-sim-and-analysis/images/acolmu.png b/2-gen-and-fastsim/2-1-event-generation/acolmu.png similarity index 100% rename from fast-sim-and-analysis/images/acolmu.png rename to 2-gen-and-fastsim/2-1-event-generation/acolmu.png diff --git a/fast-sim-and-analysis/images/costheta_mup.png b/2-gen-and-fastsim/2-1-event-generation/costheta_mup.png similarity index 100% rename from fast-sim-and-analysis/images/costheta_mup.png rename to 2-gen-and-fastsim/2-1-event-generation/costheta_mup.png diff --git a/2-gen-and-fastsim/2-1-event-generation/histmaker_ttmm.py b/2-gen-and-fastsim/2-1-event-generation/histmaker_ttmm.py new file mode 100644 index 000000000..3ea93a79b --- /dev/null +++ b/2-gen-and-fastsim/2-1-event-generation/histmaker_ttmm.py @@ -0,0 +1,92 @@ + +# list of processes (mandatory) +processList = { + 'p8_tautau_ecm91': {'fraction':1}, + 'wz_tautau_ecm91': {'fraction':1}, + 'kk_tautau_ecm91': {'fraction':1}, +} +# Link to the dictonary that contains all the cross section informations etc... +# Mandatory but anyone is good for local files +procDict = "FCCee_procDict_winter2023_IDEA.json" + +# Define the input dir (optional) +inputDir = "./generation/gen/" + +#Optional: output directory, default is local running directory +outputDir = "./outputs/histmaker/ttmm/" + +# optional: ncpus, default is 4, -1 uses all cores available +nCPUS = -1 + +# scale the histograms with the cross-section and integrated luminosity +doScale = False +# doScale = True +# intLumi = 1000000 # 1 /ab + +# define some binning for various histograms +bins_p_l = (100, 0, 50) # 0.5 GeV bins +bins_cosTheta = (50, -1, 1) +bins_acol = (50, -1, -.9) + +# build_graph function that contains the analysis logic, cuts and histograms (mandatory) +def build_graph(df, dataset): + import ROOT + ROOT.gInterpreter.Declare(""" + + #ifndef funDone + #define funDone + + float cosTheta(const edm4hep::Vector3d& in){ + return (in.z/sqrt(pow(in.x,2)+pow(in.y,2)+pow(in.z,2))); + }; + + float scalarProductNorm(const edm4hep::Vector3d& in1, const edm4hep::Vector3d& in2 ){ + return ((in1.x*in2.x + in1.y*in2.y + in1.z*in2.z)/sqrt(pow(in1.x,2)+pow(in1.y,2)+pow(in1.z,2))/sqrt(pow(in2.x,2)+pow(in2.y,2)+pow(in2.z,2) )); + }; + + float momP(const edm4hep::Vector3d& in ){ + return (sqrt(pow(in.x,2)+pow(in.y,2)+pow(in.z,2))); + }; + + #endif + """) + + results = [] + df = df.Define("weight", "1.0") + weightsum = df.Sum("weight") + + # Connect to taus + df = df.Define("tauplusvec", ROOT.MCParticle.sel_pdgID(-15, 0),["MCParticles"]) + df = df.Define("tauminusvec", ROOT.MCParticle.sel_pdgID(15, 0),["MCParticles"]) + df = df.Define("tauplus", "tauplusvec[0]") + df = df.Define("tauminus", "tauminusvec[0]") + + # Connect to muons + df = df.Define("muplusvec", ROOT.MCParticle.sel_pdgID(-13, 0),["MCParticles"]) + df = df.Define("muminusvec", ROOT.MCParticle.sel_pdgID(13, 0),["MCParticles"]) + df = df.Define("muplus", "muplusvec[0]") + df = df.Define("muminus", "muminusvec[0]") + + # CosThetas + df = df.Define("cthetaup", "cosTheta(tauplusvec[0].momentum)") + df = df.Define("cthetaum", "cosTheta(tauminusvec[0].momentum)") + df = df.Define("cthemup", "cosTheta(muplusvec[0].momentum)") + df = df.Define("cthemun", "cosTheta(muminusvec[0].momentum)") + + # Acollinearities + df = df.Define("acoltau", "scalarProductNorm(tauminusvec[0].momentum, tauplusvec[0].momentum)") + df = df.Define("acolmu", "scalarProductNorm(muminusvec[0].momentum, muplusvec[0].momentum)") + + # Muon momenta + df = df.Define("muplus_p", "momP(muplusvec[0].momentum)") + df = df.Define("muminus_p", "momP(muminusvec[0].momentum)") + + # baseline histograms, before any selection cuts (store with _cut0) + results.append(df.Histo1D(("P_mup", "", *bins_p_l), "muplus_p")) + results.append(df.Histo1D(("P_mum", "", *bins_p_l), "muminus_p")) + results.append(df.Histo1D(("CosTheta_taup", "", *bins_cosTheta), "cthetaup")) + results.append(df.Histo1D(("CosTheta_mup", "", *bins_cosTheta), "cthemup")) + results.append(df.Histo1D(("AcolTau", "", *bins_acol), "acoltau")) + results.append(df.Histo1D(("AcolMu", "", *bins_acol), "acolmu")) + + return results, weightsum diff --git a/fast-sim-and-analysis/images/p_mup.png b/2-gen-and-fastsim/2-1-event-generation/p_mup.png similarity index 100% rename from fast-sim-and-analysis/images/p_mup.png rename to 2-gen-and-fastsim/2-1-event-generation/p_mup.png diff --git a/fast-sim-and-analysis/k4simdelphes/doc/starterkit/FccFastSimDelphes/Readme.md b/2-gen-and-fastsim/2-2-fastsim-delphes/README.md similarity index 99% rename from fast-sim-and-analysis/k4simdelphes/doc/starterkit/FccFastSimDelphes/Readme.md rename to 2-gen-and-fastsim/2-2-fastsim-delphes/README.md index 5005468cd..5ffd14f0c 100644 --- a/fast-sim-and-analysis/k4simdelphes/doc/starterkit/FccFastSimDelphes/Readme.md +++ b/2-gen-and-fastsim/2-2-fastsim-delphes/README.md @@ -1,4 +1,4 @@ -# FCC: Getting started with simulating events in Delphes +# Getting Started with Fast Simulation in Delphes :::{admonition} Learning Objectives :class: objectives diff --git a/fast-sim-and-analysis/eedE.md b/2-gen-and-fastsim/2-4-eedE/README.md similarity index 95% rename from fast-sim-and-analysis/eedE.md rename to 2-gen-and-fastsim/2-4-eedE/README.md index cec92a09b..4ec3ab243 100644 --- a/fast-sim-and-analysis/eedE.md +++ b/2-gen-and-fastsim/2-4-eedE/README.md @@ -1,4 +1,4 @@ -Understanding generated process: eedE +EDM4hep Event Data Explorer: eedE =========================================== The [EDM4hep event data explorer (eedE)](https://key4hep.github.io/eede/release/index.html) is a tool for visualizing the association between various objects in EDM4hep events. It is lightweight and self-explanatory. This section explains the usage of eedE. @@ -38,7 +38,7 @@ An example output can be found at [example.edm4hep.json](https://fccsw.web.cern. ## Using eedE Once the data has been converted into a json format via edm4hep2json, one can then head to the website of [eedE](https://key4hep.github.io/eede/release/index.html). After pressing the Start button, one is required to upload the EDM4hep json file via the Browse button. You can then select the type of association (`view`) to visualize. -```{image} images/eedE/eede_upload.png +```{image} eede_upload.png :align: center :width: 600px ``` @@ -47,7 +47,7 @@ Once the data has been converted into a json format via edm4hep2json, one can th Here we take the MC particle tree as an example. In the tree shown in the picture illustrates a collision at 91 GeV, where both the electron and positron emit a ISR photon before they merge into an on-shell Z boson, which decays into a pair of b quarks. -```{image} images/eedE/eede_Zbb_example.png +```{image} eede_Zbb_example.png :align: center :width: 400px ``` diff --git a/fast-sim-and-analysis/images/eedE/eede_Zbb_example.png b/2-gen-and-fastsim/2-4-eedE/eede_Zbb_example.png similarity index 100% rename from fast-sim-and-analysis/images/eedE/eede_Zbb_example.png rename to 2-gen-and-fastsim/2-4-eedE/eede_Zbb_example.png diff --git a/fast-sim-and-analysis/images/eedE/eede_upload.png b/2-gen-and-fastsim/2-4-eedE/eede_upload.png similarity index 100% rename from fast-sim-and-analysis/images/eedE/eede_upload.png rename to 2-gen-and-fastsim/2-4-eedE/eede_upload.png diff --git a/2-gen-and-fastsim/README.md b/2-gen-and-fastsim/README.md new file mode 100644 index 000000000..2dfedec90 --- /dev/null +++ b/2-gen-and-fastsim/README.md @@ -0,0 +1,24 @@ +# Generation and Fast Simulation + +If you want to get started with generation and a first quick inspection of fast-simulated +events, you're at the right place. This chapter focuses on the generation of samples. A more in-depth look at FCCAnalyse is given in the next chapter. + +Fast simulation is currently supported through the Delphes approach. Support for the Papas approach, initially used for FCC-ee, is +discontinued. + +If you have any problems or questions, you can +[open an issue][fcc-tutorials-issues] on the +[GitHub repository where these lessons are developed][fcc-tutorials-repo]. + + +[fcc-tutorials-issues]: https://github.com/HEP-FCC/fcc-tutorials/issues +[fcc-tutorials-repo]: https://github.com/HEP-FCC/fcc-tutorials + +```{eval-rst} +.. toctree:: + :caption: Contents: + + 2-1-event-generation/README.md + 2-2-fastsim-delphes/README.md + 2-4-eedE/README.md +``` diff --git a/3-analysis/3-1-higgs-analysis/README.md b/3-analysis/3-1-higgs-analysis/README.md new file mode 100644 index 000000000..6dda80f12 --- /dev/null +++ b/3-analysis/3-1-higgs-analysis/README.md @@ -0,0 +1,146 @@ +# Getting Started: Higgs Mass Analysis with FCCAnalyses + +> +> Original author: Michele Selvaggi +> + +Let's first clone and build `FCCAnalyses` with the following commands: +```bash +git clone --branch master https://github.com/HEP-FCC/FCCAnalyses.git +cd FCCAnalyses +source ./setup.sh +fccanalysis build -j 8 +``` +and create a directory containing this tutorial: +```bash +cd .. +mkdir tutorial && cd tutorial +``` + +Copy the necessary files, either from the web or from some location where the +files were produced locally + +```bash +mkdir localSamples && cd localSamples +mkdir p8_ee_WW_mumu_ecm240 && cd p8_ee_WW_mumu_ecm240 +wget https://fccsw.web.cern.ch/tutorials/ana-sim-evt/p8_ee_WW_mumu_ecm240/p8_ee_WW_mumu_ecm240_edm4hep.root +cd .. +mkdir p8_ee_ZZ_mumubb_ecm240 && cd p8_ee_ZZ_mumubb_ecm240 +wget https://fccsw.web.cern.ch/tutorials/ana-sim-evt/p8_ee_ZZ_mumubb_ecm240/p8_ee_ZZ_mumubb_ecm240_edm4hep.root +cd .. +mkdir p8_ee_ZH_Zmumu_ecm240 && cd p8_ee_ZH_Zmumu_ecm240 +wget https://fccsw.web.cern.ch/tutorials/ana-sim-evt/p8_ee_ZH_Zmumu_ecm240/p8_ee_ZH_Zmumu_ecm240_edm4hep.root +cd ../.. +``` + +This tutorial consists in two parts. Both parts will make use of ee->ZH (Z->mumu)events, with its relevant backgrounds ee->WW and ee->ZZ: + +- in **Part I** you will construct the recoil mass observable and apply a list of pre-selection cuts. +- in **Part II** you will learn how to run an exclusive jet clustering algorithm, evaluate the various jet flavor probabilities and use them to select H->bb events. + +:::{admonition} Learning Objectives +:class: objectives + +In this first example, you will learn how to: + +- read the **edm4hep** data format and construct physics observable (such as the recoil mass) +- define C++ helper functions in a separate that will be compiled at run time +- apply an **event selection** and **fill histograms** in a single iteration using the **histmaker** option. +- produce **flat ntuples** with observables of interest with **FCCAnalyses** +- produce plots with the **plot** option. +::: + +## Part I - Recoil Mass: Analysis and Histograms in a Single Step + +Start by downloading this file called [functions.h](functions.h). This contains C++ helper functions that you will need to compute observables with RDataframe. + +Next, download the [histmaker_recoil.py](histmaker_recoil.py) script, which processes the previously produced ROOT samples, reconstructs muon and Z candidates, applies a sequence of event-selection cuts, and produces a set of histograms. + +The script first defines the input/output paths, luminosity scaling, and histogram binning. The main analysis logic is implemented in the ```build_graph``` function: reconstructed muons are selected and isolated muons with ```p > 20 GeV``` are retained. The analysis then applies successive cuts, including opposite-sign muon selection, Z-boson candidate reconstruction, Z mass and momentum requirements, missing-energy selection, and finally a recoil-mass window to suppress background processes. + +Before running the script, update the ```inputDir``` variable so it points to the directory containing your local samples; the output histograms will be written to ```outputDir```. Finally, run the histmaker script using the fccanalysis ```run``` parameter to generate a ROOT file containing the resulting TH1 histograms: + +```bash +fccanalysis run histmaker_recoil.py +``` + +Now download the the plotting script [plots_recoil.py](plots_recoil.py) and run it using the fccanalysis ```plots``` parameter: + + +```bash +fccanalysis plots plots_recoil.py +``` + +Please note that the event statistics is not great because we only produced on 10 000 events in the `Delphes Fast Simulation` step. + + +## Part II - Jet Flavor: Producing a flat ntuple tree before creating histograms and plots + +:::{admonition} Learning Objectives +:class: objectives + +In this second example, you will learn how to: + +- read the **edm4hep** data format, produce jet collections and evaluate the ParticleNet jet tagger score and apply an an event **preselection** +- produce **flat ntuples** with observables of interest with **FCCAnalyses** +- apply an **event selection** and **fill histograms** in a single iteration using the **histmaker** option. +- produce plots with the **plot** option. +::: + + +This first analysis stage usually runs on large samples on batch, and the idea is to produce small ntuples with less variables. Also, jet inference of the jet tagger is pretty slow, and usually has to be performed only once. In this exercise we will run the **histmaker** in a separate, second stage. + +Download this analysis script [treemaker_flavor.py](treemaker_flavor.py) and run + +```bash +fccanalysis run treemaker_flavor.py +``` + +This will produce a root file for every process containing a flat tree `events` containing high-level variables. In addition to selecting muons as done in the previous example, this script create a new collection of `ReconstructedParticles` without the two high energy muons, and runs the jet clustering algorithm in exclusive N=2 mode of the new collection. In such a way, the two clustered jets form the H->jj jet candidates. The jet flavour algorithm is then evaluated on these two jets and the relevant scores are stored in the output tree. + +Now we can download a dedicated [histmaker_flavor.py](histmaker_flavor.py) script, that runs this time on the just created flat ntuples files instead of the edm4hep format. + +Run it as before: + +```bash +fccanalysis run histmaker_flavor.py +``` + +This script takes the ntuples produced in the previous step, applies a similar selection as in the previous examples, but requires the jets to have a high probability to be B-like. + +To compare the results between the flavor and recoil approaches, we again produce plots using a dedicated [plots_flavor.py](plots_flavor.py) script and run it: + +```bash +fccanalysis plots plots_flavor.py +``` + +:::{admonition} Exercises +:class: challenge + +## Simple + +1) Modify `histmaker_flavor.py` to require the two jets individually to be B-like, i.e requiring the B score is greater 0.5 for each jet. + +2) Selecting gluon-like jets instead. You will need to modify both the `treemaker_flavor.py` and `histmaker_flavor.py` for this.) + +3) Produce plots with larger statistics by re-running `DelphesPythia8_EDM4HEP` with more events. In particular produce a ZZ inclusive sample using to include all Z decays. Rerun all the examples above. + +## Advanced + +1) To evaluate the impact of detector performance, smear the neutral hadron resolution in the `ReconstructedParticlesNoMuons` collection and check the impact on the dijet invariant mass resolution. An example can be found [here] (https://github.com/HEP-FCC/FCCAnalyses/blob/master/examples/FCCee/smearing/smear_jets.py): + +2) Now smear the impact parameter resolution and evaluate the imapct on the efficiency of selecting two B-tagged jets or two C-tagged jets. + +3) **This part can only be on lxplus and for people having the access rights to eos and the analysis dictonary** +In order to produce plots with more statistics using centrally produced samples, we could use already processed large statistics samples. +To do so we re-run the pre-selection over 10 percent of the total statistics [here](https://fcc-physics-events.web.cern.ch/FCCee/spring2021/Delphesevents_IDEA.php). +Add to your a `analysis_stage1.py` file + +```python +processList = { + 'p8_ee_ZZ_ecm240':{'fraction':0.1}, + 'p8_ee_WW_ecm240':{'fraction':0.1}, + 'p8_ee_ZH_ecm240':{'fraction':0.1} +} +prodTag = "FCCee/winter2023/IDEA/" +::: diff --git a/fast-sim-and-analysis/fccanalyses/doc/starterkit/FccFastSimAnalysis/analysis.py b/3-analysis/3-1-higgs-analysis/analysis.py similarity index 100% rename from fast-sim-and-analysis/fccanalyses/doc/starterkit/FccFastSimAnalysis/analysis.py rename to 3-analysis/3-1-higgs-analysis/analysis.py diff --git a/fast-sim-and-analysis/fccanalyses/doc/starterkit/FccFastSimAnalysis/doPlots.py b/3-analysis/3-1-higgs-analysis/doPlots.py similarity index 100% rename from fast-sim-and-analysis/fccanalyses/doc/starterkit/FccFastSimAnalysis/doPlots.py rename to 3-analysis/3-1-higgs-analysis/doPlots.py diff --git a/fast-sim-and-analysis/fccanalyses/doc/starterkit/FccFastSimAnalysis/finalSel.py b/3-analysis/3-1-higgs-analysis/finalSel.py similarity index 100% rename from fast-sim-and-analysis/fccanalyses/doc/starterkit/FccFastSimAnalysis/finalSel.py rename to 3-analysis/3-1-higgs-analysis/finalSel.py diff --git a/3-analysis/3-1-higgs-analysis/functions.h b/3-analysis/3-1-higgs-analysis/functions.h new file mode 100644 index 000000000..f5f191154 --- /dev/null +++ b/3-analysis/3-1-higgs-analysis/functions.h @@ -0,0 +1,270 @@ +#ifndef ZHfunctions_H +#define ZHfunctions_H + +#include +#include +#include + +#include "TLorentzVector.h" +#include "ROOT/RVec.hxx" +#include "edm4hep/ReconstructedParticleData.h" +#include "edm4hep/MCParticleData.h" +#include "edm4hep/ParticleIDData.h" +#include "ReconstructedParticle2MC.h" + + +namespace FCCAnalyses { namespace ZHfunctions { + + +// build the Z resonance based on the available leptons. Returns the best lepton pair compatible with the Z mass and recoil at 125 GeV +// technically, it returns a ReconstructedParticleData object with index 0 the di-lepton system, index and 2 the leptons of the pair +struct resonanceBuilder_mass_recoil { + float m_resonance_mass; + float m_recoil_mass; + float chi2_recoil_frac; + float ecm; + bool m_use_MC_Kinematics; + resonanceBuilder_mass_recoil(float arg_resonance_mass, float arg_recoil_mass, float arg_chi2_recoil_frac, float arg_ecm, bool arg_use_MC_Kinematics); + Vec_rp operator()(Vec_rp legs, Vec_i recind, Vec_i mcind, Vec_rp reco, Vec_mc mc, Vec_i parents, Vec_i daugthers) ; +}; + +resonanceBuilder_mass_recoil::resonanceBuilder_mass_recoil(float arg_resonance_mass, float arg_recoil_mass, float arg_chi2_recoil_frac, float arg_ecm, bool arg_use_MC_Kinematics) {m_resonance_mass = arg_resonance_mass, m_recoil_mass = arg_recoil_mass, chi2_recoil_frac = arg_chi2_recoil_frac, ecm = arg_ecm, m_use_MC_Kinematics = arg_use_MC_Kinematics;} + +Vec_rp resonanceBuilder_mass_recoil::resonanceBuilder_mass_recoil::operator()(Vec_rp legs, Vec_i recind, Vec_i mcind, Vec_rp reco, Vec_mc mc, Vec_i parents, Vec_i daugthers) { + + Vec_rp result; + result.reserve(3); + std::vector> pairs; // for each permutation, add the indices of the muons + int n = legs.size(); + + if(n > 1) { + ROOT::VecOps::RVec v(n); + std::fill(v.end() - 2, v.end(), true); // helper variable for permutations + do { + std::vector pair; + rp reso; + reso.charge = 0; + TLorentzVector reso_lv; + for(int i = 0; i < n; ++i) { + if(v[i]) { + pair.push_back(i); + reso.charge += legs[i].charge; + TLorentzVector leg_lv; + + if(m_use_MC_Kinematics) { // MC kinematics + int track_index = legs[i].tracks_begin; // index in the Track array + int mc_index = ReconstructedParticle2MC::getTrack2MC_index(track_index, recind, mcind, reco); + if (mc_index >= 0 && mc_index < mc.size()) { + leg_lv.SetXYZM(mc.at(mc_index).momentum.x, mc.at(mc_index).momentum.y, mc.at(mc_index).momentum.z, mc.at(mc_index).mass); + } + } + else { // reco kinematics + leg_lv.SetXYZM(legs[i].momentum.x, legs[i].momentum.y, legs[i].momentum.z, legs[i].mass); + } + + reso_lv += leg_lv; + } + } + + if(reso.charge != 0) continue; // neglect non-zero charge pairs + reso.momentum.x = reso_lv.Px(); + reso.momentum.y = reso_lv.Py(); + reso.momentum.z = reso_lv.Pz(); + reso.mass = reso_lv.M(); + result.emplace_back(reso); + pairs.push_back(pair); + + } while(std::next_permutation(v.begin(), v.end())); + } + else { + std::cout << "ERROR: resonanceBuilder_mass_recoil, at least two leptons required." << std::endl; + exit(1); + } + + if(result.size() > 1) { + + Vec_rp bestReso; + + int idx_min = -1; + float d_min = 9e9; + for (int i = 0; i < result.size(); ++i) { + + // calculate recoil + auto recoil_p4 = TLorentzVector(0, 0, 0, ecm); + TLorentzVector tv1; + tv1.SetXYZM(result.at(i).momentum.x, result.at(i).momentum.y, result.at(i).momentum.z, result.at(i).mass); + recoil_p4 -= tv1; + + auto recoil_fcc = edm4hep::ReconstructedParticleData(); + recoil_fcc.momentum.x = recoil_p4.Px(); + recoil_fcc.momentum.y = recoil_p4.Py(); + recoil_fcc.momentum.z = recoil_p4.Pz(); + recoil_fcc.mass = recoil_p4.M(); + + TLorentzVector tg; + tg.SetXYZM(result.at(i).momentum.x, result.at(i).momentum.y, result.at(i).momentum.z, result.at(i).mass); + + float boost = tg.P(); + float mass = std::pow(result.at(i).mass - m_resonance_mass, 2); // mass + float rec = std::pow(recoil_fcc.mass - m_recoil_mass, 2); // recoil + float d = (1.0-chi2_recoil_frac)*mass + chi2_recoil_frac*rec; + + if(d < d_min) { + d_min = d; + idx_min = i; + } + + + } + if(idx_min > -1) { + bestReso.push_back(result.at(idx_min)); + auto & l1 = legs[pairs[idx_min][0]]; + auto & l2 = legs[pairs[idx_min][1]]; + bestReso.emplace_back(l1); + bestReso.emplace_back(l2); + } + else { + std::cout << "ERROR: resonanceBuilder_mass_recoil, no mininum found." << std::endl; + exit(1); + } + return bestReso; + } + else { + auto & l1 = legs[0]; + auto & l2 = legs[1]; + result.emplace_back(l1); + result.emplace_back(l2); + return result; + } +} + + + + +struct sel_iso { + sel_iso(float arg_max_iso); + float m_max_iso = .25; + Vec_rp operator() (Vec_rp in, Vec_f iso); + }; + +sel_iso::sel_iso(float arg_max_iso) : m_max_iso(arg_max_iso) {}; +ROOT::VecOps::RVec sel_iso::operator() (Vec_rp in, Vec_f iso) { + Vec_rp result; + result.reserve(in.size()); + for (size_t i = 0; i < in.size(); ++i) { + auto & p = in[i]; + if (iso[i] < m_max_iso) { + result.emplace_back(p); + } + } + return result; +} + + +// compute the cone isolation for reco particles +struct coneIsolation { + + coneIsolation(float arg_dr_min, float arg_dr_max); + double deltaR(double eta1, double phi1, double eta2, double phi2) { return TMath::Sqrt(TMath::Power(eta1-eta2, 2) + (TMath::Power(phi1-phi2, 2))); }; + + float dr_min = 0; + float dr_max = 0.4; + Vec_f operator() (Vec_rp in, Vec_rp rps) ; +}; + +coneIsolation::coneIsolation(float arg_dr_min, float arg_dr_max) : dr_min(arg_dr_min), dr_max( arg_dr_max ) { }; +Vec_f coneIsolation::coneIsolation::operator() (Vec_rp in, Vec_rp rps) { + + Vec_f result; + result.reserve(in.size()); + + std::vector lv_reco; + std::vector lv_charged; + std::vector lv_neutral; + + for(size_t i = 0; i < rps.size(); ++i) { + + ROOT::Math::PxPyPzEVector tlv; + tlv.SetPxPyPzE(rps.at(i).momentum.x, rps.at(i).momentum.y, rps.at(i).momentum.z, rps.at(i).energy); + + if(rps.at(i).charge == 0) lv_neutral.push_back(tlv); + else lv_charged.push_back(tlv); + } + + for(size_t i = 0; i < in.size(); ++i) { + + ROOT::Math::PxPyPzEVector tlv; + tlv.SetPxPyPzE(in.at(i).momentum.x, in.at(i).momentum.y, in.at(i).momentum.z, in.at(i).energy); + lv_reco.push_back(tlv); + } + + + // compute the isolation (see https://github.com/delphes/delphes/blob/master/modules/Isolation.cc#L154) + for (auto & lv_reco_ : lv_reco) { + + double sumNeutral = 0.0; + double sumCharged = 0.0; + + // charged + for (auto & lv_charged_ : lv_charged) { + + double dr = coneIsolation::deltaR(lv_reco_.Eta(), lv_reco_.Phi(), lv_charged_.Eta(), lv_charged_.Phi()); + if(dr > dr_min && dr < dr_max) sumCharged += lv_charged_.P(); + } + + // neutral + for (auto & lv_neutral_ : lv_neutral) { + + double dr = coneIsolation::deltaR(lv_reco_.Eta(), lv_reco_.Phi(), lv_neutral_.Eta(), lv_neutral_.Phi()); + if(dr > dr_min && dr < dr_max) sumNeutral += lv_neutral_.P(); + } + + double sum = sumCharged + sumNeutral; + double ratio= sum / lv_reco_.P(); + result.emplace_back(ratio); + } + return result; +} + + + +// returns missing energy vector, based on reco particles +Vec_rp missingEnergy(float ecm, Vec_rp in, float p_cutoff = 0.0) { + float px = 0, py = 0, pz = 0, e = 0; + for(auto &p : in) { + if (std::sqrt(p.momentum.x * p.momentum.x + p.momentum.y*p.momentum.y) < p_cutoff) continue; + px += -p.momentum.x; + py += -p.momentum.y; + pz += -p.momentum.z; + e += p.energy; + } + + Vec_rp ret; + rp res; + res.momentum.x = px; + res.momentum.y = py; + res.momentum.z = pz; + res.energy = ecm-e; + ret.emplace_back(res); + return ret; +} + +// calculate the cosine(theta) of the missing energy vector +float get_cosTheta_miss(Vec_rp met){ + + float costheta = 0.; + if(met.size() > 0) { + + TLorentzVector lv_met; + lv_met.SetPxPyPzE(met[0].momentum.x, met[0].momentum.y, met[0].momentum.z, met[0].energy); + costheta = fabs(std::cos(lv_met.Theta())); + } + return costheta; +} + + + + +}} + +#endif \ No newline at end of file diff --git a/3-analysis/3-1-higgs-analysis/histmaker_flavor.py b/3-analysis/3-1-higgs-analysis/histmaker_flavor.py new file mode 100644 index 000000000..9a7ca275f --- /dev/null +++ b/3-analysis/3-1-higgs-analysis/histmaker_flavor.py @@ -0,0 +1,90 @@ +# list of processes (mandatory) +processList = { + "p8_ee_ZH_Zmumu_ecm240": { + "fraction": 1, + "crossSection": 0.201868 * 0.034, + }, + "p8_ee_ZZ_mumubb_ecm240": { + "fraction": 1, + "crossSection": 2 * 1.35899 * 0.034 * 0.152, + }, +} + +# Production tag when running over EDM4Hep centrally produced events, this points to the yaml files for getting sample statistics (mandatory) +#prodTag = "FCCee/winter2023/IDEA/" + +# Link to the dictonary that contains all the cross section informations etc... (mandatory) +procDict = "FCCee_procDict_winter2023_IDEA.json" + +# Define the input dir (optional) +inputDir = "./outputs/treemaker/flavor/" + +# Optional: output directory, default is local running directory +outputDir = "./outputs/histmaker/flavor/" + + +# optional: ncpus, default is 4, -1 uses all cores available +nCPUS = -1 + +# scale the histograms with the cross-section and integrated luminosity +doScale = True +intLumi = 5000000 # 5 /ab + + +# define some binning for various histograms +bins_p_mu = (2000, 0, 200) # 100 MeV bins +bins_m_ll = (2000, 0, 200) # 100 MeV bins +bins_p_ll = (2000, 0, 200) # 100 MeV bins +bins_recoil = (200000, 0, 200) # 1 MeV bins +bins_cosThetaMiss = (10000, 0, 1) + +bins_m_jj = (100, 50, 150) # 1 GeV bins +bins_score = (50, 0, 2.0) # + +bins_theta = (500, -5, 5) +bins_eta = (600, -3, 3) +bins_phi = (500, -5, 5) + +bins_count = (50, 0, 50) +bins_charge = (10, -5, 5) +bins_iso = (500, 0, 5) + + +# build_graph function that contains the analysis logic, cuts and histograms (mandatory) +def build_graph(df, dataset): + + results = [] + df = df.Define("weight", "1.0") + weightsum = df.Sum("weight") + + ######### + ### CUT 4: Z mass window + ######### + df = df.Filter("zmumu_m > 86 && zmumu_m < 96") + + ######### + ### CUT 5: Z momentum + ######### + df = df.Filter("zmumu_p > 20 && zmumu_p < 70") + + ######### + ### CUT 6: recoil mass window + ######### + df = df.Filter("zmumu_recoil_m < 140 && zmumu_recoil_m > 120") + + ######### + ### CUT 7: cut on the jet tagging score to select H->bb events + ######### + df = df.Define("scoresum_B", "recojet_isB[0] + recojet_isB[1]") + results.append(df.Histo1D(("scoresum_B", "", *bins_score), "scoresum_B")) + + df = df.Filter("scoresum_B > 1.0") + + results.append(df.Histo1D(("zmumu_m", "", *bins_m_ll), "zmumu_m")) + results.append( + df.Histo1D(("zmumu_recoil_m", "", *bins_recoil), "zmumu_recoil_m") + ) + results.append(df.Histo1D(("zmumu_p", "", *bins_p_ll), "zmumu_p")) + results.append(df.Histo1D(("jj_m", "", *bins_m_jj), "jj_m")) + + return results, weightsum \ No newline at end of file diff --git a/3-analysis/3-1-higgs-analysis/histmaker_recoil.py b/3-analysis/3-1-higgs-analysis/histmaker_recoil.py new file mode 100644 index 000000000..1337f8211 --- /dev/null +++ b/3-analysis/3-1-higgs-analysis/histmaker_recoil.py @@ -0,0 +1,176 @@ +# list of processes (mandatory) +processList = { + #'p8_ee_ZZ_ecm240':{'fraction':1}, + #'p8_ee_WW_ecm240':{'fraction':1}, + #'wzp6_ee_mumuH_ecm240':{'fraction':1}, + 'p8_ee_WW_mumu_ecm240': {'fraction':1, 'crossSection': 0.25792}, + 'p8_ee_ZZ_mumubb_ecm240': {'fraction':1, 'crossSection': 2 * 1.35899 * 0.034 * 0.152}, + 'p8_ee_ZH_Zmumu_ecm240': {'fraction':1, 'crossSection': 0.201868 * 0.034}, +} + +# Production tag when running over EDM4Hep centrally produced events, this points to the yaml files for getting sample statistics (mandatory) +#prodTag = "FCCee/winter2023/IDEA/" + +# Link to the dictonary that contains all the cross section informations etc... (mandatory) +procDict = "FCCee_procDict_winter2023_IDEA.json" + +# additional/custom C++ functions, defined in header files (optional) +includePaths = ["functions.h"] + +# Define the input dir (optional) +#inputDir = "outputs/FCCee/higgs/mH-recoil/mumu/stage1" +inputDir = "./localSamples/" + +#Optional: output directory, default is local running directory +outputDir = "./outputs/histmaker/recoil/" + + +# optional: ncpus, default is 4, -1 uses all cores available +nCPUS = -1 + +# scale the histograms with the cross-section and integrated luminosity +doScale = True +intLumi = 5000000 # 5 /ab + + +# define some binning for various histograms +bins_p_mu = (2000, 0, 200) # 100 MeV bins +bins_m_ll = (2000, 0, 200) # 100 MeV bins +bins_p_ll = (2000, 0, 200) # 100 MeV bins +bins_recoil = (200000, 0, 200) # 1 MeV bins +bins_cosThetaMiss = (10000, 0, 1) + +bins_theta = (500, -5, 5) +bins_eta = (600, -3, 3) +bins_phi = (500, -5, 5) + +bins_count = (50, 0, 50) +bins_charge = (10, -5, 5) +bins_iso = (500, 0, 5) + + + +# build_graph function that contains the analysis logic, cuts and histograms (mandatory) +def build_graph(df, dataset): + + results = [] + df = df.Define("weight", "1.0") + weightsum = df.Sum("weight") + + # define some aliases to be used later on + df = df.Alias("Particle0", "_Particle_daughters.index") + df = df.Alias("Particle1", "_Particle_parents.index") + df = df.Alias("RecoMCLink0", "_RecoMCLink_from.index") + df = df.Alias("RecoMCLink1", "_RecoMCLink_to.index") + df = df.Alias("Muon0", "Muon_objIdx.index") + + + # get all the leptons from the collection + df = df.Define("muons_all", "FCCAnalyses::ReconstructedParticle::get(Muon0, ReconstructedParticles)") + # select leptons with momentum > 20 GeV + df = df.Define("muons", "FCCAnalyses::ReconstructedParticle::sel_p(20)(muons_all)") + + df = df.Define("muons_p", "FCCAnalyses::ReconstructedParticle::get_p(muons)") + df = df.Define("muons_theta", "FCCAnalyses::ReconstructedParticle::get_theta(muons)") + df = df.Define("muons_phi", "FCCAnalyses::ReconstructedParticle::get_phi(muons)") + df = df.Define("muons_q", "FCCAnalyses::ReconstructedParticle::get_charge(muons)") + df = df.Define("muons_no", "FCCAnalyses::ReconstructedParticle::get_n(muons)") + + # compute the muon isolation and store muons with an isolation cut of 0.25 in a separate column muons_sel_iso + df = df.Define("muons_iso", "FCCAnalyses::ZHfunctions::coneIsolation(0.01, 0.5)(muons, ReconstructedParticles)") + df = df.Define("muons_sel_iso", "FCCAnalyses::ZHfunctions::sel_iso(0.25)(muons, muons_iso)") + + + # baseline histograms, before any selection cuts (store with _cut0) + results.append(df.Histo1D(("muons_p_cut0", "", *bins_p_mu), "muons_p")) + results.append(df.Histo1D(("muons_theta_cut0", "", *bins_theta), "muons_theta")) + results.append(df.Histo1D(("muons_phi_cut0", "", *bins_phi), "muons_phi")) + results.append(df.Histo1D(("muons_q_cut0", "", *bins_charge), "muons_q")) + results.append(df.Histo1D(("muons_no_cut0", "", *bins_count), "muons_no")) + results.append(df.Histo1D(("muons_iso_cut0", "", *bins_iso), "muons_iso")) + + + ######### + ### CUT 0: all events + ######### + df = df.Define("cut0", "0") + results.append(df.Histo1D(("cutFlow", "", *bins_count), "cut0")) + + + ######### + ### CUT 1: at least 1 muon with at least one isolated one + ######### + df = df.Filter("muons_no >= 1 && muons_sel_iso.size() > 0") + df = df.Define("cut1", "1") + results.append(df.Histo1D(("cutFlow", "", *bins_count), "cut1")) + + + ######### + ### CUT 2 :at least 2 opposite-sign (OS) leptons + ######### + df = df.Filter("muons_no >= 2 && abs(Sum(muons_q)) < muons_q.size()") + df = df.Define("cut2", "2") + results.append(df.Histo1D(("cutFlow", "", *bins_count), "cut2")) + + # now we build the Z resonance based on the available leptons. + # the function resonanceBuilder_mass_recoil returns the best lepton pair compatible with the Z mass (91.2 GeV) and recoil at 125 GeV + # the argument 0.4 gives a weight to the Z mass and the recoil mass in the chi2 minimization + # technically, it returns a ReconstructedParticleData object with index 0 the di-lepton system, index and 2 the leptons of the pair + df = df.Define("zbuilder_result", "FCCAnalyses::ZHfunctions::resonanceBuilder_mass_recoil(91.2, 125, 0.4, 240, false)(muons, RecoMCLink0, RecoMCLink1, ReconstructedParticles, Particle, Particle0, Particle1)") + df = df.Define("zmumu", "Vec_rp{zbuilder_result[0]}") # the Z + df = df.Define("zmumu_muons", "Vec_rp{zbuilder_result[1],zbuilder_result[2]}") # the leptons + df = df.Define("zmumu_m", "FCCAnalyses::ReconstructedParticle::get_mass(zmumu)[0]") # Z mass + df = df.Define("zmumu_p", "FCCAnalyses::ReconstructedParticle::get_p(zmumu)[0]") # momentum of the Z + df = df.Define("zmumu_recoil", "FCCAnalyses::ReconstructedParticle::recoilBuilder(240)(zmumu)") # compute the recoil based on the reconstructed Z + df = df.Define("zmumu_recoil_m", "FCCAnalyses::ReconstructedParticle::get_mass(zmumu_recoil)[0]") # recoil mass + df = df.Define("zmumu_muons_p", "FCCAnalyses::ReconstructedParticle::get_p(zmumu_muons)") # get the momentum of the 2 muons from the Z resonance + + + + ######### + ### CUT 3: Z mass window + ######### + df = df.Filter("zmumu_m > 86 && zmumu_m < 96") + df = df.Define("cut3", "3") + results.append(df.Histo1D(("cutFlow", "", *bins_count), "cut3")) + + + ######### + ### CUT 4: Z momentum + ######### + df = df.Filter("zmumu_p > 20 && zmumu_p < 70") + df = df.Define("cut4", "4") + results.append(df.Histo1D(("cutFlow", "", *bins_count), "cut4")) + + + ######### + ### CUT 5: cosThetaMiss + ######### + df = df.Define("missingEnergy", "FCCAnalyses::ZHfunctions::missingEnergy(240., ReconstructedParticles)") + #df = df.Define("cosTheta_miss", "FCCAnalyses::get_cosTheta_miss(missingEnergy)") + df = df.Define("cosTheta_miss", "FCCAnalyses::ZHfunctions::get_cosTheta_miss(missingEnergy)") + results.append(df.Histo1D(("cosThetaMiss_cut4", "", *bins_cosThetaMiss), "cosTheta_miss")) # plot it before the cut + + df = df.Filter("cosTheta_miss < 0.98") + df = df.Define("cut5", "5") + results.append(df.Histo1D(("cutFlow", "", *bins_count), "cut5")) + + + ######### + ### CUT 6: recoil mass window + ######### + df = df.Filter("zmumu_recoil_m < 140 && zmumu_recoil_m > 120") + df = df.Define("cut6", "6") + results.append(df.Histo1D(("cutFlow", "", *bins_count), "cut6")) + + + ######################## + # Final histograms + ######################## + results.append(df.Histo1D(("zmumu_m", "", *bins_m_ll), "zmumu_m")) + results.append(df.Histo1D(("zmumu_recoil_m", "", *bins_recoil), "zmumu_recoil_m")) + results.append(df.Histo1D(("zmumu_p", "", *bins_p_ll), "zmumu_p")) + results.append(df.Histo1D(("zmumu_muons_p", "", *bins_p_mu), "zmumu_muons_p")) + + + return results, weightsum \ No newline at end of file diff --git a/fast-sim-and-analysis/fccanalyses/doc/starterkit/FccFastSimAnalysis/plots.py b/3-analysis/3-1-higgs-analysis/plots.py similarity index 100% rename from fast-sim-and-analysis/fccanalyses/doc/starterkit/FccFastSimAnalysis/plots.py rename to 3-analysis/3-1-higgs-analysis/plots.py diff --git a/3-analysis/3-1-higgs-analysis/plots_flavor.py b/3-analysis/3-1-higgs-analysis/plots_flavor.py new file mode 100644 index 000000000..b98fa8853 --- /dev/null +++ b/3-analysis/3-1-higgs-analysis/plots_flavor.py @@ -0,0 +1,68 @@ +import ROOT + +# global parameters +intLumi = 1 +intLumiLabel = "L = 5 ab^{-1}" +ana_tex = "e^{+}e^{-} #rightarrow ZH #rightarrow #mu^{+}#mu^{-} b b" +delphesVersion = "3.4.2" +energy = 240.0 +collider = "FCC-ee" +formats = ["png", "pdf"] + +outdir = './outputs/plots/flavor/' +inputDir = './outputs/histmaker/flavor/' + +plotStatUnc = True + +colors = {} +colors["ZH"] = ROOT.kRed +colors["ZZ"] = ROOT.kGreen + 2 + +procs = {} +procs["signal"] = {"ZH": ["p8_ee_ZH_Zmumu_ecm240"]} +procs["backgrounds"] = {"ZZ": ["p8_ee_ZZ_mumubb_ecm240"]} + +legend = {} +legend["ZH"] = "ZH" +legend["ZZ"] = "ZZ" + +hists = {} + +hists["zmumu_recoil_m"] = { + "output": "zmumu_recoil_m", + "logy": False, + "stack": True, + "rebin": 100, + "xmin": 120, + "xmax": 140, + "ymin": 0, + "ymax": 2000, + "xtitle": "Recoil (GeV)", + "ytitle": "Events / 100 MeV", +} + +hists["jj_m"] = { + "output": "jj_m", + "logy": False, + "stack": True, + "rebin": 2, + "xmin": 50, + "xmax": 150, + "ymin": 0, + "ymax": 4000, + "xtitle": "m_{jj} (GeV)", + "ytitle": "Events / 2 GeV", +} + +hists["scoresum_B"] = { + "output": "scoresum_B", + "logy": True, + "stack": True, + "rebin": 1, + "xmin": 0, + "xmax": 2.0, + "ymin": 1, + "ymax": 100000, + "xtitle": "p_{1}(B) + p_{2}(B)", + "ytitle": "Events", +} \ No newline at end of file diff --git a/3-analysis/3-1-higgs-analysis/plots_recoil.py b/3-analysis/3-1-higgs-analysis/plots_recoil.py new file mode 100644 index 000000000..cefba5558 --- /dev/null +++ b/3-analysis/3-1-higgs-analysis/plots_recoil.py @@ -0,0 +1,101 @@ +import ROOT + +# global parameters +intLumi = 1. +intLumiLabel = "L = 5 ab^{-1}" +ana_tex = 'e^{+}e^{-} #rightarrow ZH #rightarrow #mu^{+}#mu^{-} + X' +delphesVersion = '3.4.2' +energy = 240.0 +collider = 'FCC-ee' +formats = ['png','pdf'] + +outdir = './outputs/plots/recoil/' +inputDir = './outputs/histmaker/recoil/' + +plotStatUnc = True + +colors = {} +colors['ZH'] = ROOT.kRed +colors['WW'] = ROOT.kBlue+1 +colors['ZZ'] = ROOT.kGreen+2 + +procs = {} +procs['signal'] = {'ZH':['p8_ee_ZH_Zmumu_ecm240']} +procs['backgrounds'] = {'WW':['p8_ee_WW_mumu_ecm240'], 'ZZ':['p8_ee_ZZ_mumubb_ecm240']} + + +legend = {} +legend['ZH'] = 'ZH' +legend['WW'] = 'WW' +legend['ZZ'] = 'ZZ' + + + +hists = {} + +hists["zmumu_recoil_m"] = { + "output": "zmumu_recoil_m", + "logy": False, + "stack": True, + "rebin": 100, + "xmin": 120, + "xmax": 140, + "ymin": 0, + "ymax": 2500, + "xtitle": "Recoil (GeV)", + "ytitle": "Events / 100 MeV", +} + +hists["zmumu_p"] = { + "output": "zmumu_p", + "logy": False, + "stack": True, + "rebin": 2, + "xmin": 0, + "xmax": 80, + "ymin": 0, + "ymax": 2000, + "xtitle": "p(#mu^{#plus}#mu^{#minus}) (GeV)", + "ytitle": "Events ", +} + +hists["zmumu_m"] = { + "output": "zmumu_m", + "logy": False, + "stack": True, + "rebin": 2, + "xmin": 86, + "xmax": 96, + "ymin": 0, + "ymax": 3000, + "xtitle": "m(#mu^{#plus}#mu^{#minus}) (GeV)", + "ytitle": "Events ", +} + +hists["cosThetaMiss_cut4"] = { + "output": "cosThetaMiss_cut4", + "logy": True, + "stack": True, + "rebin": 10, + "xmin": 0, + "xmax": 1, + "ymin": 10, + "ymax": 100000, + "xtitle": "cos(#theta_{miss})", + "ytitle": "Events ", + "extralab": "Before cos(#theta_{miss}) cut", +} + + +hists["cutFlow"] = { + "output": "cutFlow", + "logy": True, + "stack": True, + "xmin": 0, + "xmax": 6, + "ymin": 1e4, + "ymax": 1e11, + "xtitle": ["All events", "#geq 1 #mu^{#pm} + ISO", "#geq 2 #mu^{#pm} + OS", "86 < m_{#mu^{+}#mu^{#minus}} < 96", "20 < p_{#mu^{+}#mu^{#minus}} < 70", "|cos#theta_{miss}| < 0.98", "120 < m_{rec} < 140"], + "ytitle": "Events ", + "scaleSig": 10 +} \ No newline at end of file diff --git a/3-analysis/3-1-higgs-analysis/plots_ttmm.py b/3-analysis/3-1-higgs-analysis/plots_ttmm.py new file mode 100644 index 000000000..bfe9ca3a1 --- /dev/null +++ b/3-analysis/3-1-higgs-analysis/plots_ttmm.py @@ -0,0 +1,113 @@ +import ROOT + +# global parameters +intLumi = 1. +intLumiLabel = "L = 7 pb^{-1}" +ana_tex = 'e^{+}e^{-} #rightarrow Z #rightarrow #tau^{+}#tau^{-}' +delphesVersion = '3.5' +energy = 91.188 +collider = 'FCC-ee' +inputDir = './outputs/histmaker/ttmm/' # _after_stage1 +formats = ['png','pdf'] +outdir = './outputs/plots/ttmm/' # _after_stage1 +plotStatUnc = True + +colors = {} +colors['kk'] = ROOT.kRed +colors['wz'] = ROOT.kBlue+1 +colors['p8'] = ROOT.kGreen+2 + +procs = {} +procs['signal'] = {'p8':['p8_tautau_ecm91'], 'wz':['wz_tautau_ecm91'], 'kk':['kk_tautau_ecm91']} +procs['backgrounds'] = {} + + +legend = {} +legend['p8'] = 'Pythia8' +legend['wz'] = 'Whizard' +legend['kk'] = 'KKMCee' + + + +hists = {} + +hists["AcolTau"] = { + "output": "AcolTau", + "logy": True, + "stack": False, + "rebin": 1, + "xmin": -1, + "xmax": -.9, + "ymin": 0.1, + "ymax": 10000, + "xtitle": "Acol", + "ytitle": "Events / 0.002", +} + +hists["AcolMu"] = { + "output": "AcolMu", + "logy": True, + "stack": False, + "rebin": 1, + "xmin": -1, + "xmax": -.9, + "ymin": 0.1, + "ymax": 10000, + "xtitle": "Acol", + "ytitle": "Events / 0.002", +} + +hists["CosTheta_taup"] = { + "output": "CosTheta_taup", + "logy": False, + "stack": False, + "rebin": 1, + "xmin": -1, + "xmax": 1, + "ymin": 0, + "ymax": 600, + "xtitle": "CosTheta Tau+", + "ytitle": "Events / 0.002", +} + +hists["CosTheta_mup"] = { + "output": "CosTheta_mup", + "logy": False, + "stack": False, + "rebin": 1, + "xmin": -1, + "xmax": 1, + "ymin": 0, + "ymax": 600, + "xtitle": "CosTheta Mu+", + "ytitle": "Events / 0.002", +} + + +hists["P_mup"] = { + "output": "P_mup", + "logy": False, + "stack": False, + "rebin": 1, + "xmin": 0, + "xmax": 50, + "ymin": 0, + "ymax": 350, + "xtitle": "P Mu+", + "ytitle": "Events / 0.5 GeV/c", +} + +hists["P_mum"] = { + "output": "P_mum", + "logy": False, + "stack": False, + "rebin": 1, + "xmin": 0, + "xmax": 50, + "ymin": 0, + "ymax": 350, + "xtitle": "P Mu-", + "ytitle": "Events / 0.5 GeV/c", +} + + diff --git a/3-analysis/3-1-higgs-analysis/treemaker_flavor.py b/3-analysis/3-1-higgs-analysis/treemaker_flavor.py new file mode 100644 index 000000000..380132d56 --- /dev/null +++ b/3-analysis/3-1-higgs-analysis/treemaker_flavor.py @@ -0,0 +1,261 @@ +import os, copy + +# list of processes +processList = { + "p8_ee_ZH_Zmumu_ecm240": { + "fraction": 1, + "crossSection": 0.201868 * 0.034, + }, + "p8_ee_ZZ_mumubb_ecm240": { + "fraction": 1, + "crossSection": 2 * 1.35899 * 0.034 * 0.152, + }, +} + +# Production tag when running over EDM4Hep centrally produced events, this points to the yaml files for getting sample statistics (mandatory) +#prodTag = "FCCee/winter2023/IDEA/" + +#Optional: output directory, default is local running directory +outputDir = "./outputs/treemaker/flavor/" + +# Define the input dir (optional) +inputDir = "./localSamples/" + +# additional/costom C++ functions, defined in header files (optional) +includePaths = ["functions.h"] + +## latest particle transformer model, trained on 9M jets in winter2023 samples +model_name = "fccee_flavtagging_edm4hep_wc_v1" + +## model files needed for unit testing in CI +url_model_dir = "https://fccsw.web.cern.ch/fccsw/testsamples/jet_flavour_tagging/winter2023/wc_pt_13_01_2022/" +url_preproc = "{}/{}.json".format(url_model_dir, model_name) +url_model = "{}/{}.onnx".format(url_model_dir, model_name) + +## model files locally stored on /eos +model_dir = ( + "/eos/experiment/fcc/ee/jet_flavour_tagging/winter2023/wc_pt_13_01_2022/" +) +local_preproc = "{}/{}.json".format(model_dir, model_name) +local_model = "{}/{}.onnx".format(model_dir, model_name) + +## get local file, else download from url +def get_file_path(url, filename): + if os.path.exists(filename): + return os.path.abspath(filename) + else: + urllib.request.urlretrieve(url, os.path.basename(url)) + return os.path.basename(url) + + +weaver_preproc = get_file_path(url_preproc, local_preproc) +weaver_model = get_file_path(url_model, local_model) + +from addons.ONNXRuntime.jetFlavourHelper import JetFlavourHelper +from addons.FastJet.jetClusteringHelper import ( + ExclusiveJetClusteringHelper, +) + +jetFlavourHelper = None +jetClusteringHelper = None + + +# Mandatory: RDFanalysis class where the use defines the operations on the TTree +class RDFanalysis: + + # __________________________________________________________ + # Mandatory: analysers funtion to define the analysers to process, please make sure you return the last dataframe, in this example it is df2 + def analysers(df): + + # __________________________________________________________ + # Mandatory: analysers funtion to define the analysers to process, please make sure you return the last dataframe, in this example it is df2 + + # define some aliases to be used later on + df = df.Alias("Particle0", "_Particle_daughters.index") + df = df.Alias("Particle1", "_Particle_parents.index") + df = df.Alias("RecoMCLink0", "_RecoMCLink_from.index") + df = df.Alias("RecoMCLink1", "_RecoMCLink_to.index") + df = df.Alias("Muon0", "Muon_objIdx.index") + # get all the leptons from the collection + df = df.Define( + "muons_all", + "FCCAnalyses::ReconstructedParticle::get(Muon0, ReconstructedParticles)", + ) + # select leptons with momentum > 20 GeV + df = df.Define( + "muons", + "FCCAnalyses::ReconstructedParticle::sel_p(20)(muons_all)", + ) + df = df.Define( + "muons_p", "FCCAnalyses::ReconstructedParticle::get_p(muons)" + ) + df = df.Define( + "muons_theta", + "FCCAnalyses::ReconstructedParticle::get_theta(muons)", + ) + df = df.Define( + "muons_phi", + "FCCAnalyses::ReconstructedParticle::get_phi(muons)", + ) + df = df.Define( + "muons_q", + "FCCAnalyses::ReconstructedParticle::get_charge(muons)", + ) + df = df.Define( + "muons_no", "FCCAnalyses::ReconstructedParticle::get_n(muons)" + ) + + # compute the muon isolation and store muons with an isolation cut of 0.25 in a separate column muons_sel_iso + df = df.Define( + "muons_iso", + "FCCAnalyses::ZHfunctions::coneIsolation(0.01, 0.5)(muons, ReconstructedParticles)", + ) + df = df.Define( + "muons_sel_iso", + "FCCAnalyses::ZHfunctions::sel_iso(0.25)(muons, muons_iso)", + ) + + ######### + ### CUT 1: at least 1 muon with at least one isolated one + ######### + df = df.Filter("muons_no >= 1 && muons_sel_iso.size() > 0") + ######### + ### CUT 2 :at least 2 opposite-sign (OS) leptons + ######### + df = df.Filter("muons_no >= 2 && abs(Sum(muons_q)) < muons_q.size()") + # now we build the Z resonance based on the available leptons. + # the function resonanceBuilder_mass_recoil returns the best lepton pair compatible with the Z mass (91.2 GeV) and recoil at 125 GeV + # the argument 0.4 gives a weight to the Z mass and the recoil mass in the chi2 minimization + # technically, it returns a ReconstructedParticleData object with index 0 the di-lepton system, index and 2 the leptons of the pair + + ## here cluster jets in the events but first remove muons from the list of + ## reconstructed particles + + ## create a new collection of reconstructed particles removing muons with p>20 + df = df.Define( + "ReconstructedParticlesNoMuons", + "FCCAnalyses::ReconstructedParticle::remove(ReconstructedParticles,muons)", + ) + + ## perform N=2 jet clustering + global jetClusteringHelper + global jetFlavourHelper + + ## define jet and run clustering parameters + ## name of collections in EDM root files + collections = { + "GenParticles": "Particle", + "PFParticles": "ReconstructedParticles", + "PFTracks": "EFlowTrack", + "PFPhotons": "EFlowPhoton", + "PFNeutralHadrons": "EFlowNeutralHadron", + "TrackState": "_EFlowTrack_trackStates", + "TrackerHits": "TrackerHits", + "CalorimeterHits": "CalorimeterHits", + "dNdx": "EFlowTrack_dNdx", + "PathLength": "EFlowTrack_L", + "Bz": "magFieldBz", + } + + collections_nomuons = copy.deepcopy(collections) + collections_nomuons["PFParticles"] = "ReconstructedParticlesNoMuons" + + jetClusteringHelper = ExclusiveJetClusteringHelper( + collections_nomuons["PFParticles"], 2 + ) + df = jetClusteringHelper.define(df) + + ## define jet flavour tagging parameters + + jetFlavourHelper = JetFlavourHelper( + collections_nomuons, + jetClusteringHelper.jets, + jetClusteringHelper.constituents, + ) + + ## define observables for tagger + df = jetFlavourHelper.define(df) + + ## tagger inference + df = jetFlavourHelper.inference(weaver_preproc, weaver_model, df) + + df = df.Define( + "zbuilder_result", + "FCCAnalyses::ZHfunctions::resonanceBuilder_mass_recoil(91.2, 125, 0.4, 240, false)(muons, RecoMCLink0, RecoMCLink1, ReconstructedParticles, Particle, Particle0, Particle1)", + ) + df = df.Define("zmumu", "Vec_rp{zbuilder_result[0]}") # the Z + df = df.Define( + "zmumu_muons", "Vec_rp{zbuilder_result[1],zbuilder_result[2]}" + ) # the leptons + df = df.Define( + "zmumu_m", + "FCCAnalyses::ReconstructedParticle::get_mass(zmumu)[0]", + ) # Z mass + df = df.Define( + "zmumu_p", "FCCAnalyses::ReconstructedParticle::get_p(zmumu)[0]" + ) # momentum of the Z + df = df.Define( + "zmumu_recoil", + "FCCAnalyses::ReconstructedParticle::recoilBuilder(240)(zmumu)", + ) # compute the recoil based on the reconstructed Z + df = df.Define( + "zmumu_recoil_m", + "FCCAnalyses::ReconstructedParticle::get_mass(zmumu_recoil)[0]", + ) # recoil mass + df = df.Define( + "zmumu_muons_p", + "FCCAnalyses::ReconstructedParticle::get_p(zmumu_muons)", + ) # get the momentum of the 2 muons from the Z resonance + + df = df.Define( + "missingEnergy", + "FCCAnalyses::ZHfunctions::missingEnergy(240., ReconstructedParticles)", + ) + # .Define("cosTheta_miss", "FCCAnalyses::get_cosTheta_miss(missingEnergy)") + df = df.Define( + "cosTheta_miss", + "FCCAnalyses::ZHfunctions::get_cosTheta_miss(missingEnergy)", + ) + + df = df.Define( + "missing_p", + "FCCAnalyses::ReconstructedParticle::get_p(missingEnergy)", + ) + + ######### + ### CUT 3: Njets = 2 + ######### + df = df.Filter("event_njet > 1") + + df = df.Define( + "jets_p4", + "JetConstituentsUtils::compute_tlv_jets({})".format( + jetClusteringHelper.jets + ), + ) + df = df.Define( + "jj_m", + "JetConstituentsUtils::InvariantMass(jets_p4[0], jets_p4[1])", + ) + + return df + + # __________________________________________________________ + # Mandatory: output function, please make sure you return the branchlist as a python list + def output(): + branchList = [ + "zmumu_m", + "zmumu_p", + "zmumu_recoil_m", + "cosTheta_miss", + "missing_p", + "jj_m", + ] + + ## outputs jet properties + # branchList += jetClusteringHelper.outputBranches() + + ## outputs jet scores and constituent breakdown + branchList += jetFlavourHelper.outputBranches() + + return branchList \ No newline at end of file diff --git a/fast-sim-and-analysis/FccFastSimVertexing/Exercises/MyAnalysis.cc b/3-analysis/3-2-tracking-vertexing/Exercises/MyAnalysis.cc similarity index 100% rename from fast-sim-and-analysis/FccFastSimVertexing/Exercises/MyAnalysis.cc rename to 3-analysis/3-2-tracking-vertexing/Exercises/MyAnalysis.cc diff --git a/fast-sim-and-analysis/FccFastSimVertexing/Exercises/MyAnalysis.h b/3-analysis/3-2-tracking-vertexing/Exercises/MyAnalysis.h similarity index 100% rename from fast-sim-and-analysis/FccFastSimVertexing/Exercises/MyAnalysis.h rename to 3-analysis/3-2-tracking-vertexing/Exercises/MyAnalysis.h diff --git a/fast-sim-and-analysis/FccFastSimVertexing/Exercises/analysis_Tau3Mu_MCseeded.py b/3-analysis/3-2-tracking-vertexing/Exercises/analysis_Tau3Mu_MCseeded.py similarity index 100% rename from fast-sim-and-analysis/FccFastSimVertexing/Exercises/analysis_Tau3Mu_MCseeded.py rename to 3-analysis/3-2-tracking-vertexing/Exercises/analysis_Tau3Mu_MCseeded.py diff --git a/fast-sim-and-analysis/FccFastSimVertexing/Exercises/analysis_Tau3Mu_stage1.py b/3-analysis/3-2-tracking-vertexing/Exercises/analysis_Tau3Mu_stage1.py similarity index 100% rename from fast-sim-and-analysis/FccFastSimVertexing/Exercises/analysis_Tau3Mu_stage1.py rename to 3-analysis/3-2-tracking-vertexing/Exercises/analysis_Tau3Mu_stage1.py diff --git a/fast-sim-and-analysis/FccFastSimVertexing/Readme.md b/3-analysis/3-2-tracking-vertexing/README.md similarity index 99% rename from fast-sim-and-analysis/FccFastSimVertexing/Readme.md rename to 3-analysis/3-2-tracking-vertexing/README.md index 05ec17fb8..474ead3e1 100644 --- a/fast-sim-and-analysis/FccFastSimVertexing/Readme.md +++ b/3-analysis/3-2-tracking-vertexing/README.md @@ -1,4 +1,4 @@ -# Tracking and vertexing example using specific flavour decays +# Beyond the Basics: Tracking and Vertexing > > Original authors: Emmanuel Francois Perez, Clement Helsens @@ -41,7 +41,7 @@ process is quite streamlined and requires only few steps. As a first step create a fork of the [FCCAnalyses project](https://github.com/HEP-FCC/FCCAnalyses) on GitHub. More details about FCC Software development workflow can be found in -[](/developing-fcc-software/FccSoftwareGit.md#development-workflow). +[](./../../6-developing-fccsw/FccSoftwareGit.md#development-workflow). After a short while the forking should be done and you can download the FCCAnalyses to your machine. Go inside the area that you have setup for this diff --git a/fast-sim-and-analysis/FccFastSimVertexing/analysis_Bs2JpsiPhi_MCseeded.py b/3-analysis/3-2-tracking-vertexing/analysis_Bs2JpsiPhi_MCseeded.py similarity index 100% rename from fast-sim-and-analysis/FccFastSimVertexing/analysis_Bs2JpsiPhi_MCseeded.py rename to 3-analysis/3-2-tracking-vertexing/analysis_Bs2JpsiPhi_MCseeded.py diff --git a/fast-sim-and-analysis/FccFastSimVertexing/analysis_Tau3Mu.py b/3-analysis/3-2-tracking-vertexing/analysis_Tau3Mu.py similarity index 100% rename from fast-sim-and-analysis/FccFastSimVertexing/analysis_Tau3Mu.py rename to 3-analysis/3-2-tracking-vertexing/analysis_Tau3Mu.py diff --git a/fast-sim-and-analysis/FccFastSimVertexing/analysis_Tau3Mu_MCseeded.py b/3-analysis/3-2-tracking-vertexing/analysis_Tau3Mu_MCseeded.py similarity index 100% rename from fast-sim-and-analysis/FccFastSimVertexing/analysis_Tau3Mu_MCseeded.py rename to 3-analysis/3-2-tracking-vertexing/analysis_Tau3Mu_MCseeded.py diff --git a/fast-sim-and-analysis/FccFastSimVertexing/analysis_Tau3Mu_MCseeded_start.py b/3-analysis/3-2-tracking-vertexing/analysis_Tau3Mu_MCseeded_start.py similarity index 100% rename from fast-sim-and-analysis/FccFastSimVertexing/analysis_Tau3Mu_MCseeded_start.py rename to 3-analysis/3-2-tracking-vertexing/analysis_Tau3Mu_MCseeded_start.py diff --git a/fast-sim-and-analysis/FccFastSimVertexing/analysis_Tau3Mu_final.py b/3-analysis/3-2-tracking-vertexing/analysis_Tau3Mu_final.py similarity index 100% rename from fast-sim-and-analysis/FccFastSimVertexing/analysis_Tau3Mu_final.py rename to 3-analysis/3-2-tracking-vertexing/analysis_Tau3Mu_final.py diff --git a/fast-sim-and-analysis/FccFastSimVertexing/analysis_Tau3Mu_plots.py b/3-analysis/3-2-tracking-vertexing/analysis_Tau3Mu_plots.py similarity index 100% rename from fast-sim-and-analysis/FccFastSimVertexing/analysis_Tau3Mu_plots.py rename to 3-analysis/3-2-tracking-vertexing/analysis_Tau3Mu_plots.py diff --git a/fast-sim-and-analysis/FccFastSimVertexing/analysis_Tau3Mu_stage1.py b/3-analysis/3-2-tracking-vertexing/analysis_Tau3Mu_stage1.py similarity index 100% rename from fast-sim-and-analysis/FccFastSimVertexing/analysis_Tau3Mu_stage1.py rename to 3-analysis/3-2-tracking-vertexing/analysis_Tau3Mu_stage1.py diff --git a/fast-sim-and-analysis/FccFastSimVertexing/analysis_primary_vertex.py b/3-analysis/3-2-tracking-vertexing/analysis_primary_vertex.py similarity index 100% rename from fast-sim-and-analysis/FccFastSimVertexing/analysis_primary_vertex.py rename to 3-analysis/3-2-tracking-vertexing/analysis_primary_vertex.py diff --git a/fast-sim-and-analysis/FccFastSimVertexing/analysis_primary_vertex_final.py b/3-analysis/3-2-tracking-vertexing/analysis_primary_vertex_final.py similarity index 100% rename from fast-sim-and-analysis/FccFastSimVertexing/analysis_primary_vertex_final.py rename to 3-analysis/3-2-tracking-vertexing/analysis_primary_vertex_final.py diff --git a/fast-sim-and-analysis/FccFastSimVertexing/analyzers.h b/3-analysis/3-2-tracking-vertexing/analyzers.h similarity index 100% rename from fast-sim-and-analysis/FccFastSimVertexing/analyzers.h rename to 3-analysis/3-2-tracking-vertexing/analyzers.h diff --git a/fast-sim-and-analysis/FccFastSimVertexing/analyzers_Tau3Mu.h b/3-analysis/3-2-tracking-vertexing/analyzers_Tau3Mu.h similarity index 100% rename from fast-sim-and-analysis/FccFastSimVertexing/analyzers_Tau3Mu.h rename to 3-analysis/3-2-tracking-vertexing/analyzers_Tau3Mu.h diff --git a/fast-sim-and-analysis/FccFastSimVertexing/dummy_analysis.py b/3-analysis/3-2-tracking-vertexing/dummy_analysis.py similarity index 100% rename from fast-sim-and-analysis/FccFastSimVertexing/dummy_analysis.py rename to 3-analysis/3-2-tracking-vertexing/dummy_analysis.py diff --git a/fast-sim-and-analysis/FccFastSimVertexing/plot_Bs2JsiPhi.C b/3-analysis/3-2-tracking-vertexing/plot_Bs2JsiPhi.C similarity index 100% rename from fast-sim-and-analysis/FccFastSimVertexing/plot_Bs2JsiPhi.C rename to 3-analysis/3-2-tracking-vertexing/plot_Bs2JsiPhi.C diff --git a/fast-sim-and-analysis/FccFastSimVertexing/plot_primary_vertex.C b/3-analysis/3-2-tracking-vertexing/plot_primary_vertex.C similarity index 100% rename from fast-sim-and-analysis/FccFastSimVertexing/plot_primary_vertex.C rename to 3-analysis/3-2-tracking-vertexing/plot_primary_vertex.C diff --git a/fast-sim-and-analysis/FCCAnalysesProblemsAndSolutions.md b/3-analysis/3-3-useful-info/README.md similarity index 84% rename from fast-sim-and-analysis/FCCAnalysesProblemsAndSolutions.md rename to 3-analysis/3-3-useful-info/README.md index ffe934bd2..0b57bd154 100644 --- a/fast-sim-and-analysis/FCCAnalysesProblemsAndSolutions.md +++ b/3-analysis/3-3-useful-info/README.md @@ -1,4 +1,10 @@ -# FCCAnalyses: Common problems and solutions +# Some Useful Info on EDM4hep, Analyzers, and More + +:::{admonition} Needs Updating ... +:class: prereq + +This section is currently under construction to reflect the updates made to EDM4hep in the more recent past. +::: This directory contains a number of examples each showcasing a specific functionality of the FCCAnalyses framework. It serves as a reference guide for how to implement specific common usecases or you can work through the examples one-by-one in order as a tutorial to familiarize yourself with the full functionality of the framework. @@ -14,15 +20,15 @@ Certain examples may have additional options, you can always check what options are available with `python .py -h`. -## Prerequisites - -The FCCAnalyses framework is based on the [RDataFrame](https://root.cern/doc/master/classROOT_1_1RDataFrame.html) interface which allows fast and efficient analysis of [ROOT's TTrees](https://root.cern/doc/master/classTTree.html) and on samples following the [EDM4HEP event data model](https://edm4hep.web.cern.ch/). Some brief explanations and links to further material on the two are given below, a basic understanding of both is necessary for using this framework to write your own analysis code. +## EDM4hep in FCCAnalyses +The FCCAnalyses framework is based on the [RDataFrame](https://root.cern/doc/master/classROOT_1_1RDataFrame.html) interface which allows fast and efficient analysis of [ROOT's TTrees](https://root.cern/doc/master/classTTree.html) and on samples following the [EDM4HEP event data model](https://edm4hep.web.cern.ch/). Some brief explanations and links to further material on the two are given below --- a basic understanding of both is necessary for using this framework to write your own analysis code. ### EDM4hep event model -```{figure} https://github.com/key4hep/EDM4hep/raw/master/doc/edm4hep_diagram.svg +```{figure} https://raw.githubusercontent.com/key4hep/EDM4hep/main/doc/edm4hep_diagram.svg :align: center +:alt: EDM4hep event data model overview EDM4hep event data model overview. ``` @@ -33,97 +39,67 @@ datatypes. It is described in a single generated with the help of [Podio](https://github.com/AIDASoft/podio). For example the datatype for the calorimeter hit has following members: ``` -#------------- CalorimeterHit -edm4hep::CalorimeterHit: - Description: "Calorimeter hit" - Author : "F.Gaede, DESY" - Members: - - uint64_t cellID //detector specific (geometrical) cell id. - - float energy //energy of the hit in [GeV]. - - float energyError //error of the hit energy in [GeV]. - - float time //time of the hit in [ns]. - - edm4hep::Vector3f position //position of the hit in world coordinates in [mm]. - - int32_t type //type of hit. Mapping of integer types to names via collection parameters "CalorimeterHitTypeNames" and "CalorimeterHitTypeValues". + edm4hep::CalorimeterHit: + Description: "Calorimeter hit" + Author: "EDM4hep authors" + Members: + - uint64_t cellID // detector specific (geometrical) cell id + - float energy [GeV] // energy of the hit + - float energyError [GeV] // error of the hit energy + - float time [ns] // time of the hit + - edm4hep::Vector3f position [mm] // position of the hit in world coordinates + - int32_t type // type of hit ``` [Link to EDM4HEP class overview](https://edm4hep.web.cern.ch/namespaceedm4hep.html) (structure-of-edm4hep-files)= -### Structure of EDM4hep files - -The content of an EDM4hep file can be seen by opening it in ROOT, and by -inspecting the content of the `events` tree with a TBrowser. Example with a -file from the "spring2021" campaign: +### Structure of EDM4hep Files +The content of an EDM4hep file can be seen by opening it in ROOT, and by inspecting the content of the `events` tree with a TBrowser. +For example, ```sh -root -l /eos/experiment/fcc/ee/generation/DelphesEvents/spring2021/IDEA/wzp6_ee_mumuH_ecm240/events_012879310.root +root -l https://fccsw.web.cern.ch/tutorials/ana-sim-evt/p8_ee_WW_mumu_ecm240/p8_ee_WW_mumu_ecm240_edm4hep.root root[0] TBrowser b ``` -```{figure} images/browser_events.png +```{figure} events_TBrowser.png :align: center :class: with-border -Example file from "spring2021" campaign in ROOT TBrowser. +Example edm4hep.root file opened in ROOT TBrowser. ``` -As shown in the screenshot above, there are two types of branches: +As shown in the screenshot above, there are several types of branches in an +EDM4hep ROOT file: -1. Branches without a pound sign (`#`) in their name like: `Electron`, `Muon`, ... - They refer to collections of objects. -:::{admonition} Nota Bene -:class: callout -`Particle` denotes the collection of Monte-Carlo particles. `Muon` contains the -isolated muons, while `AllMuon` contains all muons, isolated or not. -::: +1. Main object collections, such as: ```Particle, ReconstructedParticles, CalorimeterHits, ...``` +These correspond to the main EDM4hep collections containing the physics +objects and their data members (momentum, charge, mass, vertex position, +etc.). +For example, the `Particle` branch stores the full collection of Monte Carlo particles data type `edm4hep::MCParticleData`. +The `ReconstructedParticles` branch stores reconstructed particles as data type `edm4hep::ReconstructedParticleData`. -2. Branches with a pound sign in their name: - Each of the object collections listed above, e.g. `Collection`, has up to six - associated collections of references, i.e. indices that point to another or to - the same object collection. They are labeled `Collection#i`, with - `i = 0 ... 5`. For example, the `Muon` collection has one single associated - collection of references, `Muon#0`. - -To figure out which collection is pointed to by `Muon#0` (or by any other -collection of references), one can look at the value of `Muon#0.collectionID` -(see screenshot below). -The `collectionID` of `Muon#0` is the collection number `7` (in the example file -used here), which, in the list of "object collections" above, corresponds to the -collection of `ReconstructedParticles`. -Indeed, the `Muon` collection itself contains nothing (see screenshot below): -all the information is contained in the `ReconstructedParticles`. The `Muon` -collection, together with `Muon#0`, just provides a convenient way to access, -among the `ReconstructedParticles`, those that were identified as muons. - -```{figure} images/browser_Muon0.png -:align: center -:class: with-border - -Muon collection example. -``` -The same holds for the `Electron` and `Photon` collections. On the other hand, -the `MissingET` collection is already a `ReconstructedParticle`, as can be seen -by inspecting it in the TBrowser: +2. PODIO auxiliary branches, prefixed with a single underscore `_` such as: +```_Particle_parents, _Particle_daughters, _EFlowTrack_trackStates, ...``` +These are internal storage branches automatically generated by PODIO for +variable-length members and relations between EDM4hep objects. -```{figure} images/browser_missingET.png -:align: center -:class: with-border +3. Relation/index collections, such as: +```Muon_objIdx, Electron_objIdx, ...``` +These collections store indices pointing to objects in another collection. +For example, `Muon_objIdx.index` contains indices into the global `ReconstructedParticles` collection. +FCCAnalyses makes use of these indices to retrieve the corresponding reconstructed particles. For example to retrieve a list of muons: +```python +df = df.Alias("Muon0", "Muon_objIdx.index") -Missing $E_T$ collection example. +df = df.Define( + "muons_all", + "FCCAnalyses::ReconstructedParticle::get(Muon0, ReconstructedParticles)") ``` -The `Particle` collection corresponds to the Monte-Carlo particles. It has two -associated collections of references, `Particle#0` and `Particle#1`. As can -be seen by looking at their collectionID, they both point to collection number -5, i.e. to the Particle collection itself. Particle#0 and Particle#1 contain, -respectively, links to the parents and to the daughters of the MC particles --- -as can be seen in the -[EDM4hep yaml description here](https://github.com/key4hep/EDM4hep/blob/master/edm4hep.yaml#L156-L157). -Examples will be given below, showing how to navigate through the Monte-Carlo -record using `Particle`, `Particle#0` and `Particle#1`. - ## Overall organisation of analysis code (C++) diff --git a/fast-sim-and-analysis/images/browser_Muon0.png b/3-analysis/3-3-useful-info/browser_Muon0.png similarity index 100% rename from fast-sim-and-analysis/images/browser_Muon0.png rename to 3-analysis/3-3-useful-info/browser_Muon0.png diff --git a/fast-sim-and-analysis/images/browser_events.png b/3-analysis/3-3-useful-info/browser_events.png similarity index 100% rename from fast-sim-and-analysis/images/browser_events.png rename to 3-analysis/3-3-useful-info/browser_events.png diff --git a/fast-sim-and-analysis/images/browser_missingET.png b/3-analysis/3-3-useful-info/browser_missingET.png similarity index 100% rename from fast-sim-and-analysis/images/browser_missingET.png rename to 3-analysis/3-3-useful-info/browser_missingET.png diff --git a/3-analysis/3-3-useful-info/edm4hep.png b/3-analysis/3-3-useful-info/edm4hep.png new file mode 100644 index 000000000..f1215dd0d Binary files /dev/null and b/3-analysis/3-3-useful-info/edm4hep.png differ diff --git a/3-analysis/3-3-useful-info/events_TBrowser.png b/3-analysis/3-3-useful-info/events_TBrowser.png new file mode 100644 index 000000000..2fbff3288 Binary files /dev/null and b/3-analysis/3-3-useful-info/events_TBrowser.png differ diff --git a/3-analysis/README.md b/3-analysis/README.md new file mode 100644 index 000000000..8ed379487 --- /dev/null +++ b/3-analysis/README.md @@ -0,0 +1,23 @@ +# Analysis at FCC + +FCCAnalyses is a high-level analysis framework developed within the FCC software ecosystem. It provides a convenient interface for performing physics analyses on EDM4hep-based data using ROOT RDataFrame as the underlying event-processing engine. + +This chapter introduces FCCAnalyses through a series of practical examples, starting from simple analysis workflows and gradually moving toward more realistic use cases. The final section of this chapter provides a more theoretical introduction to the core tools and data model used throughout FCCAnalyses, including EDM4hep and ROOT RDataFrame, which form the backbone of most workflows. + +If you have any problems or questions, you can +[open an issue][fcc-tutorials-issues] on the +[GitHub repository where these lessons are developed][fcc-tutorials-repo]. + + +[fcc-tutorials-issues]: https://github.com/HEP-FCC/fcc-tutorials/issues +[fcc-tutorials-repo]: https://github.com/HEP-FCC/fcc-tutorials + +```{eval-rst} +.. toctree:: + :caption: Contents: + + 3-1-higgs-analysis/README.md + 3-2-tracking-vertexing/README.md + 3-3-useful-info/README.md + +``` \ No newline at end of file diff --git a/full-detector-simulations/FCCeeCLD/FCCeeCLD.md b/4-full-detector-sim/FCCeeCLD/FCCeeCLD.md similarity index 100% rename from full-detector-simulations/FCCeeCLD/FCCeeCLD.md rename to 4-full-detector-sim/FCCeeCLD/FCCeeCLD.md diff --git a/full-detector-simulations/FCCeeCaloPhotonPi0Discrimination/FCCeeCaloPhotonPi0Discrimination.md b/4-full-detector-sim/FCCeeCaloPhotonPi0Discrimination/FCCeeCaloPhotonPi0Discrimination.md similarity index 98% rename from full-detector-simulations/FCCeeCaloPhotonPi0Discrimination/FCCeeCaloPhotonPi0Discrimination.md rename to 4-full-detector-sim/FCCeeCaloPhotonPi0Discrimination/FCCeeCaloPhotonPi0Discrimination.md index 909ed4c4e..b53d7c78c 100644 --- a/full-detector-simulations/FCCeeCaloPhotonPi0Discrimination/FCCeeCaloPhotonPi0Discrimination.md +++ b/4-full-detector-sim/FCCeeCaloPhotonPi0Discrimination/FCCeeCaloPhotonPi0Discrimination.md @@ -294,8 +294,8 @@ fccanalysis run analysis_tutorial_mva.py --output photons_10layers.root --test We get the following plotting scripts ```shell -wget https://raw.githubusercontent.com/HEP-FCC/fcc-tutorials/main/full-detector-simulations/FCCeeCaloPhotonPi0Discrimination/draw_rocCurve_pi0_gamma_GNN.py -wget https://raw.githubusercontent.com/HEP-FCC/fcc-tutorials/main/full-detector-simulations/FCCeeCaloPhotonPi0Discrimination/rocCurveFacility.py +wget https://raw.githubusercontent.com/HEP-FCC/fcc-tutorials/main/4-full-detector-sim/FCCeeCaloPhotonPi0Discrimination/draw_rocCurve_pi0_gamma_GNN.py +wget https://raw.githubusercontent.com/HEP-FCC/fcc-tutorials/main/4-full-detector-sim/FCCeeCaloPhotonPi0Discrimination/rocCurveFacility.py ``` Edit `draw_rocCurve_pi0_gamma_GNN.py` and edit the following: diff --git a/full-detector-simulations/FCCeeCaloPhotonPi0Discrimination/draw_rocCurve_pi0_gamma_GNN.py b/4-full-detector-sim/FCCeeCaloPhotonPi0Discrimination/draw_rocCurve_pi0_gamma_GNN.py similarity index 100% rename from full-detector-simulations/FCCeeCaloPhotonPi0Discrimination/draw_rocCurve_pi0_gamma_GNN.py rename to 4-full-detector-sim/FCCeeCaloPhotonPi0Discrimination/draw_rocCurve_pi0_gamma_GNN.py diff --git a/full-detector-simulations/FCCeeCaloPhotonPi0Discrimination/rocCurveFacility.py b/4-full-detector-sim/FCCeeCaloPhotonPi0Discrimination/rocCurveFacility.py similarity index 100% rename from full-detector-simulations/FCCeeCaloPhotonPi0Discrimination/rocCurveFacility.py rename to 4-full-detector-sim/FCCeeCaloPhotonPi0Discrimination/rocCurveFacility.py diff --git a/full-detector-simulations/FCCeeDriftChamber/FCCeeDriftChamber.md b/4-full-detector-sim/FCCeeDriftChamber/FCCeeDriftChamber.md similarity index 100% rename from full-detector-simulations/FCCeeDriftChamber/FCCeeDriftChamber.md rename to 4-full-detector-sim/FCCeeDriftChamber/FCCeeDriftChamber.md diff --git a/full-detector-simulations/FCCeeGeneralOverview/FCCeeGeneralOverview.md b/4-full-detector-sim/FCCeeGeneralOverview/FCCeeGeneralOverview.md similarity index 98% rename from full-detector-simulations/FCCeeGeneralOverview/FCCeeGeneralOverview.md rename to 4-full-detector-sim/FCCeeGeneralOverview/FCCeeGeneralOverview.md index 26dedac24..0b5868329 100644 --- a/full-detector-simulations/FCCeeGeneralOverview/FCCeeGeneralOverview.md +++ b/4-full-detector-sim/FCCeeGeneralOverview/FCCeeGeneralOverview.md @@ -155,7 +155,7 @@ int plot_recoil_mass(std::string input_file_path) {