16 from ROOT
import Belle2
17 from ROOT.Belle2
import TrackFindingCDC
as TFCDC
34 return logging.getLogger(__name__)
37 CONTACT =
"oliver.frost@desy.de"
40 def getNaiveBetheEnergyLoss(p, pdg_code, s):
42 eloss = s * 1 * 10**-4
46 def getBetheStoppingPower(p, pdg_code):
48 energy = np.sqrt(mass * mass + p * p)
53 gamma2 = gamma * gamma
56 eMass = 0.511 * Belle2.Unit.MeV
58 m_eDensity = 0.000515726
60 Wmax = 2 * eMass * beta2 * gamma2 / (1 + 2 * gamma * eMass / mass)
63 K = 0.307075 * Belle2.Unit.MeV * Belle2.Unit.cm2
65 K * m_eDensity / beta2 *
66 (1.0 / 2.0 * math.log(2 * eMass * beta2 * gamma2 * Wmax / I2) - beta2)
73 factor = 178.6 * 0.00015e-04 / 2
75 dEdx = factor / beta2 * (math.log(2 * eMass * beta2 * gamma2 * Wmax / I2) - beta2)
84 def getBetheEnergyLoss(p, pdg_code, path):
85 dEdx = getBetheStoppingPower(p, pdg_code)
90 def getMomentumLossFactor(p, pdg_code, eloss):
91 p_factor = (p - eloss) / p
95 def DeltaR(path, particleID, P):
96 eloss = getBetheEnergyLoss(P, particleID, path)
97 return getMomentumLossFactor(P, particleID, eloss)
101 """Harvester to generate, postprocess and inspect MC events for energy-loss evaluation"""
105 generator_module =
"eloss_gun"
107 detector_setup =
"TrackingDetectorConstB"
111 """Get the output ROOT filename"""
115 """Harvest and post-process the generated events"""
118 path.add_module(harvesting_module)
119 return harvesting_module
122 """Convert command-line arguments to basf2 argument list"""
124 return argument_parser
128 Sets up a path that plays back pregenerated events or generates events
129 based on the properties in the base class.
133 path.add_module(
"TFCDC_WireHitPreparer",
135 flightTimeEstimation=
"outwards",
138 path.add_module(
'TFCDC_AxialTrackCreatorMCTruth',
140 useOnlyBeforeTOP=
True,
142 reconstructedDriftLength=
True,
143 reconstructedPositions=
True)
150 """Module to collect information about the generated segments and
151 compose validation plots on terminate."""
155 super().
__init__(foreach=
'CDCTrackVector',
156 output_file_name=output_file_name)
161 origin_track_fitter = TFCDC.CDCRiemannFitter()
162 origin_track_fitter.setOriginConstrained()
167 """Receive signal at the start of event processing"""
170 self.
mc_track_lookupmc_track_lookup = TFCDC.CDCMCTrackLookUp.getInstance()
179 """Initialize the MC-hit lookup method"""
180 TFCDC.CDCMCHitLookUp.getInstance().fill()
183 """Select tracks with at least 4 segments and associated primary MC particle with pt >= 0.25 GeV/c"""
188 mc_particle = mc_track_lookup.getMCParticle(track)
191 if mc_particle
is None:
194 if mc_particle.getMomentum().Rho() < 0.250:
197 return is_primary(mc_particle)
200 """Aggregate the track and MC information for dE/dx analysis"""
213 mc_particle = mc_track_lookup.getMCParticle(track)
214 pdg_code = mc_particle.getPDG()
215 t_vertex = mc_particle.getVertex()
216 t_mom = mc_particle.getMomentum()
217 charge = mc_particle.getCharge()
218 mass = mc_particle.getMass()
219 mc_energy = mc_particle.getEnergy()
221 mc_vertex2D = TFCDC.Vector2D(t_vertex.XYvector())
222 mc_mom2D = TFCDC.Vector2D(t_mom.XYvector())
223 mc_trajectory2D = TFCDC.CDCTrajectory2D(mc_vertex2D, 0, mc_mom2D, charge)
224 mc_pt = mc_mom2D.norm()
227 first_sim_hit = first_hit.getRelated(
"CDCSimHits")
228 if first_sim_hit
is None:
231 if first_sim_hit.getWireID().getICLayer() != 0:
235 last_sim_hit = last_hit.getRelated(
"CDCSimHits")
236 if last_sim_hit
is None:
242 first_sim_pos3D = TFCDC.Vector3D(first_sim_hit.getPosTrack())
243 first_sim_mom3D = TFCDC.Vector3D(first_sim_hit.getMomentum())
244 first_sim_tof = first_sim_hit.getFlightTime()
245 first_sim_energy = np.sqrt(first_sim_mom3D.norm() ** 2 + mass ** 2)
246 first_sim_pt = first_sim_mom3D.cylindricalR()
247 first_sim_pz = first_sim_mom3D.z()
249 first_sim_mom2D = first_sim_mom3D.xy()
252 first_sim_trajectory2D = TFCDC.CDCTrajectory2D(first_sim_pos3D.xy(), first_sim_tof, first_sim_mom2D, charge)
257 for reco_hit3D
in track:
258 sim_hit = self.
mc_hit_lookupmc_hit_lookup.getSimHit(reco_hit3D.getWireHit().getHit())
262 sim_mom3D = TFCDC.Vector3D(sim_hit.getMomentum())
263 sim_energy = np.sqrt(sim_mom3D.norm() ** 2 + mass ** 2)
264 sim_pt = sim_mom3D.cylindricalR()
265 sim_pz = sim_mom3D.z()
267 mc_eloss_truth = mc_energy - sim_energy
268 first_eloss_truth = first_sim_energy - sim_energy
270 sim_pos3D = TFCDC.Vector3D(sim_hit.getPosTrack())
271 sim_pos2D = sim_pos3D.xy()
273 layer_cid = reco_hit3D.getWire().getICLayer()
274 bz = self.
bfieldbfield.getBFieldZ(sim_pos3D)
275 r = sim_pos3D.cylindricalR()
283 mc_s2D = mc_trajectory2D.calcArcLength2D(sim_pos2D)
284 first_s2D = first_sim_trajectory2D.calcArcLength2D(sim_pos2D)
290 mc_eloss_estimate = self.
eloss_estimatoreloss_estimator.getEnergyLoss(mc_pt, pdg_code, mc_s2D)
291 first_eloss_estimate = self.
eloss_estimatoreloss_estimator.getEnergyLoss(first_sim_pt, pdg_code, first_s2D)
292 first_ploss_factor = self.
eloss_estimatoreloss_estimator.getMomentumLossFactor(first_sim_pt, pdg_code, first_s2D)
294 sasha_eloss_estimate = getBetheEnergyLoss(first_sim_pt, pdg_code, first_s2D)
295 sasha_ploss_factor = DeltaR(first_s2D, pdg_code, first_sim_pt)
298 first_residual2D = first_sim_trajectory2D.getDist2D(sim_pos2D)
299 first_disp2D = charge * first_residual2D
301 first_loss_disp2D_estimate = abs(self.
eloss_estimatoreloss_estimator.getLossDist2D(first_sim_pt, pdg_code, first_s2D))
302 first_delossed_disp2D = first_disp2D - first_loss_disp2D_estimate
305 mc_residual2D = mc_trajectory2D.getDist2D(sim_pos2D)
306 mc_disp2D = charge * mc_residual2D
308 mc_loss_disp2D_estimate = abs(self.
eloss_estimatoreloss_estimator.getLossDist2D(mc_pt, pdg_code, mc_s2D))
309 mc_delossed_disp2D = mc_disp2D - mc_loss_disp2D_estimate
331 if abs(mc_residual2D) > 6:
334 if abs(first_residual2D) > 6:
342 pdg_code=abs(pdg_code),
346 first_sim_pt=first_sim_pt,
349 diff_pt=first_sim_pt - sim_pt,
350 diff_pz=first_sim_pz - sim_pz,
352 mc_eloss_truth=mc_eloss_truth,
353 mc_eloss_estimate=mc_eloss_estimate,
355 first_eloss_truth=first_eloss_truth,
357 first_eloss_estimate=first_eloss_estimate,
358 sasha_eloss_estimate=sasha_eloss_estimate,
360 first_ploss_factor=first_ploss_factor,
361 sasha_ploss_factor=sasha_ploss_factor,
366 first_residual2D=first_residual2D,
367 first_disp2D=first_disp2D,
368 first_loss_disp2D_estimate=first_loss_disp2D_estimate,
369 first_delossed_disp2D=first_delossed_disp2D,
372 mc_residual2D=mc_residual2D,
374 mc_loss_disp2D_estimate=mc_loss_disp2D_estimate,
375 mc_delossed_disp2D=mc_delossed_disp2D,
387 save_tree = refiners.save_tree()
389 save_histograms = refiners.save_histograms(
395 save_histograms_stackby_charge = refiners.save_histograms(
409 save_scatter = refiners.save_scatters(
415 groupby=[
None,
"charge"],
416 filter=
lambda x: x == 211,
417 filter_on=
"pdg_code",
421 save_profiles = refiners.save_profiles(
428 groupby=[
None,
"charge"],
432 save_bz_profiles = refiners.save_profiles(
441 save_cid_histogram = refiners.save_histograms(
446 'first_delossed_disp2D',
451 groupby=[
"layer_cid"],
456 save_cid_profiles = refiners.save_profiles(
462 'first_delossed_disp2D',
465 groupby=[
"layer_cid"],
470 save_cid_scatters = refiners.save_scatters(
476 'first_delossed_disp2D',
479 groupby=[
"layer_cid"],
486 save_energy_cid_histogram = refiners.save_histograms(
489 'first_eloss_estimate',
493 groupby=[
"layer_cid"],
495 folder_name=
'energy/{groupby_addition}',
499 save_energy_cid_profiles = refiners.save_profiles(
503 'first_eloss_estimate',
506 groupby=[
"layer_cid"],
508 folder_name=
'energy/{groupby_addition}',
512 save_energy_cid_scatters = refiners.save_scatters(
516 'first_eloss_estimate',
519 groupby=[
"layer_cid"],
521 folder_name=
'energy/{groupby_addition}',
527 run.configure_and_execute_from_commandline()
530 if __name__ ==
"__main__":
531 logging.basicConfig(stream=sys.stdout, level=logging.INFO, format=
'%(levelname)s:%(message)s')
mc_track_lookup
by default, there is no method to find matching MC tracks
mc_hit_lookup
Method to find matching MC hits.
track_fitter
Use the CDCReimannFitter with a constrained origin for track fitting.
bfield
Method to interrogate the magnetic field values.
eloss_estimator
Method to estimate dE/dx in the CDC.
def __init__(self, output_file_name)
def create_argument_parser(self, **kwds)
def harvesting_module(self, path=None)
def output_file_name(self)
output_file_name
Disable the writing of an output ROOT file.
output_file_name
There is no default for the name of the output TFile.
int main(int argc, char **argv)
Run all tests.