From 7622c5072c73677d08f5898cd6b8cf1da9fee256 Mon Sep 17 00:00:00 2001 From: Chao Peng <cpeng@anl.gov> Date: Tue, 20 Oct 2020 23:05:09 -0500 Subject: [PATCH] added reconstruction script for RICH --- rich/forward_hadrons.sh | 70 ++++++++++++++++++++++++++++ rich/options/rich_reco.py | 33 +++++++++++++ rich/rich_config.yml | 14 ++++++ rich/scripts/rich_data_gen.py | 87 +++++++++++++++++++++++++++++++++++ rich/scripts/rich_samples.py | 44 ++++++++++++++++++ 5 files changed, 248 insertions(+) create mode 100644 rich/forward_hadrons.sh create mode 100644 rich/options/rich_reco.py create mode 100644 rich/rich_config.yml create mode 100644 rich/scripts/rich_data_gen.py create mode 100644 rich/scripts/rich_samples.py diff --git a/rich/forward_hadrons.sh b/rich/forward_hadrons.sh new file mode 100644 index 00000000..4ef74e96 --- /dev/null +++ b/rich/forward_hadrons.sh @@ -0,0 +1,70 @@ +#!/bin/bash + +if [[ ! -n "${JUGGLER_DETECTOR}" ]] ; then + export JUGGLER_DETECTOR="topside" +fi + +if [[ ! -n "${JUGGLER_N_EVENTS}" ]] ; then + export JUGGLER_N_EVENTS=100 +fi + +if [[ ! -n "${P_start}" ]] ; then + export P_start=5.0 +fi + +if [[ ! -n "${P_end}" ]] ; then + export P_end=100.0 +fi + +if [[ ! -n "${Angle_start}" ]] ; then + export Angle_start=3.0 +fi + +if [[ ! -n "${Angle_end}" ]] ; then + export Angle_end=8.0 +fi + +export JUGGLER_FILE_NAME_TAG="emcal_uniform_electrons" +export JUGGLER_GEN_FILE="${JUGGLER_FILE_NAME_TAG}.hepmc" + +export JUGGLER_SIM_FILE="sim_${JUGGLER_FILE_NAME_TAG}.root" +export JUGGLER_REC_FILE="rec_${JUGGLER_FILE_NAME_TAG}.root" + +echo "JUGGLER_N_EVENTS = ${JUGGLER_N_EVENTS}" +echo "JUGGLER_DETECTOR = ${JUGGLER_DETECTOR}" + + +# Build the detector constructors. +git clone https://eicweb.phy.anl.gov/EIC/detectors/${JUGGLER_DETECTOR}.git +mkdir ${JUGGLER_DETECTOR}/build +pushd ${JUGGLER_DETECTOR}/build +cmake ../. -DCMAKE_INSTALL_PREFIX=/usr/local && make -j30 install +popd + +# generate the input events +# note datasets is now only used to develop datasets. +#git clone https://eicweb.phy.anl.gov/EIC/datasets.git datasets +python rich/scripts/rich_data_gen.py \ + ${JUGGLER_FILE_NAME_TAG}.hepmc \ + -n ${JUGGLER_N_EVENTS} \ + --pmin ${P_start} \ + --pmax ${P_end} \ + --angmin ${Angle_start} \ + --angmax ${Angle_end} + +pushd ${JUGGLER_DETECTOR} +ls -l +# run geant4 simulations +python options/ForwardRICH/simu.py \ + --compact=${JUGGLER_DETECTOR}.xml \ + -i ../${JUGGLER_FILE_NAME_TAG} \ + -o ${JUGGLER_SIM_FILE} + -n ${JUGGLER_N_EVENTS} + +# @TODO changeable simulation file name and detector xml file name +xenv -x /usr/local/Juggler.xenv gaudirun.py ../rich/options/rich_reco.py +ls -l +popd + +# @TODO add analysis scripts + diff --git a/rich/options/rich_reco.py b/rich/options/rich_reco.py new file mode 100644 index 00000000..d0557aeb --- /dev/null +++ b/rich/options/rich_reco.py @@ -0,0 +1,33 @@ +from Gaudi.Configuration import * +from GaudiKernel import SystemOfUnits as units + +from GaudiKernel.DataObjectHandleBase import DataObjectHandleBase +from Configurables import ApplicationMgr, EICDataSvc, PodioOutput, GeoSvc + +geo_service = GeoSvc("GeoSvc", detectors=["topside.xml"]) +podioevent = EICDataSvc("EventDataSvc", inputs=["rich_test.root"], OutputLevel=DEBUG) + +from Configurables import PodioInput +from Configurables import Jug__Digi__PhotoMultiplierDigi as PhotoMultiplierDigi +from Configurables import Jug__Reco__PhotoMultiplierReco as PhotoMultiplierReco +from Configurables import Jug__Reco__PhotoRingClusters as PhotoRingClusters + +qe_data = [(1.0, 0.25), (7.5, 0.25),] +podioinput = PodioInput("PodioReader", collections=["mcparticles", "ForwardRICHHits"], OutputLevel=DEBUG) +pmtdigi = PhotoMultiplierDigi(inputHitCollection="ForwardRICHHits", outputHitCollection="DigiForwardRICHHits", + quantumEfficiency=[(a*units.eV, b) for a, b in qe_data]) +pmtreco = PhotoMultiplierReco(inputHitCollection="DigiForwardRICHHits", outputHitCollection="RecoForwardRICHHits") +richcluster = PhotoRingClusters(inputHitCollection="RecoForwardRICHHits", inputTrackCollection="mcparticles", + outputClusterCollection="RICHClusters") + +out = PodioOutput("out", filename="rich_test_reco.root") +out.outputCommands = ["keep *"] + +ApplicationMgr( + TopAlg = [podioinput, pmtdigi, pmtreco, richcluster, out], + EvtSel = 'NONE', + EvtMax = 100000, + ExtSvc = [podioevent], + OutputLevel=DEBUG + ) + diff --git a/rich/rich_config.yml b/rich/rich_config.yml new file mode 100644 index 00000000..4fc4c395 --- /dev/null +++ b/rich/rich_config.yml @@ -0,0 +1,14 @@ +rich_job_x: + image: eicweb.phy.anl.gov:4567/eic/juggler/juggler:latest + tags: + - silicon + needs: ["get_data"] + timeout: 24 hours + artifacts: + expire_in: 20 weeks + paths: + - results/ + stage: run + script: + - bash rich/forward_hadrons.sh + diff --git a/rich/scripts/rich_data_gen.py b/rich/scripts/rich_data_gen.py new file mode 100644 index 00000000..c609a888 --- /dev/null +++ b/rich/scripts/rich_data_gen.py @@ -0,0 +1,87 @@ +import os +from pyHepMC3 import HepMC3 as hm +import numpy as np +import argparse + + +PARTICLES = [ +# (111, 0.134.9766), # pi0 + (211, 0.13957018), # pi+ +# (-211, 0.13957018), # pi- +# (311, 0.497648), # K0 + (321, 0.493677), # K+ +# (-321, 0.493677), # K- + (2212, 0.938272), # proton +# (2112, 0.939565), # neutron +# (11, 0.51099895e-3), # electron +# (-11, 0.51099895e-3), # positron +] + + +# p in GeV, angle in degree, vertex in mm +def gen_event(prange=(8, 100), arange=(0, 20)): + evt = hm.GenEvent(momentum_unit=hm.Units.MomentumUnit.GEV, length_unit=hm.Units.LengthUnit.MM) + pid, mass = PARTICLES[np.random.randint(len(PARTICLES))] + + # final state + state = 1 + + # momentum, angles, energy + p = np.random.uniform(*prange) + theta = np.random.uniform(*arange)*np.pi/180. + phi = np.random.uniform(0., 2.*np.pi) + e0 = np.sqrt(p*p + mass*mass) + + px = np.cos(phi)*np.sin(theta) + py = np.sin(phi)*np.sin(theta) + pz = np.cos(theta) + + # beam + pbeam = hm.GenParticle(hm.FourVector(0, 0, 0, 0.938272), 2212, 4) + ebeam = hm.GenParticle(hm.FourVector(0, 0, e0, np.sqrt(e0*e0 + 0.511e-3*0.511e-3)), -11, 4) + + hout = hm.GenParticle(hm.FourVector(px*p, py*p, pz*p, e0), pid, state) + # evt.add_particle(part) + vert = hm.GenVertex() + vert.add_particle_in(ebeam) + vert.add_particle_in(pbeam) + vert.add_particle_out(hout) + evt.add_vertex(vert) + return evt + + +if __name__ == "__main__": + parser = argparse.ArgumentParser('RICH dataset generator') + + parser.add_argument('output', help='path to the output file') + parser.add_argument('-n', type=int, default=1000, dest='nev', help='number of events to generate') + parser.add_argument('--pmin', type=float, default=8.0, dest='pmin', help='minimum momentum in GeV') + parser.add_argument('--pmax', type=float, default=100.0, dest='pmax', help='maximum momentum in GeV') + parser.add_argument('--angmin', type=float, default=0.0, dest='angmin', help='minimum angle in degree') + parser.add_argument('--angmax', type=float, default=20.0, dest='angmax', help='maximum angle in degree') + parser.add_argument('-s', type=int, default=-1, dest='seed', help='seed for random generator') + + args = parser.parse_args() + + # random seed + if args.seed < 0: + args.seed = os.environ.get('SEED', int.from_bytes(os.urandom(4), byteorder='big', signed=False)) + np.random.seed(args.seed) + + output = hm.WriterAscii(args.output); + if output.failed(): + print("Cannot open file \"{}\"".format(args.output)) + sys.exit(2) + + count = 0 + while count < args.nev: + if (count % 1000 == 0): + print("Generated {} events".format(count), end='\r') + evt = gen_event((args.pmin, args.pmax), (args.angmin, args.angmax)) + output.write_event(evt) + evt.clear() + count += 1 + + print("Generated {} events".format(args.nev)) + output.close() + diff --git a/rich/scripts/rich_samples.py b/rich/scripts/rich_samples.py new file mode 100644 index 00000000..0dcc2bdb --- /dev/null +++ b/rich/scripts/rich_samples.py @@ -0,0 +1,44 @@ +import ROOT +import numpy as np +from ROOT import gROOT +import argparse +from matplotlib import pyplot as plt +from matplotlib.patches import Ellipse +import matplotlib.transforms as transforms + +parser = argparse.ArgumentParser(description='rich reconstruction analysis') +parser.add_argument('nevents', type=int, help='number of events') +args = parser.parse_args() + +gROOT.Macro('rootlogon.C') +f = ROOT.TFile("rich_test_reco.root") +events = f.events + +nev = 0 +while nev < args.nevents: + iev = np.random.randint(0, events.GetEntries()) + events.GetEntry(iev) + if events.RICHClusters.size() == 0: + continue + + nev += 1 + x, y = [], [] + for hit in events.RecoForwardRICHHits: + x.append(hit.position.x) + y.append(hit.position.y) + + fig, ax = plt.subplots(figsize=(9, 9), dpi=120) + colors = plt.rcParams['axes.prop_cycle'].by_key()['color'] + ax.scatter(x, y, s=9, marker='s', color=colors[0]) + + for cluster in events.RICHClusters: + ellipse = Ellipse((cluster.position.x, cluster.position.y), width=cluster.radius * 2, height=cluster.radius * 2, + edgecolor='red', fill=False, lw=2, alpha=0.8) + ellipse.set_transform(ax.transData) + ax.add_patch(ellipse) + ax.set_xlim(-60, 60) + ax.set_ylim(-60, 60) + ax.set_xlabel('X (mm)') + ax.set_ylabel('Y (mm)') + fig.savefig('rich_cluster_{}.png'.format(iev)) + -- GitLab