-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Co-authored-by: Dmitry Kalinkin <[email protected]>
- Loading branch information
Showing
6 changed files
with
389 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
def get_n_events(wildcards): | ||
energy = float(wildcards.P) | ||
n_events = 1000 | ||
n_events = int(n_events // ((energy / 20) ** 0.5)) | ||
return n_events | ||
|
||
rule insert_tau_generate: | ||
input: | ||
script="benchmarks/insert_tau/analysis/gen_particles.cxx", | ||
params: | ||
N_EVENTS=get_n_events, | ||
th_max=7.0, | ||
th_min=1.7, | ||
output: | ||
GEN_FILE="sim_output/insert_tau/tau-_{P}GeV.hepmc", | ||
shell: | ||
""" | ||
root -l -b -q '{input.script}({params.N_EVENTS},"{output.GEN_FILE}", "tau-", {params.th_min}, {params.th_max}, 0., 360., {wildcards.P})' | ||
""" | ||
|
||
rule insert_tau_simulate: | ||
input: | ||
GEN_FILE="sim_output/insert_tau/tau-_{P}GeV.hepmc", | ||
warmup="warmup/{DETECTOR_CONFIG}.edm4hep.root", | ||
params: | ||
N_EVENTS=get_n_events, | ||
PHYSICS_LIST="FTFP_BERT", | ||
output: | ||
SIM_FILE="sim_output/insert_tau/{DETECTOR_CONFIG}_sim_tau-_{P}GeV_{INDEX}.edm4hep.root" | ||
shell: | ||
""" | ||
# Running simulation | ||
npsim \ | ||
--compactFile $DETECTOR_PATH/{wildcards.DETECTOR_CONFIG}.xml \ | ||
--numberOfEvents {params.N_EVENTS} \ | ||
--skipNEvents $(( {params.N_EVENTS} * {wildcards.INDEX} )) \ | ||
--physicsList {params.PHYSICS_LIST} \ | ||
--inputFiles {input.GEN_FILE} \ | ||
--outputFile {output.SIM_FILE} | ||
""" | ||
|
||
rule insert_tau_recon: | ||
input: | ||
SIM_FILE="sim_output/insert_tau/{DETECTOR_CONFIG}_sim_tau-_{P}GeV_{INDEX}.edm4hep.root", | ||
params: | ||
N_EVENTS=get_n_events, | ||
output: | ||
REC_FILE="sim_output/insert_tau/{DETECTOR_CONFIG}_rec_tau-_{P}GeV_{INDEX}.edm4eic.root", | ||
shell: | ||
""" | ||
eicrecon {input.SIM_FILE} -Ppodio:output_file={output.REC_FILE} -Pdd4hep:xml_files=$DETECTOR_PATH/{wildcards.DETECTOR_CONFIG}.xml -Ppodio:output_collections=MCParticles,HcalEndcapPInsertRecHits,HcalEndcapPInsertClusters,HcalEndcapPInsertSubcellHits,EcalEndcapPInsertRecHits,EcalEndcapPInsertClusters,EcalEndcapPClusters,LFHCALClusters -Pjana:nevents={params.N_EVENTS} | ||
""" | ||
|
||
rule insert_tau_analysis: | ||
input: | ||
expand("sim_output/insert_tau/{DETECTOR_CONFIG}_rec_tau-_{P}GeV_{INDEX}.edm4eic.root", | ||
P=[20, 30, 40, 50, 60, 80, 100], | ||
DETECTOR_CONFIG=["{DETECTOR_CONFIG}"], | ||
INDEX=range(5), | ||
), | ||
script="benchmarks/insert_tau/analysis/tau_plots.py", | ||
output: | ||
results_dir=directory("results/{DETECTOR_CONFIG}/insert_tau"), | ||
shell: | ||
""" | ||
mkdir -p {output.results_dir} | ||
python {input.script} {output.results_dir} | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
#include "HepMC3/GenEvent.h" | ||
#include "HepMC3/ReaderAscii.h" | ||
#include "HepMC3/WriterAscii.h" | ||
#include "HepMC3/Print.h" | ||
|
||
#include "TRandom3.h" | ||
#include "TVector3.h" | ||
|
||
#include <iostream> | ||
#include <random> | ||
#include <cmath> | ||
#include <math.h> | ||
#include <TMath.h> | ||
#include <TDatabasePDG.h> | ||
#include <TParticlePDG.h> | ||
|
||
using namespace HepMC3; | ||
|
||
// Generate single electron as input to the Insert simulation. | ||
// -- | ||
// We generate events with a constant polar angle with respect to | ||
// the proton direction and then rotate so that the events are given | ||
// in normal lab coordinate system | ||
// -- | ||
void gen_particles( | ||
int n_events = 1000, | ||
const char* out_fname = "gen_particles.hepmc", | ||
TString particle_name = "e-", | ||
double th_min = 3., // Minimum polar angle, in degrees | ||
double th_max = 3., // Maximum polar angle, in degrees | ||
double phi_min = 0., // Minimum azimuthal angle, in degrees | ||
double phi_max = 360., // Maximum azimuthal angle, in degrees | ||
double p = 10., // Momentum in GeV/c | ||
int dist = 0, //Momentum distribution: 0=fixed, 1=uniform, 2=Gaussian | ||
int useCrossingAngle=1 // 0= no rotation, 1 = -25 mrad | ||
) | ||
{ | ||
WriterAscii hepmc_output(out_fname); | ||
int events_parsed = 0; | ||
GenEvent evt(Units::GEV, Units::MM); | ||
|
||
// Random number generator | ||
TRandom3 *r1 = new TRandom3(0); //Use time as random seed | ||
|
||
// Getting generated particle information | ||
TDatabasePDG *pdg = new TDatabasePDG(); | ||
TParticlePDG *particle = pdg->GetParticle(particle_name); | ||
const double mass = particle->Mass(); | ||
const int pdgID = particle->PdgCode(); | ||
|
||
for (events_parsed = 0; events_parsed < n_events; events_parsed++) { | ||
|
||
//Set the event number | ||
evt.set_event_number(events_parsed); | ||
|
||
// FourVector(px,py,pz,e,pdgid,status) | ||
// type 4 is beam | ||
// pdgid 11 - electron | ||
// pdgid 111 - pi0 | ||
// pdgid 2212 - proton | ||
GenParticlePtr p1 = | ||
std::make_shared<GenParticle>(FourVector(0.0, 0.0, 10.0, 10.0), 11, 4); | ||
GenParticlePtr p2 = std::make_shared<GenParticle>( | ||
FourVector(0.0, 0.0, 0.0, 0.938), 2212, 4); | ||
|
||
// Define momentum with respect to proton direction | ||
double phi = r1->Uniform(phi_min*TMath::DegToRad(),phi_max*TMath::DegToRad()); | ||
double th = r1->Uniform(th_min*TMath::DegToRad(),th_max*TMath::DegToRad()); | ||
|
||
//Total momentum distribution | ||
double pevent = -1; | ||
if(dist==0){ //fixed | ||
pevent = p; | ||
} | ||
else if(dist==1){ //Uniform: +-50% variation | ||
pevent = p*(1. + r1->Uniform(-0.5,0.5) ); | ||
} | ||
else if(dist==2){ //Gaussian: Sigma = 0.1*mean | ||
while(pevent<0) //Avoid negative values | ||
pevent = r1->Gaus(p,0.1*p); | ||
} | ||
|
||
double px = pevent * std::cos(phi) * std::sin(th); | ||
double py = pevent * std::sin(phi) * std::sin(th); | ||
double pz = pevent * std::cos(th); | ||
TVector3 pvec(px,py,pz); | ||
|
||
//Rotate to lab coordinate system | ||
double cross_angle = -25./1000.*useCrossingAngle; //in Rad | ||
TVector3 pbeam_dir(sin(cross_angle),0,cos(cross_angle)); //proton beam direction | ||
pvec.RotateY(-pbeam_dir.Theta()); // Theta is returned positive, beam in negative X | ||
// type 1 is final state | ||
// pdgid 11 - electron 0.510 MeV/c^2 | ||
GenParticlePtr p3 = std::make_shared<GenParticle>( | ||
FourVector( | ||
pvec.X(), pvec.Y(), pvec.Z(), | ||
sqrt(pevent*pevent + (mass * mass))), | ||
pdgID, 1); | ||
|
||
//If wanted, set non-zero vertex | ||
double vx = 0.; | ||
double vy = 0.; | ||
double vz = 0.; | ||
double vt = 0.; | ||
|
||
GenVertexPtr v1 = std::make_shared<GenVertex>(); | ||
evt.shift_position_by(FourVector(vx, vy, vz, vt)); | ||
v1->add_particle_in(p1); | ||
v1->add_particle_in(p2); | ||
|
||
v1->add_particle_out(p3); | ||
evt.add_vertex(v1); | ||
|
||
if (events_parsed == 0) { | ||
std::cout << "First event: " << std::endl; | ||
Print::listing(evt); | ||
} | ||
|
||
hepmc_output.write_event(evt); | ||
if (events_parsed % 100 == 0) { | ||
std::cout << "Event: " << events_parsed << std::endl; | ||
} | ||
evt.clear(); | ||
} | ||
hepmc_output.close(); | ||
std::cout << "Events parsed and written: " << events_parsed << std::endl; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
import numpy as np, pandas as pd, matplotlib.pyplot as plt, matplotlib as mpl, awkward as ak, sys | ||
import mplhep as hep | ||
hep.style.use("CMS") | ||
|
||
plt.rcParams['figure.facecolor']='white' | ||
plt.rcParams['savefig.facecolor']='white' | ||
plt.rcParams['savefig.bbox']='tight' | ||
|
||
plt.rcParams["figure.figsize"] = (7, 7) | ||
|
||
config=sys.argv[1].split("/")[1] #results/{config}/{benchmark_name} | ||
outdir=sys.argv[1]+"/" | ||
try: | ||
import os | ||
os.mkdir(outdir[:-1]) | ||
except: | ||
pass | ||
|
||
import uproot as ur | ||
arrays_sim={} | ||
momenta=20, 30, 40, 50, 60,80,100 | ||
for p in momenta: | ||
arrays_sim[p] = ur.concatenate({ | ||
f'sim_output/insert_tau/{config}_rec_tau-_{p}GeV_{index}.edm4eic.root': 'events' | ||
for index in range(5) | ||
}) | ||
|
||
|
||
for a in arrays_sim.values(): | ||
#recon | ||
Etot=0 | ||
px=0 | ||
py=0 | ||
pz=0 | ||
for det in "HcalEndcapPInsert", "EcalEndcapPInsert", "EcalEndcapP", "LFHCAL": | ||
|
||
E=a[f'{det}Clusters.energy'] | ||
|
||
#todo apply corrections depending on whether this is an electromagnetic or hadronic shower. | ||
|
||
x=a[f'{det}Clusters.position.x'] | ||
y=a[f'{det}Clusters.position.y'] | ||
z=a[f'{det}Clusters.position.z'] | ||
r=np.sqrt(x**2+y**2+z**2) | ||
Etot=Etot+np.sum(E, axis=-1) | ||
px=px+np.sum(E*x/r,axis=-1) | ||
py=py+np.sum(E*y/r,axis=-1) | ||
pz=pz+np.sum(E*z/r,axis=-1) | ||
|
||
a['jet_p_recon']=np.sqrt(px**2+py**2+pz**2) | ||
a['jet_E_recon']=Etot | ||
|
||
a['jet_theta_recon']=np.arctan2(np.hypot(px*np.cos(-.025)-pz*np.sin(-.025),py), | ||
pz*np.cos(-.025)+px*np.sin(-.025)) | ||
|
||
#truth | ||
m=a['MCParticles.mass'][::,2:] | ||
px=a['MCParticles.momentum.x'][::,2:] | ||
py=a['MCParticles.momentum.y'][::,2:] | ||
pz=a['MCParticles.momentum.z'][::,2:] | ||
E=np.sqrt(m**2+px**2+py**2+pz**2) | ||
status=a['MCParticles.simulatorStatus'][::,2:] | ||
PDG=a['MCParticles.PDG'][::,2:] | ||
|
||
#find the hadronic part: initial-state tau - all leptons | ||
selection=1*(PDG==15)-1*(np.abs(PDG)==16) | ||
is_hadronic=1*(np.sum((PDG==-14)+(PDG==-12), axis=-1)==0) | ||
|
||
px_hfs, py_hfs, pz_hfs= np.sum(px*selection,axis=-1)*is_hadronic,np.sum(py*selection,axis=-1)*is_hadronic, np.sum(pz*selection,axis=-1)*is_hadronic | ||
|
||
a['hfs_p_truth']=np.sqrt(px_hfs**2+py_hfs**2+pz_hfs**2) | ||
a['hfs_E_truth']=np.sum(E*selection,axis=-1)*is_hadronic | ||
|
||
|
||
a['hfs_theta_truth']=np.arctan2(np.hypot(px_hfs*np.cos(-.025)-pz_hfs*np.sin(-.025),py_hfs), | ||
pz_hfs*np.cos(-.025)+px_hfs*np.sin(-.025)) | ||
a['hfs_eta_truth']=-np.log(np.tan(a['hfs_theta_truth']/2)) | ||
a['n_mu']=np.sum(np.abs(PDG)==13, axis=-1) | ||
a['n_e']=np.sum(np.abs(PDG)==13, axis=-1) | ||
a['hfs_mass_truth']=np.sqrt(a['hfs_E_truth']**2-a['hfs_p_truth']**2) | ||
|
||
for a in arrays_sim.values(): | ||
selection=(a['hfs_eta_truth']>3.1) & (a['hfs_eta_truth']<3.8)\ | ||
&(a['n_mu']==0)&(a['n_e']==0)&(a['hfs_mass_truth']>.140)&(a['jet_E_recon']>0) | ||
|
||
Etruth=[] | ||
Erecon=[] | ||
|
||
theta_truth=[] | ||
theta_recon=[] | ||
|
||
eta_max=3.7 | ||
eta_min=3.3 | ||
for a in arrays_sim.values(): | ||
selection=(a['hfs_eta_truth']>eta_min) & (a['hfs_eta_truth']<eta_max)\ | ||
&(a['n_mu']==0)&(a['n_e']==0)&(a['hfs_mass_truth']>.140)&(a['jet_E_recon']>1) | ||
theta_truth=np.concatenate((theta_truth,a['hfs_theta_truth'][selection])) | ||
theta_recon=np.concatenate((theta_recon,a['jet_theta_recon'][selection])) | ||
Etruth=np.concatenate((Etruth,a['hfs_E_truth'][selection])) | ||
Erecon=np.concatenate((Erecon,a['jet_E_recon'][selection])) | ||
|
||
plt.figure() | ||
plt.scatter(theta_truth, theta_recon, 1) | ||
plt.xlabel("$\\theta^{hfs}_{\\rm truth}$ [rad]") | ||
plt.ylabel("$\\theta^{hfs}_{\\rm rec}$ [rad]") | ||
plt.title(f"$E_{{\\tau}}$=20-100 GeV, ${eta_min}<\\eta_{{hfs}}<{eta_max}$") | ||
plt.plot([0.04,0.1], [0.04, 0.1], color='tab:orange') | ||
plt.ylim(0, 0.15) | ||
plt.savefig(outdir+"/theta_scatter.pdf") | ||
|
||
plt.figure() | ||
plt.scatter(Etruth, Erecon, 1) | ||
plt.xlabel("$E^{hfs}_{\\rm truth}$ [GeV]") | ||
plt.ylabel("$E^{hfs}_{\\rm rec}$ [GeV]") | ||
plt.title(f"$E_{{\\tau}}$=20-100 GeV, ${eta_min}<\\eta_{{hfs}}<{eta_max}$") | ||
plt.plot((0,100), (0, 100), color='tab:orange') | ||
plt.savefig(outdir+"/energy_scatter.pdf") | ||
|
||
def gauss(x, A,mu, sigma): | ||
return A * np.exp(-(x-mu)**2/(2*sigma**2)) | ||
from scipy.optimize import curve_fit | ||
|
||
res=[] | ||
dres=[] | ||
emid=[] | ||
ew=[] | ||
partitions=(20,30, 40, 60,80,100) | ||
for emin, emax in zip(partitions[:-1], partitions[1:]): | ||
|
||
y,x = np.histogram((theta_recon-theta_truth)[(Etruth>emin)&(Etruth<emax)], bins=100, range=(-0.03,0.03)) | ||
bc=(x[1:]+x[:-1])/2 | ||
slc=abs(bc)<0.5 | ||
# try: | ||
p0=(100, 0, 0.15) | ||
fnc=gauss | ||
sigma=np.sqrt(y[slc])+(y[slc]==0) | ||
|
||
coeff, var_matrix = curve_fit(fnc, list(bc[slc]), list(y[slc]), p0=p0, sigma=list(sigma), maxfev=10000) | ||
res.append(abs(coeff[2])) | ||
dres.append(np.sqrt(var_matrix[2][2])) | ||
emid.append((emin+emax)/2) | ||
ew.append((emax-emin)/2) | ||
plt.errorbar(emid, 1000*np.array(res),1000*np.array(dres), ew, ls='', label=f'{eta_min}<$\\eta_{{hfs}}$<{eta_max}') | ||
plt.xlabel('$E_{hfs}$ [GeV]') | ||
plt.ylabel('$\\theta$ resolution [mrad]') | ||
plt.ylim(0) | ||
|
||
fnc=lambda E,B:B/E | ||
p0=[1,] | ||
coeff, var_matrix = curve_fit(fnc, emid, res, p0=p0, sigma=list(dres), maxfev=10000) | ||
xx=np.linspace(10, 100, 100) | ||
plt.plot(xx, 1000*fnc(xx, *coeff), label=f"fit: ${coeff[0]:.2f}/E$ mrad") | ||
plt.legend() | ||
plt.savefig(outdir+"/theta_res.pdf") |
Oops, something went wrong.