318 def reconstruct(self) -> pybasf2.Path:
319 """
320 Returns pybasf2.Path which reconstructs the particles and does the vertex fitting if necessary
321 """
322 path = basf2.create_path()
323
324 for particle in self.particles:
325 for channel in particle.channels:
326
328 channel.daughters[0].split(
':')[0]) ==
pdg.from_name(particle.name)):
329 ma.cutAndCopyList(channel.name, channel.daughters[0], channel.preCutConfig.userCut, writeOut=True, path=path)
330 v2EI = basf2.register_module('VariablesToExtraInfo')
331 v2EI.set_name(f'VariablesToExtraInfo_{channel.name}')
332 v2EI.param('particleList', channel.name)
333 v2EI.param('variables', {f'constant({channel.decayModeID})': 'decayModeID'})
334
335 v2EI.set_log_level(basf2.logging.log_level.ERROR)
336 path.add_module(v2EI)
337 else:
338 ma.reconstructDecay(channel.decayString, channel.preCutConfig.userCut, channel.decayModeID,
339 writeOut=True, path=path)
340 if self.config.monitor:
341 if "tag" in (channel.name).lower():
342 ma.matchTagTruth(channel.name, path=path)
343 else:
344 ma.matchMCTruth(channel.name, path=path)
345 bc_variable = channel.preCutConfig.bestCandidateVariable
346 if self.config.monitor == 'simple':
347 hist_variables = [channel.mvaConfig.target, 'extraInfo(decayModeID)']
348 hist_variables_2d = [(channel.mvaConfig.target, 'extraInfo(decayModeID)')]
349 else:
350 hist_variables = [bc_variable, 'mcErrors', 'mcParticleStatus',
351 channel.mvaConfig.target] + list(channel.mvaConfig.spectators.keys())
352 hist_variables_2d = [(bc_variable, channel.mvaConfig.target),
353 (bc_variable, 'mcErrors'),
354 (bc_variable, 'mcParticleStatus')]
355 for specVar in channel.mvaConfig.spectators:
356 hist_variables_2d.append((bc_variable, specVar))
357 hist_variables_2d.append((channel.mvaConfig.target, specVar))
358 filename = os.path.join(self.config.monitoring_path, 'Monitor_PreReconstruction_BeforeRanking.root')
359 ma.variablesToHistogram(
360 channel.name,
361 variables=config.variables2binnings(hist_variables),
362 variables_2d=config.variables2binnings_2d(hist_variables_2d),
363 filename=filename,
364 ignoreCommandLineOverride=True,
365 directory=f'{channel.label}',
366 path=path)
367
368 if channel.preCutConfig.bestCandidateMode == 'lowest':
369 ma.rankByLowest(channel.name,
370 channel.preCutConfig.bestCandidateVariable,
371 channel.preCutConfig.bestCandidateCut,
372 'preCut_rank',
373 path=path)
374 elif channel.preCutConfig.bestCandidateMode == 'highest':
375 ma.rankByHighest(channel.name,
376 channel.preCutConfig.bestCandidateVariable,
377 channel.preCutConfig.bestCandidateCut,
378 'preCut_rank',
379 path=path)
380 else:
381 raise RuntimeError(f'Unknown bestCandidateMode {repr(channel.preCutConfig.bestCandidateMode)}')
382
383 if 'gamma' in channel.decayString and channel.pi0veto:
384 ma.buildRestOfEvent(channel.name, path=path)
385 Ddaughter_roe_path = basf2.Path()
386 deadEndPath = basf2.Path()
387 ma.signalSideParticleFilter(channel.name, '', Ddaughter_roe_path, deadEndPath)
388 ma.fillParticleList('gamma:roe', 'isInRestOfEvent == 1', path=Ddaughter_roe_path)
389
390 matches = list(re.finditer('gamma', channel.decayString))
391 pi0lists = []
392 for igamma in range(len(matches)):
393 start, end = matches[igamma-1].span()
394 tempString = f'{channel.decayString[:start]}^gamma{channel.decayString[end:]}'
395 ma.fillSignalSideParticleList(f'gamma:sig_{igamma}', tempString, path=Ddaughter_roe_path)
396 ma.reconstructDecay(f'pi0:veto_{igamma} -> gamma:sig_{igamma} gamma:roe', '', path=Ddaughter_roe_path)
397 pi0lists.append(f'pi0:veto_{igamma}')
398 ma.copyLists('pi0:veto', pi0lists, writeOut=False, path=Ddaughter_roe_path)
399 ma.rankByLowest('pi0:veto', 'abs(dM)', 1, path=Ddaughter_roe_path)
400 ma.matchMCTruth('pi0:veto', path=Ddaughter_roe_path)
401 ma.variableToSignalSideExtraInfo(
402 'pi0:veto',
403 {
404 'InvM': 'pi0vetoMass',
405 'formula((daughter(0,E)-daughter(1,E))/(daughter(0,E)+daughter(1,E)))': 'pi0vetoEnergyAsymmetry',
406 },
407 path=Ddaughter_roe_path
408 )
409 path.for_each('RestOfEvent', 'RestOfEvents', Ddaughter_roe_path)
410
411 if self.config.monitor:
412 filename = os.path.join(self.config.monitoring_path, 'Monitor_PreReconstruction_AfterRanking.root')
413 if self.config.monitor != 'simple':
414 hist_variables += ['extraInfo(preCut_rank)']
415 hist_variables_2d += [('extraInfo(preCut_rank)', channel.mvaConfig.target),
416 ('extraInfo(preCut_rank)', 'mcErrors'),
417 ('extraInfo(preCut_rank)', 'mcParticleStatus')]
418 for specVar in channel.mvaConfig.spectators:
419 hist_variables_2d.append(('extraInfo(preCut_rank)', specVar))
420 ma.variablesToHistogram(
421 channel.name,
422 variables=config.variables2binnings(hist_variables),
423 variables_2d=config.variables2binnings_2d(hist_variables_2d),
424 filename=filename,
425 ignoreCommandLineOverride=True,
426 directory=f'{channel.label}',
427 path=path)
428
429
430 elif self.config.training:
431 if "tag" in (channel.name).lower():
432 ma.matchTagTruth(channel.name, path=path)
433 else:
434 ma.matchMCTruth(channel.name, path=path)
435
437 pvfit = basf2.register_module('ParticleVertexFitter')
438 pvfit.set_name(f'ParticleVertexFitter_{channel.name}')
439 pvfit.param('listName', channel.name)
440 pvfit.param('confidenceLevel', channel.preCutConfig.vertexCut)
441 pvfit.param('vertexFitter', 'KFit')
442 pvfit.param('fitType', 'vertex')
443 pvfit.set_log_level(basf2.logging.log_level.ERROR)
444 path.add_module(pvfit)
445 elif re.findall(r"[\w']+", channel.decayString).count('pi0') > 1 and particle.name != 'pi0':
446 basf2.B2INFO(f"Ignoring vertex fit for {channel.name} because multiple pi0 are not supported yet.")
447 elif len(channel.daughters) > 1:
448 pvfit = basf2.register_module('ParticleVertexFitter')
449 pvfit.set_name(f'ParticleVertexFitter_{channel.name}')
450 pvfit.param('listName', channel.name)
451 pvfit.param('confidenceLevel', channel.preCutConfig.vertexCut)
452 pvfit.param('vertexFitter', 'KFit')
453 if particle.name in ['pi0']:
454 pvfit.param('fitType', 'mass')
455 else:
456 pvfit.param('fitType', 'vertex')
457 pvfit.set_log_level(basf2.logging.log_level.ERROR)
458 path.add_module(pvfit)
459
460 if self.config.monitor:
461 if self.config.monitor == 'simple':
462 hist_variables = [channel.mvaConfig.target, 'extraInfo(decayModeID)']
463 hist_variables_2d = [(channel.mvaConfig.target, 'extraInfo(decayModeID)')]
464 else:
465 hist_variables = ['chiProb', 'mcErrors', 'mcParticleStatus',
466 channel.mvaConfig.target] + list(channel.mvaConfig.spectators.keys())
467 hist_variables_2d = [('chiProb', channel.mvaConfig.target),
468 ('chiProb', 'mcErrors'),
469 ('chiProb', 'mcParticleStatus')]
470 for specVar in channel.mvaConfig.spectators:
471 hist_variables_2d.append(('chiProb', specVar))
472 hist_variables_2d.append((channel.mvaConfig.target, specVar))
473 filename = os.path.join(self.config.monitoring_path, 'Monitor_PreReconstruction_AfterVertex.root')
474 ma.variablesToHistogram(
475 channel.name,
476 variables=config.variables2binnings(hist_variables),
477 variables_2d=config.variables2binnings_2d(hist_variables_2d),
478 filename=filename,
479 ignoreCommandLineOverride=True,
480 directory=f'{channel.label}',
481 path=path)
482
483 return path
484
485